@frumu/tandem-panel 0.3.28 → 0.4.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.
|
@@ -0,0 +1,1680 @@
|
|
|
1
|
+
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const i of r)if(i.type==="childList")for(const a of i.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&s(a)}).observe(document,{childList:!0,subtree:!0});function n(r){const i={};return r.integrity&&(i.integrity=r.integrity),r.referrerPolicy&&(i.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?i.credentials="include":r.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(r){if(r.ep)return;r.ep=!0;const i=n(r);fetch(r.href,i)}})();function A(e,t,n){function s(c,l){if(c._zod||Object.defineProperty(c,"_zod",{value:{def:l,constr:a,traits:new Set},enumerable:!1}),c._zod.traits.has(e))return;c._zod.traits.add(e),t(c,l);const d=a.prototype,u=Object.keys(d);for(let m=0;m<u.length;m++){const _=u[m];_ in c||(c[_]=d[_].bind(c))}}const r=n?.Parent??Object;class i extends r{}Object.defineProperty(i,"name",{value:e});function a(c){var l;const d=n?.Parent?new i:this;s(d,c),(l=d._zod).deferred??(l.deferred=[]);for(const u of d._zod.deferred)u();return d}return Object.defineProperty(a,"init",{value:s}),Object.defineProperty(a,Symbol.hasInstance,{value:c=>n?.Parent&&c instanceof n.Parent?!0:c?._zod?.traits?.has(e)}),Object.defineProperty(a,"name",{value:e}),a}class kn extends Error{constructor(){super("Encountered Promise during synchronous parse. Use .parseAsync() instead.")}}class xa extends Error{constructor(t){super(`Encountered unidirectional transform during encode: ${t}`),this.name="ZodEncodeError"}}const $a={};function Ft(e){return $a}function Ea(e){const t=Object.values(e).filter(s=>typeof s=="number");return Object.entries(e).filter(([s,r])=>t.indexOf(+s)===-1).map(([s,r])=>r)}function hr(e,t){return typeof t=="bigint"?t.toString():t}function Or(e){return{get value(){{const t=e();return Object.defineProperty(this,"value",{value:t}),t}}}}function zr(e){return e==null}function Nr(e){const t=e.startsWith("^")?1:0,n=e.endsWith("$")?e.length-1:e.length;return e.slice(t,n)}function zc(e,t){const n=(e.toString().split(".")[1]||"").length,s=t.toString();let r=(s.split(".")[1]||"").length;if(r===0&&/\d?e-\d?/.test(s)){const l=s.match(/\d?e-(\d?)/);l?.[1]&&(r=Number.parseInt(l[1]))}const i=n>r?n:r,a=Number.parseInt(e.toFixed(i).replace(".","")),c=Number.parseInt(t.toFixed(i).replace(".",""));return a%c/10**i}const yi=Symbol("evaluating");function xe(e,t,n){let s;Object.defineProperty(e,t,{get(){if(s!==yi)return s===void 0&&(s=yi,s=n()),s},set(r){Object.defineProperty(e,t,{value:r})},configurable:!0})}function on(e,t,n){Object.defineProperty(e,t,{value:n,writable:!0,enumerable:!0,configurable:!0})}function Zt(...e){const t={};for(const n of e){const s=Object.getOwnPropertyDescriptors(n);Object.assign(t,s)}return Object.defineProperties({},t)}function bi(e){return JSON.stringify(e)}function Nc(e){return e.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_-]+/g,"-").replace(/^-+|-+$/g,"")}const Ta="captureStackTrace"in Error?Error.captureStackTrace:(...e)=>{};function As(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}const Dc=Or(()=>{if(typeof navigator<"u"&&navigator?.userAgent?.includes("Cloudflare"))return!1;try{const e=Function;return new e(""),!0}catch{return!1}});function $n(e){if(As(e)===!1)return!1;const t=e.constructor;if(t===void 0||typeof t!="function")return!0;const n=t.prototype;return!(As(n)===!1||Object.prototype.hasOwnProperty.call(n,"isPrototypeOf")===!1)}function Aa(e){return $n(e)?{...e}:Array.isArray(e)?[...e]:e}const jc=new Set(["string","number","symbol"]);function Fs(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Ht(e,t,n){const s=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(s._zod.parent=e),s}function te(e){const t=e;if(!t)return{};if(typeof t=="string")return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw new Error("Cannot specify both `message` and `error` params");t.error=t.message}return delete t.message,typeof t.error=="string"?{...t,error:()=>t.error}:t}function qc(e){return Object.keys(e).filter(t=>e[t]._zod.optin==="optional"&&e[t]._zod.optout==="optional")}const Fc={safeint:[Number.MIN_SAFE_INTEGER,Number.MAX_SAFE_INTEGER],int32:[-2147483648,2147483647],uint32:[0,4294967295],float32:[-34028234663852886e22,34028234663852886e22],float64:[-Number.MAX_VALUE,Number.MAX_VALUE]};function Uc(e,t){const n=e._zod.def,s=n.checks;if(s&&s.length>0)throw new Error(".pick() cannot be used on object schemas containing refinements");const i=Zt(e._zod.def,{get shape(){const a={};for(const c in t){if(!(c in n.shape))throw new Error(`Unrecognized key: "${c}"`);t[c]&&(a[c]=n.shape[c])}return on(this,"shape",a),a},checks:[]});return Ht(e,i)}function Vc(e,t){const n=e._zod.def,s=n.checks;if(s&&s.length>0)throw new Error(".omit() cannot be used on object schemas containing refinements");const i=Zt(e._zod.def,{get shape(){const a={...e._zod.def.shape};for(const c in t){if(!(c in n.shape))throw new Error(`Unrecognized key: "${c}"`);t[c]&&delete a[c]}return on(this,"shape",a),a},checks:[]});return Ht(e,i)}function Zc(e,t){if(!$n(t))throw new Error("Invalid input to extend: expected a plain object");const n=e._zod.def.checks;if(n&&n.length>0){const i=e._zod.def.shape;for(const a in t)if(Object.getOwnPropertyDescriptor(i,a)!==void 0)throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.")}const r=Zt(e._zod.def,{get shape(){const i={...e._zod.def.shape,...t};return on(this,"shape",i),i}});return Ht(e,r)}function Hc(e,t){if(!$n(t))throw new Error("Invalid input to safeExtend: expected a plain object");const n=Zt(e._zod.def,{get shape(){const s={...e._zod.def.shape,...t};return on(this,"shape",s),s}});return Ht(e,n)}function Bc(e,t){const n=Zt(e._zod.def,{get shape(){const s={...e._zod.def.shape,...t._zod.def.shape};return on(this,"shape",s),s},get catchall(){return t._zod.def.catchall},checks:[]});return Ht(e,n)}function Jc(e,t,n){const r=t._zod.def.checks;if(r&&r.length>0)throw new Error(".partial() cannot be used on object schemas containing refinements");const a=Zt(t._zod.def,{get shape(){const c=t._zod.def.shape,l={...c};if(n)for(const d in n){if(!(d in c))throw new Error(`Unrecognized key: "${d}"`);n[d]&&(l[d]=e?new e({type:"optional",innerType:c[d]}):c[d])}else for(const d in c)l[d]=e?new e({type:"optional",innerType:c[d]}):c[d];return on(this,"shape",l),l},checks:[]});return Ht(t,a)}function Kc(e,t,n){const s=Zt(t._zod.def,{get shape(){const r=t._zod.def.shape,i={...r};if(n)for(const a in n){if(!(a in i))throw new Error(`Unrecognized key: "${a}"`);n[a]&&(i[a]=new e({type:"nonoptional",innerType:r[a]}))}else for(const a in r)i[a]=new e({type:"nonoptional",innerType:r[a]});return on(this,"shape",i),i}});return Ht(t,s)}function wn(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n<e.issues.length;n++)if(e.issues[n]?.continue!==!0)return!0;return!1}function Sn(e,t){return t.map(n=>{var s;return(s=n).path??(s.path=[]),n.path.unshift(e),n})}function ys(e){return typeof e=="string"?e:e?.message}function Ut(e,t,n){const s={...e,path:e.path??[]};if(!e.message){const r=ys(e.inst?._zod.def?.error?.(e))??ys(t?.error?.(e))??ys(n.customError?.(e))??ys(n.localeError?.(e))??"Invalid input";s.message=r}return delete s.inst,delete s.continue,t?.reportInput||delete s.input,s}function Dr(e){return Array.isArray(e)?"array":typeof e=="string"?"string":"unknown"}function Kn(...e){const[t,n,s]=e;return typeof t=="string"?{message:t,code:"custom",input:n,inst:s}:{...t}}const Ia=(e,t)=>{e.name="$ZodError",Object.defineProperty(e,"_zod",{value:e._zod,enumerable:!1}),Object.defineProperty(e,"issues",{value:t,enumerable:!1}),e.message=JSON.stringify(t,hr,2),Object.defineProperty(e,"toString",{value:()=>e.message,enumerable:!1})},Ca=A("$ZodError",Ia),Ma=A("$ZodError",Ia,{Parent:Error});function Gc(e,t=n=>n.message){const n={},s=[];for(const r of e.issues)r.path.length>0?(n[r.path[0]]=n[r.path[0]]||[],n[r.path[0]].push(t(r))):s.push(t(r));return{formErrors:s,fieldErrors:n}}function Wc(e,t=n=>n.message){const n={_errors:[]},s=r=>{for(const i of r.issues)if(i.code==="invalid_union"&&i.errors.length)i.errors.map(a=>s({issues:a}));else if(i.code==="invalid_key")s({issues:i.issues});else if(i.code==="invalid_element")s({issues:i.issues});else if(i.path.length===0)n._errors.push(t(i));else{let a=n,c=0;for(;c<i.path.length;){const l=i.path[c];c===i.path.length-1?(a[l]=a[l]||{_errors:[]},a[l]._errors.push(t(i))):a[l]=a[l]||{_errors:[]},a=a[l],c++}}};return s(e),n}const jr=e=>(t,n,s,r)=>{const i=s?Object.assign(s,{async:!1}):{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new kn;if(a.issues.length){const c=new(r?.Err??e)(a.issues.map(l=>Ut(l,i,Ft())));throw Ta(c,r?.callee),c}return a.value},qr=e=>async(t,n,s,r)=>{const i=s?Object.assign(s,{async:!0}):{async:!0};let a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise&&(a=await a),a.issues.length){const c=new(r?.Err??e)(a.issues.map(l=>Ut(l,i,Ft())));throw Ta(c,r?.callee),c}return a.value},Us=e=>(t,n,s)=>{const r=s?{...s,async:!1}:{async:!1},i=t._zod.run({value:n,issues:[]},r);if(i instanceof Promise)throw new kn;return i.issues.length?{success:!1,error:new(e??Ca)(i.issues.map(a=>Ut(a,r,Ft())))}:{success:!0,data:i.value}},Yc=Us(Ma),Vs=e=>async(t,n,s)=>{const r=s?Object.assign(s,{async:!0}):{async:!0};let i=t._zod.run({value:n,issues:[]},r);return i instanceof Promise&&(i=await i),i.issues.length?{success:!1,error:new e(i.issues.map(a=>Ut(a,r,Ft())))}:{success:!0,data:i.value}},Xc=Vs(Ma),Qc=e=>(t,n,s)=>{const r=s?Object.assign(s,{direction:"backward"}):{direction:"backward"};return jr(e)(t,n,r)},el=e=>(t,n,s)=>jr(e)(t,n,s),tl=e=>async(t,n,s)=>{const r=s?Object.assign(s,{direction:"backward"}):{direction:"backward"};return qr(e)(t,n,r)},nl=e=>async(t,n,s)=>qr(e)(t,n,s),sl=e=>(t,n,s)=>{const r=s?Object.assign(s,{direction:"backward"}):{direction:"backward"};return Us(e)(t,n,r)},rl=e=>(t,n,s)=>Us(e)(t,n,s),il=e=>async(t,n,s)=>{const r=s?Object.assign(s,{direction:"backward"}):{direction:"backward"};return Vs(e)(t,n,r)},al=e=>async(t,n,s)=>Vs(e)(t,n,s),ol=/^[cC][^\s-]{8,}$/,cl=/^[0-9a-z]+$/,ll=/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/,dl=/^[0-9a-vA-V]{20}$/,ul=/^[A-Za-z0-9]{27}$/,pl=/^[a-zA-Z0-9_-]{21}$/,ml=/^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,fl=/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,wi=e=>e?new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${e}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`):/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,hl=/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/,gl="^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$";function vl(){return new RegExp(gl,"u")}const yl=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,bl=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/,wl=/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,Sl=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,_l=/^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,Ra=/^[A-Za-z0-9_-]*$/,kl=/^\+[1-9]\d{6,14}$/,Pa="(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))",xl=new RegExp(`^${Pa}$`);function La(e){const t="(?:[01]\\d|2[0-3]):[0-5]\\d";return typeof e.precision=="number"?e.precision===-1?`${t}`:e.precision===0?`${t}:[0-5]\\d`:`${t}:[0-5]\\d\\.\\d{${e.precision}}`:`${t}(?::[0-5]\\d(?:\\.\\d+)?)?`}function $l(e){return new RegExp(`^${La(e)}$`)}function El(e){const t=La({precision:e.precision}),n=["Z"];e.local&&n.push(""),e.offset&&n.push("([+-](?:[01]\\d|2[0-3]):[0-5]\\d)");const s=`${t}(?:${n.join("|")})`;return new RegExp(`^${Pa}T(?:${s})$`)}const Tl=e=>{const t=e?`[\\s\\S]{${e?.minimum??0},${e?.maximum??""}}`:"[\\s\\S]*";return new RegExp(`^${t}$`)},Al=/^-?\d+$/,Oa=/^-?\d+(?:\.\d+)?$/,Il=/^(?:true|false)$/i,Cl=/^[^A-Z]*$/,Ml=/^[^a-z]*$/,lt=A("$ZodCheck",(e,t)=>{var n;e._zod??(e._zod={}),e._zod.def=t,(n=e._zod).onattach??(n.onattach=[])}),za={number:"number",bigint:"bigint",object:"date"},Na=A("$ZodCheckLessThan",(e,t)=>{lt.init(e,t);const n=za[typeof t.value];e._zod.onattach.push(s=>{const r=s._zod.bag,i=(t.inclusive?r.maximum:r.exclusiveMaximum)??Number.POSITIVE_INFINITY;t.value<i&&(t.inclusive?r.maximum=t.value:r.exclusiveMaximum=t.value)}),e._zod.check=s=>{(t.inclusive?s.value<=t.value:s.value<t.value)||s.issues.push({origin:n,code:"too_big",maximum:typeof t.value=="object"?t.value.getTime():t.value,input:s.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),Da=A("$ZodCheckGreaterThan",(e,t)=>{lt.init(e,t);const n=za[typeof t.value];e._zod.onattach.push(s=>{const r=s._zod.bag,i=(t.inclusive?r.minimum:r.exclusiveMinimum)??Number.NEGATIVE_INFINITY;t.value>i&&(t.inclusive?r.minimum=t.value:r.exclusiveMinimum=t.value)}),e._zod.check=s=>{(t.inclusive?s.value>=t.value:s.value>t.value)||s.issues.push({origin:n,code:"too_small",minimum:typeof t.value=="object"?t.value.getTime():t.value,input:s.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),Rl=A("$ZodCheckMultipleOf",(e,t)=>{lt.init(e,t),e._zod.onattach.push(n=>{var s;(s=n._zod.bag).multipleOf??(s.multipleOf=t.value)}),e._zod.check=n=>{if(typeof n.value!=typeof t.value)throw new Error("Cannot mix number and bigint in multiple_of check.");(typeof n.value=="bigint"?n.value%t.value===BigInt(0):zc(n.value,t.value)===0)||n.issues.push({origin:typeof n.value,code:"not_multiple_of",divisor:t.value,input:n.value,inst:e,continue:!t.abort})}}),Pl=A("$ZodCheckNumberFormat",(e,t)=>{lt.init(e,t),t.format=t.format||"float64";const n=t.format?.includes("int"),s=n?"int":"number",[r,i]=Fc[t.format];e._zod.onattach.push(a=>{const c=a._zod.bag;c.format=t.format,c.minimum=r,c.maximum=i,n&&(c.pattern=Al)}),e._zod.check=a=>{const c=a.value;if(n){if(!Number.isInteger(c)){a.issues.push({expected:s,format:t.format,code:"invalid_type",continue:!1,input:c,inst:e});return}if(!Number.isSafeInteger(c)){c>0?a.issues.push({input:c,code:"too_big",maximum:Number.MAX_SAFE_INTEGER,note:"Integers must be within the safe integer range.",inst:e,origin:s,inclusive:!0,continue:!t.abort}):a.issues.push({input:c,code:"too_small",minimum:Number.MIN_SAFE_INTEGER,note:"Integers must be within the safe integer range.",inst:e,origin:s,inclusive:!0,continue:!t.abort});return}}c<r&&a.issues.push({origin:"number",input:c,code:"too_small",minimum:r,inclusive:!0,inst:e,continue:!t.abort}),c>i&&a.issues.push({origin:"number",input:c,code:"too_big",maximum:i,inclusive:!0,inst:e,continue:!t.abort})}}),Ll=A("$ZodCheckMaxLength",(e,t)=>{var n;lt.init(e,t),(n=e._zod.def).when??(n.when=s=>{const r=s.value;return!zr(r)&&r.length!==void 0}),e._zod.onattach.push(s=>{const r=s._zod.bag.maximum??Number.POSITIVE_INFINITY;t.maximum<r&&(s._zod.bag.maximum=t.maximum)}),e._zod.check=s=>{const r=s.value;if(r.length<=t.maximum)return;const a=Dr(r);s.issues.push({origin:a,code:"too_big",maximum:t.maximum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),Ol=A("$ZodCheckMinLength",(e,t)=>{var n;lt.init(e,t),(n=e._zod.def).when??(n.when=s=>{const r=s.value;return!zr(r)&&r.length!==void 0}),e._zod.onattach.push(s=>{const r=s._zod.bag.minimum??Number.NEGATIVE_INFINITY;t.minimum>r&&(s._zod.bag.minimum=t.minimum)}),e._zod.check=s=>{const r=s.value;if(r.length>=t.minimum)return;const a=Dr(r);s.issues.push({origin:a,code:"too_small",minimum:t.minimum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),zl=A("$ZodCheckLengthEquals",(e,t)=>{var n;lt.init(e,t),(n=e._zod.def).when??(n.when=s=>{const r=s.value;return!zr(r)&&r.length!==void 0}),e._zod.onattach.push(s=>{const r=s._zod.bag;r.minimum=t.length,r.maximum=t.length,r.length=t.length}),e._zod.check=s=>{const r=s.value,i=r.length;if(i===t.length)return;const a=Dr(r),c=i>t.length;s.issues.push({origin:a,...c?{code:"too_big",maximum:t.length}:{code:"too_small",minimum:t.length},inclusive:!0,exact:!0,input:s.value,inst:e,continue:!t.abort})}}),Zs=A("$ZodCheckStringFormat",(e,t)=>{var n,s;lt.init(e,t),e._zod.onattach.push(r=>{const i=r._zod.bag;i.format=t.format,t.pattern&&(i.patterns??(i.patterns=new Set),i.patterns.add(t.pattern))}),t.pattern?(n=e._zod).check??(n.check=r=>{t.pattern.lastIndex=0,!t.pattern.test(r.value)&&r.issues.push({origin:"string",code:"invalid_format",format:t.format,input:r.value,...t.pattern?{pattern:t.pattern.toString()}:{},inst:e,continue:!t.abort})}):(s=e._zod).check??(s.check=()=>{})}),Nl=A("$ZodCheckRegex",(e,t)=>{Zs.init(e,t),e._zod.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:"string",code:"invalid_format",format:"regex",input:n.value,pattern:t.pattern.toString(),inst:e,continue:!t.abort})}}),Dl=A("$ZodCheckLowerCase",(e,t)=>{t.pattern??(t.pattern=Cl),Zs.init(e,t)}),jl=A("$ZodCheckUpperCase",(e,t)=>{t.pattern??(t.pattern=Ml),Zs.init(e,t)}),ql=A("$ZodCheckIncludes",(e,t)=>{lt.init(e,t);const n=Fs(t.includes),s=new RegExp(typeof t.position=="number"?`^.{${t.position}}${n}`:n);t.pattern=s,e._zod.onattach.push(r=>{const i=r._zod.bag;i.patterns??(i.patterns=new Set),i.patterns.add(s)}),e._zod.check=r=>{r.value.includes(t.includes,t.position)||r.issues.push({origin:"string",code:"invalid_format",format:"includes",includes:t.includes,input:r.value,inst:e,continue:!t.abort})}}),Fl=A("$ZodCheckStartsWith",(e,t)=>{lt.init(e,t);const n=new RegExp(`^${Fs(t.prefix)}.*`);t.pattern??(t.pattern=n),e._zod.onattach.push(s=>{const r=s._zod.bag;r.patterns??(r.patterns=new Set),r.patterns.add(n)}),e._zod.check=s=>{s.value.startsWith(t.prefix)||s.issues.push({origin:"string",code:"invalid_format",format:"starts_with",prefix:t.prefix,input:s.value,inst:e,continue:!t.abort})}}),Ul=A("$ZodCheckEndsWith",(e,t)=>{lt.init(e,t);const n=new RegExp(`.*${Fs(t.suffix)}$`);t.pattern??(t.pattern=n),e._zod.onattach.push(s=>{const r=s._zod.bag;r.patterns??(r.patterns=new Set),r.patterns.add(n)}),e._zod.check=s=>{s.value.endsWith(t.suffix)||s.issues.push({origin:"string",code:"invalid_format",format:"ends_with",suffix:t.suffix,input:s.value,inst:e,continue:!t.abort})}}),Vl=A("$ZodCheckOverwrite",(e,t)=>{lt.init(e,t),e._zod.check=n=>{n.value=t.tx(n.value)}});class Zl{constructor(t=[]){this.content=[],this.indent=0,this&&(this.args=t)}indented(t){this.indent+=1,t(this),this.indent-=1}write(t){if(typeof t=="function"){t(this,{execution:"sync"}),t(this,{execution:"async"});return}const s=t.split(`
|
|
2
|
+
`).filter(a=>a),r=Math.min(...s.map(a=>a.length-a.trimStart().length)),i=s.map(a=>a.slice(r)).map(a=>" ".repeat(this.indent*2)+a);for(const a of i)this.content.push(a)}compile(){const t=Function,n=this?.args,r=[...(this?.content??[""]).map(i=>` ${i}`)];return new t(...n,r.join(`
|
|
3
|
+
`))}}const Hl={major:4,minor:3,patch:6},Pe=A("$ZodType",(e,t)=>{var n;e??(e={}),e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=Hl;const s=[...e._zod.def.checks??[]];e._zod.traits.has("$ZodCheck")&&s.unshift(e);for(const r of s)for(const i of r._zod.onattach)i(e);if(s.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{const r=(a,c,l)=>{let d=wn(a),u;for(const m of c){if(m._zod.def.when){if(!m._zod.def.when(a))continue}else if(d)continue;const _=a.issues.length,b=m._zod.check(a);if(b instanceof Promise&&l?.async===!1)throw new kn;if(u||b instanceof Promise)u=(u??Promise.resolve()).then(async()=>{await b,a.issues.length!==_&&(d||(d=wn(a,_)))});else{if(a.issues.length===_)continue;d||(d=wn(a,_))}}return u?u.then(()=>a):a},i=(a,c,l)=>{if(wn(a))return a.aborted=!0,a;const d=r(c,s,l);if(d instanceof Promise){if(l.async===!1)throw new kn;return d.then(u=>e._zod.parse(u,l))}return e._zod.parse(d,l)};e._zod.run=(a,c)=>{if(c.skipChecks)return e._zod.parse(a,c);if(c.direction==="backward"){const d=e._zod.parse({value:a.value,issues:[]},{...c,skipChecks:!0});return d instanceof Promise?d.then(u=>i(u,a,c)):i(d,a,c)}const l=e._zod.parse(a,c);if(l instanceof Promise){if(c.async===!1)throw new kn;return l.then(d=>r(d,s,c))}return r(l,s,c)}}xe(e,"~standard",()=>({validate:r=>{try{const i=Yc(e,r);return i.success?{value:i.data}:{issues:i.error?.issues}}catch{return Xc(e,r).then(a=>a.success?{value:a.data}:{issues:a.error?.issues})}},vendor:"zod",version:1}))}),Fr=A("$ZodString",(e,t)=>{Pe.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??Tl(e._zod.bag),e._zod.parse=(n,s)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value=="string"||n.issues.push({expected:"string",code:"invalid_type",input:n.value,inst:e}),n}}),Ae=A("$ZodStringFormat",(e,t)=>{Zs.init(e,t),Fr.init(e,t)}),Bl=A("$ZodGUID",(e,t)=>{t.pattern??(t.pattern=fl),Ae.init(e,t)}),Jl=A("$ZodUUID",(e,t)=>{if(t.version){const s={v1:1,v2:2,v3:3,v4:4,v5:5,v6:6,v7:7,v8:8}[t.version];if(s===void 0)throw new Error(`Invalid UUID version: "${t.version}"`);t.pattern??(t.pattern=wi(s))}else t.pattern??(t.pattern=wi());Ae.init(e,t)}),Kl=A("$ZodEmail",(e,t)=>{t.pattern??(t.pattern=hl),Ae.init(e,t)}),Gl=A("$ZodURL",(e,t)=>{Ae.init(e,t),e._zod.check=n=>{try{const s=n.value.trim(),r=new URL(s);t.hostname&&(t.hostname.lastIndex=0,t.hostname.test(r.hostname)||n.issues.push({code:"invalid_format",format:"url",note:"Invalid hostname",pattern:t.hostname.source,input:n.value,inst:e,continue:!t.abort})),t.protocol&&(t.protocol.lastIndex=0,t.protocol.test(r.protocol.endsWith(":")?r.protocol.slice(0,-1):r.protocol)||n.issues.push({code:"invalid_format",format:"url",note:"Invalid protocol",pattern:t.protocol.source,input:n.value,inst:e,continue:!t.abort})),t.normalize?n.value=r.href:n.value=s;return}catch{n.issues.push({code:"invalid_format",format:"url",input:n.value,inst:e,continue:!t.abort})}}}),Wl=A("$ZodEmoji",(e,t)=>{t.pattern??(t.pattern=vl()),Ae.init(e,t)}),Yl=A("$ZodNanoID",(e,t)=>{t.pattern??(t.pattern=pl),Ae.init(e,t)}),Xl=A("$ZodCUID",(e,t)=>{t.pattern??(t.pattern=ol),Ae.init(e,t)}),Ql=A("$ZodCUID2",(e,t)=>{t.pattern??(t.pattern=cl),Ae.init(e,t)}),ed=A("$ZodULID",(e,t)=>{t.pattern??(t.pattern=ll),Ae.init(e,t)}),td=A("$ZodXID",(e,t)=>{t.pattern??(t.pattern=dl),Ae.init(e,t)}),nd=A("$ZodKSUID",(e,t)=>{t.pattern??(t.pattern=ul),Ae.init(e,t)}),sd=A("$ZodISODateTime",(e,t)=>{t.pattern??(t.pattern=El(t)),Ae.init(e,t)}),rd=A("$ZodISODate",(e,t)=>{t.pattern??(t.pattern=xl),Ae.init(e,t)}),id=A("$ZodISOTime",(e,t)=>{t.pattern??(t.pattern=$l(t)),Ae.init(e,t)}),ad=A("$ZodISODuration",(e,t)=>{t.pattern??(t.pattern=ml),Ae.init(e,t)}),od=A("$ZodIPv4",(e,t)=>{t.pattern??(t.pattern=yl),Ae.init(e,t),e._zod.bag.format="ipv4"}),cd=A("$ZodIPv6",(e,t)=>{t.pattern??(t.pattern=bl),Ae.init(e,t),e._zod.bag.format="ipv6",e._zod.check=n=>{try{new URL(`http://[${n.value}]`)}catch{n.issues.push({code:"invalid_format",format:"ipv6",input:n.value,inst:e,continue:!t.abort})}}}),ld=A("$ZodCIDRv4",(e,t)=>{t.pattern??(t.pattern=wl),Ae.init(e,t)}),dd=A("$ZodCIDRv6",(e,t)=>{t.pattern??(t.pattern=Sl),Ae.init(e,t),e._zod.check=n=>{const s=n.value.split("/");try{if(s.length!==2)throw new Error;const[r,i]=s;if(!i)throw new Error;const a=Number(i);if(`${a}`!==i)throw new Error;if(a<0||a>128)throw new Error;new URL(`http://[${r}]`)}catch{n.issues.push({code:"invalid_format",format:"cidrv6",input:n.value,inst:e,continue:!t.abort})}}});function ja(e){if(e==="")return!0;if(e.length%4!==0)return!1;try{return atob(e),!0}catch{return!1}}const ud=A("$ZodBase64",(e,t)=>{t.pattern??(t.pattern=_l),Ae.init(e,t),e._zod.bag.contentEncoding="base64",e._zod.check=n=>{ja(n.value)||n.issues.push({code:"invalid_format",format:"base64",input:n.value,inst:e,continue:!t.abort})}});function pd(e){if(!Ra.test(e))return!1;const t=e.replace(/[-_]/g,s=>s==="-"?"+":"/"),n=t.padEnd(Math.ceil(t.length/4)*4,"=");return ja(n)}const md=A("$ZodBase64URL",(e,t)=>{t.pattern??(t.pattern=Ra),Ae.init(e,t),e._zod.bag.contentEncoding="base64url",e._zod.check=n=>{pd(n.value)||n.issues.push({code:"invalid_format",format:"base64url",input:n.value,inst:e,continue:!t.abort})}}),fd=A("$ZodE164",(e,t)=>{t.pattern??(t.pattern=kl),Ae.init(e,t)});function hd(e,t=null){try{const n=e.split(".");if(n.length!==3)return!1;const[s]=n;if(!s)return!1;const r=JSON.parse(atob(s));return!("typ"in r&&r?.typ!=="JWT"||!r.alg||t&&(!("alg"in r)||r.alg!==t))}catch{return!1}}const gd=A("$ZodJWT",(e,t)=>{Ae.init(e,t),e._zod.check=n=>{hd(n.value,t.alg)||n.issues.push({code:"invalid_format",format:"jwt",input:n.value,inst:e,continue:!t.abort})}}),qa=A("$ZodNumber",(e,t)=>{Pe.init(e,t),e._zod.pattern=e._zod.bag.pattern??Oa,e._zod.parse=(n,s)=>{if(t.coerce)try{n.value=Number(n.value)}catch{}const r=n.value;if(typeof r=="number"&&!Number.isNaN(r)&&Number.isFinite(r))return n;const i=typeof r=="number"?Number.isNaN(r)?"NaN":Number.isFinite(r)?void 0:"Infinity":void 0;return n.issues.push({expected:"number",code:"invalid_type",input:r,inst:e,...i?{received:i}:{}}),n}}),vd=A("$ZodNumberFormat",(e,t)=>{Pl.init(e,t),qa.init(e,t)}),yd=A("$ZodBoolean",(e,t)=>{Pe.init(e,t),e._zod.pattern=Il,e._zod.parse=(n,s)=>{if(t.coerce)try{n.value=!!n.value}catch{}const r=n.value;return typeof r=="boolean"||n.issues.push({expected:"boolean",code:"invalid_type",input:r,inst:e}),n}}),bd=A("$ZodAny",(e,t)=>{Pe.init(e,t),e._zod.parse=n=>n}),wd=A("$ZodUnknown",(e,t)=>{Pe.init(e,t),e._zod.parse=n=>n}),Sd=A("$ZodNever",(e,t)=>{Pe.init(e,t),e._zod.parse=(n,s)=>(n.issues.push({expected:"never",code:"invalid_type",input:n.value,inst:e}),n)});function Si(e,t,n){e.issues.length&&t.issues.push(...Sn(n,e.issues)),t.value[n]=e.value}const _d=A("$ZodArray",(e,t)=>{Pe.init(e,t),e._zod.parse=(n,s)=>{const r=n.value;if(!Array.isArray(r))return n.issues.push({expected:"array",code:"invalid_type",input:r,inst:e}),n;n.value=Array(r.length);const i=[];for(let a=0;a<r.length;a++){const c=r[a],l=t.element._zod.run({value:c,issues:[]},s);l instanceof Promise?i.push(l.then(d=>Si(d,n,a))):Si(l,n,a)}return i.length?Promise.all(i).then(()=>n):n}});function Is(e,t,n,s,r){if(e.issues.length){if(r&&!(n in s))return;t.issues.push(...Sn(n,e.issues))}e.value===void 0?n in s&&(t.value[n]=void 0):t.value[n]=e.value}function Fa(e){const t=Object.keys(e.shape);for(const s of t)if(!e.shape?.[s]?._zod?.traits?.has("$ZodType"))throw new Error(`Invalid element at key "${s}": expected a Zod schema`);const n=qc(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function Ua(e,t,n,s,r,i){const a=[],c=r.keySet,l=r.catchall._zod,d=l.def.type,u=l.optout==="optional";for(const m in t){if(c.has(m))continue;if(d==="never"){a.push(m);continue}const _=l.run({value:t[m],issues:[]},s);_ instanceof Promise?e.push(_.then(b=>Is(b,n,m,t,u))):Is(_,n,m,t,u)}return a.length&&n.issues.push({code:"unrecognized_keys",keys:a,input:t,inst:i}),e.length?Promise.all(e).then(()=>n):n}const kd=A("$ZodObject",(e,t)=>{if(Pe.init(e,t),!Object.getOwnPropertyDescriptor(t,"shape")?.get){const c=t.shape;Object.defineProperty(t,"shape",{get:()=>{const l={...c};return Object.defineProperty(t,"shape",{value:l}),l}})}const s=Or(()=>Fa(t));xe(e._zod,"propValues",()=>{const c=t.shape,l={};for(const d in c){const u=c[d]._zod;if(u.values){l[d]??(l[d]=new Set);for(const m of u.values)l[d].add(m)}}return l});const r=As,i=t.catchall;let a;e._zod.parse=(c,l)=>{a??(a=s.value);const d=c.value;if(!r(d))return c.issues.push({expected:"object",code:"invalid_type",input:d,inst:e}),c;c.value={};const u=[],m=a.shape;for(const _ of a.keys){const b=m[_],x=b._zod.optout==="optional",y=b._zod.run({value:d[_],issues:[]},l);y instanceof Promise?u.push(y.then(I=>Is(I,c,_,d,x))):Is(y,c,_,d,x)}return i?Ua(u,d,c,l,s.value,e):u.length?Promise.all(u).then(()=>c):c}}),xd=A("$ZodObjectJIT",(e,t)=>{kd.init(e,t);const n=e._zod.parse,s=Or(()=>Fa(t)),r=_=>{const b=new Zl(["shape","payload","ctx"]),x=s.value,y=O=>{const P=bi(O);return`shape[${P}]._zod.run({ value: input[${P}], issues: [] }, ctx)`};b.write("const input = payload.value;");const I=Object.create(null);let g=0;for(const O of x.keys)I[O]=`key_${g++}`;b.write("const newResult = {};");for(const O of x.keys){const P=I[O],j=bi(O),N=_[O]?._zod?.optout==="optional";b.write(`const ${P} = ${y(O)};`),N?b.write(`
|
|
4
|
+
if (${P}.issues.length) {
|
|
5
|
+
if (${j} in input) {
|
|
6
|
+
payload.issues = payload.issues.concat(${P}.issues.map(iss => ({
|
|
7
|
+
...iss,
|
|
8
|
+
path: iss.path ? [${j}, ...iss.path] : [${j}]
|
|
9
|
+
})));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (${P}.value === undefined) {
|
|
14
|
+
if (${j} in input) {
|
|
15
|
+
newResult[${j}] = undefined;
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
newResult[${j}] = ${P}.value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
`):b.write(`
|
|
22
|
+
if (${P}.issues.length) {
|
|
23
|
+
payload.issues = payload.issues.concat(${P}.issues.map(iss => ({
|
|
24
|
+
...iss,
|
|
25
|
+
path: iss.path ? [${j}, ...iss.path] : [${j}]
|
|
26
|
+
})));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (${P}.value === undefined) {
|
|
30
|
+
if (${j} in input) {
|
|
31
|
+
newResult[${j}] = undefined;
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
newResult[${j}] = ${P}.value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
`)}b.write("payload.value = newResult;"),b.write("return payload;");const C=b.compile();return(O,P)=>C(_,O,P)};let i;const a=As,c=!$a.jitless,d=c&&Dc.value,u=t.catchall;let m;e._zod.parse=(_,b)=>{m??(m=s.value);const x=_.value;return a(x)?c&&d&&b?.async===!1&&b.jitless!==!0?(i||(i=r(t.shape)),_=i(_,b),u?Ua([],x,_,b,m,e):_):n(_,b):(_.issues.push({expected:"object",code:"invalid_type",input:x,inst:e}),_)}});function _i(e,t,n,s){for(const i of e)if(i.issues.length===0)return t.value=i.value,t;const r=e.filter(i=>!wn(i));return r.length===1?(t.value=r[0].value,r[0]):(t.issues.push({code:"invalid_union",input:t.value,inst:n,errors:e.map(i=>i.issues.map(a=>Ut(a,s,Ft())))}),t)}const $d=A("$ZodUnion",(e,t)=>{Pe.init(e,t),xe(e._zod,"optin",()=>t.options.some(r=>r._zod.optin==="optional")?"optional":void 0),xe(e._zod,"optout",()=>t.options.some(r=>r._zod.optout==="optional")?"optional":void 0),xe(e._zod,"values",()=>{if(t.options.every(r=>r._zod.values))return new Set(t.options.flatMap(r=>Array.from(r._zod.values)))}),xe(e._zod,"pattern",()=>{if(t.options.every(r=>r._zod.pattern)){const r=t.options.map(i=>i._zod.pattern);return new RegExp(`^(${r.map(i=>Nr(i.source)).join("|")})$`)}});const n=t.options.length===1,s=t.options[0]._zod.run;e._zod.parse=(r,i)=>{if(n)return s(r,i);let a=!1;const c=[];for(const l of t.options){const d=l._zod.run({value:r.value,issues:[]},i);if(d instanceof Promise)c.push(d),a=!0;else{if(d.issues.length===0)return d;c.push(d)}}return a?Promise.all(c).then(l=>_i(l,r,e,i)):_i(c,r,e,i)}}),Ed=A("$ZodIntersection",(e,t)=>{Pe.init(e,t),e._zod.parse=(n,s)=>{const r=n.value,i=t.left._zod.run({value:r,issues:[]},s),a=t.right._zod.run({value:r,issues:[]},s);return i instanceof Promise||a instanceof Promise?Promise.all([i,a]).then(([l,d])=>ki(n,l,d)):ki(n,i,a)}});function gr(e,t){if(e===t)return{valid:!0,data:e};if(e instanceof Date&&t instanceof Date&&+e==+t)return{valid:!0,data:e};if($n(e)&&$n(t)){const n=Object.keys(t),s=Object.keys(e).filter(i=>n.indexOf(i)!==-1),r={...e,...t};for(const i of s){const a=gr(e[i],t[i]);if(!a.valid)return{valid:!1,mergeErrorPath:[i,...a.mergeErrorPath]};r[i]=a.data}return{valid:!0,data:r}}if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return{valid:!1,mergeErrorPath:[]};const n=[];for(let s=0;s<e.length;s++){const r=e[s],i=t[s],a=gr(r,i);if(!a.valid)return{valid:!1,mergeErrorPath:[s,...a.mergeErrorPath]};n.push(a.data)}return{valid:!0,data:n}}return{valid:!1,mergeErrorPath:[]}}function ki(e,t,n){const s=new Map;let r;for(const c of t.issues)if(c.code==="unrecognized_keys"){r??(r=c);for(const l of c.keys)s.has(l)||s.set(l,{}),s.get(l).l=!0}else e.issues.push(c);for(const c of n.issues)if(c.code==="unrecognized_keys")for(const l of c.keys)s.has(l)||s.set(l,{}),s.get(l).r=!0;else e.issues.push(c);const i=[...s].filter(([,c])=>c.l&&c.r).map(([c])=>c);if(i.length&&r&&e.issues.push({...r,keys:i}),wn(e))return e;const a=gr(t.value,n.value);if(!a.valid)throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(a.mergeErrorPath)}`);return e.value=a.data,e}const Td=A("$ZodRecord",(e,t)=>{Pe.init(e,t),e._zod.parse=(n,s)=>{const r=n.value;if(!$n(r))return n.issues.push({expected:"record",code:"invalid_type",input:r,inst:e}),n;const i=[],a=t.keyType._zod.values;if(a){n.value={};const c=new Set;for(const d of a)if(typeof d=="string"||typeof d=="number"||typeof d=="symbol"){c.add(typeof d=="number"?d.toString():d);const u=t.valueType._zod.run({value:r[d],issues:[]},s);u instanceof Promise?i.push(u.then(m=>{m.issues.length&&n.issues.push(...Sn(d,m.issues)),n.value[d]=m.value})):(u.issues.length&&n.issues.push(...Sn(d,u.issues)),n.value[d]=u.value)}let l;for(const d in r)c.has(d)||(l=l??[],l.push(d));l&&l.length>0&&n.issues.push({code:"unrecognized_keys",input:r,inst:e,keys:l})}else{n.value={};for(const c of Reflect.ownKeys(r)){if(c==="__proto__")continue;let l=t.keyType._zod.run({value:c,issues:[]},s);if(l instanceof Promise)throw new Error("Async schemas not supported in object keys currently");if(typeof c=="string"&&Oa.test(c)&&l.issues.length){const m=t.keyType._zod.run({value:Number(c),issues:[]},s);if(m instanceof Promise)throw new Error("Async schemas not supported in object keys currently");m.issues.length===0&&(l=m)}if(l.issues.length){t.mode==="loose"?n.value[c]=r[c]:n.issues.push({code:"invalid_key",origin:"record",issues:l.issues.map(m=>Ut(m,s,Ft())),input:c,path:[c],inst:e});continue}const u=t.valueType._zod.run({value:r[c],issues:[]},s);u instanceof Promise?i.push(u.then(m=>{m.issues.length&&n.issues.push(...Sn(c,m.issues)),n.value[l.value]=m.value})):(u.issues.length&&n.issues.push(...Sn(c,u.issues)),n.value[l.value]=u.value)}}return i.length?Promise.all(i).then(()=>n):n}}),Ad=A("$ZodEnum",(e,t)=>{Pe.init(e,t);const n=Ea(t.entries),s=new Set(n);e._zod.values=s,e._zod.pattern=new RegExp(`^(${n.filter(r=>jc.has(typeof r)).map(r=>typeof r=="string"?Fs(r):r.toString()).join("|")})$`),e._zod.parse=(r,i)=>{const a=r.value;return s.has(a)||r.issues.push({code:"invalid_value",values:n,input:a,inst:e}),r}}),Id=A("$ZodTransform",(e,t)=>{Pe.init(e,t),e._zod.parse=(n,s)=>{if(s.direction==="backward")throw new xa(e.constructor.name);const r=t.transform(n.value,n);if(s.async)return(r instanceof Promise?r:Promise.resolve(r)).then(a=>(n.value=a,n));if(r instanceof Promise)throw new kn;return n.value=r,n}});function xi(e,t){return e.issues.length&&t===void 0?{issues:[],value:void 0}:e}const Va=A("$ZodOptional",(e,t)=>{Pe.init(e,t),e._zod.optin="optional",e._zod.optout="optional",xe(e._zod,"values",()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),xe(e._zod,"pattern",()=>{const n=t.innerType._zod.pattern;return n?new RegExp(`^(${Nr(n.source)})?$`):void 0}),e._zod.parse=(n,s)=>{if(t.innerType._zod.optin==="optional"){const r=t.innerType._zod.run(n,s);return r instanceof Promise?r.then(i=>xi(i,n.value)):xi(r,n.value)}return n.value===void 0?n:t.innerType._zod.run(n,s)}}),Cd=A("$ZodExactOptional",(e,t)=>{Va.init(e,t),xe(e._zod,"values",()=>t.innerType._zod.values),xe(e._zod,"pattern",()=>t.innerType._zod.pattern),e._zod.parse=(n,s)=>t.innerType._zod.run(n,s)}),Md=A("$ZodNullable",(e,t)=>{Pe.init(e,t),xe(e._zod,"optin",()=>t.innerType._zod.optin),xe(e._zod,"optout",()=>t.innerType._zod.optout),xe(e._zod,"pattern",()=>{const n=t.innerType._zod.pattern;return n?new RegExp(`^(${Nr(n.source)}|null)$`):void 0}),xe(e._zod,"values",()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,null]):void 0),e._zod.parse=(n,s)=>n.value===null?n:t.innerType._zod.run(n,s)}),Rd=A("$ZodDefault",(e,t)=>{Pe.init(e,t),e._zod.optin="optional",xe(e._zod,"values",()=>t.innerType._zod.values),e._zod.parse=(n,s)=>{if(s.direction==="backward")return t.innerType._zod.run(n,s);if(n.value===void 0)return n.value=t.defaultValue,n;const r=t.innerType._zod.run(n,s);return r instanceof Promise?r.then(i=>$i(i,t)):$i(r,t)}});function $i(e,t){return e.value===void 0&&(e.value=t.defaultValue),e}const Pd=A("$ZodPrefault",(e,t)=>{Pe.init(e,t),e._zod.optin="optional",xe(e._zod,"values",()=>t.innerType._zod.values),e._zod.parse=(n,s)=>(s.direction==="backward"||n.value===void 0&&(n.value=t.defaultValue),t.innerType._zod.run(n,s))}),Ld=A("$ZodNonOptional",(e,t)=>{Pe.init(e,t),xe(e._zod,"values",()=>{const n=t.innerType._zod.values;return n?new Set([...n].filter(s=>s!==void 0)):void 0}),e._zod.parse=(n,s)=>{const r=t.innerType._zod.run(n,s);return r instanceof Promise?r.then(i=>Ei(i,e)):Ei(r,e)}});function Ei(e,t){return!e.issues.length&&e.value===void 0&&e.issues.push({code:"invalid_type",expected:"nonoptional",input:e.value,inst:t}),e}const Od=A("$ZodCatch",(e,t)=>{Pe.init(e,t),xe(e._zod,"optin",()=>t.innerType._zod.optin),xe(e._zod,"optout",()=>t.innerType._zod.optout),xe(e._zod,"values",()=>t.innerType._zod.values),e._zod.parse=(n,s)=>{if(s.direction==="backward")return t.innerType._zod.run(n,s);const r=t.innerType._zod.run(n,s);return r instanceof Promise?r.then(i=>(n.value=i.value,i.issues.length&&(n.value=t.catchValue({...n,error:{issues:i.issues.map(a=>Ut(a,s,Ft()))},input:n.value}),n.issues=[]),n)):(n.value=r.value,r.issues.length&&(n.value=t.catchValue({...n,error:{issues:r.issues.map(i=>Ut(i,s,Ft()))},input:n.value}),n.issues=[]),n)}}),zd=A("$ZodPipe",(e,t)=>{Pe.init(e,t),xe(e._zod,"values",()=>t.in._zod.values),xe(e._zod,"optin",()=>t.in._zod.optin),xe(e._zod,"optout",()=>t.out._zod.optout),xe(e._zod,"propValues",()=>t.in._zod.propValues),e._zod.parse=(n,s)=>{if(s.direction==="backward"){const i=t.out._zod.run(n,s);return i instanceof Promise?i.then(a=>bs(a,t.in,s)):bs(i,t.in,s)}const r=t.in._zod.run(n,s);return r instanceof Promise?r.then(i=>bs(i,t.out,s)):bs(r,t.out,s)}});function bs(e,t,n){return e.issues.length?(e.aborted=!0,e):t._zod.run({value:e.value,issues:e.issues},n)}const Nd=A("$ZodReadonly",(e,t)=>{Pe.init(e,t),xe(e._zod,"propValues",()=>t.innerType._zod.propValues),xe(e._zod,"values",()=>t.innerType._zod.values),xe(e._zod,"optin",()=>t.innerType?._zod?.optin),xe(e._zod,"optout",()=>t.innerType?._zod?.optout),e._zod.parse=(n,s)=>{if(s.direction==="backward")return t.innerType._zod.run(n,s);const r=t.innerType._zod.run(n,s);return r instanceof Promise?r.then(Ti):Ti(r)}});function Ti(e){return e.value=Object.freeze(e.value),e}const Dd=A("$ZodCustom",(e,t)=>{lt.init(e,t),Pe.init(e,t),e._zod.parse=(n,s)=>n,e._zod.check=n=>{const s=n.value,r=t.fn(s);if(r instanceof Promise)return r.then(i=>Ai(i,n,s,e));Ai(r,n,s,e)}});function Ai(e,t,n,s){if(!e){const r={code:"custom",input:n,inst:s,path:[...s._zod.def.path??[]],continue:!s._zod.def.abort};s._zod.def.params&&(r.params=s._zod.def.params),t.issues.push(Kn(r))}}var Ii;class jd{constructor(){this._map=new WeakMap,this._idmap=new Map}add(t,...n){const s=n[0];return this._map.set(t,s),s&&typeof s=="object"&&"id"in s&&this._idmap.set(s.id,t),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(t){const n=this._map.get(t);return n&&typeof n=="object"&&"id"in n&&this._idmap.delete(n.id),this._map.delete(t),this}get(t){const n=t._zod.parent;if(n){const s={...this.get(n)??{}};delete s.id;const r={...s,...this._map.get(t)};return Object.keys(r).length?r:void 0}return this._map.get(t)}has(t){return this._map.has(t)}}function qd(){return new jd}(Ii=globalThis).__zod_globalRegistry??(Ii.__zod_globalRegistry=qd());const Zn=globalThis.__zod_globalRegistry;function Fd(e,t){return new e({type:"string",...te(t)})}function Ud(e,t){return new e({type:"string",format:"email",check:"string_format",abort:!1,...te(t)})}function Ci(e,t){return new e({type:"string",format:"guid",check:"string_format",abort:!1,...te(t)})}function Vd(e,t){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,...te(t)})}function Zd(e,t){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v4",...te(t)})}function Hd(e,t){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v6",...te(t)})}function Bd(e,t){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v7",...te(t)})}function Jd(e,t){return new e({type:"string",format:"url",check:"string_format",abort:!1,...te(t)})}function Kd(e,t){return new e({type:"string",format:"emoji",check:"string_format",abort:!1,...te(t)})}function Gd(e,t){return new e({type:"string",format:"nanoid",check:"string_format",abort:!1,...te(t)})}function Wd(e,t){return new e({type:"string",format:"cuid",check:"string_format",abort:!1,...te(t)})}function Yd(e,t){return new e({type:"string",format:"cuid2",check:"string_format",abort:!1,...te(t)})}function Xd(e,t){return new e({type:"string",format:"ulid",check:"string_format",abort:!1,...te(t)})}function Qd(e,t){return new e({type:"string",format:"xid",check:"string_format",abort:!1,...te(t)})}function eu(e,t){return new e({type:"string",format:"ksuid",check:"string_format",abort:!1,...te(t)})}function tu(e,t){return new e({type:"string",format:"ipv4",check:"string_format",abort:!1,...te(t)})}function nu(e,t){return new e({type:"string",format:"ipv6",check:"string_format",abort:!1,...te(t)})}function su(e,t){return new e({type:"string",format:"cidrv4",check:"string_format",abort:!1,...te(t)})}function ru(e,t){return new e({type:"string",format:"cidrv6",check:"string_format",abort:!1,...te(t)})}function iu(e,t){return new e({type:"string",format:"base64",check:"string_format",abort:!1,...te(t)})}function au(e,t){return new e({type:"string",format:"base64url",check:"string_format",abort:!1,...te(t)})}function ou(e,t){return new e({type:"string",format:"e164",check:"string_format",abort:!1,...te(t)})}function cu(e,t){return new e({type:"string",format:"jwt",check:"string_format",abort:!1,...te(t)})}function lu(e,t){return new e({type:"string",format:"datetime",check:"string_format",offset:!1,local:!1,precision:null,...te(t)})}function du(e,t){return new e({type:"string",format:"date",check:"string_format",...te(t)})}function uu(e,t){return new e({type:"string",format:"time",check:"string_format",precision:null,...te(t)})}function pu(e,t){return new e({type:"string",format:"duration",check:"string_format",...te(t)})}function mu(e,t){return new e({type:"number",checks:[],...te(t)})}function fu(e,t){return new e({type:"number",check:"number_format",abort:!1,format:"safeint",...te(t)})}function hu(e,t){return new e({type:"boolean",...te(t)})}function gu(e){return new e({type:"any"})}function vu(e){return new e({type:"unknown"})}function yu(e,t){return new e({type:"never",...te(t)})}function Mi(e,t){return new Na({check:"less_than",...te(t),value:e,inclusive:!1})}function rr(e,t){return new Na({check:"less_than",...te(t),value:e,inclusive:!0})}function Ri(e,t){return new Da({check:"greater_than",...te(t),value:e,inclusive:!1})}function ir(e,t){return new Da({check:"greater_than",...te(t),value:e,inclusive:!0})}function Pi(e,t){return new Rl({check:"multiple_of",...te(t),value:e})}function Za(e,t){return new Ll({check:"max_length",...te(t),maximum:e})}function Cs(e,t){return new Ol({check:"min_length",...te(t),minimum:e})}function Ha(e,t){return new zl({check:"length_equals",...te(t),length:e})}function bu(e,t){return new Nl({check:"string_format",format:"regex",...te(t),pattern:e})}function wu(e){return new Dl({check:"string_format",format:"lowercase",...te(e)})}function Su(e){return new jl({check:"string_format",format:"uppercase",...te(e)})}function _u(e,t){return new ql({check:"string_format",format:"includes",...te(t),includes:e})}function ku(e,t){return new Fl({check:"string_format",format:"starts_with",...te(t),prefix:e})}function xu(e,t){return new Ul({check:"string_format",format:"ends_with",...te(t),suffix:e})}function In(e){return new Vl({check:"overwrite",tx:e})}function $u(e){return In(t=>t.normalize(e))}function Eu(){return In(e=>e.trim())}function Tu(){return In(e=>e.toLowerCase())}function Au(){return In(e=>e.toUpperCase())}function Iu(){return In(e=>Nc(e))}function Cu(e,t,n){return new e({type:"array",element:t,...te(n)})}function Mu(e,t,n){return new e({type:"custom",check:"custom",fn:t,...te(n)})}function Ru(e){const t=Pu(n=>(n.addIssue=s=>{if(typeof s=="string")n.issues.push(Kn(s,n.value,t._zod.def));else{const r=s;r.fatal&&(r.continue=!1),r.code??(r.code="custom"),r.input??(r.input=n.value),r.inst??(r.inst=t),r.continue??(r.continue=!t._zod.def.abort),n.issues.push(Kn(r))}},e(n.value,n)));return t}function Pu(e,t){const n=new lt({check:"custom",...te(t)});return n._zod.check=e,n}function Ba(e){let t=e?.target??"draft-2020-12";return t==="draft-4"&&(t="draft-04"),t==="draft-7"&&(t="draft-07"),{processors:e.processors??{},metadataRegistry:e?.metadata??Zn,target:t,unrepresentable:e?.unrepresentable??"throw",override:e?.override??(()=>{}),io:e?.io??"output",counter:0,seen:new Map,cycles:e?.cycles??"ref",reused:e?.reused??"inline",external:e?.external??void 0}}function Ve(e,t,n={path:[],schemaPath:[]}){var s;const r=e._zod.def,i=t.seen.get(e);if(i)return i.count++,n.schemaPath.includes(e)&&(i.cycle=n.path),i.schema;const a={schema:{},count:1,cycle:void 0,path:n.path};t.seen.set(e,a);const c=e._zod.toJSONSchema?.();if(c)a.schema=c;else{const u={...n,schemaPath:[...n.schemaPath,e],path:n.path};if(e._zod.processJSONSchema)e._zod.processJSONSchema(t,a.schema,u);else{const _=a.schema,b=t.processors[r.type];if(!b)throw new Error(`[toJSONSchema]: Non-representable type encountered: ${r.type}`);b(e,t,_,u)}const m=e._zod.parent;m&&(a.ref||(a.ref=m),Ve(m,t,u),t.seen.get(m).isParent=!0)}const l=t.metadataRegistry.get(e);return l&&Object.assign(a.schema,l),t.io==="input"&&rt(e)&&(delete a.schema.examples,delete a.schema.default),t.io==="input"&&a.schema._prefault&&((s=a.schema).default??(s.default=a.schema._prefault)),delete a.schema._prefault,t.seen.get(e).schema}function Ja(e,t){const n=e.seen.get(t);if(!n)throw new Error("Unprocessed schema. This is a bug in Zod.");const s=new Map;for(const a of e.seen.entries()){const c=e.metadataRegistry.get(a[0])?.id;if(c){const l=s.get(c);if(l&&l!==a[0])throw new Error(`Duplicate schema id "${c}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);s.set(c,a[0])}}const r=a=>{const c=e.target==="draft-2020-12"?"$defs":"definitions";if(e.external){const m=e.external.registry.get(a[0])?.id,_=e.external.uri??(x=>x);if(m)return{ref:_(m)};const b=a[1].defId??a[1].schema.id??`schema${e.counter++}`;return a[1].defId=b,{defId:b,ref:`${_("__shared")}#/${c}/${b}`}}if(a[1]===n)return{ref:"#"};const d=`#/${c}/`,u=a[1].schema.id??`__schema${e.counter++}`;return{defId:u,ref:d+u}},i=a=>{if(a[1].schema.$ref)return;const c=a[1],{ref:l,defId:d}=r(a);c.def={...c.schema},d&&(c.defId=d);const u=c.schema;for(const m in u)delete u[m];u.$ref=l};if(e.cycles==="throw")for(const a of e.seen.entries()){const c=a[1];if(c.cycle)throw new Error(`Cycle detected: #/${c.cycle?.join("/")}/<root>
|
|
38
|
+
|
|
39
|
+
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(const a of e.seen.entries()){const c=a[1];if(t===a[0]){i(a);continue}if(e.external){const d=e.external.registry.get(a[0])?.id;if(t!==a[0]&&d){i(a);continue}}if(e.metadataRegistry.get(a[0])?.id){i(a);continue}if(c.cycle){i(a);continue}if(c.count>1&&e.reused==="ref"){i(a);continue}}}function Ka(e,t){const n=e.seen.get(t);if(!n)throw new Error("Unprocessed schema. This is a bug in Zod.");const s=a=>{const c=e.seen.get(a);if(c.ref===null)return;const l=c.def??c.schema,d={...l},u=c.ref;if(c.ref=null,u){s(u);const _=e.seen.get(u),b=_.schema;if(b.$ref&&(e.target==="draft-07"||e.target==="draft-04"||e.target==="openapi-3.0")?(l.allOf=l.allOf??[],l.allOf.push(b)):Object.assign(l,b),Object.assign(l,d),a._zod.parent===u)for(const y in l)y==="$ref"||y==="allOf"||y in d||delete l[y];if(b.$ref&&_.def)for(const y in l)y==="$ref"||y==="allOf"||y in _.def&&JSON.stringify(l[y])===JSON.stringify(_.def[y])&&delete l[y]}const m=a._zod.parent;if(m&&m!==u){s(m);const _=e.seen.get(m);if(_?.schema.$ref&&(l.$ref=_.schema.$ref,_.def))for(const b in l)b==="$ref"||b==="allOf"||b in _.def&&JSON.stringify(l[b])===JSON.stringify(_.def[b])&&delete l[b]}e.override({zodSchema:a,jsonSchema:l,path:c.path??[]})};for(const a of[...e.seen.entries()].reverse())s(a[0]);const r={};if(e.target==="draft-2020-12"?r.$schema="https://json-schema.org/draft/2020-12/schema":e.target==="draft-07"?r.$schema="http://json-schema.org/draft-07/schema#":e.target==="draft-04"?r.$schema="http://json-schema.org/draft-04/schema#":e.target,e.external?.uri){const a=e.external.registry.get(t)?.id;if(!a)throw new Error("Schema is missing an `id` property");r.$id=e.external.uri(a)}Object.assign(r,n.def??n.schema);const i=e.external?.defs??{};for(const a of e.seen.entries()){const c=a[1];c.def&&c.defId&&(i[c.defId]=c.def)}e.external||Object.keys(i).length>0&&(e.target==="draft-2020-12"?r.$defs=i:r.definitions=i);try{const a=JSON.parse(JSON.stringify(r));return Object.defineProperty(a,"~standard",{value:{...t["~standard"],jsonSchema:{input:Ms(t,"input",e.processors),output:Ms(t,"output",e.processors)}},enumerable:!1,writable:!1}),a}catch{throw new Error("Error converting schema to JSON.")}}function rt(e,t){const n=t??{seen:new Set};if(n.seen.has(e))return!1;n.seen.add(e);const s=e._zod.def;if(s.type==="transform")return!0;if(s.type==="array")return rt(s.element,n);if(s.type==="set")return rt(s.valueType,n);if(s.type==="lazy")return rt(s.getter(),n);if(s.type==="promise"||s.type==="optional"||s.type==="nonoptional"||s.type==="nullable"||s.type==="readonly"||s.type==="default"||s.type==="prefault")return rt(s.innerType,n);if(s.type==="intersection")return rt(s.left,n)||rt(s.right,n);if(s.type==="record"||s.type==="map")return rt(s.keyType,n)||rt(s.valueType,n);if(s.type==="pipe")return rt(s.in,n)||rt(s.out,n);if(s.type==="object"){for(const r in s.shape)if(rt(s.shape[r],n))return!0;return!1}if(s.type==="union"){for(const r of s.options)if(rt(r,n))return!0;return!1}if(s.type==="tuple"){for(const r of s.items)if(rt(r,n))return!0;return!!(s.rest&&rt(s.rest,n))}return!1}const Lu=(e,t={})=>n=>{const s=Ba({...n,processors:t});return Ve(e,s),Ja(s,e),Ka(s,e)},Ms=(e,t,n={})=>s=>{const{libraryOptions:r,target:i}=s??{},a=Ba({...r??{},target:i,io:t,processors:n});return Ve(e,a),Ja(a,e),Ka(a,e)},Ou={guid:"uuid",url:"uri",datetime:"date-time",json_string:"json-string",regex:""},zu=(e,t,n,s)=>{const r=n;r.type="string";const{minimum:i,maximum:a,format:c,patterns:l,contentEncoding:d}=e._zod.bag;if(typeof i=="number"&&(r.minLength=i),typeof a=="number"&&(r.maxLength=a),c&&(r.format=Ou[c]??c,r.format===""&&delete r.format,c==="time"&&delete r.format),d&&(r.contentEncoding=d),l&&l.size>0){const u=[...l];u.length===1?r.pattern=u[0].source:u.length>1&&(r.allOf=[...u.map(m=>({...t.target==="draft-07"||t.target==="draft-04"||t.target==="openapi-3.0"?{type:"string"}:{},pattern:m.source}))])}},Nu=(e,t,n,s)=>{const r=n,{minimum:i,maximum:a,format:c,multipleOf:l,exclusiveMaximum:d,exclusiveMinimum:u}=e._zod.bag;typeof c=="string"&&c.includes("int")?r.type="integer":r.type="number",typeof u=="number"&&(t.target==="draft-04"||t.target==="openapi-3.0"?(r.minimum=u,r.exclusiveMinimum=!0):r.exclusiveMinimum=u),typeof i=="number"&&(r.minimum=i,typeof u=="number"&&t.target!=="draft-04"&&(u>=i?delete r.minimum:delete r.exclusiveMinimum)),typeof d=="number"&&(t.target==="draft-04"||t.target==="openapi-3.0"?(r.maximum=d,r.exclusiveMaximum=!0):r.exclusiveMaximum=d),typeof a=="number"&&(r.maximum=a,typeof d=="number"&&t.target!=="draft-04"&&(d<=a?delete r.maximum:delete r.exclusiveMaximum)),typeof l=="number"&&(r.multipleOf=l)},Du=(e,t,n,s)=>{n.type="boolean"},ju=(e,t,n,s)=>{n.not={}},qu=(e,t,n,s)=>{},Fu=(e,t,n,s)=>{},Uu=(e,t,n,s)=>{const r=e._zod.def,i=Ea(r.entries);i.every(a=>typeof a=="number")&&(n.type="number"),i.every(a=>typeof a=="string")&&(n.type="string"),n.enum=i},Vu=(e,t,n,s)=>{if(t.unrepresentable==="throw")throw new Error("Custom types cannot be represented in JSON Schema")},Zu=(e,t,n,s)=>{if(t.unrepresentable==="throw")throw new Error("Transforms cannot be represented in JSON Schema")},Hu=(e,t,n,s)=>{const r=n,i=e._zod.def,{minimum:a,maximum:c}=e._zod.bag;typeof a=="number"&&(r.minItems=a),typeof c=="number"&&(r.maxItems=c),r.type="array",r.items=Ve(i.element,t,{...s,path:[...s.path,"items"]})},Bu=(e,t,n,s)=>{const r=n,i=e._zod.def;r.type="object",r.properties={};const a=i.shape;for(const d in a)r.properties[d]=Ve(a[d],t,{...s,path:[...s.path,"properties",d]});const c=new Set(Object.keys(a)),l=new Set([...c].filter(d=>{const u=i.shape[d]._zod;return t.io==="input"?u.optin===void 0:u.optout===void 0}));l.size>0&&(r.required=Array.from(l)),i.catchall?._zod.def.type==="never"?r.additionalProperties=!1:i.catchall?i.catchall&&(r.additionalProperties=Ve(i.catchall,t,{...s,path:[...s.path,"additionalProperties"]})):t.io==="output"&&(r.additionalProperties=!1)},Ju=(e,t,n,s)=>{const r=e._zod.def,i=r.inclusive===!1,a=r.options.map((c,l)=>Ve(c,t,{...s,path:[...s.path,i?"oneOf":"anyOf",l]}));i?n.oneOf=a:n.anyOf=a},Ku=(e,t,n,s)=>{const r=e._zod.def,i=Ve(r.left,t,{...s,path:[...s.path,"allOf",0]}),a=Ve(r.right,t,{...s,path:[...s.path,"allOf",1]}),c=d=>"allOf"in d&&Object.keys(d).length===1,l=[...c(i)?i.allOf:[i],...c(a)?a.allOf:[a]];n.allOf=l},Gu=(e,t,n,s)=>{const r=n,i=e._zod.def;r.type="object";const a=i.keyType,l=a._zod.bag?.patterns;if(i.mode==="loose"&&l&&l.size>0){const u=Ve(i.valueType,t,{...s,path:[...s.path,"patternProperties","*"]});r.patternProperties={};for(const m of l)r.patternProperties[m.source]=u}else(t.target==="draft-07"||t.target==="draft-2020-12")&&(r.propertyNames=Ve(i.keyType,t,{...s,path:[...s.path,"propertyNames"]})),r.additionalProperties=Ve(i.valueType,t,{...s,path:[...s.path,"additionalProperties"]});const d=a._zod.values;if(d){const u=[...d].filter(m=>typeof m=="string"||typeof m=="number");u.length>0&&(r.required=u)}},Wu=(e,t,n,s)=>{const r=e._zod.def,i=Ve(r.innerType,t,s),a=t.seen.get(e);t.target==="openapi-3.0"?(a.ref=r.innerType,n.nullable=!0):n.anyOf=[i,{type:"null"}]},Yu=(e,t,n,s)=>{const r=e._zod.def;Ve(r.innerType,t,s);const i=t.seen.get(e);i.ref=r.innerType},Xu=(e,t,n,s)=>{const r=e._zod.def;Ve(r.innerType,t,s);const i=t.seen.get(e);i.ref=r.innerType,n.default=JSON.parse(JSON.stringify(r.defaultValue))},Qu=(e,t,n,s)=>{const r=e._zod.def;Ve(r.innerType,t,s);const i=t.seen.get(e);i.ref=r.innerType,t.io==="input"&&(n._prefault=JSON.parse(JSON.stringify(r.defaultValue)))},ep=(e,t,n,s)=>{const r=e._zod.def;Ve(r.innerType,t,s);const i=t.seen.get(e);i.ref=r.innerType;let a;try{a=r.catchValue(void 0)}catch{throw new Error("Dynamic catch values are not supported in JSON Schema")}n.default=a},tp=(e,t,n,s)=>{const r=e._zod.def,i=t.io==="input"?r.in._zod.def.type==="transform"?r.out:r.in:r.out;Ve(i,t,s);const a=t.seen.get(e);a.ref=i},np=(e,t,n,s)=>{const r=e._zod.def;Ve(r.innerType,t,s);const i=t.seen.get(e);i.ref=r.innerType,n.readOnly=!0},Ga=(e,t,n,s)=>{const r=e._zod.def;Ve(r.innerType,t,s);const i=t.seen.get(e);i.ref=r.innerType},sp=A("ZodISODateTime",(e,t)=>{sd.init(e,t),Oe.init(e,t)});function rp(e){return lu(sp,e)}const ip=A("ZodISODate",(e,t)=>{rd.init(e,t),Oe.init(e,t)});function ap(e){return du(ip,e)}const op=A("ZodISOTime",(e,t)=>{id.init(e,t),Oe.init(e,t)});function cp(e){return uu(op,e)}const lp=A("ZodISODuration",(e,t)=>{ad.init(e,t),Oe.init(e,t)});function dp(e){return pu(lp,e)}const up=(e,t)=>{Ca.init(e,t),e.name="ZodError",Object.defineProperties(e,{format:{value:n=>Wc(e,n)},flatten:{value:n=>Gc(e,n)},addIssue:{value:n=>{e.issues.push(n),e.message=JSON.stringify(e.issues,hr,2)}},addIssues:{value:n=>{e.issues.push(...n),e.message=JSON.stringify(e.issues,hr,2)}},isEmpty:{get(){return e.issues.length===0}}})},bt=A("ZodError",up,{Parent:Error}),pp=jr(bt),mp=qr(bt),fp=Us(bt),hp=Vs(bt),gp=Qc(bt),vp=el(bt),yp=tl(bt),bp=nl(bt),wp=sl(bt),Sp=rl(bt),_p=il(bt),kp=al(bt),Le=A("ZodType",(e,t)=>(Pe.init(e,t),Object.assign(e["~standard"],{jsonSchema:{input:Ms(e,"input"),output:Ms(e,"output")}}),e.toJSONSchema=Lu(e,{}),e.def=t,e.type=t.type,Object.defineProperty(e,"_def",{value:t}),e.check=(...n)=>e.clone(Zt(t,{checks:[...t.checks??[],...n.map(s=>typeof s=="function"?{_zod:{check:s,def:{check:"custom"},onattach:[]}}:s)]}),{parent:!0}),e.with=e.check,e.clone=(n,s)=>Ht(e,n,s),e.brand=()=>e,e.register=((n,s)=>(n.add(e,s),e)),e.parse=(n,s)=>pp(e,n,s,{callee:e.parse}),e.safeParse=(n,s)=>fp(e,n,s),e.parseAsync=async(n,s)=>mp(e,n,s,{callee:e.parseAsync}),e.safeParseAsync=async(n,s)=>hp(e,n,s),e.spa=e.safeParseAsync,e.encode=(n,s)=>gp(e,n,s),e.decode=(n,s)=>vp(e,n,s),e.encodeAsync=async(n,s)=>yp(e,n,s),e.decodeAsync=async(n,s)=>bp(e,n,s),e.safeEncode=(n,s)=>wp(e,n,s),e.safeDecode=(n,s)=>Sp(e,n,s),e.safeEncodeAsync=async(n,s)=>_p(e,n,s),e.safeDecodeAsync=async(n,s)=>kp(e,n,s),e.refine=(n,s)=>e.check(ym(n,s)),e.superRefine=n=>e.check(bm(n)),e.overwrite=n=>e.check(In(n)),e.optional=()=>Ni(e),e.exactOptional=()=>im(e),e.nullable=()=>Di(e),e.nullish=()=>Ni(Di(e)),e.nonoptional=n=>um(e,n),e.array=()=>cn(e),e.or=n=>Yp([e,n]),e.and=n=>Qp(e,n),e.transform=n=>ji(e,sm(n)),e.default=n=>cm(e,n),e.prefault=n=>dm(e,n),e.catch=n=>mm(e,n),e.pipe=n=>ji(e,n),e.readonly=()=>gm(e),e.describe=n=>{const s=e.clone();return Zn.add(s,{description:n}),s},Object.defineProperty(e,"description",{get(){return Zn.get(e)?.description},configurable:!0}),e.meta=(...n)=>{if(n.length===0)return Zn.get(e);const s=e.clone();return Zn.add(s,n[0]),s},e.isOptional=()=>e.safeParse(void 0).success,e.isNullable=()=>e.safeParse(null).success,e.apply=n=>n(e),e)),Wa=A("_ZodString",(e,t)=>{Fr.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(s,r,i)=>zu(e,s,r);const n=e._zod.bag;e.format=n.format??null,e.minLength=n.minimum??null,e.maxLength=n.maximum??null,e.regex=(...s)=>e.check(bu(...s)),e.includes=(...s)=>e.check(_u(...s)),e.startsWith=(...s)=>e.check(ku(...s)),e.endsWith=(...s)=>e.check(xu(...s)),e.min=(...s)=>e.check(Cs(...s)),e.max=(...s)=>e.check(Za(...s)),e.length=(...s)=>e.check(Ha(...s)),e.nonempty=(...s)=>e.check(Cs(1,...s)),e.lowercase=s=>e.check(wu(s)),e.uppercase=s=>e.check(Su(s)),e.trim=()=>e.check(Eu()),e.normalize=(...s)=>e.check($u(...s)),e.toLowerCase=()=>e.check(Tu()),e.toUpperCase=()=>e.check(Au()),e.slugify=()=>e.check(Iu())}),xp=A("ZodString",(e,t)=>{Fr.init(e,t),Wa.init(e,t),e.email=n=>e.check(Ud($p,n)),e.url=n=>e.check(Jd(Ep,n)),e.jwt=n=>e.check(cu(Fp,n)),e.emoji=n=>e.check(Kd(Tp,n)),e.guid=n=>e.check(Ci(Li,n)),e.uuid=n=>e.check(Vd(ws,n)),e.uuidv4=n=>e.check(Zd(ws,n)),e.uuidv6=n=>e.check(Hd(ws,n)),e.uuidv7=n=>e.check(Bd(ws,n)),e.nanoid=n=>e.check(Gd(Ap,n)),e.guid=n=>e.check(Ci(Li,n)),e.cuid=n=>e.check(Wd(Ip,n)),e.cuid2=n=>e.check(Yd(Cp,n)),e.ulid=n=>e.check(Xd(Mp,n)),e.base64=n=>e.check(iu(Dp,n)),e.base64url=n=>e.check(au(jp,n)),e.xid=n=>e.check(Qd(Rp,n)),e.ksuid=n=>e.check(eu(Pp,n)),e.ipv4=n=>e.check(tu(Lp,n)),e.ipv6=n=>e.check(nu(Op,n)),e.cidrv4=n=>e.check(su(zp,n)),e.cidrv6=n=>e.check(ru(Np,n)),e.e164=n=>e.check(ou(qp,n)),e.datetime=n=>e.check(rp(n)),e.date=n=>e.check(ap(n)),e.time=n=>e.check(cp(n)),e.duration=n=>e.check(dp(n))});function G(e){return Fd(xp,e)}const Oe=A("ZodStringFormat",(e,t)=>{Ae.init(e,t),Wa.init(e,t)}),$p=A("ZodEmail",(e,t)=>{Kl.init(e,t),Oe.init(e,t)}),Li=A("ZodGUID",(e,t)=>{Bl.init(e,t),Oe.init(e,t)}),ws=A("ZodUUID",(e,t)=>{Jl.init(e,t),Oe.init(e,t)}),Ep=A("ZodURL",(e,t)=>{Gl.init(e,t),Oe.init(e,t)}),Tp=A("ZodEmoji",(e,t)=>{Wl.init(e,t),Oe.init(e,t)}),Ap=A("ZodNanoID",(e,t)=>{Yl.init(e,t),Oe.init(e,t)}),Ip=A("ZodCUID",(e,t)=>{Xl.init(e,t),Oe.init(e,t)}),Cp=A("ZodCUID2",(e,t)=>{Ql.init(e,t),Oe.init(e,t)}),Mp=A("ZodULID",(e,t)=>{ed.init(e,t),Oe.init(e,t)}),Rp=A("ZodXID",(e,t)=>{td.init(e,t),Oe.init(e,t)}),Pp=A("ZodKSUID",(e,t)=>{nd.init(e,t),Oe.init(e,t)}),Lp=A("ZodIPv4",(e,t)=>{od.init(e,t),Oe.init(e,t)}),Op=A("ZodIPv6",(e,t)=>{cd.init(e,t),Oe.init(e,t)}),zp=A("ZodCIDRv4",(e,t)=>{ld.init(e,t),Oe.init(e,t)}),Np=A("ZodCIDRv6",(e,t)=>{dd.init(e,t),Oe.init(e,t)}),Dp=A("ZodBase64",(e,t)=>{ud.init(e,t),Oe.init(e,t)}),jp=A("ZodBase64URL",(e,t)=>{md.init(e,t),Oe.init(e,t)}),qp=A("ZodE164",(e,t)=>{fd.init(e,t),Oe.init(e,t)}),Fp=A("ZodJWT",(e,t)=>{gd.init(e,t),Oe.init(e,t)}),Ya=A("ZodNumber",(e,t)=>{qa.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(s,r,i)=>Nu(e,s,r),e.gt=(s,r)=>e.check(Ri(s,r)),e.gte=(s,r)=>e.check(ir(s,r)),e.min=(s,r)=>e.check(ir(s,r)),e.lt=(s,r)=>e.check(Mi(s,r)),e.lte=(s,r)=>e.check(rr(s,r)),e.max=(s,r)=>e.check(rr(s,r)),e.int=s=>e.check(Oi(s)),e.safe=s=>e.check(Oi(s)),e.positive=s=>e.check(Ri(0,s)),e.nonnegative=s=>e.check(ir(0,s)),e.negative=s=>e.check(Mi(0,s)),e.nonpositive=s=>e.check(rr(0,s)),e.multipleOf=(s,r)=>e.check(Pi(s,r)),e.step=(s,r)=>e.check(Pi(s,r)),e.finite=()=>e;const n=e._zod.bag;e.minValue=Math.max(n.minimum??Number.NEGATIVE_INFINITY,n.exclusiveMinimum??Number.NEGATIVE_INFINITY)??null,e.maxValue=Math.min(n.maximum??Number.POSITIVE_INFINITY,n.exclusiveMaximum??Number.POSITIVE_INFINITY)??null,e.isInt=(n.format??"").includes("int")||Number.isSafeInteger(n.multipleOf??.5),e.isFinite=!0,e.format=n.format??null});function yt(e){return mu(Ya,e)}const Up=A("ZodNumberFormat",(e,t)=>{vd.init(e,t),Ya.init(e,t)});function Oi(e){return fu(Up,e)}const Vp=A("ZodBoolean",(e,t)=>{yd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Du(e,n,s)});function Hs(e){return hu(Vp,e)}const Zp=A("ZodAny",(e,t)=>{bd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>qu()});function Bs(){return gu(Zp)}const Hp=A("ZodUnknown",(e,t)=>{wd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Fu()});function zi(){return vu(Hp)}const Bp=A("ZodNever",(e,t)=>{Sd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>ju(e,n,s)});function Jp(e){return yu(Bp,e)}const Kp=A("ZodArray",(e,t)=>{_d.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Hu(e,n,s,r),e.element=t.element,e.min=(n,s)=>e.check(Cs(n,s)),e.nonempty=n=>e.check(Cs(1,n)),e.max=(n,s)=>e.check(Za(n,s)),e.length=(n,s)=>e.check(Ha(n,s)),e.unwrap=()=>e.element});function cn(e,t){return Cu(Kp,e,t)}const Gp=A("ZodObject",(e,t)=>{xd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Bu(e,n,s,r),xe(e,"shape",()=>t.shape),e.keyof=()=>tm(Object.keys(e._zod.def.shape)),e.catchall=n=>e.clone({...e._zod.def,catchall:n}),e.passthrough=()=>e.clone({...e._zod.def,catchall:zi()}),e.loose=()=>e.clone({...e._zod.def,catchall:zi()}),e.strict=()=>e.clone({...e._zod.def,catchall:Jp()}),e.strip=()=>e.clone({...e._zod.def,catchall:void 0}),e.extend=n=>Zc(e,n),e.safeExtend=n=>Hc(e,n),e.merge=n=>Bc(e,n),e.pick=n=>Uc(e,n),e.omit=n=>Vc(e,n),e.partial=(...n)=>Jc(Qa,e,n[0]),e.required=(...n)=>Kc(eo,e,n[0])});function et(e,t){const n={type:"object",shape:e??{},...te(t)};return new Gp(n)}const Wp=A("ZodUnion",(e,t)=>{$d.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Ju(e,n,s,r),e.options=t.options});function Yp(e,t){return new Wp({type:"union",options:e,...te(t)})}const Xp=A("ZodIntersection",(e,t)=>{Ed.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Ku(e,n,s,r)});function Qp(e,t){return new Xp({type:"intersection",left:e,right:t})}const em=A("ZodRecord",(e,t)=>{Td.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Gu(e,n,s,r),e.keyType=t.keyType,e.valueType=t.valueType});function Xa(e,t,n){return new em({type:"record",keyType:e,valueType:t,...te(n)})}const vr=A("ZodEnum",(e,t)=>{Ad.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(s,r,i)=>Uu(e,s,r),e.enum=t.entries,e.options=Object.values(t.entries);const n=new Set(Object.keys(t.entries));e.extract=(s,r)=>{const i={};for(const a of s)if(n.has(a))i[a]=t.entries[a];else throw new Error(`Key ${a} not found in enum`);return new vr({...t,checks:[],...te(r),entries:i})},e.exclude=(s,r)=>{const i={...t.entries};for(const a of s)if(n.has(a))delete i[a];else throw new Error(`Key ${a} not found in enum`);return new vr({...t,checks:[],...te(r),entries:i})}});function tm(e,t){const n=Array.isArray(e)?Object.fromEntries(e.map(s=>[s,s])):e;return new vr({type:"enum",entries:n,...te(t)})}const nm=A("ZodTransform",(e,t)=>{Id.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Zu(e,n),e._zod.parse=(n,s)=>{if(s.direction==="backward")throw new xa(e.constructor.name);n.addIssue=i=>{if(typeof i=="string")n.issues.push(Kn(i,n.value,t));else{const a=i;a.fatal&&(a.continue=!1),a.code??(a.code="custom"),a.input??(a.input=n.value),a.inst??(a.inst=e),n.issues.push(Kn(a))}};const r=t.transform(n.value,n);return r instanceof Promise?r.then(i=>(n.value=i,n)):(n.value=r,n)}});function sm(e){return new nm({type:"transform",transform:e})}const Qa=A("ZodOptional",(e,t)=>{Va.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Ga(e,n,s,r),e.unwrap=()=>e._zod.def.innerType});function Ni(e){return new Qa({type:"optional",innerType:e})}const rm=A("ZodExactOptional",(e,t)=>{Cd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Ga(e,n,s,r),e.unwrap=()=>e._zod.def.innerType});function im(e){return new rm({type:"optional",innerType:e})}const am=A("ZodNullable",(e,t)=>{Md.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Wu(e,n,s,r),e.unwrap=()=>e._zod.def.innerType});function Di(e){return new am({type:"nullable",innerType:e})}const om=A("ZodDefault",(e,t)=>{Rd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Xu(e,n,s,r),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function cm(e,t){return new om({type:"default",innerType:e,get defaultValue(){return typeof t=="function"?t():Aa(t)}})}const lm=A("ZodPrefault",(e,t)=>{Pd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Qu(e,n,s,r),e.unwrap=()=>e._zod.def.innerType});function dm(e,t){return new lm({type:"prefault",innerType:e,get defaultValue(){return typeof t=="function"?t():Aa(t)}})}const eo=A("ZodNonOptional",(e,t)=>{Ld.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Yu(e,n,s,r),e.unwrap=()=>e._zod.def.innerType});function um(e,t){return new eo({type:"nonoptional",innerType:e,...te(t)})}const pm=A("ZodCatch",(e,t)=>{Od.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>ep(e,n,s,r),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function mm(e,t){return new pm({type:"catch",innerType:e,catchValue:typeof t=="function"?t:()=>t})}const fm=A("ZodPipe",(e,t)=>{zd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>tp(e,n,s,r),e.in=t.in,e.out=t.out});function ji(e,t){return new fm({type:"pipe",in:e,out:t})}const hm=A("ZodReadonly",(e,t)=>{Nd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>np(e,n,s,r),e.unwrap=()=>e._zod.def.innerType});function gm(e){return new hm({type:"readonly",innerType:e})}const vm=A("ZodCustom",(e,t)=>{Dd.init(e,t),Le.init(e,t),e._zod.processJSONSchema=(n,s,r)=>Vu(e,n)});function ym(e,t={}){return Mu(vm,e,t)}function bm(e){return Ru(e)}var wm=class extends Error{constructor(e,t,n,s){super(`Tandem API Validation Error [${t}] at ${e}: ${n.length} issues found.`),this.endpoint=e,this.status=t,this.issues=n,this.rawSnippet=s,this.name="TandemValidationError"}},qi=G().or(et({id:G().optional(),runID:G().optional(),runId:G().optional(),run_id:G().optional(),sessionID:G().optional(),sessionId:G().optional(),session_id:G().optional(),missionID:G().optional(),missionId:G().optional(),mission_id:G().optional(),instanceID:G().optional(),instanceId:G().optional(),instance_id:G().optional()})).transform(e=>typeof e=="string"?e:e.id||e.runID||e.runId||e.run_id||e.sessionID||e.sessionId||e.session_id||e.missionID||e.missionId||e.mission_id||e.instanceID||e.instanceId||e.instance_id);Bs().transform(e=>e);Xa(G(),Bs()).transform(e=>e);var Sm=et({ready:Hs().optional(),phase:G().optional()}).passthrough(),xs=et({id:G(),title:G(),created_at_ms:yt().optional(),createdAtMs:yt().optional(),directory:G().optional(),workspace_root:G().optional(),workspaceRoot:G().optional(),archived:Hs().optional()}).passthrough().transform(e=>({...e,createdAtMs:e.created_at_ms??e.createdAtMs??0,workspaceRoot:e.workspace_root??e.workspaceRoot})),Fi=et({sessions:cn(xs).optional().default([]),count:yt().optional().default(0)}).passthrough(),_m=et({active:et({runID:G().optional(),runId:G().optional(),run_id:G().optional(),attachEventStream:G().optional()}).passthrough().nullable().optional()}).passthrough().transform(e=>e.active?{active:{...e.active,runId:e.active.runId||e.active.runID||e.active.run_id}}:{active:null}),to=et({ok:Hs().optional(),runID:G().optional(),runId:G().optional(),run_id:G().optional(),status:G().optional()}).passthrough().transform(e=>({...e,runId:e.runId||e.runID||e.run_id})),no=et({id:G().optional(),runID:G().optional(),runId:G().optional(),run_id:G().optional(),routine_id:G().optional(),automation_id:G().optional(),status:G().optional(),started_at_ms:yt().optional(),finished_at_ms:yt().optional()}).passthrough().transform(e=>({...e,runId:e.runId||e.runID||e.run_id,routineId:e.routine_id,automationId:e.automation_id,startedAtMs:e.started_at_ms,finishedAtMs:e.finished_at_ms}));et({ok:Hs().default(!0),rev:yt().optional()}).passthrough();var km=et({key:G(),value:Bs(),rev:yt().optional(),updated_at_ms:yt().optional(),updated_by:G().optional()}).passthrough().transform(e=>({...e,updatedAtMs:e.updated_at_ms,updatedBy:e.updated_by})),xm=et({items:cn(km).optional().default([]),count:yt().optional().default(0)}).passthrough(),$m=et({id:G().optional(),text:G().optional(),content:G().optional(),user_id:G().optional(),userID:G().optional(),source_type:G().optional(),sourceType:G().optional(),tags:cn(G()).optional(),source:G().optional(),session_id:G().optional(),sessionID:G().optional(),run_id:G().optional(),runID:G().optional()}).passthrough().transform(e=>({...e,text:e.text||e.content,content:e.content||e.text,userId:e.userID||e.user_id,sourceType:e.sourceType||e.source_type,sessionId:e.session_id||e.sessionID,runId:e.run_id||e.runID})),Em=et({items:cn($m).optional().default([]),count:yt().optional().default(0)}).passthrough(),Tm=et({id:G(),text:G().optional(),content:G().optional(),score:yt().optional(),source_type:G().optional(),sourceType:G().optional(),run_id:G().optional(),runID:G().optional(),tags:cn(G()).optional()}).passthrough().transform(e=>({...e,text:e.text||e.content,content:e.content||e.text,sourceType:e.sourceType||e.source_type,runId:e.runID||e.run_id})),Am=et({results:cn(Tm).optional().default([]),count:yt().optional().default(0)}).passthrough(),Im=et({type:G(),properties:Xa(G(),Bs()).optional().default({}),sessionID:G().optional(),session_id:G().optional(),sessionId:G().optional(),runID:G().optional(),run_id:G().optional(),runId:G().optional(),timestamp:G().optional()}).passthrough().transform(e=>({...e,properties:e.properties,sessionId:e.sessionId||e.sessionID||e.session_id,runId:e.runId||e.runID||e.run_id}));function ct(e,t,n,s){const r=e.safeParse(t);if(!r.success){const i=JSON.stringify(t).substring(0,200);throw new wm(n,s,r.error.issues,i)}return r.data}function Cm(e){const t=e.trim();if(!t||t===": keep-alive"||t.startsWith(":"))return null;try{const n=JSON.parse(t),s=Im.safeParse(n);return s.success?s.data:null}catch{return null}}async function*Ui(e,t,n){const s=n?.connectTimeoutMs??3e4,r=new AbortController,i=setTimeout(()=>r.abort(),s),a=n?.signal?Mm([r.signal,n.signal]):r.signal;let c;try{c=await fetch(e,{headers:{Accept:"text/event-stream",Authorization:`Bearer ${t}`,"Cache-Control":"no-cache"},signal:a})}finally{clearTimeout(i)}if(!c.ok){const m=await c.text().catch(()=>"");throw new Error(`SSE connect failed (${c.status} ${c.statusText}): ${m}`)}if(!c.body)throw new Error("SSE response has no body");const l=new TextDecoder,d=c.body.getReader();let u="";try{for(;;){const{done:m,value:_}=await d.read();if(m)break;u+=l.decode(_,{stream:!0});const b=u.split(`
|
|
40
|
+
`);u=b.pop()??"";let x="";for(const y of b)if(y.startsWith("data:"))x+=y.slice(5).trimStart();else if(y===""&&x){const I=Cm(x);I&&(yield I),x=""}}}finally{d.releaseLock()}}function Mm(e){const t=new AbortController;for(const n of e){if(n.aborted){t.abort(n.reason);break}n.addEventListener("abort",()=>t.abort(n.reason),{once:!0})}return t.signal}var bn=e=>typeof e=="string"&&e.trim().length>0?e:null,Rm=e=>{try{const t=qi.parse(e);if(t)return t}catch{const t=e.run||null;if(t)try{const n=qi.parse(t);if(n)return n}catch{}}throw new Error("Run ID missing in engine response")},Pm=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.token=e.token,this.timeoutMs=e.timeoutMs??2e4;const t=this._request.bind(this);this.sessions=new Lm(this.baseUrl,this.token,this.timeoutMs,t),this.permissions=new Om(t),this.questions=new zm(t),this.providers=new Nm(t),this.channels=new Dm(t),this.mcp=new jm(t),this.routines=new Vm(t),this.automations=new Zm(t),this.memory=new qm(t),this.skills=new Fm(t),this.resources=new Um(t),this.agentTeams=new Hm(t),this.missions=new Bm(t)}setToken(e){this.token=e,this.sessions.setToken(e)}async health(){const e=await this._request("/global/health");return ct(Sm,e,"/global/health",200)}async listToolIds(){return this._request("/tool/ids")}async listTools(){const e=await this._request("/tool");return Array.isArray(e)?e:[]}async executeTool(e,t){return this._request("/tool/execute",{method:"POST",body:JSON.stringify({tool:e,args:t??{}})})}stream(e,t,n){const s=new URLSearchParams({sessionID:e});t&&s.set("runID",t);const r=`${this.baseUrl}/event?${s.toString()}`;return Ui(r,this.token,n)}globalStream(e){const t=`${this.baseUrl}/global/event`;return Ui(t,this.token,e)}async runEvents(e,t){const n=new URLSearchParams;t?.sinceSeq!==void 0&&n.set("since_seq",String(t.sinceSeq)),t?.tail!==void 0&&n.set("tail",String(t.tail));const s=n.toString()?`?${n.toString()}`:"",r=await this._request(`/run/${encodeURIComponent(e)}/events${s}`);return Array.isArray(r)?r:[]}async _request(e,t={}){const n=new AbortController,s=setTimeout(()=>n.abort(),this.timeoutMs);let r;try{r=await fetch(`${this.baseUrl}${e}`,{...t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`,...t.headers??{}},signal:n.signal})}catch(i){throw i instanceof Error&&i.name==="AbortError"?new Error(`Request timed out after ${this.timeoutMs}ms: ${e}`):i}finally{clearTimeout(s)}if(r.status!==204){if(!r.ok){const i=await r.text().catch(()=>"");throw new Error(`Request failed (${r.status} ${r.statusText}): ${i}`)}return r.json()}}},Lm=class{constructor(e,t,n,s){this.baseUrl=e,this.token=t,this.timeoutMs=n,this.req=s}setToken(e){this.token=e}async create(e={}){const t={title:e.title??"Tandem SDK Session",directory:e.directory??"."};return e.permissions&&(t.permission=e.permissions),e.model&&e.provider&&(t.model={providerID:e.provider,modelID:e.model},t.provider=e.provider),(await this.req("/session",{method:"POST",body:JSON.stringify(t)})).id}async list(e={}){const t=new URLSearchParams;e.q&&t.set("q",e.q),e.page!==void 0&&t.set("page",String(e.page)),e.pageSize!==void 0&&t.set("page_size",String(e.pageSize)),e.archived!==void 0&&t.set("archived",String(e.archived)),e.scope&&t.set("scope",e.scope),e.workspace&&t.set("workspace",e.workspace);const n=t.toString()?`?${t.toString()}`:"",s=await this.req(`/session${n}`);return ct(Fi,s,"/session",200)}async get(e){const t=await this.req(`/session/${encodeURIComponent(e)}`);return ct(xs,t,`/session/${e}`,200)}async update(e,t){const n=await this.req(`/session/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(t)});return ct(xs,n,`/session/${e}`,200)}async archive(e){return this.update(e,{archived:!0})}async delete(e){await this.req(`/session/${encodeURIComponent(e)}`,{method:"DELETE"})}async messages(e){return this.req(`/session/${encodeURIComponent(e)}/message`)}async todos(e){const t=await this.req(`/session/${encodeURIComponent(e)}/todo`);return Array.isArray(t)?t:t.todos??[]}async activeRun(e){const t=await this.req(`/session/${encodeURIComponent(e)}/run`);return ct(_m,t,`/session/${e}/run`,200)}async promptAsync(e,t,n){const s={parts:[{type:"text",text:t}]};n?.provider&&n?.model&&(s.model={providerID:n.provider,modelID:n.model});const r=`/session/${encodeURIComponent(e)}/prompt_async?return=run`,i=new AbortController,a=setTimeout(()=>i.abort(),this.timeoutMs);let c;try{c=await fetch(`${this.baseUrl}${r}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`},body:JSON.stringify(s),signal:i.signal})}finally{clearTimeout(a)}if(c.status===409){const u=(await c.json().catch(()=>({}))).activeRun,m=bn(u?.runID)||bn(u?.runId)||bn(u?.run_id);if(m)return{runId:m}}if(!c.ok){const d=await c.text().catch(()=>"");throw new Error(`promptAsync failed (${c.status}): ${d}`)}const l=await c.json();return{runId:Rm(l)}}async promptSync(e,t){const n={parts:[{type:"text",text:t}]},s=await this.req(`/session/${encodeURIComponent(e)}/prompt_sync`,{method:"POST",body:JSON.stringify(n)});return bn(s.reply)||bn(s.text)||bn(s.output)||""}async abort(e){return this.req(`/session/${encodeURIComponent(e)}/abort`,{method:"POST",body:JSON.stringify({})})}async cancel(e){return this.req(`/session/${encodeURIComponent(e)}/cancel`,{method:"POST",body:JSON.stringify({})})}async cancelRun(e,t){return this.req(`/session/${encodeURIComponent(e)}/run/${encodeURIComponent(t)}/cancel`,{method:"POST",body:JSON.stringify({})})}async fork(e){const t=await this.req(`/session/${encodeURIComponent(e)}/fork`,{method:"POST",body:JSON.stringify({})});return ct(xs,t,`/session/${e}/fork`,200)}async diff(e){return this.req(`/session/${encodeURIComponent(e)}/diff`)}async revert(e){return this.req(`/session/${encodeURIComponent(e)}/revert`,{method:"POST",body:JSON.stringify({})})}async unrevert(e){return this.req(`/session/${encodeURIComponent(e)}/unrevert`,{method:"POST",body:JSON.stringify({})})}async children(e){const t=await this.req(`/session/${encodeURIComponent(e)}/children`);return ct(Fi,t,`/session/${e}/children`,200).sessions}async summarize(e){return this.req(`/session/${encodeURIComponent(e)}/summarize`,{method:"POST",body:JSON.stringify({})})}async attach(e,t){return this.req(`/session/${encodeURIComponent(e)}/attach`,{method:"POST",body:JSON.stringify({target_workspace:t})})}},Om=class{constructor(e){this.req=e}async list(){return this.req("/permission")}async reply(e,t){const n=await this.req(`/permission/${encodeURIComponent(e)}/reply`,{method:"POST",body:JSON.stringify({reply:t})});if(!n.ok)throw new Error(`Permission reply rejected: ${n.error??e}`);return{ok:!0}}},zm=class{constructor(e){this.req=e}async list(){const e=await this.req("/question");return Array.isArray(e)?{questions:e}:e}async reply(e,t){return this.req(`/question/${encodeURIComponent(e)}/reply`,{method:"POST",body:JSON.stringify({answer:t})})}async reject(e){return this.req(`/question/${encodeURIComponent(e)}/reject`,{method:"POST",body:JSON.stringify({})})}},Nm=class{constructor(e){this.req=e}async catalog(){return this.req("/provider")}async config(){return this.req("/config/providers")}async setDefaults(e,t){await this.req("/config",{method:"PATCH",body:JSON.stringify({default_provider:e,providers:{[e]:{default_model:t}}})})}async setApiKey(e,t){await this.req(`/auth/${encodeURIComponent(e)}`,{method:"PUT",body:JSON.stringify({apiKey:t})})}async authStatus(){return this.req("/provider/auth")}},Dm=class{constructor(e){this.req=e}async config(){return this.req("/channels/config")}async status(){return this.req("/channels/status")}async put(e,t){return this.req(`/channels/${e}`,{method:"PUT",body:JSON.stringify(t)})}async delete(e){return this.req(`/channels/${e}`,{method:"DELETE"})}},jm=class{constructor(e){this.req=e}async list(){return this.req("/mcp")}async listTools(){return this.req("/mcp/tools")}async listResources(){const e=await this.req("/mcp/resources");return Array.isArray(e)?e:[]}async add(e){return this.req("/mcp",{method:"POST",body:JSON.stringify(e)})}async connect(e){return this.req(`/mcp/${encodeURIComponent(e)}/connect`,{method:"POST"})}async disconnect(e){return this.req(`/mcp/${encodeURIComponent(e)}/disconnect`,{method:"POST"})}async refresh(e){return this.req(`/mcp/${encodeURIComponent(e)}/refresh`,{method:"POST"})}async setEnabled(e,t){return this.req(`/mcp/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify({enabled:t})})}},qm=class{constructor(e){this.req=e}async put(e){return this.req("/memory/put",{method:"POST",body:JSON.stringify(e)})}async search(e){const t=await this.req("/memory/search",{method:"POST",body:JSON.stringify(e)});return ct(Am,t,"/memory/search",200)}async list(e){const t=new URLSearchParams;e?.q&&t.set("q",e.q),e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.offset!==void 0&&t.set("offset",String(e.offset)),e?.userId&&t.set("user_id",e.userId);const n=t.toString()?`?${t.toString()}`:"",s=await this.req(`/memory${n}`);return ct(Em,s,"/memory",200)}async delete(e){return this.req(`/memory/${encodeURIComponent(e)}`,{method:"DELETE"})}async promote(e){return this.req("/memory/promote",{method:"POST",body:JSON.stringify(e)})}async demote(e){const t={id:e.id,run_id:e.runId};return this.req("/memory/demote",{method:"POST",body:JSON.stringify(t)})}async audit(e){const t=new URLSearchParams;e?.run_id&&t.set("run_id",e.run_id),e?.limit!==void 0&&t.set("limit",String(e.limit));const n=t.toString()?`?${t.toString()}`:"",s=await this.req(`/memory/audit${n}`);return Array.isArray(s)?{entries:s,count:s.length}:s}},Fm=class{constructor(e){this.req=e}async list(e){const t=e?`?location=${encodeURIComponent(e)}`:"",n=await this.req(`/skills${t}`);return Array.isArray(n)?{skills:n,count:n.length}:n}async get(e){return this.req(`/skills/${encodeURIComponent(e)}`)}async import(e){return this.req("/skills/import",{method:"POST",body:JSON.stringify(e)})}async preview(e){return this.req("/skills/import/preview",{method:"POST",body:JSON.stringify(e)})}async templates(){const e=await this.req("/skills/templates");return Array.isArray(e)?{templates:e,count:e.length}:e}},Um=class{constructor(e){this.req=e}async list(e){const t=new URLSearchParams;e?.prefix&&t.set("prefix",e.prefix),e?.limit!==void 0&&t.set("limit",String(e.limit));const n=t.toString()?`?${t.toString()}`:"",s=await this.req(`/resource${n}`);return ct(xm,s,"/resource",200)}async write(e){return this.req("/resource",{method:"PUT",body:JSON.stringify(e)})}async delete(e,t){return this.req("/resource",{method:"DELETE",body:JSON.stringify({key:e,...t})})}},Vm=class{constructor(e){this.req=e}async list(){return this.req("/routines")}async create(e){const t={...e};return"prompt"in t&&!("entrypoint"in t)&&(t.entrypoint=t.prompt),this.req("/routines",{method:"POST",body:JSON.stringify(t)})}async update(e,t){return this.req(`/routines/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(t)})}async delete(e){await this.req(`/routines/${encodeURIComponent(e)}`,{method:"DELETE"})}async runNow(e){const t=await this.req(`/routines/${encodeURIComponent(e)}/run_now`,{method:"POST",body:JSON.stringify({})});return ct(to,t,`/routines/${e}/run_now`,200)}async listRuns(e){const t=new URLSearchParams;e?.routine_id&&t.set("routine_id",e.routine_id),e?.limit!==void 0&&t.set("limit",String(e.limit));const n=t.toString()?`?${t.toString()}`:"";return this.req(`/routines/runs${n}`)}async getRunsForRoutine(e,t=25){return this.req(`/routines/${encodeURIComponent(e)}/runs?limit=${t}`)}async getRun(e){const t=await this.req(`/routines/runs/${encodeURIComponent(e)}`);return ct(no,t,`/routines/runs/${e}`,200)}async listArtifacts(e){return this.req(`/routines/runs/${encodeURIComponent(e)}/artifacts`)}async approveRun(e,t){return this.req(`/routines/runs/${encodeURIComponent(e)}/approve`,{method:"POST",body:JSON.stringify({reason:t??""})})}async denyRun(e,t){return this.req(`/routines/runs/${encodeURIComponent(e)}/deny`,{method:"POST",body:JSON.stringify({reason:t??""})})}async pauseRun(e,t){return this.req(`/routines/runs/${encodeURIComponent(e)}/pause`,{method:"POST",body:JSON.stringify({reason:t??""})})}async resumeRun(e,t){return this.req(`/routines/runs/${encodeURIComponent(e)}/resume`,{method:"POST",body:JSON.stringify({reason:t??""})})}async history(e,t){const n=t!==void 0?`?limit=${t}`:"",s=await this.req(`/routines/${encodeURIComponent(e)}/history${n}`);return Array.isArray(s)?{history:s,count:s.length}:s}},Zm=class{constructor(e){this.req=e}async list(){return this.req("/automations")}async create(e){return this.req("/automations",{method:"POST",body:JSON.stringify(e)})}async update(e,t){return this.req(`/automations/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(t)})}async delete(e){await this.req(`/automations/${encodeURIComponent(e)}`,{method:"DELETE"})}async runNow(e){const t=await this.req(`/automations/${encodeURIComponent(e)}/run_now`,{method:"POST",body:JSON.stringify({})});return ct(to,t,`/automations/${e}/run_now`,200)}async listRuns(e){const t=new URLSearchParams;e?.automation_id&&t.set("automation_id",e.automation_id),e?.limit!==void 0&&t.set("limit",String(e.limit));const n=t.toString()?`?${t.toString()}`:"";return this.req(`/automations/runs${n}`)}async getRunsForAutomation(e,t=25){return this.req(`/automations/${encodeURIComponent(e)}/runs?limit=${t}`)}async getRun(e){const t=await this.req(`/automations/runs/${encodeURIComponent(e)}`);return ct(no,t,`/automations/runs/${e}`,200)}async listArtifacts(e){return this.req(`/automations/runs/${encodeURIComponent(e)}/artifacts`)}async approveRun(e,t){return this.req(`/automations/runs/${encodeURIComponent(e)}/approve`,{method:"POST",body:JSON.stringify({reason:t??""})})}async denyRun(e,t){return this.req(`/automations/runs/${encodeURIComponent(e)}/deny`,{method:"POST",body:JSON.stringify({reason:t??""})})}async pauseRun(e,t){return this.req(`/automations/runs/${encodeURIComponent(e)}/pause`,{method:"POST",body:JSON.stringify({reason:t??""})})}async resumeRun(e,t){return this.req(`/automations/runs/${encodeURIComponent(e)}/resume`,{method:"POST",body:JSON.stringify({reason:t??""})})}async history(e,t){const n=t!==void 0?`?limit=${t}`:"",s=await this.req(`/automations/${encodeURIComponent(e)}/history${n}`);return Array.isArray(s)?{history:s,count:s.length}:s}},Hm=class{constructor(e){this.req=e}async listTemplates(){return this.req("/agent-team/templates")}async listInstances(e){const t=new URLSearchParams;e?.missionID&&t.set("missionID",e.missionID),e?.parentInstanceID&&t.set("parentInstanceID",e.parentInstanceID),e?.status&&t.set("status",e.status);const n=t.toString()?`?${t.toString()}`:"";return this.req(`/agent-team/instances${n}`)}async listMissions(){return this.req("/agent-team/missions")}async listApprovals(){return this.req("/agent-team/approvals")}async spawn(e){return this.req("/agent-team/spawn",{method:"POST",body:JSON.stringify(e)})}async approveSpawn(e,t){return this.req(`/agent-team/approvals/spawn/${encodeURIComponent(e)}/approve`,{method:"POST",body:JSON.stringify({reason:t??""})})}async denySpawn(e,t){return this.req(`/agent-team/approvals/spawn/${encodeURIComponent(e)}/deny`,{method:"POST",body:JSON.stringify({reason:t??""})})}},Bm=class{constructor(e){this.req=e}async list(){return this.req("/mission")}async create(e){return this.req("/mission",{method:"POST",body:JSON.stringify(e)})}async get(e){return this.req(`/mission/${encodeURIComponent(e)}`)}async applyEvent(e,t){return this.req(`/mission/${encodeURIComponent(e)}/event`,{method:"POST",body:JSON.stringify({event:t})})}};const rn=e=>e;let so=rn;const Js=(e,t,n)=>{const s=t-e;return s===0?1:(n-e)/s};function Ur(e){let t;return()=>(t===void 0&&(t=e()),t)}const Jm=Ur(()=>window.ScrollTimeline!==void 0);class Km{constructor(t){this.stop=()=>this.runAll("stop"),this.animations=t.filter(Boolean)}get finished(){return Promise.all(this.animations.map(t=>"finished"in t?t.finished:t))}getAll(t){return this.animations[0][t]}setAll(t,n){for(let s=0;s<this.animations.length;s++)this.animations[s][t]=n}attachTimeline(t,n){const s=this.animations.map(r=>{if(Jm()&&r.attachTimeline)return r.attachTimeline(t);if(typeof n=="function")return n(r)});return()=>{s.forEach((r,i)=>{r&&r(),this.animations[i].stop()})}}get time(){return this.getAll("time")}set time(t){this.setAll("time",t)}get speed(){return this.getAll("speed")}set speed(t){this.setAll("speed",t)}get startTime(){return this.getAll("startTime")}get duration(){let t=0;for(let n=0;n<this.animations.length;n++)t=Math.max(t,this.animations[n].duration);return t}runAll(t){this.animations.forEach(n=>n[t]())}flatten(){this.runAll("flatten")}play(){this.runAll("play")}pause(){this.runAll("pause")}cancel(){this.runAll("cancel")}complete(){this.runAll("complete")}}class ro extends Km{then(t,n){return Promise.all(this.animations).then(t).catch(n)}}const Mt=e=>e*1e3,Rt=e=>e/1e3,Rs=2e4;function Vr(e){let t=0;const n=50;let s=e.next(t);for(;!s.done&&t<Rs;)t+=n,s=e.next(t);return t>=Rs?1/0:t}const io=(e,t,n=10)=>{let s="";const r=Math.max(Math.round(t/n),2);for(let i=0;i<r;i++)s+=e(Js(0,r-1,i))+", ";return`linear(${s.substring(0,s.length-2)})`},an=(e,t,n)=>n>t?t:n<e?e:n;function ao(e,t){return t?e*(1e3/t):0}const Gm=5;function oo(e,t,n){const s=Math.max(t-Gm,0);return ao(n-e(s),t-s)}const De={stiffness:100,damping:10,mass:1,velocity:0,duration:800,bounce:.3,visualDuration:.3,restSpeed:{granular:.01,default:2},restDelta:{granular:.005,default:.5},minDuration:.01,maxDuration:10,minDamping:.05,maxDamping:1},ar=.001;function Wm({duration:e=De.duration,bounce:t=De.bounce,velocity:n=De.velocity,mass:s=De.mass}){let r,i,a=1-t;a=an(De.minDamping,De.maxDamping,a),e=an(De.minDuration,De.maxDuration,Rt(e)),a<1?(r=d=>{const u=d*a,m=u*e,_=u-n,b=yr(d,a),x=Math.exp(-m);return ar-_/b*x},i=d=>{const m=d*a*e,_=m*n+n,b=Math.pow(a,2)*Math.pow(d,2)*e,x=Math.exp(-m),y=yr(Math.pow(d,2),a);return(-r(d)+ar>0?-1:1)*((_-b)*x)/y}):(r=d=>{const u=Math.exp(-d*e),m=(d-n)*e+1;return-ar+u*m},i=d=>{const u=Math.exp(-d*e),m=(n-d)*(e*e);return u*m});const c=5/e,l=Xm(r,i,c);if(e=Mt(e),isNaN(l))return{stiffness:De.stiffness,damping:De.damping,duration:e};{const d=Math.pow(l,2)*s;return{stiffness:d,damping:a*2*Math.sqrt(s*d),duration:e}}}const Ym=12;function Xm(e,t,n){let s=n;for(let r=1;r<Ym;r++)s=s-e(s)/t(s);return s}function yr(e,t){return e*Math.sqrt(1-t*t)}const Qm=["duration","bounce"],ef=["stiffness","damping","mass"];function Vi(e,t){return t.some(n=>e[n]!==void 0)}function tf(e){let t={velocity:De.velocity,stiffness:De.stiffness,damping:De.damping,mass:De.mass,isResolvedFromDuration:!1,...e};if(!Vi(e,ef)&&Vi(e,Qm))if(e.visualDuration){const n=e.visualDuration,s=2*Math.PI/(n*1.2),r=s*s,i=2*an(.05,1,1-(e.bounce||0))*Math.sqrt(r);t={...t,mass:De.mass,stiffness:r,damping:i}}else{const n=Wm(e);t={...t,...n,mass:De.mass},t.isResolvedFromDuration=!0}return t}function Zr(e=De.visualDuration,t=De.bounce){const n=typeof e!="object"?{visualDuration:e,keyframes:[0,1],bounce:t}:e;let{restSpeed:s,restDelta:r}=n;const i=n.keyframes[0],a=n.keyframes[n.keyframes.length-1],c={done:!1,value:i},{stiffness:l,damping:d,mass:u,duration:m,velocity:_,isResolvedFromDuration:b}=tf({...n,velocity:-Rt(n.velocity||0)}),x=_||0,y=d/(2*Math.sqrt(l*u)),I=a-i,g=Rt(Math.sqrt(l/u)),C=Math.abs(I)<5;s||(s=C?De.restSpeed.granular:De.restSpeed.default),r||(r=C?De.restDelta.granular:De.restDelta.default);let O;if(y<1){const j=yr(g,y);O=Y=>{const N=Math.exp(-y*g*Y);return a-N*((x+y*g*I)/j*Math.sin(j*Y)+I*Math.cos(j*Y))}}else if(y===1)O=j=>a-Math.exp(-g*j)*(I+(x+g*I)*j);else{const j=g*Math.sqrt(y*y-1);O=Y=>{const N=Math.exp(-y*g*Y),z=Math.min(j*Y,300);return a-N*((x+y*g*I)*Math.sinh(z)+j*I*Math.cosh(z))/j}}const P={calculatedDuration:b&&m||null,next:j=>{const Y=O(j);if(b)c.done=j>=m;else{let N=0;y<1&&(N=j===0?Mt(x):oo(O,j,Y));const z=Math.abs(N)<=s,D=Math.abs(a-Y)<=r;c.done=z&&D}return c.value=c.done?a:Y,c},toString:()=>{const j=Math.min(Vr(P),Rs),Y=io(N=>P.next(j*N).value,j,30);return j+"ms "+Y}};return P}function nf(e,t=100,n){const s=n({...e,keyframes:[0,t]}),r=Math.min(Vr(s),Rs);return{type:"keyframes",ease:i=>s.next(r*i).value/t,duration:Rt(r)}}function Ks(e){return typeof e=="function"}const sf=(e,t,n)=>{const s=t-e;return((n-e)%s+s)%s+e},co=e=>Array.isArray(e)&&typeof e[0]!="number";function lo(e,t){return co(e)?e[sf(0,e.length,t)]:e}const Qn=(e,t,n)=>e+(t-e)*n;function uo(e,t){const n=e[e.length-1];for(let s=1;s<=t;s++){const r=Js(0,t,s);e.push(Qn(n,1,r))}}function po(e){const t=[0];return uo(t,e.length-1),t}const it=e=>!!(e&&e.getVelocity);function rf(e,t,n){var s;if(e instanceof Element)return[e];if(typeof e=="string"){let r=document;const i=(s=n?.[e])!==null&&s!==void 0?s:r.querySelectorAll(e);return i?Array.from(i):[]}return Array.from(e)}function Hr(e){return typeof e=="object"&&!Array.isArray(e)}function mo(e,t,n,s){return typeof e=="string"&&Hr(t)?rf(e,n,s):e instanceof NodeList?Array.from(e):Array.isArray(e)?e:[e]}function af(e,t,n){return e*(t+1)}function Zi(e,t,n,s){var r;return typeof t=="number"?t:t.startsWith("-")||t.startsWith("+")?Math.max(0,e+parseFloat(t)):t==="<"?n:(r=s.get(t))!==null&&r!==void 0?r:e}function of(e,t){e.indexOf(t)===-1&&e.push(t)}function fo(e,t){const n=e.indexOf(t);n>-1&&e.splice(n,1)}function cf(e,t,n){for(let s=0;s<e.length;s++){const r=e[s];r.at>t&&r.at<n&&(fo(e,r),s--)}}function lf(e,t,n,s,r,i){cf(e,r,i);for(let a=0;a<t.length;a++)e.push({value:t[a],at:Qn(r,i,s[a]),easing:lo(n,a)})}function df(e,t){for(let n=0;n<e.length;n++)e[n]=e[n]/(t+1)}function uf(e,t){return e.at===t.at?e.value===null?1:t.value===null?-1:0:e.at-t.at}const pf="easeInOut";function mf(e,{defaultTransition:t={},...n}={},s,r){const i=t.duration||.3,a=new Map,c=new Map,l={},d=new Map;let u=0,m=0,_=0;for(let b=0;b<e.length;b++){const x=e[b];if(typeof x=="string"){d.set(x,m);continue}else if(!Array.isArray(x)){d.set(x.name,Zi(m,x.at,u,d));continue}let[y,I,g={}]=x;g.at!==void 0&&(m=Zi(m,g.at,u,d));let C=0;const O=(P,j,Y,N=0,z=0)=>{const D=ff(P),{delay:R=0,times:Z=po(D),type:le="keyframes",repeat:ee,repeatType:U,repeatDelay:se=0,...re}=j;let{ease:ue=t.ease||"easeOut",duration:ce}=j;const Ee=typeof R=="function"?R(N,z):R,ve=D.length,je=Ks(le)?le:r?.[le];if(ve<=2&&je){let me=100;if(ve===2&&vf(D)){const pe=D[1]-D[0];me=Math.abs(pe)}const de={...re};ce!==void 0&&(de.duration=Mt(ce));const fe=nf(de,me,je);ue=fe.ease,ce=fe.duration}ce??(ce=i);const ne=m+Ee;Z.length===1&&Z[0]===0&&(Z[1]=1);const X=Z.length-D.length;if(X>0&&uo(Z,X),D.length===1&&D.unshift(null),ee){ce=af(ce,ee);const me=[...D],de=[...Z];ue=Array.isArray(ue)?[...ue]:[ue];const fe=[...ue];for(let pe=0;pe<ee;pe++){D.push(...me);for(let be=0;be<me.length;be++)Z.push(de[be]+(pe+1)),ue.push(be===0?"linear":lo(fe,be-1))}df(Z,ee)}const $e=ne+ce;lf(Y,D,ue,Z,ne,$e),C=Math.max(Ee+ce,C),_=Math.max($e,_)};if(it(y)){const P=Hi(y,c);O(I,g,Bi("default",P))}else{const P=mo(y,I,s,l),j=P.length;for(let Y=0;Y<j;Y++){I=I,g=g;const N=P[Y],z=Hi(N,c);for(const D in I)O(I[D],hf(g,D),Bi(D,z),Y,j)}}u=m,m+=C}return c.forEach((b,x)=>{for(const y in b){const I=b[y];I.sort(uf);const g=[],C=[],O=[];for(let j=0;j<I.length;j++){const{at:Y,value:N,easing:z}=I[j];g.push(N),C.push(Js(0,_,Y)),O.push(z||"easeOut")}C[0]!==0&&(C.unshift(0),g.unshift(g[0]),O.unshift(pf)),C[C.length-1]!==1&&(C.push(1),g.push(null)),a.has(x)||a.set(x,{keyframes:{},transition:{}});const P=a.get(x);P.keyframes[y]=g,P.transition[y]={...t,duration:_,ease:O,times:C,...n}}}),a}function Hi(e,t){return!t.has(e)&&t.set(e,{}),t.get(e)}function Bi(e,t){return t[e]||(t[e]=[]),t[e]}function ff(e){return Array.isArray(e)?e:[e]}function hf(e,t){return e&&e[t]?{...e,...e[t]}:{...e}}const gf=e=>typeof e=="number",vf=e=>e.every(gf),En=new WeakMap;function ho(e,t){return e?e[t]||e.default||e:void 0}const Cn=["transformPerspective","x","y","z","translateX","translateY","translateZ","scale","scaleX","scaleY","rotate","rotateX","rotateY","rotateZ","skew","skewX","skewY"],Mn=new Set(Cn),go=new Set(["width","height","top","left","right","bottom",...Cn]),yf=e=>Array.isArray(e),bf=e=>yf(e)?e[e.length-1]||0:e,wf={useManualTiming:!1};function Sf(e){let t=new Set,n=new Set,s=!1,r=!1;const i=new WeakSet;let a={delta:0,timestamp:0,isProcessing:!1};function c(d){i.has(d)&&(l.schedule(d),e()),d(a)}const l={schedule:(d,u=!1,m=!1)=>{const b=m&&s?t:n;return u&&i.add(d),b.has(d)||b.add(d),d},cancel:d=>{n.delete(d),i.delete(d)},process:d=>{if(a=d,s){r=!0;return}s=!0,[t,n]=[n,t],t.forEach(c),t.clear(),s=!1,r&&(r=!1,l.process(d))}};return l}const Ss=["read","resolveKeyframes","update","preRender","render","postRender"],_f=40;function kf(e,t){let n=!1,s=!0;const r={delta:0,timestamp:0,isProcessing:!1},i=()=>n=!0,a=Ss.reduce((g,C)=>(g[C]=Sf(i),g),{}),{read:c,resolveKeyframes:l,update:d,preRender:u,render:m,postRender:_}=a,b=()=>{const g=performance.now();n=!1,r.delta=s?1e3/60:Math.max(Math.min(g-r.timestamp,_f),1),r.timestamp=g,r.isProcessing=!0,c.process(r),l.process(r),d.process(r),u.process(r),m.process(r),_.process(r),r.isProcessing=!1,n&&t&&(s=!1,e(b))},x=()=>{n=!0,s=!0,r.isProcessing||e(b)};return{schedule:Ss.reduce((g,C)=>{const O=a[C];return g[C]=(P,j=!1,Y=!1)=>(n||x(),O.schedule(P,j,Y)),g},{}),cancel:g=>{for(let C=0;C<Ss.length;C++)a[Ss[C]].cancel(g)},state:r,steps:a}}const{schedule:Pt,cancel:br,state:Ps}=kf(typeof requestAnimationFrame<"u"?requestAnimationFrame:rn,!0);let $s;function xf(){$s=void 0}const qt={now:()=>($s===void 0&&qt.set(Ps.isProcessing||wf.useManualTiming?Ps.timestamp:performance.now()),$s),set:e=>{$s=e,queueMicrotask(xf)}};class vo{constructor(){this.subscriptions=[]}add(t){return of(this.subscriptions,t),()=>fo(this.subscriptions,t)}notify(t,n,s){const r=this.subscriptions.length;if(r)if(r===1)this.subscriptions[0](t,n,s);else for(let i=0;i<r;i++){const a=this.subscriptions[i];a&&a(t,n,s)}}getSize(){return this.subscriptions.length}clear(){this.subscriptions.length=0}}const Ji=30,$f=e=>!isNaN(parseFloat(e));class Ef{constructor(t,n={}){this.version="11.18.2",this.canTrackVelocity=null,this.events={},this.updateAndNotify=(s,r=!0)=>{const i=qt.now();this.updatedAt!==i&&this.setPrevFrameValue(),this.prev=this.current,this.setCurrent(s),this.current!==this.prev&&this.events.change&&this.events.change.notify(this.current),r&&this.events.renderRequest&&this.events.renderRequest.notify(this.current)},this.hasAnimated=!1,this.setCurrent(t),this.owner=n.owner}setCurrent(t){this.current=t,this.updatedAt=qt.now(),this.canTrackVelocity===null&&t!==void 0&&(this.canTrackVelocity=$f(this.current))}setPrevFrameValue(t=this.current){this.prevFrameValue=t,this.prevUpdatedAt=this.updatedAt}onChange(t){return this.on("change",t)}on(t,n){this.events[t]||(this.events[t]=new vo);const s=this.events[t].add(n);return t==="change"?()=>{s(),Pt.read(()=>{this.events.change.getSize()||this.stop()})}:s}clearListeners(){for(const t in this.events)this.events[t].clear()}attach(t,n){this.passiveEffect=t,this.stopPassiveEffect=n}set(t,n=!0){!n||!this.passiveEffect?this.updateAndNotify(t,n):this.passiveEffect(t,this.updateAndNotify)}setWithVelocity(t,n,s){this.set(n),this.prev=void 0,this.prevFrameValue=t,this.prevUpdatedAt=this.updatedAt-s}jump(t,n=!0){this.updateAndNotify(t),this.prev=t,this.prevUpdatedAt=this.prevFrameValue=void 0,n&&this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}get(){return this.current}getPrevious(){return this.prev}getVelocity(){const t=qt.now();if(!this.canTrackVelocity||this.prevFrameValue===void 0||t-this.updatedAt>Ji)return 0;const n=Math.min(this.updatedAt-this.prevUpdatedAt,Ji);return ao(parseFloat(this.current)-parseFloat(this.prevFrameValue),n)}start(t){return this.stop(),new Promise(n=>{this.hasAnimated=!0,this.animation=t(n),this.events.animationStart&&this.events.animationStart.notify()}).then(()=>{this.events.animationComplete&&this.events.animationComplete.notify(),this.clearAnimation()})}stop(){this.animation&&(this.animation.stop(),this.events.animationCancel&&this.events.animationCancel.notify()),this.clearAnimation()}isAnimating(){return!!this.animation}clearAnimation(){delete this.animation}destroy(){this.clearListeners(),this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}}function Gn(e,t){return new Ef(e,t)}function Ki(e){const t=[{},{}];return e?.values.forEach((n,s)=>{t[0][s]=n.get(),t[1][s]=n.getVelocity()}),t}function yo(e,t,n,s){if(typeof t=="function"){const[r,i]=Ki(s);t=t(n!==void 0?n:e.custom,r,i)}if(typeof t=="string"&&(t=e.variants&&e.variants[t]),typeof t=="function"){const[r,i]=Ki(s);t=t(n!==void 0?n:e.custom,r,i)}return t}function Tf(e,t,n){const s=e.getProps();return yo(s,t,s.custom,e)}function Af(e,t,n){e.hasValue(t)?e.getValue(t).set(n):e.addValue(t,Gn(n))}function If(e,t){const n=Tf(e,t);let{transitionEnd:s={},transition:r={},...i}=n||{};i={...i,...s};for(const a in i){const c=bf(i[a]);Af(e,a,c)}}function Cf(e){return!!(it(e)&&e.add)}function Mf(e,t){const n=e.getValue("willChange");if(Cf(n))return n.add(t)}const Br=e=>e.replace(/([a-z])([A-Z])/gu,"$1-$2").toLowerCase(),Rf="framerAppearId",Pf="data-"+Br(Rf);function Lf(e){return e.props[Pf]}function Gi(e,t){e.timeline=t,e.onfinish=null}const Jr=e=>Array.isArray(e)&&typeof e[0]=="number",Of={linearEasing:void 0};function zf(e,t){const n=Ur(e);return()=>{var s;return(s=Of[t])!==null&&s!==void 0?s:n()}}const Ls=zf(()=>{try{document.createElement("div").animate({opacity:0},{easing:"linear(0, 1)"})}catch{return!1}return!0},"linearEasing");function bo(e){return!!(typeof e=="function"&&Ls()||!e||typeof e=="string"&&(e in wr||Ls())||Jr(e)||Array.isArray(e)&&e.every(bo))}const Hn=([e,t,n,s])=>`cubic-bezier(${e}, ${t}, ${n}, ${s})`,wr={linear:"linear",ease:"ease",easeIn:"ease-in",easeOut:"ease-out",easeInOut:"ease-in-out",circIn:Hn([0,.65,.55,1]),circOut:Hn([.55,0,1,.45]),backIn:Hn([.31,.01,.66,-.59]),backOut:Hn([.33,1.53,.69,.99])};function wo(e,t){if(e)return typeof e=="function"&&Ls()?io(e,t):Jr(e)?Hn(e):Array.isArray(e)?e.map(n=>wo(n,t)||wr.easeOut):wr[e]}const So=(e,t,n)=>(((1-3*n+3*t)*e+(3*n-6*t))*e+3*t)*e,Nf=1e-7,Df=12;function jf(e,t,n,s,r){let i,a,c=0;do a=t+(n-t)/2,i=So(a,s,r)-e,i>0?n=a:t=a;while(Math.abs(i)>Nf&&++c<Df);return a}function es(e,t,n,s){if(e===t&&n===s)return rn;const r=i=>jf(i,0,1,e,n);return i=>i===0||i===1?i:So(r(i),t,s)}const _o=e=>t=>t<=.5?e(2*t)/2:(2-e(2*(1-t)))/2,ko=e=>t=>1-e(1-t),xo=es(.33,1.53,.69,.99),Kr=ko(xo),$o=_o(Kr),Eo=e=>(e*=2)<1?.5*Kr(e):.5*(2-Math.pow(2,-10*(e-1))),Gr=e=>1-Math.sin(Math.acos(e)),qf=ko(Gr),To=_o(Gr),Ao=e=>/^0[^.\s]+$/u.test(e);function Ff(e){return typeof e=="number"?e===0:e!==null?e==="none"||e==="0"||Ao(e):!0}const Rn={test:e=>typeof e=="number",parse:parseFloat,transform:e=>e},Wn={...Rn,transform:e=>an(0,1,e)},_s={...Rn,default:1},Jn=e=>Math.round(e*1e5)/1e5,Wr=/-?(?:\d+(?:\.\d+)?|\.\d+)/gu;function Uf(e){return e==null}const Vf=/^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu,Yr=(e,t)=>n=>!!(typeof n=="string"&&Vf.test(n)&&n.startsWith(e)||t&&!Uf(n)&&Object.prototype.hasOwnProperty.call(n,t)),Io=(e,t,n)=>s=>{if(typeof s!="string")return s;const[r,i,a,c]=s.match(Wr);return{[e]:parseFloat(r),[t]:parseFloat(i),[n]:parseFloat(a),alpha:c!==void 0?parseFloat(c):1}},Zf=e=>an(0,255,e),or={...Rn,transform:e=>Math.round(Zf(e))},nn={test:Yr("rgb","red"),parse:Io("red","green","blue"),transform:({red:e,green:t,blue:n,alpha:s=1})=>"rgba("+or.transform(e)+", "+or.transform(t)+", "+or.transform(n)+", "+Jn(Wn.transform(s))+")"};function Hf(e){let t="",n="",s="",r="";return e.length>5?(t=e.substring(1,3),n=e.substring(3,5),s=e.substring(5,7),r=e.substring(7,9)):(t=e.substring(1,2),n=e.substring(2,3),s=e.substring(3,4),r=e.substring(4,5),t+=t,n+=n,s+=s,r+=r),{red:parseInt(t,16),green:parseInt(n,16),blue:parseInt(s,16),alpha:r?parseInt(r,16)/255:1}}const Sr={test:Yr("#"),parse:Hf,transform:nn.transform},ts=e=>({test:t=>typeof t=="string"&&t.endsWith(e)&&t.split(" ").length===1,parse:parseFloat,transform:t=>`${t}${e}`}),jt=ts("deg"),xn=ts("%"),ae=ts("px"),Bf=ts("vh"),Jf=ts("vw"),Wi={...xn,parse:e=>xn.parse(e)/100,transform:e=>xn.transform(e*100)},_n={test:Yr("hsl","hue"),parse:Io("hue","saturation","lightness"),transform:({hue:e,saturation:t,lightness:n,alpha:s=1})=>"hsla("+Math.round(e)+", "+xn.transform(Jn(t))+", "+xn.transform(Jn(n))+", "+Jn(Wn.transform(s))+")"},Qe={test:e=>nn.test(e)||Sr.test(e)||_n.test(e),parse:e=>nn.test(e)?nn.parse(e):_n.test(e)?_n.parse(e):Sr.parse(e),transform:e=>typeof e=="string"?e:e.hasOwnProperty("red")?nn.transform(e):_n.transform(e)},Kf=/(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;function Gf(e){var t,n;return isNaN(e)&&typeof e=="string"&&(((t=e.match(Wr))===null||t===void 0?void 0:t.length)||0)+(((n=e.match(Kf))===null||n===void 0?void 0:n.length)||0)>0}const Co="number",Mo="color",Wf="var",Yf="var(",Yi="${}",Xf=/var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;function Yn(e){const t=e.toString(),n=[],s={color:[],number:[],var:[]},r=[];let i=0;const c=t.replace(Xf,l=>(Qe.test(l)?(s.color.push(i),r.push(Mo),n.push(Qe.parse(l))):l.startsWith(Yf)?(s.var.push(i),r.push(Wf),n.push(l)):(s.number.push(i),r.push(Co),n.push(parseFloat(l))),++i,Yi)).split(Yi);return{values:n,split:c,indexes:s,types:r}}function Ro(e){return Yn(e).values}function Po(e){const{split:t,types:n}=Yn(e),s=t.length;return r=>{let i="";for(let a=0;a<s;a++)if(i+=t[a],r[a]!==void 0){const c=n[a];c===Co?i+=Jn(r[a]):c===Mo?i+=Qe.transform(r[a]):i+=r[a]}return i}}const Qf=e=>typeof e=="number"?0:e;function eh(e){const t=Ro(e);return Po(e)(t.map(Qf))}const Pn={test:Gf,parse:Ro,createTransformer:Po,getAnimatableNone:eh},th=new Set(["brightness","contrast","saturate","opacity"]);function nh(e){const[t,n]=e.slice(0,-1).split("(");if(t==="drop-shadow")return e;const[s]=n.match(Wr)||[];if(!s)return e;const r=n.replace(s,"");let i=th.has(t)?1:0;return s!==n&&(i*=100),t+"("+i+r+")"}const sh=/\b([a-z-]*)\(.*?\)/gu,_r={...Pn,getAnimatableNone:e=>{const t=e.match(sh);return t?t.map(nh).join(" "):e}},rh={borderWidth:ae,borderTopWidth:ae,borderRightWidth:ae,borderBottomWidth:ae,borderLeftWidth:ae,borderRadius:ae,radius:ae,borderTopLeftRadius:ae,borderTopRightRadius:ae,borderBottomRightRadius:ae,borderBottomLeftRadius:ae,width:ae,maxWidth:ae,height:ae,maxHeight:ae,top:ae,right:ae,bottom:ae,left:ae,padding:ae,paddingTop:ae,paddingRight:ae,paddingBottom:ae,paddingLeft:ae,margin:ae,marginTop:ae,marginRight:ae,marginBottom:ae,marginLeft:ae,backgroundPositionX:ae,backgroundPositionY:ae},ih={rotate:jt,rotateX:jt,rotateY:jt,rotateZ:jt,scale:_s,scaleX:_s,scaleY:_s,scaleZ:_s,skew:jt,skewX:jt,skewY:jt,distance:ae,translateX:ae,translateY:ae,translateZ:ae,x:ae,y:ae,z:ae,perspective:ae,transformPerspective:ae,opacity:Wn,originX:Wi,originY:Wi,originZ:ae},Xi={...Rn,transform:Math.round},Xr={...rh,...ih,zIndex:Xi,size:ae,fillOpacity:Wn,strokeOpacity:Wn,numOctaves:Xi},ah={...Xr,color:Qe,backgroundColor:Qe,outlineColor:Qe,fill:Qe,stroke:Qe,borderColor:Qe,borderTopColor:Qe,borderRightColor:Qe,borderBottomColor:Qe,borderLeftColor:Qe,filter:_r,WebkitFilter:_r},Qr=e=>ah[e];function Lo(e,t){let n=Qr(e);return n!==_r&&(n=Pn),n.getAnimatableNone?n.getAnimatableNone(t):void 0}const oh=new Set(["auto","none","0"]);function ch(e,t,n){let s=0,r;for(;s<e.length&&!r;){const i=e[s];typeof i=="string"&&!oh.has(i)&&Yn(i).values.length&&(r=e[s]),s++}if(r&&n)for(const i of t)e[i]=Lo(n,r)}const Qi=e=>e===Rn||e===ae,ea=(e,t)=>parseFloat(e.split(", ")[t]),ta=(e,t)=>(n,{transform:s})=>{if(s==="none"||!s)return 0;const r=s.match(/^matrix3d\((.+)\)$/u);if(r)return ea(r[1],t);{const i=s.match(/^matrix\((.+)\)$/u);return i?ea(i[1],e):0}},lh=new Set(["x","y","z"]),dh=Cn.filter(e=>!lh.has(e));function uh(e){const t=[];return dh.forEach(n=>{const s=e.getValue(n);s!==void 0&&(t.push([n,s.get()]),s.set(n.startsWith("scale")?1:0))}),t}const Tn={width:({x:e},{paddingLeft:t="0",paddingRight:n="0"})=>e.max-e.min-parseFloat(t)-parseFloat(n),height:({y:e},{paddingTop:t="0",paddingBottom:n="0"})=>e.max-e.min-parseFloat(t)-parseFloat(n),top:(e,{top:t})=>parseFloat(t),left:(e,{left:t})=>parseFloat(t),bottom:({y:e},{top:t})=>parseFloat(t)+(e.max-e.min),right:({x:e},{left:t})=>parseFloat(t)+(e.max-e.min),x:ta(4,13),y:ta(5,14)};Tn.translateX=Tn.x;Tn.translateY=Tn.y;const sn=new Set;let kr=!1,xr=!1;function Oo(){if(xr){const e=Array.from(sn).filter(s=>s.needsMeasurement),t=new Set(e.map(s=>s.element)),n=new Map;t.forEach(s=>{const r=uh(s);r.length&&(n.set(s,r),s.render())}),e.forEach(s=>s.measureInitialState()),t.forEach(s=>{s.render();const r=n.get(s);r&&r.forEach(([i,a])=>{var c;(c=s.getValue(i))===null||c===void 0||c.set(a)})}),e.forEach(s=>s.measureEndState()),e.forEach(s=>{s.suspendedScrollY!==void 0&&window.scrollTo(0,s.suspendedScrollY)})}xr=!1,kr=!1,sn.forEach(e=>e.complete()),sn.clear()}function zo(){sn.forEach(e=>{e.readKeyframes(),e.needsMeasurement&&(xr=!0)})}function ph(){zo(),Oo()}class ei{constructor(t,n,s,r,i,a=!1){this.isComplete=!1,this.isAsync=!1,this.needsMeasurement=!1,this.isScheduled=!1,this.unresolvedKeyframes=[...t],this.onComplete=n,this.name=s,this.motionValue=r,this.element=i,this.isAsync=a}scheduleResolve(){this.isScheduled=!0,this.isAsync?(sn.add(this),kr||(kr=!0,Pt.read(zo),Pt.resolveKeyframes(Oo))):(this.readKeyframes(),this.complete())}readKeyframes(){const{unresolvedKeyframes:t,name:n,element:s,motionValue:r}=this;for(let i=0;i<t.length;i++)if(t[i]===null)if(i===0){const a=r?.get(),c=t[t.length-1];if(a!==void 0)t[0]=a;else if(s&&n){const l=s.readValue(n,c);l!=null&&(t[0]=l)}t[0]===void 0&&(t[0]=c),r&&a===void 0&&r.set(t[0])}else t[i]=t[i-1]}setFinalKeyframe(){}measureInitialState(){}renderEndStyles(){}measureEndState(){}complete(){this.isComplete=!0,this.onComplete(this.unresolvedKeyframes,this.finalKeyframe),sn.delete(this)}cancel(){this.isComplete||(this.isScheduled=!1,sn.delete(this))}resume(){this.isComplete||this.scheduleResolve()}}const No=e=>/^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(e),Do=e=>t=>typeof t=="string"&&t.startsWith(e),jo=Do("--"),mh=Do("var(--"),ti=e=>mh(e)?fh.test(e.split("/*")[0].trim()):!1,fh=/var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu,hh=/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;function gh(e){const t=hh.exec(e);if(!t)return[,];const[,n,s,r]=t;return[`--${n??s}`,r]}function qo(e,t,n=1){const[s,r]=gh(e);if(!s)return;const i=window.getComputedStyle(t).getPropertyValue(s);if(i){const a=i.trim();return No(a)?parseFloat(a):a}return ti(r)?qo(r,t,n+1):r}const Fo=e=>t=>t.test(e),vh={test:e=>e==="auto",parse:e=>e},Uo=[Rn,ae,xn,jt,Jf,Bf,vh],na=e=>Uo.find(Fo(e));class Vo extends ei{constructor(t,n,s,r,i){super(t,n,s,r,i,!0)}readKeyframes(){const{unresolvedKeyframes:t,element:n,name:s}=this;if(!n||!n.current)return;super.readKeyframes();for(let l=0;l<t.length;l++){let d=t[l];if(typeof d=="string"&&(d=d.trim(),ti(d))){const u=qo(d,n.current);u!==void 0&&(t[l]=u),l===t.length-1&&(this.finalKeyframe=d)}}if(this.resolveNoneKeyframes(),!go.has(s)||t.length!==2)return;const[r,i]=t,a=na(r),c=na(i);if(a!==c)if(Qi(a)&&Qi(c))for(let l=0;l<t.length;l++){const d=t[l];typeof d=="string"&&(t[l]=parseFloat(d))}else this.needsMeasurement=!0}resolveNoneKeyframes(){const{unresolvedKeyframes:t,name:n}=this,s=[];for(let r=0;r<t.length;r++)Ff(t[r])&&s.push(r);s.length&&ch(t,s,n)}measureInitialState(){const{element:t,unresolvedKeyframes:n,name:s}=this;if(!t||!t.current)return;s==="height"&&(this.suspendedScrollY=window.pageYOffset),this.measuredOrigin=Tn[s](t.measureViewportBox(),window.getComputedStyle(t.current)),n[0]=this.measuredOrigin;const r=n[n.length-1];r!==void 0&&t.getValue(s,r).jump(r,!1)}measureEndState(){var t;const{element:n,name:s,unresolvedKeyframes:r}=this;if(!n||!n.current)return;const i=n.getValue(s);i&&i.jump(this.measuredOrigin,!1);const a=r.length-1,c=r[a];r[a]=Tn[s](n.measureViewportBox(),window.getComputedStyle(n.current)),c!==null&&this.finalKeyframe===void 0&&(this.finalKeyframe=c),!((t=this.removedTransforms)===null||t===void 0)&&t.length&&this.removedTransforms.forEach(([l,d])=>{n.getValue(l).set(d)}),this.resolveNoneKeyframes()}}const sa=(e,t)=>t==="zIndex"?!1:!!(typeof e=="number"||Array.isArray(e)||typeof e=="string"&&(Pn.test(e)||e==="0")&&!e.startsWith("url("));function yh(e){const t=e[0];if(e.length===1)return!0;for(let n=0;n<e.length;n++)if(e[n]!==t)return!0}function bh(e,t,n,s){const r=e[0];if(r===null)return!1;if(t==="display"||t==="visibility")return!0;const i=e[e.length-1],a=sa(r,t),c=sa(i,t);return!a||!c?!1:yh(e)||(n==="spring"||Ks(n))&&s}const wh=e=>e!==null;function Gs(e,{repeat:t,repeatType:n="loop"},s){const r=e.filter(wh),i=t&&n!=="loop"&&t%2===1?0:r.length-1;return!i||s===void 0?r[i]:s}const Sh=40;class Zo{constructor({autoplay:t=!0,delay:n=0,type:s="keyframes",repeat:r=0,repeatDelay:i=0,repeatType:a="loop",...c}){this.isStopped=!1,this.hasAttemptedResolve=!1,this.createdAt=qt.now(),this.options={autoplay:t,delay:n,type:s,repeat:r,repeatDelay:i,repeatType:a,...c},this.updateFinishedPromise()}calcStartTime(){return this.resolvedAt?this.resolvedAt-this.createdAt>Sh?this.resolvedAt:this.createdAt:this.createdAt}get resolved(){return!this._resolved&&!this.hasAttemptedResolve&&ph(),this._resolved}onKeyframesResolved(t,n){this.resolvedAt=qt.now(),this.hasAttemptedResolve=!0;const{name:s,type:r,velocity:i,delay:a,onComplete:c,onUpdate:l,isGenerator:d}=this.options;if(!d&&!bh(t,s,r,i))if(a)this.options.duration=0;else{l&&l(Gs(t,this.options,n)),c&&c(),this.resolveFinishedPromise();return}const u=this.initPlayback(t,n);u!==!1&&(this._resolved={keyframes:t,finalKeyframe:n,...u},this.onPostResolved())}onPostResolved(){}then(t,n){return this.currentFinishedPromise.then(t,n)}flatten(){this.options.type="keyframes",this.options.ease="linear"}updateFinishedPromise(){this.currentFinishedPromise=new Promise(t=>{this.resolveFinishedPromise=t})}}function cr(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+(t-e)*6*n:n<1/2?t:n<2/3?e+(t-e)*(2/3-n)*6:e}function _h({hue:e,saturation:t,lightness:n,alpha:s}){e/=360,t/=100,n/=100;let r=0,i=0,a=0;if(!t)r=i=a=n;else{const c=n<.5?n*(1+t):n+t-n*t,l=2*n-c;r=cr(l,c,e+1/3),i=cr(l,c,e),a=cr(l,c,e-1/3)}return{red:Math.round(r*255),green:Math.round(i*255),blue:Math.round(a*255),alpha:s}}function Os(e,t){return n=>n>0?t:e}const lr=(e,t,n)=>{const s=e*e,r=n*(t*t-s)+s;return r<0?0:Math.sqrt(r)},kh=[Sr,nn,_n],xh=e=>kh.find(t=>t.test(e));function ra(e){const t=xh(e);if(!t)return!1;let n=t.parse(e);return t===_n&&(n=_h(n)),n}const ia=(e,t)=>{const n=ra(e),s=ra(t);if(!n||!s)return Os(e,t);const r={...n};return i=>(r.red=lr(n.red,s.red,i),r.green=lr(n.green,s.green,i),r.blue=lr(n.blue,s.blue,i),r.alpha=Qn(n.alpha,s.alpha,i),nn.transform(r))},$h=(e,t)=>n=>t(e(n)),ni=(...e)=>e.reduce($h),$r=new Set(["none","hidden"]);function Eh(e,t){return $r.has(e)?n=>n<=0?e:t:n=>n>=1?t:e}function Th(e,t){return n=>Qn(e,t,n)}function si(e){return typeof e=="number"?Th:typeof e=="string"?ti(e)?Os:Qe.test(e)?ia:Ch:Array.isArray(e)?Ho:typeof e=="object"?Qe.test(e)?ia:Ah:Os}function Ho(e,t){const n=[...e],s=n.length,r=e.map((i,a)=>si(i)(i,t[a]));return i=>{for(let a=0;a<s;a++)n[a]=r[a](i);return n}}function Ah(e,t){const n={...e,...t},s={};for(const r in n)e[r]!==void 0&&t[r]!==void 0&&(s[r]=si(e[r])(e[r],t[r]));return r=>{for(const i in s)n[i]=s[i](r);return n}}function Ih(e,t){var n;const s=[],r={color:0,var:0,number:0};for(let i=0;i<t.values.length;i++){const a=t.types[i],c=e.indexes[a][r[a]],l=(n=e.values[c])!==null&&n!==void 0?n:0;s[i]=l,r[a]++}return s}const Ch=(e,t)=>{const n=Pn.createTransformer(t),s=Yn(e),r=Yn(t);return s.indexes.var.length===r.indexes.var.length&&s.indexes.color.length===r.indexes.color.length&&s.indexes.number.length>=r.indexes.number.length?$r.has(e)&&!r.values.length||$r.has(t)&&!s.values.length?Eh(e,t):ni(Ho(Ih(s,r),r.values),n):Os(e,t)};function Bo(e,t,n){return typeof e=="number"&&typeof t=="number"&&typeof n=="number"?Qn(e,t,n):si(e)(e,t)}function aa({keyframes:e,velocity:t=0,power:n=.8,timeConstant:s=325,bounceDamping:r=10,bounceStiffness:i=500,modifyTarget:a,min:c,max:l,restDelta:d=.5,restSpeed:u}){const m=e[0],_={done:!1,value:m},b=z=>c!==void 0&&z<c||l!==void 0&&z>l,x=z=>c===void 0?l:l===void 0||Math.abs(c-z)<Math.abs(l-z)?c:l;let y=n*t;const I=m+y,g=a===void 0?I:a(I);g!==I&&(y=g-m);const C=z=>-y*Math.exp(-z/s),O=z=>g+C(z),P=z=>{const D=C(z),R=O(z);_.done=Math.abs(D)<=d,_.value=_.done?g:R};let j,Y;const N=z=>{b(_.value)&&(j=z,Y=Zr({keyframes:[_.value,x(_.value)],velocity:oo(O,z,_.value),damping:r,stiffness:i,restDelta:d,restSpeed:u}))};return N(0),{calculatedDuration:null,next:z=>{let D=!1;return!Y&&j===void 0&&(D=!0,P(z),N(z)),j!==void 0&&z>=j?Y.next(z-j):(!D&&P(z),_)}}}const Mh=es(.42,0,1,1),Rh=es(0,0,.58,1),Jo=es(.42,0,.58,1),Ph={linear:rn,easeIn:Mh,easeInOut:Jo,easeOut:Rh,circIn:Gr,circInOut:To,circOut:qf,backIn:Kr,backInOut:$o,backOut:xo,anticipate:Eo},Er=e=>{if(Jr(e)){so(e.length===4);const[t,n,s,r]=e;return es(t,n,s,r)}else if(typeof e=="string")return Ph[e];return e};function Lh(e,t,n){const s=[],r=n||Bo,i=e.length-1;for(let a=0;a<i;a++){let c=r(e[a],e[a+1]);if(t){const l=Array.isArray(t)?t[a]||rn:t;c=ni(l,c)}s.push(c)}return s}function Oh(e,t,{clamp:n=!0,ease:s,mixer:r}={}){const i=e.length;if(so(i===t.length),i===1)return()=>t[0];if(i===2&&t[0]===t[1])return()=>t[1];const a=e[0]===e[1];e[0]>e[i-1]&&(e=[...e].reverse(),t=[...t].reverse());const c=Lh(t,s,r),l=c.length,d=u=>{if(a&&u<e[0])return t[0];let m=0;if(l>1)for(;m<e.length-2&&!(u<e[m+1]);m++);const _=Js(e[m],e[m+1],u);return c[m](_)};return n?u=>d(an(e[0],e[i-1],u)):d}function zh(e,t){return e.map(n=>n*t)}function Nh(e,t){return e.map(()=>t||Jo).splice(0,e.length-1)}function zs({duration:e=300,keyframes:t,times:n,ease:s="easeInOut"}){const r=co(s)?s.map(Er):Er(s),i={done:!1,value:t[0]},a=zh(n&&n.length===t.length?n:po(t),e),c=Oh(a,t,{ease:Array.isArray(r)?r:Nh(t,r)});return{calculatedDuration:e,next:l=>(i.value=c(l),i.done=l>=e,i)}}const Dh=e=>{const t=({timestamp:n})=>e(n);return{start:()=>Pt.update(t,!0),stop:()=>br(t),now:()=>Ps.isProcessing?Ps.timestamp:qt.now()}},jh={decay:aa,inertia:aa,tween:zs,keyframes:zs,spring:Zr},qh=e=>e/100;class ri extends Zo{constructor(t){super(t),this.holdTime=null,this.cancelTime=null,this.currentTime=0,this.playbackSpeed=1,this.pendingPlayState="running",this.startTime=null,this.state="idle",this.stop=()=>{if(this.resolver.cancel(),this.isStopped=!0,this.state==="idle")return;this.teardown();const{onStop:l}=this.options;l&&l()};const{name:n,motionValue:s,element:r,keyframes:i}=this.options,a=r?.KeyframeResolver||ei,c=(l,d)=>this.onKeyframesResolved(l,d);this.resolver=new a(i,c,n,s,r),this.resolver.scheduleResolve()}flatten(){super.flatten(),this._resolved&&Object.assign(this._resolved,this.initPlayback(this._resolved.keyframes))}initPlayback(t){const{type:n="keyframes",repeat:s=0,repeatDelay:r=0,repeatType:i,velocity:a=0}=this.options,c=Ks(n)?n:jh[n]||zs;let l,d;c!==zs&&typeof t[0]!="number"&&(l=ni(qh,Bo(t[0],t[1])),t=[0,100]);const u=c({...this.options,keyframes:t});i==="mirror"&&(d=c({...this.options,keyframes:[...t].reverse(),velocity:-a})),u.calculatedDuration===null&&(u.calculatedDuration=Vr(u));const{calculatedDuration:m}=u,_=m+r,b=_*(s+1)-r;return{generator:u,mirroredGenerator:d,mapPercentToKeyframes:l,calculatedDuration:m,resolvedDuration:_,totalDuration:b}}onPostResolved(){const{autoplay:t=!0}=this.options;this.play(),this.pendingPlayState==="paused"||!t?this.pause():this.state=this.pendingPlayState}tick(t,n=!1){const{resolved:s}=this;if(!s){const{keyframes:z}=this.options;return{done:!0,value:z[z.length-1]}}const{finalKeyframe:r,generator:i,mirroredGenerator:a,mapPercentToKeyframes:c,keyframes:l,calculatedDuration:d,totalDuration:u,resolvedDuration:m}=s;if(this.startTime===null)return i.next(0);const{delay:_,repeat:b,repeatType:x,repeatDelay:y,onUpdate:I}=this.options;this.speed>0?this.startTime=Math.min(this.startTime,t):this.speed<0&&(this.startTime=Math.min(t-u/this.speed,this.startTime)),n?this.currentTime=t:this.holdTime!==null?this.currentTime=this.holdTime:this.currentTime=Math.round(t-this.startTime)*this.speed;const g=this.currentTime-_*(this.speed>=0?1:-1),C=this.speed>=0?g<0:g>u;this.currentTime=Math.max(g,0),this.state==="finished"&&this.holdTime===null&&(this.currentTime=u);let O=this.currentTime,P=i;if(b){const z=Math.min(this.currentTime,u)/m;let D=Math.floor(z),R=z%1;!R&&z>=1&&(R=1),R===1&&D--,D=Math.min(D,b+1),D%2&&(x==="reverse"?(R=1-R,y&&(R-=y/m)):x==="mirror"&&(P=a)),O=an(0,1,R)*m}const j=C?{done:!1,value:l[0]}:P.next(O);c&&(j.value=c(j.value));let{done:Y}=j;!C&&d!==null&&(Y=this.speed>=0?this.currentTime>=u:this.currentTime<=0);const N=this.holdTime===null&&(this.state==="finished"||this.state==="running"&&Y);return N&&r!==void 0&&(j.value=Gs(l,this.options,r)),I&&I(j.value),N&&this.finish(),j}get duration(){const{resolved:t}=this;return t?Rt(t.calculatedDuration):0}get time(){return Rt(this.currentTime)}set time(t){t=Mt(t),this.currentTime=t,this.holdTime!==null||this.speed===0?this.holdTime=t:this.driver&&(this.startTime=this.driver.now()-t/this.speed)}get speed(){return this.playbackSpeed}set speed(t){const n=this.playbackSpeed!==t;this.playbackSpeed=t,n&&(this.time=Rt(this.currentTime))}play(){if(this.resolver.isScheduled||this.resolver.resume(),!this._resolved){this.pendingPlayState="running";return}if(this.isStopped)return;const{driver:t=Dh,onPlay:n,startTime:s}=this.options;this.driver||(this.driver=t(i=>this.tick(i))),n&&n();const r=this.driver.now();this.holdTime!==null?this.startTime=r-this.holdTime:this.startTime?this.state==="finished"&&(this.startTime=r):this.startTime=s??this.calcStartTime(),this.state==="finished"&&this.updateFinishedPromise(),this.cancelTime=this.startTime,this.holdTime=null,this.state="running",this.driver.start()}pause(){var t;if(!this._resolved){this.pendingPlayState="paused";return}this.state="paused",this.holdTime=(t=this.currentTime)!==null&&t!==void 0?t:0}complete(){this.state!=="running"&&this.play(),this.pendingPlayState=this.state="finished",this.holdTime=null}finish(){this.teardown(),this.state="finished";const{onComplete:t}=this.options;t&&t()}cancel(){this.cancelTime!==null&&this.tick(this.cancelTime),this.teardown(),this.updateFinishedPromise()}teardown(){this.state="idle",this.stopDriver(),this.resolveFinishedPromise(),this.updateFinishedPromise(),this.startTime=this.cancelTime=null,this.resolver.cancel()}stopDriver(){this.driver&&(this.driver.stop(),this.driver=void 0)}sample(t){return this.startTime=0,this.tick(t,!0)}}const Fh=new Set(["opacity","clipPath","filter","transform"]);function Uh(e,t,n,{delay:s=0,duration:r=300,repeat:i=0,repeatType:a="loop",ease:c="easeInOut",times:l}={}){const d={[t]:n};l&&(d.offset=l);const u=wo(c,r);return Array.isArray(u)&&(d.easing=u),e.animate(d,{delay:s,duration:r,easing:Array.isArray(u)?"linear":u,fill:"both",iterations:i+1,direction:a==="reverse"?"alternate":"normal"})}const Vh=Ur(()=>Object.hasOwnProperty.call(Element.prototype,"animate")),Ns=10,Zh=2e4;function Hh(e){return Ks(e.type)||e.type==="spring"||!bo(e.ease)}function Bh(e,t){const n=new ri({...t,keyframes:e,repeat:0,delay:0,isGenerator:!0});let s={done:!1,value:e[0]};const r=[];let i=0;for(;!s.done&&i<Zh;)s=n.sample(i),r.push(s.value),i+=Ns;return{times:void 0,keyframes:r,duration:i-Ns,ease:"linear"}}const Ko={anticipate:Eo,backInOut:$o,circInOut:To};function Jh(e){return e in Ko}class oa extends Zo{constructor(t){super(t);const{name:n,motionValue:s,element:r,keyframes:i}=this.options;this.resolver=new Vo(i,(a,c)=>this.onKeyframesResolved(a,c),n,s,r),this.resolver.scheduleResolve()}initPlayback(t,n){let{duration:s=300,times:r,ease:i,type:a,motionValue:c,name:l,startTime:d}=this.options;if(!c.owner||!c.owner.current)return!1;if(typeof i=="string"&&Ls()&&Jh(i)&&(i=Ko[i]),Hh(this.options)){const{onComplete:m,onUpdate:_,motionValue:b,element:x,...y}=this.options,I=Bh(t,y);t=I.keyframes,t.length===1&&(t[1]=t[0]),s=I.duration,r=I.times,i=I.ease,a="keyframes"}const u=Uh(c.owner.current,l,t,{...this.options,duration:s,times:r,ease:i});return u.startTime=d??this.calcStartTime(),this.pendingTimeline?(Gi(u,this.pendingTimeline),this.pendingTimeline=void 0):u.onfinish=()=>{const{onComplete:m}=this.options;c.set(Gs(t,this.options,n)),m&&m(),this.cancel(),this.resolveFinishedPromise()},{animation:u,duration:s,times:r,type:a,ease:i,keyframes:t}}get duration(){const{resolved:t}=this;if(!t)return 0;const{duration:n}=t;return Rt(n)}get time(){const{resolved:t}=this;if(!t)return 0;const{animation:n}=t;return Rt(n.currentTime||0)}set time(t){const{resolved:n}=this;if(!n)return;const{animation:s}=n;s.currentTime=Mt(t)}get speed(){const{resolved:t}=this;if(!t)return 1;const{animation:n}=t;return n.playbackRate}set speed(t){const{resolved:n}=this;if(!n)return;const{animation:s}=n;s.playbackRate=t}get state(){const{resolved:t}=this;if(!t)return"idle";const{animation:n}=t;return n.playState}get startTime(){const{resolved:t}=this;if(!t)return null;const{animation:n}=t;return n.startTime}attachTimeline(t){if(!this._resolved)this.pendingTimeline=t;else{const{resolved:n}=this;if(!n)return rn;const{animation:s}=n;Gi(s,t)}return rn}play(){if(this.isStopped)return;const{resolved:t}=this;if(!t)return;const{animation:n}=t;n.playState==="finished"&&this.updateFinishedPromise(),n.play()}pause(){const{resolved:t}=this;if(!t)return;const{animation:n}=t;n.pause()}stop(){if(this.resolver.cancel(),this.isStopped=!0,this.state==="idle")return;this.resolveFinishedPromise(),this.updateFinishedPromise();const{resolved:t}=this;if(!t)return;const{animation:n,keyframes:s,duration:r,type:i,ease:a,times:c}=t;if(n.playState==="idle"||n.playState==="finished")return;if(this.time){const{motionValue:d,onUpdate:u,onComplete:m,element:_,...b}=this.options,x=new ri({...b,keyframes:s,duration:r,type:i,ease:a,times:c,isGenerator:!0}),y=Mt(this.time);d.setWithVelocity(x.sample(y-Ns).value,x.sample(y).value,Ns)}const{onStop:l}=this.options;l&&l(),this.cancel()}complete(){const{resolved:t}=this;t&&t.animation.finish()}cancel(){const{resolved:t}=this;t&&t.animation.cancel()}static supports(t){const{motionValue:n,name:s,repeatDelay:r,repeatType:i,damping:a,type:c}=t;if(!n||!n.owner||!(n.owner.current instanceof HTMLElement))return!1;const{onUpdate:l,transformTemplate:d}=n.owner.getProps();return Vh()&&s&&Fh.has(s)&&!l&&!d&&!r&&i!=="mirror"&&a!==0&&c!=="inertia"}}const Kh={type:"spring",stiffness:500,damping:25,restSpeed:10},Gh=e=>({type:"spring",stiffness:550,damping:e===0?2*Math.sqrt(550):30,restSpeed:10}),Wh={type:"keyframes",duration:.8},Yh={type:"keyframes",ease:[.25,.1,.35,1],duration:.3},Xh=(e,{keyframes:t})=>t.length>2?Wh:Mn.has(e)?e.startsWith("scale")?Gh(t[1]):Kh:Yh;function Qh({when:e,delay:t,delayChildren:n,staggerChildren:s,staggerDirection:r,repeat:i,repeatType:a,repeatDelay:c,from:l,elapsed:d,...u}){return!!Object.keys(u).length}const Go=(e,t,n,s={},r,i)=>a=>{const c=ho(s,e)||{},l=c.delay||s.delay||0;let{elapsed:d=0}=s;d=d-Mt(l);let u={keyframes:Array.isArray(n)?n:[null,n],ease:"easeOut",velocity:t.getVelocity(),...c,delay:-d,onUpdate:_=>{t.set(_),c.onUpdate&&c.onUpdate(_)},onComplete:()=>{a(),c.onComplete&&c.onComplete()},name:e,motionValue:t,element:i?void 0:r};Qh(c)||(u={...u,...Xh(e,u)}),u.duration&&(u.duration=Mt(u.duration)),u.repeatDelay&&(u.repeatDelay=Mt(u.repeatDelay)),u.from!==void 0&&(u.keyframes[0]=u.from);let m=!1;if((u.type===!1||u.duration===0&&!u.repeatDelay)&&(u.duration=0,u.delay===0&&(m=!0)),m&&!i&&t.get()!==void 0){const _=Gs(u.keyframes,c);if(_!==void 0)return Pt.update(()=>{u.onUpdate(_),u.onComplete()}),new ro([])}return!i&&oa.supports(u)?new oa(u):new ri(u)};function eg({protectedKeys:e,needsAnimating:t},n){const s=e.hasOwnProperty(n)&&t[n]!==!0;return t[n]=!1,s}function tg(e,t,{delay:n=0,transitionOverride:s,type:r}={}){var i;let{transition:a=e.getDefaultTransition(),transitionEnd:c,...l}=t;s&&(a=s);const d=[],u=r&&e.animationState&&e.animationState.getState()[r];for(const m in l){const _=e.getValue(m,(i=e.latestValues[m])!==null&&i!==void 0?i:null),b=l[m];if(b===void 0||u&&eg(u,m))continue;const x={delay:n,...ho(a||{},m)};let y=!1;if(window.MotionHandoffAnimation){const g=Lf(e);if(g){const C=window.MotionHandoffAnimation(g,m,Pt);C!==null&&(x.startTime=C,y=!0)}}Mf(e,m),_.start(Go(m,_,b,e.shouldReduceMotion&&go.has(m)?{type:!1}:x,e,y));const I=_.animation;I&&d.push(I)}return c&&Promise.all(d).then(()=>{Pt.update(()=>{c&&If(e,c)})}),d}function ng(e){return e instanceof SVGElement&&e.tagName!=="svg"}const ca=()=>({min:0,max:0}),ii=()=>({x:ca(),y:ca()}),la={animation:["animate","variants","whileHover","whileTap","exit","whileInView","whileFocus","whileDrag"],exit:["exit"],drag:["drag","dragControls"],focus:["whileFocus"],hover:["whileHover","onHoverStart","onHoverEnd"],tap:["whileTap","onTap","onTapStart","onTapCancel"],pan:["onPan","onPanStart","onPanSessionStart","onPanEnd"],inView:["whileInView","onViewportEnter","onViewportLeave"],layout:["layout","layoutId"]},Tr={};for(const e in la)Tr[e]={isEnabled:t=>la[e].some(n=>!!t[n])};const sg=typeof window<"u",Ar={current:null},Wo={current:!1};function rg(){if(Wo.current=!0,!!sg)if(window.matchMedia){const e=window.matchMedia("(prefers-reduced-motion)"),t=()=>Ar.current=e.matches;e.addListener(t),t()}else Ar.current=!1}const ig=[...Uo,Qe,Pn],ag=e=>ig.find(Fo(e));function og(e){return e!==null&&typeof e=="object"&&typeof e.start=="function"}function cg(e){return typeof e=="string"||Array.isArray(e)}const lg=["animate","whileInView","whileFocus","whileHover","whileTap","whileDrag","exit"],dg=["initial",...lg];function Yo(e){return og(e.animate)||dg.some(t=>cg(e[t]))}function ug(e){return!!(Yo(e)||e.variants)}function pg(e,t,n){for(const s in t){const r=t[s],i=n[s];if(it(r))e.addValue(s,r);else if(it(i))e.addValue(s,Gn(r,{owner:e}));else if(i!==r)if(e.hasValue(s)){const a=e.getValue(s);a.liveStyle===!0?a.jump(r):a.hasAnimated||a.set(r)}else{const a=e.getStaticValue(s);e.addValue(s,Gn(a!==void 0?a:r,{owner:e}))}}for(const s in n)t[s]===void 0&&e.removeValue(s);return t}const da=["AnimationStart","AnimationComplete","Update","BeforeLayoutMeasure","LayoutMeasure","LayoutAnimationStart","LayoutAnimationComplete"];class Xo{scrapeMotionValuesFromProps(t,n,s){return{}}constructor({parent:t,props:n,presenceContext:s,reducedMotionConfig:r,blockInitialAnimation:i,visualState:a},c={}){this.current=null,this.children=new Set,this.isVariantNode=!1,this.isControllingVariants=!1,this.shouldReduceMotion=null,this.values=new Map,this.KeyframeResolver=ei,this.features={},this.valueSubscriptions=new Map,this.prevMotionValues={},this.events={},this.propEventSubscriptions={},this.notifyUpdate=()=>this.notify("Update",this.latestValues),this.render=()=>{this.current&&(this.triggerBuild(),this.renderInstance(this.current,this.renderState,this.props.style,this.projection))},this.renderScheduledAt=0,this.scheduleRender=()=>{const b=qt.now();this.renderScheduledAt<b&&(this.renderScheduledAt=b,Pt.render(this.render,!1,!0))};const{latestValues:l,renderState:d,onUpdate:u}=a;this.onUpdate=u,this.latestValues=l,this.baseTarget={...l},this.initialValues=n.initial?{...l}:{},this.renderState=d,this.parent=t,this.props=n,this.presenceContext=s,this.depth=t?t.depth+1:0,this.reducedMotionConfig=r,this.options=c,this.blockInitialAnimation=!!i,this.isControllingVariants=Yo(n),this.isVariantNode=ug(n),this.isVariantNode&&(this.variantChildren=new Set),this.manuallyAnimateOnMount=!!(t&&t.current);const{willChange:m,..._}=this.scrapeMotionValuesFromProps(n,{},this);for(const b in _){const x=_[b];l[b]!==void 0&&it(x)&&x.set(l[b],!1)}}mount(t){this.current=t,En.set(t,this),this.projection&&!this.projection.instance&&this.projection.mount(t),this.parent&&this.isVariantNode&&!this.isControllingVariants&&(this.removeFromVariantTree=this.parent.addVariantChild(this)),this.values.forEach((n,s)=>this.bindToMotionValue(s,n)),Wo.current||rg(),this.shouldReduceMotion=this.reducedMotionConfig==="never"?!1:this.reducedMotionConfig==="always"?!0:Ar.current,this.parent&&this.parent.children.add(this),this.update(this.props,this.presenceContext)}unmount(){En.delete(this.current),this.projection&&this.projection.unmount(),br(this.notifyUpdate),br(this.render),this.valueSubscriptions.forEach(t=>t()),this.valueSubscriptions.clear(),this.removeFromVariantTree&&this.removeFromVariantTree(),this.parent&&this.parent.children.delete(this);for(const t in this.events)this.events[t].clear();for(const t in this.features){const n=this.features[t];n&&(n.unmount(),n.isMounted=!1)}this.current=null}bindToMotionValue(t,n){this.valueSubscriptions.has(t)&&this.valueSubscriptions.get(t)();const s=Mn.has(t),r=n.on("change",c=>{this.latestValues[t]=c,this.props.onUpdate&&Pt.preRender(this.notifyUpdate),s&&this.projection&&(this.projection.isTransformDirty=!0)}),i=n.on("renderRequest",this.scheduleRender);let a;window.MotionCheckAppearSync&&(a=window.MotionCheckAppearSync(this,t,n)),this.valueSubscriptions.set(t,()=>{r(),i(),a&&a(),n.owner&&n.stop()})}sortNodePosition(t){return!this.current||!this.sortInstanceNodePosition||this.type!==t.type?0:this.sortInstanceNodePosition(this.current,t.current)}updateFeatures(){let t="animation";for(t in Tr){const n=Tr[t];if(!n)continue;const{isEnabled:s,Feature:r}=n;if(!this.features[t]&&r&&s(this.props)&&(this.features[t]=new r(this)),this.features[t]){const i=this.features[t];i.isMounted?i.update():(i.mount(),i.isMounted=!0)}}}triggerBuild(){this.build(this.renderState,this.latestValues,this.props)}measureViewportBox(){return this.current?this.measureInstanceViewportBox(this.current,this.props):ii()}getStaticValue(t){return this.latestValues[t]}setStaticValue(t,n){this.latestValues[t]=n}update(t,n){(t.transformTemplate||this.props.transformTemplate)&&this.scheduleRender(),this.prevProps=this.props,this.props=t,this.prevPresenceContext=this.presenceContext,this.presenceContext=n;for(let s=0;s<da.length;s++){const r=da[s];this.propEventSubscriptions[r]&&(this.propEventSubscriptions[r](),delete this.propEventSubscriptions[r]);const i="on"+r,a=t[i];a&&(this.propEventSubscriptions[r]=this.on(r,a))}this.prevMotionValues=pg(this,this.scrapeMotionValuesFromProps(t,this.prevProps,this),this.prevMotionValues),this.handleChildMotionValue&&this.handleChildMotionValue(),this.onUpdate&&this.onUpdate(this)}getProps(){return this.props}getVariant(t){return this.props.variants?this.props.variants[t]:void 0}getDefaultTransition(){return this.props.transition}getTransformPagePoint(){return this.props.transformPagePoint}getClosestVariantNode(){return this.isVariantNode?this:this.parent?this.parent.getClosestVariantNode():void 0}addVariantChild(t){const n=this.getClosestVariantNode();if(n)return n.variantChildren&&n.variantChildren.add(t),()=>n.variantChildren.delete(t)}addValue(t,n){const s=this.values.get(t);n!==s&&(s&&this.removeValue(t),this.bindToMotionValue(t,n),this.values.set(t,n),this.latestValues[t]=n.get())}removeValue(t){this.values.delete(t);const n=this.valueSubscriptions.get(t);n&&(n(),this.valueSubscriptions.delete(t)),delete this.latestValues[t],this.removeValueFromRenderState(t,this.renderState)}hasValue(t){return this.values.has(t)}getValue(t,n){if(this.props.values&&this.props.values[t])return this.props.values[t];let s=this.values.get(t);return s===void 0&&n!==void 0&&(s=Gn(n===null?void 0:n,{owner:this}),this.addValue(t,s)),s}readValue(t,n){var s;let r=this.latestValues[t]!==void 0||!this.current?this.latestValues[t]:(s=this.getBaseTargetFromProps(this.props,t))!==null&&s!==void 0?s:this.readValueFromInstance(this.current,t,this.options);return r!=null&&(typeof r=="string"&&(No(r)||Ao(r))?r=parseFloat(r):!ag(r)&&Pn.test(n)&&(r=Lo(t,n)),this.setBaseTarget(t,it(r)?r.get():r)),it(r)?r.get():r}setBaseTarget(t,n){this.baseTarget[t]=n}getBaseTarget(t){var n;const{initial:s}=this.props;let r;if(typeof s=="string"||typeof s=="object"){const a=yo(this.props,s,(n=this.presenceContext)===null||n===void 0?void 0:n.custom);a&&(r=a[t])}if(s&&r!==void 0)return r;const i=this.getBaseTargetFromProps(this.props,t);return i!==void 0&&!it(i)?i:this.initialValues[t]!==void 0&&r===void 0?void 0:this.baseTarget[t]}on(t,n){return this.events[t]||(this.events[t]=new vo),this.events[t].add(n)}notify(t,...n){this.events[t]&&this.events[t].notify(...n)}}class Qo extends Xo{constructor(){super(...arguments),this.KeyframeResolver=Vo}sortInstanceNodePosition(t,n){return t.compareDocumentPosition(n)&2?1:-1}getBaseTargetFromProps(t,n){return t.style?t.style[n]:void 0}removeValueFromRenderState(t,{vars:n,style:s}){delete n[t],delete s[t]}handleChildMotionValue(){this.childSubscription&&(this.childSubscription(),delete this.childSubscription);const{children:t}=this.props;it(t)&&(this.childSubscription=t.on("change",n=>{this.current&&(this.current.textContent=`${n}`)}))}}const ec=(e,t)=>t&&typeof e=="number"?t.transform(e):e,mg={x:"translateX",y:"translateY",z:"translateZ",transformPerspective:"perspective"},fg=Cn.length;function hg(e,t,n){let s="",r=!0;for(let i=0;i<fg;i++){const a=Cn[i],c=e[a];if(c===void 0)continue;let l=!0;if(typeof c=="number"?l=c===(a.startsWith("scale")?1:0):l=parseFloat(c)===0,!l||n){const d=ec(c,Xr[a]);if(!l){r=!1;const u=mg[a]||a;s+=`${u}(${d}) `}n&&(t[a]=d)}}return s=s.trim(),n?s=n(t,r?"":s):r&&(s="none"),s}function tc(e,t,n){const{style:s,vars:r,transformOrigin:i}=e;let a=!1,c=!1;for(const l in t){const d=t[l];if(Mn.has(l)){a=!0;continue}else if(jo(l)){r[l]=d;continue}else{const u=ec(d,Xr[l]);l.startsWith("origin")?(c=!0,i[l]=u):s[l]=u}}if(t.transform||(a||n?s.transform=hg(t,e.transform,n):s.transform&&(s.transform="none")),c){const{originX:l="50%",originY:d="50%",originZ:u=0}=i;s.transformOrigin=`${l} ${d} ${u}`}}const gg={offset:"stroke-dashoffset",array:"stroke-dasharray"},vg={offset:"strokeDashoffset",array:"strokeDasharray"};function yg(e,t,n=1,s=0,r=!0){e.pathLength=1;const i=r?gg:vg;e[i.offset]=ae.transform(-s);const a=ae.transform(t),c=ae.transform(n);e[i.array]=`${a} ${c}`}function ua(e,t,n){return typeof e=="string"?e:ae.transform(t+n*e)}function bg(e,t,n){const s=ua(t,e.x,e.width),r=ua(n,e.y,e.height);return`${s} ${r}`}function wg(e,{attrX:t,attrY:n,attrScale:s,originX:r,originY:i,pathLength:a,pathSpacing:c=1,pathOffset:l=0,...d},u,m){if(tc(e,d,m),u){e.style.viewBox&&(e.attrs.viewBox=e.style.viewBox);return}e.attrs=e.style,e.style={};const{attrs:_,style:b,dimensions:x}=e;_.transform&&(x&&(b.transform=_.transform),delete _.transform),x&&(r!==void 0||i!==void 0||b.transform)&&(b.transformOrigin=bg(x,r!==void 0?r:.5,i!==void 0?i:.5)),t!==void 0&&(_.x=t),n!==void 0&&(_.y=n),s!==void 0&&(_.scale=s),a!==void 0&&yg(_,a,c,l,!1)}const nc=new Set(["baseFrequency","diffuseConstant","kernelMatrix","kernelUnitLength","keySplines","keyTimes","limitingConeAngle","markerHeight","markerWidth","numOctaves","targetX","targetY","surfaceScale","specularConstant","specularExponent","stdDeviation","tableValues","viewBox","gradientTransform","pathLength","startOffset","textLength","lengthAdjust"]),Sg=e=>typeof e=="string"&&e.toLowerCase()==="svg";function sc(e,{style:t,vars:n},s,r){Object.assign(e.style,t,r&&r.getProjectionStyles(s));for(const i in n)e.style.setProperty(i,n[i])}function _g(e,t,n,s){sc(e,t,void 0,s);for(const r in t.attrs)e.setAttribute(nc.has(r)?r:Br(r),t.attrs[r])}const kg={};function xg(e,{layout:t,layoutId:n}){return Mn.has(e)||e.startsWith("origin")||(t||n!==void 0)&&(!!kg[e]||e==="opacity")}function rc(e,t,n){var s;const{style:r}=e,i={};for(const a in r)(it(r[a])||t.style&&it(t.style[a])||xg(a,e)||((s=n?.getValue(a))===null||s===void 0?void 0:s.liveStyle)!==void 0)&&(i[a]=r[a]);return i}function $g(e,t,n){const s=rc(e,t,n);for(const r in e)if(it(e[r])||it(t[r])){const i=Cn.indexOf(r)!==-1?"attr"+r.charAt(0).toUpperCase()+r.substring(1):r;s[i]=e[r]}return s}class Eg extends Qo{constructor(){super(...arguments),this.type="svg",this.isSVGTag=!1,this.measureInstanceViewportBox=ii}getBaseTargetFromProps(t,n){return t[n]}readValueFromInstance(t,n){if(Mn.has(n)){const s=Qr(n);return s&&s.default||0}return n=nc.has(n)?n:Br(n),t.getAttribute(n)}scrapeMotionValuesFromProps(t,n,s){return $g(t,n,s)}build(t,n,s){wg(t,n,this.isSVGTag,s.transformTemplate)}renderInstance(t,n,s,r){_g(t,n,s,r)}mount(t){this.isSVGTag=Sg(t.tagName),super.mount(t)}}function Tg({top:e,left:t,right:n,bottom:s}){return{x:{min:t,max:n},y:{min:e,max:s}}}function Ag(e,t){if(!t)return e;const n=t({x:e.left,y:e.top}),s=t({x:e.right,y:e.bottom});return{top:n.y,left:n.x,bottom:s.y,right:s.x}}function Ig(e,t){return Tg(Ag(e.getBoundingClientRect(),t))}function Cg(e){return window.getComputedStyle(e)}class Mg extends Qo{constructor(){super(...arguments),this.type="html",this.renderInstance=sc}readValueFromInstance(t,n){if(Mn.has(n)){const s=Qr(n);return s&&s.default||0}else{const s=Cg(t),r=(jo(n)?s.getPropertyValue(n):s[n])||0;return typeof r=="string"?r.trim():r}}measureInstanceViewportBox(t,{transformPagePoint:n}){return Ig(t,n)}build(t,n,s){tc(t,n,s.transformTemplate)}scrapeMotionValuesFromProps(t,n,s){return rc(t,n,s)}}function Rg(e,t){return e in t}class Pg extends Xo{constructor(){super(...arguments),this.type="object"}readValueFromInstance(t,n){if(Rg(n,t)){const s=t[n];if(typeof s=="string"||typeof s=="number")return s}}getBaseTargetFromProps(){}removeValueFromRenderState(t,n){delete n.output[t]}measureInstanceViewportBox(){return ii()}build(t,n){Object.assign(t.output,n)}renderInstance(t,{output:n}){Object.assign(t,n)}sortInstanceNodePosition(){return 0}}function Lg(e){const t={presenceContext:null,props:{},visualState:{renderState:{transform:{},transformOrigin:{},style:{},vars:{},attrs:{}},latestValues:{}}},n=ng(e)?new Eg(t):new Mg(t);n.mount(e),En.set(e,n)}function Og(e){const t={presenceContext:null,props:{},visualState:{renderState:{output:{}},latestValues:{}}},n=new Pg(t);n.mount(e),En.set(e,n)}function zg(e,t,n){const s=it(e)?e:Gn(e);return s.start(Go("",s,t,n)),s.animation}function Ng(e,t){return it(e)||typeof e=="number"||typeof e=="string"&&!Hr(t)}function ic(e,t,n,s){const r=[];if(Ng(e,t))r.push(zg(e,Hr(t)&&t.default||t,n&&(n.default||n)));else{const i=mo(e,t,s),a=i.length;for(let c=0;c<a;c++){const l=i[c],d=l instanceof Element?Lg:Og;En.has(l)||d(l);const u=En.get(l),m={...n};"delay"in m&&typeof m.delay=="function"&&(m.delay=m.delay(c,a)),r.push(...tg(u,{...t,transition:m},{}))}}return r}function Dg(e,t,n){const s=[];return mf(e,t,n,{spring:Zr}).forEach(({keyframes:i,transition:a},c)=>{s.push(...ic(c,i,a))}),s}function jg(e){return Array.isArray(e)&&e.some(Array.isArray)}function qg(e){function t(n,s,r){let i=[];return jg(n)?i=Dg(n,s,e):i=ic(n,s,r,e),new ro(i)}return t}const Ir=qg();function Fg(e,t){if(e==="first")return 0;{const n=t-1;return e==="last"?n:n/2}}function Ug(e=.1,{startDelay:t=0,from:n=0,ease:s}={}){return(r,i)=>{const a=typeof n=="number"?n:Fg(n,i),c=Math.abs(a-r);let l=e*c;if(s){const d=i*e;l=Er(s)(l/d)*d}return t+l}}async function Vt(e,t={}){const n=await fetch(e,{...t,credentials:"include",headers:{"content-type":"application/json",...t.headers||{}}});if(!n.ok){const r=await n.text().catch(()=>"");let i=r||`${e} failed (${n.status})`;try{const a=r?JSON.parse(r):null;a?.error&&(i=a.error)}catch{}throw new Error(i)}const s=await n.text();return s?JSON.parse(s):{}}function ht(e){return document.getElementById(e)}function Re(e){return String(e||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Vg({title:e,message:t,confirmLabel:n,cancelLabel:s,danger:r}){const i=document.createElement("div");return i.className="tcp-confirm-overlay",i.innerHTML=`
|
|
41
|
+
<div class="tcp-confirm-dialog" role="dialog" aria-modal="true" aria-labelledby="tcp-confirm-title">
|
|
42
|
+
<h3 id="tcp-confirm-title" class="tcp-confirm-title">${Re(e)}</h3>
|
|
43
|
+
<p class="tcp-confirm-message">${Re(t)}</p>
|
|
44
|
+
<div class="tcp-confirm-actions">
|
|
45
|
+
<button type="button" class="tcp-btn" data-confirm-cancel>${Re(s)}</button>
|
|
46
|
+
<button type="button" class="${r?"tcp-btn-danger":"tcp-btn-primary"}" data-confirm-ok>${Re(n)}</button>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
`,i}function ai(e={}){const t=String(e.title||"Confirm action"),n=String(e.message||"Are you sure?"),s=String(e.confirmLabel||"Confirm"),r=String(e.cancelLabel||"Cancel"),i=e.danger!==!1,a=document.querySelector(".tcp-confirm-overlay");a&&a.remove();const c=Vg({title:t,message:n,confirmLabel:s,cancelLabel:r,danger:i});document.body.appendChild(c);const l=c.querySelector("[data-confirm-cancel]"),d=c.querySelector("[data-confirm-ok]");return d instanceof HTMLElement&&d.focus(),new Promise(u=>{const m=b=>{document.removeEventListener("keydown",_),c.remove(),u(b)},_=b=>{b.key==="Escape"&&(b.preventDefault(),m(!1)),b.key==="Enter"&&(b.preventDefault(),m(!0))};document.addEventListener("keydown",_),c.addEventListener("click",b=>{b.target===c&&m(!1)}),l?.addEventListener("click",()=>m(!1)),d?.addEventListener("click",()=>m(!0))})}function ac(e="dashboard"){return(window.location.hash||`#/${e}`).replace(/^#\//,"").split("?")[0].split("/")[0].trim()||e}function oi(e,t,n="dashboard"){return t.find(s=>s[0]===e)?e:n}function Zg(e){window.location.hash=`#/${e}`}function Hg(e){function t(){let r=ht("toasts");return r||(r=document.createElement("div"),r.id="toasts",r.className="toasts",document.body.appendChild(r)),r}function n(){const r=t();r.innerHTML=e.toasts.map(i=>`<div class="toast toast-${i.kind}">${Re(i.text)}</div>`).join("")}function s(r,i){const a=Math.random().toString(36).slice(2);e.toasts.push({id:a,kind:r,text:i}),e.toasts=e.toasts.slice(-4),n(),setTimeout(()=>{e.toasts=e.toasts.filter(c=>c.id!==a),n()},3500)}return{toast:s,renderToasts:n}}const ns=[["dashboard","Dashboard","home"],["chat","Chat","message-square"],["agents","Automations","clock"],["channels","Channels","message-circle"],["mcp","MCP","link"],["packs","Packs","package"],["swarm","Swarm (Live)","share-2"],["files","Files","folder-open"],["memory","Memory","database"],["teams","Teams","users"],["feed","Live Feed","radio"],["settings","Settings","settings"]],Bg=ns.filter(([e])=>!["channels","mcp","packs","files"].includes(e)),Jg={openai:{label:"OpenAI",keyUrl:"https://platform.openai.com/api-keys",placeholder:"sk-proj-..."},anthropic:{label:"Anthropic",keyUrl:"https://console.anthropic.com/settings/keys",placeholder:"sk-ant-..."},google:{label:"Google",keyUrl:"https://aistudio.google.com/app/apikey",placeholder:"AIza..."},groq:{label:"Groq",keyUrl:"https://console.groq.com/keys",placeholder:"gsk_..."},mistral:{label:"Mistral",keyUrl:"https://console.mistral.ai/api-keys/",placeholder:"..."},openrouter:{label:"OpenRouter",keyUrl:"https://openrouter.ai/settings/keys",placeholder:"sk-or-v1-..."},ollama:{label:"Ollama",keyUrl:"",placeholder:"No key required"}};function Kg(){return{authed:!1,route:"dashboard",me:null,client:null,needsProviderOnboarding:!1,providerReady:!1,providerDefault:"",providerDefaultModel:"",providerConnected:[],providerError:"",providerGateNoticeShown:!1,botName:"Tandem",botAvatarUrl:"",controlPanelName:"Tandem Control Panel",themeId:"charcoal_fire",currentSessionId:"",chatUploadedFiles:[],filesDir:"uploads",cleanup:[],toasts:[]}}function st(e,t){try{const n=e();return n&&typeof n.then=="function"?n.catch(()=>t):Promise.resolve(n??t)}catch{return Promise.resolve(t)}}function xt(e,t){return Array.isArray(e)?e:e&&Array.isArray(e[t])?e[t]:[]}function Gg(e){const t=String(e||"").toLowerCase();return t?t.includes("done")||t.includes("complete")||t.includes("success")||t.includes("finished")?"completed":t.includes("fail")||t.includes("error")||t.includes("cancel")||t.includes("deny")?"failed":t.includes("wait")||t.includes("queue")||t.includes("new")||t.includes("pending")?"queued":"running":"running"}function pa(e){const t=[e?.updatedAtMs,e?.updated_at_ms,e?.finishedAtMs,e?.finished_at_ms,e?.startedAtMs,e?.started_at_ms,e?.createdAtMs,e?.created_at_ms,e?.firedAtMs,e?.fired_at_ms];for(const n of t){const s=Number(n);if(Number.isFinite(s)&&s>0)return s}return 0}function Wg(e){const t=[e?.total_tokens,e?.totalTokens];for(const n of t){const s=Number(n);if(Number.isFinite(s)&&s>=0)return s}return 0}function Yg(e){const t=[e?.estimated_cost_usd,e?.estimatedCostUsd];for(const n of t){const s=Number(n);if(Number.isFinite(s)&&s>=0)return s}return 0}function Xg(e){if(!e)return!1;const t=e.schedule||e.cron||e.interval||e.trigger;return typeof t=="string"?t.trim().length>0:typeof t=="number"?t>0:t&&typeof t=="object"?Object.keys(t).length>0:!1}function dr(e){const t=Math.max(1,...e.map(n=>n.value));return e.map(n=>({...n,pct:Math.max(4,Math.round(n.value/t*100))})).filter(n=>n.value>0)}async function Qg(e){const{api:t,state:n,byId:s,escapeHtml:r,setRoute:i}=e,[a,c,l,d,u,m,_,b,x,y,I,g,C,O]=await Promise.all([st(()=>t("/api/system/health"),{}),st(()=>n.client.providers.config(),{default:null,providers:{}}),st(()=>n.client.channels.status(),{}),st(()=>n.client.routines.list(),{routines:[]}),st(()=>n.client.automations.list(),{automations:[]}),st(()=>n.client?.automationsV2?.list?n.client.automationsV2.list():{automations:[]},{automations:[]}),st(()=>n.client.routines.listRuns({limit:120}),{runs:[]}),st(()=>n.client.automations.listRuns({limit:120}),{runs:[]}),st(async()=>{if(!n.client?.automationsV2?.list||!n.client?.automationsV2?.listRuns)return{runs:[]};const E=await n.client.automationsV2.list(),ie=xt(E,"automations").slice(0,30);return{runs:(await Promise.all(ie.map(_e=>st(()=>n.client.automationsV2.listRuns(String(_e?.automation_id||_e?.automationId||_e?.id||""),20),{runs:[]})))).flatMap(_e=>xt(_e,"runs"))}},{runs:[]}),st(()=>n.client.sessions.list({pageSize:50}),[]),st(()=>t("/api/swarm/status"),{status:"unknown"}),st(()=>t("/api/swarm/snapshot"),{registry:{value:{tasks:{}}}}),st(()=>n.client?.agentTeams?.listInstances?n.client.agentTeams.listInstances():{},{instances:[]}),st(()=>n.client?.agentTeams?.listApprovals?n.client.agentTeams.listApprovals():{},{spawnApprovals:[]})]),P=xt(d,"routines"),j=xt(u,"automations"),Y=xt(m,"automations"),N=xt(_,"runs"),z=xt(b,"runs"),D=xt(x,"runs"),R=[...N,...z,...D],Z=xt(y,"sessions"),le=xt(C,"instances"),ee=xt(O,"spawnApprovals"),U=Object.values(g?.registry?.value?.tasks||{}),se=Object.values(l||{}).filter(E=>E?.connected).length,re={completed:0,running:0,queued:0,failed:0};for(const E of R)re[Gg(E?.status)]+=1;const ue=dr([{key:"completed",label:"Completed",value:re.completed},{key:"running",label:"Running",value:re.running},{key:"queued",label:"Queued",value:re.queued},{key:"failed",label:"Failed",value:re.failed}]),ce=[...P,...j,...Y],Ee=ce.filter(E=>Xg(E)).length,ve=Math.max(ce.length-Ee,0),je=ce.filter(E=>{const ie=String(E?.status||"").toLowerCase();return ie.includes("pause")||ie.includes("disable")||ie.includes("stop")}).length,ne=dr([{key:"scheduled",label:"Scheduled",value:Ee},{key:"manual",label:"Manual",value:ve},{key:"paused",label:"Paused/Disabled",value:je}]),X={running:0,done:0,failed:0};for(const E of U){const ie=String(E?.status||"").toLowerCase();ie.includes("fail")||ie.includes("error")?X.failed+=1:ie.includes("done")||ie.includes("complete")?X.done+=1:X.running+=1}const $e=dr([{key:"running",label:"Active",value:X.running},{key:"completed",label:"Completed",value:X.done},{key:"failed",label:"Failed",value:X.failed}]),me=Date.now(),de=new Array(12).fill(0).map((E,ie)=>({label:`${11-ie}h`,value:0}));for(const E of R){const ie=pa(E);if(!ie)continue;const ye=Math.floor((me-ie)/36e5);ye>=0&&ye<12&&(de[11-ye].value+=1)}const fe=Math.max(1,...de.map(E=>E.value)),pe=me-24*36e5,be=me-168*36e5;let k=0,T=0,M=0,K=0;const J=new Map;for(const E of R){const ie=pa(E),ye=Wg(E),Ie=Yg(E),_e=String(E?.automation_id||E?.automationId||E?.automationID||E?.routine_id||E?.routineId||"unknown").trim();if(ie>=be&&(T+=ye,K+=Ie),ie>=pe&&(k+=ye,M+=Ie),_e){const at=J.get(_e)||{cost:0,tokens:0,runs:0};at.cost+=Ie,at.tokens+=ye,at.runs+=1,J.set(_e,at)}}const q=[...J.entries()].map(([E,ie])=>({id:E,...ie})).sort((E,ie)=>ie.cost-E.cost).slice(0,6);s("view").innerHTML=`
|
|
50
|
+
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
51
|
+
<div class="tcp-card">
|
|
52
|
+
<div class="mb-2 flex items-center justify-between"><span class="tcp-subtle">Engine</span><i data-lucide="cpu"></i></div>
|
|
53
|
+
<div class="text-2xl font-semibold">${r(a.engine?.version||"unknown")}</div>
|
|
54
|
+
<p class="mt-1 text-sm ${a.engine?.ready||a.engine?.healthy?"text-lime-300":"text-rose-300"}">${a.engine?.ready||a.engine?.healthy?"Healthy":"Unhealthy"}</p>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="tcp-card">
|
|
57
|
+
<div class="mb-2 flex items-center justify-between"><span class="tcp-subtle">Provider</span><i data-lucide="bot"></i></div>
|
|
58
|
+
<div class="text-2xl font-semibold">${r(c.default||"none")}</div>
|
|
59
|
+
<p class="mt-1 text-sm text-slate-400">Default model configured</p>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="tcp-card">
|
|
62
|
+
<div class="mb-2 flex items-center justify-between"><span class="tcp-subtle">Channels</span><i data-lucide="messages-square"></i></div>
|
|
63
|
+
<div class="text-2xl font-semibold">${se}</div>
|
|
64
|
+
<p class="mt-1 text-sm text-slate-400">Connected integrations</p>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="tcp-card">
|
|
67
|
+
<div class="mb-2 flex items-center justify-between"><span class="tcp-subtle">Scheduled</span><i data-lucide="clock-3"></i></div>
|
|
68
|
+
<div class="text-2xl font-semibold">${Ee}</div>
|
|
69
|
+
<p class="mt-1 text-sm text-slate-400">Routines + automations with a trigger</p>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<section class="tcp-card">
|
|
74
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
75
|
+
<h3 class="tcp-title">Automations + Cost</h3>
|
|
76
|
+
<span class="tcp-subtle text-xs">all automation run paths</span>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="dashboard-kpis mb-4">
|
|
79
|
+
<div><span class="dashboard-kpi-label">Tokens (24h)</span><strong>${k.toLocaleString()}</strong></div>
|
|
80
|
+
<div><span class="dashboard-kpi-label">Tokens (7d)</span><strong>${T.toLocaleString()}</strong></div>
|
|
81
|
+
<div><span class="dashboard-kpi-label">Estimated Cost (24h)</span><strong>$${M.toFixed(4)}</strong></div>
|
|
82
|
+
<div><span class="dashboard-kpi-label">Estimated Cost (7d)</span><strong>$${K.toFixed(4)}</strong></div>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="mb-2 text-xs text-slate-500">
|
|
85
|
+
Cost estimate uses server rate TANDEM_TOKEN_COST_PER_1K_USD and run token totals from provider usage telemetry.
|
|
86
|
+
</div>
|
|
87
|
+
${q.length?`<div class="dashboard-bars">${q.map(E=>{const ie=K>0?Math.max(4,Math.round(E.cost/Math.max(K,1e-4)*100)):4;return`
|
|
88
|
+
<div class="dashboard-bar-row">
|
|
89
|
+
<div class="dashboard-bar-meta">
|
|
90
|
+
<span class="font-mono">${r(E.id)}</span>
|
|
91
|
+
<span class="dashboard-bar-count">$${E.cost.toFixed(4)} · ${E.tokens.toLocaleString()} tok · ${E.runs} runs</span>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="dashboard-bar-track"><span class="dashboard-bar-fill running" style="width:${ie}%"></span></div>
|
|
94
|
+
</div>
|
|
95
|
+
`}).join("")}</div>`:'<p class="tcp-subtle">No token/cost telemetry recorded yet for sampled runs.</p>'}
|
|
96
|
+
</section>
|
|
97
|
+
|
|
98
|
+
<div class="grid gap-4 xl:grid-cols-3">
|
|
99
|
+
<section class="tcp-card">
|
|
100
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
101
|
+
<h3 class="tcp-title">Run Status (latest ${R.length})</h3>
|
|
102
|
+
<span class="tcp-subtle text-xs">routines + automations</span>
|
|
103
|
+
</div>
|
|
104
|
+
${ue.length?`<div class="dashboard-bars">${ue.map(E=>`
|
|
105
|
+
<div class="dashboard-bar-row">
|
|
106
|
+
<div class="dashboard-bar-meta">
|
|
107
|
+
<span>${r(E.label)}</span>
|
|
108
|
+
<span class="dashboard-bar-count">${E.value}</span>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="dashboard-bar-track"><span class="dashboard-bar-fill ${E.key}" style="width:${E.pct}%"></span></div>
|
|
111
|
+
</div>
|
|
112
|
+
`).join("")}</div>`:'<p class="tcp-subtle">No run history yet.</p>'}
|
|
113
|
+
</section>
|
|
114
|
+
|
|
115
|
+
<section class="tcp-card">
|
|
116
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
117
|
+
<h3 class="tcp-title">Schedule Composition</h3>
|
|
118
|
+
<span class="tcp-subtle text-xs">${ce.length} configured</span>
|
|
119
|
+
</div>
|
|
120
|
+
${ne.length?`<div class="dashboard-bars">${ne.map(E=>`
|
|
121
|
+
<div class="dashboard-bar-row">
|
|
122
|
+
<div class="dashboard-bar-meta">
|
|
123
|
+
<span>${r(E.label)}</span>
|
|
124
|
+
<span class="dashboard-bar-count">${E.value}</span>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="dashboard-bar-track"><span class="dashboard-bar-fill ${E.key}" style="width:${E.pct}%"></span></div>
|
|
127
|
+
</div>
|
|
128
|
+
`).join("")}</div>`:'<p class="tcp-subtle">No routines or automations found.</p>'}
|
|
129
|
+
</section>
|
|
130
|
+
|
|
131
|
+
<section class="tcp-card">
|
|
132
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
133
|
+
<h3 class="tcp-title">Execution Snapshot</h3>
|
|
134
|
+
<span class="tcp-subtle text-xs">swarm + teams</span>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="dashboard-kpis mb-3">
|
|
137
|
+
<div><span class="dashboard-kpi-label">Swarm status</span><strong>${r(String(I.status||"unknown"))}</strong></div>
|
|
138
|
+
<div><span class="dashboard-kpi-label">Team instances</span><strong>${le.length}</strong></div>
|
|
139
|
+
<div><span class="dashboard-kpi-label">Pending approvals</span><strong>${ee.length}</strong></div>
|
|
140
|
+
<div><span class="dashboard-kpi-label">Chat sessions</span><strong>${Z.length}</strong></div>
|
|
141
|
+
</div>
|
|
142
|
+
${$e.length?`<div class="dashboard-bars">${$e.map(E=>`
|
|
143
|
+
<div class="dashboard-bar-row">
|
|
144
|
+
<div class="dashboard-bar-meta">
|
|
145
|
+
<span>${r(E.label)}</span>
|
|
146
|
+
<span class="dashboard-bar-count">${E.value}</span>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="dashboard-bar-track"><span class="dashboard-bar-fill ${E.key}" style="width:${E.pct}%"></span></div>
|
|
149
|
+
</div>
|
|
150
|
+
`).join("")}</div>`:'<p class="tcp-subtle">No swarm task records available.</p>'}
|
|
151
|
+
</section>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div class="tcp-card">
|
|
155
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
156
|
+
<h3 class="tcp-title">Run Volume (Last 12h)</h3>
|
|
157
|
+
<span class="tcp-subtle text-xs">${R.length} total sampled runs</span>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="dashboard-histogram">
|
|
160
|
+
${de.map(E=>{const ie=Math.max(8,Math.round(E.value/fe*100));return`
|
|
161
|
+
<div class="dashboard-histogram-bin">
|
|
162
|
+
<span class="dashboard-histogram-count">${E.value}</span>
|
|
163
|
+
<span class="dashboard-histogram-bar" style="height:${ie}%"></span>
|
|
164
|
+
<span class="dashboard-histogram-label">${r(E.label)}</span>
|
|
165
|
+
</div>
|
|
166
|
+
`}).join("")}
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<div class="tcp-card">
|
|
171
|
+
<h3 class="tcp-title mb-3">Quick Actions</h3>
|
|
172
|
+
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
|
|
173
|
+
<button class="tcp-btn w-full justify-start" data-goto="chat"><i data-lucide="message-square"></i> Open Chat</button>
|
|
174
|
+
<button class="tcp-btn w-full justify-start" data-goto="agents"><i data-lucide="clipboard-list"></i> Automations + Cost</button>
|
|
175
|
+
<button class="tcp-btn w-full justify-start" data-goto="swarm"><i data-lucide="workflow"></i> Launch Swarm</button>
|
|
176
|
+
<button class="tcp-btn w-full justify-start" data-goto="mcp"><i data-lucide="plug-zap"></i> Connect MCP</button>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
`,s("view").querySelectorAll("[data-goto]").forEach(E=>{E.addEventListener("click",()=>i(E.dataset.goto))})}function ma(e){const t=String(e||"").trim();return t&&(/^https?:\/\//i.test(t)||/^mailto:/i.test(t))?t:""}function Vn(e){let t=Re(e||"");const n=[];return t=t.replace(/`([^`]+)`/g,(s,r)=>{const i=`@@CODE${n.length}@@`;return n.push(`<code>${Re(r)}</code>`),i}),t=t.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(s,r,i)=>{const a=ma(i);return a?`<a href="${Re(a)}" target="_blank" rel="noreferrer">${Re(r)}</a>`:`${Re(r)} (${Re(i)})`}),t=t.replace(/(https?:\/\/[^\s<]+)/g,s=>{const r=ma(s);return r?`<a href="${Re(r)}" target="_blank" rel="noreferrer">${Re(s)}</a>`:Re(s)}),t=t.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),t=t.replace(/__([^_]+)__/g,"<strong>$1</strong>"),t=t.replace(/\*([^*]+)\*/g,"<em>$1</em>"),t=t.replace(/_([^_]+)_/g,"<em>$1</em>"),t=t.replace(/~~([^~]+)~~/g,"<s>$1</s>"),t=t.replace(/@@CODE(\d+)@@/g,(s,r)=>n[Number(r)]||""),t}function ev(e){const t=String(e||"").replace(/\r/g,"").split(`
|
|
180
|
+
`),n=[];let s=0;for(;s<t.length;){const r=t[s];if(/^\s*```/.test(r)){const c=[];for(s+=1;s<t.length&&!/^\s*```/.test(t[s]);)c.push(t[s]),s+=1;s<t.length&&(s+=1),n.push(`<pre><code>${Re(c.join(`
|
|
181
|
+
`))}</code></pre>`);continue}const i=r.match(/^(#{1,6})\s+(.+)$/);if(i){const c=i[1].length;n.push(`<h${c}>${Vn(i[2])}</h${c}>`),s+=1;continue}if(/^[-*+]\s+/.test(r)){const c=[];for(;s<t.length&&/^[-*+]\s+/.test(t[s]);)c.push(t[s].replace(/^[-*+]\s+/,"")),s+=1;n.push(`<ul>${c.map(l=>`<li>${Vn(l)}</li>`).join("")}</ul>`);continue}if(/^\d+\.\s+/.test(r)){const c=[];for(;s<t.length&&/^\d+\.\s+/.test(t[s]);)c.push(t[s].replace(/^\d+\.\s+/,"")),s+=1;n.push(`<ol>${c.map(l=>`<li>${Vn(l)}</li>`).join("")}</ol>`);continue}if(/^>\s?/.test(r)){const c=[];for(;s<t.length&&/^>\s?/.test(t[s]);)c.push(t[s].replace(/^>\s?/,"")),s+=1;n.push(`<blockquote>${c.map(l=>Vn(l)).join("<br/>")}</blockquote>`);continue}if(!r.trim()){s+=1;continue}const a=[r];for(s+=1;s<t.length&&t[s].trim()&&!/^(#{1,6})\s+/.test(t[s])&&!/^[-*+]\s+/.test(t[s])&&!/^\d+\.\s+/.test(t[s])&&!/^>\s?/.test(t[s])&&!/^\s*```/.test(t[s]);)a.push(t[s]),s+=1;n.push(`<p>${a.map(c=>Vn(c)).join("<br/>")}</p>`)}return n.join("")}const tv="control-panel",oc="tandem_control_panel_chat_auto_approve_tools",nv={md:"text/markdown",txt:"text/plain",csv:"text/csv",json:"application/json",pdf:"application/pdf",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp"};function fa(e=""){const t=String(e).toLowerCase().split(".").pop()||"";return nv[t]||"application/octet-stream"}function sv(e,t){if(!e||!t)return t||"";const n=String(e).replace(/[\\/]+$/,""),s=String(t).replace(/^[\\/]+/,"");return`${n}/${s}`}function rv(){try{return localStorage.getItem(oc)==="1"}catch{return!1}}function iv(e){try{localStorage.setItem(oc,e?"1":"0")}catch{}}async function av(e){const{state:t,byId:n,toast:s,escapeHtml:r,api:i,renderIcons:a,addCleanup:c,setRoute:l}=e,d=await J();t.currentSessionId||(t.currentSessionId=d[0]?.id||"");let u=!1;n("view").innerHTML=`
|
|
182
|
+
<div id="chat-layout" class="chat-layout min-w-0 h-[calc(100vh-2rem)]">
|
|
183
|
+
<aside id="chat-sessions-panel" class="chat-sessions-panel">
|
|
184
|
+
<div class="chat-sessions-header">
|
|
185
|
+
<h3 class="chat-sessions-title"><i data-lucide="clock-3"></i> Sessions</h3>
|
|
186
|
+
<button id="new-session" class="tcp-btn h-8 px-2.5 text-xs"><i data-lucide="plus"></i> New</button>
|
|
187
|
+
</div>
|
|
188
|
+
<div id="session-list" class="chat-session-list"></div>
|
|
189
|
+
</aside>
|
|
190
|
+
<button id="chat-scrim" class="chat-scrim" aria-label="Close sessions"></button>
|
|
191
|
+
<div class="chat-workspace min-h-0 min-w-0">
|
|
192
|
+
<div class="chat-main-shell flex min-h-0 min-w-0 flex-col overflow-hidden">
|
|
193
|
+
<div class="chat-main-header shrink-0">
|
|
194
|
+
<button id="chat-toggle-sessions" type="button" class="chat-icon-btn h-8 w-8" title="Sessions"><i data-lucide="clock-3"></i></button>
|
|
195
|
+
<div class="chat-main-dot"></div>
|
|
196
|
+
<h3 id="chat-title" class="tcp-title chat-main-title">Chat</h3>
|
|
197
|
+
<span id="chat-tool-count" class="chat-main-tools hidden"></span>
|
|
198
|
+
</div>
|
|
199
|
+
<div id="messages" class="chat-messages mb-2 min-h-0 min-w-0 flex-1 space-y-2 overflow-auto p-3"></div>
|
|
200
|
+
<div class="chat-composer shrink-0">
|
|
201
|
+
<div id="chat-attach-row" class="chat-attach-row mb-2 hidden">
|
|
202
|
+
<input id="chat-file-input" type="file" class="hidden" multiple />
|
|
203
|
+
<span id="chat-attach-summary" class="tcp-subtle">0 files attached</span>
|
|
204
|
+
<div id="chat-files" class="chat-files-line"></div>
|
|
205
|
+
</div>
|
|
206
|
+
<div id="chat-upload-progress" class="mb-2 grid gap-1.5"></div>
|
|
207
|
+
<div class="chat-input-wrap">
|
|
208
|
+
<button id="chat-file-pick-inner" type="button" class="chat-icon-btn chat-icon-btn-inner" title="Attach files"><i data-lucide="paperclip"></i></button>
|
|
209
|
+
<textarea id="chat-input" rows="1" class="tcp-input chat-input-with-clip chat-input-modern resize-none" placeholder="Ask anything... (Enter to send, Shift+Enter newline)"></textarea>
|
|
210
|
+
<button id="send-chat" class="chat-send-btn" title="Send"><i data-lucide="send"></i></button>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
<aside class="chat-right-rail hidden min-h-0 flex-col gap-3 overflow-hidden xl:flex">
|
|
215
|
+
<section class="min-h-0">
|
|
216
|
+
<div class="mb-2 flex items-center justify-between">
|
|
217
|
+
<p class="chat-rail-label">Tools</p>
|
|
218
|
+
<span id="chat-rail-tools-count" class="chat-rail-count">0</span>
|
|
219
|
+
</div>
|
|
220
|
+
<div id="chat-tools-list" class="chat-tools-list"></div>
|
|
221
|
+
</section>
|
|
222
|
+
<section class="min-h-0">
|
|
223
|
+
<div class="mb-2 flex items-center justify-between">
|
|
224
|
+
<p class="chat-rail-label">Approvals</p>
|
|
225
|
+
<span id="chat-rail-permissions-count" class="chat-rail-count">0</span>
|
|
226
|
+
</div>
|
|
227
|
+
<div class="mb-2 flex items-center gap-2">
|
|
228
|
+
<button id="chat-approve-all" class="tcp-btn h-7 px-2 text-[11px]">Approve all</button>
|
|
229
|
+
<label class="chat-auto-approve-label">
|
|
230
|
+
<input id="chat-auto-approve" type="checkbox" class="chat-auto-approve-checkbox" />
|
|
231
|
+
Auto
|
|
232
|
+
</label>
|
|
233
|
+
</div>
|
|
234
|
+
<div id="chat-permissions-list" class="chat-tools-activity"></div>
|
|
235
|
+
</section>
|
|
236
|
+
<section class="min-h-0 flex-1">
|
|
237
|
+
<div class="mb-2 flex items-center justify-between">
|
|
238
|
+
<p class="chat-rail-label">Pack Events</p>
|
|
239
|
+
<div class="flex items-center gap-2">
|
|
240
|
+
<span id="chat-pack-events-count" class="chat-rail-count">0</span>
|
|
241
|
+
<button id="chat-pack-events-clear" class="tcp-btn h-7 px-2 text-[11px]">Clear</button>
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
<div id="chat-pack-events" class="chat-tools-activity"></div>
|
|
245
|
+
</section>
|
|
246
|
+
<section class="min-h-0 flex-1">
|
|
247
|
+
<div class="mb-2 flex items-center justify-between">
|
|
248
|
+
<p class="chat-rail-label">Tool Activity</p>
|
|
249
|
+
<button id="chat-tools-clear" class="tcp-btn h-7 px-2 text-[11px]">Clear</button>
|
|
250
|
+
</div>
|
|
251
|
+
<div id="chat-tools-activity" class="chat-tools-activity"></div>
|
|
252
|
+
</section>
|
|
253
|
+
</aside>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
`;const m=n("chat-layout"),_=n("chat-sessions-panel"),b=n("chat-scrim"),x=n("session-list"),y=n("messages"),I=n("chat-input"),g=n("send-chat"),C=n("chat-file-input"),O=n("chat-file-pick-inner"),P=n("chat-attach-row"),j=n("chat-files"),Y=n("chat-upload-progress"),N=n("chat-attach-summary"),z=n("chat-title"),D=n("chat-tool-count"),R=n("chat-rail-tools-count"),Z=n("chat-rail-permissions-count"),le=n("chat-pack-events-count"),ee=n("chat-pack-events-clear"),U=n("chat-pack-events"),se=n("chat-permissions-list"),re=n("chat-approve-all"),ue=n("chat-auto-approve"),ce=n("chat-tools-list"),Ee=n("chat-tools-activity"),ve=Array.isArray(t.chatUploadedFiles)?t.chatUploadedFiles:[];t.chatUploadedFiles=ve;const je=new Map,ne=[],X=new Set,$e=[],me=new Set,de=[],fe=new Set;let pe=rv(),be=!1,k=[],T=!1;function M(h){u=!!h,m.classList.toggle("sessions-open",u),_.classList.toggle("open",u),b.classList.toggle("open",u)}function K(){I.style.height="0px",I.style.height=`${Math.min(I.scrollHeight,180)}px`}async function J(){const h=v=>String(v?.title||"").trim().toLowerCase().startsWith("__provider_test__");try{const v=await t.client.sessions.list({pageSize:50});if(Array.isArray(v))return v.filter(S=>!h(S));if(Array.isArray(v?.sessions))return v.sessions.filter(S=>!h(S))}catch{}try{const v=await i("/api/engine/session?page_size=50");return Array.isArray(v)?v.filter(S=>!h(S)):Array.isArray(v?.sessions)?v.sessions.filter(S=>!h(S)):[]}catch{return[]}}function q(){const h=String(t.providerDefault||"").trim(),v=String(t.providerDefaultModel||"").trim();return!h||!v?null:{providerID:h,modelID:v}}async function E(){const h=q();if(h)return h;try{const v=await t.client.providers.config(),S=String(v?.default||"").trim(),H=String(v?.providers?.[S]?.default_model||"").trim();if(S&&(t.providerDefault=S),H&&(t.providerDefaultModel=H),S&&H)return{providerID:S,modelID:H}}catch{}return q()}async function ie(){const h=await E(),v={title:`Chat ${new Date().toLocaleTimeString()}`};h&&(v.provider=h.providerID,v.model=h.modelID);const S=await t.client.sessions.create(v),H=await t.client.sessions.get(S).catch(()=>({id:S,title:S}));return d.unshift(H),t.currentSessionId=S,Bt(),At(),Kt(),await Et(),await tt(),S}function ye(h){const v=Number(h||0);return v<1024?`${v} B`:v<1024*1024?`${(v/1024).toFixed(1)} KB`:`${(v/(1024*1024)).toFixed(1)} MB`}function Ie(){const h=d.find(S=>S.id===t.currentSessionId),v=String(h?.title||"").trim();return v||(t.currentSessionId?`Session ${t.currentSessionId.slice(0,8)}`:"Chat")}function _e(){z.textContent=Ie();const h=k.length;if(h>0){const v=`${h} tool${h===1?"":"s"}`;D.textContent=v,D.classList.remove("hidden"),R.textContent=String(h)}else D.classList.add("hidden"),R.textContent="0"}function at(h){return h==="completed"?"chat-tool-chip-ok":h==="failed"?"chat-tool-chip-failed":"chat-tool-chip-running"}function Ye(){ce.innerHTML=k.slice(0,32).map(h=>`<button type="button" class="chat-tool-pill" data-tool-insert="${r(h)}" title="Insert ${r(h)}">${r(h)}</button>`).join("")||'<p class="chat-rail-empty">No tools loaded.</p>',ce.querySelectorAll("[data-tool-insert]").forEach(h=>{h.addEventListener("click",()=>{const v=String(h.dataset.toolInsert||"").trim();v&&(I.value=I.value.trim()?`${I.value} ${v}`:v,I.focus())})}),Ee.innerHTML=ne.slice(0,24).map(h=>{const v=new Date(h.at).toLocaleTimeString();return`<div class="chat-tool-chip ${at(h.status)}" title="${r(v)}">${r(h.tool)}: ${r(h.status)}</div>`}).join("")||'<p class="chat-rail-empty">No tool events yet.</p>',_e()}function ln(h,v){const S=v&&typeof v=="object"?v:{},H=String(h||"").trim()||"pack.event",W=String(S.path||"").trim(),Te=String(S.attachment_id||S.attachmentId||"").trim(),He=String(S.connector||"").trim(),Fe=String(S.channel_id||S.channelId||"").trim(),Ue=String(S.sender_id||S.senderId||"").trim(),Ce=String(S.name||"").trim(),Tt=String(S.version||"").trim(),dt=String(S.error||"").trim(),Be=[];Ce&&Be.push(Ce),Tt&&Be.push(Tt),W&&Be.push(W),He&&Be.push(He),Fe&&Be.push(`channel=${Fe}`),Ue&&Be.push(`sender=${Ue}`);const Gt=Be.join(" · ");return{id:`${H}:${Te||W||Ce||"event"}`,type:H,path:W,attachment_id:Te,connector:He,channel_id:Fe,sender_id:Ue,error:dt,summary:Gt||H,at:Date.now()}}function gt(){!le||!U||(le.textContent=String($e.length),U.innerHTML=$e.slice(0,20).map(h=>{const v=new Date(h.at).toLocaleTimeString();return`
|
|
257
|
+
<article class="chat-pack-event-card">
|
|
258
|
+
<div class="flex items-center justify-between gap-2">
|
|
259
|
+
<div class="chat-pack-event-title truncate" title="${r(h.type)}">${r(h.type)}</div>
|
|
260
|
+
<span class="chat-pack-event-time">${r(v)}</span>
|
|
261
|
+
</div>
|
|
262
|
+
<div class="chat-pack-event-summary mt-0.5">${r(h.summary)}</div>
|
|
263
|
+
${h.error?`<div class="chat-pack-event-error mt-1">${r(h.error)}</div>`:""}
|
|
264
|
+
<div class="mt-1 flex flex-wrap gap-1">
|
|
265
|
+
<button class="tcp-btn h-6 px-1.5 text-[10px]" data-pack-open="1">Packs</button>
|
|
266
|
+
${h.path?`<button class="tcp-btn h-6 px-1.5 text-[10px]" data-pack-install-path="${r(h.path)}">Install path</button>`:""}
|
|
267
|
+
${h.path&&h.attachment_id?`<button class="tcp-btn h-6 px-1.5 text-[10px]" data-pack-install-attachment="${r(h.attachment_id)}" data-pack-path="${r(h.path)}" data-pack-connector="${r(h.connector)}" data-pack-channel="${r(h.channel_id)}" data-pack-sender="${r(h.sender_id)}">Install attach</button>`:""}
|
|
268
|
+
</div>
|
|
269
|
+
</article>
|
|
270
|
+
`}).join("")||'<p class="chat-rail-empty">No pack events yet.</p>',U.querySelectorAll("[data-pack-open]").forEach(h=>{h.addEventListener("click",()=>{l?.("packs")})}),U.querySelectorAll("[data-pack-install-path]").forEach(h=>{h.addEventListener("click",async()=>{const v=String(h.getAttribute("data-pack-install-path")||"").trim();if(v)try{const S=await t.client.packs.install({path:v,source:{kind:"control_panel_chat",event:"pack.detected"}});s("ok",`Installed ${S?.installed?.name||"pack"} ${S?.installed?.version||""}`.trim())}catch(S){s("err",`Install failed: ${S instanceof Error?S.message:String(S)}`)}})}),U.querySelectorAll("[data-pack-install-attachment]").forEach(h=>{h.addEventListener("click",async()=>{const v=String(h.getAttribute("data-pack-install-attachment")||"").trim(),S=String(h.getAttribute("data-pack-path")||"").trim();if(!(!v||!S))try{const H=await t.client.packs.installFromAttachment({attachment_id:v,path:S,connector:String(h.getAttribute("data-pack-connector")||"").trim()||void 0,channel_id:String(h.getAttribute("data-pack-channel")||"").trim()||void 0,sender_id:String(h.getAttribute("data-pack-sender")||"").trim()||void 0});s("ok",`Installed ${H?.installed?.name||"pack"} ${H?.installed?.version||""}`.trim())}catch(H){s("err",`Install failed: ${H instanceof Error?H.message:String(H)}`)}})}))}function At(){$e.splice(0,$e.length),me.clear(),gt()}function Ln(h,v){const S=ln(h,v);String(S.type).toLowerCase().startsWith("pack.")&&(me.has(S.id)||(me.add(S.id),me.size>400&&me.clear(),$e.unshift(S),$e.length>80&&($e.length=80),gt()))}function Bt(){ne.splice(0,ne.length),X.clear(),Ye()}function dn(h,v,S=""){const H=String(h||"").trim();if(H){if(S){if(X.has(S))return;X.add(S),X.size>1e3&&X.clear()}ne.unshift({id:`${H}:${v}:${Date.now()}:${Math.random().toString(36).slice(2,8)}`,tool:H,status:v,at:Date.now()}),ne.length>80&&(ne.length=80),Ye()}}function is(h,v=0){const S=String(h||"").trim();if(!S)return;const H=document.createElement("div");H.className="chat-msg user",H.innerHTML=`
|
|
271
|
+
<div class="chat-msg-role">User</div>
|
|
272
|
+
<pre class="chat-msg-pre">${r(S)}</pre>
|
|
273
|
+
${v>0?`<div class="chat-msg-attachments mt-1">${v} attachment${v===1?"":"s"}</div>`:""}
|
|
274
|
+
`,y.appendChild(H),y.scrollTop=y.scrollHeight}function Lt(h){return String(h||"").trim().replace(/\s+/g," ").replace(/[<>]/g,"")}function $t(h){const v=h||{},S=v.call||v.toolCall||v.part||{};return Lt(v.tool||v.name||v.toolName||v.tool_id||v.toolID||S.tool||S.name||S.toolName||"")}function un(h){const v=h||{},S=v.call||v.toolCall||v.part||{};return String(v.callID||v.toolCallID||v.tool_call_id||v.id||S.callID||S.toolCallID||S.tool_call_id||S.id||"").trim()}function Ot(h,v=""){const S=h?.properties||{};return String(h?.runId||h?.runID||h?.run_id||S.runID||S.runId||S.run_id||S.run?.id||v).trim()}function pn(h){if(!h)return null;const v=h.request||h.approval||h.permission||{},S=String(h.id||h.requestID||h.requestId||h.approvalID||v.id||v.requestID||v.requestId||"").trim();if(!S)return null;const H=String(h.sessionId||h.sessionID||h.session_id||v.sessionId||v.sessionID||v.session_id||"").trim();return{id:S,tool:Lt(h.tool||v.tool||v.name||"tool")||"tool",permission:String(h.permission||v.permission||"").trim(),pattern:String(h.pattern||v.pattern||"").trim(),sessionId:H,status:String(h.status||v.status||"").trim().toLowerCase()}}function Jt(h){const v=String(h||"").trim().toLowerCase();return v?v.includes("approved")||v.includes("rejected")||v.includes("denied")||v.includes("resolved")||v.includes("expired")||v.includes("cancel")||v.includes("complete")||v.includes("done")||v.includes("timeout")?!1:v.includes("pending")||v.includes("request")||v.includes("ask")||v.includes("await")||v.includes("open")||v.includes("queue")||v.includes("new")||v.includes("progress")||v==="unknown":!0}function On(h){if(!Jt(h?.status))return;const v=de.findIndex(S=>S.id===h.id);v>=0?de[v]={...de[v],...h}:de.unshift(h)}function as(h){const v=de.findIndex(S=>S.id===h);v>=0&&de.splice(v,1)}function wt(){const h=de.length;Z.textContent=String(h),re.disabled=h===0||be,ue.checked=pe,se.innerHTML=de.slice(0,20).map(v=>{const S=fe.has(v.id),H=[v.permission,v.pattern].filter(Boolean).join(" ");return`
|
|
275
|
+
<article class="chat-pack-event-card">
|
|
276
|
+
<div class="chat-pack-event-title truncate" title="${r(v.id)}">${r(v.tool)}</div>
|
|
277
|
+
<div class="chat-pack-event-summary mt-0.5">${r(H||v.id)}</div>
|
|
278
|
+
<div class="mt-1 flex gap-1">
|
|
279
|
+
<button class="tcp-btn h-6 px-1.5 text-[10px]" data-perm-allow="${r(v.id)}" ${S?"disabled":""}>Allow</button>
|
|
280
|
+
<button class="tcp-btn h-6 px-1.5 text-[10px]" data-perm-always="${r(v.id)}" ${S?"disabled":""}>Always</button>
|
|
281
|
+
<button class="tcp-btn-danger h-6 px-1.5 text-[10px]" data-perm-deny="${r(v.id)}" ${S?"disabled":""}>Deny</button>
|
|
282
|
+
</div>
|
|
283
|
+
</article>
|
|
284
|
+
`}).join("")||'<p class="chat-rail-empty">No pending approvals.</p>',se.querySelectorAll("[data-perm-allow]").forEach(v=>{v.addEventListener("click",async()=>{const S=String(v.dataset.permAllow||"").trim();S&&await zt(S,"once")})}),se.querySelectorAll("[data-perm-always]").forEach(v=>{v.addEventListener("click",async()=>{const S=String(v.dataset.permAlways||"").trim();S&&await zt(S,"always")})}),se.querySelectorAll("[data-perm-deny]").forEach(v=>{v.addEventListener("click",async()=>{const S=String(v.dataset.permDeny||"").trim();S&&await zt(S,"deny")})})}async function zt(h,v,S=!1){if(!h||fe.has(h))return;const H=v==="allow"?"once":v;fe.add(h),wt();try{await t.client.permissions.reply(h,H),as(h),S||s("ok",`Permission ${H==="deny"?"denied":"approved"} (${h}).`)}catch(W){S||s("err",W instanceof Error?W.message:String(W))}finally{fe.delete(h),wt(),Et()}}async function zn(){if(!(!pe||be||de.length===0)){be=!0,wt();try{for(const h of[...de])await zt(h.id,"always",!0)}finally{be=!1,wt()}}}async function Et(){const h=await t.client.permissions.list().catch(()=>({requests:[]})),v=Array.isArray(h?.requests)?h.requests:[],S=String(t.currentSessionId||"").trim();de.splice(0,de.length);for(const H of v){const W=pn(H);W&&(W.sessionId&&S&&W.sessionId!==S||Jt(W.status)&&de.push(W))}wt(),zn()}function os(h){return(Array.isArray(h)?h:Array.isArray(h?.tools)?h.tools:[]).map(S=>{if(typeof S=="string")return S;const H=S||{};return String(H.name||H.id||H.tool||"").trim()}).filter(Boolean)}async function Ys(){try{const h=await t.client.listTools().catch(()=>null);let v=os(h||[]);if(!v.length){const S=await i("/api/engine/tool").catch(()=>[]);v=os(S||[])}k=[...new Set(v)].sort((S,H)=>S.localeCompare(H))}catch{k=[]}Ye()}function It(){const h=[...je.entries()];if(!h.length){Y.innerHTML="";return}Y.innerHTML=h.map(([v,S])=>{const H=Math.max(0,Math.min(100,Number(S.progress||0)));return`
|
|
285
|
+
<div class="chat-upload-card">
|
|
286
|
+
<div class="mb-1 flex items-center justify-between gap-2 text-xs">
|
|
287
|
+
<span class="chat-upload-name truncate">${r(S.name)}</span>
|
|
288
|
+
<span class="${S.error?"chat-upload-meta-error":"chat-upload-meta"}">${S.error?r(S.error):`${H}%`}</span>
|
|
289
|
+
</div>
|
|
290
|
+
<div class="chat-upload-bar">
|
|
291
|
+
<div class="chat-upload-bar-fill" style="width:${H}%"></div>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
`}).join("")}function mn(){if(!ve.length){j.innerHTML="",N.textContent="",P.classList.add("hidden");return}const h=ve.length;N.textContent=`${h} attached`,P.classList.remove("hidden"),j.innerHTML=ve.map((v,S)=>`
|
|
295
|
+
<div class="chat-file-pill min-w-0">
|
|
296
|
+
<span class="chat-file-pill-name" title="${r(v.path)}">${r(v.path)}</span>
|
|
297
|
+
<span class="chat-file-pill-size">${r(ye(v.size))}</span>
|
|
298
|
+
<button class="chat-file-pill-btn chat-file-pill-btn-danger" type="button" data-file-remove="${S}" title="Remove from list"><i data-lucide="x"></i></button>
|
|
299
|
+
</div>
|
|
300
|
+
`).join(""),j.querySelectorAll("[data-file-remove]").forEach(v=>{v.addEventListener("click",()=>{const S=Number(v.dataset.fileRemove);Number.isFinite(S)&&(ve.splice(S,1),mn())})}),a(j)}function mi(h){return new Promise((v,S)=>{const H=`${Date.now()}-${Math.random().toString(16).slice(2)}`;je.set(H,{name:h.name,progress:0,error:""}),It();const W=new XMLHttpRequest;W.open("POST",`/api/files/upload?dir=${encodeURIComponent(tv)}`),W.withCredentials=!0,W.responseType="json",W.setRequestHeader("x-file-name",encodeURIComponent(h.name)),W.upload.onprogress=Te=>{if(!Te.lengthComputable)return;const He=je.get(H);He&&(He.progress=Te.loaded/Te.total*100,It())},W.onerror=()=>{const Te=je.get(H);Te&&(Te.error="Network error"),It(),setTimeout(()=>{je.delete(H),It()},1200),S(new Error(`Upload failed: ${h.name}`))},W.onload=()=>{const Te=W.response||{};if(W.status<200||W.status>=300||Te?.ok===!1){const He=Te?.error||`Upload failed (${W.status})`,Fe=je.get(H);Fe&&(Fe.error=String(He)),It(),setTimeout(()=>{je.delete(H),It()},1800),S(new Error(String(He)));return}je.delete(H),It(),v(Te)},W.send(h)})}async function Xs(h){const v=[...h||[]];if(!v.length)return;let S=0;for(const H of v)try{const W=await mi(H);ve.unshift({name:W.name||H.name,path:W.path||H.name,size:Number(W.size||H.size||0),mime:H.type||fa(W.name||H.name),url:W.absPath||sv(W.root,W.path)||W.path||H.name}),S+=1,mn()}catch(W){s("err",W instanceof Error?W.message:String(W))}S>0&&s("ok",`Uploaded ${S} file${S===1?"":"s"}.`)}async function cs(h){await t.client.sessions.delete(h);const v=d.findIndex(S=>S.id===h);v>=0&&d.splice(v,1),t.currentSessionId===h&&(t.currentSessionId=d[0]?.id||"",t.currentSessionId||await ie()),Bt(),At(),Kt(),await tt()}function Kt(){x.innerHTML=d.map(h=>`
|
|
301
|
+
<div class="chat-session-row">
|
|
302
|
+
<button class="chat-session-btn ${h.id===t.currentSessionId?"active":""}" data-sid="${h.id}" title="${r(h.id)}">
|
|
303
|
+
<span class="block truncate">${r(h.title||h.id.slice(0,8))}</span>
|
|
304
|
+
</button>
|
|
305
|
+
<button class="chat-session-del" data-del-sid="${h.id}" title="Delete session">
|
|
306
|
+
<i data-lucide="trash-2"></i>
|
|
307
|
+
</button>
|
|
308
|
+
</div>
|
|
309
|
+
`).join(""),x.querySelectorAll("[data-sid]").forEach(h=>{h.addEventListener("click",async()=>{t.currentSessionId=h.dataset.sid,Bt(),At(),Kt(),await Et(),await tt(),M(!1)})}),x.querySelectorAll("[data-del-sid]").forEach(h=>{h.addEventListener("click",async v=>{v.stopPropagation();const S=h.dataset.delSid;if(!(!S||!await ai({title:"Delete session",message:"This will permanently remove this chat session and its messages.",confirmLabel:"Delete session"})))try{await cs(S),s("ok","Session deleted.")}catch(W){s("err",W instanceof Error?W.message:String(W))}})}),a(x)}async function tt(){if(_e(),!t.currentSessionId){y.innerHTML='<p class="tcp-subtle">Create a session to begin.</p>';return}const h=await t.client.sessions.messages(t.currentSessionId).catch(()=>[]),v=String(t.botName||"Assistant").trim()||"Assistant",S=String(t.botAvatarUrl||"").trim();y.innerHTML=h.map(H=>{const W=String(H?.info?.role||"unknown"),He=r(W==="assistant"?v:W==="user"?"User":W==="system"?"System":W),Fe=W==="assistant"?`<span class="inline-flex items-center gap-2">${S?`<img src="${r(S)}" alt="${r(v)}" class="chat-avatar-ring h-5 w-5 rounded-full object-cover" />`:""}<span>${He}</span></span>`:He,Ue=(H.parts||[]).map(Be=>Be.text||"").join(`
|
|
310
|
+
`),Ce=W==="assistant"||W==="system",Tt=Ce?`<div class="tcp-markdown tcp-markdown-ai">${ev(Ue)}</div>`:`<pre class="chat-msg-pre">${r(Ue)}</pre>`;return`<div class="chat-msg ${Ce?"assistant":"user"}"><div class="chat-msg-role">${Fe}</div>${Tt}</div>`}).join(""),y.scrollTop=y.scrollHeight}n("new-session").addEventListener("click",async()=>{M(!1);try{await ie()}catch(h){s("err",h instanceof Error?h.message:String(h))}}),re?.addEventListener("click",async()=>{const h=de.map(S=>S.id).filter(Boolean);if(!h.length)return;for(const S of h)await zt(S,"once",!0);await Et();const v=h.filter(S=>de.some(H=>String(H.id||"").trim()===S)).length;v>0?s("warn",`${v} request${v===1?"":"s"} still pending (likely stale/expired).`):s("ok",`Approved ${h.length} pending request${h.length===1?"":"s"}.`)}),ue?.addEventListener("change",()=>{pe=!!ue.checked,iv(pe),wt(),pe&&zn()});async function ls(){if(T)return;const h=I.value.trim(),v=ve.slice(),S=h||(v.length?"Please analyze the attached file(s).":"");if(!(!S&&v.length===0)){I.value="",K(),T=!0,g.disabled=!0;try{t.currentSessionId||await ie(),is(S,v.length);const H=await E();if(!H)throw new Error("No default provider/model configured. Set it in Settings before sending chat.");v.length>0&&s("info",`Sending with ${v.length} attached file${v.length===1?"":"s"}.`);const W=v.map(B=>({type:"file",mime:B.mime||fa(B.name||B.path),filename:B.name||B.path||"attachment",url:B.url||B.path}));W.push({type:"text",text:S});const Te=async()=>{const B=await fetch(`/api/engine/session/${encodeURIComponent(t.currentSessionId)}/run`,{method:"GET",credentials:"include"});if(!B.ok)return"";const he=await B.json().catch(()=>({}));return he?.active?.runID||he?.active?.runId||he?.active?.run_id||""},He=async()=>{const B=await Te().catch(()=>"");B&&await fetch(`/api/engine/session/${encodeURIComponent(t.currentSessionId)}/run/${encodeURIComponent(B)}/cancel`,{method:"POST",credentials:"include",headers:{"content-type":"application/json"},body:JSON.stringify({})}).catch(()=>{}),await fetch(`/api/engine/session/${encodeURIComponent(t.currentSessionId)}/cancel`,{method:"POST",credentials:"include",headers:{"content-type":"application/json"},body:JSON.stringify({})}).catch(()=>{});for(let he=0;he<50;he+=1){if(!await Te().catch(()=>""))return!0;await new Promise(Ze=>setTimeout(Ze,200))}return!1},Fe=async()=>fetch(`/api/engine/session/${encodeURIComponent(t.currentSessionId)}/prompt_async?return=run`,{method:"POST",credentials:"include",headers:{"content-type":"application/json"},body:JSON.stringify({parts:W,model:{providerID:H.providerID,modelID:H.modelID}})});let Ue=await Fe(),Ce="";if(Ue.status===409){if(!await He())throw new Error("Session has a stuck active run. Cancel it from engine/session and retry.");if(Ue=await Fe(),Ue.ok){const he=await Ue.json().catch(()=>({}));Ce=he?.runID||he?.runId||he?.run_id||""}else{if(Ue.status===409)throw new Error("Session is still busy with another run. Please retry in a moment.");{const he=await Ue.text().catch(()=>"");throw new Error(`prompt_async retry failed (${Ue.status}): ${he}`)}}}else if(Ue.ok){const B=await Ue.json().catch(()=>({}));Ce=B?.runID||B?.runId||B?.run_id||""}else{const B=await Ue.text().catch(()=>"");throw new Error(`prompt_async failed (${Ue.status}): ${B}`)}if(!Ce)throw new Error("No run ID returned from engine.");v.length>0&&(ve.splice(0,ve.length),mn());let Tt="",dt=!1;const Be=r(String(t.botName||"Assistant").trim()||"Assistant"),Gt=String(t.botAvatarUrl||"").trim(),Nt=document.createElement("div");Nt.className="chat-msg assistant",Nt.innerHTML=`
|
|
311
|
+
<div class="chat-msg-role"><span class="inline-flex items-center gap-2">${Gt?`<img src="${r(Gt)}" alt="${Be}" class="chat-avatar-ring h-5 w-5 rounded-full object-cover" />`:""}<span>${Be}</span></span></div>
|
|
312
|
+
<div class="tcp-thinking" aria-live="polite">
|
|
313
|
+
<span>Thinking</span>
|
|
314
|
+
<i></i><i></i><i></i>
|
|
315
|
+
</div>
|
|
316
|
+
<pre class="streaming-msg chat-msg-pre hidden"></pre>
|
|
317
|
+
`,y.appendChild(Nt),y.scrollTop=y.scrollHeight;const Wt=Nt.querySelector(".tcp-thinking"),Nn=Nt.querySelector(".streaming-msg"),ds=new Set(["run.complete","run.completed","session.run.finished","session.run.completed"]),Qs=new Set(["run.failed","session.run.failed","run.cancelled","run.canceled","session.run.cancelled","session.run.canceled"]),us=new Set(["tool.called","tool_call.started","session.tool_call"]),ut=new Set(["tool.result","tool_call.completed","tool_call.failed","session.tool_result"]);let fn=!1;const Dn=new AbortController;let Yt=null,jn=null,Ct="";const Xt=3e4,hn=18e4,Qt=async(B,he)=>{const ge=Date.now();for(;Date.now()-ge<he;){const Ze=await Te().catch(()=>B);if(await tt(),!Ze||Ze!==B)return!0;await new Promise(Je=>setTimeout(Je,350))}return!1},gn=B=>{const he=String(B||"").trim();return he!=="server.connected"&&he!=="engine.lifecycle.ready"},Dt=()=>{Yt&&clearTimeout(Yt),Yt=setTimeout(()=>{fn=!0,Ct="no-events-timeout",Dn.abort("no-events-timeout")},Xt)};Dt(),jn=setTimeout(()=>{fn=!0,Ct="max-stream-window",Dn.abort("max-stream-window")},hn);try{for await(const B of t.client.stream(t.currentSessionId,Ce,{signal:Dn.signal})){gn(B.type)&&Dt();const he=Ot(B);if(B.type==="approval.requested"||B.type==="permission.request"||B.type==="permission.asked"){const ge=pn(B.properties||{});ge?(!ge.sessionId||ge.sessionId===String(t.currentSessionId||"").trim())&&(On(ge),wt(),zn()):Et()}if(B.type==="approval.resolved"||B.type==="permission.resolved"||B.type==="permission.replied"){const ge=pn(B.properties||{});ge?.id&&as(ge.id),wt(),Et()}if(String(B.type||"").toLowerCase().startsWith("pack.")&&Ln(B.type,B.properties||{}),!(he&&he!==Ce)){if(B.type==="session.response"){const ge=String(B.properties?.delta||"");if(!ge)continue;dt=!0,Wt&&Wt.classList.add("hidden"),Nn.classList.remove("hidden"),Tt+=ge,Nn.textContent=Tt,y.scrollTop=y.scrollHeight}if(us.has(B.type)){const ge=$t(B.properties)||"tool",Ze=un(B.properties);dn(ge,"started",`${Ze||he||Ce}:${ge}:started`)}if(ut.has(B.type)){const ge=$t(B.properties)||"tool",Ze=un(B.properties),Je=String(B.properties?.status||B.properties?.state||"").toLowerCase(),St=B.type==="tool_call.failed"||Je.includes("fail")||Je.includes("error")||!!B.properties?.error;dn(ge,St?"failed":"completed",`${Ze||he||Ce}:${ge}:${St?"failed":"completed"}`)}if(B.type==="message.part.updated"){const ge=B.properties?.part||{},Ze=String(ge.type||"").trim().toLowerCase().replace(/_/g,"-"),Je=$t(ge)||$t(B.properties),St=un(ge),ze=ge?.state,Ke=String((ze&&typeof ze=="object"?ze.status:ze)||ge.status||"").trim().toLowerCase(),Ge=!!ge.error||!!(ze&&typeof ze=="object"&&ze.error)||Ke.includes("fail")||Ke.includes("error")||Ke.includes("deny")||Ke.includes("reject")||Ke.includes("cancel"),nt=!!ge.result||!!ge.output||!!(ze&&typeof ze=="object"&&(ze.output||ze.result))||Ke.includes("done")||Ke.includes("complete")||Ke.includes("success");if(Je&&(Ze==="tool"||Ze==="tool-invocation")){const vn=Ge?"failed":nt?"completed":"started";dn(Je,vn,`${St||he||Ce}:${Je}:${vn}`)}Je&&Ze==="tool-result"&&dn(Je,Ge?"failed":"completed",`${St||he||Ce}:${Je}:${Ge?"failed":"completed"}`)}if(Qs.has(B.type))throw new Error(String(B.properties?.error||"Run failed."));if((B.type==="session.updated"||B.type==="session.status")&&String(B.properties?.status||"").toLowerCase()==="idle"||ds.has(B.type))break}}}catch(B){const he=String(B?.message||B||"").toLowerCase();if(!(fn||he.includes("abort")||he.includes("terminated")||he.includes("networkerror")))throw B}if(Yt&&clearTimeout(Yt),jn&&clearTimeout(jn),fn){const B=await Qt(Ce,45e3);if(await tt(),!B)throw new Error("Run stream timed out and the run is still active. Check engine/provider logs and retry.")}if(!dt&&Wt&&(Wt.innerHTML="<span>Finalizing response...</span>"),await tt(),await new Promise(B=>setTimeout(B,180)),await tt(),await new Promise(B=>setTimeout(B,220)),await tt(),!dt&&await Te().catch(()=>"")===Ce){if(await Qt(Ce,3e4)){await tt();return}const ge=Ct||"stream-ended-without-final-delta";throw new Error(`Run ${Ce} is still active without a final response (${ge}).`)}}catch(H){const W=H instanceof Error?H.message:String(H),Te=W.includes("no-events-timeout")||W.includes("max-stream-window")||W.includes("AbortError")||W.toLowerCase().includes("terminated")?"Run stream timed out before events were received. Check engine/provider logs and retry.":W;s("err",Te),await tt()}finally{T=!1,g.disabled=!1}}}g.addEventListener("click",()=>{ls()}),n("chat-toggle-sessions")?.addEventListener("click",()=>{M(!u)}),b?.addEventListener("click",()=>{M(!1)}),n("chat-tools-clear")?.addEventListener("click",()=>{Bt()}),ee?.addEventListener("click",()=>{At()}),O.addEventListener("click",()=>{C.click()}),C.addEventListener("change",async()=>{await Xs(C.files),C.value=""}),I.addEventListener("keydown",h=>{h.key==="Enter"&&!h.shiftKey&&(h.preventDefault(),ls())}),I.addEventListener("input",()=>{K()}),Kt(),mn(),Ye(),gt(),wt(),Ys(),Et();const we=setInterval(()=>{t.route==="chat"&&Et()},2500);c?.(()=>clearInterval(we)),!t.currentSessionId&&d.length===0&&await ie().catch(()=>{}),M(!1),K(),await tt()}async function ft(e){const{state:t,byId:n,toast:s,escapeHtml:r,api:i,renderIcons:a,setRoute:c}=e,l=["overview","routines","automations","templates","runs"],d="tcp_agents_wizard_seen_v1",u=()=>{const o=String(window.location.hash||""),[,p=""]=o.split("?"),f=new URLSearchParams(p),w=String(f.get("tab")||"").trim().toLowerCase(),$=l.includes(w)?w:"overview",V=String(f.get("flow")||"").trim().toLowerCase()==="routine"?"routine":"advanced",Q=Number.parseInt(String(f.get("step")||"0"),10),oe=Number.isFinite(Q)?Math.min(2,Math.max(0,Q)):0,ke=f.has("wizard"),Se=String(f.get("wizard")||"0").trim()==="1";return{tab:$,flow:V,step:oe,wizard:Se,wizardProvided:ke}},m=(o={})=>{const p=u(),f={tab:l.includes(String(o.tab||"").toLowerCase())?String(o.tab).toLowerCase():p.tab,flow:String(o.flow||p.flow).toLowerCase()==="routine"?"routine":"advanced",step:Number.isFinite(Number(o.step))?Math.min(2,Math.max(0,Number.parseInt(String(o.step),10)||0)):p.step,wizard:typeof o.wizard=="boolean"?o.wizard:String(o.wizard||"").trim()==="1"?!0:o.wizard===0?!1:p.wizard},w=new URLSearchParams;w.set("tab",f.tab),w.set("flow",f.flow),w.set("step",String(f.step)),w.set("wizard",f.wizard?"1":"0");const $=`#/agents?${w.toString()}`;window.location.hash!==$&&(window.location.hash=$)},[_,b,x,y,I,g,C,O,P,j]=await Promise.all([t.client.routines.list().catch(()=>({routines:[]})),t.client.automations.list().catch(()=>({automations:[]})),t.client?.automationsV2?.list?.().catch(()=>({automations:[]}))||Promise.resolve({automations:[]}),t.client.routines.listRuns({limit:100}).catch(()=>({runs:[]})),t.client.automations.listRuns({limit:100}).catch(()=>({runs:[]})),t.client.providers.catalog().catch(()=>({all:[],connected:[],default:null})),t.client.providers.config().catch(()=>({default:null,providers:{}})),t.client.listToolIds().catch(()=>[]),t.client?.mcp?.list?.().catch(()=>({}))||Promise.resolve({}),t.client?.skills?.list?.().catch(()=>({skills:[]}))||Promise.resolve({skills:[]})]),Y=_.routines||[],N=b.automations||[],z=Array.isArray(x?.automations)?x.automations:[],D=Array.isArray(y?.runs)?y.runs:[],R=Array.isArray(I?.runs)?I.runs:[],Z=Array.isArray(g?.all)?g.all:[],le=C?.providers||{},ee=Array.isArray(O)?O.map(o=>String(o||"").trim()).filter(Boolean).sort():[],re=(o=>!o||typeof o!="object"?[]:(Array.isArray(o)?o.map(f=>[String(f?.name||""),f]):Object.entries(o)).map(([f,w])=>{const $=w&&typeof w=="object"?w:{},L=String($.name||f||"").trim();if(!L)return null;const V=!!$.connected,Q=$.enabled!==!1;return{name:L,connected:V,enabled:Q}}).filter(Boolean).sort((f,w)=>f.name.localeCompare(w.name)))(P).filter(o=>o.connected&&o.enabled).map(o=>o.name),ue=Array.isArray(j?.skills)?j.skills.map(o=>String(o?.name||o?.id||"").trim()).filter(Boolean).sort((o,p)=>o.localeCompare(p)):[],ce=(o="")=>String(o).toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"routine",Ee=o=>{if(!o)return"manual";if(typeof o=="string")return o;const p=Number(o?.interval_seconds?.seconds??o?.intervalSeconds?.seconds??o?.intervalSeconds??0);if(p>0)return p%3600===0?`every ${p/3600}h`:p%60===0?`every ${p/60}m`:`every ${p}s`;const f=String(o?.cron?.expression??o?.cron?.cron??o?.expression??o?.cron??"").trim();if(f){const w=f,$=w.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/);if($){const V=String($[1]).padStart(2,"0");return`daily ${String($[2]).padStart(2,"0")}:${V}`}const L=w.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+([0-6])$/);if(L){const V=String(L[1]).padStart(2,"0"),Q=String(L[2]).padStart(2,"0");return`weekly ${["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][Number.parseInt(L[3],10)]||L[3]} ${Q}:${V}`}return`cron ${w}`.trim()}return o.type==="manual"?"manual":JSON.stringify(o)},ve=o=>{const p=String(o?.args?.promptFilePath||"").trim();return p||String(o?.entrypoint||o?.prompt||"").match(/(control-panel\/routines\/[A-Za-z0-9._\-\/]+\.md)/)?.[1]||""},je=o=>{const p=o?.args?.model_policy?.default_model,f=String(p?.provider_id||"").trim(),w=String(p?.model_id||"").trim();return!f||!w?"":`${f}/${w}`},ne=(o,p,f)=>{const w=o?.[p]??o?.[f]??[];if(!Array.isArray(w))return[];const $=new Set,L=[];for(const V of w){const Q=String(V||"").trim();Q&&($.has(Q)||($.add(Q),L.push(Q)))}return L},X=(o,p,f,w)=>{const $=o?.[p];if(typeof $=="boolean")return $;const L=o?.[f];return typeof L=="boolean"?L:w},$e=o=>{const p=new Set,f=[];return String(o||"").split(",").map(w=>w.trim()).filter(Boolean).forEach(w=>{p.has(w)||(p.add(w),f.push(w))}),f},me=o=>String(o?.id||o?.routine_id||o?.routineID||o?.routineId||"").trim(),de=o=>String(o?.id||o?.automation_id||o?.automationID||o?.automationId||"").trim(),fe=o=>String(o?.runId||o?.runID||o?.run_id||o?.id||"").trim(),pe=o=>String(o?.routineId||o?.routine_id||o?.routineID||o?.routineId||"").trim(),be=o=>String(o?.automationId||o?.automation_id||o?.automationID||o?.automationId||"").trim(),k=o=>String(o?.status||"unknown").toLowerCase(),T=o=>String(o?.detail||o?.reason||"").trim(),M=o=>{const p=[o?.updatedAtMs,o?.updated_at_ms,o?.finishedAtMs,o?.finished_at_ms,o?.startedAtMs,o?.started_at_ms,o?.createdAtMs,o?.created_at_ms,o?.firedAtMs,o?.fired_at_ms];for(const f of p){const w=Number(f);if(Number.isFinite(w)&&w>0)return w}return 0},K=o=>{const p=Number(o);return!Number.isFinite(p)||p<=0?"time n/a":new Date(p).toLocaleString()},J=(o,p=120)=>{const f=String(o||"").trim();return f?f.length>p?`${f.slice(0,p-1)}...`:f:""},q=o=>{const p=String(o||"").toLowerCase();return p.includes("complete")||p.includes("succeed")?"tcp-badge-info":p.includes("fail")||p.includes("cancel")||p.includes("deny")?"tcp-badge-err":p.includes("block")||p.includes("approval")||p.includes("pause")?"tcp-badge-warn":"tcp-badge-info"},E=o=>{const p=String(o||"").toLowerCase();return p==="pending_approval"||p.includes("awaiting_approval")},ie=(o,p)=>{const f=new Map,w=[...o].sort(($,L)=>M(L)-M($));for(const $ of w){const L=p($);!L||f.has(L)||f.set(L,$)}return f},ye=new Map(Y.map(o=>[me(o),String(o.name||me(o)||"Routine").trim()]).filter(([o])=>!!o)),Ie=new Map(Y.map(o=>[me(o),o]).filter(([o])=>!!o)),_e=new Map(N.map(o=>[de(o),String(o.name||de(o)||"Automation").trim()]).filter(([o])=>!!o)),at=ie(D,pe),Ye=ie(R,be),ln=[...D.map(o=>({family:"routine",run:o})),...R.map(o=>({family:"automation",run:o}))].sort((o,p)=>M(p.run)-M(o.run)),gt=[],At=new Set;for(const o of ln){const p=fe(o.run),f=o.family==="routine"?pe(o.run):be(o.run),w=p||`${o.family}:${f}:${M(o.run)}:${k(o.run)}`;if(!At.has(w)&&(At.add(w),gt.push(o),gt.length>=30))break}const Ln=new Set(N.map(o=>de(o)).filter(Boolean)),Bt=new Set(Y.map(o=>me(o)).filter(Boolean)),dn=Ln.size>0&&Ln.size===Bt.size&&[...Ln].every(o=>Bt.has(o)),is=Object.fromEntries(Object.entries(le).map(([o,p])=>[o,String(p?.default_model||p?.defaultModel||"").trim()])),Lt=Z.map(o=>o.id).filter(Boolean),$t=o=>{const p=Z.find(f=>f.id===o);return Object.keys(p?.models||{})},un=String(C?.default||g?.default||t.providerDefault||"").trim(),Ot=Lt.includes(un)?un:Lt[0]||"",pn=String(is[Ot]||t.providerDefaultModel||"").trim(),Jt=$t(Ot),On=Jt.includes(pn)?pn:Jt[0]||"",as=Z.map(o=>{const p=String(o.name||o.id||"").trim()||o.id;return`<option value="${r(o.id)}" ${o.id===Ot?"selected":""}>${r(p)}</option>`}).join("")||'<option value="">No providers found</option>',wt=Jt.map(o=>`<option value="${r(o)}" ${o===On?"selected":""}>${r(o)}</option>`).join("")||'<option value="">No models found</option>',zt=ee.map(o=>`<option value="${r(o)}"></option>`).join(""),zn=N.map(o=>{const p=de(o),f=Ye.get(p),w=k(f),$=fe(f),L=J(T(f)),V=E(w)&&!!$;return`<div class="tcp-list-item">
|
|
318
|
+
<div class="flex items-center justify-between gap-2">
|
|
319
|
+
<span>${r(String(o.name||p||"Automation"))}</span>
|
|
320
|
+
<div class="flex items-center gap-2">
|
|
321
|
+
<span class="tcp-subtle">${r(String(o.status||""))}</span>
|
|
322
|
+
${p?`<button data-run-automation="${r(p)}" class="tcp-btn h-7 px-2 text-xs"><i data-lucide="play"></i> Run</button>`:""}
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
${f?`<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
326
|
+
<span class="${q(w)}">${r(w)}</span>
|
|
327
|
+
<span class="tcp-subtle">${r(K(M(f)))}</span>
|
|
328
|
+
<span class="tcp-subtle font-mono">${r($||"run n/a")}</span>
|
|
329
|
+
</div>
|
|
330
|
+
${V?`<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
331
|
+
<button data-run-review="approve" data-run-id="${r($)}" data-run-family="automation" class="tcp-btn h-7 px-2 text-xs">Approve</button>
|
|
332
|
+
<button data-run-review="deny" data-run-id="${r($)}" data-run-family="automation" class="tcp-btn-danger h-7 px-2 text-xs">Deny</button>
|
|
333
|
+
</div>`:""}
|
|
334
|
+
${L?`<div class="mt-1 text-xs text-slate-400">${r(L)}</div>`:""}`:'<div class="mt-1 text-xs text-slate-500">No automation runs yet.</div>'}
|
|
335
|
+
</div>`}).join("")||'<p class="tcp-subtle">No automations.</p>',Et=o=>String(o?.automation_id||o?.automationId||o?.id||o?.automationID||"").trim(),os=z.map(o=>{const p=Et(o),f=String(o?.status||"draft").toLowerCase(),w=Number(o?.next_fire_at_ms||o?.nextFireAtMs||0),$=Array.isArray(o?.flow?.nodes)?o.flow.nodes.length:0,L=Array.isArray(o?.agents)?o.agents.length:0;return`<div class="tcp-list-item">
|
|
336
|
+
<div class="flex items-center justify-between gap-2">
|
|
337
|
+
<span>${r(String(o?.name||p||"Automation"))}</span>
|
|
338
|
+
<div class="flex items-center gap-2">
|
|
339
|
+
<span class="${q(f)}">${r(f)}</span>
|
|
340
|
+
${p?`<button data-v2-run-now="${r(p)}" class="tcp-btn h-7 px-2 text-xs"><i data-lucide="play"></i> Run</button>`:""}
|
|
341
|
+
${p?`<button data-v2-toggle="${r(p)}" data-v2-next="${f==="paused"?"resume":"pause"}" class="tcp-btn h-7 px-2 text-xs">
|
|
342
|
+
<i data-lucide="${f==="paused"?"play-circle":"pause-circle"}"></i> ${f==="paused"?"Resume":"Pause"}
|
|
343
|
+
</button>`:""}
|
|
344
|
+
${p?`<button data-v2-runs="${r(p)}" class="tcp-btn h-7 px-2 text-xs"><i data-lucide="list"></i> Runs</button>`:""}
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
348
|
+
<span class="tcp-subtle">${L} agents</span>
|
|
349
|
+
<span class="tcp-subtle">${$} nodes</span>
|
|
350
|
+
<span class="tcp-subtle">${w>0?K(w):"manual schedule"}</span>
|
|
351
|
+
<span class="tcp-subtle font-mono">${r(p||"id n/a")}</span>
|
|
352
|
+
</div>
|
|
353
|
+
</div>`}).join("")||'<p class="tcp-subtle">No advanced automations.</p>',Ys=gt.map(({family:o,run:p})=>{const f=o==="routine",w=f?pe(p):be(p),$=fe(p),L=f?ye.get(w)||w||"Routine":_e.get(w)||w||"Automation",V=k(p),Q=E(V)&&!!$,oe=J(T(p),180);return`<div class="tcp-list-item">
|
|
354
|
+
<div class="flex items-center justify-between gap-2">
|
|
355
|
+
<span class="font-medium">${r(L)}</span>
|
|
356
|
+
<div class="flex items-center gap-2">
|
|
357
|
+
${$?`<button data-inspect-run="${r($)}" data-run-family="${r(o)}" class="tcp-btn h-7 px-2 text-xs">Details</button>`:""}
|
|
358
|
+
${Q?`<button data-run-review="approve" data-run-id="${r($)}" data-run-family="${r(o)}" class="tcp-btn h-7 px-2 text-xs">Approve</button>
|
|
359
|
+
<button data-run-review="deny" data-run-id="${r($)}" data-run-family="${r(o)}" class="tcp-btn-danger h-7 px-2 text-xs">Deny</button>`:""}
|
|
360
|
+
<span class="${q(V)}">${r(V)}</span>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
364
|
+
<span class="tcp-subtle">${f?"Routine":"Automation"}</span>
|
|
365
|
+
<span class="tcp-subtle">${r(K(M(p)))}</span>
|
|
366
|
+
<span class="tcp-subtle font-mono">${r($||"run n/a")}</span>
|
|
367
|
+
</div>
|
|
368
|
+
${oe?`<div class="mt-1 text-xs text-slate-400">${r(oe)}</div>`:""}
|
|
369
|
+
</div>`}).join("")||'<p class="tcp-subtle">No runs yet.</p>',It=o=>{const p=Number(o?.total_tokens??o?.totalTokens??0);return Number.isFinite(p)&&p>=0?p:0},mn=o=>{const p=Number(o?.estimated_cost_usd??o?.estimatedCostUsd??0);return Number.isFinite(p)&&p>=0?p:0},Xs=Date.now()-24*36e5;let cs=0,Kt=0;const tt=new Map;for(const o of[...D,...R]){const p=M(o),f=It(o),w=mn(o);p>=Xs&&(cs+=f,Kt+=w);const $=pe(o)||be(o)||"unknown",L=tt.get($)||{cost:0};L.cost+=w,tt.set($,L)}const ls=[...tt.entries()].map(([o,p])=>({id:o,cost:p.cost})).sort((o,p)=>p.cost-o.cost).slice(0,3),we=u();if(!we.wizard&&!we.wizardProvided&&!Y.length&&!N.length&&!z.length){let o=!1;try{o=localStorage.getItem(d)==="1"}catch{o=!1}o||setTimeout(()=>{m({tab:"overview",wizard:!0,flow:"advanced",step:0})},0)}const h=(...o)=>o.includes(we.tab)?"":" hidden",v=we.flow==="routine"?["Choose flow","Configure routine","Run + monitor"]:["Choose flow","Configure agents","Run + monitor"];n("view").innerHTML=`
|
|
370
|
+
<div class="agents-theme grid gap-4">
|
|
371
|
+
<div class="tcp-card" data-agents-panel="header">
|
|
372
|
+
<div class="flex flex-wrap items-center justify-between gap-3">
|
|
373
|
+
<div>
|
|
374
|
+
<h3 class="tcp-title">Automations</h3>
|
|
375
|
+
<p class="tcp-subtle text-xs">Build, schedule, and operate routines and multi-agent automations.</p>
|
|
376
|
+
</div>
|
|
377
|
+
<div class="flex flex-wrap gap-2">
|
|
378
|
+
<button id="agents-open-settings-integrations" class="tcp-btn"><i data-lucide="settings"></i> Integrations In Settings</button>
|
|
379
|
+
<button id="agents-launch-wizard" class="tcp-btn-primary"><i data-lucide="sparkles"></i> Launch Walkthrough</button>
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
<div class="tcp-card" data-agents-panel="tab-shell">
|
|
384
|
+
<div class="tcp-settings-tabs" role="tablist" aria-label="Automation sections">
|
|
385
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${we.tab==="overview"?"active":""}" data-agents-tab="overview" role="tab" aria-selected="${we.tab==="overview"}">Overview</button>
|
|
386
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${we.tab==="routines"?"active":""}" data-agents-tab="routines" role="tab" aria-selected="${we.tab==="routines"}">Routines</button>
|
|
387
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${we.tab==="automations"?"active":""}" data-agents-tab="automations" role="tab" aria-selected="${we.tab==="automations"}">Automations</button>
|
|
388
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${we.tab==="templates"?"active":""}" data-agents-tab="templates" role="tab" aria-selected="${we.tab==="templates"}">Templates</button>
|
|
389
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${we.tab==="runs"?"active":""}" data-agents-tab="runs" role="tab" aria-selected="${we.tab==="runs"}">Runs & Approvals</button>
|
|
390
|
+
</div>
|
|
391
|
+
<div class="agents-tab-panel${h("overview")}" data-agents-panel="overview">
|
|
392
|
+
<h3 class="tcp-title mb-2">Overview</h3>
|
|
393
|
+
<div class="dashboard-kpis mb-3">
|
|
394
|
+
<div><span class="dashboard-kpi-label">Routines</span><strong>${Y.length}</strong></div>
|
|
395
|
+
<div><span class="dashboard-kpi-label">Automations</span><strong>${z.length}</strong></div>
|
|
396
|
+
<div><span class="dashboard-kpi-label">Pending approvals</span><strong>${gt.filter(o=>E(k(o.run))).length}</strong></div>
|
|
397
|
+
<div><span class="dashboard-kpi-label">Recent runs</span><strong>${gt.length}</strong></div>
|
|
398
|
+
</div>
|
|
399
|
+
<div class="rounded-xl border border-slate-700/60 bg-slate-900/30 p-3">
|
|
400
|
+
<div class="mb-2 flex items-center justify-between gap-2">
|
|
401
|
+
<span class="font-medium">Automations + Cost (24h)</span>
|
|
402
|
+
<span class="tcp-subtle text-xs">dashboard has full analytics</span>
|
|
403
|
+
</div>
|
|
404
|
+
<div class="grid gap-2 md:grid-cols-3">
|
|
405
|
+
<div class="tcp-subtle">Tokens: <span class="font-mono text-slate-200">${cs.toLocaleString()}</span></div>
|
|
406
|
+
<div class="tcp-subtle">Estimated cost: <span class="font-mono text-slate-200">$${Kt.toFixed(4)}</span></div>
|
|
407
|
+
<div class="tcp-subtle">Top owners: <span class="font-mono text-slate-200">${r(ls.map(o=>o.id).join(", ")||"none")}</span></div>
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
<div class="agents-tab-panel${we.wizard?"":" hidden"}" data-agents-panel="wizard">
|
|
412
|
+
<div class="flex items-center justify-between gap-2">
|
|
413
|
+
<h3 class="tcp-title">Walkthrough Wizard</h3>
|
|
414
|
+
<button id="agents-wizard-close" class="tcp-btn">Close</button>
|
|
415
|
+
</div>
|
|
416
|
+
<div class="agents-steps mt-3">
|
|
417
|
+
${v.map((o,p)=>`<span class="agents-step-chip ${we.step===p?"active":""}">${p+1}. ${r(o)}</span>`).join("")}
|
|
418
|
+
</div>
|
|
419
|
+
<div class="mt-3 rounded-xl border border-slate-700/60 bg-slate-900/35 p-3">
|
|
420
|
+
${we.step===0?`<p class="tcp-subtle mb-3">Pick what you want to build first.</p>
|
|
421
|
+
<div class="flex flex-wrap gap-2">
|
|
422
|
+
<button data-wizard-flow="advanced" class="tcp-btn ${we.flow==="advanced"?"border-slate-300/80":""}">Advanced automation</button>
|
|
423
|
+
<button data-wizard-flow="routine" class="tcp-btn ${we.flow==="routine"?"border-slate-300/80":""}">Routine</button>
|
|
424
|
+
</div>`:we.step===1?`<p class="tcp-subtle mb-3">${we.flow==="routine"?"Configure schedule, model, and policy for your routine.":"Configure schedule, per-agent models/skills, and DAG nodes."}</p>
|
|
425
|
+
<button id="agents-wizard-open-builder" class="tcp-btn-primary">${we.flow==="routine"?"Open Routine Builder":"Open Automation Builder"}</button>`:`<p class="tcp-subtle mb-3">Launch runs and monitor approvals, pause/resume, and outcomes.</p>
|
|
426
|
+
<button id="agents-wizard-open-runs" class="tcp-btn-primary">Open Runs & Approvals</button>`}
|
|
427
|
+
</div>
|
|
428
|
+
<div class="mt-3 flex items-center justify-between">
|
|
429
|
+
<button id="agents-wizard-prev" class="tcp-btn" ${we.step<=0?"disabled":""}>Back</button>
|
|
430
|
+
<button id="agents-wizard-next" class="tcp-btn-primary">${we.step>=2?"Finish":"Next"}</button>
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
<div class="agents-tab-panel${h("templates")}" data-agents-panel="templates">
|
|
434
|
+
<h3 class="tcp-title mb-3">Automation Templates</h3>
|
|
435
|
+
<div class="grid gap-2 md:grid-cols-2">
|
|
436
|
+
<button class="tcp-btn justify-start" data-template-id="github_bug_hunter">GitHub bug hunter</button>
|
|
437
|
+
<button class="tcp-btn justify-start" data-template-id="code_generation_pipeline">Code generation pipeline</button>
|
|
438
|
+
<button class="tcp-btn justify-start" data-template-id="release_notes_changelog">Release notes + changelog</button>
|
|
439
|
+
<button class="tcp-btn justify-start" data-template-id="marketing_content_engine">Marketing content engine</button>
|
|
440
|
+
<button class="tcp-btn justify-start" data-template-id="sales_lead_outreach">Sales lead outreach</button>
|
|
441
|
+
<button class="tcp-btn justify-start" data-template-id="productivity_inbox_to_tasks">Productivity: inbox to tasks</button>
|
|
442
|
+
</div>
|
|
443
|
+
<p class="tcp-subtle mt-3 text-xs">Selecting a template pre-fills the advanced automation builder and opens the walkthrough.</p>
|
|
444
|
+
</div>
|
|
445
|
+
<div class="agents-tab-panel${h("routines")}" data-agents-panel="routines">
|
|
446
|
+
<h3 class="tcp-title mb-3">Create Routine</h3>
|
|
447
|
+
<p id="routine-form-mode" class="mb-2 text-xs text-slate-400">Creating new routine</p>
|
|
448
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
449
|
+
<input id="routine-name" class="tcp-input" placeholder="Routine name" />
|
|
450
|
+
<select id="routine-schedule-mode" class="tcp-select">
|
|
451
|
+
<option value="interval">Every X minutes/hours</option>
|
|
452
|
+
<option value="daily">Daily at specific time</option>
|
|
453
|
+
<option value="weekly">Weekly on a specific day/time</option>
|
|
454
|
+
<option value="customCron">Custom cron</option>
|
|
455
|
+
<option value="manual">Manual only</option>
|
|
456
|
+
</select>
|
|
457
|
+
</div>
|
|
458
|
+
<div id="routine-interval-controls" class="mt-3 grid gap-3 md:grid-cols-2">
|
|
459
|
+
<input id="routine-interval-value" class="tcp-input" type="number" min="1" max="10000" step="1" value="30" />
|
|
460
|
+
<select id="routine-interval-unit" class="tcp-select">
|
|
461
|
+
<option value="minutes">Minutes</option>
|
|
462
|
+
<option value="hours">Hours</option>
|
|
463
|
+
</select>
|
|
464
|
+
</div>
|
|
465
|
+
<div id="routine-daily-controls" class="mt-3 grid hidden gap-3 md:grid-cols-2">
|
|
466
|
+
<input id="routine-time" class="tcp-input" type="time" value="09:00" />
|
|
467
|
+
<div class="tcp-subtle self-center text-xs">Runs once per day at selected time</div>
|
|
468
|
+
</div>
|
|
469
|
+
<div id="routine-weekly-controls" class="mt-3 grid hidden gap-3 md:grid-cols-2">
|
|
470
|
+
<select id="routine-weekday" class="tcp-select">
|
|
471
|
+
<option value="1">Monday</option>
|
|
472
|
+
<option value="2">Tuesday</option>
|
|
473
|
+
<option value="3">Wednesday</option>
|
|
474
|
+
<option value="4">Thursday</option>
|
|
475
|
+
<option value="5">Friday</option>
|
|
476
|
+
<option value="6">Saturday</option>
|
|
477
|
+
<option value="0">Sunday</option>
|
|
478
|
+
</select>
|
|
479
|
+
<input id="routine-weekly-time" class="tcp-input" type="time" value="09:00" />
|
|
480
|
+
</div>
|
|
481
|
+
<div id="routine-cron-controls" class="mt-3 grid hidden gap-3 md:grid-cols-1">
|
|
482
|
+
<input id="routine-cron" class="tcp-input hidden" placeholder="Cron e.g. 0 * * * *" />
|
|
483
|
+
</div>
|
|
484
|
+
<div class="mt-2 text-xs text-slate-400">
|
|
485
|
+
<span id="routine-schedule-preview" class="font-mono">Schedule: every 30m</span>
|
|
486
|
+
</div>
|
|
487
|
+
<div class="mt-3 grid gap-3 md:grid-cols-2">
|
|
488
|
+
<div>
|
|
489
|
+
<label class="mb-1 block text-sm text-slate-300">Routine Provider</label>
|
|
490
|
+
<select id="routine-model-provider" class="tcp-select" ${Z.length?"":"disabled"}>
|
|
491
|
+
${as}
|
|
492
|
+
</select>
|
|
493
|
+
</div>
|
|
494
|
+
<div>
|
|
495
|
+
<label class="mb-1 block text-sm text-slate-300">Routine Model</label>
|
|
496
|
+
<select id="routine-model-id" class="tcp-select" ${Jt.length?"":"disabled"}>
|
|
497
|
+
${wt}
|
|
498
|
+
</select>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
<div class="mt-1 text-xs text-slate-400">
|
|
502
|
+
Model route for this routine: <span id="routine-model-preview" class="font-mono">${r(Ot&&On?`${Ot}/${On}`:"default engine route")}</span>
|
|
503
|
+
</div>
|
|
504
|
+
<div class="mt-3 rounded-xl border border-slate-700/70 bg-slate-900/35 p-3">
|
|
505
|
+
<label class="mb-2 inline-flex items-center gap-2 text-xs text-slate-200">
|
|
506
|
+
<input id="routine-allow-everything" type="checkbox" class="h-4 w-4 accent-slate-400" />
|
|
507
|
+
Allow everything (no approval, all tools, external integrations)
|
|
508
|
+
</label>
|
|
509
|
+
<label class="mb-1 block text-sm text-slate-300">Tool Allowlist (optional)</label>
|
|
510
|
+
<input
|
|
511
|
+
id="routine-allowed-tools"
|
|
512
|
+
list="routine-tool-options"
|
|
513
|
+
class="tcp-input font-mono text-xs"
|
|
514
|
+
placeholder="Comma-separated tool IDs (leave empty to allow all tools by policy)"
|
|
515
|
+
/>
|
|
516
|
+
<datalist id="routine-tool-options">${zt}</datalist>
|
|
517
|
+
<div id="routine-tool-scope-preview" class="mt-1 text-xs text-slate-400">Tool scope: all tools allowed by policy</div>
|
|
518
|
+
<div class="mt-2 grid gap-2 md:grid-cols-2">
|
|
519
|
+
<label class="inline-flex items-center gap-2 text-xs text-slate-300">
|
|
520
|
+
<input id="routine-requires-approval" type="checkbox" class="h-4 w-4 accent-slate-400" checked />
|
|
521
|
+
Require approval for external side effects
|
|
522
|
+
</label>
|
|
523
|
+
<label class="inline-flex items-center gap-2 text-xs text-slate-300">
|
|
524
|
+
<input id="routine-external-integrations" type="checkbox" class="h-4 w-4 accent-slate-400" />
|
|
525
|
+
Allow external integrations (MCP/connectors)
|
|
526
|
+
</label>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
529
|
+
<div class="mt-4 rounded-xl border border-slate-700/70 bg-slate-900/35 p-3">
|
|
530
|
+
<div class="mb-2 flex items-center justify-between gap-2">
|
|
531
|
+
<label class="inline-flex items-center gap-2 text-sm text-slate-200">
|
|
532
|
+
<input id="routine-use-file" type="checkbox" class="h-4 w-4 accent-slate-400" checked />
|
|
533
|
+
Save prompt as Markdown file (recommended)
|
|
534
|
+
</label>
|
|
535
|
+
<button id="save-routine-file" class="tcp-btn"><i data-lucide="save"></i> Save Prompt File</button>
|
|
536
|
+
</div>
|
|
537
|
+
<input id="routine-file-path" class="tcp-input mb-3 font-mono text-xs" value="control-panel/routines/new-routine.md" />
|
|
538
|
+
<textarea id="routine-prompt" class="tcp-input" rows="6" placeholder="Write your routine instructions in Markdown..."></textarea>
|
|
539
|
+
<div class="mt-2 text-xs text-slate-400">
|
|
540
|
+
Tip: keep goals, constraints, and output format in this file so you can improve it anytime without rewriting the routine.
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
<div class="mt-3 grid gap-2 md:grid-cols-[1fr_auto]">
|
|
544
|
+
<div class="text-xs text-slate-400">Create will use the selected schedule and entry prompt.</div>
|
|
545
|
+
<div class="flex items-center justify-end gap-2">
|
|
546
|
+
<button id="cancel-edit-routine" class="tcp-btn hidden">Cancel Edit</button>
|
|
547
|
+
<button id="create-routine" class="tcp-btn-primary"><i data-lucide="plus"></i> Create</button>
|
|
548
|
+
</div>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
<div class="agents-tab-panel${h("routines")}" data-agents-panel="routines">
|
|
552
|
+
<h3 class="tcp-title mb-3">Routines (${Y.length})</h3>
|
|
553
|
+
<div id="routine-list" class="tcp-list"></div>
|
|
554
|
+
</div>
|
|
555
|
+
<div class="agents-tab-panel${h("automations")}" data-agents-panel="automations">
|
|
556
|
+
<h3 class="tcp-title mb-3">Automations (${N.length})</h3>
|
|
557
|
+
${dn?'<p class="tcp-subtle mb-2">Automation endpoints currently mirror routine records in this workspace.</p>':""}
|
|
558
|
+
<div class="tcp-list">${zn}</div>
|
|
559
|
+
</div>
|
|
560
|
+
<div class="agents-tab-panel${h("automations")}" data-agents-panel="automations">
|
|
561
|
+
<h3 class="tcp-title mb-3">Automation Builder</h3>
|
|
562
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
563
|
+
<input id="automation-v2-name" class="tcp-input" placeholder="Automation name" />
|
|
564
|
+
<input id="automation-v2-description" class="tcp-input" placeholder="Description (optional)" />
|
|
565
|
+
</div>
|
|
566
|
+
<div class="mt-3 grid gap-3 md:grid-cols-3">
|
|
567
|
+
<select id="automation-v2-schedule-type" class="tcp-select">
|
|
568
|
+
<option value="manual">Manual</option>
|
|
569
|
+
<option value="interval">Interval</option>
|
|
570
|
+
<option value="cron">Cron</option>
|
|
571
|
+
</select>
|
|
572
|
+
<input id="automation-v2-interval-seconds" class="tcp-input" type="number" min="1" value="3600" placeholder="Interval seconds" />
|
|
573
|
+
<input id="automation-v2-cron" class="tcp-input" placeholder="Cron expression (UTC by default)" />
|
|
574
|
+
</div>
|
|
575
|
+
<div class="mt-3 grid gap-3 md:grid-cols-3">
|
|
576
|
+
<input id="automation-v2-timezone" class="tcp-input" value="UTC" />
|
|
577
|
+
<select id="automation-v2-misfire" class="tcp-select">
|
|
578
|
+
<option value="run_once">run_once</option>
|
|
579
|
+
<option value="skip">skip</option>
|
|
580
|
+
<option value="catch_up">catch_up</option>
|
|
581
|
+
</select>
|
|
582
|
+
<input id="automation-v2-agent-count" class="tcp-input" type="number" min="1" max="12" value="2" />
|
|
583
|
+
</div>
|
|
584
|
+
<div class="mt-3 grid gap-3 md:grid-cols-[1fr_auto]">
|
|
585
|
+
<select id="automation-v2-preset" class="tcp-select">
|
|
586
|
+
<option value="">Choose preset...</option>
|
|
587
|
+
<option value="github_bug_hunter">GitHub bug hunter</option>
|
|
588
|
+
<option value="code_generation_pipeline">Code generation pipeline</option>
|
|
589
|
+
<option value="release_notes_changelog">Release notes + changelog</option>
|
|
590
|
+
<option value="marketing_content_engine">Marketing content engine</option>
|
|
591
|
+
<option value="sales_lead_outreach">Sales lead outreach</option>
|
|
592
|
+
<option value="productivity_inbox_to_tasks">Productivity: inbox to tasks</option>
|
|
593
|
+
</select>
|
|
594
|
+
<button id="automation-v2-apply-preset" class="tcp-btn"><i data-lucide="sparkles"></i> Apply Preset</button>
|
|
595
|
+
</div>
|
|
596
|
+
<div class="mt-2 text-xs text-slate-400">Per-agent model routing: choose provider + model per agent. Defaults come from Settings. Use “Custom” only when needed.</div>
|
|
597
|
+
<div class="mt-3">
|
|
598
|
+
<button id="automation-v2-generate-agents" class="tcp-btn"><i data-lucide="users"></i> Generate Agent Rows</button>
|
|
599
|
+
</div>
|
|
600
|
+
<datalist id="automation-v2-skill-options">${ue.map(o=>`<option value="${r(o)}"></option>`).join("")}</datalist>
|
|
601
|
+
<datalist id="automation-v2-tool-options">${zt}</datalist>
|
|
602
|
+
<div id="automation-v2-agents-editor" class="mt-3 grid gap-2"></div>
|
|
603
|
+
<div class="mt-4">
|
|
604
|
+
<div class="mb-2 flex items-center justify-between">
|
|
605
|
+
<h4 class="text-sm font-semibold text-slate-200">Flow Nodes (DAG)</h4>
|
|
606
|
+
<button id="automation-v2-add-node" class="tcp-btn h-7 px-2 text-xs"><i data-lucide="plus"></i> Add Node</button>
|
|
607
|
+
</div>
|
|
608
|
+
<div id="automation-v2-nodes-editor" class="grid gap-2"></div>
|
|
609
|
+
</div>
|
|
610
|
+
<div class="mt-4 flex items-center justify-end gap-2">
|
|
611
|
+
<button id="automation-v2-create" class="tcp-btn-primary"><i data-lucide="save"></i> Create Automation</button>
|
|
612
|
+
</div>
|
|
613
|
+
</div>
|
|
614
|
+
<div class="agents-tab-panel${h("automations")}" data-agents-panel="automations">
|
|
615
|
+
<h3 class="tcp-title mb-3">Advanced Automations (${z.length})</h3>
|
|
616
|
+
<div class="tcp-list">${os}</div>
|
|
617
|
+
</div>
|
|
618
|
+
<div class="agents-tab-panel${h("automations")}" data-agents-panel="automations">
|
|
619
|
+
<h3 class="tcp-title mb-2">Automation Run Inspector</h3>
|
|
620
|
+
<div id="automation-v2-run-inspector" class="tcp-list">
|
|
621
|
+
<p class="tcp-subtle">Click an automation "Runs" button to inspect and control run state.</p>
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
<div class="agents-tab-panel${h("runs")}" data-agents-panel="runs">
|
|
625
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
626
|
+
<h3 class="tcp-title">Recent Runs (${gt.length})</h3>
|
|
627
|
+
<button id="refresh-runs" class="tcp-btn"><i data-lucide="refresh-cw"></i> Refresh</button>
|
|
628
|
+
</div>
|
|
629
|
+
<div class="tcp-list">${Ys}</div>
|
|
630
|
+
</div>
|
|
631
|
+
<div class="agents-tab-panel${h("runs")}" data-agents-panel="runs">
|
|
632
|
+
<h3 class="tcp-title mb-2">Run Inspector</h3>
|
|
633
|
+
<div id="run-inspector" class="tcp-list">
|
|
634
|
+
<p class="tcp-subtle">Pick any recent run and click Details to inspect status, full detail, and artifacts.</p>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
</div>
|
|
638
|
+
`,n("view").querySelectorAll("[data-agents-tab]").forEach(o=>o.addEventListener("click",()=>{const p=String(o.getAttribute("data-agents-tab")||"").trim().toLowerCase();l.includes(p)&&m({tab:p})})),n("agents-launch-wizard")?.addEventListener("click",()=>{m({wizard:!0,step:0})}),n("agents-open-settings-integrations")?.addEventListener("click",()=>{c("settings")}),n("agents-wizard-close")?.addEventListener("click",()=>{try{localStorage.setItem(d,"1")}catch{}m({wizard:!1})}),n("agents-wizard-prev")?.addEventListener("click",()=>{m({step:Math.max(0,we.step-1)})}),n("agents-wizard-next")?.addEventListener("click",()=>{if(we.step>=2){try{localStorage.setItem(d,"1")}catch{}m({wizard:!1,tab:"runs"});return}m({step:Math.min(2,we.step+1)})}),n("view").querySelectorAll("[data-wizard-flow]").forEach(o=>o.addEventListener("click",()=>{const p=String(o.getAttribute("data-wizard-flow")||"").trim().toLowerCase();m({flow:p==="routine"?"routine":"advanced"})})),n("agents-wizard-open-builder")?.addEventListener("click",()=>{m({tab:we.flow==="routine"?"routines":"automations",step:2})}),n("agents-wizard-open-runs")?.addEventListener("click",()=>{m({tab:"runs",step:2})});const S=n("routine-list");S.innerHTML=Y.map(o=>{const p=me(o),f=at.get(p),w=k(f),$=fe(f),L=J(T(f)),V=je(o),Q=String(o.status||"active").toLowerCase(),oe=ne(o,"allowed_tools","allowedTools"),ke=X(o,"requires_approval","requiresApproval",!0),Se=X(o,"external_integrations_allowed","externalIntegrationsAllowed",!1),Me=Q==="paused",Xe=E(w)&&!!$;return`
|
|
639
|
+
<div class="tcp-list-item flex items-center justify-between gap-3">
|
|
640
|
+
<div>
|
|
641
|
+
<div class="font-medium">${r(o.name||p||"Unnamed routine")}</div>
|
|
642
|
+
<div class="mt-1 flex items-center gap-2">
|
|
643
|
+
<span class="${Me?"tcp-badge-warn":"tcp-badge-info"}">${r(Q)}</span>
|
|
644
|
+
<span class="tcp-subtle font-mono">${r(Ee(o.schedule))}</span>
|
|
645
|
+
</div>
|
|
646
|
+
<div class="mt-1 text-xs text-slate-400 font-mono">${r(V||"default engine route")}</div>
|
|
647
|
+
<div class="mt-1 text-xs text-slate-400">
|
|
648
|
+
tools: ${r(oe.length?oe.join(", "):"all (no explicit allowlist)")}
|
|
649
|
+
</div>
|
|
650
|
+
<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
651
|
+
<span class="${ke?"tcp-badge-warn":"tcp-badge-info"}">${ke?"approval required":"no approval gate"}</span>
|
|
652
|
+
<span class="${Se?"tcp-badge-info":"tcp-badge-warn"}">${Se?"external integrations allowed":"external integrations blocked"}</span>
|
|
653
|
+
</div>
|
|
654
|
+
${f?`<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
655
|
+
<span class="${q(w)}">${r(w)}</span>
|
|
656
|
+
<span class="tcp-subtle">${r(K(M(f)))}</span>
|
|
657
|
+
<span class="tcp-subtle font-mono">${r($||"run n/a")}</span>
|
|
658
|
+
</div>
|
|
659
|
+
${L?`<div class="mt-1 text-xs text-slate-400">${r(L)}</div>`:""}`:'<div class="mt-1 text-xs text-slate-500">No runs yet.</div>'}
|
|
660
|
+
${ve(o)?`<div class="mt-1 text-xs text-slate-400 font-mono">${r(ve(o))}</div>`:""}
|
|
661
|
+
</div>
|
|
662
|
+
<div class="flex gap-2">
|
|
663
|
+
<button data-run="${r(p)}" class="tcp-btn"><i data-lucide="play"></i> Run</button>
|
|
664
|
+
${Xe?`<button data-run-review="approve" data-run-id="${r($)}" data-run-family="routine" class="tcp-btn">Approve</button>
|
|
665
|
+
<button data-run-review="deny" data-run-id="${r($)}" data-run-family="routine" class="tcp-btn-danger">Deny</button>`:""}
|
|
666
|
+
<button data-toggle-status="${r(p)}" data-next-status="${Me?"active":"paused"}" class="tcp-btn">
|
|
667
|
+
<i data-lucide="${Me?"play-circle":"pause-circle"}"></i> ${Me?"Resume":"Pause"}
|
|
668
|
+
</button>
|
|
669
|
+
<button data-edit-routine="${r(p)}" class="tcp-btn"><i data-lucide="pencil"></i> Edit</button>
|
|
670
|
+
${ve(o)?`<button data-edit-file="${r(ve(o))}" class="tcp-btn"><i data-lucide="folder-open"></i> Prompt File</button>`:""}
|
|
671
|
+
<button data-del="${r(p)}" class="tcp-btn-danger"><i data-lucide="trash-2"></i></button>
|
|
672
|
+
</div>
|
|
673
|
+
</div>`}).join("")||'<p class="tcp-subtle">No routines.</p>',a(S),n("refresh-runs").addEventListener("click",()=>{ft(e)});const H=n("run-inspector"),W=n("automation-v2-run-inspector"),Te=t.client?.automationsV2,He=!!Te;He||(W.innerHTML='<p class="tcp-subtle">Advanced automation client API is unavailable in this build.</p>');const Fe=async o=>{if(!He)throw new Error("Advanced automation API unavailable.");return o(Te)},Ue=['<option value="">Default from settings</option>',...Lt.map(o=>`<option value="${r(o)}">${r(o)}</option>`),'<option value="__custom__">Custom provider...</option>'].join(""),Ce=(o,p={})=>`
|
|
674
|
+
<div data-v2-agent-row="${o}" class="rounded-xl border border-slate-700/60 bg-slate-900/30 p-3">
|
|
675
|
+
<div class="mb-2 text-xs text-slate-300 font-semibold">Agent ${o+1}</div>
|
|
676
|
+
<div class="grid gap-2 md:grid-cols-2">
|
|
677
|
+
<input data-v2-agent-field="agent_id" data-v2-agent-index="${o}" class="tcp-input font-mono text-xs" value="${r(String(p.agent_id||`agent-${o+1}`))}" />
|
|
678
|
+
<input data-v2-agent-field="display_name" data-v2-agent-index="${o}" class="tcp-input" placeholder="Display name" value="${r(String(p.display_name||`Agent ${o+1}`))}" />
|
|
679
|
+
<select data-v2-agent-field="model_provider_select" data-v2-agent-index="${o}" class="tcp-select">${Ue}</select>
|
|
680
|
+
<input data-v2-agent-field="model_provider_custom" data-v2-agent-index="${o}" class="tcp-input" placeholder="Custom provider id (enabled when Custom provider selected)" value="${r(String(p.model_provider||""))}" />
|
|
681
|
+
<select data-v2-agent-field="model_id_select" data-v2-agent-index="${o}" class="tcp-select">
|
|
682
|
+
<option value="">Default model for provider</option>
|
|
683
|
+
<option value="__custom__">Custom model...</option>
|
|
684
|
+
</select>
|
|
685
|
+
<input data-v2-agent-field="model_id_custom" data-v2-agent-index="${o}" class="tcp-input" placeholder="Custom model id (enabled when Custom model selected)" value="${r(String(p.model_id||""))}" />
|
|
686
|
+
<input data-v2-agent-field="skills" data-v2-agent-index="${o}" class="tcp-input" list="automation-v2-skill-options" placeholder="Skills (text tags, comma-separated)" value="${r(String(Array.isArray(p.skills)?p.skills.join(", "):p.skills||""))}" />
|
|
687
|
+
<select data-v2-agent-field="tool_mode" data-v2-agent-index="${o}" class="tcp-select">
|
|
688
|
+
<option value="standard">Standard tools (recommended)</option>
|
|
689
|
+
<option value="read_only">Read-only tools</option>
|
|
690
|
+
<option value="custom">Custom allow/deny policy</option>
|
|
691
|
+
</select>
|
|
692
|
+
<div class="md:col-span-2 rounded-lg border border-slate-700/60 bg-slate-900/30 p-2">
|
|
693
|
+
<div class="mb-1 text-xs text-slate-400">Allowed MCP servers for this agent</div>
|
|
694
|
+
<div class="grid gap-2 sm:grid-cols-2">
|
|
695
|
+
${re.length?re.map(f=>{const w=Array.isArray(p.mcp_servers)&&p.mcp_servers.includes(f);return`<label class="inline-flex items-center gap-2 text-xs text-slate-300">
|
|
696
|
+
<input data-v2-agent-field="mcp_server_option" data-v2-agent-index="${o}" type="checkbox" value="${r(f)}" ${w?"checked":""} class="h-4 w-4 accent-slate-400" />
|
|
697
|
+
${r(f)}
|
|
698
|
+
</label>`}).join(""):'<span class="text-xs text-slate-500">No connected MCP servers found. Connect servers in MCP tab.</span>'}
|
|
699
|
+
</div>
|
|
700
|
+
</div>
|
|
701
|
+
<input data-v2-agent-field="allowlist" data-v2-agent-index="${o}" class="tcp-input md:col-span-2" list="automation-v2-tool-options" placeholder="Custom tool allowlist (comma-separated)" value="${r(String(Array.isArray(p.allowlist)?p.allowlist.join(", "):p.allowlist||""))}" />
|
|
702
|
+
<input data-v2-agent-field="denylist" data-v2-agent-index="${o}" class="tcp-input md:col-span-2" list="automation-v2-tool-options" placeholder="Custom tool denylist (comma-separated)" value="${r(String(Array.isArray(p.denylist)?p.denylist.join(", "):p.denylist||""))}" />
|
|
703
|
+
</div>
|
|
704
|
+
</div>
|
|
705
|
+
`,Tt=(o,p={})=>`
|
|
706
|
+
<div data-v2-node-row="${o}" class="rounded-xl border border-slate-700/60 bg-slate-900/30 p-3">
|
|
707
|
+
<div class="mb-2 text-xs text-slate-300 font-semibold">Node ${o+1}</div>
|
|
708
|
+
<div class="grid gap-2 md:grid-cols-2">
|
|
709
|
+
<input data-v2-node-field="node_id" data-v2-node-index="${o}" class="tcp-input font-mono text-xs" value="${r(String(p.node_id||`node-${o+1}`))}" />
|
|
710
|
+
<input data-v2-node-field="agent_id" data-v2-node-index="${o}" class="tcp-input font-mono text-xs" value="${r(String(p.agent_id||"agent-1"))}" />
|
|
711
|
+
<input data-v2-node-field="objective" data-v2-node-index="${o}" class="tcp-input md:col-span-2" placeholder="Node objective" value="${r(String(p.objective||""))}" />
|
|
712
|
+
<input data-v2-node-field="depends_on" data-v2-node-index="${o}" class="tcp-input md:col-span-2 font-mono text-xs" placeholder="depends_on csv (node-1,node-2)" value="${r(String(Array.isArray(p.depends_on)?p.depends_on.join(", "):p.depends_on||""))}" />
|
|
713
|
+
<input data-v2-node-field="timeout_ms" data-v2-node-index="${o}" class="tcp-input" type="number" min="0" placeholder="timeout ms" value="${r(String(p.timeout_ms||""))}" />
|
|
714
|
+
</div>
|
|
715
|
+
</div>
|
|
716
|
+
`,dt=o=>String(o||"").split(",").map(p=>p.trim()).filter(Boolean),Be=o=>{const p=n("view"),f=vt=>p.querySelector(`[data-v2-agent-index="${o}"][data-v2-agent-field="${vt}"]`),w=f("model_provider_select"),$=f("model_provider_custom"),L=f("model_id_select"),V=f("model_id_custom");if(!w||!$||!L||!V)return;const Q=w.value==="__custom__",oe=String(w.value||"").trim(),ke=Q?String($.value||"").trim():oe||Ot||"";$.disabled=!Q,$.classList.toggle("opacity-60",!Q);const Se=ke?$t(ke):[],Me=String(V.value||"").trim();L.innerHTML=['<option value="">Default model for provider</option>',...Se.map(vt=>`<option value="${r(vt)}">${r(vt)}</option>`),'<option value="__custom__">Custom model...</option>'].join("");const Xe=String(L.value||"").trim();!!Me&&Se.includes(Me)?L.value=Me:Me||Xe==="__custom__"?L.value="__custom__":L.value="";const Ne=L.value==="__custom__";V.disabled=!Ne,V.classList.toggle("opacity-60",!Ne)},Gt=()=>{const o=[...n("automation-v2-agents-editor").querySelectorAll("[data-v2-agent-row]")];for(const p of o){const f=String(p.getAttribute("data-v2-agent-index")||"").trim();if(!f)continue;const w=n("view"),$=qe=>w.querySelector(`[data-v2-agent-index="${f}"][data-v2-agent-field="${qe}"]`),L=$("model_provider_select"),V=$("model_provider_custom"),Q=$("model_id_select");$("model_id_custom");const oe=$("tool_mode"),ke=$("allowlist"),Se=$("denylist"),Me=dt(String(ke?.value||"")),Xe=dt(String(Se?.value||"")),mt=Me.length===1&&Me[0]==="read"&&!Xe.length;oe&&(oe.value=mt?"read_only":Me.length||Xe.length?"custom":"standard");const Ne=String(V?.value||"").trim();L&&(Ne&&Lt.includes(Ne)?L.value=Ne:Ne?L.value="__custom__":L.value=""),Be(f),L&&L.dataset.wired!=="1"&&(L.dataset.wired="1",L.addEventListener("change",()=>Be(f))),V&&V.dataset.wired!=="1"&&(V.dataset.wired="1",V.addEventListener("input",()=>Be(f))),Q&&Q.dataset.wired!=="1"&&(Q.dataset.wired="1",Q.addEventListener("change",()=>Be(f)));const vt=()=>{if(!oe||!ke||!Se)return;const We=String(oe.value||"standard")==="custom";ke.disabled=!We,Se.disabled=!We,ke.classList.toggle("opacity-60",!We),Se.classList.toggle("opacity-60",!We)};vt(),oe&&oe.dataset.wired!=="1"&&(oe.dataset.wired="1",oe.addEventListener("change",vt))}},Nt=()=>{const o=Math.max(1,Math.min(12,Number.parseInt(String(n("automation-v2-agent-count")?.value||"2"),10)||2));n("automation-v2-agents-editor").innerHTML=Array.from({length:o},(p,f)=>Ce(f)).join(""),Gt()},Wt=()=>{const o=n("automation-v2-nodes-editor"),p=o.querySelectorAll("[data-v2-node-row]").length;o.insertAdjacentHTML("beforeend",Tt(p))},Nn=(o=[],p=[])=>{const f=Array.isArray(o)&&o.length?o:[{agent_id:"agent-1"}];n("automation-v2-agent-count").value=String(Math.min(12,Math.max(1,f.length))),n("automation-v2-agents-editor").innerHTML=f.slice(0,12).map(($,L)=>Ce(L,$)).join(""),Gt();const w=Array.isArray(p)&&p.length?p:[{node_id:"node-1",agent_id:"agent-1"}];n("automation-v2-nodes-editor").innerHTML=w.map(($,L)=>Tt(L,$)).join("")},ds={github_bug_hunter:{name:"GitHub Bug Hunter",description:"Monitor issues, reproduce, patch, and verify fixes automatically.",schedule:{type:"interval",interval_seconds:3600,timezone:"UTC",misfire_policy:"run_once"},agents:[{agent_id:"triage",display_name:"Issue Triage",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",skills:["issue-triage"],mcp_servers:["github","composio"],allowlist:["read","mcp.github.*","mcp.composio.*"]},{agent_id:"fixer",display_name:"Fix Implementer",model_provider:"openrouter",model_id:"anthropic/claude-3.5-sonnet",skills:["coding"],mcp_servers:["github"],allowlist:["read","write","edit","bash","mcp.github.*"]},{agent_id:"qa",display_name:"Regression Tester",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",skills:["testing"],mcp_servers:["github"],allowlist:["read","bash","mcp.github.*"]}],nodes:[{node_id:"scan-issues",agent_id:"triage",objective:"Find high-signal open bugs and collect repro clues."},{node_id:"implement-fix",agent_id:"fixer",objective:"Implement minimal safe fix and prepare patch summary.",depends_on:["scan-issues"]},{node_id:"run-tests",agent_id:"qa",objective:"Run targeted checks and report verification status.",depends_on:["implement-fix"]}]},code_generation_pipeline:{name:"Code Generation Pipeline",description:"Draft implementation, refine quality, and validate quickly.",schedule:{type:"manual",timezone:"UTC",misfire_policy:"run_once"},agents:[{agent_id:"planner",display_name:"Planner",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read"]},{agent_id:"builder",display_name:"Builder",model_provider:"openrouter",model_id:"anthropic/claude-3.5-sonnet",allowlist:["read","write","edit","bash"]},{agent_id:"reviewer",display_name:"Reviewer",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read","bash"]}],nodes:[{node_id:"plan",agent_id:"planner",objective:"Produce implementation plan with acceptance criteria."},{node_id:"implement",agent_id:"builder",objective:"Generate and refine code changes from plan.",depends_on:["plan"]},{node_id:"validate",agent_id:"reviewer",objective:"Run checks/tests and summarize risks.",depends_on:["implement"]}]},release_notes_changelog:{name:"Release Notes + Changelog",description:"Collect changes and draft release comms.",schedule:{type:"cron",cron_expression:"0 15 * * 5",timezone:"UTC",misfire_policy:"run_once"},agents:[{agent_id:"collector",display_name:"Change Collector",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read","bash","mcp.github.*"],mcp_servers:["github"]},{agent_id:"writer",display_name:"Release Writer",model_provider:"openrouter",model_id:"anthropic/claude-3.5-sonnet",allowlist:["read","write","edit"]}],nodes:[{node_id:"collect",agent_id:"collector",objective:"Gather merged PRs/issues since last release."},{node_id:"draft",agent_id:"writer",objective:"Draft release notes and changelog sections.",depends_on:["collect"]}]},marketing_content_engine:{name:"Marketing Content Engine",description:"Generate campaign-ready social + email content from product updates.",schedule:{type:"interval",interval_seconds:86400,timezone:"UTC",misfire_policy:"run_once"},agents:[{agent_id:"research",display_name:"Trend Research",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["websearch","webfetch","read"]},{agent_id:"copy",display_name:"Copywriter",model_provider:"openrouter",model_id:"anthropic/claude-3.5-sonnet",allowlist:["read","write","edit"]},{agent_id:"editor",display_name:"Brand Editor",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read","edit"]}],nodes:[{node_id:"market-scan",agent_id:"research",objective:"Find relevant trends and competitor angles."},{node_id:"draft-assets",agent_id:"copy",objective:"Draft LinkedIn post, email blurb, and CTA variations.",depends_on:["market-scan"]},{node_id:"brand-check",agent_id:"editor",objective:"Align tone/style and produce final approved copy.",depends_on:["draft-assets"]}]},sales_lead_outreach:{name:"Sales Lead Outreach",description:"Enrich leads and generate personalized outreach drafts.",schedule:{type:"interval",interval_seconds:21600,timezone:"UTC",misfire_policy:"run_once"},agents:[{agent_id:"enrichment",display_name:"Lead Enrichment",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read","websearch","mcp.composio.*"],mcp_servers:["composio"]},{agent_id:"outreach",display_name:"Outreach Writer",model_provider:"openrouter",model_id:"anthropic/claude-3.5-sonnet",allowlist:["read","write","edit","mcp.composio.*"],mcp_servers:["composio"]}],nodes:[{node_id:"enrich-leads",agent_id:"enrichment",objective:"Enrich lead list with role/company context."},{node_id:"draft-outreach",agent_id:"outreach",objective:"Create personalized outreach drafts and follow-up options.",depends_on:["enrich-leads"]}]},productivity_inbox_to_tasks:{name:"Inbox to Tasks",description:"Convert inbound messages into prioritized action items and calendar-ready summaries.",schedule:{type:"interval",interval_seconds:1800,timezone:"UTC",misfire_policy:"run_once"},agents:[{agent_id:"classifier",display_name:"Inbox Classifier",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read","mcp.composio.*"],mcp_servers:["composio"]},{agent_id:"planner",display_name:"Task Planner",model_provider:"openrouter",model_id:"openai/gpt-4o-mini",allowlist:["read","write","edit","todo_write"]}],nodes:[{node_id:"classify",agent_id:"classifier",objective:"Classify inbox items into urgent, important, and informational."},{node_id:"task-plan",agent_id:"planner",objective:"Generate prioritized tasks with due windows and concise summaries.",depends_on:["classify"]}]}};Nt(),Wt(),n("view").querySelectorAll("[data-template-id]").forEach(o=>o.addEventListener("click",()=>{const p=String(o.getAttribute("data-template-id")||"").trim(),f=ds[p];if(!f){s("err","Preset not found.");return}n("automation-v2-preset").value=p,n("automation-v2-name").value=String(f.name||""),n("automation-v2-description").value=String(f.description||"");const w=f.schedule||{};n("automation-v2-schedule-type").value=String(w.type||"manual"),n("automation-v2-cron").value=String(w.cron_expression||""),n("automation-v2-interval-seconds").value=String(w.interval_seconds||3600),n("automation-v2-timezone").value=String(w.timezone||"UTC"),n("automation-v2-misfire").value=String(w.misfire_policy||"run_once"),Nn(f.agents||[],f.nodes||[]),m({tab:"automations",wizard:!0,flow:"advanced",step:1}),s("ok",`Template loaded: ${f.name}`)})),n("automation-v2-generate-agents")?.addEventListener("click",()=>{Nt(),s("ok","Agent rows regenerated.")}),n("automation-v2-add-node")?.addEventListener("click",()=>{Wt()}),n("automation-v2-apply-preset")?.addEventListener("click",()=>{const o=String(n("automation-v2-preset")?.value||"").trim();if(!o){s("err","Choose a preset first.");return}const p=ds[o];if(!p){s("err","Preset not found.");return}n("automation-v2-name").value=String(p.name||""),n("automation-v2-description").value=String(p.description||"");const f=p.schedule||{};n("automation-v2-schedule-type").value=String(f.type||"manual"),n("automation-v2-cron").value=String(f.cron_expression||""),n("automation-v2-interval-seconds").value=String(f.interval_seconds||3600),n("automation-v2-timezone").value=String(f.timezone||"UTC"),n("automation-v2-misfire").value=String(f.misfire_policy||"run_once"),Nn(p.agents||[],p.nodes||[]),s("ok",`Preset applied: ${p.name}`)}),n("automation-v2-create")?.addEventListener("click",async()=>{try{const o=String(n("automation-v2-name")?.value||"").trim();if(!o)throw new Error("Automation name is required.");const p=String(n("automation-v2-description")?.value||"").trim(),f=String(n("automation-v2-schedule-type")?.value||"manual").trim(),w=String(n("automation-v2-timezone")?.value||"UTC").trim()||"UTC",$=String(n("automation-v2-misfire")?.value||"run_once").trim(),L=String(n("automation-v2-cron")?.value||"").trim(),V=Number.parseInt(String(n("automation-v2-interval-seconds")?.value||"3600"),10);if(f==="cron"&&!L)throw new Error("Cron expression is required for cron schedule.");if(f==="interval"&&!(Number.isFinite(V)&&V>0))throw new Error("Interval seconds must be greater than 0.");const Q=[...n("automation-v2-agents-editor").querySelectorAll("[data-v2-agent-row]")],oe=new Set,ke=[];for(const Ne of Q){const vt=String(Ne.getAttribute("data-v2-agent-index")||""),qe=sr=>n("view").querySelector(`[data-v2-agent-index="${vt}"][data-v2-agent-field="${sr}"]`)?.value||"",We=String(qe("agent_id")).trim();if(!We)continue;if(oe.has(We))throw new Error(`Duplicate agent_id: ${We}`);oe.add(We);const Un=String(qe("model_provider_select")).trim(),vs=String(qe("model_provider_custom")).trim(),yn=String(qe("model_id_select")).trim(),tr=String(qe("model_id_custom")).trim(),gi=Un==="__custom__"?vs:Un||String(qe("model_provider")).trim(),vi=yn==="__custom__"?tr:yn||String(qe("model_id")).trim(),nr=String(qe("tool_mode")).trim()||"standard",Pc=[...n("view").querySelectorAll(`[data-v2-agent-index="${vt}"][data-v2-agent-field="mcp_server_option"]:checked`)].map(sr=>String(sr.value||"").trim()).filter(Boolean),Lc=nr==="custom"?dt(qe("allowlist")):nr==="read_only"?["read"]:[],Oc=nr==="custom"?dt(qe("denylist")):[];ke.push({agent_id:We,display_name:String(qe("display_name")).trim()||We,model_policy:gi&&vi?{default_model:{provider_id:gi,model_id:vi}}:void 0,skills:dt(qe("skills")),tool_policy:{allowlist:Lc,denylist:Oc},mcp_policy:{allowed_servers:Pc}})}if(!ke.length)throw new Error("At least one agent is required.");const Se=[...n("automation-v2-nodes-editor").querySelectorAll("[data-v2-node-row]")],Me=new Set,Xe=[];for(const Ne of Se){const vt=String(Ne.getAttribute("data-v2-node-index")||""),qe=tr=>n("view").querySelector(`[data-v2-node-index="${vt}"][data-v2-node-field="${tr}"]`)?.value||"",We=String(qe("node_id")).trim(),Un=String(qe("objective")).trim(),vs=String(qe("agent_id")).trim();if(!We||!Un||!vs)continue;if(Me.has(We))throw new Error(`Duplicate node_id: ${We}`);Me.add(We);const yn=Number.parseInt(String(qe("timeout_ms")).trim(),10);Xe.push({node_id:We,objective:Un,agent_id:vs,depends_on:dt(qe("depends_on")),timeout_ms:Number.isFinite(yn)&&yn>0?yn:void 0})}if(!Xe.length)throw new Error("At least one flow node is required.");const mt={name:o,description:p||void 0,status:"active",schedule:{type:f,cron_expression:f==="cron"?L:void 0,interval_seconds:f==="interval"?V:void 0,timezone:w,misfire_policy:$},agents:ke,flow:{nodes:Xe},execution:{max_parallel_agents:Math.min(ke.length,4)}};await Fe(Ne=>Ne.create(mt)),s("ok","Automation created."),ft(e)}catch(o){s("err",o instanceof Error?o.message:String(o))}});const Qs=async(o,p,f)=>{const w=String(p||"").toLowerCase()==="automation",$=String(f||"").toLowerCase()==="deny"?"deny":"approve";if(!o)throw new Error("Run ID is missing.");if($==="approve"){w?await t.client.automations.approveRun(o,"approved from control panel"):await t.client.routines.approveRun(o,"approved from control panel");return}w?await t.client.automations.denyRun(o,"denied from control panel"):await t.client.routines.denyRun(o,"denied from control panel")},us=o=>{o.querySelectorAll("[data-run-review]").forEach(p=>{p.dataset.wired!=="1"&&(p.dataset.wired="1",p.addEventListener("click",async()=>{const f=String(p.dataset.runId||"").trim(),w=String(p.dataset.runFamily||"routine").trim().toLowerCase(),$=String(p.dataset.runReview||"approve").trim().toLowerCase();if(!f){s("err","Run ID is missing.");return}const L=[...n("view").querySelectorAll("[data-run-review]")].filter(Q=>String(Q.dataset.runId||"").trim()===f&&String(Q.dataset.runFamily||"routine").trim().toLowerCase()===w),V=new Map;for(const Q of L)V.set(Q,Q.innerHTML),Q.disabled=!0,Q.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i>',a(Q);try{await Qs(f,w,$),s("ok",`${$==="deny"?"Denied":"Approved"} ${w} run ${f}.`),setTimeout(()=>{ft(e)},250)}catch(Q){s("err",Q instanceof Error?Q.message:String(Q));for(const oe of L)oe.isConnected&&(oe.disabled=!1,oe.innerHTML=V.get(oe)||oe.innerHTML,a(oe))}}))})};us(n("view")),n("view").querySelectorAll("[data-inspect-run]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.inspectRun||"").trim(),f=String(o.dataset.runFamily||"routine").trim();if(!p){s("err","Run ID is missing.");return}const w=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Loading',a(o);try{let $=await t.client.routines.getRun(p).catch(()=>null),L=await t.client.routines.listArtifacts(p).catch(()=>null);if(!$&&f==="automation"&&($=await t.client.automations.getRun(p).catch(()=>null),L=await t.client.automations.listArtifacts(p).catch(()=>null)),!$)throw new Error("Run details not found.");const V=Array.isArray(L?.artifacts)?L.artifacts:[],Q=ne($,"allowed_tools","allowedTools"),oe=k($),ke=X($,"requires_approval","requiresApproval",!0),Se=X($,"external_integrations_allowed","externalIntegrationsAllowed",!1);H.innerHTML=`
|
|
717
|
+
<div class="tcp-list-item">
|
|
718
|
+
<div class="mb-2 flex flex-wrap items-center gap-2">
|
|
719
|
+
<span class="${q(oe)}">${r(oe)}</span>
|
|
720
|
+
<span class="tcp-subtle font-mono">${r(p)}</span>
|
|
721
|
+
<span class="tcp-subtle">${r(K(M($)))}</span>
|
|
722
|
+
</div>
|
|
723
|
+
<div class="mb-2 text-xs text-slate-300">
|
|
724
|
+
${r(Q.length?`Allowlist (${Q.length}): ${Q.join(", ")}`:"No explicit allowlist: all tools are available subject to policy.")}
|
|
725
|
+
</div>
|
|
726
|
+
<div class="mb-2 flex flex-wrap items-center gap-2 text-xs">
|
|
727
|
+
<span class="${ke?"tcp-badge-warn":"tcp-badge-info"}">${ke?"approval required":"no approval gate"}</span>
|
|
728
|
+
<span class="${Se?"tcp-badge-info":"tcp-badge-warn"}">${Se?"external integrations allowed":"external integrations blocked"}</span>
|
|
729
|
+
</div>
|
|
730
|
+
${E(oe)?`<div class="mb-2 flex flex-wrap items-center gap-2 text-xs">
|
|
731
|
+
<button data-run-review="approve" data-run-id="${r(p)}" data-run-family="${r(f)}" class="tcp-btn h-7 px-2 text-xs">Approve</button>
|
|
732
|
+
<button data-run-review="deny" data-run-id="${r(p)}" data-run-family="${r(f)}" class="tcp-btn-danger h-7 px-2 text-xs">Deny</button>
|
|
733
|
+
</div>`:""}
|
|
734
|
+
<div class="mb-2 text-xs text-slate-300">${r(T($)||"No detail text available.")}</div>
|
|
735
|
+
<div class="mb-2 text-xs text-slate-400">Artifacts: ${V.length}</div>
|
|
736
|
+
${V.length?`<div class="mb-2 grid gap-1">${V.map(Me=>{const Xe=String(Me?.uri||"").trim(),mt=String(Me?.kind||"artifact"),Ne=String(Me?.label||mt).trim();return`<div class="text-xs text-slate-300"><span class="tcp-subtle">${r(mt)}</span> <span class="font-mono">${r(Ne)}</span> ${Xe?`<span class="tcp-subtle">${r(Xe)}</span>`:""}</div>`}).join("")}</div>`:""}
|
|
737
|
+
<details class="mt-2">
|
|
738
|
+
<summary class="cursor-pointer text-xs text-slate-400">Raw run payload</summary>
|
|
739
|
+
<pre class="tcp-code mt-2">${r(JSON.stringify($,null,2))}</pre>
|
|
740
|
+
</details>
|
|
741
|
+
</div>
|
|
742
|
+
`,us(H),a(H)}catch($){s("err",$ instanceof Error?$.message:String($))}finally{o.isConnected&&(o.disabled=!1,o.innerHTML=w,a(o))}})),n("view").querySelectorAll("[data-run-automation]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.runAutomation||"").trim();if(!p){s("err","Automation ID is missing. Refresh and try again.");return}const f=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Running...',a(o);try{const w=await t.client.automations.runNow(p),$=String(w?.runId||"").trim(),L=String(w?.status||"").trim(),V=[];$&&V.push(`run ${$}`),L&&V.push(`status ${L}`),s("ok",V.length?`Automation triggered (${V.join(", ")}). It should move from queued to running within ~1 second.`:"Automation triggered."),setTimeout(()=>{ft(e)},500)}catch(w){s("err",w instanceof Error?w.message:String(w))}finally{o.isConnected&&(o.disabled=!1,o.innerHTML=f,a(o))}})),n("view").querySelectorAll("[data-v2-run-now]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.v2RunNow||"").trim();if(!p)return;const f=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Running...',a(o);try{const w=await Fe(L=>L.runNow(p)),$=String(w?.run?.run_id||w?.run?.runId||"").trim();s("ok",$?`Automation triggered (run ${$}).`:"Automation triggered."),setTimeout(()=>ft(e),450)}catch(w){s("err",w instanceof Error?w.message:String(w))}finally{o.isConnected&&(o.disabled=!1,o.innerHTML=f,a(o))}})),n("view").querySelectorAll("[data-v2-toggle]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.v2Toggle||"").trim(),f=String(o.dataset.v2Next||"").trim().toLowerCase();if(!p)return;const w=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Saving...',a(o);try{f==="pause"?(await Fe($=>$.pause(p,"paused from control panel")),s("ok","Automation paused.")):(await Fe($=>$.resume(p)),s("ok","Automation resumed.")),setTimeout(()=>ft(e),300)}catch($){s("err",$ instanceof Error?$.message:String($))}finally{o.isConnected&&(o.disabled=!1,o.innerHTML=w,a(o))}})),n("view").querySelectorAll("[data-v2-runs]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.v2Runs||"").trim();if(!p)return;const f=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Loading',a(o);try{const w=await Fe(V=>V.listRuns(p,20)),$=Array.isArray(w?.runs)?w.runs:[],L=$.map(V=>{const Q=String(V?.run_id||V?.runId||"").trim(),oe=String(V?.status||"unknown").toLowerCase(),ke=Number(V?.updated_at_ms||V?.updatedAtMs||0);return`<div class="rounded-lg border border-slate-700/60 p-2">
|
|
743
|
+
<div class="flex items-center justify-between gap-2">
|
|
744
|
+
<span class="font-mono text-xs">${r(Q||"run n/a")}</span>
|
|
745
|
+
<span class="${q(oe)}">${r(oe)}</span>
|
|
746
|
+
</div>
|
|
747
|
+
<div class="mt-1 flex flex-wrap items-center gap-2 text-xs">
|
|
748
|
+
<span class="tcp-subtle">${r(K(ke))}</span>
|
|
749
|
+
${Q?`<button data-v2-run-action="pause" data-v2-run-id="${r(Q)}" class="tcp-btn h-7 px-2 text-xs">Pause</button>
|
|
750
|
+
<button data-v2-run-action="resume" data-v2-run-id="${r(Q)}" class="tcp-btn h-7 px-2 text-xs">Resume</button>
|
|
751
|
+
<button data-v2-run-action="cancel" data-v2-run-id="${r(Q)}" class="tcp-btn-danger h-7 px-2 text-xs">Cancel</button>`:""}
|
|
752
|
+
</div>
|
|
753
|
+
<details class="mt-1">
|
|
754
|
+
<summary class="cursor-pointer text-xs text-slate-400">Run payload</summary>
|
|
755
|
+
<pre class="tcp-code mt-1">${r(JSON.stringify(V,null,2))}</pre>
|
|
756
|
+
</details>
|
|
757
|
+
</div>`}).join("")||'<p class="tcp-subtle">No runs found for this automation.</p>';W.innerHTML=`<div class="tcp-list-item">
|
|
758
|
+
<div class="mb-2 flex items-center justify-between gap-2">
|
|
759
|
+
<span class="font-medium">Automation: ${r(p)}</span>
|
|
760
|
+
<span class="tcp-subtle">${$.length} runs</span>
|
|
761
|
+
</div>
|
|
762
|
+
<div class="grid gap-2">${L}</div>
|
|
763
|
+
</div>`,W.querySelectorAll("[data-v2-run-action]").forEach(V=>V.addEventListener("click",async()=>{const Q=String(V.dataset.v2RunAction||"").trim(),oe=String(V.dataset.v2RunId||"").trim();if(!oe)return;const ke=V.innerHTML;V.disabled=!0,V.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i>',a(V);try{Q==="pause"?await Fe(Se=>Se.pauseRun(oe,"paused from control panel")):Q==="resume"?await Fe(Se=>Se.resumeRun(oe,"resumed from control panel")):await Fe(Se=>Se.cancelRun(oe,"cancelled from control panel")),s("ok",`Run ${oe} ${Q} requested.`),setTimeout(()=>ft(e),300)}catch(Se){s("err",Se instanceof Error?Se.message:String(Se))}finally{V.isConnected&&(V.disabled=!1,V.innerHTML=ke,a(V))}})),a(W)}catch(w){s("err",w instanceof Error?w.message:String(w))}finally{o.isConnected&&(o.disabled=!1,o.innerHTML=f,a(o))}})),S.querySelectorAll("[data-toggle-status]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.toggleStatus||"").trim(),f=String(o.dataset.nextStatus||"").trim();if(!p||!f){s("err","Routine status action is missing details. Refresh and try again.");return}const w=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Saving...',a(o);try{await t.client.routines.update(p,{status:f}),s("ok",`Routine ${f==="paused"?"paused":"resumed"}.`),ft(e)}catch($){s("err",$ instanceof Error?$.message:String($)),o.isConnected&&(o.disabled=!1,o.innerHTML=w,a(o))}})),S.querySelectorAll("[data-run]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.run||"").trim();if(!p){s("err","Routine ID is missing. Refresh and try again.");return}const f=o.innerHTML;o.disabled=!0,o.innerHTML='<i data-lucide="refresh-cw" class="animate-spin"></i> Running...',a(o);try{const w=await t.client.routines.runNow(p),$=String(w?.runId||"").trim(),L=String(w?.status||"").trim(),V=[];$&&V.push(`run ${$}`),L&&V.push(`status ${L}`),s("ok",V.length?`Routine triggered (${V.join(", ")}). It should move from queued to running within ~1 second.`:"Routine triggered."),setTimeout(()=>{ft(e)},500)}catch(w){s("err",w instanceof Error?w.message:String(w))}finally{o.isConnected&&(o.disabled=!1,o.innerHTML=f,a(o))}})),S.querySelectorAll("[data-del]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.del||"").trim();if(!p){s("err","Routine ID is missing. Refresh and try again.");return}try{await t.client.routines.delete(p),s("ok","Routine deleted."),ft(e)}catch(f){s("err",f instanceof Error?f.message:String(f))}})),S.querySelectorAll("[data-edit-file]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.editFile||"").trim();if(p)try{const f=await i(`/api/files/read?path=${encodeURIComponent(p)}`);n("routine-use-file").checked=!0,n("routine-file-path").value=p,n("routine-prompt").value=String(f?.text||""),s("ok",`Loaded prompt file: ${p}`)}catch(f){s("err",f instanceof Error?f.message:String(f))}})),S.querySelectorAll("[data-edit-routine]").forEach(o=>o.addEventListener("click",async()=>{const p=String(o.dataset.editRoutine||"").trim();if(!p){s("err","Routine ID is missing.");return}const f=Ie.get(p);if(!f){s("err","Routine details not found. Refresh and try again.");return}he.value=String(f.name||"").trim(),Ac(f.schedule);const w=ve(f);if(w){ge.checked=!0,Je.value=w;try{const L=await i(`/api/files/read?path=${encodeURIComponent(w)}`);Ze.value=String(L?.text||"")}catch{Ze.value=String(f.entrypoint||""),s("err",`Could not read ${w}; loaded entrypoint text instead.`)}}else ge.checked=!1,Ze.value=String(f.entrypoint||f.prompt||""),fs();nt.value=ne(f,"allowed_tools","allowedTools").join(", "),_t.checked=X(f,"requires_approval","requiresApproval",!0),kt.checked=X(f,"external_integrations_allowed","externalIntegrationsAllowed",!1);const $=Tc($e(nt.value||""),!!_t.checked,!!kt.checked);er($,{restore:!1}),gs(),Ic(f),Cc(p,String(f.name||"")),he.focus()})),a(n("view"));const ut=n("routine-schedule-mode"),fn=n("routine-interval-controls"),Dn=n("routine-daily-controls"),Yt=n("routine-weekly-controls"),jn=n("routine-cron-controls"),Ct=n("routine-interval-value"),Xt=n("routine-interval-unit"),hn=n("routine-time"),Qt=n("routine-weekday"),gn=n("routine-weekly-time"),Dt=n("routine-cron"),B=n("routine-schedule-preview"),he=n("routine-name"),ge=n("routine-use-file"),Ze=n("routine-prompt"),Je=n("routine-file-path"),St=n("routine-model-provider"),ze=n("routine-model-id"),Ke=n("routine-model-preview"),Ge=n("routine-allow-everything"),nt=n("routine-allowed-tools"),vn=n("routine-tool-scope-preview"),_t=n("routine-requires-approval"),kt=n("routine-external-integrations"),ps=n("routine-form-mode"),qn=n("cancel-edit-routine"),ms=n("create-routine");let Fn="";const fs=()=>{const o=`control-panel/routines/${ce(he.value||"new-routine")}.md`,f=String(Je.value||"").trim().replace(/\\/g,"/").replace(/^\/+/,"")||o,w=f==="control-panel"||f.startsWith("control-panel/")?f:`control-panel/${f}`;Je.value=w.endsWith(".md")?w:`${w}.md`},Ec=o=>{const p=$t(o);if(!p.length)return"";const f=String(is[o]||"").trim();return f&&p.includes(f)?f:p[0]},hs=()=>{const o=String(St?.value||"").trim(),p=$t(o);if(!ze)return;if(ze.innerHTML=p.map($=>`<option value="${r($)}">${r($)}</option>`).join("")||'<option value="">No models found</option>',!p.length){ze.disabled=!0,Ke&&(Ke.textContent="default engine route");return}ze.disabled=!1;const f=Ec(o);f&&(ze.value=f);const w=String(ze.value||"").trim();Ke&&(Ke.textContent=o&&w?`${o}/${w}`:"default engine route")},gs=()=>{const o=$e(nt?.value||"");if(vn){if(Ge?.checked){vn.textContent="Tool scope: unrestricted (all tools + external integrations, no approval gate)";return}vn.textContent=o.length?`Tool scope: allowlist (${o.length})`:"Tool scope: all tools allowed by policy"}},Tc=(o,p,f)=>!p&&f&&o.length===0,er=(o,{restore:p=!0}={})=>{Ge&&(Ge.checked=!!o,o?(Ge.dataset.prevTools=String(nt?.value||""),Ge.dataset.prevRequiresApproval=_t?.checked?"1":"0",Ge.dataset.prevExternalIntegrations=kt?.checked?"1":"0",nt&&(nt.value="",nt.disabled=!0),_t&&(_t.checked=!1,_t.disabled=!0),kt&&(kt.checked=!0,kt.disabled=!0)):(nt&&(nt.disabled=!1),_t&&(_t.disabled=!1),kt&&(kt.disabled=!1),p&&(nt&&(nt.value=String(Ge.dataset.prevTools||"")),_t&&(_t.checked=String(Ge.dataset.prevRequiresApproval||"1")==="1"),kt&&(kt.checked=String(Ge.dataset.prevExternalIntegrations||"0")==="1"))),gs())},Ac=o=>{const p=Number(o?.interval_seconds?.seconds??o?.intervalSeconds?.seconds??o?.intervalSeconds??0),f=String(o?.cron?.expression??o?.cron?.cron??o?.expression??o?.cron??"").trim();if(p>0){p%3600===0?(ut.value="interval",Xt.value="hours",Ct.value=String(Math.max(1,Math.floor(p/3600)))):(ut.value="interval",Xt.value="minutes",Ct.value=String(Math.max(1,Math.floor(p/60)))),pt();return}if(!f){ut.value="manual",pt();return}const w=f.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+\*$/);if(w){ut.value="daily";const L=String(Number.parseInt(w[1],10)).padStart(2,"0"),V=String(Number.parseInt(w[2],10)).padStart(2,"0");hn.value=`${V}:${L}`,pt();return}const $=f.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+([0-6])$/);if($){ut.value="weekly";const L=String(Number.parseInt($[1],10)).padStart(2,"0"),V=String(Number.parseInt($[2],10)).padStart(2,"0");Qt.value=String(Number.parseInt($[3],10)),gn.value=`${V}:${L}`,pt();return}ut.value="customCron",Dt.value=f,pt()},Ic=o=>{const p=String(o?.args?.model_policy?.default_model?.provider_id||"").trim(),f=String(o?.args?.model_policy?.default_model?.model_id||"").trim();if(!p||!Lt.includes(p)){hs();return}St.value=p,hs();const w=$t(p);f&&w.includes(f)&&(ze.value=f,Ke&&(Ke.textContent=`${p}/${f}`))},Cc=(o,p="")=>{Fn=o,ps&&(ps.textContent=`Editing routine ${p||o}`),ms&&(ms.innerHTML='<i data-lucide="save"></i> Save Changes'),qn&&qn.classList.remove("hidden"),a(n("view"))},Mc=()=>{Fn="",ps&&(ps.textContent="Creating new routine"),ms&&(ms.innerHTML='<i data-lucide="plus"></i> Create'),qn&&qn.classList.add("hidden"),a(n("view"))},fi=()=>{const o=String(ut.value||"interval");if(o==="interval"){const f=Number.parseInt(String(Ct.value||"30"),10),w=Number.isFinite(f)?f:30;if(w<=0)throw new Error("Interval must be at least 1.");const L=String(Xt.value||"minutes")==="hours"?3600:60;return{interval_seconds:{seconds:w*L}}}if(o==="manual")return{interval_seconds:{seconds:24*3600}};if(o==="daily"){const[f,w]=String(hn.value||"09:00").split(":").map(V=>Number.parseInt(V,10)),$=Number.isFinite(f)?Math.min(23,Math.max(0,f)):9;return{cron:{expression:`${Number.isFinite(w)?Math.min(59,Math.max(0,w)):0} ${$} * * *`}}}if(o==="weekly"){const[f,w]=String(gn.value||"09:00").split(":").map(oe=>Number.parseInt(oe,10)),$=Number.isFinite(f)?Math.min(23,Math.max(0,f)):9,L=Number.isFinite(w)?Math.min(59,Math.max(0,w)):0,V=Number.parseInt(String(Qt.value||"1"),10),Q=Number.isFinite(V)?Math.min(6,Math.max(0,V)):1;return{cron:{expression:`${L} ${$} * * ${Q}`}}}const p=String(Dt.value||"").trim();if(!p)throw new Error("Custom cron is required.");return{cron:{expression:p}}},Rc=()=>{const o=String(ut.value||"interval");if(o==="interval"){const f=Number.parseInt(String(Ct.value||"30"),10),w=String(Xt.value||"minutes");return`every ${Number.isFinite(f)&&f>0?f:30}${w==="hours"?"h":"m"}`}if(o==="daily")return`daily at ${String(hn.value||"09:00")}`;if(o==="weekly"){const f={0:"Sunday",1:"Monday",2:"Tuesday",3:"Wednesday",4:"Thursday",5:"Friday",6:"Saturday"},w=Number.parseInt(String(Qt.value||"1"),10);return`weekly on ${f[w]||"Monday"} at ${String(gn.value||"09:00")}`}if(o==="manual")return"manual";const p=String(Dt.value||"").trim();return p?`cron ${p}`:"custom cron (required)"},pt=()=>{const o=String(ut.value||"interval"),p=o==="interval",f=o==="daily",w=o==="weekly",$=o==="customCron";fn.classList.toggle("hidden",!p),Dn.classList.toggle("hidden",!f),Yt.classList.toggle("hidden",!w),jn.classList.toggle("hidden",!$),Dt.classList.toggle("hidden",!$);try{const L=fi();B.textContent=`Schedule: ${Rc()} (${Ee(L)})`}catch(L){B.textContent=`Schedule: ${L instanceof Error?L.message:String(L)}`}},hi=async()=>{fs();const o=String(Je.value||"").trim(),p=String(Ze.value||"");if(!o||!p.trim())throw new Error("Prompt file path and content are required.");return await i("/api/files/write",{method:"POST",body:JSON.stringify({path:o,text:p,overwrite:!0})}),o};n("save-routine-file").addEventListener("click",async()=>{try{const o=await hi();s("ok",`Saved ${o}`)}catch(o){s("err",o instanceof Error?o.message:String(o))}}),he.addEventListener("input",()=>{const o=String(Je.value||"").trim();(!o||/new-routine\.md$/i.test(o))&&fs()}),ut.addEventListener("change",pt),Ct.addEventListener("input",pt),Xt.addEventListener("change",pt),hn.addEventListener("input",pt),Qt.addEventListener("change",pt),gn.addEventListener("input",pt),Dt.addEventListener("input",pt),St?.addEventListener("change",()=>{hs()}),ze?.addEventListener("change",()=>{const o=String(St?.value||"").trim(),p=String(ze?.value||"").trim();Ke&&(Ke.textContent=o&&p?`${o}/${p}`:"default engine route")}),Ge?.addEventListener("change",()=>{er(!!Ge.checked,{restore:!0})}),nt?.addEventListener("input",gs),qn?.addEventListener("click",()=>{ft(e)}),pt(),fs(),hs(),er(!!Ge?.checked,{restore:!1}),gs(),Mc(),n("create-routine").addEventListener("click",async()=>{try{const o=String(he.value||"").trim(),p=String(Ze.value||"").trim();if(!o||!p)throw new Error("Name and prompt are required.");const f=fi(),w=String(ut.value||"")==="manual";let $=p,L="";ge.checked&&(L=await hi(),$=[`Use the routine prompt markdown at: ${L}`,"Read the file first, then execute its instructions exactly."].join(`
|
|
764
|
+
`));const V={};L&&(V.promptFilePath=L);const Q=String(St?.value||"").trim(),oe=String(ze?.value||"").trim();Q&&oe&&(V.model_policy={default_model:{provider_id:Q,model_id:oe}});const ke=!!Ge?.checked,Se=ke?[]:$e(nt?.value||""),Me=ke?!1:!!_t?.checked,Xe=ke?!0:!!kt?.checked;if(Fn){const mt=Ie.get(Fn),Ne={name:o,entrypoint:$,schedule:f,args:V,allowed_tools:Se,requires_approval:Me,external_integrations_allowed:Xe};w?Ne.status="paused":mt?.status&&(Ne.status=String(mt.status).toLowerCase()),await t.client.routines.update(Fn,Ne),s("ok","Routine updated.")}else{const mt=await t.client.routines.create({name:o,entrypoint:$,schedule:f,args:V,allowed_tools:Se,requires_approval:Me,external_integrations_allowed:Xe});if(w){const Ne=me(mt?.routine||mt||{});Ne&&await t.client.routines.update(Ne,{status:"paused"})}s("ok","Routine created.")}ft(e)}catch(o){s("err",o instanceof Error?o.message:String(o))}})}async function Ds(e){const{state:t,byId:n,toast:s,escapeHtml:r,api:i,setRoute:a}=e,c=e?.embeddedInSettings===!0,[l,d]=await Promise.all([t.client.channels.status().catch(()=>({})),t.client.channels.config().catch(()=>({}))]),u=["telegram","discord","slack"],m=(g,C,O,P=void 0)=>!g||typeof g!="object"?P:g[C]!==void 0?g[C]:g[O]!==void 0?g[O]:P,_=g=>Array.isArray(g)&&g.length?g.join(", "):"*",b=!!m(d.discord||{},"has_token","hasToken",!1),x=c?"":`
|
|
765
|
+
<div class="tcp-card">
|
|
766
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
767
|
+
<div>
|
|
768
|
+
<h3 class="tcp-title">Moved To Settings</h3>
|
|
769
|
+
<p class="tcp-subtle">Channels is now managed under Settings.</p>
|
|
770
|
+
</div>
|
|
771
|
+
<button id="channels-open-settings" class="tcp-btn"><i data-lucide="settings"></i> Open Settings</button>
|
|
772
|
+
</div>
|
|
773
|
+
</div>`;n("view").innerHTML=`
|
|
774
|
+
${x}
|
|
775
|
+
<div class="tcp-card">
|
|
776
|
+
<div class="mb-3 flex items-center justify-between">
|
|
777
|
+
<h3 class="tcp-title">Channels</h3>
|
|
778
|
+
<i data-lucide="messages-square"></i>
|
|
779
|
+
</div>
|
|
780
|
+
${b?"":`<div class="mb-3 rounded-lg border border-amber-500/30 bg-amber-500/10 p-3 text-sm text-amber-100">
|
|
781
|
+
<div class="font-semibold">Discord Quick Setup</div>
|
|
782
|
+
<div class="mt-1">1) Create bot and copy token. 2) Enable Message Content Intent. 3) Invite bot with channel send/read permissions. 4) Save then click Verify Discord.</div>
|
|
783
|
+
</div>`}
|
|
784
|
+
<div id="channels-list" class="tcp-list"></div>
|
|
785
|
+
</div>
|
|
786
|
+
`,c||n("channels-open-settings")?.addEventListener("click",()=>a("settings"));const y=n("channels-list");y.innerHTML=u.map(g=>{const C=l[g]||{},O=m(C,"last_error","lastError","");return`
|
|
787
|
+
<div class="tcp-list-item">
|
|
788
|
+
<div class="mb-3 flex items-center justify-between">
|
|
789
|
+
<strong class="capitalize">${g}</strong>
|
|
790
|
+
<span class="${C.connected?"tcp-badge-ok":"tcp-badge-warn"}">${C.connected?"connected":"not connected"}</span>
|
|
791
|
+
</div>
|
|
792
|
+
<div class="grid gap-3 lg:grid-cols-4">
|
|
793
|
+
<input id="${g}-token" class="tcp-input" placeholder="bot token" />
|
|
794
|
+
<input id="${g}-users" class="tcp-input" placeholder="allowed users (comma, * for all)" />
|
|
795
|
+
${g==="discord"?`<input id="${g}-guild" class="tcp-input" placeholder="guild id (optional)" />`:g==="slack"?`<input id="${g}-channel" class="tcp-input" placeholder="channel id (required for slack)" />`:`<select id="${g}-style" class="tcp-select">
|
|
796
|
+
<option value="default">style: default</option>
|
|
797
|
+
<option value="compact">style: compact</option>
|
|
798
|
+
<option value="friendly">style: friendly</option>
|
|
799
|
+
<option value="ops">style: ops</option>
|
|
800
|
+
</select>`}
|
|
801
|
+
<div class="flex gap-2">
|
|
802
|
+
<button class="tcp-btn-primary" data-save="${g}"><i data-lucide="save"></i> Save</button>
|
|
803
|
+
${g==="discord"?`<button class="tcp-btn" data-verify="${g}">Verify Discord</button>`:""}
|
|
804
|
+
<button class="tcp-btn-danger" data-del="${g}"><i data-lucide="trash-2"></i></button>
|
|
805
|
+
</div>
|
|
806
|
+
</div>
|
|
807
|
+
<div class="mt-2 flex flex-wrap items-center gap-3 text-xs text-slate-400">
|
|
808
|
+
${g==="telegram"||g==="discord"?`<label class="inline-flex items-center gap-2"><input id="${g}-mention" type="checkbox" /> mention only</label>`:""}
|
|
809
|
+
${g==="discord"?"<span>Tip: use <code>@bot /help</code> style commands (Discord app slash commands are not registered).</span>":""}
|
|
810
|
+
</div>
|
|
811
|
+
${g==="discord"?`<div id="${g}-verify-result" class="mt-2 text-xs text-slate-300"></div>`:""}
|
|
812
|
+
${O?`<div class="mt-2 text-xs text-rose-300">last error: ${r(String(O))}</div>`:""}
|
|
813
|
+
</div>
|
|
814
|
+
`}).join(""),u.forEach(g=>{const C=d[g]||{},O=m(C,"allowed_users","allowedUsers",["*"]),P=!!m(C,"mention_only","mentionOnly",g==="discord"),j=m(C,"guild_id","guildId",""),Y=m(C,"channel_id","channelId",""),N=String(m(C,"style_profile","styleProfile","default")||"default"),z=!!m(C,"has_token","hasToken",!1),D=n(`${g}-token`);D&&z&&(D.placeholder="token configured (leave blank to keep)");const R=n(`${g}-users`);R&&(R.value=_(O));const Z=n(`${g}-mention`);Z&&(Z.checked=P);const le=n(`${g}-guild`);le&&(le.value=j||"");const ee=n(`${g}-channel`);ee&&(ee.value=Y||"");const U=n(`${g}-style`);U&&(U.value=N)});const I=g=>{const C=n(`${g}-token`).value.trim(),O=n(`${g}-users`).value.trim(),P={bot_token:C,allowed_users:O?O.split(",").map(j=>j.trim()).filter(Boolean):["*"]};return(g==="telegram"||g==="discord")&&(P.mention_only=!!n(`${g}-mention`)?.checked),g==="telegram"&&(P.style_profile=String(n(`${g}-style`)?.value||"default")),g==="discord"&&(P.guild_id=n(`${g}-guild`)?.value?.trim()||null),g==="slack"&&(P.channel_id=n(`${g}-channel`)?.value?.trim()||null),P};y.querySelectorAll("[data-save]").forEach(g=>g.addEventListener("click",async()=>{const C=g.dataset.save,O=I(C);try{await t.client.channels.put(C,O),s("ok",`${C} saved.`),Ds(e)}catch(P){s("err",P instanceof Error?P.message:String(P))}})),y.querySelectorAll("[data-verify]").forEach(g=>g.addEventListener("click",async()=>{const C=g.dataset.verify,O=n(`${C}-verify-result`);O&&(O.className="mt-2 text-xs text-slate-300",O.textContent="Verifying Discord configuration...");try{const P=await i(`/api/engine/channels/${encodeURIComponent(C)}/verify`,{method:"POST",body:JSON.stringify(I(C))}),j=m(P,"checks","checks",{}),Y=m(P,"hints","hints",[]),N=!!m(P,"ok","ok",!1),z=!!m(j,"token_auth_ok","tokenAuthOk",!1),D=!!m(j,"gateway_ok","gatewayOk",!1),R=!!m(j,"message_content_intent_ok","messageContentIntentOk",!1),Z=Array.isArray(Y)&&Y.length>0?String(Y[0]):"",le=N?"Verification passed: token/auth, gateway, and Message Content intent are OK.":`Verification failed: token=${z?"ok":"fail"}, gateway=${D?"ok":"fail"}, message_intent=${R?"ok":"fail"}. ${Z}`;O&&(O.className=`mt-2 text-xs ${N?"text-emerald-300":"text-amber-200"}`,O.innerHTML=r(le)),s(N?"ok":"warn",N?"Discord verify passed.":"Discord verify failed.")}catch(P){const j=P instanceof Error?P.message:String(P);O&&(O.className="mt-2 text-xs text-rose-300",O.textContent=`Verify request failed: ${j}`),s("err",j)}})),y.querySelectorAll("[data-del]").forEach(g=>g.addEventListener("click",async()=>{const C=g.dataset.del;try{await t.client.channels.delete(C),s("ok",`${C} deleted.`),Ds(e)}catch(O){s("err",O instanceof Error?O.message:String(O))}}))}function ci(e){try{return new URL(e)}catch{return null}}function Cr(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")||"mcp-server"}function ha(e){const t=ci(e);if(!t)return"";const n=String(t.hostname||"").toLowerCase();if(!n)return"";if(n.endsWith("composio.dev"))return"composio";const s=n.split(".").filter(Boolean);if(s.length===0)return"";const r=["backend","api","mcp","www"].includes(s[0])&&s[1]||s[0];return Cr(r)}function li(e){const t=ci(e);return t?String(t.hostname||"").toLowerCase().endsWith("composio.dev"):!1}function ur(e,t=""){if(!e||typeof e!="object")return null;const n=e,s=String(n.name||t||"").trim();return s?{name:s,transport:String(n.transport||"").trim(),connected:!!n.connected,enabled:n.enabled!==!1,lastError:String(n.last_error||n.lastError||"").trim(),headers:n.headers&&typeof n.headers=="object"?n.headers:{},toolCache:Array.isArray(n.tool_cache||n.toolCache)?n.tool_cache||n.toolCache:[]}:null}function ga(e){return Array.isArray(e)?e.map(t=>ur(t)).filter(Boolean).sort((t,n)=>t.name.localeCompare(n.name)):!e||typeof e!="object"?[]:Array.isArray(e.servers)?e.servers.map(t=>ur(t)).filter(Boolean).sort((t,n)=>t.name.localeCompare(n.name)):Object.entries(e).map(([t,n])=>ur(n&&typeof n=="object"?n:{transport:String(n||"")},t)).filter(Boolean).sort((t,n)=>t.name.localeCompare(n.name))}function ov(e){return Array.isArray(e)?e.map(t=>typeof t=="string"?t:!t||typeof t!="object"?"":String(t.namespaced_name||t.namespacedName||t.id||t.tool_name||t.toolName||"").trim()).filter(Boolean):[]}function cv(e){const t=e&&typeof e=="object"?e:{},n=Array.isArray(t.servers)?t.servers:[];return{generatedAt:String(t.generated_at||"").trim(),count:Number.isFinite(Number(t.count))?Number(t.count):n.length,servers:n.map(s=>!s||typeof s!="object"?null:{slug:String(s.slug||"").trim(),name:String(s.name||s.slug||"").trim(),description:String(s.description||"").trim(),transportUrl:String(s.transport_url||"").trim(),serverConfigName:String(s.server_config_name||s.slug||"").trim(),documentationUrl:String(s.documentation_url||"").trim(),directoryUrl:String(s.directory_url||"").trim(),toolCount:Number.isFinite(Number(s.tool_count))?Number(s.tool_count):0,requiresAuth:s.requires_auth!==!1,requiresSetup:!!s.requires_setup}).filter(s=>s&&s.slug&&s.transportUrl).sort((s,r)=>s.name.localeCompare(r.name))}}function lv(e,t,n,s){return!!!String(t||"").trim()||e==="none"?"No auth header will be sent.":e==="custom"?n?`Header preview: ${n}: <token>`:"Set a custom header name.":e==="x-api-key"?"Header preview: x-api-key: <token>":e==="bearer"?"Header preview: Authorization: Bearer <token>":li(s)?"Auto mode: detected Composio URL -> x-api-key":"Auto mode: using Authorization Bearer token"}function dv({authMode:e,token:t,customHeader:n,transport:s}){const r=String(t||"").trim();if(!r||e==="none")return{};if(e==="custom"){const a=String(n||"").trim();if(!a)throw new Error("Custom header name is required.");return{[a]:r}}return e==="x-api-key"?{"x-api-key":r}:e==="bearer"?{Authorization:`Bearer ${r.replace(/^bearer\s+/i,"").trim()}`}:li(s)?{"x-api-key":r}:{Authorization:`Bearer ${r.replace(/^bearer\s+/i,"").trim()}`}}async function en(e){const{state:t,byId:n,api:s,toast:r,escapeHtml:i,setRoute:a}=e,c=e?.embeddedInSettings===!0,[l,d,u]=await Promise.all([t.client.mcp.list().catch(()=>({})),t.client.mcp.listTools().catch(()=>[]),s("/api/engine/mcp/catalog",{method:"GET"}).catch(()=>null)]),m=ga(l),_=ov(d),b=cv(u?.catalog||null),x=U=>String(U||"").split(",").map(se=>se.trim()).filter(Boolean),y=c?"":`
|
|
815
|
+
<div class="tcp-card">
|
|
816
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
817
|
+
<div>
|
|
818
|
+
<h3 class="tcp-title">Moved To Settings</h3>
|
|
819
|
+
<p class="tcp-subtle">MCP connection management is now organized under Settings.</p>
|
|
820
|
+
</div>
|
|
821
|
+
<button id="mcp-open-settings" class="tcp-btn"><i data-lucide="settings"></i> Open Settings</button>
|
|
822
|
+
</div>
|
|
823
|
+
</div>`;n("view").innerHTML=`
|
|
824
|
+
${y}
|
|
825
|
+
<div class="grid gap-4 xl:grid-cols-[440px_1fr]">
|
|
826
|
+
<div class="tcp-card">
|
|
827
|
+
<h3 class="tcp-title mb-2">Add MCP Server</h3>
|
|
828
|
+
<p class="tcp-subtle mb-3">Paste your MCP endpoint URL and token. For Composio URLs, Auto auth uses <code>x-api-key</code>.</p>
|
|
829
|
+
<div class="grid gap-3">
|
|
830
|
+
<div>
|
|
831
|
+
<label class="mb-1 block text-sm text-slate-300">Name</label>
|
|
832
|
+
<input id="mcp-name" class="tcp-input" placeholder="composio" value="composio" />
|
|
833
|
+
</div>
|
|
834
|
+
<div>
|
|
835
|
+
<label class="mb-1 block text-sm text-slate-300">Transport URL</label>
|
|
836
|
+
<input id="mcp-transport" class="tcp-input" placeholder="https://backend.composio.dev/.../mcp?user_id=..." />
|
|
837
|
+
</div>
|
|
838
|
+
<div>
|
|
839
|
+
<label class="mb-1 block text-sm text-slate-300">Auth Mode</label>
|
|
840
|
+
<select id="mcp-auth-mode" class="tcp-select">
|
|
841
|
+
<option value="auto" selected>Auto (Composio => x-api-key, else Bearer)</option>
|
|
842
|
+
<option value="x-api-key">x-api-key</option>
|
|
843
|
+
<option value="bearer">Authorization Bearer</option>
|
|
844
|
+
<option value="custom">Custom Header</option>
|
|
845
|
+
<option value="none">No Auth Header</option>
|
|
846
|
+
</select>
|
|
847
|
+
</div>
|
|
848
|
+
<div id="mcp-custom-header-wrap" class="hidden">
|
|
849
|
+
<label class="mb-1 block text-sm text-slate-300">Custom Header Name</label>
|
|
850
|
+
<input id="mcp-custom-header" class="tcp-input" placeholder="X-My-Token" />
|
|
851
|
+
</div>
|
|
852
|
+
<div>
|
|
853
|
+
<label class="mb-1 block text-sm text-slate-300">Token (optional)</label>
|
|
854
|
+
<input id="mcp-token" class="tcp-input" type="password" placeholder="token" />
|
|
855
|
+
</div>
|
|
856
|
+
<p id="mcp-auth-preview" class="tcp-subtle"></p>
|
|
857
|
+
<button id="mcp-add" class="tcp-btn-primary"><i data-lucide="plug-zap"></i> Add + Connect</button>
|
|
858
|
+
</div>
|
|
859
|
+
</div>
|
|
860
|
+
|
|
861
|
+
<div class="grid gap-4">
|
|
862
|
+
<div class="tcp-card">
|
|
863
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
864
|
+
<h3 class="tcp-title">Servers (${m.length})</h3>
|
|
865
|
+
<button id="mcp-refresh-all" class="tcp-btn"><i data-lucide="refresh-cw"></i> Reload</button>
|
|
866
|
+
</div>
|
|
867
|
+
<div id="mcp-servers" class="tcp-list"></div>
|
|
868
|
+
</div>
|
|
869
|
+
|
|
870
|
+
<div class="tcp-card">
|
|
871
|
+
<h3 class="tcp-title mb-3">Discovered MCP Tools (${_.length})</h3>
|
|
872
|
+
<pre class="tcp-code max-h-[320px] overflow-auto">${i(_.slice(0,350).join(`
|
|
873
|
+
`))||"No tools discovered yet. Connect a server first."}</pre>
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<div class="tcp-card">
|
|
877
|
+
<h3 class="tcp-title mb-2">Capability Readiness Check</h3>
|
|
878
|
+
<p class="tcp-subtle mb-3">Validate required capability IDs before creating or running automation templates.</p>
|
|
879
|
+
<div class="grid gap-2 md:grid-cols-[1fr_auto]">
|
|
880
|
+
<input id="mcp-readiness-required" class="tcp-input" placeholder="required capabilities csv (e.g. github.list_issues,github.create_pull_request)" />
|
|
881
|
+
<button id="mcp-readiness-check" class="tcp-btn"><i data-lucide="shield-check"></i> Check</button>
|
|
882
|
+
</div>
|
|
883
|
+
<pre id="mcp-readiness-result" class="tcp-code mt-3 max-h-[260px] overflow-auto">No readiness check yet.</pre>
|
|
884
|
+
</div>
|
|
885
|
+
|
|
886
|
+
<div class="tcp-card">
|
|
887
|
+
<div class="mb-2 flex flex-wrap items-center justify-between gap-2">
|
|
888
|
+
<h3 class="tcp-title">Remote MCP Packs (${b.count})</h3>
|
|
889
|
+
<span class="tcp-subtle text-xs">${i(b.generatedAt?`generated ${b.generatedAt}`:"catalog unavailable")}</span>
|
|
890
|
+
</div>
|
|
891
|
+
<p class="tcp-subtle mb-3">Anthropic remote MCP examples exported as per-server TOML packs. Use Apply to prefill transport/name.</p>
|
|
892
|
+
<div class="mb-3 grid gap-2 md:grid-cols-[1fr_auto]">
|
|
893
|
+
<input id="mcp-catalog-search" class="tcp-input" placeholder="Search pack name, slug, or URL" />
|
|
894
|
+
<button id="mcp-catalog-refresh" class="tcp-btn"><i data-lucide="refresh-cw"></i> Refresh</button>
|
|
895
|
+
</div>
|
|
896
|
+
<div id="mcp-catalog-list" class="grid gap-2"></div>
|
|
897
|
+
</div>
|
|
898
|
+
</div>
|
|
899
|
+
</div>
|
|
900
|
+
`,c||n("mcp-open-settings")?.addEventListener("click",()=>a("settings"));const I=n("mcp-name"),g=n("mcp-transport"),C=n("mcp-token"),O=n("mcp-auth-mode"),P=n("mcp-custom-header-wrap"),j=n("mcp-custom-header"),Y=n("mcp-auth-preview"),N=()=>{const U=O.value;P.classList.toggle("hidden",U!=="custom"),Y.textContent=lv(U,C.value,j.value,g.value)},z=()=>{const U=String(I.value||"").trim();if(!U||U==="composio"||U==="mcp-server"){const se=ha(g.value.trim());se&&(I.value=se)}};g.addEventListener("input",()=>{z(),N()}),C.addEventListener("input",N),O.addEventListener("change",N),j.addEventListener("input",N),N(),n("mcp-add").addEventListener("click",async()=>{const U=String(g.value||"").trim(),se=Cr(I.value||ha(U)),re=String(O.value||"auto"),ue=C.value,ce=j.value;if(!U)return r("err","Transport URL is required.");if(!ci(U)&&!U.startsWith("stdio:"))return r("err","Transport must be a valid URL or stdio:* transport.");try{const Ee=dv({authMode:re,token:ue,customHeader:ce,transport:U}),ve={name:se,transport:U,enabled:!0};if(Object.keys(Ee).length&&(ve.headers=Ee),await t.client.mcp.add(ve),!(await t.client.mcp.connect(se))?.ok){const X=ga(await t.client.mcp.list().catch(()=>({}))).find(de=>de.name===se),$e=X?.lastError?` ${X.lastError}`:"",me=li(U)&&/401|403|unauthorized|forbidden|invalid api key|api key/i.test($e)?" Composio usually expects `x-api-key` and a valid `user_id` query param.":"";throw new Error(`Unable to connect MCP server "${se}".${$e}${me}`)}r("ok",`MCP "${se}" connected.`),await en(e)}catch(Ee){r("err",Ee instanceof Error?Ee.message:String(Ee)),await en(e)}}),n("mcp-refresh-all").addEventListener("click",()=>{en(e)}),n("mcp-readiness-check")?.addEventListener("click",async()=>{try{const U=x(n("mcp-readiness-required")?.value);if(!U.length){r("err","Enter at least one required capability.");return}const se=t.client?.capabilities?.readiness?await t.client.capabilities.readiness({workflow_id:"control-panel-readiness",required_capabilities:U}):await s("/api/engine/capabilities/readiness",{method:"POST",body:JSON.stringify({workflow_id:"control-panel-readiness",required_capabilities:U})});n("mcp-readiness-result").textContent=JSON.stringify(se?.readiness||se,null,2);const re=!!(se?.readiness||se)?.runnable;r("ok",re?"Ready":"Not ready")}catch(U){r("err",U instanceof Error?U.message:String(U))}});const D=n("mcp-catalog-list"),R=n("mcp-catalog-search"),Z=n("mcp-catalog-refresh"),le=()=>{const U=String(R?.value||"").trim().toLowerCase(),se=b.servers.filter(re=>U?re.name.toLowerCase().includes(U)||re.slug.toLowerCase().includes(U)||re.transportUrl.toLowerCase().includes(U):!0).slice(0,80);if(!se.length){D.innerHTML='<p class="tcp-subtle">No catalog entries match your search.</p>';return}D.innerHTML=se.map(re=>`
|
|
901
|
+
<div class="tcp-list-item grid gap-2">
|
|
902
|
+
<div class="flex flex-wrap items-start justify-between gap-2">
|
|
903
|
+
<div>
|
|
904
|
+
<div class="font-semibold">${i(re.name)}</div>
|
|
905
|
+
<div class="tcp-subtle text-xs">${i(re.slug)}${re.requiresSetup?" · setup required":""}</div>
|
|
906
|
+
</div>
|
|
907
|
+
<div class="flex flex-wrap gap-2">
|
|
908
|
+
<span class="tcp-badge-info">Tools: ${re.toolCount}</span>
|
|
909
|
+
<span class="${re.requiresAuth?"tcp-badge-warn":"tcp-badge-ok"}">${re.requiresAuth?"Auth":"Authless"}</span>
|
|
910
|
+
</div>
|
|
911
|
+
</div>
|
|
912
|
+
<div class="tcp-subtle text-xs break-all">${i(re.transportUrl)}</div>
|
|
913
|
+
${re.description?`<div class="text-xs text-slate-200">${i(re.description)}</div>`:""}
|
|
914
|
+
<div class="flex flex-wrap gap-2">
|
|
915
|
+
<button class="tcp-btn" data-catalog-apply="${i(re.slug)}">Apply</button>
|
|
916
|
+
<a class="tcp-btn" href="/api/engine/mcp/catalog/${encodeURIComponent(re.slug)}/toml" target="_blank" rel="noreferrer">Open TOML</a>
|
|
917
|
+
${re.documentationUrl?`<a class="tcp-btn" href="${i(re.documentationUrl)}" target="_blank" rel="noreferrer">Docs</a>`:""}
|
|
918
|
+
</div>
|
|
919
|
+
</div>
|
|
920
|
+
`).join(""),D.querySelectorAll("[data-catalog-apply]").forEach(re=>{re.addEventListener("click",()=>{const ue=String(re.getAttribute("data-catalog-apply")||"").trim(),ce=b.servers.find(Ee=>Ee.slug===ue);ce&&(I.value=Cr(ce.serverConfigName||ce.slug||ce.name),g.value=ce.transportUrl,z(),N(),r("ok",`Loaded pack ${ce.name}. Add + Connect when ready.`))})})};R?.addEventListener("input",le),Z?.addEventListener("click",()=>{en(e)}),le();const ee=n("mcp-servers");ee.innerHTML=m.map(U=>{const se=Object.keys(U.headers||{}).filter(Boolean),re=Array.isArray(U.toolCache)?U.toolCache.length:0;return`
|
|
921
|
+
<div class="tcp-list-item grid gap-2">
|
|
922
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
923
|
+
<div>
|
|
924
|
+
<div class="font-semibold">${i(U.name)}</div>
|
|
925
|
+
<div class="tcp-subtle">${i(U.transport||"No transport set")}</div>
|
|
926
|
+
</div>
|
|
927
|
+
<div class="flex flex-wrap gap-2">
|
|
928
|
+
<span class="${U.connected?"tcp-badge-ok":"tcp-badge-warn"}">${U.connected?"Connected":"Disconnected"}</span>
|
|
929
|
+
<span class="${U.enabled?"tcp-badge-info":"tcp-badge-warn"}">${U.enabled?"Enabled":"Disabled"}</span>
|
|
930
|
+
<span class="tcp-badge-info">Tools: ${re}</span>
|
|
931
|
+
</div>
|
|
932
|
+
</div>
|
|
933
|
+
${U.lastError?`<div class="rounded-xl border border-rose-700/60 bg-rose-950/20 px-2 py-1 text-xs text-rose-300">${i(U.lastError)}</div>`:""}
|
|
934
|
+
${se.length?`<div class="tcp-subtle text-xs">Auth headers: ${i(se.join(", "))}</div>`:'<div class="tcp-subtle text-xs">No stored auth headers.</div>'}
|
|
935
|
+
<div class="flex flex-wrap gap-2">
|
|
936
|
+
<button class="tcp-btn" data-action="${U.connected?"disconnect":"connect"}" data-name="${encodeURIComponent(U.name)}">
|
|
937
|
+
${U.connected?"Disconnect":"Connect"}
|
|
938
|
+
</button>
|
|
939
|
+
<button class="tcp-btn" data-action="refresh" data-name="${encodeURIComponent(U.name)}">Refresh</button>
|
|
940
|
+
<button class="tcp-btn" data-action="toggle-enabled" data-name="${encodeURIComponent(U.name)}" data-enabled="${U.enabled?"1":"0"}">
|
|
941
|
+
${U.enabled?"Disable":"Enable"}
|
|
942
|
+
</button>
|
|
943
|
+
<button class="tcp-btn-danger" data-action="delete" data-name="${encodeURIComponent(U.name)}">Delete</button>
|
|
944
|
+
</div>
|
|
945
|
+
</div>
|
|
946
|
+
`}).join("")||'<p class="tcp-subtle">No MCP servers configured.</p>',ee.querySelectorAll("button[data-action]").forEach(U=>{U.addEventListener("click",async()=>{const se=String(U.dataset.action||""),re=String(U.dataset.name||""),ue=re?decodeURIComponent(re):"";if(ue)try{if(se==="connect")await t.client.mcp.connect(ue),r("ok",`Connected ${ue}.`);else if(se==="disconnect")await t.client.mcp.disconnect(ue),r("ok",`Disconnected ${ue}.`);else if(se==="refresh")await t.client.mcp.refresh(ue),r("ok",`Refreshed ${ue}.`);else if(se==="toggle-enabled"){const ce=String(U.dataset.enabled||"0")==="1";await t.client.mcp.setEnabled(ue,!ce),r("ok",`${ce?"Disabled":"Enabled"} ${ue}.`)}else se==="delete"&&(await s(`/api/engine/mcp/${encodeURIComponent(ue)}`,{method:"DELETE"}),r("ok",`Deleted ${ue}.`));await en(e)}catch(ce){r("err",ce instanceof Error?ce.message:String(ce))}})})}async function cc(e){const{byId:t,state:n,toast:s,renderIcons:r,escapeHtml:i,api:a,setRoute:c}=e,l=e?.embeddedInSettings===!0,d=k=>{const T=String(k||"").toLowerCase();return T==="official"?"tcp-badge-info":T==="verified"?"tcp-badge-warn":"tcp-badge-err"},u=k=>Array.isArray(k)?k:[],m={list:()=>n.client?.packs?.list?n.client.packs.list():a("/api/engine/packs",{method:"GET"}),inspect:k=>n.client?.packs?.inspect?n.client.packs.inspect(k):a(`/api/engine/packs/${encodeURIComponent(k)}`,{method:"GET"}),install:k=>n.client?.packs?.install?n.client.packs.install(k):a("/api/engine/packs/install",{method:"POST",body:JSON.stringify(k)}),uninstall:k=>n.client?.packs?.uninstall?n.client.packs.uninstall(k):a("/api/engine/packs/uninstall",{method:"POST",body:JSON.stringify(k)}),export:k=>n.client?.packs?.export?n.client.packs.export(k):a("/api/engine/packs/export",{method:"POST",body:JSON.stringify(k)}),updates:k=>n.client?.packs?.updates?n.client.packs.updates(k):a(`/api/engine/packs/${encodeURIComponent(k)}/updates`,{method:"GET"}),update:(k,T)=>n.client?.packs?.update?n.client.packs.update(k,T):a(`/api/engine/packs/${encodeURIComponent(k)}/update`,{method:"POST",body:JSON.stringify(T||{})})},_={discovery:()=>n.client?.capabilities?.discovery?n.client.capabilities.discovery():a("/api/engine/capabilities/discovery",{method:"GET"}),readiness:k=>n.client?.capabilities?.readiness?n.client.capabilities.readiness(k):a("/api/engine/capabilities/readiness",{method:"POST",body:JSON.stringify(k||{})})},b=k=>String(k||"").split(",").map(T=>T.trim()).filter(T=>T.length>0),x=k=>[...new Set(u(k).map(T=>String(T||"").trim()).filter(Boolean))],y=t("view"),I=l?"":`
|
|
947
|
+
<div class="tcp-card mb-4">
|
|
948
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
949
|
+
<div>
|
|
950
|
+
<h3 class="tcp-title">Moved To Settings</h3>
|
|
951
|
+
<p class="tcp-subtle">Pack management now lives under Settings.</p>
|
|
952
|
+
</div>
|
|
953
|
+
<button id="packs-open-settings" class="tcp-btn"><i data-lucide="settings"></i> Open Settings</button>
|
|
954
|
+
</div>
|
|
955
|
+
</div>`;y.innerHTML=`
|
|
956
|
+
${I}
|
|
957
|
+
<div class="tcp-card mb-4">
|
|
958
|
+
<h3 class="tcp-title mb-2">Pack Library</h3>
|
|
959
|
+
<p class="tcp-subtle mb-3">Install, inspect, export, and remove Tandem Packs.</p>
|
|
960
|
+
<div class="grid gap-2 md:grid-cols-3">
|
|
961
|
+
<input id="packs-install-url" class="tcp-input" placeholder="Install from URL (https://...zip)" />
|
|
962
|
+
<input id="packs-install-path" class="tcp-input" placeholder="Install from server path (/path/to/pack.zip)" />
|
|
963
|
+
<button id="packs-install-btn" class="tcp-btn-primary"><i data-lucide="download"></i> Install</button>
|
|
964
|
+
</div>
|
|
965
|
+
<div class="mt-3 flex flex-wrap gap-2">
|
|
966
|
+
<button id="packs-refresh-btn" class="tcp-btn"><i data-lucide="refresh-cw"></i> Refresh</button>
|
|
967
|
+
<button id="packs-cap-discovery-btn" class="tcp-btn"><i data-lucide="binary"></i> Capability Discovery</button>
|
|
968
|
+
</div>
|
|
969
|
+
<div id="packs-inspect-summary" class="mt-3 hidden rounded-xl border border-slate-800 bg-slate-950/70 p-3 text-xs text-slate-200"></div>
|
|
970
|
+
<pre id="packs-meta" class="mt-3 rounded-xl border border-slate-800 bg-slate-950/70 p-3 text-xs text-slate-300 hidden"></pre>
|
|
971
|
+
</div>
|
|
972
|
+
|
|
973
|
+
<div id="packs-list" class="grid gap-3"></div>
|
|
974
|
+
|
|
975
|
+
<div class="tcp-card mt-4">
|
|
976
|
+
<div class="mb-2 flex items-center justify-between gap-2">
|
|
977
|
+
<h3 class="tcp-title">Skill Module Library</h3>
|
|
978
|
+
<button id="presets-refresh-btn" class="tcp-btn"><i data-lucide="refresh-cw"></i> Refresh</button>
|
|
979
|
+
</div>
|
|
980
|
+
<div class="grid gap-2 md:grid-cols-3">
|
|
981
|
+
<input id="presets-filter-text" class="tcp-input" placeholder="Filter by id/tag/layer" />
|
|
982
|
+
<input id="presets-filter-publisher" class="tcp-input" placeholder="Publisher filter" />
|
|
983
|
+
<input id="presets-filter-capability" class="tcp-input" placeholder="Required capability filter" />
|
|
984
|
+
</div>
|
|
985
|
+
<div id="presets-skill-list" class="mt-3 grid gap-2"></div>
|
|
986
|
+
</div>
|
|
987
|
+
|
|
988
|
+
<div class="tcp-card mt-4">
|
|
989
|
+
<h3 class="tcp-title mb-2">Agent Preset Builder</h3>
|
|
990
|
+
<p class="tcp-subtle mb-3">Create from a preset or compose from modules, preview prompt deterministically, and save/fork override.</p>
|
|
991
|
+
<div class="grid gap-2 md:grid-cols-3">
|
|
992
|
+
<select id="agent-builder-source" class="tcp-input"></select>
|
|
993
|
+
<input id="agent-builder-fork-id" class="tcp-input" placeholder="Fork target id (optional)" />
|
|
994
|
+
<button id="agent-builder-fork-btn" class="tcp-btn"><i data-lucide="copy-plus"></i> Fork Selected Preset</button>
|
|
995
|
+
</div>
|
|
996
|
+
<div class="mt-2 grid gap-2 md:grid-cols-2">
|
|
997
|
+
<div>
|
|
998
|
+
<label class="tcp-subtle block text-xs mb-1">Skill modules (multi-select)</label>
|
|
999
|
+
<select id="agent-builder-modules" class="tcp-input h-36" multiple></select>
|
|
1000
|
+
</div>
|
|
1001
|
+
<div>
|
|
1002
|
+
<label class="tcp-subtle block text-xs mb-1">Base prompt</label>
|
|
1003
|
+
<textarea id="agent-builder-base" class="tcp-input h-36" placeholder="You are a pragmatic coding agent..."></textarea>
|
|
1004
|
+
</div>
|
|
1005
|
+
</div>
|
|
1006
|
+
<div class="mt-2 grid gap-2 md:grid-cols-2">
|
|
1007
|
+
<input id="agent-builder-required" class="tcp-input" placeholder="Additional required capabilities (csv)" />
|
|
1008
|
+
<input id="agent-builder-optional" class="tcp-input" placeholder="Additional optional capabilities (csv)" />
|
|
1009
|
+
</div>
|
|
1010
|
+
<div class="mt-2">
|
|
1011
|
+
<label class="tcp-subtle block text-xs mb-1">Extra fragments JSON (optional array of {id,phase,content})</label>
|
|
1012
|
+
<textarea id="agent-builder-fragments" class="tcp-input h-28" placeholder='[{"id":"tone.ops","phase":"style","content":"Be concise and operational."}]'></textarea>
|
|
1013
|
+
</div>
|
|
1014
|
+
<div class="mt-3 flex flex-wrap gap-2">
|
|
1015
|
+
<button id="agent-builder-preview-btn" class="tcp-btn"><i data-lucide="sparkles"></i> Compose Preview</button>
|
|
1016
|
+
<button id="agent-builder-summary-btn" class="tcp-btn"><i data-lucide="shield-check"></i> Capability Summary</button>
|
|
1017
|
+
<button id="agent-builder-save-btn" class="tcp-btn-primary"><i data-lucide="save"></i> Save Override</button>
|
|
1018
|
+
</div>
|
|
1019
|
+
<pre id="agent-builder-preview" class="mt-3 hidden rounded-xl border border-slate-800 bg-slate-950/70 p-3 text-xs text-slate-200"></pre>
|
|
1020
|
+
<pre id="agent-builder-summary" class="mt-2 hidden rounded-xl border border-slate-800 bg-slate-950/70 p-3 text-xs text-slate-200"></pre>
|
|
1021
|
+
</div>
|
|
1022
|
+
|
|
1023
|
+
<div class="tcp-card mt-4">
|
|
1024
|
+
<h3 class="tcp-title mb-2">Automation Preset Builder</h3>
|
|
1025
|
+
<p class="tcp-subtle mb-3">Start from automation preset, bind steps to agents, and compute merged automation capabilities.</p>
|
|
1026
|
+
<div class="grid gap-2 md:grid-cols-3">
|
|
1027
|
+
<select id="automation-builder-source" class="tcp-input"></select>
|
|
1028
|
+
<input id="automation-builder-id" class="tcp-input" placeholder="Override id (required to save)" />
|
|
1029
|
+
<button id="automation-builder-add-task" class="tcp-btn"><i data-lucide="plus"></i> Add Step</button>
|
|
1030
|
+
</div>
|
|
1031
|
+
<div id="automation-builder-tasks" class="mt-3 grid gap-2"></div>
|
|
1032
|
+
<div class="mt-3 flex flex-wrap gap-2">
|
|
1033
|
+
<button id="automation-builder-summary-btn" class="tcp-btn"><i data-lucide="shield-check"></i> Capability Summary</button>
|
|
1034
|
+
<button id="automation-builder-save-btn" class="tcp-btn-primary"><i data-lucide="save"></i> Save Override</button>
|
|
1035
|
+
</div>
|
|
1036
|
+
<pre id="automation-builder-summary" class="mt-3 hidden rounded-xl border border-slate-800 bg-slate-950/70 p-3 text-xs text-slate-200"></pre>
|
|
1037
|
+
</div>
|
|
1038
|
+
`;const g=t("packs-list"),C=t("packs-meta"),O=t("packs-inspect-summary"),P=t("presets-skill-list"),j=t("agent-builder-preview"),Y=t("agent-builder-summary"),N=t("automation-builder-summary"),z=t("automation-builder-tasks");let D=null,R=[];const Z=()=>u(D?.skill_modules),le=()=>u(D?.agent_presets),ee=()=>u(D?.automation_presets),U=k=>le().find(T=>String(T?.id||"")===String(k||"")),se=k=>ee().find(T=>String(T?.id||"")===String(k||"")),re=(k,T)=>{if(k){if(!T){k.classList.add("hidden"),k.textContent="";return}k.classList.remove("hidden"),k.textContent=typeof T=="string"?T:JSON.stringify(T,null,2)}},ue=async(k,T,M=[])=>{const K=await _.readiness({workflow_id:k,required_capabilities:x(T),optional_capabilities:x(M)}),J=K?.readiness||K||{};if(J?.runnable)return J;const q=u(J?.blocking_issues).map(ie=>String(ie?.message||ie?.code||"").trim()).filter(Boolean),E=q.length?q.join(" | "):"Capability readiness failed. Connect/refresh MCP servers and verify bindings.";throw new Error(E)},ce=()=>{const k=t("agent-builder-modules");return u(k?.selectedOptions).map(T=>String(T?.value||"")).filter(Boolean)},Ee=()=>x(ce().flatMap(k=>{const T=Z().find(M=>String(M?.id||"")===k);return u(T?.required_capabilities)})),ve=()=>{const k=x([...Ee(),...b(t("agent-builder-required")?.value)]),M=x(b(t("agent-builder-optional")?.value)).filter(K=>!k.includes(K));return{required:k,optional:M}},je=()=>{const k=String(t("agent-builder-fragments")?.value||"").trim();if(!k)return[];const T=JSON.parse(k);if(!Array.isArray(T))throw new Error("Extra fragments JSON must be an array.");return T.map(M=>({id:String(M?.id||"").trim(),phase:String(M?.phase||"").trim()||"domain",content:String(M?.content||"").trim()})).filter(M=>M.id&&M.content)},ne=()=>[...ce().map(T=>({id:`skill.${T}`,phase:"domain",content:`Enable skill module ${T}.`})),...je()],X=()=>{const k=le().map(T=>`<option value="${i(String(T?.id||""))}">${i(String(T?.id||""))}</option>`).join("");if(!R.length){z.innerHTML='<p class="tcp-subtle">No steps yet. Click "Add Step" to add task-agent bindings.</p>';return}z.innerHTML=R.map((T,M)=>{const K=i(T.id||`step_${M+1}`),J=i((T.required||[]).join(", ")),q=i((T.optional||[]).join(", "));return i(String(T.agent_id||"")),`
|
|
1039
|
+
<div class="rounded-xl border border-slate-800 bg-slate-950/60 p-3" data-task-row="${M}">
|
|
1040
|
+
<div class="grid gap-2 md:grid-cols-5">
|
|
1041
|
+
<input class="tcp-input" data-field="id" value="${K}" placeholder="step id" />
|
|
1042
|
+
<select class="tcp-input" data-field="agent_id">
|
|
1043
|
+
<option value="">(none)</option>
|
|
1044
|
+
${k}
|
|
1045
|
+
</select>
|
|
1046
|
+
<input class="tcp-input" data-field="required" value="${J}" placeholder="required caps csv" />
|
|
1047
|
+
<input class="tcp-input" data-field="optional" value="${q}" placeholder="optional caps csv" />
|
|
1048
|
+
<button class="tcp-btn" data-remove-row="${M}"><i data-lucide="trash-2"></i> Remove</button>
|
|
1049
|
+
</div>
|
|
1050
|
+
</div>
|
|
1051
|
+
`}).join(""),z.querySelectorAll("[data-task-row]").forEach(T=>{const M=Number(T.getAttribute("data-task-row")),K=T.querySelector('select[data-field="agent_id"]');K&&R[M]&&(K.value=String(R[M].agent_id||"")),T.querySelectorAll("input,select").forEach(J=>{J.addEventListener("input",()=>{const q=String(J.getAttribute("data-field")||"").trim();if(!q||!R[M])return;const E=String(J.value||"");q==="required"||q==="optional"?R[M][q]=b(E):R[M][q]=E.trim()})})}),z.querySelectorAll("[data-remove-row]").forEach(T=>{T.addEventListener("click",()=>{const M=Number(T.getAttribute("data-remove-row"));R=R.filter((K,J)=>J!==M),X(),r()})}),r()},$e=()=>{const k=t("agent-builder-source"),T=t("agent-builder-modules"),M=t("automation-builder-source"),K=le(),J=ee(),q=Z();k.innerHTML=['<option value="">Select source agent preset</option>',...K.map(E=>`<option value="${i(String(E?.id||""))}">${i(String(E?.id||""))} (${i(String(E?.layer||"unknown"))})</option>`)].join(""),T.innerHTML=q.map(E=>`<option value="${i(String(E?.id||""))}">${i(String(E?.id||""))} (${i(String(E?.layer||"unknown"))})</option>`).join(""),M.innerHTML=['<option value="">Select source automation preset</option>',...J.map(E=>`<option value="${i(String(E?.id||""))}">${i(String(E?.id||""))} (${i(String(E?.layer||"unknown"))})</option>`)].join("")},me=()=>{const k=Z(),T=String(t("presets-filter-text")?.value||"").trim().toLowerCase(),M=String(t("presets-filter-publisher")?.value||"").trim().toLowerCase(),K=String(t("presets-filter-capability")?.value||"").trim().toLowerCase(),J=k.filter(q=>{const E=String(q?.id||"").toLowerCase(),ie=String(q?.layer||"").toLowerCase(),ye=Array.isArray(q?.tags)?q.tags.map(Ye=>String(Ye||"").toLowerCase()):[],Ie=String(q?.publisher||"").toLowerCase(),_e=Array.isArray(q?.required_capabilities)?q.required_capabilities.map(Ye=>String(Ye||"").toLowerCase()):[],at=[E,ie,...ye].join(" ");return!(T&&!at.includes(T)||M&&!Ie.includes(M)||K&&!_e.some(Ye=>Ye.includes(K)))});if(!J.length){P.innerHTML='<p class="tcp-subtle">No skill modules found.</p>';return}P.innerHTML=J.map(q=>{const E=Array.isArray(q?.required_capabilities)?q.required_capabilities:[],ie=Array.isArray(q?.tags)?q.tags:[];return`
|
|
1052
|
+
<article class="rounded-xl border border-slate-800 bg-slate-950/60 p-3">
|
|
1053
|
+
<div class="flex items-center justify-between gap-2">
|
|
1054
|
+
<strong>${i(String(q?.id||"unknown"))}</strong>
|
|
1055
|
+
<span class="tcp-subtle text-xs">${i(String(q?.layer||"unknown"))}</span>
|
|
1056
|
+
</div>
|
|
1057
|
+
<div class="mt-1 text-xs text-slate-400">publisher: ${i(String(q?.publisher||"unknown"))}</div>
|
|
1058
|
+
<div class="mt-1 text-xs text-slate-400">required capabilities: ${i(String(E.length))}</div>
|
|
1059
|
+
<div class="mt-1 text-xs text-slate-500">${i(ie.join(", ")||"no tags")}</div>
|
|
1060
|
+
</article>
|
|
1061
|
+
`}).join("")},de=async()=>{try{D=(await a("/api/presets/index"))?.index||{skill_modules:[],agent_presets:[],automation_presets:[]},$e(),me(),X()}catch(k){D={skill_modules:[],agent_presets:[],automation_presets:[]},$e(),me(),X(),s("err",`Preset index load failed: ${k instanceof Error?k.message:String(k)}`)}},fe=k=>{if(!O)return;const T=k?.pack||{},M=T?.installed||{},K=T?.trust||{},J=T?.risk||{},q=T?.permission_sheet||{},E=String(K?.verification_badge||"unverified"),ie=String(K?.signature||"unsigned"),ye=u(q?.required_capabilities),Ie=u(q?.optional_capabilities),_e=u(q?.provider_specific_dependencies),at=u(q?.routines_declared),Ye=`${String(M?.name||"unknown")}@${String(M?.version||"unknown")}`;O.classList.remove("hidden"),O.innerHTML=`
|
|
1062
|
+
<div class="flex items-center justify-between gap-2">
|
|
1063
|
+
<strong class="text-sm">${i(Ye)}</strong>
|
|
1064
|
+
<span class="${d(E)}">${i(E)}</span>
|
|
1065
|
+
</div>
|
|
1066
|
+
<div class="mt-2 grid gap-1 text-[11px] text-slate-300">
|
|
1067
|
+
<div>signature: <span class="font-mono">${i(ie)}</span></div>
|
|
1068
|
+
<div>risk level: <span class="font-mono">${i(String(q?.risk_level||"standard"))}</span></div>
|
|
1069
|
+
<div>required capabilities: <span class="font-mono">${ye.length}</span></div>
|
|
1070
|
+
<div>optional capabilities: <span class="font-mono">${Ie.length}</span></div>
|
|
1071
|
+
<div>provider-specific deps: <span class="font-mono">${_e.length}</span></div>
|
|
1072
|
+
<div>routines declared: <span class="font-mono">${at.length}</span></div>
|
|
1073
|
+
<div>routines enabled: <span class="font-mono">${i(String(J?.routines_enabled??!1))}</span></div>
|
|
1074
|
+
</div>
|
|
1075
|
+
`},pe=k=>{if(C){if(!k){C.classList.add("hidden"),C.textContent="",O?.classList.add("hidden");return}C.classList.remove("hidden"),C.textContent=JSON.stringify(k,null,2)}},be=async()=>{try{const k=await m.list(),T=Array.isArray(k?.packs)?k.packs:[];if(!T.length){g.innerHTML='<div class="tcp-card"><p class="tcp-subtle">No installed packs.</p></div>',r();return}g.innerHTML=T.map(M=>{const K=String(M.pack_id||M.name||""),J=String(M.name||"unknown"),q=String(M.version||"unknown"),E=String(M.pack_type||"unknown");return`
|
|
1076
|
+
<div class="tcp-card">
|
|
1077
|
+
<div class="flex items-start justify-between gap-3">
|
|
1078
|
+
<div>
|
|
1079
|
+
<h4 class="font-semibold">${i(J)} <span class="tcp-subtle">(${i(q)})</span></h4>
|
|
1080
|
+
<p class="tcp-subtle text-xs">pack_id: <span class="font-mono">${i(K)}</span> · type: ${i(E)}</p>
|
|
1081
|
+
</div>
|
|
1082
|
+
<div class="flex flex-wrap gap-2">
|
|
1083
|
+
<button class="tcp-btn" data-pack-inspect="${i(K)}"><i data-lucide="search"></i> Inspect</button>
|
|
1084
|
+
<button class="tcp-btn" data-pack-export="${i(K)}"><i data-lucide="archive"></i> Export</button>
|
|
1085
|
+
<button class="tcp-btn" data-pack-updates="${i(K)}"><i data-lucide="badge-check"></i> Updates</button>
|
|
1086
|
+
<button class="tcp-btn" data-pack-update="${i(K)}"><i data-lucide="arrow-up-circle"></i> Update</button>
|
|
1087
|
+
<button class="tcp-btn" data-pack-remove="${i(K)}"><i data-lucide="trash-2"></i> Uninstall</button>
|
|
1088
|
+
</div>
|
|
1089
|
+
</div>
|
|
1090
|
+
</div>`}).join(""),r(),g.querySelectorAll("[data-pack-inspect]").forEach(M=>{M.addEventListener("click",async()=>{const K=M.getAttribute("data-pack-inspect");if(K)try{const J=await m.inspect(K);fe(J),pe(J)}catch(J){s("err",`Inspect failed: ${J instanceof Error?J.message:String(J)}`)}})}),g.querySelectorAll("[data-pack-export]").forEach(M=>{M.addEventListener("click",async()=>{const K=M.getAttribute("data-pack-export");if(K)try{const J=await m.export({pack_id:K});s("ok",`Exported to ${J?.exported?.path||"unknown path"}`)}catch(J){s("err",`Export failed: ${J instanceof Error?J.message:String(J)}`)}})}),g.querySelectorAll("[data-pack-updates]").forEach(M=>{M.addEventListener("click",async()=>{const K=M.getAttribute("data-pack-updates");if(K)try{const J=await m.updates(K);pe(J);const q=Array.isArray(J?.updates)?J.updates.length:0,E=!!J?.reapproval_required;s(E?"warn":"info",E?`Updates available: ${q}. Permission scope changed; re-approval required.`:`Updates available: ${q}`)}catch(J){s("err",`Updates check failed: ${J instanceof Error?J.message:String(J)}`)}})}),g.querySelectorAll("[data-pack-update]").forEach(M=>{M.addEventListener("click",async()=>{const K=M.getAttribute("data-pack-update");if(K)try{const J=await m.update(K,{});pe(J);const q=!!J?.reapproval_required;s(q?"warn":"info",J?.reason||(J?.updated?"Pack updated":q?"No update applied. Permission re-approval required.":"No update applied"))}catch(J){s("err",`Update failed: ${J instanceof Error?J.message:String(J)}`)}})}),g.querySelectorAll("[data-pack-remove]").forEach(M=>{M.addEventListener("click",async()=>{const K=M.getAttribute("data-pack-remove");if(!(!K||!await ai({title:"Uninstall pack",message:`Remove installed pack ${K}? This does not delete exported zip files.`,confirmLabel:"Uninstall"})))try{await m.uninstall({pack_id:K}),s("ok",`Uninstalled ${K}`),await be()}catch(q){s("err",`Uninstall failed: ${q instanceof Error?q.message:String(q)}`)}})})}catch(k){g.innerHTML=`<div class="tcp-card"><p class="text-rose-300 text-sm">Failed to load packs: ${i(k instanceof Error?k.message:String(k))}</p></div>`,r()}};t("packs-refresh-btn")?.addEventListener("click",()=>{be()}),l||t("packs-open-settings")?.addEventListener("click",()=>c("settings")),t("presets-refresh-btn")?.addEventListener("click",()=>{de()}),t("presets-filter-text")?.addEventListener("input",me),t("presets-filter-publisher")?.addEventListener("input",me),t("presets-filter-capability")?.addEventListener("input",me),t("packs-cap-discovery-btn")?.addEventListener("click",async()=>{try{const k=await _.discovery();pe(k);const T=Array.isArray(k?.tools)?k.tools.length:0;s("ok",`Discovered ${T} tools`)}catch(k){s("err",`Capability discovery failed: ${k instanceof Error?k.message:String(k)}`)}}),t("packs-install-btn")?.addEventListener("click",async()=>{const k=String(t("packs-install-url")?.value||"").trim(),T=String(t("packs-install-path")?.value||"").trim();if(!k&&!T){s("err","Provide either URL or server path.");return}try{const M=await m.install({url:k||void 0,path:T||void 0,source:{kind:"control_panel"}});pe(M),s("ok",`Installed ${M?.installed?.name||"pack"} ${M?.installed?.version||""}`.trim()),await be()}catch(M){s("err",`Install failed: ${M instanceof Error?M.message:String(M)}`)}}),t("agent-builder-fork-btn")?.addEventListener("click",async()=>{const k=String(t("agent-builder-source")?.value||"").trim();if(!k){s("err","Select a source agent preset first.");return}const T=U(k);if(!T?.path){s("err","Selected source preset has no readable path.");return}try{const M=await a("/api/presets/fork",{method:"POST",body:JSON.stringify({kind:"agent_preset",source_path:T.path,target_id:String(t("agent-builder-fork-id")?.value||"").trim()||void 0})});pe(M),s("ok",`Forked to ${M?.path||"override"}`),await de()}catch(M){s("err",`Fork failed: ${M instanceof Error?M.message:String(M)}`)}}),t("agent-builder-preview-btn")?.addEventListener("click",async()=>{try{const T=(await a("/api/presets/compose/preview",{method:"POST",body:JSON.stringify({base_prompt:String(t("agent-builder-base")?.value||""),fragments:ne()})}))?.composition||{};re(j,{composition_hash:T?.composition_hash,ordered_fragment_ids:T?.ordered_fragment_ids,prompt:T?.prompt})}catch(k){s("err",`Compose preview failed: ${k instanceof Error?k.message:String(k)}`)}}),t("agent-builder-summary-btn")?.addEventListener("click",async()=>{try{const k=await a("/api/presets/capability_summary",{method:"POST",body:JSON.stringify({agent:ve(),tasks:[]})});re(Y,k?.summary||k)}catch(k){s("err",`Capability summary failed: ${k instanceof Error?k.message:String(k)}`)}}),t("agent-builder-save-btn")?.addEventListener("click",async()=>{const k=String(t("agent-builder-source")?.value||"").trim(),T=String(t("agent-builder-fork-id")?.value||"").trim()||k;if(!T){s("err","Provide target id (or select source preset).");return}const M=ve();try{await ue(`agent:${T}`,M.required,M.optional)}catch(E){s("err",`Readiness blocked save: ${E instanceof Error?E.message:String(E)}`);return}const K=ce(),J=String(t("agent-builder-base")?.value||"").trim(),q=[`id: ${T}`,"version: 0.1.0","publisher: local.user","description: Project override agent preset","tags:"," - override","modules:",...K.map(E=>` - ${E}`),"capabilities:"," required:",...M.required.length?M.required.map(E=>` - ${E}`):[" - "]," optional:",...M.optional.length?M.optional.map(E=>` - ${E}`):[" - "],"prompt:"," base: |",...J?J.split(`
|
|
1091
|
+
`).map(E=>` ${E}`):[" "]," fragments:",...ne().map(E=>` - id: ${E.id}
|
|
1092
|
+
phase: ${E.phase}
|
|
1093
|
+
content: ${JSON.stringify(E.content)}`),""].join(`
|
|
1094
|
+
`);try{const E=await a(`/api/presets/overrides/agent_preset/${encodeURIComponent(T)}`,{method:"PUT",body:JSON.stringify({content:q})});pe(E),s("ok",`Saved agent override ${T}`),await de()}catch(E){s("err",`Save override failed: ${E instanceof Error?E.message:String(E)}`)}}),t("automation-builder-add-task")?.addEventListener("click",()=>{R.push({id:`step_${R.length+1}`,agent_id:"",required:[],optional:[]}),X()}),t("automation-builder-source")?.addEventListener("change",()=>{const k=String(t("automation-builder-source")?.value||"").trim(),T=se(k);if(!k||!T){R=[],X();return}R=[{id:`${k}_step_1`,agent_id:String(t("agent-builder-source")?.value||"").trim(),required:x(u(T.required_capabilities)),optional:[]}],X()}),t("automation-builder-summary-btn")?.addEventListener("click",async()=>{try{const k=String(t("agent-builder-source")?.value||"").trim(),T=U(k),M={required:x(u(T?.required_capabilities).concat(ve().required)),optional:ve().optional},K=R.map(q=>{const E=U(q.agent_id),ie=x(u(E?.required_capabilities)),ye=x(ie.concat(u(q.required))),Ie=x(u(q.optional)).filter(_e=>!ye.includes(_e));return{required:ye,optional:Ie}}),J=await a("/api/presets/capability_summary",{method:"POST",body:JSON.stringify({agent:M,tasks:K})});re(N,J?.summary||J)}catch(k){s("err",`Automation summary failed: ${k instanceof Error?k.message:String(k)}`)}}),t("automation-builder-save-btn")?.addEventListener("click",async()=>{const k=String(t("automation-builder-id")?.value||"").trim();if(!k){s("err","Automation override id is required.");return}let T=null,M=[],K=[];try{const q=String(t("agent-builder-source")?.value||"").trim(),E=U(q),ie={required:x(u(E?.required_capabilities).concat(ve().required)),optional:ve().optional},ye=R.map(_e=>{const at=U(_e.agent_id),Ye=x(u(at?.required_capabilities)),ln=x(Ye.concat(u(_e.required))),gt=x(u(_e.optional)).filter(At=>!ln.includes(At));return{required:ln,optional:gt}});T=(await a("/api/presets/capability_summary",{method:"POST",body:JSON.stringify({agent:ie,tasks:ye})}))?.summary||null,M=x(u(T?.automation?.required)),K=x(u(T?.automation?.optional))}catch{T=null}try{await ue(`automation:${k}`,M,K)}catch(q){s("err",`Readiness blocked save: ${q instanceof Error?q.message:String(q)}`);return}const J=[`id: ${k}`,"version: 0.1.0","publisher: local.user","description: Project override automation preset","tags:"," - override","tasks:",...R.length?R.flatMap(q=>[` - id: ${q.id||"step"}`,` agent_preset: ${q.agent_id||""}`," capabilities:"," required:",...u(q.required).length?u(q.required).map(E=>` - ${E}`):[" - "]," optional:",...u(q.optional).length?u(q.optional).map(E=>` - ${E}`):[" - "]]):[" - id: step_1"," agent_preset: "],"capabilities:"," required:",...(T?.automation?.required||[]).length?T.automation.required.map(q=>` - ${q}`):[" - "]," optional:",...(T?.automation?.optional||[]).length?T.automation.optional.map(q=>` - ${q}`):[" - "],""].join(`
|
|
1095
|
+
`);try{const q=await a(`/api/presets/overrides/automation_preset/${encodeURIComponent(k)}`,{method:"PUT",body:JSON.stringify({content:J})});pe(q),s("ok",`Saved automation override ${k}`),await de()}catch(q){s("err",`Save automation override failed: ${q instanceof Error?q.message:String(q)}`)}}),await be(),await de()}function pr(e){const t=String(e||"").toLowerCase();return t.includes("fail")||t.includes("error")?"tcp-badge-err":t.includes("wait")||t.includes("queue")||t.includes("new")?"tcp-badge-warn":"tcp-badge-ok"}function uv(e){const t=new Map;for(const n of e){const s=n.ownerRole||"unknown",r=t.get(s)||{total:0,running:0,done:0,failed:0};r.total+=1;const i=String(n.status||"").toLowerCase();i.includes("fail")||i.includes("error")?r.failed+=1:i.includes("done")||i.includes("complete")?r.done+=1:r.running+=1,t.set(s,r)}return[...t.entries()]}function pv(e){return e?e.kind==="task_transition"?`${e.taskId}: ${e.from} -> ${e.to} (${e.reason||"status changed"})`:e.kind==="task_reason"?`${e.taskId}: ${e.reason||"updated"}`:e.reason||JSON.stringify(e):""}async function Bn(e){const{api:t,byId:n,escapeHtml:s,toast:r,state:i,addCleanup:a}=e;if(i.route!=="swarm")return;const c=i.route;if(i.__swarmLiveCleanup&&Array.isArray(i.__swarmLiveCleanup))for(const g of i.__swarmLiveCleanup)try{g()}catch{}i.__swarmLiveCleanup=[];const l=await t("/api/swarm/status").catch(()=>({status:"error"})),d=await t("/api/swarm/snapshot").catch(()=>({registry:{value:{tasks:{}}},logs:[],reasons:[]}));if(i.route!==c)return;const u=Object.values(d.registry?.value?.tasks||{}),m=(d.reasons||[]).slice().reverse(),_=uv(u);n("view").innerHTML=`
|
|
1096
|
+
<div class="tcp-card">
|
|
1097
|
+
<div class="mb-3 flex items-center justify-between gap-3">
|
|
1098
|
+
<h3 class="tcp-title flex items-center gap-2"><i data-lucide="cpu"></i> Node Swarm Orchestrator</h3>
|
|
1099
|
+
<span class="${pr(l.status)}">${s(l.status||"idle")}</span>
|
|
1100
|
+
</div>
|
|
1101
|
+
<p class="mb-3 rounded-xl border border-slate-700/60 bg-slate-900/25 px-3 py-2 text-xs text-slate-300">
|
|
1102
|
+
Swarm is best for short-lived interactive orchestration. For persistent scheduled multi-agent pipelines, use <strong>Automations</strong>.
|
|
1103
|
+
</p>
|
|
1104
|
+
<div class="grid gap-3 md:grid-cols-[1fr_1fr_120px_auto]">
|
|
1105
|
+
<input id="swarm-root" class="tcp-input" value="${s(l.workspaceRoot||"")}" placeholder="workspace root" />
|
|
1106
|
+
<input id="swarm-objective" class="tcp-input" value="${s(l.objective||"Ship a small feature end-to-end")}" placeholder="objective" />
|
|
1107
|
+
<input id="swarm-max" class="tcp-input" type="number" min="1" value="${s(String(l.maxTasks||3))}" />
|
|
1108
|
+
<div class="flex gap-2">
|
|
1109
|
+
<button id="swarm-start" class="tcp-btn-primary" ${l.localEngine?"":"disabled"}><i data-lucide="play"></i> Start</button>
|
|
1110
|
+
<button id="swarm-stop" class="tcp-btn-danger"><i data-lucide="square"></i> Stop</button>
|
|
1111
|
+
</div>
|
|
1112
|
+
</div>
|
|
1113
|
+
${l.localEngine?"":'<p class="mt-3 rounded-xl border border-amber-700/60 bg-amber-950/20 px-3 py-2 text-sm text-amber-300">Swarm orchestration is disabled on remote engine URLs. Monitoring remains available.</p>'}
|
|
1114
|
+
</div>
|
|
1115
|
+
|
|
1116
|
+
<div class="tcp-card">
|
|
1117
|
+
<h3 class="tcp-title mb-3">Live Agent Flow</h3>
|
|
1118
|
+
<div class="overflow-hidden rounded-xl border border-slate-700 bg-black/20 p-2">
|
|
1119
|
+
<svg viewBox="0 0 680 240" class="h-[280px] w-full">
|
|
1120
|
+
<defs>
|
|
1121
|
+
<linearGradient id="wire-grad" x1="0" y1="0" x2="1" y2="0">
|
|
1122
|
+
<stop offset="0%" stop-color="#64748b" stop-opacity="0.12"></stop>
|
|
1123
|
+
<stop offset="50%" stop-color="#94a3b8" stop-opacity="0.95"></stop>
|
|
1124
|
+
<stop offset="100%" stop-color="#64748b" stop-opacity="0.12"></stop>
|
|
1125
|
+
</linearGradient>
|
|
1126
|
+
</defs>
|
|
1127
|
+
<line x1="140" y1="120" x2="320" y2="60" stroke="url(#wire-grad)" stroke-width="2" class="wire-line-active"></line>
|
|
1128
|
+
<line x1="140" y1="120" x2="320" y2="120" stroke="url(#wire-grad)" stroke-width="2" class="wire-line-active"></line>
|
|
1129
|
+
<line x1="140" y1="120" x2="320" y2="180" stroke="url(#wire-grad)" stroke-width="2" class="wire-line-active"></line>
|
|
1130
|
+
<line x1="360" y1="60" x2="540" y2="50" stroke="url(#wire-grad)" stroke-width="2" class="wire-line-active"></line>
|
|
1131
|
+
<line x1="360" y1="120" x2="540" y2="120" stroke="url(#wire-grad)" stroke-width="2" class="wire-line-active"></line>
|
|
1132
|
+
<line x1="360" y1="180" x2="540" y2="190" stroke="url(#wire-grad)" stroke-width="2" class="wire-line-active"></line>
|
|
1133
|
+
|
|
1134
|
+
<circle cx="120" cy="120" r="20" fill="rgba(30,41,59,0.95)" stroke="rgba(148,163,184,0.8)" stroke-width="1.5" class="node-active"></circle>
|
|
1135
|
+
<text x="120" y="152" text-anchor="middle" fill="#cbd5e1" font-size="11">Manager</text>
|
|
1136
|
+
<circle cx="340" cy="60" r="18" fill="rgba(30,41,59,0.95)" stroke="rgba(148,163,184,0.7)" stroke-width="1.5" class="node-active"></circle>
|
|
1137
|
+
<text x="340" y="92" text-anchor="middle" fill="#cbd5e1" font-size="11">Worker</text>
|
|
1138
|
+
<circle cx="340" cy="120" r="18" fill="rgba(30,41,59,0.95)" stroke="rgba(148,163,184,0.7)" stroke-width="1.5" class="node-active"></circle>
|
|
1139
|
+
<text x="340" y="152" text-anchor="middle" fill="#cbd5e1" font-size="11">Tester</text>
|
|
1140
|
+
<circle cx="340" cy="180" r="18" fill="rgba(30,41,59,0.95)" stroke="rgba(148,163,184,0.7)" stroke-width="1.5" class="node-active"></circle>
|
|
1141
|
+
<text x="340" y="212" text-anchor="middle" fill="#cbd5e1" font-size="11">Reviewer</text>
|
|
1142
|
+
</svg>
|
|
1143
|
+
</div>
|
|
1144
|
+
<div class="mt-3 grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
|
|
1145
|
+
${_.map(([g,C])=>`<div class="tcp-list-item"><div class="font-medium">${s(g)}</div><div class="tcp-subtle mt-1">${C.total} tasks</div><div class="text-xs text-slate-400">${C.running} active / ${C.done} done / ${C.failed} failed</div></div>`).join("")||'<p class="tcp-subtle">No active roles yet.</p>'}
|
|
1146
|
+
</div>
|
|
1147
|
+
</div>
|
|
1148
|
+
|
|
1149
|
+
<div class="tcp-card">
|
|
1150
|
+
<div class="mb-3 flex items-center justify-between gap-2">
|
|
1151
|
+
<h3 class="tcp-title">Swarm Why Timeline</h3>
|
|
1152
|
+
<div class="flex gap-2">
|
|
1153
|
+
<select id="swarm-reason-kind" class="tcp-select !w-auto !py-1.5 text-xs">
|
|
1154
|
+
<option value="">All kinds</option>
|
|
1155
|
+
<option value="task_transition">task_transition</option>
|
|
1156
|
+
<option value="task_reason">task_reason</option>
|
|
1157
|
+
</select>
|
|
1158
|
+
<input id="swarm-reason-task" class="tcp-input !w-44 !py-1.5 text-xs" placeholder="Filter by task id" />
|
|
1159
|
+
</div>
|
|
1160
|
+
</div>
|
|
1161
|
+
<div id="swarm-reasons" class="grid max-h-[420px] gap-2 overflow-auto"></div>
|
|
1162
|
+
</div>
|
|
1163
|
+
|
|
1164
|
+
<div class="grid gap-4 lg:grid-cols-2">
|
|
1165
|
+
<div class="tcp-card">
|
|
1166
|
+
<h3 class="tcp-title mb-3">Tasks (${u.length})</h3>
|
|
1167
|
+
<div id="swarm-tasks" class="grid max-h-[420px] gap-2 overflow-auto"></div>
|
|
1168
|
+
</div>
|
|
1169
|
+
<div class="tcp-card">
|
|
1170
|
+
<h3 class="tcp-title mb-3">Swarm Logs</h3>
|
|
1171
|
+
<pre id="swarm-logs" class="tcp-code max-h-[420px] overflow-auto"></pre>
|
|
1172
|
+
</div>
|
|
1173
|
+
</div>
|
|
1174
|
+
`;const b=n("swarm-tasks");b.innerHTML=u.sort((g,C)=>(C.lastUpdateMs||0)-(g.lastUpdateMs||0)).map(g=>`<div class="tcp-list-item"><div class="flex items-center justify-between gap-2"><strong>${s(g.taskId)}</strong><span class="${pr(g.status)}">${s(g.status||"unknown")}</span></div><div class="mt-1 text-xs uppercase tracking-wide text-slate-400">${s(g.ownerRole||"")}</div><div class="tcp-subtle mt-1">${s(g.statusReason||"")}</div></div>`).join("")||'<p class="tcp-subtle">No swarm tasks yet.</p>';function x(){const g=n("swarm-reason-kind").value.trim(),C=n("swarm-reason-task").value.trim().toLowerCase(),O=m.filter(P=>!(g&&P.kind!==g||C&&!String(P.taskId||"").toLowerCase().includes(C)));n("swarm-reasons").innerHTML=O.map(P=>`
|
|
1175
|
+
<div class="tcp-list-item">
|
|
1176
|
+
<div class="flex items-center justify-between gap-2"><span class="text-xs text-slate-400">${new Date(P.at).toLocaleTimeString()}</span><span class="${pr(P.to||P.from)}">${s(P.kind||"reason")}</span></div>
|
|
1177
|
+
<div class="mt-1"><strong>${s(P.taskId||"swarm")}</strong> <span class="tcp-subtle">${s(P.role||"")}</span></div>
|
|
1178
|
+
<div class="mt-1 text-sm text-slate-300">${s(pv(P))}</div>
|
|
1179
|
+
</div>
|
|
1180
|
+
`).join("")||'<p class="tcp-subtle">No timeline reasons yet.</p>'}n("swarm-reason-kind").addEventListener("change",x),n("swarm-reason-task").addEventListener("input",x),x(),n("swarm-logs").textContent=(d.logs||[]).slice(-200).map(g=>`[${new Date(g.at).toLocaleTimeString()}] ${g.stream}: ${g.line}`).join(`
|
|
1181
|
+
`),n("swarm-start").addEventListener("click",async()=>{try{await t("/api/swarm/start",{method:"POST",body:JSON.stringify({workspaceRoot:n("swarm-root").value.trim(),objective:n("swarm-objective").value.trim(),maxTasks:Number.parseInt(n("swarm-max").value,10)||3})}),r("ok","Swarm started."),Bn(e)}catch(g){r("err",g instanceof Error?g.message:String(g))}}),n("swarm-stop").addEventListener("click",async()=>{try{await t("/api/swarm/stop",{method:"POST"}),r("ok","Swarm stop requested."),Bn(e)}catch(g){r("err",g instanceof Error?g.message:String(g))}});const y=setInterval(()=>{i.route==="swarm"&&Bn(e)},4e3),I=()=>clearInterval(y);i.__swarmLiveCleanup.push(I),a(I);try{const g=new EventSource("/api/swarm/events",{withCredentials:!0});g.onmessage=()=>{i.route==="swarm"&&Bn(e)},g.onerror=()=>g.close();const C=()=>g.close();i.__swarmLiveCleanup.push(C),a(C)}catch{}}function mv(e){const t=Number(e||0);return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}function fv(e){const t=Number(e||0);return t?new Date(t).toLocaleString():"n/a"}const hv={md:"text/markdown",txt:"text/plain",csv:"text/csv",json:"application/json",pdf:"application/pdf",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp"};function lc(e=""){const t=String(e).toLowerCase().split(".").pop()||"";return hv[t]||"application/octet-stream"}function gv(e,t){if(!e||!t)return t||"";const n=String(e).replace(/[\\/]+$/,""),s=String(t).replace(/^[\\/]+/,"");return`${n}/${s}`}function va(e){const t=String(e?.root||"").trim();return(Array.isArray(e)?e:Array.isArray(e?.files)?e.files:Array.isArray(e?.entries)?e.entries:Array.isArray(e?.items)?e.items:[]).map(s=>{if(typeof s=="string"){const a=s.replace(/^\/+/,"");return{name:a.split("/").pop()||a,path:a,size:0,updatedAt:0}}const r=String(s.relative_to_base||s.path||s.key||s.name||"").replace(/^\/+/,"");if(!r)return null;const i=String(s.name||r.split("/").pop()||r);return{name:i,path:r,size:Number(s.size||s.size_bytes||s.bytes||0),updatedAt:Number(s.updatedAt||s.modified_at_ms||s.modifiedAt||s.mtimeMs||0),mime:lc(i),url:String(s.absPath||s.absolute_path||gv(t,r)||r)}}).filter(Boolean)}function dc(e){return String(e||"").trim().replace(/\\/g,"/").replace(/^\/+/,"").replace(/\/+$/,"")}const Es="control-panel",ya="channel_uploads";function vv(e){const t=dc(e);return t===Es||t.startsWith(`${Es}/`)?t:Es}async function uc(e){const{state:t,byId:n,api:s,escapeHtml:r,toast:i,renderIcons:a,setRoute:c}=e,l=e?.embeddedInSettings===!0,d=new Map,u=[],m=vv(t.filesDir||Es);t.filesDir=m;const _=l?"":`
|
|
1182
|
+
<div class="tcp-card">
|
|
1183
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
1184
|
+
<div>
|
|
1185
|
+
<h3 class="tcp-title">Moved To Settings</h3>
|
|
1186
|
+
<p class="tcp-subtle">Files and storage tools are now organized under Settings.</p>
|
|
1187
|
+
</div>
|
|
1188
|
+
<button id="files-open-settings" class="tcp-btn"><i data-lucide="settings"></i> Open Settings</button>
|
|
1189
|
+
</div>
|
|
1190
|
+
</div>`;n("view").innerHTML=`
|
|
1191
|
+
${_}
|
|
1192
|
+
<div class="tcp-card grid gap-3">
|
|
1193
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
1194
|
+
<h3 class="tcp-title">Storage Browser</h3>
|
|
1195
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
1196
|
+
<label for="files-upload-input" class="tcp-btn cursor-pointer"><i data-lucide="file-up"></i> Upload Files</label>
|
|
1197
|
+
<input id="files-upload-input" type="file" class="hidden" multiple />
|
|
1198
|
+
<button id="files-refresh" class="tcp-btn"><i data-lucide="refresh-cw"></i> Refresh</button>
|
|
1199
|
+
</div>
|
|
1200
|
+
</div>
|
|
1201
|
+
<div id="files-upload-progress" class="grid gap-1.5"></div>
|
|
1202
|
+
<div class="overflow-auto rounded-xl border border-slate-700 bg-black/20">
|
|
1203
|
+
<table class="w-full min-w-[760px] text-sm">
|
|
1204
|
+
<thead class="border-b border-slate-700 bg-slate-900/40 text-left text-slate-400">
|
|
1205
|
+
<tr>
|
|
1206
|
+
<th class="px-3 py-2">Name</th>
|
|
1207
|
+
<th class="px-3 py-2">Path</th>
|
|
1208
|
+
<th class="px-3 py-2">Size</th>
|
|
1209
|
+
<th class="px-3 py-2">Updated</th>
|
|
1210
|
+
<th class="px-3 py-2 text-right">Actions</th>
|
|
1211
|
+
</tr>
|
|
1212
|
+
</thead>
|
|
1213
|
+
<tbody id="files-table"></tbody>
|
|
1214
|
+
</table>
|
|
1215
|
+
</div>
|
|
1216
|
+
</div>
|
|
1217
|
+
`,l||n("files-open-settings")?.addEventListener("click",()=>c("settings"));const b=n("files-table"),x=n("files-upload-progress"),y=n("files-upload-input");function I(){const N=[...d.entries()];x.innerHTML=N.map(([z,D])=>{const R=Math.max(0,Math.min(100,Number(D.progress||0)));return`
|
|
1218
|
+
<div class="rounded-lg border border-slate-700/70 bg-slate-900/40 px-2 py-1.5">
|
|
1219
|
+
<div class="mb-1 flex items-center justify-between gap-2 text-xs">
|
|
1220
|
+
<span class="truncate text-slate-200">${r(D.name)}</span>
|
|
1221
|
+
<span class="${D.error?"text-rose-300":"text-slate-400"}">${D.error?r(D.error):`${R}%`}</span>
|
|
1222
|
+
</div>
|
|
1223
|
+
<div class="h-1.5 overflow-hidden rounded-full bg-slate-800">
|
|
1224
|
+
<div class="h-full rounded-full bg-slate-400/80 transition-all duration-150" style="width:${R}%"></div>
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
`}).join("")}function g(){if(!u.length){b.innerHTML='<tr><td colspan="5" class="px-3 py-5 text-center text-slate-400">No files in this directory.</td></tr>';return}b.innerHTML=u.map((N,z)=>`
|
|
1228
|
+
<tr class="border-b border-slate-800/70">
|
|
1229
|
+
<td class="px-3 py-2 font-medium text-slate-200">
|
|
1230
|
+
${r(N.name)}
|
|
1231
|
+
</td>
|
|
1232
|
+
<td class="px-3 py-2 font-mono text-xs text-slate-400">${r(N.path)}</td>
|
|
1233
|
+
<td class="px-3 py-2 text-slate-300">${r(mv(N.size))}</td>
|
|
1234
|
+
<td class="px-3 py-2 text-slate-400">${r(fv(N.updatedAt))}</td>
|
|
1235
|
+
<td class="px-3 py-2">
|
|
1236
|
+
<div class="flex justify-end gap-1.5">
|
|
1237
|
+
<button type="button" class="tcp-btn px-2.5" data-use-chat="${z}" title="Use in chat">Use in Chat</button>
|
|
1238
|
+
<a class="tcp-btn px-2.5" href="/api/files/download?path=${encodeURIComponent(N.path)}" title="Download"><i data-lucide="download"></i></a>
|
|
1239
|
+
<button type="button" class="tcp-btn-danger px-2.5" data-del-file="${z}" title="Delete"><i data-lucide="trash-2"></i></button>
|
|
1240
|
+
</div>
|
|
1241
|
+
</td>
|
|
1242
|
+
</tr>
|
|
1243
|
+
`).join(""),b.querySelectorAll("[data-use-chat]").forEach(N=>{N.addEventListener("click",()=>{const z=Number(N.dataset.useChat);if(!Number.isFinite(z)||!u[z])return;const D=u[z];(t.chatUploadedFiles||[]).some(Z=>Z.path===D.path)||(t.chatUploadedFiles=[{name:D.name,path:D.path,size:D.size,mime:D.mime||lc(D.name),url:D.url||D.path,attach:!0},...t.chatUploadedFiles||[]]),i("ok",`${D.name} added to chat attachments.`),c("chat")})}),b.querySelectorAll("[data-del-file]").forEach(N=>{N.addEventListener("click",async()=>{const z=Number(N.dataset.delFile);if(!Number.isFinite(z)||!u[z])return;const D=u[z];if(await ai({title:"Delete file",message:`Permanently delete ${D.path}?`,confirmLabel:"Delete file"}))try{await s("/api/files/delete",{method:"POST",body:JSON.stringify({path:D.path})}),i("ok",`${D.name} deleted.`),await P()}catch(Z){i("err",Z instanceof Error?Z.message:String(Z))}})}),a(b)}async function C(N){const z=N?`${ya}/${N}`:ya,D=`?path=${encodeURIComponent(z)}`,R=await s(`/api/engine/global/storage/files${D}`);return va(R)}async function O(N){const z=N?`?dir=${encodeURIComponent(N)}`:"",D=await s(`/api/files/list${z}`);return va(D)}async function P(){try{let N=[];try{N=await C(m)}catch{N=await O(m)}const z=N.map(D=>{const R=dc(D.path||"");if(!R)return null;const Z=R.split("/").pop()||R;return{...D,kind:"file",name:Z,path:R}}).filter(Boolean).sort((D,R)=>D.path.localeCompare(R.path));u.splice(0,u.length,...z),g()}catch(N){i("err",N instanceof Error?N.message:String(N))}}function j(N){return new Promise((z,D)=>{const R=`${Date.now()}-${Math.random().toString(16).slice(2)}`;d.set(R,{name:N.name,progress:0,error:""}),I();const Z=new XMLHttpRequest,le=m?`?dir=${encodeURIComponent(m)}`:"";Z.open("POST",`/api/files/upload${le}`),Z.withCredentials=!0,Z.responseType="json",Z.setRequestHeader("x-file-name",encodeURIComponent(N.name)),Z.upload.onprogress=ee=>{if(!ee.lengthComputable)return;const U=d.get(R);U&&(U.progress=ee.loaded/ee.total*100,I())},Z.onerror=()=>{const ee=d.get(R);ee&&(ee.error="Network error"),I(),setTimeout(()=>{d.delete(R),I()},1200),D(new Error(`Upload failed: ${N.name}`))},Z.onload=()=>{const ee=Z.response||{};if(Z.status<200||Z.status>=300||ee?.ok===!1){const U=ee?.error||`Upload failed (${Z.status})`,se=d.get(R);se&&(se.error=String(U)),I(),setTimeout(()=>{d.delete(R),I()},1800),D(new Error(String(U)));return}d.delete(R),I(),z(ee)},Z.send(N)})}async function Y(N){const z=[...N||[]];if(!z.length)return;let D=0;for(const R of z)try{await j(R),D+=1}catch(Z){i("err",Z instanceof Error?Z.message:String(Z))}D>0&&(i("ok",`Uploaded ${D} file${D===1?"":"s"} to tandem/${m||"."}.`),await P())}n("files-refresh").addEventListener("click",()=>{P()}),y.addEventListener("change",async()=>{await Y(y.files),y.value=""}),a(n("view")),await P()}async function Mr(e){const{state:t,byId:n,toast:s,escapeHtml:r}=e,a=(await t.client.memory.list({limit:100}).catch(()=>({items:[]}))).items||[];n("view").innerHTML=`
|
|
1244
|
+
<div class="tcp-card">
|
|
1245
|
+
<div class="mb-3 flex items-center justify-between">
|
|
1246
|
+
<h3 class="tcp-title">Memory</h3>
|
|
1247
|
+
<span class="tcp-badge-info">${a.length} records</span>
|
|
1248
|
+
</div>
|
|
1249
|
+
<div class="grid gap-3 md:grid-cols-[1fr_auto_auto]">
|
|
1250
|
+
<input id="mem-query" class="tcp-input" placeholder="Search query" />
|
|
1251
|
+
<button id="mem-search" class="tcp-btn-primary"><i data-lucide="search"></i> Search</button>
|
|
1252
|
+
<button id="mem-refresh" class="tcp-btn"><i data-lucide="refresh-cw"></i></button>
|
|
1253
|
+
</div>
|
|
1254
|
+
<div id="mem-results" class="tcp-list mt-3"></div>
|
|
1255
|
+
</div>
|
|
1256
|
+
`;const c=l=>{n("mem-results").innerHTML=l.map(d=>`
|
|
1257
|
+
<div class="tcp-list-item flex items-center justify-between gap-3">
|
|
1258
|
+
<div>
|
|
1259
|
+
<strong class="font-mono text-xs text-slate-300">${r(d.id||"(no id)")}</strong>
|
|
1260
|
+
<div class="tcp-subtle mt-1">${r((d.text||d.content||"").slice(0,140))}</div>
|
|
1261
|
+
</div>
|
|
1262
|
+
<button data-del="${r(d.id||"")}" class="tcp-btn-danger"><i data-lucide="trash-2"></i></button>
|
|
1263
|
+
</div>
|
|
1264
|
+
`).join("")||'<p class="tcp-subtle">No memory records.</p>',n("mem-results").querySelectorAll("[data-del]").forEach(d=>d.addEventListener("click",async()=>{const u=d.dataset.del;if(u)try{await t.client.memory.delete(u),s("ok","Memory deleted."),Mr(e)}catch(m){s("err",m instanceof Error?m.message:String(m))}}))};c(a),n("mem-refresh").addEventListener("click",()=>Mr(e)),n("mem-search").addEventListener("click",async()=>{const l=n("mem-query").value.trim();if(!l)return c(a);try{const d=await t.client.memory.search({query:l,limit:50});c(d.results||[])}catch(d){s("err",d instanceof Error?d.message:String(d))}})}function ks(e){return Array.isArray(e)?e:[]}function yv(e){return e?.id||e?.instanceID||e?.missionID||e?.templateID||"(unknown)"}function bv(e){return e?.status||e?.state||e?.phase||"unknown"}function mr(e,t){return t?JSON.stringify(e||{}).toLowerCase().includes(t):!0}function fr(e,t,n,s="id"){return e.length?e.map(r=>{const i=n(r?.[s]||yv(r)),a=n(bv(r));return`
|
|
1265
|
+
<article class="tcp-list-item">
|
|
1266
|
+
<div class="flex items-center justify-between gap-2">
|
|
1267
|
+
<strong>${i}</strong>
|
|
1268
|
+
<span class="tcp-badge-info">${a}</span>
|
|
1269
|
+
</div>
|
|
1270
|
+
<div class="tcp-subtle mt-1">role: ${n(r?.role||r?.ownerRole||"n/a")}</div>
|
|
1271
|
+
<div class="tcp-subtle">mission: ${n(r?.missionID||r?.missionId||r?.mission||"n/a")}</div>
|
|
1272
|
+
<details class="mt-2">
|
|
1273
|
+
<summary class="cursor-pointer text-xs text-slate-400">Details</summary>
|
|
1274
|
+
<pre class="tcp-code mt-2">${n(JSON.stringify(r,null,2))}</pre>
|
|
1275
|
+
</details>
|
|
1276
|
+
</article>
|
|
1277
|
+
`}).join(""):`<p class="tcp-subtle">${t}</p>`}async function Ts(e){const{state:t,byId:n,toast:s,escapeHtml:r}=e,[i,a,c,l]=await Promise.all([t.client.agentTeams.listTemplates().catch(()=>({templates:[]})),t.client.agentTeams.listInstances().catch(()=>({instances:[]})),t.client.agentTeams.listMissions().catch(()=>({missions:[]})),t.client.agentTeams.listApprovals().catch(()=>({spawnApprovals:[]}))]),d=ks(i.templates),u=ks(a.instances),m=ks(c.missions),_=ks(l.spawnApprovals);n("view").innerHTML=`
|
|
1278
|
+
<div class="tcp-card">
|
|
1279
|
+
<h3 class="tcp-title mb-3">Spawn Agent Team Instance</h3>
|
|
1280
|
+
<div class="grid gap-3 md:grid-cols-4">
|
|
1281
|
+
<input id="team-mission" class="tcp-input" placeholder="missionID" />
|
|
1282
|
+
<input id="team-role" class="tcp-input" placeholder="role" value="worker" />
|
|
1283
|
+
<input id="team-template" class="tcp-input" placeholder="templateID" value="worker-default" />
|
|
1284
|
+
<button id="team-spawn" class="tcp-btn-primary">Spawn</button>
|
|
1285
|
+
</div>
|
|
1286
|
+
</div>
|
|
1287
|
+
|
|
1288
|
+
<div class="tcp-card">
|
|
1289
|
+
<div class="mb-3 flex items-center justify-between gap-3">
|
|
1290
|
+
<h3 class="tcp-title">Teams & Missions</h3>
|
|
1291
|
+
<input id="teams-filter" class="tcp-input max-w-sm" placeholder="Filter instances/missions/templates" />
|
|
1292
|
+
</div>
|
|
1293
|
+
|
|
1294
|
+
<div class="grid gap-4 lg:grid-cols-2">
|
|
1295
|
+
<section>
|
|
1296
|
+
<h4 class="mb-2 font-medium">Approvals (${_.length})</h4>
|
|
1297
|
+
<div id="team-approvals" class="tcp-list"></div>
|
|
1298
|
+
</section>
|
|
1299
|
+
<section>
|
|
1300
|
+
<h4 class="mb-2 font-medium">Instances (${u.length})</h4>
|
|
1301
|
+
<div id="team-instances" class="tcp-list"></div>
|
|
1302
|
+
</section>
|
|
1303
|
+
</div>
|
|
1304
|
+
|
|
1305
|
+
<div class="mt-4 grid gap-4 lg:grid-cols-2">
|
|
1306
|
+
<section>
|
|
1307
|
+
<h4 class="mb-2 font-medium">Missions (${m.length})</h4>
|
|
1308
|
+
<div id="team-missions" class="tcp-list"></div>
|
|
1309
|
+
</section>
|
|
1310
|
+
<section>
|
|
1311
|
+
<h4 class="mb-2 font-medium">Templates (${d.length})</h4>
|
|
1312
|
+
<div id="team-templates" class="tcp-list"></div>
|
|
1313
|
+
</section>
|
|
1314
|
+
</div>
|
|
1315
|
+
</div>
|
|
1316
|
+
`,n("team-spawn").addEventListener("click",async()=>{try{await t.client.agentTeams.spawn({missionID:n("team-mission").value.trim(),role:n("team-role").value.trim()||"worker",templateID:n("team-template").value.trim()||"worker-default",source:"ui_action",justification:"spawn from control panel"}),s("ok","Spawn requested."),Ts(e)}catch(y){s("err",y instanceof Error?y.message:String(y))}});function b(){const y=n("teams-filter").value.trim().toLowerCase(),I=u.filter(O=>mr(O,y)),g=m.filter(O=>mr(O,y)),C=d.filter(O=>mr(O,y));n("team-instances").innerHTML=fr(I,"No instances.",r,"instanceID"),n("team-missions").innerHTML=fr(g,"No missions.",r,"missionID"),n("team-templates").innerHTML=fr(C,"No templates.",r,"templateID")}const x=n("team-approvals");x.innerHTML=_.map(y=>{const I=r(y.approvalID||y.id||"");return`
|
|
1317
|
+
<div class="tcp-list-item flex items-center justify-between gap-3">
|
|
1318
|
+
<div>
|
|
1319
|
+
<div><strong>${I||"approval"}</strong></div>
|
|
1320
|
+
<div class="tcp-subtle">mission: ${r(y.missionID||y.missionId||"n/a")}</div>
|
|
1321
|
+
</div>
|
|
1322
|
+
<div class="flex gap-2">
|
|
1323
|
+
<button data-ap="${I}" class="tcp-btn-primary">Approve</button>
|
|
1324
|
+
<button data-den="${I}" class="tcp-btn-danger">Deny</button>
|
|
1325
|
+
</div>
|
|
1326
|
+
</div>`}).join("")||'<p class="tcp-subtle">No pending spawn approvals.</p>',x.querySelectorAll("[data-ap]").forEach(y=>y.addEventListener("click",async()=>{try{await t.client.agentTeams.approveSpawn(y.dataset.ap,"approved in portal"),s("ok","Approved."),Ts(e)}catch(I){s("err",I instanceof Error?I.message:String(I))}})),x.querySelectorAll("[data-den]").forEach(y=>y.addEventListener("click",async()=>{try{await t.client.agentTeams.denySpawn(y.dataset.den,"denied in portal"),s("ok","Denied."),Ts(e)}catch(I){s("err",I instanceof Error?I.message:String(I))}})),n("teams-filter").addEventListener("input",b),b()}function Rr(e){return e?.type||e?.event||"event"}function ba(e){const t=String(e||"").toLowerCase();return t.includes("fail")||t.includes("error")?"tcp-badge-err":t.includes("warn")||t.includes("retry")?"tcp-badge-warn":"tcp-badge-info"}function wv(e){const t=e?.properties&&typeof e.properties=="object"?e.properties:{};return{type:Rr(e),path:String(t.path||e?.path||"").trim(),attachment_id:String(t.attachment_id||e?.attachment_id||"").trim(),connector:String(t.connector||e?.connector||"").trim(),channel_id:String(t.channel_id||e?.channel_id||"").trim(),sender_id:String(t.sender_id||e?.sender_id||"").trim(),pack_id:String(t.pack_id||e?.pack_id||"").trim(),name:String(t.name||e?.name||"").trim(),version:String(t.version||e?.version||"").trim(),error:String(t.error||e?.error||"").trim()}}function Sv(e,t){const n=[];return e.name&&n.push(`name: ${t(e.name)}`),e.version&&n.push(`version: ${t(e.version)}`),e.pack_id&&n.push(`pack_id: ${t(e.pack_id)}`),e.path&&n.push(`path: ${t(e.path)}`),e.connector&&n.push(`connector: ${t(e.connector)}`),e.channel_id&&n.push(`channel: ${t(e.channel_id)}`),e.sender_id&&n.push(`sender: ${t(e.sender_id)}`),n.join(" · ")}async function _v(e){const{byId:t,escapeHtml:n,state:s,addCleanup:r,toast:i,setRoute:a}=e;t("view").innerHTML=`
|
|
1327
|
+
<div class="tcp-card">
|
|
1328
|
+
<div class="mb-3 flex flex-wrap items-center justify-between gap-3">
|
|
1329
|
+
<h3 class="tcp-title flex items-center gap-2"><i data-lucide="activity"></i> Global Live Feed</h3>
|
|
1330
|
+
<div class="flex gap-2">
|
|
1331
|
+
<input id="feed-filter" class="tcp-input min-w-[220px]" placeholder="Filter by type or payload" />
|
|
1332
|
+
<button id="feed-clear" class="tcp-btn">Clear</button>
|
|
1333
|
+
</div>
|
|
1334
|
+
</div>
|
|
1335
|
+
<div id="feed-events" class="grid max-h-[68vh] gap-2 overflow-auto rounded-xl border border-slate-700 bg-black/20 p-2"></div>
|
|
1336
|
+
</div>
|
|
1337
|
+
`;const c=t("feed-events"),l=[];function d(){const m=t("feed-filter").value.trim().toLowerCase(),_=l.filter(b=>m?`${Rr(b.data)} ${JSON.stringify(b.data||{})}`.toLowerCase().includes(m):!0);c.innerHTML=_.map(b=>{const x=Rr(b.data);if(String(x).toLowerCase().startsWith("pack.")){const y=wv(b.data),I=Sv(y,n);return`
|
|
1338
|
+
<article class="tcp-list-item">
|
|
1339
|
+
<div class="flex items-center justify-between gap-2">
|
|
1340
|
+
<strong>${n(x)}</strong>
|
|
1341
|
+
<span class="${ba(x)}">${new Date(b.at).toLocaleTimeString()}</span>
|
|
1342
|
+
</div>
|
|
1343
|
+
<div class="tcp-subtle mt-1">${I||"pack lifecycle event"}</div>
|
|
1344
|
+
${y.error?`<div class="mt-1 text-xs text-rose-300">${n(y.error)}</div>`:""}
|
|
1345
|
+
<div class="mt-2 flex flex-wrap gap-2">
|
|
1346
|
+
<button class="tcp-btn" data-pack-open="1">Open Pack Library</button>
|
|
1347
|
+
${y.path?`<button class="tcp-btn" data-pack-install-path="${n(y.path)}">Install from Path</button>`:""}
|
|
1348
|
+
${y.path&&y.attachment_id?`<button class="tcp-btn" data-pack-install-attachment="${n(y.attachment_id)}" data-pack-path="${n(y.path)}" data-pack-connector="${n(y.connector)}" data-pack-channel="${n(y.channel_id)}" data-pack-sender="${n(y.sender_id)}">Install from Attachment</button>`:""}
|
|
1349
|
+
</div>
|
|
1350
|
+
<details class="mt-2">
|
|
1351
|
+
<summary class="cursor-pointer text-xs text-slate-400">Payload</summary>
|
|
1352
|
+
<pre class="tcp-code mt-2">${n(JSON.stringify(b.data,null,2))}</pre>
|
|
1353
|
+
</details>
|
|
1354
|
+
</article>
|
|
1355
|
+
`}return`
|
|
1356
|
+
<article class="tcp-list-item">
|
|
1357
|
+
<div class="flex items-center justify-between gap-2">
|
|
1358
|
+
<strong>${n(x)}</strong>
|
|
1359
|
+
<span class="${ba(x)}">${new Date(b.at).toLocaleTimeString()}</span>
|
|
1360
|
+
</div>
|
|
1361
|
+
<div class="tcp-subtle mt-1">session: ${n(b.data?.sessionID||b.data?.sessionId||"n/a")} run: ${n(b.data?.runID||b.data?.runId||"n/a")}</div>
|
|
1362
|
+
<details class="mt-2">
|
|
1363
|
+
<summary class="cursor-pointer text-xs text-slate-400">Payload</summary>
|
|
1364
|
+
<pre class="tcp-code mt-2">${n(JSON.stringify(b.data,null,2))}</pre>
|
|
1365
|
+
</details>
|
|
1366
|
+
</article>
|
|
1367
|
+
`}).join("")||'<p class="tcp-subtle">No events yet.</p>',c.querySelectorAll("[data-pack-open]").forEach(b=>{b.addEventListener("click",()=>{a?.("packs")})}),c.querySelectorAll("[data-pack-install-path]").forEach(b=>{b.addEventListener("click",async()=>{const x=String(b.getAttribute("data-pack-install-path")||"").trim();if(x)try{const y=await s.client.packs.install({path:x,source:{kind:"control_panel_feed",event:"pack.detected"}});i("ok",`Installed ${y?.installed?.name||"pack"} ${y?.installed?.version||""}`.trim())}catch(y){i("err",`Install failed: ${y instanceof Error?y.message:String(y)}`)}})}),c.querySelectorAll("[data-pack-install-attachment]").forEach(b=>{b.addEventListener("click",async()=>{const x=String(b.getAttribute("data-pack-install-attachment")||"").trim(),y=String(b.getAttribute("data-pack-path")||"").trim();if(!(!x||!y))try{const I=await s.client.packs.installFromAttachment({attachment_id:x,path:y,connector:String(b.getAttribute("data-pack-connector")||"").trim()||void 0,channel_id:String(b.getAttribute("data-pack-channel")||"").trim()||void 0,sender_id:String(b.getAttribute("data-pack-sender")||"").trim()||void 0});i("ok",`Installed ${I?.installed?.name||"pack"} ${I?.installed?.version||""}`.trim())}catch(I){i("err",`Install failed: ${I instanceof Error?I.message:String(I)}`)}})}),c.scrollTop=c.scrollHeight}const u=new EventSource("/api/engine/global/event",{withCredentials:!0});u.onmessage=m=>{try{const _=JSON.parse(m.data);for(l.push({at:Date.now(),data:_});l.length>300;)l.shift();s.route==="feed"&&d()}catch{}},u.onerror=()=>{u.close(),i("err","Live feed disconnected.")},t("feed-filter").addEventListener("input",d),t("feed-clear").addEventListener("click",()=>{l.length=0,d()}),r(()=>u.close()),d()}const ot="__custom_provider__",pc=["general","packs","channels","mcp","files"];function kv(){const e=String(window.location.hash||""),[,t=""]=e.split("?"),n=new URLSearchParams(t),s=String(n.get("tab")||"general").trim().toLowerCase();return pc.includes(s)?s:"general"}function xv(e){const t=pc.includes(String(e||"").toLowerCase())?String(e).toLowerCase():"general",n=new URLSearchParams;n.set("tab",t);const s=`#/settings?${n.toString()}`;window.location.hash!==s&&(window.location.hash=s)}async function di(e){const{byId:t,state:n,escapeHtml:s,renderIcons:r,THEMES:i=[],setTheme:a}=e,c=t("view"),l=!n.providerReady,d=kv(),u=l?"general":d;l&&d!=="general"&&window.location.hash!=="#/settings?tab=general"&&(window.location.hash="#/settings?tab=general"),c.innerHTML=`
|
|
1368
|
+
<div class="tcp-card">
|
|
1369
|
+
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
|
|
1370
|
+
<h3 class="tcp-title flex items-center gap-2"><i data-lucide="sliders-horizontal"></i> Settings</h3>
|
|
1371
|
+
<span class="tcp-badge-info">Unified Surface</span>
|
|
1372
|
+
</div>
|
|
1373
|
+
<p class="tcp-subtle mb-3">Configure platform behavior, integrations, and assets without leaving Settings.</p>
|
|
1374
|
+
${l?`<div class="mb-3 rounded-xl border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm text-amber-200">
|
|
1375
|
+
Complete provider + default model setup first. Other sections stay locked until this wizard is finished.
|
|
1376
|
+
</div>`:""}
|
|
1377
|
+
<div class="tcp-settings-tabs" role="tablist" aria-label="Settings sections">
|
|
1378
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${u==="general"?"active":""}" data-settings-tab="general" role="tab" aria-selected="${u==="general"}"><i data-lucide="settings-2"></i> General</button>
|
|
1379
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${u==="packs"?"active":""} ${l?"locked":""}" data-settings-tab="packs" role="tab" aria-selected="${u==="packs"}" ${l?'disabled aria-disabled="true"':""}><i data-lucide="package"></i> Packs</button>
|
|
1380
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${u==="channels"?"active":""} ${l?"locked":""}" data-settings-tab="channels" role="tab" aria-selected="${u==="channels"}" ${l?'disabled aria-disabled="true"':""}><i data-lucide="message-circle"></i> Channels</button>
|
|
1381
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${u==="mcp"?"active":""} ${l?"locked":""}" data-settings-tab="mcp" role="tab" aria-selected="${u==="mcp"}" ${l?'disabled aria-disabled="true"':""}><i data-lucide="link"></i> MCP</button>
|
|
1382
|
+
<button class="tcp-settings-tab tcp-settings-tab-underline ${u==="files"?"active":""} ${l?"locked":""}" data-settings-tab="files" role="tab" aria-selected="${u==="files"}" ${l?'disabled aria-disabled="true"':""}><i data-lucide="folder-open"></i> Files</button>
|
|
1383
|
+
</div>
|
|
1384
|
+
<div class="mt-4 border-t border-slate-800 pt-4">
|
|
1385
|
+
<div id="settings-tab-content" class="grid gap-4"></div>
|
|
1386
|
+
</div>
|
|
1387
|
+
</div>
|
|
1388
|
+
`,c.querySelectorAll("[data-settings-tab]").forEach(x=>x.addEventListener("click",()=>{if(x.disabled)return;const y=String(x.getAttribute("data-settings-tab")||"").trim().toLowerCase();xv(y)}));const m=t("settings-tab-content");if(!m)return;if(u==="general"){m.innerHTML=`
|
|
1389
|
+
<div class="tcp-card">
|
|
1390
|
+
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
|
|
1391
|
+
<h3 class="tcp-title flex items-center gap-2"><i data-lucide="sparkles"></i> Appearance</h3>
|
|
1392
|
+
<span class="tcp-badge-info">Theme Selector</span>
|
|
1393
|
+
</div>
|
|
1394
|
+
<p class="tcp-subtle mb-3">Pick the control-panel theme. Changes apply instantly across all pages.</p>
|
|
1395
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
1396
|
+
<div>
|
|
1397
|
+
<label class="mb-1 block text-sm text-slate-300">Theme</label>
|
|
1398
|
+
<select id="settings-theme-id" class="tcp-select">
|
|
1399
|
+
${i.map(y=>`<option value="${s(y.id)}" ${y.id===n.themeId?"selected":""}>${s(y.name)}</option>`).join("")}
|
|
1400
|
+
</select>
|
|
1401
|
+
</div>
|
|
1402
|
+
</div>
|
|
1403
|
+
<div class="theme-swatch-grid mt-3">
|
|
1404
|
+
${i.map(y=>`
|
|
1405
|
+
<button class="theme-swatch ${y.id===n.themeId?"active":""}" data-theme-select="${s(y.id)}" type="button">
|
|
1406
|
+
<span class="theme-swatch-dot" style="background:${s(y.cssVars["--color-primary"]||"#888")}"></span>
|
|
1407
|
+
<span>${s(y.name)}</span>
|
|
1408
|
+
</button>
|
|
1409
|
+
`).join("")}
|
|
1410
|
+
</div>
|
|
1411
|
+
</div>
|
|
1412
|
+
<div class="tcp-card">
|
|
1413
|
+
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
|
|
1414
|
+
<h3 class="tcp-title flex items-center gap-2"><i data-lucide="settings-2"></i> Provider Setup Wizard</h3>
|
|
1415
|
+
<span class="${n.providerReady?"tcp-badge-ok":"tcp-badge-warn"}">${n.providerReady?"Ready":"Not Configured"}</span>
|
|
1416
|
+
</div>
|
|
1417
|
+
<p class="tcp-subtle">Step 1: Select provider. Step 2: Configure model. Step 3: Add key (if required). Step 4: Run test. Step 5: Set bot identity + personality.</p>
|
|
1418
|
+
<div class="mt-3 flex flex-wrap gap-2">
|
|
1419
|
+
<span class="${n.providerDefault?"tcp-badge-ok":"tcp-badge-warn"}">Default: ${s(n.providerDefault||"none")}</span>
|
|
1420
|
+
<span class="${n.providerConnected.length>0?"tcp-badge-info":"tcp-badge-warn"}">Connected: ${n.providerConnected.length}</span>
|
|
1421
|
+
</div>
|
|
1422
|
+
${n.providerError?`<p class="mt-3 rounded-xl border border-amber-700/60 bg-amber-950/30 px-3 py-2 text-sm text-amber-300"><i data-lucide="triangle-alert"></i> ${s(n.providerError)}</p>`:""}
|
|
1423
|
+
<div id="provider-settings" class="mt-4"></div>
|
|
1424
|
+
<div id="identity-settings" class="mt-6 border-t border-slate-800 pt-5"></div>
|
|
1425
|
+
</div>
|
|
1426
|
+
<div class="tcp-card">
|
|
1427
|
+
<h3 class="tcp-title mb-2 flex items-center gap-2"><i data-lucide="shield"></i> Session Authorization</h3>
|
|
1428
|
+
<p class="tcp-subtle">Use Logout in the sidebar to clear your current portal session token binding.</p>
|
|
1429
|
+
</div>
|
|
1430
|
+
`;const x=y=>{const I=String(y||"").trim();!I||!a||(a(I),di(e))};t("settings-theme-id")?.addEventListener("change",y=>x(y?.target?.value)),c.querySelectorAll("[data-theme-select]").forEach(y=>y.addEventListener("click",()=>x(y.getAttribute("data-theme-select")))),await $v(e,t("provider-settings")),await Ev(e,t("identity-settings")),r(c);return}m.innerHTML='<div id="settings-subview-host" class="grid gap-4"></div>';const _=t("settings-subview-host");if(!_)return;const b={...e,embeddedInSettings:!0,byId:x=>x==="view"?_:_.querySelector(`#${x}`)};u==="packs"?await cc(b):u==="channels"?await Ds(b):u==="mcp"?await en(b):u==="files"&&await uc(b),r(c)}async function $v(e,t){const{state:n,api:s,toast:r,escapeHtml:i,providerHints:a,refreshProviderStatus:c,renderIcons:l}=e,d=await n.client.providers.catalog(),u=await n.client.providers.config();let m=await n.client.providers.authStatus().catch(()=>({}));const _=d.all||[],b=new Set(_.map(Z=>Z.id)),x=String(d.default||u.default||_[0]?.id||"").trim();let y=b.has(x)?x:ot,I="",g=y===ot?x:"",C=g?String(u.providers?.[g]?.url||""):"",O=g?String(u.providers?.[g]?.defaultModel||u.providers?.[g]?.default_model||""):"",P=!1;const j=()=>{if(y===ot)return;const Z=_.find(U=>U.id===y),le=Object.keys(Z?.models||{}),ee=u.providers?.[y]||{};I=ee.defaultModel||ee.default_model||le[0]||""};j();const Y=[..._.map(Z=>({id:Z.id,label:a[Z.id]?.label||Z.name||Z.id})),{id:ot,label:"Custom Provider"}],N=Z=>String(Z||"").trim().toLowerCase(),z=Z=>{const le=N(Z);if(!le)return!1;const ee=m;if(ee&&typeof ee=="object"){const U=ee[le];if(U&&typeof U=="object"&&(U.has_key===!0||U.hasKey===!0||U.configured===!0||U.connected===!0))return!0;if(ee.providers&&typeof ee.providers=="object"){const se=ee.providers[le];if(se&&typeof se=="object"&&(se.has_key===!0||se.hasKey===!0||se.configured===!0||se.connected===!0))return!0}}return!1},D=Z=>{const le=N(Z);return!!le&&le!=="ollama"&&le!=="local"},R=()=>{const Z=y===ot?[]:Object.keys((_.find(ne=>ne.id===y)||{}).models||{}),ee=z(y===ot?g:y),U=!ee||P;t.innerHTML=`
|
|
1431
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
1432
|
+
<div>
|
|
1433
|
+
<label class="mb-1 block text-sm text-slate-300">Provider</label>
|
|
1434
|
+
<select id="provider-select" class="tcp-select">
|
|
1435
|
+
${Y.map(ne=>`<option value="${i(ne.id)}" ${ne.id===y?"selected":""}>${i(ne.label)}</option>`).join("")}
|
|
1436
|
+
</select>
|
|
1437
|
+
</div>
|
|
1438
|
+
${y===ot?`<div>
|
|
1439
|
+
<label class="mb-1 block text-sm text-slate-300">Custom Provider ID</label>
|
|
1440
|
+
<input id="custom-provider-id" class="tcp-input" placeholder="my-provider" value="${i(g)}" />
|
|
1441
|
+
</div>`:`<div>
|
|
1442
|
+
<label class="mb-1 block text-sm text-slate-300">Model</label>
|
|
1443
|
+
<select id="provider-model" class="tcp-select">${Z.map(ne=>`<option ${ne===I?"selected":""}>${i(ne)}</option>`).join("")}</select>
|
|
1444
|
+
</div>`}
|
|
1445
|
+
</div>
|
|
1446
|
+
|
|
1447
|
+
${y===ot?`<div class="mt-3 grid gap-3 md:grid-cols-2">
|
|
1448
|
+
<div>
|
|
1449
|
+
<label class="mb-1 block text-sm text-slate-300">Base URL</label>
|
|
1450
|
+
<input id="custom-provider-url" class="tcp-input" placeholder="https://api.example.com/v1" value="${i(C)}" />
|
|
1451
|
+
</div>
|
|
1452
|
+
<div>
|
|
1453
|
+
<label class="mb-1 block text-sm text-slate-300">Default Model</label>
|
|
1454
|
+
<input id="custom-provider-model" class="tcp-input" placeholder="gpt-4o-mini" value="${i(O)}" />
|
|
1455
|
+
</div>
|
|
1456
|
+
</div>
|
|
1457
|
+
<p class="tcp-subtle mt-2">Custom providers use OpenAI-compatible chat completions endpoints.</p>`:""}
|
|
1458
|
+
|
|
1459
|
+
<div class="mt-3 grid gap-3 md:grid-cols-2">
|
|
1460
|
+
<div>
|
|
1461
|
+
<label class="mb-1 block text-sm text-slate-300">API Key (optional)</label>
|
|
1462
|
+
<input id="provider-key" class="tcp-input" type="password" placeholder="${i(a[y]?.placeholder||"sk-...")}" ${U?"":"disabled"} />
|
|
1463
|
+
<p class="mt-1 text-xs ${ee?"text-lime-300":"text-amber-300"}">
|
|
1464
|
+
${ee?"A key is already stored for this provider. Leave blank to keep it.":"No stored key detected for this provider."}
|
|
1465
|
+
</p>
|
|
1466
|
+
${ee?`<div class="mt-2 flex flex-wrap gap-2">
|
|
1467
|
+
<button id="provider-toggle-replace-key" class="tcp-btn h-8 px-2.5 text-xs">${P?"Keep existing key":"Replace key"}</button>
|
|
1468
|
+
<button id="provider-clear-key" class="tcp-btn-danger h-8 px-2.5 text-xs">Clear stored key</button>
|
|
1469
|
+
</div>`:""}
|
|
1470
|
+
</div>
|
|
1471
|
+
<div class="flex items-end justify-end gap-2">
|
|
1472
|
+
<button id="provider-test" class="tcp-btn"><i data-lucide="flask-conical"></i> Test Model Run</button>
|
|
1473
|
+
<button id="provider-save" class="tcp-btn-primary"><i data-lucide="save"></i> Save Provider</button>
|
|
1474
|
+
</div>
|
|
1475
|
+
</div>
|
|
1476
|
+
<div id="provider-test-status" class="mt-2 text-xs tcp-subtle"></div>
|
|
1477
|
+
`,t.querySelector("#provider-select").addEventListener("change",ne=>{y=ne.target.value,y!==ot&&j(),R()});const se=t.querySelector("#provider-model");se&&se.addEventListener("change",ne=>I=ne.target.value);const re=t.querySelector("#custom-provider-id");re&&re.addEventListener("input",ne=>g=ne.target.value.trim());const ue=t.querySelector("#custom-provider-url");ue&&ue.addEventListener("input",ne=>C=ne.target.value.trim());const ce=t.querySelector("#custom-provider-model");ce&&ce.addEventListener("input",ne=>O=ne.target.value.trim());const Ee=t.querySelector("#provider-toggle-replace-key");Ee&&Ee.addEventListener("click",()=>{P=!P,R()});const ve=t.querySelector("#provider-clear-key");ve&&ve.addEventListener("click",async()=>{const ne=N(y===ot?g:y);if(!ne){r("err","Select a provider first.");return}try{await s(`/api/engine/auth/${encodeURIComponent(ne)}`,{method:"DELETE"}),m=await n.client.providers.authStatus().catch(()=>m),P=!0,r("ok",`Cleared stored key for ${ne}.`),R()}catch(X){r("err",X instanceof Error?X.message:String(X))}});const je=async({quiet:ne=!1}={})=>{const X=t.querySelector("#provider-key")?.value?.trim?.()||"",$e=N(y===ot?g:y),me=z($e),de=X.length>0;if(y===ot){const fe=N(g);if(!fe)throw new Error("Custom provider ID is required.");if(!C)throw new Error("Custom provider URL is required.");if(!O)throw new Error("Custom default model is required.");if(await s("/api/engine/config",{method:"PATCH",body:JSON.stringify({default_provider:fe,providers:{[fe]:{url:C,default_model:O}}})}),me&&P&&!X)throw new Error("Enter a new API key or keep existing key.");de&&await n.client.providers.setApiKey(fe,X)}else{if(!y)throw new Error("Select a provider first.");if(!I)throw new Error("Select a default model first.");if(me&&P&&!X)throw new Error("Enter a new API key or keep existing key.");de&&await n.client.providers.setApiKey(y,X),await n.client.providers.setDefaults(y,I)}await c(),de&&(m=await n.client.providers.authStatus().catch(()=>m),P=!1),ne||r("ok","Provider configuration saved.")};t.querySelector("#provider-save").addEventListener("click",async()=>{const ne=t.querySelector("#provider-save");try{ne.disabled=!0,await je(),di(e)}catch(X){r("err",X instanceof Error?X.message:String(X))}finally{ne.disabled=!1}}),t.querySelector("#provider-test").addEventListener("click",async()=>{const ne=t.querySelector("#provider-test"),X=t.querySelector("#provider-test-status"),$e=ne.innerHTML,me=25e3,de=async(fe,pe,be)=>{const k=Date.now();for(;Date.now()-k<be;){const T=await n.client.sessions.activeRun(fe).catch(()=>({active:null})),M=String(T?.active?.runId||"").trim();if(!M||pe&&M!==pe)return!0;await new Promise(K=>setTimeout(K,500))}return!1};try{ne.disabled=!0,ne.innerHTML='<i data-lucide="flask-conical"></i> Testing...',l?.(t),X&&(X.className="mt-2 text-xs tcp-subtle",X.textContent="Saving provider settings and running a test request..."),await je({quiet:!0});const fe=N(y===ot?g:y),pe=String(y===ot?O:I).trim();if(!fe)throw new Error("Select a provider before running the model test.");if(!pe)throw new Error("Select a default model before running the model test.");if(D(fe)&&!z(fe))throw new Error("No stored key detected for this provider. Save a valid API key first.");const be=async()=>{const T=await n.client.sessions.create({title:`__provider_test__ ${new Date().toISOString()}`,directory:"/tmp/tandem-provider-test",provider:fe,model:pe});try{const{runId:M}=await n.client.sessions.promptAsync(T,"READY",{provider:fe,model:pe},{toolMode:"none",contextMode:"none"});if(X&&(X.className="mt-2 text-xs tcp-subtle",X.textContent="Run accepted. Waiting for provider response..."),!await de(T,String(M||"").trim(),me))throw await n.client.sessions.cancelRun(T,String(M||"").trim()).catch(()=>{}),await n.client.sessions.cancel(T).catch(()=>{}),new Error("Model test timed out after 25s. Provider is reachable but response is slow.");const J=await n.client.runEvents(String(M||"").trim(),{tail:80}).catch(()=>[]),q=J.find(ye=>String(ye?.type||"").trim()==="provider.call.error");if(q){const ye=q?.properties||{},Ie=String(ye?.detail||ye?.error||"").trim(),_e=String(ye?.error_code||"").trim();throw new Error(`Provider call failed${_e?` (${_e})`:""}${Ie?`: ${Ie}`:""}`)}const ie=(await n.client.sessions.messages(T).catch(()=>[])).map(ye=>(ye.parts||[]).map(Ie=>String(Ie?.text||"")).join(`
|
|
1478
|
+
`)).join(`
|
|
1479
|
+
`).trim();if(!ie){const ye=J.map(_e=>String(_e?.type||"").trim()).filter(Boolean),Ie=ye.length?` Events: ${ye.slice(-8).join(", ")}`:"";throw new Error(`Run finished but no assistant response was returned.${Ie}`)}return ie}finally{await n.client.sessions.delete(T).catch(()=>{})}};let k="";try{k=await be()}catch(T){const M=T instanceof Error?T.message:String(T);if(/BodyStreamBuffer was aborted/i.test(M))X&&(X.className="mt-2 text-xs text-amber-300",X.textContent="Provider stream aborted once. Retrying test..."),k=await be();else throw T}if(await c(),X){X.className="mt-2 text-xs text-lime-300";const T=k.toUpperCase();X.textContent=T.includes("READY")?"Model test succeeded.":`Model responded successfully: ${k.slice(0,140)}`}r("ok","Model run test completed.")}catch(fe){const pe=fe instanceof Error?fe.message:String(fe),be=/BodyStreamBuffer was aborted/i.test(pe)?"Provider stream was aborted. Check provider credentials/network, then retry.":pe;X&&(X.className="mt-2 text-xs text-rose-300",X.textContent=be),r("err",be)}finally{ne.disabled=!1,ne.innerHTML=$e,l?.(t)}}),l?.(t)};R()}async function Ev(e,t){const{state:n,toast:s,escapeHtml:r,refreshIdentityStatus:i,renderShell:a,renderIcons:c,api:l}=e,d=async()=>n.client?.identity?.get?n.client.identity.get():l("/api/engine/config/identity",{method:"GET"}),u=async z=>n.client?.identity?.patch?n.client.identity.patch(z):l("/api/engine/config/identity",{method:"PATCH",body:JSON.stringify(z)});let m;try{m=await d()}catch(z){t.innerHTML=`
|
|
1480
|
+
<p class="rounded-xl border border-rose-700/60 bg-rose-950/30 px-3 py-2 text-sm text-rose-300">
|
|
1481
|
+
Failed to load identity settings: ${r(z instanceof Error?z.message:String(z))}
|
|
1482
|
+
</p>
|
|
1483
|
+
`;return}const _=m?.identity||{},b=_?.bot||{},x=b?.aliases||{},I=(_?.personality||{})?.default||{},g=Array.isArray(m?.presets)&&m.presets.length>0?m.presets:[{id:"balanced",label:"Balanced"},{id:"concise",label:"Concise"},{id:"friendly",label:"Friendly"},{id:"mentor",label:"Mentor"},{id:"critical",label:"Critical"}];let C=String(b?.canonical_name||b?.canonicalName||"").trim(),O=String(b?.avatar_url||b?.avatarUrl||"").trim(),P=String(x?.control_panel||x?.controlPanel||"").trim(),j=String(I?.preset||"balanced").trim()||"balanced",Y=String(I?.custom_instructions||I?.customInstructions||"").trim();const N=()=>{t.innerHTML=`
|
|
1484
|
+
<div class="mb-3">
|
|
1485
|
+
<h4 class="tcp-title flex items-center gap-2"><i data-lucide="bot"></i> Identity & Personality</h4>
|
|
1486
|
+
<p class="tcp-subtle mt-1">Control assistant naming and default response style.</p>
|
|
1487
|
+
</div>
|
|
1488
|
+
|
|
1489
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
1490
|
+
<div>
|
|
1491
|
+
<label class="mb-1 block text-sm text-slate-300">Canonical bot name</label>
|
|
1492
|
+
<input id="identity-canonical-name" class="tcp-input" placeholder="Assistant" value="${r(C)}" />
|
|
1493
|
+
</div>
|
|
1494
|
+
<div>
|
|
1495
|
+
<label class="mb-1 block text-sm text-slate-300">Control panel alias (optional)</label>
|
|
1496
|
+
<input id="identity-control-panel-alias" class="tcp-input" placeholder="Assistant Control Panel" value="${r(P)}" />
|
|
1497
|
+
</div>
|
|
1498
|
+
</div>
|
|
1499
|
+
|
|
1500
|
+
<div class="mt-3">
|
|
1501
|
+
<label class="mb-1 block text-sm text-slate-300">Avatar (optional)</label>
|
|
1502
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
1503
|
+
<div class="h-10 w-10 overflow-hidden rounded-xl border border-slate-600 bg-muted">
|
|
1504
|
+
<img src="${r(O||"/tandem-logo.png")}" alt="${r(C||"Assistant")}" class="h-full w-full object-cover" />
|
|
1505
|
+
</div>
|
|
1506
|
+
<input id="identity-avatar-file" type="file" accept="image/png,image/jpeg,image/webp,image/gif" class="tcp-input !h-auto !py-1.5 text-xs" />
|
|
1507
|
+
${O?'<button id="identity-avatar-clear" class="tcp-btn h-8 px-2 text-xs">Remove</button>':""}
|
|
1508
|
+
</div>
|
|
1509
|
+
</div>
|
|
1510
|
+
|
|
1511
|
+
<div class="mt-3 grid gap-3 md:grid-cols-2">
|
|
1512
|
+
<div>
|
|
1513
|
+
<label class="mb-1 block text-sm text-slate-300">Personality preset</label>
|
|
1514
|
+
<select id="identity-preset" class="tcp-select">
|
|
1515
|
+
${g.map(R=>`<option value="${r(R.id)}" ${R.id===j?"selected":""}>${r(R.label||R.id)}</option>`).join("")}
|
|
1516
|
+
</select>
|
|
1517
|
+
</div>
|
|
1518
|
+
</div>
|
|
1519
|
+
|
|
1520
|
+
<div class="mt-3">
|
|
1521
|
+
<label class="mb-1 block text-sm text-slate-300">Custom personality instructions (optional)</label>
|
|
1522
|
+
<textarea id="identity-custom-instructions" class="tcp-input min-h-[96px]" rows="4" placeholder="Keep responses concise and operationally focused.">${r(Y)}</textarea>
|
|
1523
|
+
</div>
|
|
1524
|
+
|
|
1525
|
+
<div class="mt-3 flex items-center justify-end gap-2">
|
|
1526
|
+
<button id="identity-save" class="tcp-btn-primary"><i data-lucide="save"></i> Save Identity</button>
|
|
1527
|
+
</div>
|
|
1528
|
+
`,t.querySelector("#identity-canonical-name").addEventListener("input",R=>{C=R.target.value}),t.querySelector("#identity-control-panel-alias").addEventListener("input",R=>{P=R.target.value});const z=t.querySelector("#identity-avatar-file");z&&z.addEventListener("change",async R=>{const Z=R.target?.files?.[0];if(!Z)return;if(Z.size>10*1024*1024){s("err","Avatar image is too large (max 10 MB).");return}const le=new FileReader;le.onload=()=>{const ee=typeof le.result=="string"?le.result:"";if(!ee){s("err","Failed to read avatar file.");return}O=ee,N()},le.onerror=()=>s("err","Failed to read avatar file."),le.readAsDataURL(Z)});const D=t.querySelector("#identity-avatar-clear");D&&D.addEventListener("click",()=>{O="",N()}),t.querySelector("#identity-preset").addEventListener("change",R=>{j=R.target.value}),t.querySelector("#identity-custom-instructions").addEventListener("input",R=>{Y=R.target.value}),t.querySelector("#identity-save").addEventListener("click",async()=>{try{const R=C.trim();if(!R)throw new Error("Canonical bot name is required.");const Z=P.trim(),le=Y.trim(),ee=await u({identity:{bot:{canonical_name:R,avatar_url:O||null,aliases:{control_panel:Z||void 0}},personality:{default:{preset:j||"balanced",custom_instructions:le||null}}}});await i(),a(),s("ok","Identity settings saved."),m=ee,C=String(ee?.identity?.bot?.canonical_name||"").trim(),O=String(ee?.identity?.bot?.avatar_url||"").trim(),P=String(ee?.identity?.bot?.aliases?.control_panel||"").trim(),j=String(ee?.identity?.personality?.default?.preset||"balanced").trim()||"balanced",Y=String(ee?.identity?.personality?.default?.custom_instructions||"").trim(),N()}catch(R){s("err",R instanceof Error?R.message:String(R))}}),c?.(t)};N()}const wa={dashboard:Qg,chat:av,agents:ft,channels:Ds,mcp:en,packs:cc,swarm:Bn,files:uc,memory:Mr,teams:Ts,feed:_v,settings:di};const mc={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const fc=([e,t,n])=>{const s=document.createElementNS("http://www.w3.org/2000/svg",e);return Object.keys(t).forEach(r=>{s.setAttribute(r,String(t[r]))}),n?.length&&n.forEach(r=>{const i=fc(r);s.appendChild(i)}),s},Tv=(e,t={})=>{const s={...mc,...t};return fc(["svg",s,e])};const Av=e=>{for(const t in e)if(t.startsWith("aria-")||t==="role"||t==="title")return!0;return!1};const Iv=(...e)=>e.filter((t,n,s)=>!!t&&t.trim()!==""&&s.indexOf(t)===n).join(" ").trim();const Cv=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,n,s)=>s?s.toUpperCase():n.toLowerCase());const Mv=e=>{const t=Cv(e);return t.charAt(0).toUpperCase()+t.slice(1)};const Rv=e=>Array.from(e.attributes).reduce((t,n)=>(t[n.name]=n.value,t),{}),Sa=e=>typeof e=="string"?e:!e||!e.class?"":e.class&&typeof e.class=="string"?e.class.split(" "):e.class&&Array.isArray(e.class)?e.class:"",_a=(e,{nameAttr:t,icons:n,attrs:s})=>{const r=e.getAttribute(t);if(r==null)return;const i=Mv(r),a=n[i];if(!a)return console.warn(`${e.outerHTML} icon name was not found in the provided icons object.`);const c=Rv(e),l=Av(c)?{}:{"aria-hidden":"true"},d={...mc,"data-lucide":r,...l,...s,...c},u=Sa(c),m=Sa(s),_=Iv("lucide",`lucide-${r}`,...u,...m);_&&Object.assign(d,{class:_});const b=Tv(a,d);return e.parentNode?.replaceChild(b,e)};const Pv=[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"}]];const Lv=[["rect",{width:"20",height:"5",x:"2",y:"3",rx:"1"}],["path",{d:"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"}],["path",{d:"M10 12h4"}]];const Ov=[["path",{d:"M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z"}],["path",{d:"m9 12 2 2 4-4"}]];const zv=[["rect",{x:"14",y:"14",width:"4",height:"6",rx:"2"}],["rect",{x:"6",y:"4",width:"4",height:"6",rx:"2"}],["path",{d:"M6 20h4"}],["path",{d:"M14 10h4"}],["path",{d:"M6 14h2v6"}],["path",{d:"M14 4h2v6"}]];const Nv=[["path",{d:"M12 8V4H8"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2"}],["path",{d:"M2 14h2"}],["path",{d:"M20 14h2"}],["path",{d:"M15 13v2"}],["path",{d:"M9 13v2"}]];const Dv=[["circle",{cx:"12",cy:"12",r:"10"}],["path",{d:"m16 12-4-4-4 4"}],["path",{d:"M12 16V8"}]];const jv=[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"}],["path",{d:"M12 11h4"}],["path",{d:"M12 16h4"}],["path",{d:"M8 11h.01"}],["path",{d:"M8 16h.01"}]];const qv=[["circle",{cx:"12",cy:"12",r:"10"}],["path",{d:"M12 6v6h4"}]];const Fv=[["circle",{cx:"12",cy:"12",r:"10"}],["path",{d:"M12 6v6l4 2"}]];const Uv=[["line",{x1:"15",x2:"15",y1:"12",y2:"18"}],["line",{x1:"12",x2:"18",y1:"15",y2:"15"}],["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"}]];const Vv=[["path",{d:"M12 20v2"}],["path",{d:"M12 2v2"}],["path",{d:"M17 20v2"}],["path",{d:"M17 2v2"}],["path",{d:"M2 12h2"}],["path",{d:"M2 17h2"}],["path",{d:"M2 7h2"}],["path",{d:"M20 12h2"}],["path",{d:"M20 17h2"}],["path",{d:"M20 7h2"}],["path",{d:"M7 20v2"}],["path",{d:"M7 2v2"}],["rect",{x:"4",y:"4",width:"16",height:"16",rx:"2"}],["rect",{x:"8",y:"8",width:"8",height:"8",rx:"1"}]];const Zv=[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5"}],["path",{d:"M3 12A9 3 0 0 0 21 12"}]];const Hv=[["path",{d:"M12 15V3"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}],["path",{d:"m7 10 5 5 5-5"}]];const Bv=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5"}],["path",{d:"M12 12v6"}],["path",{d:"m15 15-3-3-3 3"}]];const Jv=[["path",{d:"M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"}],["path",{d:"M6.453 15h11.094"}],["path",{d:"M8.5 2h7"}]];const Kv=[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2"}]];const Gv=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"}]];const Wv=[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor"}]];const Yv=[["path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"}],["path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"}]];const Xv=[["path",{d:"M3 5h.01"}],["path",{d:"M3 12h.01"}],["path",{d:"M3 19h.01"}],["path",{d:"M8 5h13"}],["path",{d:"M8 12h13"}],["path",{d:"M8 19h13"}]];const Qv=[["path",{d:"m16 17 5-5-5-5"}],["path",{d:"M21 12H9"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"}]];const ey=[["path",{d:"M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719"}]];const ty=[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"}]];const ny=[["path",{d:"M16 10a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 14.286V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"}],["path",{d:"M20 9a2 2 0 0 1 2 2v10.286a.71.71 0 0 1-1.212.502l-2.202-2.202A2 2 0 0 0 17.172 19H10a2 2 0 0 1-2-2v-1"}]];const sy=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"}],["path",{d:"M12 22V12"}],["polyline",{points:"3.29 7 12 12 20.71 7"}],["path",{d:"m7.5 4.27 9 5.15"}]];const ry=[["path",{d:"m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"}]];const iy=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"}],["path",{d:"m15 5 4 4"}]];const ay=[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"}]];const oy=[["path",{d:"M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z"}],["path",{d:"m2 22 3-3"}],["path",{d:"M7.5 13.5 10 11"}],["path",{d:"M10.5 16.5 13 14"}],["path",{d:"m18 3-4 4h6l-4 4"}]];const cy=[["path",{d:"M5 12h14"}],["path",{d:"M12 5v14"}]];const ly=[["path",{d:"M16.247 7.761a6 6 0 0 1 0 8.478"}],["path",{d:"M19.075 4.933a10 10 0 0 1 0 14.134"}],["path",{d:"M4.925 19.067a10 10 0 0 1 0-14.134"}],["path",{d:"M7.753 16.239a6 6 0 0 1 0-8.478"}],["circle",{cx:"12",cy:"12",r:"2"}]];const dy=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"}],["path",{d:"M21 3v5h-5"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"}],["path",{d:"M8 16H3v5"}]];const uy=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7"}]];const py=[["path",{d:"m21 21-4.34-4.34"}],["circle",{cx:"11",cy:"11",r:"8"}]];const my=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"}],["path",{d:"m21.854 2.147-10.94 10.939"}]];const fy=[["path",{d:"M14 17H5"}],["path",{d:"M19 7h-9"}],["circle",{cx:"17",cy:"17",r:"3"}],["circle",{cx:"7",cy:"7",r:"3"}]];const hy=[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"}],["circle",{cx:"12",cy:"12",r:"3"}]];const gy=[["circle",{cx:"18",cy:"5",r:"3"}],["circle",{cx:"6",cy:"12",r:"3"}],["circle",{cx:"18",cy:"19",r:"3"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49"}]];const vy=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["path",{d:"m9 12 2 2 4-4"}]];const yy=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}]];const by=[["path",{d:"M10 5H3"}],["path",{d:"M12 19H3"}],["path",{d:"M14 3v4"}],["path",{d:"M16 17v4"}],["path",{d:"M21 12h-9"}],["path",{d:"M21 19h-5"}],["path",{d:"M21 5h-7"}],["path",{d:"M8 10v4"}],["path",{d:"M8 12H3"}]];const wy=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"}],["path",{d:"M20 2v4"}],["path",{d:"M22 4h-4"}],["circle",{cx:"4",cy:"20",r:"2"}]];const Sy=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}]];const _y=[["path",{d:"M10 11v6"}],["path",{d:"M14 11v6"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"}],["path",{d:"M3 6h18"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"}]];const ky=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"}],["path",{d:"M12 9v4"}],["path",{d:"M12 17h.01"}]];const xy=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87"}],["circle",{cx:"9",cy:"7",r:"4"}]];const $y=[["rect",{width:"8",height:"8",x:"3",y:"3",rx:"2"}],["path",{d:"M7 11v4a2 2 0 0 0 2 2h4"}],["rect",{width:"8",height:"8",x:"13",y:"13",rx:"2"}]];const Ey=[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]];const hc=({icons:e={},nameAttr:t="data-lucide",attrs:n={},root:s=document,inTemplates:r}={})=>{if(!Object.values(e).length)throw new Error(`Please provide an icons object.
|
|
1529
|
+
If you want to use all the icons you can import it like:
|
|
1530
|
+
\`import { createIcons, icons } from 'lucide';
|
|
1531
|
+
lucide.createIcons({icons});\``);if(typeof s>"u")throw new Error("`createIcons()` only works in a browser environment.");if(Array.from(s.querySelectorAll(`[${t}]`)).forEach(a=>_a(a,{nameAttr:t,icons:e,attrs:n})),r&&Array.from(s.querySelectorAll("template")).forEach(c=>hc({icons:e,nameAttr:t,attrs:n,root:c.content,inTemplates:r})),t==="data-lucide"){const a=s.querySelectorAll("[icon-name]");a.length>0&&(console.warn("[Lucide] Some icons were found with the now deprecated icon-name attribute. These will still be replaced for backwards compatibility, but will no longer be supported in v1.0 and you should switch to data-lucide"),Array.from(a).forEach(c=>_a(c,{nameAttr:"icon-name",icons:e,attrs:n})))}},Ty={Activity:Pv,Archive:Lv,ArrowUpCircle:Dv,BadgeCheck:Ov,Binary:zv,Bot:Nv,ClipboardList:jv,Clock:Fv,Clock3:qv,CopyPlus:Uv,Cpu:Vv,Database:Zv,Download:Hv,FileUp:Bv,FlaskConical:Jv,FolderOpen:Kv,Home:Gv,KeyRound:Wv,Link:Yv,List:Xv,LogOut:Qv,MessageCircle:ey,MessageSquare:ty,MessagesSquare:ny,Paperclip:ry,Package:sy,Pencil:iy,Play:ay,PlugZap:oy,Plus:cy,Radio:ly,RefreshCw:dy,Save:uy,Search:py,Send:my,Settings:hy,Settings2:fy,ShieldCheck:vy,SlidersHorizontal:by,Sparkles:wy,Share2:gy,Shield:yy,Square:Sy,Trash2:_y,TriangleAlert:ky,X:Ey,Users:xy,Workflow:$y};function Ws(e){hc({icons:Ty,attrs:{width:"16",height:"16","stroke-width":"1.8"},...e?{root:e}:{}})}const gc="web_control",vc="tandem.themeId",Pr=[{id:"web_control",name:"Web Control",cssVars:{"--color-background":"#121212","--color-surface":"#141414","--color-surface-elevated":"#1a1a1a","--color-border":"rgba(245, 245, 245, 0.10)","--color-border-subtle":"rgba(245, 245, 245, 0.06)","--color-primary":"#F59E0B","--color-primary-hover":"#D97706","--color-primary-muted":"#B45309","--color-secondary":"#EF4444","--color-secondary-hover":"#DC2626","--color-success":"#10B981","--color-warning":"#F59E0B","--color-error":"#EF4444","--color-text":"#F5F5F5","--color-text-muted":"rgba(245, 245, 245, 0.70)","--color-text-subtle":"rgba(245, 245, 245, 0.50)","--color-glass":"rgba(255, 255, 255, 0.03)","--color-glass-border":"rgba(255, 255, 255, 0.08)","--font-sans":'"Geist Sans", "Inter", system-ui, -apple-system, sans-serif',"--font-mono":'"Geist Mono", "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace',"--tcp-glow-a":"rgba(245, 158, 11, 0.16)","--tcp-glow-b":"rgba(239, 68, 68, 0.12)"}},{id:"electric_blue",name:"Electric Blue",cssVars:{"--color-background":"#0a0a0f","--color-surface":"#12121a","--color-surface-elevated":"#1a1a24","--color-border":"#2a2a3a","--color-border-subtle":"#1f1f2e","--color-primary":"#3b82f6","--color-primary-hover":"#2563eb","--color-primary-muted":"#1d4ed8","--color-secondary":"#8b5cf6","--color-secondary-hover":"#7c3aed","--color-success":"#10b981","--color-warning":"#f59e0b","--color-error":"#ef4444","--color-text":"#f8fafc","--color-text-muted":"#94a3b8","--color-text-subtle":"#64748b","--color-glass":"rgba(18, 18, 26, 0.8)","--color-glass-border":"rgba(255, 255, 255, 0.1)","--font-sans":'"Inter", system-ui, -apple-system, sans-serif',"--font-mono":'"JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace',"--tcp-glow-a":"rgba(59, 130, 246, 0.16)","--tcp-glow-b":"rgba(139, 92, 246, 0.12)"}},{id:"emerald_night",name:"Emerald Night",cssVars:{"--color-background":"#0b1010","--color-surface":"#0f1616","--color-surface-elevated":"#142020","--color-border":"rgba(226, 232, 240, 0.12)","--color-border-subtle":"rgba(226, 232, 240, 0.08)","--color-primary":"#10B981","--color-primary-hover":"#059669","--color-primary-muted":"#047857","--color-secondary":"#22D3EE","--color-secondary-hover":"#06B6D4","--color-success":"#22C55E","--color-warning":"#F59E0B","--color-error":"#EF4444","--color-text":"#F1F5F9","--color-text-muted":"rgba(241, 245, 249, 0.72)","--color-text-subtle":"rgba(241, 245, 249, 0.52)","--color-glass":"rgba(15, 22, 22, 0.75)","--color-glass-border":"rgba(255, 255, 255, 0.10)","--font-sans":'"Geist Sans", "Inter", system-ui, -apple-system, sans-serif',"--font-mono":'"Geist Mono", "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace',"--tcp-glow-a":"rgba(16, 185, 129, 0.16)","--tcp-glow-b":"rgba(34, 211, 238, 0.12)"}},{id:"hello_bunny",name:"Hello Bunny",cssVars:{"--color-background":"#140A12","--color-surface":"#1C0E1A","--color-surface-elevated":"#251022","--color-border":"rgba(255, 228, 242, 0.12)","--color-border-subtle":"rgba(255, 228, 242, 0.08)","--color-primary":"#FB7185","--color-primary-hover":"#F43F5E","--color-primary-muted":"#E11D48","--color-secondary":"#C084FC","--color-secondary-hover":"#A855F7","--color-success":"#34D399","--color-warning":"#FBBF24","--color-error":"#FB7185","--color-text":"#FFEAF4","--color-text-muted":"rgba(255, 234, 244, 0.74)","--color-text-subtle":"rgba(255, 234, 244, 0.52)","--color-glass":"rgba(255, 255, 255, 0.04)","--color-glass-border":"rgba(255, 228, 242, 0.10)","--font-sans":'"Geist Sans", "Inter", system-ui, -apple-system, sans-serif',"--font-mono":'"Geist Mono", "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace',"--tcp-glow-a":"rgba(251, 113, 133, 0.16)","--tcp-glow-b":"rgba(192, 132, 252, 0.12)"}},{id:"porcelain",name:"Porcelain",cssVars:{"--color-background":"#F8FAFC","--color-surface":"#FFFFFF","--color-surface-elevated":"#F1F5F9","--color-border":"rgba(15, 23, 42, 0.20)","--color-border-subtle":"rgba(15, 23, 42, 0.14)","--color-primary":"#6366F1","--color-primary-hover":"#4F46E5","--color-primary-muted":"#4338CA","--color-secondary":"#F472B6","--color-secondary-hover":"#EC4899","--color-success":"#10B981","--color-warning":"#F59E0B","--color-error":"#EF4444","--color-text":"#0B1220","--color-text-muted":"rgba(11, 18, 32, 0.82)","--color-text-subtle":"rgba(11, 18, 32, 0.66)","--color-glass":"rgba(255, 255, 255, 0.72)","--color-glass-border":"rgba(15, 23, 42, 0.10)","--font-sans":'"Geist Sans", "Inter", system-ui, -apple-system, sans-serif',"--font-mono":'"Geist Mono", "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace',"--tcp-glow-a":"rgba(99, 102, 241, 0.13)","--tcp-glow-b":"rgba(244, 114, 182, 0.11)"}},{id:"neon_riot",name:"Neon Riot",cssVars:{"--color-background":"#050014","--color-surface":"#0B0720","--color-surface-elevated":"#140A3A","--color-border":"rgba(248, 250, 252, 0.16)","--color-border-subtle":"rgba(248, 250, 252, 0.10)","--color-primary":"#00E5FF","--color-primary-hover":"#00B8D4","--color-primary-muted":"#00838F","--color-secondary":"#FF3DF5","--color-secondary-hover":"#D500F9","--color-success":"#22C55E","--color-warning":"#FBBF24","--color-error":"#FB7185","--color-text":"#F8FAFC","--color-text-muted":"rgba(248, 250, 252, 0.72)","--color-text-subtle":"rgba(248, 250, 252, 0.52)","--color-glass":"rgba(5, 0, 20, 0.55)","--color-glass-border":"rgba(255, 255, 255, 0.14)","--font-sans":'"Geist Sans", "Inter", system-ui, -apple-system, sans-serif',"--font-mono":'"Geist Mono", "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace',"--tcp-glow-a":"rgba(0, 229, 255, 0.20)","--tcp-glow-b":"rgba(255, 61, 245, 0.14)"}}];function yc(e){const t=String(e||"").trim()||gc;return Pr.find(n=>n.id===t)||Pr[0]}function bc(){try{const e=localStorage.getItem(vc);return yc(e).id}catch{return gc}}function wc(e){const t=yc(e);for(const[n,s]of Object.entries(t.cssVars))document.documentElement.style.setProperty(n,String(s));return document.documentElement.dataset.theme=t.id,document.documentElement.style.colorScheme=t.id==="porcelain"?"light":"dark",t}function Ay(e){const t=wc(e);try{localStorage.setItem(vc,t.id)}catch{}return t}const js=document.getElementById("app"),F=Kg(),{toast:tn,renderToasts:Iy}=Hg(F),ui="tandem_control_panel_token";let ka=0;const Cy={app:js,state:F,api:Vt,byId:ht,escapeHtml:Re,ROUTES:ns,providerHints:Jg,toast:tn,addCleanup:Sc,clearCleanup:Xn,setRoute:ss,renderShell:rs,refreshProviderStatus:xc,refreshIdentityStatus:$c,renderIcons:Ws,THEMES:Pr,setTheme:My};function My(e){const t=Ay(e);return F.themeId=t.id,t}function Sc(e){F.cleanup.push(e)}function Xn(){for(const e of F.cleanup)try{e()}catch{}F.cleanup=[]}function qs(){return!!F.authed&&!!F.needsProviderOnboarding}function _c(){try{return localStorage.getItem(ui)||""}catch{return""}}function Ry(e){try{localStorage.setItem(ui,e)}catch{}}function kc(){try{localStorage.removeItem(ui)}catch{}}async function Lr(){try{const e=await Vt("/api/auth/me",{method:"GET"});F.authed=!0,F.me=e,F.client=new Pm({baseUrl:"/api/engine",token:"session"}),await Promise.all([xc(),$c()])}catch{F.authed=!1,F.me=null,F.client=null,F.needsProviderOnboarding=!1,F.providerReady=!1,F.providerDefault="",F.providerConnected=[],F.providerError="",F.providerGateNoticeShown=!1,F.botName="Tandem",F.botAvatarUrl="",F.controlPanelName="Tandem Control Panel",F.themeId=bc()}}async function xc(){if(!F.client){F.needsProviderOnboarding=!1,F.providerReady=!1,F.providerDefault="",F.providerDefaultModel="",F.providerConnected=[],F.providerError="";return}try{const[e,t,n]=await Promise.all([F.client.providers.config(),F.client.providers.catalog(),F.client.providers.authStatus().catch(()=>({}))]),s=String(e?.default||"").trim(),r=String(e?.providers?.[s]?.default_model||"").trim(),i=new Set((t?.connected||[]).map(d=>String(d||"").trim().toLowerCase())),a=d=>{const u=String(d||"").trim().toLowerCase();return!!u&&u!=="ollama"&&u!=="local"},c=(()=>{const d=String(s||"").trim().toLowerCase();if(!d)return!1;if(n&&typeof n=="object"){const u=n[d];if(u&&typeof u=="object"&&(u.has_key===!0||u.hasKey===!0||u.configured===!0&&!a(d)))return!0;const m=n.providers?.[d];if(m&&typeof m=="object"&&(m.has_key===!0||m.hasKey===!0||m.configured===!0&&!a(d)))return!0}return!1})(),l=!!s&&!!r&&i.has(String(s||"").trim().toLowerCase())&&(!a(s)||c);F.providerDefault=s,F.providerDefaultModel=r,F.providerConnected=[...i],F.providerReady=l,F.providerError="",F.needsProviderOnboarding=!l,l&&(F.providerGateNoticeShown=!1)}catch(e){F.providerReady=!1,F.providerDefault="",F.providerDefaultModel="",F.providerConnected=[],F.providerError=e instanceof Error?e.message:String(e),F.needsProviderOnboarding=!0}}async function $c(){if(!F.client){F.botName="Tandem",F.botAvatarUrl="",F.controlPanelName="Tandem Control Panel";return}try{const t=(F.client?.identity?.get?await F.client.identity.get():await Vt("/api/engine/config/identity",{method:"GET"}))?.identity||{},n=String(t?.bot?.canonical_name||t?.bot?.canonicalName||"").trim(),s=t?.bot?.aliases||{},r=String(t?.bot?.avatar_url||t?.bot?.avatarUrl||"").trim(),i=String(s?.control_panel||s?.controlPanel||"").trim();F.botName=n||"Tandem",F.botAvatarUrl=r,F.controlPanelName=i||`${F.botName} Control Panel`}catch{F.botName="Tandem",F.botAvatarUrl="",F.controlPanelName="Tandem Control Panel"}}function ss(e){const t=oi(e,ns);if(qs()&&t!=="settings"){if(F.providerGateNoticeShown||(tn("info","Set provider + default model first to unlock the control panel."),F.providerGateNoticeShown=!0),window.location.hash!=="#/settings?tab=general"){window.location.hash="#/settings?tab=general";return}F.route="settings",Xn(),rs();return}const n=`#/${t}`;if(window.location.hash!==n){Zg(t);return}if(F.route=t,!F.authed){An();return}Xn(),pi({showLoading:!1})}function An(){const e=_c();js.innerHTML=`
|
|
1532
|
+
<main class="mx-auto grid min-h-screen w-full max-w-3xl place-items-center px-5 py-8">
|
|
1533
|
+
<section class="tcp-panel tcp-shell-glass w-full max-w-xl">
|
|
1534
|
+
<div class="mb-6 rounded-2xl border border-slate-700 bg-black/20 p-3 tcp-soft-block">
|
|
1535
|
+
<svg viewBox="0 0 520 160" class="hero-svg chip-hero" aria-hidden="true">
|
|
1536
|
+
<defs>
|
|
1537
|
+
<linearGradient id="hero-trace-grad" x1="0" y1="0" x2="1" y2="0">
|
|
1538
|
+
<stop offset="0%" stop-color="#64748b" stop-opacity="0.22"></stop>
|
|
1539
|
+
<stop offset="50%" stop-color="#cbd5e1" stop-opacity="0.92"></stop>
|
|
1540
|
+
<stop offset="100%" stop-color="#64748b" stop-opacity="0.22"></stop>
|
|
1541
|
+
</linearGradient>
|
|
1542
|
+
<radialGradient id="hero-chip-core" cx="50%" cy="50%" r="60%">
|
|
1543
|
+
<stop offset="0%" stop-color="#f8fafc" stop-opacity="0.92"></stop>
|
|
1544
|
+
<stop offset="100%" stop-color="#64748b" stop-opacity="0.18"></stop>
|
|
1545
|
+
</radialGradient>
|
|
1546
|
+
<filter id="hero-chip-glow" x="-50%" y="-50%" width="200%" height="200%">
|
|
1547
|
+
<feGaussianBlur stdDeviation="3.5" result="blur"></feGaussianBlur>
|
|
1548
|
+
<feMerge>
|
|
1549
|
+
<feMergeNode in="blur"></feMergeNode>
|
|
1550
|
+
<feMergeNode in="SourceGraphic"></feMergeNode>
|
|
1551
|
+
</feMerge>
|
|
1552
|
+
</filter>
|
|
1553
|
+
</defs>
|
|
1554
|
+
|
|
1555
|
+
<rect class="chip-board" x="24" y="24" width="472" height="112" rx="14"></rect>
|
|
1556
|
+
|
|
1557
|
+
<g class="chip-grid">
|
|
1558
|
+
<line x1="48" y1="48" x2="472" y2="48"></line>
|
|
1559
|
+
<line x1="48" y1="80" x2="472" y2="80"></line>
|
|
1560
|
+
<line x1="48" y1="112" x2="472" y2="112"></line>
|
|
1561
|
+
<line x1="92" y1="34" x2="92" y2="126"></line>
|
|
1562
|
+
<line x1="176" y1="34" x2="176" y2="126"></line>
|
|
1563
|
+
<line x1="260" y1="34" x2="260" y2="126"></line>
|
|
1564
|
+
<line x1="344" y1="34" x2="344" y2="126"></line>
|
|
1565
|
+
<line x1="428" y1="34" x2="428" y2="126"></line>
|
|
1566
|
+
</g>
|
|
1567
|
+
|
|
1568
|
+
<g class="chip-traces">
|
|
1569
|
+
<path class="chip-trace flow-east" d="M48 48 H176 V64 H220"></path>
|
|
1570
|
+
<path class="chip-trace flow-east" d="M48 112 H176 V96 H220"></path>
|
|
1571
|
+
<path class="chip-trace flow-west" d="M472 48 H344 V64 H300"></path>
|
|
1572
|
+
<path class="chip-trace flow-west" d="M472 112 H344 V96 H300"></path>
|
|
1573
|
+
<path class="chip-trace flow-south" d="M176 34 V56 H220"></path>
|
|
1574
|
+
<path class="chip-trace flow-south" d="M344 34 V56 H300"></path>
|
|
1575
|
+
<path class="chip-trace flow-north" d="M176 126 V104 H220"></path>
|
|
1576
|
+
<path class="chip-trace flow-north" d="M344 126 V104 H300"></path>
|
|
1577
|
+
</g>
|
|
1578
|
+
|
|
1579
|
+
<g class="chip-ports">
|
|
1580
|
+
<circle cx="48" cy="48" r="4"></circle>
|
|
1581
|
+
<circle cx="48" cy="112" r="4"></circle>
|
|
1582
|
+
<circle cx="472" cy="48" r="4"></circle>
|
|
1583
|
+
<circle cx="472" cy="112" r="4"></circle>
|
|
1584
|
+
<circle cx="176" cy="34" r="4"></circle>
|
|
1585
|
+
<circle cx="344" cy="34" r="4"></circle>
|
|
1586
|
+
<circle cx="176" cy="126" r="4"></circle>
|
|
1587
|
+
<circle cx="344" cy="126" r="4"></circle>
|
|
1588
|
+
</g>
|
|
1589
|
+
|
|
1590
|
+
<rect class="chip-core-shell" x="220" y="56" width="80" height="48" rx="8"></rect>
|
|
1591
|
+
<rect class="chip-core" x="232" y="68" width="56" height="24" rx="4"></rect>
|
|
1592
|
+
<line class="chip-core-wire" x1="232" y1="80" x2="288" y2="80"></line>
|
|
1593
|
+
<line class="chip-core-wire" x1="260" y1="68" x2="260" y2="92"></line>
|
|
1594
|
+
<circle class="chip-core-pulse" cx="260" cy="80" r="12"></circle>
|
|
1595
|
+
|
|
1596
|
+
<g class="chip-packet packet-east-a">
|
|
1597
|
+
<circle cx="0" cy="0" r="2.4"></circle>
|
|
1598
|
+
</g>
|
|
1599
|
+
<g class="chip-packet packet-east-b">
|
|
1600
|
+
<circle cx="0" cy="0" r="2.4"></circle>
|
|
1601
|
+
</g>
|
|
1602
|
+
<g class="chip-packet packet-west-a">
|
|
1603
|
+
<circle cx="0" cy="0" r="2.4"></circle>
|
|
1604
|
+
</g>
|
|
1605
|
+
<g class="chip-packet packet-west-b">
|
|
1606
|
+
<circle cx="0" cy="0" r="2.4"></circle>
|
|
1607
|
+
</g>
|
|
1608
|
+
<g class="chip-packet packet-south">
|
|
1609
|
+
<circle cx="0" cy="0" r="2.2"></circle>
|
|
1610
|
+
</g>
|
|
1611
|
+
<g class="chip-packet packet-north">
|
|
1612
|
+
<circle cx="0" cy="0" r="2.2"></circle>
|
|
1613
|
+
</g>
|
|
1614
|
+
</svg>
|
|
1615
|
+
</div>
|
|
1616
|
+
<h1 class="mb-1 text-4xl font-semibold tracking-tight tcp-display">${Re(F.controlPanelName)}</h1>
|
|
1617
|
+
<p class="tcp-subtle mb-6">Use your engine API token to unlock the full web control center.</p>
|
|
1618
|
+
<form id="login-form" class="grid gap-3">
|
|
1619
|
+
<label class="text-sm tcp-subtle">Engine Token</label>
|
|
1620
|
+
<input id="token" class="tcp-input" type="password" placeholder="tk_..." autocomplete="off" value="${Re(e)}" />
|
|
1621
|
+
<label class="inline-flex items-center gap-2 text-xs tcp-subtle">
|
|
1622
|
+
<input id="remember-token" type="checkbox" class="h-4 w-4 accent-slate-400" checked />
|
|
1623
|
+
Remember token on this browser
|
|
1624
|
+
</label>
|
|
1625
|
+
<button id="login-btn" type="submit" class="tcp-btn-primary w-full"><i data-lucide="key-round"></i> Sign In</button>
|
|
1626
|
+
<button id="check-engine-btn" type="button" class="tcp-btn w-full"><i data-lucide="activity"></i> Check Engine Connectivity</button>
|
|
1627
|
+
<div id="login-err" class="min-h-[1.2rem] text-sm text-rose-300"></div>
|
|
1628
|
+
</form>
|
|
1629
|
+
</section>
|
|
1630
|
+
</main>
|
|
1631
|
+
`,Ws(),ht("login-form").addEventListener("submit",async t=>{t.preventDefault();const n=ht("token").value.trim(),s=!!ht("remember-token")?.checked,r=ht("login-err");if(r.textContent="",!n){r.textContent="Token is required.",tn("warn","Engine token is required.");return}try{await Vt("/api/auth/login",{method:"POST",body:JSON.stringify({token:n})}),s?Ry(n):kc(),await Lr(),F.authed&&rs(),tn("ok","Signed in."),ss("dashboard")}catch(i){const a=i instanceof Error?i.message:String(i);r.textContent=a,tn("err",a)}}),ht("check-engine-btn").addEventListener("click",async()=>{const t=ht("login-err");t.textContent="";try{const n=await Vt("/api/system/health"),s=n.engine?.ready||n.engine?.healthy?"healthy":"unhealthy";t.textContent=`Engine check: ${s} at ${n.engineUrl}`,t.className="min-h-[1.2rem] text-sm text-lime-300",tn(n.engine?.ready||n.engine?.healthy?"ok":"warn",`Engine ${s}: ${n.engineUrl}`)}catch(n){const s=n instanceof Error?n.message:String(n);t.textContent=s,t.className="min-h-[1.2rem] text-sm text-rose-300",tn("err",s)}})}async function pi(e={}){const{showLoading:t=!0,animateView:n=!0}=e,s=++ka,r=ht("view");if(!r)return;if(t&&(r.innerHTML=`
|
|
1632
|
+
<div class="tcp-loading-shell">
|
|
1633
|
+
<div class="tcp-skeleton h-6 w-44"></div>
|
|
1634
|
+
<div class="tcp-skeleton h-24 w-full"></div>
|
|
1635
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
1636
|
+
<div class="tcp-skeleton h-32 w-full"></div>
|
|
1637
|
+
<div class="tcp-skeleton h-32 w-full"></div>
|
|
1638
|
+
</div>
|
|
1639
|
+
</div>
|
|
1640
|
+
`),new Set(["chat","agents","swarm","teams"]).has(F.route)&&!F.providerReady){r.innerHTML=`
|
|
1641
|
+
<div class="tcp-card">
|
|
1642
|
+
<h3 class="tcp-title mb-2">Provider Setup Required</h3>
|
|
1643
|
+
<p class="tcp-subtle">This page requires a connected default provider/model before runs can execute.</p>
|
|
1644
|
+
<div class="mt-3 flex flex-wrap gap-2">
|
|
1645
|
+
<span class="tcp-badge-warn">default: ${Re(F.providerDefault||"none")}</span>
|
|
1646
|
+
<span class="tcp-badge-warn">connected: ${Re(String(F.providerConnected.length))}</span>
|
|
1647
|
+
</div>
|
|
1648
|
+
<div class="mt-4 flex justify-end">
|
|
1649
|
+
<button id="goto-settings" class="tcp-btn-primary">Open Provider Setup</button>
|
|
1650
|
+
</div>
|
|
1651
|
+
</div>
|
|
1652
|
+
`;const c=ht("goto-settings");c&&c.addEventListener("click",()=>ss("settings"));return}await(wa[F.route]||wa.dashboard)(Cy),s===ka&&(Ws(ht("view")),n&&(Py(r),Ly()))}function Py(e){try{if(window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches)return;Ir(e,{opacity:[.72,1]},{duration:.16,easing:"ease-out"});const t=[...e.querySelectorAll(".tcp-card, .tcp-panel, .tcp-list-item")].slice(0,24);if(!t.length)return;Ir(t,{opacity:[0,1],transform:["translateY(8px)","translateY(0px)"]},{duration:.2,easing:"ease-out",delay:Ug(.02)})}catch{}}function Ly(){try{if(window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches)return;const e=document.querySelector("#nav .nav-item.active");if(!e)return;Ir(e,{opacity:[.72,1],transform:["translateX(-3px)","translateX(0px)"]},{duration:.16,easing:"ease-out"})}catch{}}function rs(){if(!F.authed){An();return}Xn(),js.innerHTML=`
|
|
1653
|
+
<div class="grid min-h-screen grid-cols-1 lg:grid-cols-[270px_1fr]">
|
|
1654
|
+
<aside class="tcp-sidebar p-4">
|
|
1655
|
+
<div class="tcp-brand-tile mb-4 flex items-center gap-3 rounded-xl p-3">
|
|
1656
|
+
<div class="tcp-brand-avatar grid h-10 w-10 place-items-center overflow-hidden rounded-xl">
|
|
1657
|
+
${F.botAvatarUrl?`<img src="${Re(F.botAvatarUrl)}" alt="${Re(F.botName)}" class="h-full w-full object-cover" />`:'<i data-lucide="cpu"></i>'}
|
|
1658
|
+
</div>
|
|
1659
|
+
<div>
|
|
1660
|
+
<div class="text-base font-semibold">${Re(F.botName)}</div>
|
|
1661
|
+
<div class="tcp-subtle text-xs uppercase tracking-wider">Control Center</div>
|
|
1662
|
+
</div>
|
|
1663
|
+
</div>
|
|
1664
|
+
<nav id="nav" class="grid gap-1"></nav>
|
|
1665
|
+
${qs()?`<div class="tcp-onboarding-lock mt-3 rounded-xl p-3 text-xs">
|
|
1666
|
+
<div class="font-semibold text-amber-300">Setup Required</div>
|
|
1667
|
+
<p class="mt-1 tcp-subtle">Configure provider and default model in Settings to unlock all sections.</p>
|
|
1668
|
+
</div>`:""}
|
|
1669
|
+
<div class="mt-4 border-t border-slate-700/40 pt-4 tcp-sidebar-footer">
|
|
1670
|
+
<button id="logout-btn" class="tcp-btn w-full"><i data-lucide="log-out"></i> Logout</button>
|
|
1671
|
+
</div>
|
|
1672
|
+
</aside>
|
|
1673
|
+
<main class="min-w-0 p-3 md:p-5">
|
|
1674
|
+
<section id="view" class="grid h-full gap-4 tcp-view-surface"></section>
|
|
1675
|
+
</main>
|
|
1676
|
+
</div>
|
|
1677
|
+
`;const e=ht("nav"),t=qs();e.innerHTML=Bg.map(([n,s,r])=>{const i=t&&n!=="settings";return`<button data-route="${n}" class="nav-item ${n===F.route?"active":""} ${i?"locked":""}" ${i?'disabled aria-disabled="true"':""}>
|
|
1678
|
+
<i data-lucide="${r}"></i><span>${s}</span>
|
|
1679
|
+
</button>
|
|
1680
|
+
`}).join(""),e.querySelectorAll(".nav-item").forEach(n=>{n.addEventListener("click",()=>{n.disabled||ss(n.dataset.route)})}),ht("logout-btn").addEventListener("click",async()=>{await Vt("/api/auth/logout",{method:"POST"}).catch(()=>{}),F.authed=!1,F.me=null,F.client=null,An()}),Ws(js),Iy(),pi()}async function Oy(){try{await Vt("/api/auth/me")}catch{F.authed=!1,An()}}window.addEventListener("hashchange",()=>{const e=oi(ac(),ns),t=qs()&&e!=="settings"?"settings":e;if(t!==e&&window.location.hash!=="#/settings?tab=general"){window.location.hash="#/settings?tab=general";return}const n=t!==F.route;if(F.route=t,!F.authed){An();return}if(n){rs();return}Xn(),pi({showLoading:!1,animateView:!1})});async function zy(){if(F.themeId=bc(),wc(F.themeId),F.route=oi(ac(),ns),await Lr(),!F.authed){const t=_c().trim();if(t)try{await Vt("/api/auth/login",{method:"POST",body:JSON.stringify({token:t})}),await Lr()}catch{kc()}}if(!F.authed)return An();rs(),F.needsProviderOnboarding&&ss("settings");const e=setInterval(Oy,3e4);Sc(()=>clearInterval(e))}zy();
|