@rizom/brain 0.2.0-alpha.254 → 0.2.0-alpha.255

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/model.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{E as YC}from"./chunks/index-7md2kpcy.js";import{F as _Cx,G as s_,H as PCx}from"./chunks/index-935n8pjr.js";import{I as amx,J as smx,K as Em,L as PV,M as o20,N as t20,O as Uu,P as HO}from"./chunks/index-yyrjc8p1.js";import"./chunks/index-r51zsahe.js";import{$ as wk,$a as CRx,Aa as Qz,Ba as h1,Ca as K4,Da as hB,Ea as iA,Fa as G6,Ha as L_,Ia as xq,Ja as Bq,Ka as E80,La as m2,Qa as cB,Ra as oD,Sa as nf,Ta as IIx,Ua as JCx,Va as y2,W as h4,Wa as i3,X as hQ,Xa as iy,Y as bi,Z as Ui,_ as tD,_a as mhx,aa as fk,ab as Chx,ba as WH0,bb as chx,ca as Dk,cb as eK,da as dH,db as ghx,ea as NF0,eb as fRx,fa as cV,fb as qRx,ga as OH0,gb as xRx,ha as HH0,hb as lhx,ia as hH0,ib as cRx,ja as R4,jb as BRx,ka as XIx,kb as ARx,la as zZ,lb as HRx,mb as FRx,na as rB0,nb as JUx,oa as z9,ob as EZ,pa as AF9,pb as Cm,qa as wF9,qb as Rm,ra as eF9,rb as LCx,sa as xK9,sb as kCx,ta as oB0,xa as ym,ya as r8,yb as MCx,za as jhx,zb as vCx}from"./chunks/index-79tf6zyh.js";import"./chunks/index-fgkdhyf8.js";import"./chunks/index-3s0mc08v.js";import"./chunks/index-971rkzgv.js";import"./chunks/index-c7qkx706.js";import{Kb as SRx}from"./chunks/index-tffq26g2.js";import{Lb as wIx,Mb as fj,Ob as sO,Pb as tNx,Qb as rO,Rb as m3,Sb as oO,Tb as dB,Ub as Az,Vb as eB0,Wb as x30,Xb as dy,Yb as eNx,_b as iKx}from"./chunks/index-ndm04gqb.js";import{$b as _q,Ac as rV,Bc as rF0,Cc as eV,Dc as ZF,Ec as oF0,Fc as Qmx,Gc as Xmx,Hc as xU,Ic as hi,Jc as Ri,Kc as tF0,Lc as eF0,Mc as mQ,Nc as AK0,Oc as Jmx,Pc as jmx,Qc as gF0,Rc as xO,Sc as lE,Tc as GHx,Uc as Bz,Vc as yh,Wc as nV,Xc as WO,Yc as bq,ac as l7,ad as sw,bc as Nf,dc as e8,gc as $mx,gd as LY0,hc as r30,hd as LL,id as kL,kc as UA,lc as Mk,rc as nF0,sc as dF0,tc as cmx,uc as gmx,vc as aF0,wc as sF0,xc as Ii,yc as cF0,zc as uF0}from"./chunks/index-ms0ek6ka.js";import{Ad as AA0,Bd as v80,Cd as fKx,Dd as LO,Nd as D8,Od as xF,Pd as CH0,Qd as qB,Rd as g8,Sd as cH,Td as ryx,Ud as TNx,Vd as n30,ae as dV,be as CF0,ce as kk,de as SF0,ee as oV,fe as tV,ge as Ik,he as iF0,ie as Pmx,je as SK,ld as IQ,md as Sy,nd as EIx,td as $9}from"./chunks/index-qmfk41nk.js";import{qe as YCx,re as G1,se as U1,te as E1,we as Qk}from"./chunks/index-c8a6806x.js";import{ze as j7}from"./chunks/index-nk8ax5h8.js";import{Ae as DY,Af as j8,Be as i8,Bf as O3,Ce as ux,Cf as G9,De as i,Ee as XD,Fe as i0,Ff as nKx,Ge as VP,He as F1,Ie as Yf0,If as I1,Je as IP,Jf as eO,Ke as OP,Kf as h3,Le as Jx,Me as FW,Mf as ox,Ne as UP,Oe as Iz,Qe as Pc,Qf as Wk,Re as ww0,Rf as RHx,Se as Mx,Te as j0,Tf as KB,Ue as Z6,Ve as I6,We as w5,Wf as ny,Xe as B3,Xf as oy,Ye as fw0,Ze as zw0,af as bw0,gf as _4,hf as FD,if as f5,jf as y9,kf as jQ,lf as H0,mf as QB,nf as _w,pf as hk,tf as zA,uf as Z2,vf as vC,wf as oX,xf as lx0,zf as q3}from"./chunks/index-pv4ejw89.js";import"./chunks/index-h3am6zce.js";import{$f as N_,bg as GRx,cg as ERx,dg as jRx,eg as _Rx,fg as kRx,gg as mRx,jg as NVx,kg as q9,og as fC,qg as Zw}from"./chunks/index-03ccs0z9.js";import{$g as ZO,Ag as mk,Bg as LK0,Cg as CQ,Dg as QF,Eg as yk,Fg as FK0,Gg as gQ,Hg as j1,Ig as x$,Jg as AU,Kg as eD,Lg as V3,Mg as Kl,Ng as _K0,Og as jK0,Pg as OK,Qg as IK0,Rg as wK0,Sg as fK0,Ug as Rk,Vg as OK0,Wg as ml,Yg as Gx,Zg as gH,_g as Yk,ah as aD,bh as tIx,ch as aL,dh as uH,fh as lD,gh as r$,hh as r2,vg as J9,wg as NK0,xg as e,yg as b3,zg as X9}from"./chunks/index-z7as6m1p.js";import{jh as mx,nh as BO,sh as _7}from"./chunks/index-b191944s.js";import{$h as g,Ah as _Ox,Hh as dmx,Ih as OO,Jh as hO,Lh as SA,Mh as s$,Nh as tH,Oh as O1,Ph as pA,Qh as KL,Rh as sX0,Sh as mNx,Th as H_,Uh as FZ,Vh as S6,Wh as E4,Xh as _8,Yh as Jc,Zh as KP,_h as iD,bi as p6,di as CH,ei as GS,fi as HB,gi as l8,hi as w7,ii as eRx,ji as rL,ki as lf,li as d5,mi as O_,ni as XCx,oi as O4,pi as BC,qi as b8,ri as P_,si as VB0,yh as km,zh as nmx}from"./chunks/index-0pcaqdds.js";import{xi as X}from"./chunks/index-m5wbq721.js";import{Ai as EW,Bi as S,yi as b7,zi as z}from"./chunks/index-hr01n2vz.js";var wT=z((jI9,ZJ)=>{var yD0,mD0,CD0,cD0,gD0,TD0,pD0,uD0,SD0,iD0,lD0,nD0,dD0,DJ,AT,aD0,sD0,rD0,uW,oD0,tD0,eD0,x$0,B$0,A$0,w$0,f$0,D$0,$J,$$0,Z$0,Q$0;(function(x){var B=typeof global==="object"?global:typeof self==="object"?self:typeof this==="object"?this:{};if(typeof define==="function"&&define.amd)define("tslib",["exports"],function(w){x(A(B,A(w)))});else if(typeof ZJ==="object"&&typeof jI9==="object")x(A(B,A(jI9)));else x(A(B));function A(w,f){if(w!==B)if(typeof Object.create==="function")Object.defineProperty(w,"__esModule",{value:!0});else w.__esModule=!0;return function(D,$){return w[D]=f?f(D,$):$}}})(function(x){var B=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(D,$){D.__proto__=$}||function(D,$){for(var Z in $)if(Object.prototype.hasOwnProperty.call($,Z))D[Z]=$[Z]};yD0=function(D,$){if(typeof $!=="function"&&$!==null)throw TypeError("Class extends value "+String($)+" is not a constructor or null");B(D,$);function Z(){this.constructor=D}D.prototype=$===null?Object.create($):(Z.prototype=$.prototype,new Z)},mD0=Object.assign||function(D){for(var $,Z=1,Q=arguments.length;Z<Q;Z++){$=arguments[Z];for(var Y in $)if(Object.prototype.hasOwnProperty.call($,Y))D[Y]=$[Y]}return D},CD0=function(D,$){var Z={};for(var Q in D)if(Object.prototype.hasOwnProperty.call(D,Q)&&$.indexOf(Q)<0)Z[Q]=D[Q];if(D!=null&&typeof Object.getOwnPropertySymbols==="function"){for(var Y=0,Q=Object.getOwnPropertySymbols(D);Y<Q.length;Y++)if($.indexOf(Q[Y])<0&&Object.prototype.propertyIsEnumerable.call(D,Q[Y]))Z[Q[Y]]=D[Q[Y]]}return Z},cD0=function(D,$,Z,Q){var Y=arguments.length,W=Y<3?$:Q===null?Q=Object.getOwnPropertyDescriptor($,Z):Q,H;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")W=Reflect.decorate(D,$,Z,Q);else for(var F=D.length-1;F>=0;F--)if(H=D[F])W=(Y<3?H(W):Y>3?H($,Z,W):H($,Z))||W;return Y>3&&W&&Object.defineProperty($,Z,W),W},gD0=function(D,$){return function(Z,Q){$(Z,Q,D)}},TD0=function(D,$,Z,Q,Y,W){function H(y){if(y!==void 0&&typeof y!=="function")throw TypeError("Function expected");return y}var F=Q.kind,K=F==="getter"?"get":F==="setter"?"set":"value",q=!$&&D?Q.static?D:D.prototype:null,V=$||(q?Object.getOwnPropertyDescriptor(q,Q.name):{}),b,G=!1;for(var E=Z.length-1;E>=0;E--){var _={};for(var L in Q)_[L]=L==="access"?{}:Q[L];for(var L in Q.access)_.access[L]=Q.access[L];_.addInitializer=function(y){if(G)throw TypeError("Cannot add initializers after decoration has completed");W.push(H(y||null))};var N=(0,Z[E])(F==="accessor"?{get:V.get,set:V.set}:V[K],_);if(F==="accessor"){if(N===void 0)continue;if(N===null||typeof N!=="object")throw TypeError("Object expected");if(b=H(N.get))V.get=b;if(b=H(N.set))V.set=b;if(b=H(N.init))Y.unshift(b)}else if(b=H(N))if(F==="field")Y.unshift(b);else V[K]=b}if(q)Object.defineProperty(q,Q.name,V);G=!0},pD0=function(D,$,Z){var Q=arguments.length>2;for(var Y=0;Y<$.length;Y++)Z=Q?$[Y].call(D,Z):$[Y].call(D);return Q?Z:void 0},uD0=function(D){return typeof D==="symbol"?D:"".concat(D)},SD0=function(D,$,Z){if(typeof $==="symbol")$=$.description?"[".concat($.description,"]"):"";return Object.defineProperty(D,"name",{configurable:!0,value:Z?"".concat(Z," ",$):$})},iD0=function(D,$){if(typeof Reflect==="object"&&typeof Reflect.metadata==="function")return Reflect.metadata(D,$)},lD0=function(D,$,Z,Q){function Y(W){return W instanceof Z?W:new Z(function(H){H(W)})}return new(Z||(Z=Promise))(function(W,H){function F(V){try{q(Q.next(V))}catch(b){H(b)}}function K(V){try{q(Q.throw(V))}catch(b){H(b)}}function q(V){V.done?W(V.value):Y(V.value).then(F,K)}q((Q=Q.apply(D,$||[])).next())})},nD0=function(D,$){var Z={label:0,sent:function(){if(W[0]&1)throw W[1];return W[1]},trys:[],ops:[]},Q,Y,W,H=Object.create((typeof Iterator==="function"?Iterator:Object).prototype);return H.next=F(0),H.throw=F(1),H.return=F(2),typeof Symbol==="function"&&(H[Symbol.iterator]=function(){return this}),H;function F(q){return function(V){return K([q,V])}}function K(q){if(Q)throw TypeError("Generator is already executing.");while(H&&(H=0,q[0]&&(Z=0)),Z)try{if(Q=1,Y&&(W=q[0]&2?Y.return:q[0]?Y.throw||((W=Y.return)&&W.call(Y),0):Y.next)&&!(W=W.call(Y,q[1])).done)return W;if(Y=0,W)q=[q[0]&2,W.value];switch(q[0]){case 0:case 1:W=q;break;case 4:return Z.label++,{value:q[1],done:!1};case 5:Z.label++,Y=q[1],q=[0];continue;case 7:q=Z.ops.pop(),Z.trys.pop();continue;default:if((W=Z.trys,!(W=W.length>0&&W[W.length-1]))&&(q[0]===6||q[0]===2)){Z=0;continue}if(q[0]===3&&(!W||q[1]>W[0]&&q[1]<W[3])){Z.label=q[1];break}if(q[0]===6&&Z.label<W[1]){Z.label=W[1],W=q;break}if(W&&Z.label<W[2]){Z.label=W[2],Z.ops.push(q);break}if(W[2])Z.ops.pop();Z.trys.pop();continue}q=$.call(D,Z)}catch(V){q=[6,V],Y=0}finally{Q=W=0}if(q[0]&5)throw q[1];return{value:q[0]?q[1]:void 0,done:!0}}},dD0=function(D,$){for(var Z in D)if(Z!=="default"&&!Object.prototype.hasOwnProperty.call($,Z))$J($,D,Z)},$J=Object.create?function(D,$,Z,Q){if(Q===void 0)Q=Z;var Y=Object.getOwnPropertyDescriptor($,Z);if(!Y||("get"in Y?!$.__esModule:Y.writable||Y.configurable))Y={enumerable:!0,get:function(){return $[Z]}};Object.defineProperty(D,Q,Y)}:function(D,$,Z,Q){if(Q===void 0)Q=Z;D[Q]=$[Z]},DJ=function(D){var $=typeof Symbol==="function"&&Symbol.iterator,Z=$&&D[$],Q=0;if(Z)return Z.call(D);if(D&&typeof D.length==="number")return{next:function(){if(D&&Q>=D.length)D=void 0;return{value:D&&D[Q++],done:!D}}};throw TypeError($?"Object is not iterable.":"Symbol.iterator is not defined.")},AT=function(D,$){var Z=typeof Symbol==="function"&&D[Symbol.iterator];if(!Z)return D;var Q=Z.call(D),Y,W=[],H;try{while(($===void 0||$-- >0)&&!(Y=Q.next()).done)W.push(Y.value)}catch(F){H={error:F}}finally{try{if(Y&&!Y.done&&(Z=Q.return))Z.call(Q)}finally{if(H)throw H.error}}return W},aD0=function(){for(var D=[],$=0;$<arguments.length;$++)D=D.concat(AT(arguments[$]));return D},sD0=function(){for(var D=0,$=0,Z=arguments.length;$<Z;$++)D+=arguments[$].length;for(var Q=Array(D),Y=0,$=0;$<Z;$++)for(var W=arguments[$],H=0,F=W.length;H<F;H++,Y++)Q[Y]=W[H];return Q},rD0=function(D,$,Z){if(Z||arguments.length===2){for(var Q=0,Y=$.length,W;Q<Y;Q++)if(W||!(Q in $)){if(!W)W=Array.prototype.slice.call($,0,Q);W[Q]=$[Q]}}return D.concat(W||Array.prototype.slice.call($))},uW=function(D){return this instanceof uW?(this.v=D,this):new uW(D)},oD0=function(D,$,Z){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var Q=Z.apply(D,$||[]),Y,W=[];return Y=Object.create((typeof AsyncIterator==="function"?AsyncIterator:Object).prototype),F("next"),F("throw"),F("return",H),Y[Symbol.asyncIterator]=function(){return this},Y;function H(E){return function(_){return Promise.resolve(_).then(E,b)}}function F(E,_){if(Q[E]){if(Y[E]=function(L){return new Promise(function(N,y){W.push([E,L,N,y])>1||K(E,L)})},_)Y[E]=_(Y[E])}}function K(E,_){try{q(Q[E](_))}catch(L){G(W[0][3],L)}}function q(E){E.value instanceof uW?Promise.resolve(E.value.v).then(V,b):G(W[0][2],E)}function V(E){K("next",E)}function b(E){K("throw",E)}function G(E,_){if(E(_),W.shift(),W.length)K(W[0][0],W[0][1])}},tD0=function(D){var $,Z;return $={},Q("next"),Q("throw",function(Y){throw Y}),Q("return"),$[Symbol.iterator]=function(){return this},$;function Q(Y,W){$[Y]=D[Y]?function(H){return(Z=!Z)?{value:uW(D[Y](H)),done:!1}:W?W(H):H}:W}},eD0=function(D){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var $=D[Symbol.asyncIterator],Z;return $?$.call(D):(D=typeof DJ==="function"?DJ(D):D[Symbol.iterator](),Z={},Q("next"),Q("throw"),Q("return"),Z[Symbol.asyncIterator]=function(){return this},Z);function Q(W){Z[W]=D[W]&&function(H){return new Promise(function(F,K){H=D[W](H),Y(F,K,H.done,H.value)})}}function Y(W,H,F,K){Promise.resolve(K).then(function(q){W({value:q,done:F})},H)}},x$0=function(D,$){if(Object.defineProperty)Object.defineProperty(D,"raw",{value:$});else D.raw=$;return D};var A=Object.create?function(D,$){Object.defineProperty(D,"default",{enumerable:!0,value:$})}:function(D,$){D.default=$},w=function(D){return w=Object.getOwnPropertyNames||function($){var Z=[];for(var Q in $)if(Object.prototype.hasOwnProperty.call($,Q))Z[Z.length]=Q;return Z},w(D)};B$0=function(D){if(D&&D.__esModule)return D;var $={};if(D!=null){for(var Z=w(D),Q=0;Q<Z.length;Q++)if(Z[Q]!=="default")$J($,D,Z[Q])}return A($,D),$},A$0=function(D){return D&&D.__esModule?D:{default:D}},w$0=function(D,$,Z,Q){if(Z==="a"&&!Q)throw TypeError("Private accessor was defined without a getter");if(typeof $==="function"?D!==$||!Q:!$.has(D))throw TypeError("Cannot read private member from an object whose class did not declare it");return Z==="m"?Q:Z==="a"?Q.call(D):Q?Q.value:$.get(D)},f$0=function(D,$,Z,Q,Y){if(Q==="m")throw TypeError("Private method is not writable");if(Q==="a"&&!Y)throw TypeError("Private accessor was defined without a setter");if(typeof $==="function"?D!==$||!Y:!$.has(D))throw TypeError("Cannot write private member to an object whose class did not declare it");return Q==="a"?Y.call(D,Z):Y?Y.value=Z:$.set(D,Z),Z},D$0=function(D,$){if($===null||typeof $!=="object"&&typeof $!=="function")throw TypeError("Cannot use 'in' operator on non-object");return typeof D==="function"?$===D:D.has($)},$$0=function(D,$,Z){if($!==null&&$!==void 0){if(typeof $!=="object"&&typeof $!=="function")throw TypeError("Object expected.");var Q,Y;if(Z){if(!Symbol.asyncDispose)throw TypeError("Symbol.asyncDispose is not defined.");Q=$[Symbol.asyncDispose]}if(Q===void 0){if(!Symbol.dispose)throw TypeError("Symbol.dispose is not defined.");if(Q=$[Symbol.dispose],Z)Y=Q}if(typeof Q!=="function")throw TypeError("Object not disposable.");if(Y)Q=function(){try{Y.call(this)}catch(W){return Promise.reject(W)}};D.stack.push({value:$,dispose:Q,async:Z})}else if(Z)D.stack.push({async:!0});return $};var f=typeof SuppressedError==="function"?SuppressedError:function(D,$,Z){var Q=Error(Z);return Q.name="SuppressedError",Q.error=D,Q.suppressed=$,Q};Z$0=function(D){function $(W){D.error=D.hasError?new f(W,D.error,"An error was suppressed during disposal."):W,D.hasError=!0}var Z,Q=0;function Y(){while(Z=D.stack.pop())try{if(!Z.async&&Q===1)return Q=0,D.stack.push(Z),Promise.resolve().then(Y);if(Z.dispose){var W=Z.dispose.call(Z.value);if(Z.async)return Q|=2,Promise.resolve(W).then(Y,function(H){return $(H),Y()})}else Q|=1}catch(H){$(H)}if(Q===1)return D.hasError?Promise.reject(D.error):Promise.resolve();if(D.hasError)throw D.error}return Y()},Q$0=function(D,$){if(typeof D==="string"&&/^\.\.?\//.test(D))return D.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i,function(Z,Q,Y,W,H){return Q?$?".jsx":".js":Y&&(!W||!H)?Z:Y+W+"."+H.toLowerCase()+"js"});return D},x("__extends",yD0),x("__assign",mD0),x("__rest",CD0),x("__decorate",cD0),x("__param",gD0),x("__esDecorate",TD0),x("__runInitializers",pD0),x("__propKey",uD0),x("__setFunctionName",SD0),x("__metadata",iD0),x("__awaiter",lD0),x("__generator",nD0),x("__exportStar",dD0),x("__createBinding",$J),x("__values",DJ),x("__read",AT),x("__spread",aD0),x("__spreadArrays",sD0),x("__spreadArray",rD0),x("__await",uW),x("__asyncGenerator",oD0),x("__asyncDelegator",tD0),x("__asyncValues",eD0),x("__makeTemplateObject",x$0),x("__importStar",B$0),x("__importDefault",A$0),x("__classPrivateFieldGet",w$0),x("__classPrivateFieldSet",f$0),x("__classPrivateFieldIn",D$0),x("__addDisposableResource",$$0),x("__disposeResources",Z$0),x("__rewriteRelativeImportExtension",Q$0)})});var h$0=z(()=>{/*! *****************************************************************************
2
+ import{E as YC}from"./chunks/index-7md2kpcy.js";import{F as _Cx,G as s_,H as PCx}from"./chunks/index-c63zj09c.js";import{I as amx,J as smx,K as Em,L as PV,M as o20,N as t20,O as Uu,P as HO}from"./chunks/index-bw5wqve2.js";import"./chunks/index-r51zsahe.js";import{$ as wk,$a as CRx,Aa as Qz,Ba as h1,Ca as K4,Da as hB,Ea as iA,Fa as G6,Ha as L_,Ia as xq,Ja as Bq,Ka as E80,La as m2,Qa as cB,Ra as oD,Sa as nf,Ta as IIx,Ua as JCx,Va as y2,W as h4,Wa as i3,X as hQ,Xa as iy,Y as bi,Z as Ui,_ as tD,_a as mhx,aa as fk,ab as Chx,ba as WH0,bb as chx,ca as Dk,cb as eK,da as dH,db as ghx,ea as NF0,eb as fRx,fa as cV,fb as qRx,ga as OH0,gb as xRx,ha as HH0,hb as lhx,ia as hH0,ib as cRx,ja as R4,jb as BRx,ka as XIx,kb as ARx,la as zZ,lb as HRx,mb as FRx,na as rB0,nb as JUx,oa as z9,ob as EZ,pa as AF9,pb as Cm,qa as wF9,qb as Rm,ra as eF9,rb as LCx,sa as xK9,sb as kCx,ta as oB0,xa as ym,ya as r8,yb as MCx,za as jhx,zb as vCx}from"./chunks/index-4wd307k7.js";import"./chunks/index-fgkdhyf8.js";import"./chunks/index-3s0mc08v.js";import"./chunks/index-971rkzgv.js";import"./chunks/index-c7qkx706.js";import{Kb as SRx}from"./chunks/index-tffq26g2.js";import{Lb as wIx,Mb as fj,Ob as sO,Pb as tNx,Qb as rO,Rb as m3,Sb as oO,Tb as dB,Ub as Az,Vb as eB0,Wb as x30,Xb as dy,Yb as eNx,_b as iKx}from"./chunks/index-ndm04gqb.js";import{$b as _q,Ac as rV,Bc as rF0,Cc as eV,Dc as ZF,Ec as oF0,Fc as Qmx,Gc as Xmx,Hc as xU,Ic as hi,Jc as Ri,Kc as tF0,Lc as eF0,Mc as mQ,Nc as AK0,Oc as Jmx,Pc as jmx,Qc as gF0,Rc as xO,Sc as lE,Tc as GHx,Uc as Bz,Vc as yh,Wc as nV,Xc as WO,Yc as bq,ac as l7,ad as sw,bc as Nf,dc as e8,gc as $mx,gd as LY0,hc as r30,hd as LL,id as kL,kc as UA,lc as Mk,rc as nF0,sc as dF0,tc as cmx,uc as gmx,vc as aF0,wc as sF0,xc as Ii,yc as cF0,zc as uF0}from"./chunks/index-ms0ek6ka.js";import{Ad as AA0,Bd as v80,Cd as fKx,Dd as LO,Nd as D8,Od as xF,Pd as CH0,Qd as qB,Rd as g8,Sd as cH,Td as ryx,Ud as TNx,Vd as n30,ae as dV,be as CF0,ce as kk,de as SF0,ee as oV,fe as tV,ge as Ik,he as iF0,ie as Pmx,je as SK,ld as IQ,md as Sy,nd as EIx,td as $9}from"./chunks/index-qmfk41nk.js";import{qe as YCx,re as G1,se as U1,te as E1,we as Qk}from"./chunks/index-c8a6806x.js";import{ze as j7}from"./chunks/index-nk8ax5h8.js";import{Ae as DY,Af as j8,Be as i8,Bf as O3,Ce as ux,Cf as G9,De as i,Ee as XD,Fe as i0,Ff as nKx,Ge as VP,He as F1,Ie as Yf0,If as I1,Je as IP,Jf as eO,Ke as OP,Kf as h3,Le as Jx,Me as FW,Mf as ox,Ne as UP,Oe as Iz,Qe as Pc,Qf as Wk,Re as ww0,Rf as RHx,Se as Mx,Te as j0,Tf as KB,Ue as Z6,Ve as I6,We as w5,Wf as ny,Xe as B3,Xf as oy,Ye as fw0,Ze as zw0,af as bw0,gf as _4,hf as FD,if as f5,jf as y9,kf as jQ,lf as H0,mf as QB,nf as _w,pf as hk,tf as zA,uf as Z2,vf as vC,wf as oX,xf as lx0,zf as q3}from"./chunks/index-pv4ejw89.js";import"./chunks/index-h3am6zce.js";import{$f as N_,bg as GRx,cg as ERx,dg as jRx,eg as _Rx,fg as kRx,gg as mRx,jg as NVx,kg as q9,og as fC,qg as Zw}from"./chunks/index-03ccs0z9.js";import{$g as ZO,Ag as mk,Bg as LK0,Cg as CQ,Dg as QF,Eg as yk,Fg as FK0,Gg as gQ,Hg as j1,Ig as x$,Jg as AU,Kg as eD,Lg as V3,Mg as Kl,Ng as _K0,Og as jK0,Pg as OK,Qg as IK0,Rg as wK0,Sg as fK0,Ug as Rk,Vg as OK0,Wg as ml,Yg as Gx,Zg as gH,_g as Yk,ah as aD,bh as tIx,ch as aL,dh as uH,fh as lD,gh as r$,hh as r2,vg as J9,wg as NK0,xg as e,yg as b3,zg as X9}from"./chunks/index-z7as6m1p.js";import{jh as mx,nh as BO,sh as _7}from"./chunks/index-b191944s.js";import{$h as g,Ah as _Ox,Hh as dmx,Ih as OO,Jh as hO,Lh as SA,Mh as s$,Nh as tH,Oh as O1,Ph as pA,Qh as KL,Rh as sX0,Sh as mNx,Th as H_,Uh as FZ,Vh as S6,Wh as E4,Xh as _8,Yh as Jc,Zh as KP,_h as iD,bi as p6,di as CH,ei as GS,fi as HB,gi as l8,hi as w7,ii as eRx,ji as rL,ki as lf,li as d5,mi as O_,ni as XCx,oi as O4,pi as BC,qi as b8,ri as P_,si as VB0,yh as km,zh as nmx}from"./chunks/index-0pcaqdds.js";import{xi as X}from"./chunks/index-m5wbq721.js";import{Ai as EW,Bi as S,yi as b7,zi as z}from"./chunks/index-hr01n2vz.js";var wT=z((jI9,ZJ)=>{var yD0,mD0,CD0,cD0,gD0,TD0,pD0,uD0,SD0,iD0,lD0,nD0,dD0,DJ,AT,aD0,sD0,rD0,uW,oD0,tD0,eD0,x$0,B$0,A$0,w$0,f$0,D$0,$J,$$0,Z$0,Q$0;(function(x){var B=typeof global==="object"?global:typeof self==="object"?self:typeof this==="object"?this:{};if(typeof define==="function"&&define.amd)define("tslib",["exports"],function(w){x(A(B,A(w)))});else if(typeof ZJ==="object"&&typeof jI9==="object")x(A(B,A(jI9)));else x(A(B));function A(w,f){if(w!==B)if(typeof Object.create==="function")Object.defineProperty(w,"__esModule",{value:!0});else w.__esModule=!0;return function(D,$){return w[D]=f?f(D,$):$}}})(function(x){var B=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(D,$){D.__proto__=$}||function(D,$){for(var Z in $)if(Object.prototype.hasOwnProperty.call($,Z))D[Z]=$[Z]};yD0=function(D,$){if(typeof $!=="function"&&$!==null)throw TypeError("Class extends value "+String($)+" is not a constructor or null");B(D,$);function Z(){this.constructor=D}D.prototype=$===null?Object.create($):(Z.prototype=$.prototype,new Z)},mD0=Object.assign||function(D){for(var $,Z=1,Q=arguments.length;Z<Q;Z++){$=arguments[Z];for(var Y in $)if(Object.prototype.hasOwnProperty.call($,Y))D[Y]=$[Y]}return D},CD0=function(D,$){var Z={};for(var Q in D)if(Object.prototype.hasOwnProperty.call(D,Q)&&$.indexOf(Q)<0)Z[Q]=D[Q];if(D!=null&&typeof Object.getOwnPropertySymbols==="function"){for(var Y=0,Q=Object.getOwnPropertySymbols(D);Y<Q.length;Y++)if($.indexOf(Q[Y])<0&&Object.prototype.propertyIsEnumerable.call(D,Q[Y]))Z[Q[Y]]=D[Q[Y]]}return Z},cD0=function(D,$,Z,Q){var Y=arguments.length,W=Y<3?$:Q===null?Q=Object.getOwnPropertyDescriptor($,Z):Q,H;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")W=Reflect.decorate(D,$,Z,Q);else for(var F=D.length-1;F>=0;F--)if(H=D[F])W=(Y<3?H(W):Y>3?H($,Z,W):H($,Z))||W;return Y>3&&W&&Object.defineProperty($,Z,W),W},gD0=function(D,$){return function(Z,Q){$(Z,Q,D)}},TD0=function(D,$,Z,Q,Y,W){function H(y){if(y!==void 0&&typeof y!=="function")throw TypeError("Function expected");return y}var F=Q.kind,K=F==="getter"?"get":F==="setter"?"set":"value",q=!$&&D?Q.static?D:D.prototype:null,V=$||(q?Object.getOwnPropertyDescriptor(q,Q.name):{}),b,G=!1;for(var E=Z.length-1;E>=0;E--){var _={};for(var L in Q)_[L]=L==="access"?{}:Q[L];for(var L in Q.access)_.access[L]=Q.access[L];_.addInitializer=function(y){if(G)throw TypeError("Cannot add initializers after decoration has completed");W.push(H(y||null))};var N=(0,Z[E])(F==="accessor"?{get:V.get,set:V.set}:V[K],_);if(F==="accessor"){if(N===void 0)continue;if(N===null||typeof N!=="object")throw TypeError("Object expected");if(b=H(N.get))V.get=b;if(b=H(N.set))V.set=b;if(b=H(N.init))Y.unshift(b)}else if(b=H(N))if(F==="field")Y.unshift(b);else V[K]=b}if(q)Object.defineProperty(q,Q.name,V);G=!0},pD0=function(D,$,Z){var Q=arguments.length>2;for(var Y=0;Y<$.length;Y++)Z=Q?$[Y].call(D,Z):$[Y].call(D);return Q?Z:void 0},uD0=function(D){return typeof D==="symbol"?D:"".concat(D)},SD0=function(D,$,Z){if(typeof $==="symbol")$=$.description?"[".concat($.description,"]"):"";return Object.defineProperty(D,"name",{configurable:!0,value:Z?"".concat(Z," ",$):$})},iD0=function(D,$){if(typeof Reflect==="object"&&typeof Reflect.metadata==="function")return Reflect.metadata(D,$)},lD0=function(D,$,Z,Q){function Y(W){return W instanceof Z?W:new Z(function(H){H(W)})}return new(Z||(Z=Promise))(function(W,H){function F(V){try{q(Q.next(V))}catch(b){H(b)}}function K(V){try{q(Q.throw(V))}catch(b){H(b)}}function q(V){V.done?W(V.value):Y(V.value).then(F,K)}q((Q=Q.apply(D,$||[])).next())})},nD0=function(D,$){var Z={label:0,sent:function(){if(W[0]&1)throw W[1];return W[1]},trys:[],ops:[]},Q,Y,W,H=Object.create((typeof Iterator==="function"?Iterator:Object).prototype);return H.next=F(0),H.throw=F(1),H.return=F(2),typeof Symbol==="function"&&(H[Symbol.iterator]=function(){return this}),H;function F(q){return function(V){return K([q,V])}}function K(q){if(Q)throw TypeError("Generator is already executing.");while(H&&(H=0,q[0]&&(Z=0)),Z)try{if(Q=1,Y&&(W=q[0]&2?Y.return:q[0]?Y.throw||((W=Y.return)&&W.call(Y),0):Y.next)&&!(W=W.call(Y,q[1])).done)return W;if(Y=0,W)q=[q[0]&2,W.value];switch(q[0]){case 0:case 1:W=q;break;case 4:return Z.label++,{value:q[1],done:!1};case 5:Z.label++,Y=q[1],q=[0];continue;case 7:q=Z.ops.pop(),Z.trys.pop();continue;default:if((W=Z.trys,!(W=W.length>0&&W[W.length-1]))&&(q[0]===6||q[0]===2)){Z=0;continue}if(q[0]===3&&(!W||q[1]>W[0]&&q[1]<W[3])){Z.label=q[1];break}if(q[0]===6&&Z.label<W[1]){Z.label=W[1],W=q;break}if(W&&Z.label<W[2]){Z.label=W[2],Z.ops.push(q);break}if(W[2])Z.ops.pop();Z.trys.pop();continue}q=$.call(D,Z)}catch(V){q=[6,V],Y=0}finally{Q=W=0}if(q[0]&5)throw q[1];return{value:q[0]?q[1]:void 0,done:!0}}},dD0=function(D,$){for(var Z in D)if(Z!=="default"&&!Object.prototype.hasOwnProperty.call($,Z))$J($,D,Z)},$J=Object.create?function(D,$,Z,Q){if(Q===void 0)Q=Z;var Y=Object.getOwnPropertyDescriptor($,Z);if(!Y||("get"in Y?!$.__esModule:Y.writable||Y.configurable))Y={enumerable:!0,get:function(){return $[Z]}};Object.defineProperty(D,Q,Y)}:function(D,$,Z,Q){if(Q===void 0)Q=Z;D[Q]=$[Z]},DJ=function(D){var $=typeof Symbol==="function"&&Symbol.iterator,Z=$&&D[$],Q=0;if(Z)return Z.call(D);if(D&&typeof D.length==="number")return{next:function(){if(D&&Q>=D.length)D=void 0;return{value:D&&D[Q++],done:!D}}};throw TypeError($?"Object is not iterable.":"Symbol.iterator is not defined.")},AT=function(D,$){var Z=typeof Symbol==="function"&&D[Symbol.iterator];if(!Z)return D;var Q=Z.call(D),Y,W=[],H;try{while(($===void 0||$-- >0)&&!(Y=Q.next()).done)W.push(Y.value)}catch(F){H={error:F}}finally{try{if(Y&&!Y.done&&(Z=Q.return))Z.call(Q)}finally{if(H)throw H.error}}return W},aD0=function(){for(var D=[],$=0;$<arguments.length;$++)D=D.concat(AT(arguments[$]));return D},sD0=function(){for(var D=0,$=0,Z=arguments.length;$<Z;$++)D+=arguments[$].length;for(var Q=Array(D),Y=0,$=0;$<Z;$++)for(var W=arguments[$],H=0,F=W.length;H<F;H++,Y++)Q[Y]=W[H];return Q},rD0=function(D,$,Z){if(Z||arguments.length===2){for(var Q=0,Y=$.length,W;Q<Y;Q++)if(W||!(Q in $)){if(!W)W=Array.prototype.slice.call($,0,Q);W[Q]=$[Q]}}return D.concat(W||Array.prototype.slice.call($))},uW=function(D){return this instanceof uW?(this.v=D,this):new uW(D)},oD0=function(D,$,Z){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var Q=Z.apply(D,$||[]),Y,W=[];return Y=Object.create((typeof AsyncIterator==="function"?AsyncIterator:Object).prototype),F("next"),F("throw"),F("return",H),Y[Symbol.asyncIterator]=function(){return this},Y;function H(E){return function(_){return Promise.resolve(_).then(E,b)}}function F(E,_){if(Q[E]){if(Y[E]=function(L){return new Promise(function(N,y){W.push([E,L,N,y])>1||K(E,L)})},_)Y[E]=_(Y[E])}}function K(E,_){try{q(Q[E](_))}catch(L){G(W[0][3],L)}}function q(E){E.value instanceof uW?Promise.resolve(E.value.v).then(V,b):G(W[0][2],E)}function V(E){K("next",E)}function b(E){K("throw",E)}function G(E,_){if(E(_),W.shift(),W.length)K(W[0][0],W[0][1])}},tD0=function(D){var $,Z;return $={},Q("next"),Q("throw",function(Y){throw Y}),Q("return"),$[Symbol.iterator]=function(){return this},$;function Q(Y,W){$[Y]=D[Y]?function(H){return(Z=!Z)?{value:uW(D[Y](H)),done:!1}:W?W(H):H}:W}},eD0=function(D){if(!Symbol.asyncIterator)throw TypeError("Symbol.asyncIterator is not defined.");var $=D[Symbol.asyncIterator],Z;return $?$.call(D):(D=typeof DJ==="function"?DJ(D):D[Symbol.iterator](),Z={},Q("next"),Q("throw"),Q("return"),Z[Symbol.asyncIterator]=function(){return this},Z);function Q(W){Z[W]=D[W]&&function(H){return new Promise(function(F,K){H=D[W](H),Y(F,K,H.done,H.value)})}}function Y(W,H,F,K){Promise.resolve(K).then(function(q){W({value:q,done:F})},H)}},x$0=function(D,$){if(Object.defineProperty)Object.defineProperty(D,"raw",{value:$});else D.raw=$;return D};var A=Object.create?function(D,$){Object.defineProperty(D,"default",{enumerable:!0,value:$})}:function(D,$){D.default=$},w=function(D){return w=Object.getOwnPropertyNames||function($){var Z=[];for(var Q in $)if(Object.prototype.hasOwnProperty.call($,Q))Z[Z.length]=Q;return Z},w(D)};B$0=function(D){if(D&&D.__esModule)return D;var $={};if(D!=null){for(var Z=w(D),Q=0;Q<Z.length;Q++)if(Z[Q]!=="default")$J($,D,Z[Q])}return A($,D),$},A$0=function(D){return D&&D.__esModule?D:{default:D}},w$0=function(D,$,Z,Q){if(Z==="a"&&!Q)throw TypeError("Private accessor was defined without a getter");if(typeof $==="function"?D!==$||!Q:!$.has(D))throw TypeError("Cannot read private member from an object whose class did not declare it");return Z==="m"?Q:Z==="a"?Q.call(D):Q?Q.value:$.get(D)},f$0=function(D,$,Z,Q,Y){if(Q==="m")throw TypeError("Private method is not writable");if(Q==="a"&&!Y)throw TypeError("Private accessor was defined without a setter");if(typeof $==="function"?D!==$||!Y:!$.has(D))throw TypeError("Cannot write private member to an object whose class did not declare it");return Q==="a"?Y.call(D,Z):Y?Y.value=Z:$.set(D,Z),Z},D$0=function(D,$){if($===null||typeof $!=="object"&&typeof $!=="function")throw TypeError("Cannot use 'in' operator on non-object");return typeof D==="function"?$===D:D.has($)},$$0=function(D,$,Z){if($!==null&&$!==void 0){if(typeof $!=="object"&&typeof $!=="function")throw TypeError("Object expected.");var Q,Y;if(Z){if(!Symbol.asyncDispose)throw TypeError("Symbol.asyncDispose is not defined.");Q=$[Symbol.asyncDispose]}if(Q===void 0){if(!Symbol.dispose)throw TypeError("Symbol.dispose is not defined.");if(Q=$[Symbol.dispose],Z)Y=Q}if(typeof Q!=="function")throw TypeError("Object not disposable.");if(Y)Q=function(){try{Y.call(this)}catch(W){return Promise.reject(W)}};D.stack.push({value:$,dispose:Q,async:Z})}else if(Z)D.stack.push({async:!0});return $};var f=typeof SuppressedError==="function"?SuppressedError:function(D,$,Z){var Q=Error(Z);return Q.name="SuppressedError",Q.error=D,Q.suppressed=$,Q};Z$0=function(D){function $(W){D.error=D.hasError?new f(W,D.error,"An error was suppressed during disposal."):W,D.hasError=!0}var Z,Q=0;function Y(){while(Z=D.stack.pop())try{if(!Z.async&&Q===1)return Q=0,D.stack.push(Z),Promise.resolve().then(Y);if(Z.dispose){var W=Z.dispose.call(Z.value);if(Z.async)return Q|=2,Promise.resolve(W).then(Y,function(H){return $(H),Y()})}else Q|=1}catch(H){$(H)}if(Q===1)return D.hasError?Promise.reject(D.error):Promise.resolve();if(D.hasError)throw D.error}return Y()},Q$0=function(D,$){if(typeof D==="string"&&/^\.\.?\//.test(D))return D.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i,function(Z,Q,Y,W,H){return Q?$?".jsx":".js":Y&&(!W||!H)?Z:Y+W+"."+H.toLowerCase()+"js"});return D},x("__extends",yD0),x("__assign",mD0),x("__rest",CD0),x("__decorate",cD0),x("__param",gD0),x("__esDecorate",TD0),x("__runInitializers",pD0),x("__propKey",uD0),x("__setFunctionName",SD0),x("__metadata",iD0),x("__awaiter",lD0),x("__generator",nD0),x("__exportStar",dD0),x("__createBinding",$J),x("__values",DJ),x("__read",AT),x("__spread",aD0),x("__spreadArrays",sD0),x("__spreadArray",rD0),x("__await",uW),x("__asyncGenerator",oD0),x("__asyncDelegator",tD0),x("__asyncValues",eD0),x("__makeTemplateObject",x$0),x("__importStar",B$0),x("__importDefault",A$0),x("__classPrivateFieldGet",w$0),x("__classPrivateFieldSet",f$0),x("__classPrivateFieldIn",D$0),x("__addDisposableResource",$$0),x("__disposeResources",Z$0),x("__rewriteRelativeImportExtension",Q$0)})});var h$0=z(()=>{/*! *****************************************************************************
3
3
  Copyright (C) Microsoft. All rights reserved.
4
4
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
5
5
  this file except in compliance with the License. You may obtain a copy of the
@@ -858,7 +858,7 @@ Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
858
858
  WD9f
859
859
  -----END CERTIFICATE-----
860
860
  `;class XX0{constructor(){Object.defineProperty(this,"pemCertificates",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.pemCertificates=new Map}setRootCertificates(x){let{identifier:B,certificates:A}=x,w=[];for(let f of A)if(f instanceof Uint8Array)w.push(D5(f));else w.push(f);this.pemCertificates.set(B,w)}getRootCertificates(x){let{identifier:B}=x;return this.pemCertificates.get(B)??[]}}var gD=new XX0;gD.setRootCertificates({identifier:"android-key",certificates:[wX0,fX0,DX0,$X0]});gD.setRootCertificates({identifier:"android-safetynet",certificates:[AX0]});gD.setRootCertificates({identifier:"apple",certificates:[ZX0]});gD.setRootCertificates({identifier:"mds",certificates:[QX0]});async function YX0(x){let B=eQ0(x),A=B[0],w=B[1],f=A.x5c.map(D5);try{let F=gD.getRootCertificates({identifier:"mds"});await t1(f,F)}catch(F){throw Error("BLOB certificate path could not be validated",{cause:F})}let D=f[0];if(!await xX0(x,BX0(D)))throw Error("BLOB signature could not be verified");let Z=[];for(let F of w.entries)if(F.aaguid&&F.metadataStatement)Z.push(F.metadataStatement);let[Q,Y,W]=w.nextUpdate.split("-"),H=new Date(parseInt(Q,10),parseInt(Y,10)-1,parseInt(W,10));return{statements:Z,parsedNextUpdate:H,payload:w}}async function WX0(x){let{cosePublicKey:B,signature:A,data:w}=x,f=await t2(),D=B.get(gx.alg),$=B.get(gx.crv),Z=B.get(gx.x);if(!D)throw Error("Public key was missing alg (OKP)");if(!e3(D))throw Error(`Public key had invalid alg ${D} (OKP)`);if(!$)throw Error("Public key was missing crv (OKP)");if(!Z)throw Error("Public key was missing x (OKP)");let Q;if($===a1.ED25519)Q="Ed25519";else throw Error(`Unexpected COSE crv value of ${$} (OKP)`);let Y={kty:"OKP",crv:Q,alg:"EdDSA",x:Sx.fromBuffer(Z),ext:!1},H=await PW({keyData:Y,algorithm:{name:Q,namedCurve:Q}}),F={name:Q};return f.subtle.verify(F,H,A,w)}function FX0(x,B){let A=o9.parse(x,ND),w=new Uint8Array(A.r),f=new Uint8Array(A.s),D=nSx(B),$=HX0(w,D),Z=HX0(f,D);return jx.concat([$,Z])}function nSx(x){switch(x){case a1.P256:return 32;case a1.P384:return 48;case a1.P521:return 66;default:throw Error(`Unexpected COSE crv value of ${x} (EC2)`)}}function HX0(x,B){let A;if(x.length<B)A=new Uint8Array(B),A.set(x,B-x.length);else if(x.length===B)A=x;else if(x.length===B+1&&x[0]===0&&(x[1]&128)===128)A=x.subarray(1);else throw Error(`Invalid signature component length ${x.length}, expected ${B}`);return A}function KX0(x){let{cosePublicKey:B,signature:A,data:w,shaHashOverride:f}=x;if(KD(B)){let $=B.get(gx.crv);if(!Rf0($))throw Error(`unknown COSE curve ${$}`);let Z=FX0(A,$);return cP({cosePublicKey:B,signature:Z,data:w,shaHashOverride:f})}else if(_W(B))return gP({cosePublicKey:B,signature:A,data:w,shaHashOverride:f});else if(hf0(B))return WX0({cosePublicKey:B,signature:A,data:w});let D=B.get(gx.kty);throw Error(`Signature verification with public key of kty ${D} is not supported by this method`)}var jx={};EW(jx,{toUTF8String:()=>oSx,toHex:()=>aSx,toDataView:()=>xix,fromUTF8String:()=>tSx,fromHex:()=>sSx,fromASCIIString:()=>eSx,concat:()=>rSx,areEqual:()=>dSx});function dSx(x,B){if(x.length!=B.length)return!1;return x.every((A,w)=>A===B[w])}function aSx(x){return Array.from(x,(A)=>A.toString(16).padStart(2,"0")).join("")}function sSx(x){if(!x)return Uint8Array.from([]);if(!(x.length!==0&&x.length%2===0&&!/[^a-fA-F0-9]/u.test(x)))throw Error("Invalid hex string");let A=x.match(/.{1,2}/g)??[];return Uint8Array.from(A.map((w)=>parseInt(w,16)))}function rSx(x){let B=0,A=x.reduce((f,D)=>f+D.length,0),w=new Uint8Array(A);return x.forEach((f)=>{w.set(f,B),B+=f.length}),w}function oSx(x){return new globalThis.TextDecoder("utf-8").decode(x)}function tSx(x){return new globalThis.TextEncoder().encode(x)}function eSx(x){return Uint8Array.from(x.split("").map((B)=>B.charCodeAt(0)))}function xix(x){return new DataView(x.buffer,x.byteOffset,x.length)}async function wL(){let x=new Uint8Array(32);return await xA.getRandomValues(x),Bix.stubThis(x)}var Bix={stubThis:(x)=>x};var qX0=[-8,-7,-36,-37,-38,-39,-257,-258,-259,-65535],Aix={residentKey:"preferred",userVerification:"preferred"},wix=[-8,-7,-257];async function zX0(x){let{rpName:B,rpID:A,userName:w,userID:f,challenge:D=await wL(),userDisplayName:$="",timeout:Z=60000,attestationType:Q="none",excludeCredentials:Y=[],authenticatorSelection:W=Aix,extensions:H,supportedAlgorithmIDs:F=wix,preferredAuthenticatorType:K}=x,q=F.map((E)=>({alg:E,type:"public-key"}));if(W.residentKey===void 0){if(W.requireResidentKey)W.residentKey="required"}else W.requireResidentKey=W.residentKey==="required";let V=D;if(typeof V==="string")V=jx.fromUTF8String(V);if(typeof f==="string")throw Error("String values for `userID` are no longer supported. See https://simplewebauthn.dev/docs/advanced/server/custom-user-ids");let b=f;if(!b)b=await gf0();let G=[];if(K){if(K==="securityKey")G.push("security-key"),W.authenticatorAttachment="cross-platform";else if(K==="localDevice")G.push("client-device"),W.authenticatorAttachment="platform";else if(K==="remoteDevice")G.push("hybrid"),W.authenticatorAttachment="cross-platform"}return{challenge:Sx.fromBuffer(V),rp:{name:B,id:A},user:{id:Sx.fromBuffer(b),name:w,displayName:$},pubKeyCredParams:q,timeout:Z,attestation:Q,excludeCredentials:Y.map((E)=>{if(!Sx.isBase64URL(E.id))throw Error(`excludeCredential id "${E.id}" is not a valid base64url string`);return{...E,id:Sx.trimPadding(E.id),type:"public-key"}}),authenticatorSelection:W,extensions:{...H,credProps:!0},hints:G}}function fL({be:x,bs:B}){let A=B,w="singleDevice";if(x)w="multiDevice";if(w==="singleDevice"&&A)throw new bX0("Single-device credential indicated that it was backed up, which should be impossible.");return{credentialDeviceType:w,credentialBackedUp:A}}class bX0 extends Error{constructor(x){super(x);this.name="InvalidBackupFlags"}}async function DL(x,B){try{return await Promise.any(B.map((w)=>{return new Promise((f,D)=>{A2(jx.fromASCIIString(w)).then(($)=>{if(jx.areEqual(x,$))f(w);else D()})})}))}catch(A){if(A.name==="AggregateError")throw new VX0;throw A}}class VX0 extends Error{constructor(){super("Unexpected RP ID hash");this.name="UnexpectedRPIDHash"}}async function UX0(x){let{attStmt:B,clientDataHash:A,rpIdHash:w,credentialID:f,credentialPublicKey:D,aaguid:$,rootCertificates:Z}=x,Q=Uint8Array.from([0]),Y=JW(D),W=jx.concat([Q,w,A,f,Y]),H=B.get("sig"),F=B.get("x5c");if(!F)throw Error("No attestation certificate provided in attestation statement (FIDOU2F)");if(!H)throw Error("No attestation signature provided in attestation statement (FIDOU2F)");let K=Number.parseInt(jx.toHex($),16);if(K!==0)throw Error(`AAGUID "${K}" was not expected value`);try{await t1(F.map(D5),Z)}catch(q){throw Error(`${q.message} (FIDOU2F)`)}return w2({signature:H,data:W,x509Certificate:F[0],hashAlgorithm:f8.ES256})}var GX0="1.3.6.1.4.1.45724.1.1.4";function $L(x,B){if(!x)return!0;let A=x.find(($)=>$.extnID===GX0);if(!A)return!0;let w=o9.parse(A.extnValue,m0),f=new Uint8Array(w.buffer);if(!jx.areEqual(B,f)){let $=jx.toHex(f),Z=jx.toHex(B);throw Error(`Certificate extension id-fido-gen-ce-aaguid (${GX0}) value of "${$}" was present but not equal to attestation statement AAGUID value of "${Z}"`)}return!0}function EX0(x){return(B,...A)=>{}}var fix={url:"",no:0,nextUpdate:new Date(0)},Dix="https://mds.fidoalliance.org/",f2;(function(x){x[x.DISABLED=0]="DISABLED",x[x.REFRESHING=1]="REFRESHING",x[x.READY=2]="READY"})(f2||(f2={}));var GQ=EX0("MetadataService");class jX0{constructor(){Object.defineProperty(this,"mdsCache",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"statementCache",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"state",{enumerable:!0,configurable:!0,writable:!0,value:f2.DISABLED}),Object.defineProperty(this,"verificationMode",{enumerable:!0,configurable:!0,writable:!0,value:"strict"})}async initialize(x={}){this.statementCache={};let{mdsServers:B=[Dix],statements:A,verificationMode:w}=x;if(this.setState(f2.REFRESHING),A?.length){let f=0;A.forEach((D)=>{if(D.aaguid)this.statementCache[D.aaguid]={entry:{metadataStatement:D,statusReports:[],timeOfLastStatusChange:"1970-01-01"},url:fix.url},f+=1}),GQ(`Cached ${f} local statements`)}if(B?.length){let f=Object.keys(this.statementCache).length,D=B.length;for(let Q of B)try{let Y={url:Q,no:0,nextUpdate:new Date(0)},W=await this.downloadBlob(Y);await this.verifyBlob(W,Y)}catch(Y){GQ(`Could not download BLOB from ${Q}:`,Y),D-=1}let Z=Object.keys(this.statementCache).length-f;GQ(`Cached ${Z} statements from ${D} metadata server(s)`)}if(w)this.verificationMode=w;this.setState(f2.READY)}async getStatement(x){if(this.state===f2.DISABLED)return;if(!x)return;if(x instanceof Uint8Array)x=TP(x);await this.pauseUntilReady();let B=this.statementCache[x];if(!B){if(this.verificationMode==="strict")throw Error(`No metadata statement found for aaguid "${x}"`);return}if(B.url){let w=this.mdsCache[B.url];if(new Date>w.nextUpdate)try{this.setState(f2.REFRESHING);let D=await this.downloadBlob(w);await this.verifyBlob(D,w)}finally{this.setState(f2.READY)}}let{entry:A}=B;for(let w of A.statusReports){let{status:f}=w;if(f==="USER_VERIFICATION_BYPASS"||f==="ATTESTATION_KEY_COMPROMISE"||f==="USER_KEY_REMOTE_COMPROMISE"||f==="USER_KEY_PHYSICAL_COMPROMISE")throw Error(`Detected compromised aaguid "${x}"`)}return A.metadataStatement}async downloadBlob(x){let{url:B}=x;return await(await xL(B)).text()}async verifyBlob(x,B){let{url:A,no:w}=B,{payload:f,parsedNextUpdate:D}=await YX0(x);if(f.no<=w)throw Error(`Latest BLOB no. ${f.no} is not greater than previous no. ${w}`);for(let $ of f.entries)if($.aaguid)this.statementCache[$.aaguid]={entry:$,url:A};if(A)this.mdsCache[A]={...B,no:f.no,nextUpdate:D};else if(D<new Date)GQ(`\u26A0\uFE0F This MDS blob (serial: ${f.no}) contains stale data as of ${D.toISOString()}. Please consider re-initializing MetadataService with a newer MDS blob.`)}pauseUntilReady(){if(this.state===f2.READY)return new Promise((B)=>{B()});return new Promise((B,A)=>{let D=700,$=globalThis.setInterval(()=>{if(D<1)clearInterval($),A("State did not become ready in 70 seconds");else if(this.state===f2.READY)clearInterval($),B();D-=1},100)})}setState(x){if(this.state=x,x===f2.DISABLED)GQ("MetadataService is DISABLED");else if(x===f2.REFRESHING)GQ("MetadataService is REFRESHING");else if(x===f2.READY)GQ("MetadataService is READY")}}var TD=new jX0;async function pD({statement:x,credentialPublicKey:B,x5c:A,attestationStatementAlg:w}){let{authenticationAlgorithms:f,authenticatorGetInfo:D,attestationRootCertificates:$}=x,Z=new Set;f.forEach((b)=>{let G=_X0[b];if(G)Z.add(G)});let Q=zD(B),Y=Q.get(gx.kty),W=Q.get(gx.alg);if(!Y)throw Error("Credential public key was missing kty");if(!W)throw Error("Credential public key was missing alg");if(!Y)throw Error("Credential public key was missing kty");let H={kty:Y,alg:W};if(KD(Q)){let b=Q.get(gx.crv);H.crv=b}let F=!1;for(let b of Z){if(b.alg===H.alg&&b.kty===H.kty)if((b.kty===r7.EC2||b.kty===r7.OKP)&&b.crv===H.crv)F=!0;else F=!0;if(F)break}if(!F){let b=f.map((_)=>`'${_}' (COSE info: ${PX0(_X0[_])})`),G=JSON.stringify(b,null,2).replace(/"/g,""),E=PX0(H);throw Error(`Public key parameters ${E} did not match any of the following metadata algorithms:
861
- ${G}`)}if(w!==void 0&&D?.algorithms!==void 0){let b=D.algorithms.map((G)=>G.alg);if(b.indexOf(w)<0)throw Error(`Attestation statement alg ${w} did not match one of ${b}`)}let K=A.map(D5),q=$.map(D5),V=!1;if(K.length===1&&q.indexOf(K[0])>=0)V=!0;if(!V)try{await t1(K,q)}catch(b){throw Error(`Could not validate certificate path with any metadata root certificates: ${b.message}`)}return!0}var _X0={secp256r1_ecdsa_sha256_raw:{kty:2,alg:-7,crv:1},secp256r1_ecdsa_sha256_der:{kty:2,alg:-7,crv:1},rsassa_pss_sha256_raw:{kty:3,alg:-37},rsassa_pss_sha256_der:{kty:3,alg:-37},secp256k1_ecdsa_sha256_raw:{kty:2,alg:-47,crv:8},secp256k1_ecdsa_sha256_der:{kty:2,alg:-47,crv:8},rsassa_pss_sha384_raw:{kty:3,alg:-38},rsassa_pkcsv15_sha256_raw:{kty:3,alg:-257},rsassa_pkcsv15_sha384_raw:{kty:3,alg:-258},rsassa_pkcsv15_sha512_raw:{kty:3,alg:-259},rsassa_pkcsv15_sha1_raw:{kty:3,alg:-65535},secp384r1_ecdsa_sha384_raw:{kty:2,alg:-35,crv:2},secp512r1_ecdsa_sha256_raw:{kty:2,alg:-36,crv:3},ed25519_eddsa_sha512_raw:{kty:1,alg:-8,crv:6}};function PX0(x){let{kty:B,alg:A,crv:w}=x,f="";if(B!==r7.RSA)f=`{ kty: ${B}, alg: ${A}, crv: ${w} }`;else f=`{ kty: ${B}, alg: ${A} }`;return f}async function JX0(x){let{attStmt:B,clientDataHash:A,authData:w,credentialPublicKey:f,aaguid:D,rootCertificates:$}=x,Z=B.get("sig"),Q=B.get("x5c"),Y=B.get("alg");if(!Z)throw Error("No attestation signature provided in attestation statement (Packed)");if(!Y)throw Error("Attestation statement did not contain alg (Packed)");if(!e3(Y))throw Error(`Attestation statement contained invalid alg ${Y} (Packed)`);let W=jx.concat([w,A]),H=!1;if(Q){let{subject:F,basicConstraintsCA:K,version:q,notBefore:V,notAfter:b,parsedCertificate:G}=xH(Q[0]),{OU:E,CN:_,O:L,C:N}=F;if(E!=="Authenticator Attestation")throw Error('Certificate OU was not "Authenticator Attestation" (Packed|Full)');if(!_)throw Error("Certificate CN was empty (Packed|Full)");if(!L)throw Error("Certificate O was empty (Packed|Full)");if(!N||N.length!==2)throw Error("Certificate C was not two-character ISO 3166 code (Packed|Full)");if(K)throw Error("Certificate basic constraints CA was not `false` (Packed|Full)");if(q!==2)throw Error("Certificate version was not `3` (ASN.1 value of 2) (Packed|Full)");let y=new Date;if(V>y)throw Error(`Certificate not good before "${V.toString()}" (Packed|Full)`);if(y=new Date,b<y)throw Error(`Certificate not good after "${b.toString()}" (Packed|Full)`);try{await $L(G.tbsCertificate.extensions,D)}catch(n){throw Error(`${n.message} (Packed|Full)`)}let c=await TD.getStatement(D);if(c){if(c.attestationTypes.indexOf("basic_full")<0)throw Error("Metadata does not indicate support for full attestations (Packed|Full)");try{await pD({statement:c,credentialPublicKey:f,x5c:Q,attestationStatementAlg:Y})}catch(n){throw Error(`${n.message} (Packed|Full)`)}}else try{await t1(Q.map(D5),$)}catch(n){throw Error(`${n.message} (Packed|Full)`)}H=await w2({signature:Z,data:W,x509Certificate:Q[0],hashAlgorithm:Y})}else H=await w2({signature:Z,data:W,credentialPublicKey:f,hashAlgorithm:Y});return H}async function LX0(x){let{attStmt:B,clientDataHash:A,authData:w,aaguid:f,rootCertificates:D,verifyTimestampMS:$=!0,credentialPublicKey:Z,attestationSafetyNetEnforceCTSCheck:Q}=x,Y=B.get("alg"),W=B.get("response");if(!B.get("ver"))throw Error("No ver value in attestation (SafetyNet)");if(!W)throw Error("No response was included in attStmt by authenticator (SafetyNet)");let K=jx.toUTF8String(W).split("."),q=JSON.parse(Sx.toUTF8String(K[0])),V=JSON.parse(Sx.toUTF8String(K[1])),b=K[2],{nonce:G,ctsProfileMatch:E,timestampMs:_}=V;if($){let J0=Date.now();if(_>Date.now())throw Error(`Payload timestamp "${_}" was later than "${J0}" (SafetyNet)`);let v0=_+60000;if(J0=Date.now(),v0<J0)throw Error(`Payload timestamp "${v0}" has expired (SafetyNet)`)}let L=jx.concat([w,A]),N=await A2(L),y=Sx.fromBuffer(N,"base64");if(G!==y)throw Error("Could not verify payload nonce (SafetyNet)");if(Q&&!E)throw Error("Could not verify device integrity (SafetyNet)");let c=Sx.toBuffer(q.x5c[0],"base64"),n=xH(c),{subject:R}=n;if(R.CN!=="attest.android.com")throw Error('Certificate common name was not "attest.android.com" (SafetyNet)');let M=await TD.getStatement(f);if(M)try{await pD({statement:M,credentialPublicKey:Z,x5c:q.x5c,attestationStatementAlg:Y})}catch(J0){throw Error(`${J0.message} (SafetyNet)`)}else try{await t1(q.x5c.map(D5),D)}catch(J0){throw Error(`${J0.message} (SafetyNet)`)}let B0=jx.fromUTF8String(`${K[0]}.${K[1]}`),G0=Sx.toBuffer(b);return await w2({signature:G0,data:B0,x509Certificate:c,hashAlgorithm:Y})}var kX0={196:"TPM_ST_RSP_COMMAND",32768:"TPM_ST_NULL",32769:"TPM_ST_NO_SESSIONS",32770:"TPM_ST_SESSIONS",32788:"TPM_ST_ATTEST_NV",32789:"TPM_ST_ATTEST_COMMAND_AUDIT",32790:"TPM_ST_ATTEST_SESSION_AUDIT",32791:"TPM_ST_ATTEST_CERTIFY",32792:"TPM_ST_ATTEST_QUOTE",32793:"TPM_ST_ATTEST_TIME",32794:"TPM_ST_ATTEST_CREATION",32801:"TPM_ST_CREATION",32802:"TPM_ST_VERIFIED",32803:"TPM_ST_AUTH_SECRET",32804:"TPM_ST_HASHCHECK",32805:"TPM_ST_AUTH_SIGNED",32809:"TPM_ST_FU_MANIFEST"},HA={0:"TPM_ALG_ERROR",1:"TPM_ALG_RSA",4:"TPM_ALG_SHA",4:"TPM_ALG_SHA1",5:"TPM_ALG_HMAC",6:"TPM_ALG_AES",7:"TPM_ALG_MGF1",8:"TPM_ALG_KEYEDHASH",10:"TPM_ALG_XOR",11:"TPM_ALG_SHA256",12:"TPM_ALG_SHA384",13:"TPM_ALG_SHA512",16:"TPM_ALG_NULL",18:"TPM_ALG_SM3_256",19:"TPM_ALG_SM4",20:"TPM_ALG_RSASSA",21:"TPM_ALG_RSAES",22:"TPM_ALG_RSAPSS",23:"TPM_ALG_OAEP",24:"TPM_ALG_ECDSA",25:"TPM_ALG_ECDH",26:"TPM_ALG_ECDAA",27:"TPM_ALG_SM2",28:"TPM_ALG_ECSCHNORR",29:"TPM_ALG_ECMQV",32:"TPM_ALG_KDF1_SP800_56A",33:"TPM_ALG_KDF2",34:"TPM_ALG_KDF1_SP800_108",35:"TPM_ALG_ECC",37:"TPM_ALG_SYMCIPHER",38:"TPM_ALG_CAMELLIA",64:"TPM_ALG_CTR",65:"TPM_ALG_OFB",66:"TPM_ALG_CBC",67:"TPM_ALG_CFB",68:"TPM_ALG_ECB"},MX0={0:"TPM_ECC_NONE",1:"TPM_ECC_NIST_P192",2:"TPM_ECC_NIST_P224",3:"TPM_ECC_NIST_P256",4:"TPM_ECC_NIST_P384",5:"TPM_ECC_NIST_P521",16:"TPM_ECC_BN_P256",17:"TPM_ECC_BN_P638",32:"TPM_ECC_SM2_P256"},vX0={"id:414D4400":{name:"AMD",id:"AMD"},"id:414E5400":{name:"Ant Group",id:"ANT"},"id:41544D4C":{name:"Atmel",id:"ATML"},"id:4252434D":{name:"Broadcom",id:"BRCM"},"id:4353434F":{name:"Cisco",id:"CSCO"},"id:464C5953":{name:"Flyslice Technologies",id:"FLYS"},"id:524F4343":{name:"Fuzhou Rockchip",id:"ROCC"},"id:474F4F47":{name:"Google",id:"GOOG"},"id:48504900":{name:"HPI",id:"HPI"},"id:48504500":{name:"HPE",id:"HPE"},"id:48495349":{name:"Huawei",id:"HISI"},"id:49424d00":{name:"IBM",id:"IBM"},"id:49424D00":{name:"IBM",id:"IBM"},"id:49465800":{name:"Infineon",id:"IFX"},"id:494E5443":{name:"Intel",id:"INTC"},"id:4C454E00":{name:"Lenovo",id:"LEN"},"id:4D534654":{name:"Microsoft",id:"MSFT"},"id:4E534D20":{name:"National Semiconductor",id:"NSM"},"id:4E545A00":{name:"Nationz",id:"NTZ"},"id:4E534700":{name:"NSING",id:"NSG"},"id:4E544300":{name:"Nuvoton Technology",id:"NTC"},"id:51434F4D":{name:"Qualcomm",id:"QCOM"},"id:534D534E":{name:"Samsung",id:"SMSN"},"id:53454345":{name:"SecEdge",id:"SECE"},"id:534E5300":{name:"Sinosun",id:"SNS"},"id:534D5343":{name:"SMSC",id:"SMSC"},"id:53544D20":{name:"STMicroelectronics",id:"STM"},"id:54584E00":{name:"Texas Instruments",id:"TXN"},"id:57454300":{name:"Winbond",id:"WEC"},"id:5345414C":{name:"Wisekey",id:"SEAL"},"id:FFFFF1D0":{name:"FIDO Alliance",id:"FIDO"}},NX0={TPM_ECC_NIST_P256:1,TPM_ECC_NIST_P384:2,TPM_ECC_NIST_P521:3,TPM_ECC_BN_P256:1,TPM_ECC_SM2_P256:1};function IX0(x){let B=0,A=jx.toDataView(x),w=A.getUint32(B);B+=4;let f=A.getUint16(B);B+=2;let D=kX0[f],$=A.getUint16(B);B+=2;let Z=x.slice(B,B+=$),Q=A.getUint16(B);B+=2;let Y=x.slice(B,B+=Q),W=x.slice(B,B+=8),H=A.getUint32(B);B+=4;let F=A.getUint32(B);B+=4;let K=!!x.slice(B,B+=1),q={clock:W,resetCount:H,restartCount:F,safe:K},V=x.slice(B,B+=8),b=A.getUint16(B);B+=2;let G=x.slice(B,B+=b),E=jx.toDataView(G),_=A.getUint16(B);B+=2;let L=x.slice(B,B+=_),N={nameAlg:HA[E.getUint16(0)],nameAlgBuffer:G.slice(0,2),name:G,qualifiedName:L};return{magic:w,type:D,qualifiedSigner:Z,extraData:Y,clockInfo:q,firmwareVersion:V,attested:N}}function OX0(x){let B=0,A=jx.toDataView(x),w=HA[A.getUint16(B)];B+=2;let f=HA[A.getUint16(B)];B+=2;let D=A.getUint32(B);B+=4;let $={fixedTPM:!!(D&1),stClear:!!(D&2),fixedParent:!!(D&8),sensitiveDataOrigin:!!(D&16),userWithAuth:!!(D&32),adminWithPolicy:!!(D&64),noDA:!!(D&512),encryptedDuplication:!!(D&1024),restricted:!!(D&32768),decrypt:!!(D&65536),signOrEncrypt:!!(D&131072)},Z=A.getUint16(B);B+=2;let Q=x.slice(B,B+=Z),Y={},W=Uint8Array.from([]);if(w==="TPM_ALG_RSA"){let H=HA[A.getUint16(B)];B+=2;let F=HA[A.getUint16(B)];B+=2;let K=A.getUint16(B);B+=2;let q=A.getUint32(B);B+=4,Y.rsa={symmetric:H,scheme:F,keyBits:K,exponent:q};let V=A.getUint16(B);B+=2,W=x.slice(B,B+=V)}else if(w==="TPM_ALG_ECC"){let H=HA[A.getUint16(B)];B+=2;let F=HA[A.getUint16(B)];B+=2;let K=MX0[A.getUint16(B)];B+=2;let q=HA[A.getUint16(B)];B+=2,Y.ecc={symmetric:H,scheme:F,curveID:K,kdf:q};let V=A.getUint16(B);B+=2;let b=x.slice(B,B+=V),G=A.getUint16(B);B+=2;let E=x.slice(B,B+=G);W=jx.concat([b,E])}else throw Error(`Unexpected type "${w}" (TPM)`);return{type:w,nameAlg:f,objectAttributes:$,authPolicy:Q,parameters:Y,unique:W}}async function hX0(x){let{aaguid:B,attStmt:A,authData:w,credentialPublicKey:f,clientDataHash:D,rootCertificates:$}=x,Z=A.get("ver"),Q=A.get("sig"),Y=A.get("alg"),W=A.get("x5c"),H=A.get("pubArea"),F=A.get("certInfo");if(Z!=="2.0")throw Error(`Unexpected ver "${Z}", expected "2.0" (TPM)`);if(!Q)throw Error("No attestation signature provided in attestation statement (TPM)");if(!Y)throw Error("Attestation statement did not contain alg (TPM)");if(!e3(Y))throw Error(`Attestation statement contained invalid alg ${Y} (TPM)`);if(!W)throw Error("No attestation certificate provided in attestation statement (TPM)");if(!H)throw Error("Attestation statement did not contain pubArea (TPM)");if(!F)throw Error("Attestation statement did not contain certInfo (TPM)");let K=OX0(H),{unique:q,type:V,parameters:b}=K,G=zD(f);if(V==="TPM_ALG_RSA"){if(!_W(G))throw Error(`Credential public key with kty ${G.get(gx.kty)} did not match ${V}`);let X0=G.get(gx.n),Wx=G.get(gx.e);if(!X0)throw Error("COSE public key missing n (TPM|RSA)");if(!Wx)throw Error("COSE public key missing e (TPM|RSA)");if(!jx.areEqual(q,X0))throw Error("PubArea unique is not same as credentialPublicKey (TPM|RSA)");if(!b.rsa)throw Error("Parsed pubArea type is RSA, but missing parameters.rsa (TPM|RSA)");let A8=Wx,y8=b.rsa.exponent||65537,m8=A8[0]+(A8[1]<<8)+(A8[2]<<16);if(y8!==m8)throw Error(`Unexpected public key exp ${m8}, expected ${y8} (TPM|RSA)`)}else if(V==="TPM_ALG_ECC"){if(!KD(G))throw Error(`Credential public key with kty ${G.get(gx.kty)} did not match ${V}`);let X0=G.get(gx.crv),Wx=G.get(gx.x),A8=G.get(gx.y);if(!X0)throw Error("COSE public key missing crv (TPM|ECC)");if(!Wx)throw Error("COSE public key missing x (TPM|ECC)");if(!A8)throw Error("COSE public key missing y (TPM|ECC)");if(!jx.areEqual(q,jx.concat([Wx,A8])))throw Error("PubArea unique is not same as public key x and y (TPM|ECC)");if(!b.ecc)throw Error("Parsed pubArea type is ECC, but missing parameters.ecc (TPM|ECC)");let y8=b.ecc.curveID,m8=NX0[y8];if(m8!==X0)throw Error(`Public area key curve ID "${y8}" mapped to "${m8}" which did not match public key crv of "${X0}" (TPM|ECC)`)}else throw Error(`Unsupported pubArea.type "${V}"`);let E=IX0(F),{magic:_,type:L,attested:N,extraData:y}=E;if(_!==4283712327)throw Error(`Unexpected magic value "${_}", expected "0xff544347" (TPM)`);if(L!=="TPM_ST_ATTEST_CERTIFY")throw Error(`Unexpected type "${L}", expected "TPM_ST_ATTEST_CERTIFY" (TPM)`);let c=await A2(H,Zix(N.nameAlg)),n=jx.concat([N.nameAlgBuffer,c]);if(!jx.areEqual(N.name,n))throw Error("Attested name comparison failed (TPM)");let R=jx.concat([w,D]),M=await A2(R,Y);if(!jx.areEqual(y,M))throw Error("CertInfo extra data did not equal hashed attestation (TPM)");if(W.length<1)throw Error("No certificates present in x5c array (TPM)");let B0=xH(W[0]),{basicConstraintsCA:G0,version:I0,subject:J0,notAfter:v0,notBefore:Ex}=B0;if(G0)throw Error("Certificate basic constraints CA was not `false` (TPM)");if(I0!==2)throw Error("Certificate version was not `3` (ASN.1 value of 2) (TPM)");if(J0.combined.length>0)throw Error("Certificate subject was not empty (TPM)");let _0=new Date;if(Ex>_0)throw Error(`Certificate not good before "${Ex.toString()}" (TPM)`);if(_0=new Date,v0<_0)throw Error(`Certificate not good after "${v0.toString()}" (TPM)`);let Ax=o9.parse(W[0],i6);if(!Ax.tbsCertificate.extensions)throw Error("Certificate was missing extensions (TPM)");let u,t;if(Ax.tbsCertificate.extensions.forEach((X0)=>{if(X0.extnID===eW)u=o9.parse(X0.extnValue,tW);else if(X0.extnID===rW)t=o9.parse(X0.extnValue,nZ)}),!u)throw Error("Certificate did not contain subjectAltName extension (TPM)");if(!u[0].directoryName?.[0].length)throw Error("Certificate subjectAltName extension directoryName was empty (TPM)");let{tcgAtTpmManufacturer:F0,tcgAtTpmModel:$0,tcgAtTpmVersion:qx}=$ix(u[0].directoryName);if(!F0||!$0||!qx)throw Error("Certificate contained incomplete subjectAltName data (TPM)");if(!t)throw Error("Certificate did not contain ExtendedKeyUsage extension (TPM)");if(!vX0[F0])throw Error(`Could not match TPM manufacturer "${F0}" (TPM)`);if(t[0]!=="2.23.133.8.3")throw Error(`Unexpected extKeyUsage "${t[0]}", expected "2.23.133.8.3" (TPM)`);try{await $L(Ax.tbsCertificate.extensions,B)}catch(X0){throw Error(`${X0.message} (TPM)`)}let Nx=await TD.getStatement(B);if(Nx)try{await pD({statement:Nx,credentialPublicKey:f,x5c:W,attestationStatementAlg:Y})}catch(X0){throw Error(`${X0.message} (TPM)`)}else try{await t1(W.map(D5),$)}catch(X0){throw Error(`${X0.message} (TPM)`)}return w2({signature:Q,data:F,x509Certificate:W[0],hashAlgorithm:Y})}function $ix(x){let f,D,$;return x.forEach((Z)=>{Z.forEach((Q)=>{if(Q.type==="2.23.133.2.1")f=Q.value.toString();else if(Q.type==="2.23.133.2.2")D=Q.value.toString();else if(Q.type==="2.23.133.2.3")$=Q.value.toString()})}),{tcgAtTpmManufacturer:f,tcgAtTpmModel:D,tcgAtTpmVersion:$}}function Zix(x){if(x==="TPM_ALG_SHA256")return f8.ES256;else if(x==="TPM_ALG_SHA384")return f8.ES384;else if(x==="TPM_ALG_SHA512")return f8.ES512;throw Error(`Unexpected TPM attested name alg ${x}`)}var $u,RX0="1.3.6.1.4.1.11129.2.1.17",Zu;(function(x){x[x.verified=0]="verified",x[x.selfSigned=1]="selfSigned",x[x.unverified=2]="unverified",x[x.failed=3]="failed"})(Zu||(Zu={}));class hH{verifiedBootKey=new m0;deviceLocked=!1;verifiedBootState=Zu.verified;verifiedBootHash;constructor(x={}){Object.assign(this,x)}}U([j({type:m0})],hH.prototype,"verifiedBootKey",void 0);U([j({type:J.Boolean})],hH.prototype,"deviceLocked",void 0);U([j({type:J.Enumerated})],hH.prototype,"verifiedBootState",void 0);U([j({type:m0,optional:!0})],hH.prototype,"verifiedBootHash",void 0);var IH=$u=class extends Ux{constructor(B){super(B);Object.setPrototypeOf(this,$u.prototype)}};IH=$u=U([x0({type:a.Set,itemType:J.Integer})],IH);class cx{purpose;algorithm;keySize;digest;padding;ecCurve;rsaPublicExponent;mgfDigest;rollbackResistance;earlyBootOnly;activeDateTime;originationExpireDateTime;usageExpireDateTime;usageCountLimit;noAuthRequired;userAuthType;authTimeout;allowWhileOnBody;trustedUserPresenceRequired;trustedConfirmationRequired;unlockedDeviceRequired;allApplications;applicationId;creationDateTime;origin;rollbackResistant;rootOfTrust;osVersion;osPatchLevel;attestationApplicationId;attestationIdBrand;attestationIdDevice;attestationIdProduct;attestationIdSerial;attestationIdImei;attestationIdMeid;attestationIdManufacturer;attestationIdModel;vendorPatchLevel;bootPatchLevel;deviceUniqueAttestation;attestationIdSecondImei;moduleHash;constructor(x={}){Object.assign(this,x)}}U([j({context:1,type:IH,optional:!0})],cx.prototype,"purpose",void 0);U([j({context:2,type:J.Integer,optional:!0})],cx.prototype,"algorithm",void 0);U([j({context:3,type:J.Integer,optional:!0})],cx.prototype,"keySize",void 0);U([j({context:5,type:IH,optional:!0})],cx.prototype,"digest",void 0);U([j({context:6,type:IH,optional:!0})],cx.prototype,"padding",void 0);U([j({context:10,type:J.Integer,optional:!0})],cx.prototype,"ecCurve",void 0);U([j({context:200,type:J.Integer,optional:!0})],cx.prototype,"rsaPublicExponent",void 0);U([j({context:203,type:IH,optional:!0})],cx.prototype,"mgfDigest",void 0);U([j({context:303,type:J.Null,optional:!0})],cx.prototype,"rollbackResistance",void 0);U([j({context:305,type:J.Null,optional:!0})],cx.prototype,"earlyBootOnly",void 0);U([j({context:400,type:J.Integer,optional:!0})],cx.prototype,"activeDateTime",void 0);U([j({context:401,type:J.Integer,optional:!0})],cx.prototype,"originationExpireDateTime",void 0);U([j({context:402,type:J.Integer,optional:!0})],cx.prototype,"usageExpireDateTime",void 0);U([j({context:405,type:J.Integer,optional:!0})],cx.prototype,"usageCountLimit",void 0);U([j({context:503,type:J.Null,optional:!0})],cx.prototype,"noAuthRequired",void 0);U([j({context:504,type:J.Integer,optional:!0})],cx.prototype,"userAuthType",void 0);U([j({context:505,type:J.Integer,optional:!0})],cx.prototype,"authTimeout",void 0);U([j({context:506,type:J.Null,optional:!0})],cx.prototype,"allowWhileOnBody",void 0);U([j({context:507,type:J.Null,optional:!0})],cx.prototype,"trustedUserPresenceRequired",void 0);U([j({context:508,type:J.Null,optional:!0})],cx.prototype,"trustedConfirmationRequired",void 0);U([j({context:509,type:J.Null,optional:!0})],cx.prototype,"unlockedDeviceRequired",void 0);U([j({context:600,type:J.Null,optional:!0})],cx.prototype,"allApplications",void 0);U([j({context:601,type:m0,optional:!0})],cx.prototype,"applicationId",void 0);U([j({context:701,type:J.Integer,optional:!0})],cx.prototype,"creationDateTime",void 0);U([j({context:702,type:J.Integer,optional:!0})],cx.prototype,"origin",void 0);U([j({context:703,type:J.Null,optional:!0})],cx.prototype,"rollbackResistant",void 0);U([j({context:704,type:hH,optional:!0})],cx.prototype,"rootOfTrust",void 0);U([j({context:705,type:J.Integer,optional:!0})],cx.prototype,"osVersion",void 0);U([j({context:706,type:J.Integer,optional:!0})],cx.prototype,"osPatchLevel",void 0);U([j({context:709,type:m0,optional:!0})],cx.prototype,"attestationApplicationId",void 0);U([j({context:710,type:m0,optional:!0})],cx.prototype,"attestationIdBrand",void 0);U([j({context:711,type:m0,optional:!0})],cx.prototype,"attestationIdDevice",void 0);U([j({context:712,type:m0,optional:!0})],cx.prototype,"attestationIdProduct",void 0);U([j({context:713,type:m0,optional:!0})],cx.prototype,"attestationIdSerial",void 0);U([j({context:714,type:m0,optional:!0})],cx.prototype,"attestationIdImei",void 0);U([j({context:715,type:m0,optional:!0})],cx.prototype,"attestationIdMeid",void 0);U([j({context:716,type:m0,optional:!0})],cx.prototype,"attestationIdManufacturer",void 0);U([j({context:717,type:m0,optional:!0})],cx.prototype,"attestationIdModel",void 0);U([j({context:718,type:J.Integer,optional:!0})],cx.prototype,"vendorPatchLevel",void 0);U([j({context:719,type:J.Integer,optional:!0})],cx.prototype,"bootPatchLevel",void 0);U([j({context:720,type:J.Null,optional:!0})],cx.prototype,"deviceUniqueAttestation",void 0);U([j({context:723,type:m0,optional:!0})],cx.prototype,"attestationIdSecondImei",void 0);U([j({context:724,type:m0,optional:!0})],cx.prototype,"moduleHash",void 0);var nw;(function(x){x[x.software=0]="software",x[x.trustedEnvironment=1]="trustedEnvironment",x[x.strongBox=2]="strongBox"})(nw||(nw={}));var OH;(function(x){x[x.KM2=1]="KM2",x[x.KM3=2]="KM3",x[x.KM4=3]="KM4",x[x.KM4_1=4]="KM4_1",x[x.keyMint1=100]="keyMint1",x[x.keyMint2=200]="keyMint2",x[x.keyMint3=300]="keyMint3",x[x.keyMint4=400]="keyMint4"})(OH||(OH={}));class ZB{attestationVersion=OH.KM4;attestationSecurityLevel=nw.software;keymasterVersion=0;keymasterSecurityLevel=nw.software;attestationChallenge=new m0;uniqueId=new m0;softwareEnforced=new cx;teeEnforced=new cx;constructor(x={}){Object.assign(this,x)}}U([j({type:J.Integer})],ZB.prototype,"attestationVersion",void 0);U([j({type:J.Enumerated})],ZB.prototype,"attestationSecurityLevel",void 0);U([j({type:J.Integer})],ZB.prototype,"keymasterVersion",void 0);U([j({type:J.Enumerated})],ZB.prototype,"keymasterSecurityLevel",void 0);U([j({type:m0})],ZB.prototype,"attestationChallenge",void 0);U([j({type:m0})],ZB.prototype,"uniqueId",void 0);U([j({type:cx})],ZB.prototype,"softwareEnforced",void 0);U([j({type:cx})],ZB.prototype,"teeEnforced",void 0);class FA{attestationVersion=OH.keyMint4;attestationSecurityLevel=nw.software;keyMintVersion=0;keyMintSecurityLevel=nw.software;attestationChallenge=new m0;uniqueId=new m0;softwareEnforced=new cx;hardwareEnforced=new cx;constructor(x={}){Object.assign(this,x)}toLegacyKeyDescription(){return new ZB({attestationVersion:this.attestationVersion,attestationSecurityLevel:this.attestationSecurityLevel,keymasterVersion:this.keyMintVersion,keymasterSecurityLevel:this.keyMintSecurityLevel,attestationChallenge:this.attestationChallenge,uniqueId:this.uniqueId,softwareEnforced:this.softwareEnforced,teeEnforced:this.hardwareEnforced})}static fromLegacyKeyDescription(x){return new FA({attestationVersion:x.attestationVersion,attestationSecurityLevel:x.attestationSecurityLevel,keyMintVersion:x.keymasterVersion,keyMintSecurityLevel:x.keymasterSecurityLevel,attestationChallenge:x.attestationChallenge,uniqueId:x.uniqueId,softwareEnforced:x.softwareEnforced,hardwareEnforced:x.teeEnforced})}}U([j({type:J.Integer})],FA.prototype,"attestationVersion",void 0);U([j({type:J.Enumerated})],FA.prototype,"attestationSecurityLevel",void 0);U([j({type:J.Integer})],FA.prototype,"keyMintVersion",void 0);U([j({type:J.Enumerated})],FA.prototype,"keyMintSecurityLevel",void 0);U([j({type:m0})],FA.prototype,"attestationChallenge",void 0);U([j({type:m0})],FA.prototype,"uniqueId",void 0);U([j({type:cx})],FA.prototype,"softwareEnforced",void 0);U([j({type:cx})],FA.prototype,"hardwareEnforced",void 0);var Qu,Xu=class extends cx{};Xu=U([x0({type:a.Choice})],Xu);var RH=Qu=class extends Ux{constructor(B){super(B);Object.setPrototypeOf(this,Qu.prototype)}findProperty(B){let A=this.find((w)=>w[B]!==void 0);if(A)return A[B];return}};RH=Qu=U([x0({type:a.Sequence,itemType:Xu})],RH);class KA{attestationVersion=OH.KM4;attestationSecurityLevel=nw.software;keymasterVersion=0;keymasterSecurityLevel=nw.software;attestationChallenge=new m0;uniqueId=new m0;softwareEnforced=new RH;teeEnforced=new RH;get keyMintVersion(){return this.keymasterVersion}set keyMintVersion(x){this.keymasterVersion=x}get keyMintSecurityLevel(){return this.keymasterSecurityLevel}set keyMintSecurityLevel(x){this.keymasterSecurityLevel=x}get hardwareEnforced(){return this.teeEnforced}set hardwareEnforced(x){this.teeEnforced=x}constructor(x={}){Object.assign(this,x)}}U([j({type:J.Integer})],KA.prototype,"attestationVersion",void 0);U([j({type:J.Enumerated})],KA.prototype,"attestationSecurityLevel",void 0);U([j({type:J.Integer})],KA.prototype,"keymasterVersion",void 0);U([j({type:J.Enumerated})],KA.prototype,"keymasterSecurityLevel",void 0);U([j({type:m0})],KA.prototype,"attestationChallenge",void 0);U([j({type:m0})],KA.prototype,"uniqueId",void 0);U([j({type:RH})],KA.prototype,"softwareEnforced",void 0);U([j({type:RH})],KA.prototype,"teeEnforced",void 0);var yX0=class extends KA{constructor(B={}){if("keymasterVersion"in B&&!("keyMintVersion"in B))B.keyMintVersion=B.keymasterVersion;if("keymasterSecurityLevel"in B&&!("keyMintSecurityLevel"in B))B.keyMintSecurityLevel=B.keymasterSecurityLevel;if("teeEnforced"in B&&!("hardwareEnforced"in B))B.hardwareEnforced=B.teeEnforced;super(B)}};yX0=U([x0({type:a.Sequence})],yX0);class ZL{packageName;version;constructor(x={}){Object.assign(this,x)}}U([j({type:J.OctetString})],ZL.prototype,"packageName",void 0);U([j({type:J.Integer})],ZL.prototype,"version",void 0);class Yu{packageInfos;signatureDigests;constructor(x={}){Object.assign(this,x)}}U([j({type:ZL,repeated:"set"})],Yu.prototype,"packageInfos",void 0);U([j({type:J.OctetString,repeated:"set"})],Yu.prototype,"signatureDigests",void 0);async function mX0(x){let{authData:B,clientDataHash:A,attStmt:w,credentialPublicKey:f,aaguid:D,rootCertificates:$}=x,Z=w.get("x5c"),Q=w.get("sig"),Y=w.get("alg");if(!Z)throw Error("No attestation certificate provided in attestation statement (Android Key)");if(!Q)throw Error("No attestation signature provided in attestation statement (Android Key)");if(!Y)throw Error("Attestation statement did not contain alg (Android Key)");if(!e3(Y))throw Error(`Attestation statement contained invalid alg ${Y} (Android Key)`);let W=o9.parse(Z[0],i6),H=new Uint8Array(W.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey),F=JW(f);if(!jx.areEqual(F,H))throw Error("Credential public key does not equal leaf cert public key (Android Key)");let K=W.tbsCertificate.extensions?.find((L)=>L.extnID===RX0);if(!K)throw Error("Certificate did not contain extKeyStore (Android Key)");let q=o9.parse(K.extnValue,ZB),{attestationChallenge:V,teeEnforced:b,softwareEnforced:G}=q;if(!jx.areEqual(new Uint8Array(V.buffer),A))throw Error("Attestation challenge was not equal to client data hash (Android Key)");if(b.allApplications!==void 0)throw Error('teeEnforced contained "allApplications [600]" tag (Android Key)');if(G.allApplications!==void 0)throw Error('teeEnforced contained "allApplications [600]" tag (Android Key)');let E=await TD.getStatement(D);if(E)try{await pD({statement:E,credentialPublicKey:f,x5c:Z,attestationStatementAlg:Y})}catch(L){let N=L;throw Error(`${N.message} (Android Key)`,{cause:N})}else{let L=Z.slice(0,-1).map(D5),N=Z.slice(-1).map(D5);try{await t1(L,N)}catch(y){let c=y;throw Error(`${c.message} (Android Key)`,{cause:c})}if($.length>0&&$.indexOf(N[0])<0)throw Error("x5c root certificate was not a known root certificate (Android Key)")}let _=jx.concat([B,A]);return w2({signature:Q,data:_,x509Certificate:Z[0],hashAlgorithm:Y})}async function CX0(x){let{attStmt:B,authData:A,clientDataHash:w,credentialPublicKey:f,rootCertificates:D}=x,$=B.get("x5c");if(!$)throw Error("No attestation certificate provided in attestation statement (Apple)");try{await t1($.map(D5),D)}catch(b){throw Error(`${b.message} (Apple)`)}let Z=o9.parse($[0],i6),{extensions:Q,subjectPublicKeyInfo:Y}=Z.tbsCertificate;if(!Q)throw Error("credCert missing extensions (Apple)");let W=Q.find((b)=>b.extnID==="1.2.840.113635.100.8.2");if(!W)throw Error('credCert missing "1.2.840.113635.100.8.2" extension (Apple)');let H=jx.concat([A,w]),F=await A2(H),K=new Uint8Array(W.extnValue.buffer).slice(6);if(!jx.areEqual(F,K))throw Error("credCert nonce was not expected value (Apple)");let q=JW(f),V=new Uint8Array(Y.subjectPublicKey);if(!jx.areEqual(q,V))throw Error("Credential public key does not equal credCert public key (Apple)");return!0}async function cX0(x){let{response:B,expectedChallenge:A,expectedOrigin:w,expectedRPID:f,expectedType:D,requireUserPresence:$=!0,requireUserVerification:Z=!0,supportedAlgorithmIDs:Q=qX0,attestationSafetyNetEnforceCTSCheck:Y=!0}=x,{id:W,rawId:H,type:F,response:K}=B;if(!W)throw Error("Missing credential ID");if(W!==H)throw Error("Credential ID was not base64url-encoded");if(F!=="public-key")throw Error(`Unexpected credential type ${F}, expected "public-key"`);let q=pP(K.clientDataJSON),{type:V,origin:b,challenge:G,tokenBinding:E}=q;if(Array.isArray(D)){if(!D.includes(V)){let X0=D.join(", ");throw Error(`Unexpected registration response type "${V}", expected one of: ${X0}`)}}else if(D){if(V!==D)throw Error(`Unexpected registration response type "${V}", expected "${D}"`)}else if(V!=="webauthn.create")throw Error(`Unexpected registration response type: ${V}`);if(typeof A==="function"){if(!await A(G))throw Error(`Custom challenge verifier returned false for registration response challenge "${G}"`)}else if(G!==A)throw Error(`Unexpected registration response challenge "${G}", expected "${A}"`);if(Array.isArray(w)){if(!w.includes(b))throw Error(`Unexpected registration response origin "${b}", expected one of: ${w.join(", ")}`)}else if(b!==w)throw Error(`Unexpected registration response origin "${b}", expected "${w}"`);if(E){if(typeof E!=="object")throw Error(`Unexpected value for TokenBinding "${E}"`);if(["present","supported","not-supported"].indexOf(E.status)<0)throw Error(`Unexpected tokenBinding.status value of "${E.status}"`)}let _=Sx.toBuffer(K.attestationObject),L=cf0(_),N=L.get("fmt"),y=L.get("authData"),c=L.get("attStmt"),n=BL(y),{aaguid:R,rpIdHash:M,flags:B0,credentialID:G0,counter:I0,credentialPublicKey:J0,extensionsData:v0}=n,Ex;if(f){let X0=[];if(typeof f==="string")X0=[f];else X0=f;Ex=await DL(M,X0)}if($&&!B0.up)throw Error("User presence was required, but user was not present");if(Z&&!B0.uv)throw Error("User verification was required, but user could not be verified");if(!G0)throw Error("No credential ID was provided by authenticator");if(!J0)throw Error("No public key was provided by authenticator");if(!R)throw Error("No AAGUID was present during registration");let Ax=zD(J0).get(gx.alg);if(typeof Ax!=="number")throw Error("Credential public key was missing numeric alg");if(!Q.includes(Ax)){let X0=Q.join(", ");throw Error(`Unexpected public key alg "${Ax}", expected one of "${X0}"`)}let u=await A2(Sx.toBuffer(K.clientDataJSON)),t=gD.getRootCertificates({identifier:N}),F0={aaguid:R,attStmt:c,authData:y,clientDataHash:u,credentialID:G0,credentialPublicKey:J0,rootCertificates:t,rpIdHash:M,attestationSafetyNetEnforceCTSCheck:Y},$0=!1;if(N==="fido-u2f")$0=await UX0(F0);else if(N==="packed")$0=await JX0(F0);else if(N==="android-safetynet")$0=await LX0(F0);else if(N==="android-key")$0=await mX0(F0);else if(N==="tpm")$0=await hX0(F0);else if(N==="apple")$0=await CX0(F0);else if(N==="none"){if(c.size>0)throw Error("None attestation had unexpected attestation statement");$0=!0}else throw Error(`Unsupported Attestation Format: ${N}`);if(!$0)return{verified:!1};let{credentialDeviceType:qx,credentialBackedUp:Nx}=fL(B0);return{verified:!0,registrationInfo:{fmt:N,aaguid:TP(R),credentialType:F,credential:{id:Sx.fromBuffer(G0),publicKey:J0,counter:I0,transports:B.response.transports},attestationObject:_,userVerified:B0.uv,credentialDeviceType:qx,credentialBackedUp:Nx,origin:q.origin,rpID:Ex,authenticatorExtensionResults:v0}}}async function gX0(x){let{allowCredentials:B,challenge:A=await wL(),timeout:w=60000,userVerification:f="preferred",extensions:D,rpID:$}=x,Z=A;if(typeof Z==="string")Z=jx.fromUTF8String(Z);return{rpId:$,challenge:Sx.fromBuffer(Z),allowCredentials:B?.map((Q)=>{if(!Sx.isBase64URL(Q.id))throw Error(`allowCredential id "${Q.id}" is not a valid base64url string`);return{...Q,id:Sx.trimPadding(Q.id),type:"public-key"}}),timeout:w,userVerification:f,extensions:D}}async function TX0(x){let{response:B,expectedChallenge:A,expectedOrigin:w,expectedRPID:f,expectedType:D,credential:$,requireUserVerification:Z=!0,advancedFIDOConfig:Q}=x,{id:Y,rawId:W,type:H,response:F}=B;if(!Y)throw Error("Missing credential ID");if(Y!==W)throw Error("Credential ID was not base64url-encoded");if(H!=="public-key")throw Error(`Unexpected credential type ${H}, expected "public-key"`);if(!B)throw Error("Credential missing response");if(typeof F?.clientDataJSON!=="string")throw Error("Credential response clientDataJSON was not a string");let K=pP(F.clientDataJSON),{type:q,origin:V,challenge:b,tokenBinding:G}=K;if(Array.isArray(D)){if(!D.includes(q)){let Ex=D.join(", ");throw Error(`Unexpected authentication response type "${q}", expected one of: ${Ex}`)}}else if(D){if(q!==D)throw Error(`Unexpected authentication response type "${q}", expected "${D}"`)}else if(q!=="webauthn.get")throw Error(`Unexpected authentication response type: ${q}`);if(typeof A==="function"){if(!await A(b))throw Error(`Custom challenge verifier returned false for registration response challenge "${b}"`)}else if(b!==A)throw Error(`Unexpected authentication response challenge "${b}", expected "${A}"`);if(Array.isArray(w)){if(!w.includes(V)){let Ex=w.join(", ");throw Error(`Unexpected authentication response origin "${V}", expected one of: ${Ex}`)}}else if(V!==w)throw Error(`Unexpected authentication response origin "${V}", expected "${w}"`);if(!Sx.isBase64URL(F.authenticatorData))throw Error("Credential response authenticatorData was not a base64url string");if(!Sx.isBase64URL(F.signature))throw Error("Credential response signature was not a base64url string");if(F.userHandle&&typeof F.userHandle!=="string")throw Error("Credential response userHandle was not a string");if(G){if(typeof G!=="object")throw Error("ClientDataJSON tokenBinding was not an object");if(["present","supported","notSupported"].indexOf(G.status)<0)throw Error(`Unexpected tokenBinding status ${G.status}`)}let E=Sx.toBuffer(F.authenticatorData),_=BL(E),{rpIdHash:L,flags:N,counter:y,extensionsData:c}=_,n=[];if(typeof f==="string")n=[f];else n=f;let R=await DL(L,n);if(Q!==void 0){let{userVerification:Ex}=Q;if(Ex==="required"){if(!N.uv)throw Error("User verification required, but user could not be verified")}}else{if(!N.up)throw Error("User not present during authentication");if(Z&&!N.uv)throw Error("User verification required, but user could not be verified")}let M=await A2(Sx.toBuffer(F.clientDataJSON)),B0=jx.concat([E,M]),G0=Sx.toBuffer(F.signature);if((y>0||$.counter>0)&&y<=$.counter)throw Error(`Response counter value ${y} was lower than expected ${$.counter}`);let{credentialDeviceType:I0,credentialBackedUp:J0}=fL(N);return{verified:await w2({signature:G0,data:B0,credentialPublicKey:$.publicKey}),authenticationInfo:{newCounter:y,credentialID:$.id,userVerified:N.uv,credentialDeviceType:I0,credentialBackedUp:J0,authenticatorExtensionResults:c,origin:K.origin,rpID:R}}}var pX0="Anchor",Qix="Brain",Xix=X.looseObject({challenge:X.string().optional()});class QL{store;rpName;logger;constructor(x){this.store=new Qg(x.runtimeDatabase),this.rpName=x.rpName??Qix,this.logger=x.logger}async hasCredentials(){return this.store.hasCredentials()}async generateRegistrationOptions(x,B){let A=await this.store.listCredentials(B.subject),w=B.userName??pX0,f=B.userDisplayName??w,D=await zX0({rpName:this.rpName,rpID:x.rpID,userName:w,userDisplayName:f,attestationType:"none",authenticatorSelection:{residentKey:"required",userVerification:"required"},excludeCredentials:A.map(($)=>({id:$.id,...$.transports?{transports:$.transports}:{}}))});return await this.store.saveRegistrationChallenge(D.challenge,B.subject),D}async verifyRegistrationResponse(x,B,A){let w=x.response.clientDataJSON?uX0(x.response.clientDataJSON):void 0;if(!w)return{verified:!1};let f=await this.store.consumeRegistrationChallenge(w);if(!f||A!==void 0&&f.subject!==A)return{verified:!1};let D=await cX0({response:x,expectedChallenge:w,expectedOrigin:B.origin,expectedRPID:B.rpID,requireUserVerification:!0});if(!D.verified)return{verified:!1};let $=Math.floor(Date.now()/1000),Z=D.registrationInfo.credential;return await this.store.addCredential({id:Z.id,public_key:Yix(Z.publicKey),counter:Z.counter,...Z.transports?{transports:Z.transports}:{},subject:f.subject,user_name:pX0,credential_device_type:D.registrationInfo.credentialDeviceType,credential_backed_up:D.registrationInfo.credentialBackedUp,created_at:$,updated_at:$}),this.logger?.info("Registered passkey credential",{credentialId:Z.id}),{verified:!0,subject:f.subject}}async listCredentials(){return this.store.listCredentials()}async generateAuthenticationOptions(x){let B=await gX0({rpID:x.rpID,userVerification:"required"});return await this.store.saveAuthenticationChallenge(B.challenge),B}async verifyAuthenticationResponse(x,B){let A=x.response.clientDataJSON?uX0(x.response.clientDataJSON):void 0;if(!A)return{verified:!1};if(!await this.store.consumeAuthenticationChallenge(A))return{verified:!1};let f=await this.store.getCredential(x.id);if(!f)return{verified:!1};let D=await TX0({response:x,expectedChallenge:A,expectedOrigin:B.origin,expectedRPID:B.rpID,credential:Hix(f),requireUserVerification:!0});if(!D.verified)return{verified:!1};return await this.store.updateCredentialCounter(D.authenticationInfo.credentialID,D.authenticationInfo.newCounter),{verified:!0,subject:f.subject}}}function Yix(x){return Buffer.from(x).toString("base64url")}function Wix(x){let B=Buffer.from(x,"base64url"),A=B.buffer.slice(B.byteOffset,B.byteOffset+B.byteLength);return new Uint8Array(A)}function Hix(x){return{id:x.id,publicKey:Wix(x.public_key),counter:x.counter,...x.transports?{transports:x.transports}:{}}}function uX0(x){try{return Xix.parse(JSON.parse(Buffer.from(x,"base64url").toString("utf8"))).challenge}catch{return}}class Wu{issuer;users;identities;audit;setupFlow;targetedSetup;getChannelDescriptor;constructor(x){this.issuer=x.issuer,this.users=x.users,this.identities=x.identities,this.audit=x.audit,this.setupFlow=x.setupFlow,this.targetedSetup=x.targetedSetup,this.getChannelDescriptor=x.getChannelDescriptor}getSetupUrl(x=this.issuer){return this.setupFlow.getSetupUrl(x)}async startRegistration(x,B={},A){let w=await this.users.getUser(x);if(!w||w.status==="suspended")throw Error(`Eligible auth user not found: ${x}`);let f=A?await this.prepareDeliveryIdentity(x,A):await this.resolveStoredDeliveryIdentity(x),D=await this.setupFlow.createUserPasskeySetup(x,this.issuer,{deliveryClaimId:f.id});return await this.setupFlow.recordSetupDelivery(D.setupTokenId,f.deliverySubject),await this.audit.append({...H7(B),action:"auth.passkey.registration_started",targetType:"user",targetId:x,metadata:{expiresAt:D.expiresAt,deliveryType:f.type}}),{setupUrl:D.setupUrl,expiresAt:D.expiresAt,delivery:{type:f.type,label:this.getChannelDescriptor?.(f.type)?.subjectLabel??"Delivery channel"}}}async validateTargetedRegistration(x){await this.targetedSetup.validate({userId:x.targetUserId,setupTokenId:d1(x.token)})}async completeTargetedRegistration(x){let B=await this.users.getUser(x.targetUserId),A=await this.targetedSetup.complete({userId:x.targetUserId,setupTokenId:d1(x.token)});if(B?.status==="invited"&&A.user.status==="active")await this.audit.append({actorUserId:A.user.id,action:"auth.user.status_updated",targetType:"user",targetId:A.user.id,metadata:{status:"active"}});if(A.boundIdentity)await this.audit.append({actorUserId:A.user.id,action:"auth.identity.delivery_bound",targetType:"user",targetId:A.user.id,metadata:{type:A.boundIdentity.type}})}getPasskeySetupRequired(x=this.issuer){return this.setupFlow.getPasskeySetupRequired(x,{rotateHidden:!0})}getPasskeySetupRequiredForDelivery(x=this.issuer){return this.setupFlow.getPasskeySetupRequired(x)}hasSetupEmailDelivery(x,B){return this.setupFlow.hasSetupEmailDelivery(x,B)}recordSetupEmailDelivery(x,B,A={}){return this.setupFlow.recordSetupEmailDelivery(x,B,A)}async resolveStoredDeliveryIdentity(x){let A=(await this.identities.listIdentities(x)).filter((w)=>w.revokedAt===null&&Boolean(w.deliverySubject)&&w.evidence.some((f)=>f.sourceKind==="admin"||f.assurance==="verified"&&f.verifiedAt!==null)).at(-1);if(!A)throw Error("A confirmed delivery channel is required");return A}async prepareDeliveryIdentity(x,B){let A=B.subject.trim(),w=B.label?.trim(),{identity:f}=await this.identities.ensureIdentity({userId:x,type:B.type,subject:A,deliverySubject:A,label:w&&w.length>0?w:A,source:{kind:"admin"}});if(!f.deliverySubject)throw Error("Delivery identity subject was not persisted");return{...f,deliverySubject:f.deliverySubject}}}class XL{db;constructor(x){this.db=x}async invitePeerPerson(x){let B=Hu(x.peerId);return this.db.transaction(async(A)=>{await SX0(A,x.createdByUserId);let[w]=await A.select({peerId:O9.peerId}).from(O9).where(i(O9.peerId,B)).limit(1);if(w)throw Error("External peer is already linked");let f=Date.now(),D={id:i8("prsn"),displayName:x.displayName,profileEntityId:null,createdAt:f,updatedAt:f},$=i8("usr"),Z={id:$,personId:D.id,displayName:x.displayName,role:x.role,status:"invited",canonicalId:`user:${$.slice(4)}`,createdAt:f,updatedAt:f},Q={peerId:B,personId:D.id,verificationStatus:"unverified",createdByUserId:x.createdByUserId,createdAt:f,updatedAt:f};return await A.insert(w9).values(D),await A.insert(S0).values(Z),await A.insert(O9).values(Q),{person:D,user:Z,peer:Q}})}async linkPeer(x){let B=Hu(x.peerId);return this.db.transaction(async(A)=>{await SX0(A,x.createdByUserId);let[w]=await A.select().from(O9).where(i(O9.peerId,B)).limit(1);if(w){if(w.personId!==x.personId)throw Error("External peer is already linked to another person");return w}let[f]=await A.select({id:w9.id}).from(w9).where(i(w9.id,x.personId)).limit(1);if(!f)throw Error(`Auth person not found: ${x.personId}`);let D=Date.now(),$={peerId:B,personId:f.id,verificationStatus:"unverified",createdByUserId:x.createdByUserId,createdAt:D,updatedAt:D};return await A.insert(O9).values($),$})}async getByPeerId(x){let[B]=await this.db.select().from(O9).where(i(O9.peerId,Hu(x))).limit(1);return B}async listByPersonId(x){return this.db.select().from(O9).where(i(O9.personId,x)).orderBy(O9.createdAt,ux`rowid`)}async listAll(){return this.db.select().from(O9).orderBy(O9.createdAt,ux`rowid`)}}function Hu(x){let B=x.trim();if(!B)throw Error("External peer id is required");return B}async function SX0(x,B){let[A]=await x.select().from(S0).where(i(S0.id,B)).limit(1);if(A?.role!=="admin"||A.status!=="active")throw Error("An active Admin is required to link an external peer");return A}class YL{database;constructor(x){this.database=x}async get(x){let[B]=await this.database.db.select().from(bw).where(i(bw.domain,Fu(x))).limit(1);return B?{domain:B.domain,keyFingerprint:B.keyFingerprint,grantedLevel:B.grantedLevel}:void 0}async grant(x,B={}){if(x.grantedLevel==="admin")throw Error("A2A peer trust grants must be trusted or public");let A={domain:Fu(x.domain),keyFingerprint:x.keyFingerprint,grantedLevel:x.grantedLevel},w=Date.now();return await this.database.db.insert(bw).values({domain:A.domain,keyFingerprint:A.keyFingerprint,grantedLevel:A.grantedLevel,createdAt:w,updatedAt:w}).onConflictDoUpdate({target:bw.domain,set:{keyFingerprint:A.keyFingerprint,grantedLevel:A.grantedLevel,updatedAt:w}}),await new d2(this.database.db).append({...B.actorUserId?{actorUserId:B.actorUserId}:{},action:"auth.a2a_peer_trust.granted",targetType:"a2a_peer",targetId:A.domain,metadata:{keyFingerprint:A.keyFingerprint,grantedLevel:A.grantedLevel}}),A}async revoke(x,B={}){let A=Fu(x);if((await this.database.db.delete(bw).where(i(bw.domain,A)).returning({domain:bw.domain})).length>0)await new d2(this.database.db).append({...B.actorUserId?{actorUserId:B.actorUserId}:{},action:"auth.a2a_peer_trust.revoked",targetType:"a2a_peer",targetId:A})}}function Fu(x){let B=x.trim().toLowerCase();if(!B||B.includes(":")||B.includes("/"))throw Error("A2A peer trust domain must be a bare domain");return B}import{randomUUID as iX0}from"crypto";var _V=86400;class Ku{setupStateStore;passkeyService;setupTokenTtlSeconds;resolveSessionUserId;setupToken;constructor(x){this.setupStateStore=x.setupStateStore,this.passkeyService=x.passkeyService,this.setupTokenTtlSeconds=x.setupTokenTtlSeconds??_V,this.resolveSessionUserId=x.resolveSessionUserId}async ensureSetupToken(){let x=this.getValidSetupToken();if(x)return x;let B=await this.setupStateStore.getValidSetupToken(Math.floor(Date.now()/1000));if(B)return this.setupToken=B,B;let A=Math.floor(Date.now()/1000);if(await this.setupStateStore.hasActiveSetupToken(A))return await this.setupStateStore.hasActiveSetupDelivery(A)?void 0:this.createSetupToken();return this.createSetupToken()}async createSetupToken(){return this.setupToken={token:`setup_${iX0()}`,expiresAt:Math.floor(Date.now()/1000)+this.setupTokenTtlSeconds},await this.setupStateStore.saveSetupToken(this.setupToken),this.setupToken}getValidSetupToken(){if(!this.setupToken)return;if(this.setupToken.expiresAt<=Math.floor(Date.now()/1000)){this.setupToken=void 0;return}return this.setupToken}async resolveSetupToken(x){let B=new URL(x.url),A=B.searchParams.get("setup_token")??B.searchParams.get("token");if(!A)return;let w=await this.setupStateStore.getSetupTokenTarget(A,Math.floor(Date.now()/1000));return w?{token:A,...w}:void 0}async hasValidSetupToken(x){return Boolean(await this.resolveSetupToken(x))}async hasConflictingAccountSession(x,B){if(!B.targetUserId||!this.resolveSessionUserId)return!1;let A=await this.resolveSessionUserId(x);return A!==void 0&&A!==B.targetUserId}async consumeSetupToken(x){if(this.setupToken?.token===x)this.setupToken=void 0;await this.setupStateStore.consumeSetupToken(x)}async clearSetupState(){this.setupToken=void 0,await this.setupStateStore.clearSetupState()}getSetupUrl(x){let B=this.getValidSetupToken();if(!B)return;return Y7(x,`/setup?token=${encodeURIComponent(B.token)}`)}async getPasskeySetupRequired(x,B={}){if(await this.passkeyService.hasCredentials())return;let A=this.getValidSetupToken();if(!A&&B.rotateHidden){let w=Math.floor(Date.now()/1000);if(await this.setupStateStore.hasActiveSetupDelivery(w))return;A=await this.createSetupToken()}if(!A)return;return{setupUrl:Y7(x,`/setup?token=${encodeURIComponent(A.token)}`),expiresAt:A.expiresAt,setupTokenId:d1(A.token)}}async createUserPasskeySetup(x,B,A={}){let w={token:`setup_${iX0()}`,expiresAt:Math.floor(Date.now()/1000)+this.setupTokenTtlSeconds};return await this.setupStateStore.saveTargetedSetupToken(w,x,A),{setupUrl:Y7(B,`/setup?token=${encodeURIComponent(w.token)}`),expiresAt:w.expiresAt,setupTokenId:d1(w.token)}}consumeTargetedSetupTokensForUser(x){return this.setupStateStore.consumeTargetedSetupTokensForUser(x)}async handleSetupPage(x){let B=await this.resolveSetupToken(x);if(await this.passkeyService.hasCredentials()&&B?.targetUserId==null)return new Response("Setup already completed",{status:404});if(!B)return new Response("Not Found",{status:404});if(await this.hasConflictingAccountSession(x,B)){let A=new URL(x.url);return RZ(Ow0(`${A.pathname}${A.search}`),409)}return RZ(hw0(B.token))}async hasSetupDelivery(x,B){return this.setupStateStore.hasDelivery(x,B)}async recordSetupDelivery(x,B,A={}){await this.setupStateStore.recordDelivery(x,B,A)}async hasSetupEmailDelivery(x,B){return this.hasSetupDelivery(x,B)}async recordSetupEmailDelivery(x,B,A={}){await this.recordSetupDelivery(x,B,A)}}class qu{db;identityStore;constructor(x,B){this.db=x,this.identityStore=B}async validate(x){await lX0(this.db,x)}async complete(x){let B=Math.floor(Date.now()/1000),A=Date.now(),w=await this.db.transaction(async(f)=>{let D=await lX0(f,x),$=D.deliveryClaim;if($){let[Q]=await f.select({id:b6.id}).from(b6).where(i0(i(b6.claimId,$.id),i(b6.assurance,"verified"),FW(b6.verifiedAt))).limit(1);if(!Q)await f.insert(b6).values({id:i8("aev"),claimId:$.id,sourceKind:"provider",sourceId:null,assurance:"verified",verifiedAt:A,createdAt:A})}if(D.user.status==="invited")await f.update(S0).set({status:"active",updatedAt:A}).where(i(S0.id,D.user.id));if((await f.update(h0).set({consumedAt:B}).where(i0(i(h0.tokenHash,x.setupTokenId),Jx(h0.consumedAt))).returning({tokenHash:h0.tokenHash})).length!==1)throw Error("Invalid or consumed setup token");return await f.update(yx).set({state:"claimed",claimedAt:A,updatedAt:A}).where(i(yx.currentSetupTokenHash,x.setupTokenId)),$?.id});return{user:await this.requireUser(x.userId),...w?{boundIdentity:await this.identityStore.getIdentity(w)}:{}}}async requireUser(x){let[B]=await this.db.select().from(S0).where(i(S0.id,x)).limit(1);if(!B)throw Error(`Auth user not found: ${x}`);return B}}async function lX0(x,B){let A=Math.floor(Date.now()/1000),[w]=await x.select().from(h0).where(i0(i(h0.tokenHash,B.setupTokenId),i(h0.purpose,"passkey_setup"),i(h0.targetUserId,B.userId),Jx(h0.consumedAt),F1(h0.expiresAt,A))).limit(1);if(!w)throw Error("Invalid or consumed setup token");let[f]=await x.select().from(S0).where(i(S0.id,B.userId)).limit(1);if(!f||f.status==="suspended")throw Error("Passkey registration user is unavailable");if(!w.deliveryClaimId)return{user:f};let[D]=await x.select().from(Lx).where(i0(i(Lx.id,w.deliveryClaimId),Jx(Lx.revokedAt))).limit(1);if(!D)throw Error("Setup delivery identity is unavailable");if(D.personId!==f.personId)throw Error("Setup delivery identity does not belong to target user");if(D.type!=="email"&&D.type!=="discord"||!D.deliverySubject)throw Error("Setup delivery identity is unavailable");let[$]=await x.select({tokenHash:H1.tokenHash}).from(H1).where(i0(i(H1.tokenHash,B.setupTokenId),i(H1.recipientHash,CZ(D.deliverySubject)))).limit(1);if(!$)throw Error("Setup delivery was not confirmed");return{user:f,deliveryClaim:D}}class zu{users;audit;sessions;refreshTokens;consumeTargetedSetupTokensForUser;constructor(x){this.users=x.users,this.audit=x.audit,this.sessions=x.sessions,this.refreshTokens=x.refreshTokens,this.consumeTargetedSetupTokensForUser=x.consumeTargetedSetupTokensForUser}async createUser(x,B={}){let A=await this.users.createUser(x);return await this.audit.append({...H7(B),action:"auth.user.created",targetType:"user",targetId:A.id,metadata:{role:A.role,status:A.status}}),A}async updateRole(x,B,A={}){let w=await this.users.getUser(x),f=await this.users.updateUserRole(x,B);if(w&&w.role!==f.role)await this.revokeGrants(x),await this.audit.append({...H7(A),action:"auth.user.role_updated",targetType:"user",targetId:x,metadata:{from:w.role,to:f.role}});return f}async updateStatus(x,B,A={}){let w=await this.users.getUser(x),f=await this.users.updateUserStatus(x,B);if(w&&w.status!==f.status){let D=f.status==="suspended"?await this.consumeTargetedSetupTokensForUser(x):0;await this.revokeGrants(x),await this.audit.append({...H7(A),action:"auth.user.status_updated",targetType:"user",targetId:x,metadata:{from:w.status,to:f.status,...D>0?{consumedSetupTokens:D}:{}}})}return f}async deleteSuspendedUser(x,B={}){let A=await this.users.deleteSuspendedUser(x);return await this.audit.append({...H7(B),action:"auth.user.deleted",targetType:"user",targetId:x,metadata:{role:A.role,status:A.status}}),A}async revokeGrants(x,B={}){let[A,w]=await Promise.all([this.sessions.revokeSessionsForSubject(x),this.refreshTokens.revokeTokensForSubject(x)]);if(B.actorUserId)await this.audit.append({...H7(B),action:"auth.user.grants_revoked",targetType:"user",targetId:x,metadata:{sessions:A,refreshTokens:w}});return{sessions:A,refreshTokens:w}}}class bu{passkeyService;sessionStore;setupFlow;registrationUserProvider;validateTargetedRegistration;completeTargetedRegistration;recordAuditEvent;constructor(x){this.passkeyService=x.passkeyService,this.sessionStore=x.sessionStore,this.setupFlow=x.setupFlow,this.registrationUserProvider=x.registrationUserProvider,this.validateTargetedRegistration=x.validateTargetedRegistration,this.completeTargetedRegistration=x.completeTargetedRegistration,this.recordAuditEvent=x.recordAuditEvent}async handleRegistrationOptions(x){let B=await this.setupFlow.resolveSetupToken(x);if(await this.passkeyService.hasCredentials()&&B?.targetUserId==null)return V9("access_denied","Passkey setup already completed");if(!B)return V9("access_denied","Invalid setup token");if(await this.setupFlow.hasConflictingAccountSession(x,B))return V9("access_denied","Sign out before using a setup link for another account");try{let A=await this.passkeyService.generateRegistrationOptions(WL(x),await this.registrationUserProvider(B.targetUserId??void 0));return W7(A)}catch{return V9("access_denied","Passkey registration user is unavailable")}}async handleRegistrationVerify(x){let B=await this.setupFlow.resolveSetupToken(x);if(await this.passkeyService.hasCredentials()&&B?.targetUserId==null)return V9("access_denied","Passkey setup already completed");if(!B)return V9("access_denied","Invalid setup token");if(await this.setupFlow.hasConflictingAccountSession(x,B))return V9("access_denied","Sign out before using a setup link for another account");if(B.targetUserId)try{await this.registrationUserProvider(B.targetUserId),await this.validateTargetedRegistration?.({...B,targetUserId:B.targetUserId})}catch{return await this.recordRegistrationFailure(B.targetUserId),V9("access_denied","Passkey registration user is unavailable")}let A=await this.passkeyService.verifyRegistrationResponse(await x.json(),WL(x),B.targetUserId??void 0);if(!A.verified||B.targetUserId!==null&&A.subject!==B.targetUserId)return await this.recordRegistrationFailure(B.targetUserId),V9("access_denied","Passkey registration failed");if(B.targetUserId&&this.completeTargetedRegistration)try{await this.completeTargetedRegistration({...B,targetUserId:B.targetUserId})}catch{return await this.recordRegistrationFailure(B.targetUserId),V9("access_denied","Passkey registration user is unavailable")}else await this.setupFlow.consumeSetupToken(B.token);let w=await this.sessionStore.createSession(A.subject,{secure:OZ(x)});return W7({verified:!0},200,{"Set-Cookie":w.cookie})}async recordRegistrationFailure(x){await this.recordAuditEvent?.({action:"auth.passkey.registration_failed",...x?{targetType:"user",targetId:x}:{}})}async handleAuthenticationOptions(x){if(!await this.passkeyService.hasCredentials())return V9("access_denied","No passkey registered");let B=await this.passkeyService.generateAuthenticationOptions(WL(x));return W7(B)}async handleAuthenticationVerify(x){let B=await this.passkeyService.verifyAuthenticationResponse(await x.json(),WL(x));if(!B.verified)return await this.recordAuditEvent?.({action:"auth.passkey.authentication_failed"}),V9("access_denied","Passkey authentication failed");let A=await this.sessionStore.createSession(B.subject,{secure:OZ(x)});return W7({verified:!0},200,{"Set-Cookie":A.cookie})}}function WL(x){let B=s2(x),A=new URL(B);return{origin:A.origin,rpID:A.hostname}}class Vu{keyStore;a2aKeyStore;clientStore;authCodeStore;sessionStore;peerTrustStore;passkeyService;setupFlow;oauthEndpoints;webauthnEndpoints;runtimeDatabase;refreshTokenStore;issuer;trustedIssuers;allowLocalhostIssuers;anchor;anchorProfileEntityId;setupTokenTtlSeconds;getInvitationDeliveryProvider;getChannelDescriptor;isChannelTypeRegistered;autoStartInvitationDeliveryRecovery;invitationDeliveryRecoveryIntervalMs;invitationDeliveryRecoveryStaleMs;resolveProfileDisplayName;logger;userStore;identityReconciliationService;passkeySetupCoordinator;userManagementService;principalService;administrationService;accountService;invitationService;invitationDeliverySupervisor;interfacePrincipalStore;auditStore;initialization;firstAdminInitialization;closePromise;constructor(x){this.issuer=x.issuer,this.trustedIssuers=x.trustedIssuers,this.allowLocalhostIssuers=x.allowLocalhostIssuers,this.anchor=x.anchor,this.anchorProfileEntityId=x.anchorProfileEntityId,this.setupTokenTtlSeconds=x.setupTokenTtlSeconds??_V,this.getInvitationDeliveryProvider=x.getInvitationDeliveryProvider,this.getChannelDescriptor=x.getChannelDescriptor,this.isChannelTypeRegistered=x.isChannelTypeRegistered,this.autoStartInvitationDeliveryRecovery=x.autoStartInvitationDeliveryRecovery??!0,this.invitationDeliveryRecoveryIntervalMs=x.invitationDeliveryRecoveryIntervalMs??Gf0,this.invitationDeliveryRecoveryStaleMs=x.invitationDeliveryRecoveryStaleMs??Fg,this.resolveProfileDisplayName=x.resolveProfileDisplayName,this.logger=x.logger,this.runtimeDatabase=new HW({storageDir:x.storageDir,...x.replica?{replica:x.replica}:{}}),this.keyStore=new RP(this.runtimeDatabase),this.a2aKeyStore=new qg(this.runtimeDatabase),this.clientStore=new vP(this.runtimeDatabase),this.authCodeStore=new EP(this.runtimeDatabase),this.sessionStore=new Nz(this.runtimeDatabase),this.refreshTokenStore=new Mz(this.runtimeDatabase),this.peerTrustStore=new YL(this.runtimeDatabase),this.passkeyService=new QL({runtimeDatabase:this.runtimeDatabase,...x.logger?{logger:x.logger}:{}});let B=new Yg(this.runtimeDatabase);this.setupFlow=new Ku({setupStateStore:B,passkeyService:this.passkeyService,setupTokenTtlSeconds:this.setupTokenTtlSeconds,resolveSessionUserId:async(A)=>(await this.resolveActiveSession(A))?.user.id}),this.oauthEndpoints=new Vg({clientStore:this.clientStore,authCodeStore:this.authCodeStore,refreshTokenStore:this.refreshTokenStore,resolveSession:async(A)=>(await this.resolveActiveSession(A))?.session,keyStore:this.keyStore,...x.oauthClientMaintenanceIntervalMs!==void 0?{clientMaintenanceIntervalMs:x.oauthClientMaintenanceIntervalMs}:{},onClientMaintenanceError:(A)=>{this.logger?.warn("Failed to prune stale OAuth clients",{error:A})}}),this.webauthnEndpoints=new bu({passkeyService:this.passkeyService,sessionStore:this.sessionStore,setupFlow:this.setupFlow,recordAuditEvent:async(A)=>{await this.getAuditStore().append(A)},validateTargetedRegistration:async(A)=>{await this.getPasskeySetupCoordinator().validateTargetedRegistration(A)},completeTargetedRegistration:async(A)=>{await this.getPasskeySetupCoordinator().completeTargetedRegistration(A)},registrationUserProvider:async(A)=>{let w=A?await this.getUserStore().getUser(A):await this.ensureFirstAdminUser();if(!w||w.status==="suspended")throw Error("Passkey registration user is unavailable");return{subject:w.id,userName:w.displayName,userDisplayName:w.displayName}}})}async initialize(){if(this.closePromise)await this.closePromise,this.closePromise=void 0;if(this.initialization)return this.initialization;let x=this.initializeInternal();this.initialization=x;try{await x}catch(B){if(this.initialization===x)this.initialization=void 0;throw B}}close(){return this.closePromise??=this.closeInternal(),this.closePromise}async ensureStarted(){if(this.userStore)return;await this.runtimeDatabase.start();let x=new GW(this.runtimeDatabase.db,{...this.isChannelTypeRegistered?{isChannelTypeRegistered:this.isChannelTypeRegistered}:{}});this.userStore=new Oz(this.runtimeDatabase.db),this.identityReconciliationService=new Xg({identities:x,users:this.userStore});let B=new qu(this.runtimeDatabase.db,x);this.interfacePrincipalStore=new qP(this.runtimeDatabase.db);let A=new XL(this.runtimeDatabase.db);this.auditStore=new d2(this.runtimeDatabase.db),this.invitationService=new hP({db:this.runtimeDatabase.db,issuer:this.issuer,setupTokenTtlSeconds:this.setupTokenTtlSeconds,deliveryRecoveryStaleMs:this.invitationDeliveryRecoveryStaleMs,audit:this.auditStore,...this.getInvitationDeliveryProvider?{getDeliveryProvider:this.getInvitationDeliveryProvider}:{},...this.getChannelDescriptor?{getChannelDescriptor:this.getChannelDescriptor}:{}}),this.invitationDeliverySupervisor=new Kg(this.invitationDeliveryRecoveryIntervalMs,async(f)=>{await this.getInvitationService().recoverInterruptedDeliveries(f)},{onError:(f)=>{this.logger?.warn("Failed to recover invitation delivery",{error:f})}}),this.passkeySetupCoordinator=new Wu({issuer:this.issuer,users:this.userStore,identities:x,audit:this.auditStore,setupFlow:this.setupFlow,targetedSetup:B,...this.getChannelDescriptor?{getChannelDescriptor:this.getChannelDescriptor}:{}}),this.userManagementService=new zu({users:this.userStore,audit:this.auditStore,sessions:this.sessionStore,refreshTokens:this.refreshTokenStore,consumeTargetedSetupTokensForUser:(f)=>this.setupFlow.consumeTargetedSetupTokensForUser(f)}),this.principalService=new fg({issuer:this.issuer,trustedIssuers:this.trustedIssuers,allowLocalhostIssuers:this.allowLocalhostIssuers,users:this.userStore,identities:x,sessions:this.sessionStore,ensureFirstAdminUser:()=>this.ensureFirstAdminUser(),getJwks:()=>this.getJwks()});let w=new Tz(this.runtimeDatabase.db);this.accountService=new pc({users:this.userStore,identities:x,credentials:w,sessions:this.sessionStore,refreshTokens:this.refreshTokenStore,passkeys:this.passkeyService,audit:this.auditStore,...this.isChannelTypeRegistered?{isChannelTypeRegistered:this.isChannelTypeRegistered}:{}}),this.administrationService=new Dg({configuredAnchorKind:this.anchor,...this.resolveProfileDisplayName?{resolveProfileDisplayName:this.resolveProfileDisplayName}:{},users:this.userStore,identities:x,credentials:w,externalPeers:A,invitations:this.getInvitationService(),audit:this.auditStore,management:this.getUserManagementService(),...this.getChannelDescriptor?{getChannelDescriptor:this.getChannelDescriptor}:{},startPasskeyRegistration:(f,D,$)=>this.getPasskeySetupCoordinator().startRegistration(f,D,$)})}getUserStore(){return qA(this.userStore)}getIdentityReconciliationService(){return qA(this.identityReconciliationService)}getPasskeySetupCoordinator(){return qA(this.passkeySetupCoordinator)}getPrincipalService(){return qA(this.principalService)}getAdministrationService(){return qA(this.administrationService)}getAccountService(){return qA(this.accountService)}getInvitationService(){return qA(this.invitationService)}async startInvitationDeliveryRecovery(){await this.ensureStarted(),await this.invitationDeliverySupervisor?.start()}getInterfacePrincipalStore(){return qA(this.interfacePrincipalStore)}getAuditStore(){return qA(this.auditStore)}hasPasskeyCredentials(){return this.passkeyService.hasCredentials()}getSetupUrl(x=this.issuer){return this.setupFlow.getSetupUrl(x)}async getJwks(){let[x,B]=await Promise.all([this.keyStore.getPublicJwk(),this.a2aKeyStore.getPublicJwk()]);return{keys:[x,B]}}getUserManagementService(){return qA(this.userManagementService)}async initializeInternal(){if(await this.ensureStarted(),this.autoStartInvitationDeliveryRecovery)await this.startInvitationDeliveryRecovery();if(await this.projectConfiguredBrainAnchor(),await Promise.all([this.keyStore.getPrivateJwk(),this.a2aKeyStore.getPrivateJwk()]),this.logger?.debug("Auth service signing keys loaded"),!await this.hasPasskeyCredentials()){await this.setupFlow.ensureSetupToken();let x=this.getSetupUrl();if(x)if(r3(this.issuer))this.logger?.warn(`Passkey setup required: ${x}`);else this.logger?.warn("Passkey setup required. Ask through an Admin interface for the setup URL.")}await this.oauthEndpoints.startClientMaintenance()}async closeInternal(){await this.oauthEndpoints.stopClientMaintenance(),await this.invitationDeliverySupervisor?.close(),this.invitationDeliverySupervisor=void 0,this.userStore=void 0,this.identityReconciliationService=void 0,this.passkeySetupCoordinator=void 0,this.userManagementService=void 0,this.principalService=void 0,this.administrationService=void 0,this.accountService=void 0,this.invitationService=void 0,this.interfacePrincipalStore=void 0,this.auditStore=void 0,this.initialization=void 0,this.firstAdminInitialization=void 0,await this.runtimeDatabase.stop()}profileDisplayName(x){return kP(this.resolveProfileDisplayName,x,this.logger)}async projectConfiguredBrainAnchor(){let x=await this.getUserStore().getBrainAnchor(),B=await this.profileDisplayName(this.anchorProfileEntityId),A=B??x?.displayName??(this.anchor==="person"?"Admin":this.anchor==="team"?"Team":"Organization");await this.getUserStore().configureBrainAnchor({kind:this.anchor==="person"?"person":"collective",displayName:A,profileEntityId:this.anchorProfileEntityId,...B?{subjectDisplayName:B}:{}})}async ensureFirstAdminUser(){if(this.firstAdminInitialization)return this.firstAdminInitialization;let x=(async()=>{let B=await this.getUserStore().listUsers(),A=await this.getUserStore().ensureFirstAdminUser();if(await this.projectConfiguredBrainAnchor(),!B.some((w)=>w.id===A.id))await this.getAuditStore().append({action:"auth.user.created",targetType:"user",targetId:A.id,metadata:{role:A.role,status:A.status}});return A})();this.firstAdminInitialization=x;try{return await x}finally{if(this.firstAdminInitialization===x)this.firstAdminInitialization=void 0}}async resolveActiveSession(x){return await this.ensureStarted(),this.getPrincipalService().resolveActiveSession(x)}}function qA(x){if(!x)throw Error("Auth service has not been initialized");return x}var Fix="anchor-profile/anchor-profile";class HL{issuer;runtime;requestRouter;getInvitationDeliveryProvider;getChannelDescriptor;listChannelDescriptors;logger;constructor(x){this.issuer=a2(x.issuer),this.getInvitationDeliveryProvider=x.getInvitationDeliveryProvider,this.getChannelDescriptor=x.getChannelDescriptor,this.listChannelDescriptors=x.listChannelDescriptors,this.logger=x.logger;let B=x.isChannelTypeRegistered??(x.getChannelDescriptor?(A)=>Boolean(x.getChannelDescriptor?.(A)):void 0);this.runtime=new Vu({storageDir:x.storageDir,...x.replica?{replica:x.replica}:{},issuer:this.issuer,trustedIssuers:new Set([this.issuer,...(x.trustedIssuers??[]).map((A)=>a2(A))]),allowLocalhostIssuers:x.allowLocalhostIssuers??r3(this.issuer),anchor:x.anchor??"person",anchorProfileEntityId:x.anchorProfileEntityId??Fix,...x.resolveProfileDisplayName?{resolveProfileDisplayName:x.resolveProfileDisplayName}:{},...x.setupTokenTtlSeconds!==void 0?{setupTokenTtlSeconds:x.setupTokenTtlSeconds}:{},...x.getInvitationDeliveryProvider?{getInvitationDeliveryProvider:x.getInvitationDeliveryProvider}:{},...x.getChannelDescriptor?{getChannelDescriptor:x.getChannelDescriptor}:{},...B?{isChannelTypeRegistered:B}:{},...x.autoStartInvitationDeliveryRecovery!==void 0?{autoStartInvitationDeliveryRecovery:x.autoStartInvitationDeliveryRecovery}:{},...x.invitationDeliveryRecoveryIntervalMs!==void 0?{invitationDeliveryRecoveryIntervalMs:x.invitationDeliveryRecoveryIntervalMs}:{},...x.invitationDeliveryRecoveryStaleMs!==void 0?{invitationDeliveryRecoveryStaleMs:x.invitationDeliveryRecoveryStaleMs}:{},...x.oauthClientMaintenanceIntervalMs!==void 0?{oauthClientMaintenanceIntervalMs:x.oauthClientMaintenanceIntervalMs}:{},...x.logger?{logger:x.logger}:{}}),this.requestRouter=new Tc({setupFlow:this.runtime.setupFlow,oauthEndpoints:this.runtime.oauthEndpoints,webauthnEndpoints:this.runtime.webauthnEndpoints,handleAdminRequest:(A)=>this.handleAdminRequest(A),handleAccountRequest:(A)=>this.handleAccountRequest(A),revokeSession:async(A)=>{await this.runtime.sessionStore.revokeSessionFromRequest(A)},getAuthorizationServerMetadata:(A)=>this.getAuthorizationServerMetadata(A),getProtectedResourceMetadata:(A,w)=>this.getProtectedResourceMetadata(A,w),getJwks:()=>this.getJwks()})}getIssuer(){return this.issuer}initialize(){return this.runtime.initialize()}startInvitationDeliveryRecovery(){return this.runtime.startInvitationDeliveryRecovery()}close(){return this.runtime.close()}async initializeConfiguredInterfacePrincipals(x){await this.initialize();let B=this.runtime.getInterfacePrincipalStore();return await B.seedConfigOnce(x),B.listActiveState()}async resolveInterfacePrincipal(x,B){return await this.initialize(),this.runtime.getInterfacePrincipalStore().resolve(x,B)}async hasPasskeyCredentials(){return this.runtime.passkeyService.hasCredentials()}async revokePasskey(x,B={}){await this.runtime.ensureStarted(),await this.runtime.getAdministrationService().revokePasskey(x,B)}async getJwks(){let[x,B]=await Promise.all([this.runtime.keyStore.getPublicJwk(),this.runtime.a2aKeyStore.getPublicJwk()]);return{keys:[x,B]}}async getA2ASigningKey(){let x=await this.runtime.a2aKeyStore.getPrivateJwk();return{privateJwk:x,keyId:Y7(this.issuer,`/.well-known/jwks.json#${x.kid}`)}}async grantA2APeerTrust(x,B={}){return await this.initialize(),this.runtime.peerTrustStore.grant(x,B)}async getA2APeerTrust(x){return await this.initialize(),this.runtime.peerTrustStore.get(x)}async revokeA2APeerTrust(x,B={}){return await this.initialize(),this.runtime.peerTrustStore.revoke(x,B)}getAuthorizationServerMetadata(x=this.issuer){let B=a2(x);return{issuer:B,authorization_endpoint:Y7(B,"/authorize"),token_endpoint:Y7(B,"/token"),registration_endpoint:Y7(B,"/register"),revocation_endpoint:Y7(B,"/revoke"),jwks_uri:Y7(B,"/.well-known/jwks.json"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none","client_secret_basic","client_secret_post"],scopes_supported:["openid","profile","email","offline_access","mcp"],subject_types_supported:["public"],id_token_signing_alg_values_supported:["ES256"]}}getProtectedResourceMetadata(x,B=this.issuer){return{resource:x,authorization_servers:[a2(B)],bearer_methods_supported:["header"],resource_signing_alg_values_supported:["ES256"],scopes_supported:["mcp"]}}async registerClient(x){return await this.initialize(),this.runtime.clientStore.registerClient(x)}async getRegisteredClient(x){return await this.initialize(),this.runtime.clientStore.getClient(x)}async createUser(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().createUser(x,B)}async cancelInvitation(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().cancelInvitation(x,B)}async confirmManualInvitationDelivery(x,B,A){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().confirmManualInvitationDelivery(x,B,A)}async createInvitation(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().createInvitation(x,B)}async resendInvitation(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().resendInvitation(x,B)}async inviteExternalPeerPerson(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().inviteExternalPeerPerson(x,B)}async linkExternalPeer(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().linkExternalPeer(x,B)}async getBrainAnchor(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().getBrainAnchor()}async listUsers(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listUsers()}async listAdminUsers(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listAdminUsers()}async listInvitationChannels(){await this.runtime.ensureStarted();let x=this.listChannelDescriptors?.()??[];return await Promise.all(x.map(async(A)=>{let w=[];try{let f=this.getInvitationDeliveryProvider?.(A.type);if(f&&await f.isAvailable())w.push("automatic")}catch{}if(A.manualDelivery===!0)w.push("manual");return{type:A.type,displayName:A.displayName,subjectLabel:A.subjectLabel,...A.subjectPattern?{subjectPattern:A.subjectPattern}:{},deliveryModes:w}}))}async reconcileIdentityProposals(x){return await this.runtime.ensureStarted(),this.runtime.getIdentityReconciliationService().reconcile(x)}async listPersonExternalPeers(x){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listPersonExternalPeers(x)}async listUserIdentities(x){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listUserIdentities(x)}async listUserPasskeys(x){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listUserPasskeys(x)}async updateUserRole(x,B,A={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().updateUserRole(x,B,A)}async updateUserStatus(x,B,A={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().updateUserStatus(x,B,A)}suspendUser(x,B={}){return this.updateUserStatus(x,"suspended",B)}async deleteSuspendedUser(x,B={}){await this.runtime.ensureStarted(),await this.runtime.getAdministrationService().deleteSuspendedUser(x,B)}async revokeUserSessionsAndRefreshTokens(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().revokeUserGrants(x,B)}async attachIdentity(x,B={}){await this.runtime.ensureStarted();let A=this.validateChannelSubject(x.type,x.subject);return this.runtime.getAdministrationService().attachIdentity({...x,...A&&!x.deliverySubject?{deliverySubject:x.subject}:{}},B)}async detachIdentity(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().detachIdentity(x,B)}async recordAuditEvent(x){return await this.runtime.ensureStarted(),this.runtime.getAuditStore().append(x)}async listAuditEvents(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listAuditEvents()}async resolveActorPrincipal(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveActor(x)}async resolveIdentityAccess(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveIdentityAccess(x)}async createAuthSession(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().createSession(x,B)}async getAuthSession(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().getSession(x)}async resolveSession(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveSession(x)}createAuthLoginResponse(x){return hz(x)}async verifyBearerToken(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().verifyBearerToken(x,B)}async resolveBearerGrant(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveBearerGrant(x,B)}async resolveBearerToken(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveBearerToken(x,B)}getSetupUrl(x=this.issuer){return this.runtime.setupFlow.getSetupUrl(x)}async startPasskeyRegistrationForUser(x,B={},A){if(await this.runtime.ensureStarted(),A)this.validateChannelSubject(A.type,A.subject);return this.runtime.getPasskeySetupCoordinator().startRegistration(x,B,A)}async getPasskeySetupRequired(x=this.issuer){return await this.runtime.ensureStarted(),this.runtime.getPasskeySetupCoordinator().getPasskeySetupRequired(x)}async getPasskeySetupRequiredForDelivery(x=this.issuer){return await this.runtime.ensureStarted(),this.runtime.getPasskeySetupCoordinator().getPasskeySetupRequiredForDelivery(x)}async hasSetupEmailDelivery(x,B){return await this.runtime.ensureStarted(),this.runtime.getPasskeySetupCoordinator().hasSetupEmailDelivery(x,B)}async recordSetupEmailDelivery(x,B,A={}){await this.runtime.ensureStarted(),await this.runtime.getPasskeySetupCoordinator().recordSetupEmailDelivery(x,B,A)}async handleRequest(x){await this.initialize();let B;try{B=this.resolveRequestIssuer(x)}catch(A){return this.logger?.warn("Rejected OAuth request from untrusted issuer",{error:g(A)}),new Response("Untrusted OAuth issuer",{status:400})}return this.requestRouter.handle(x,B)}async handleWellKnownRequest(x){return this.handleRequest(x)}handleAccountRequest(x){return Jw0(x,{resolveSession:async(B)=>{let A=await this.runtime.resolveActiveSession(B);return A?{userId:A.user.id,sessionId:A.session.id}:void 0},account:this.runtime.getAccountService()})}handleAdminRequest(x){return Nw0(x,{resolveSession:(B)=>this.resolveSession(B),listUsers:()=>this.listUsers(),getBrainAnchor:()=>this.getBrainAnchor(),listAuditEvents:()=>this.listAuditEvents(),listInvitationChannels:()=>this.listInvitationChannels(),listAdminUsers:()=>this.listAdminUsers(),reconcileIdentityProposals:(B)=>this.reconcileIdentityProposals(B),listPersonExternalPeers:(B)=>this.listPersonExternalPeers(B),listUserIdentities:(B)=>this.listUserIdentities(B),listUserPasskeys:(B)=>this.listUserPasskeys(B),cancelInvitation:(B,A)=>this.cancelInvitation(B,{actorUserId:A}),confirmManualInvitationDelivery:(B,A,w)=>this.confirmManualInvitationDelivery(B,A,{actorUserId:w}),createInvitation:(B,A)=>this.createInvitation(B,{actorUserId:A}),createUser:(B,A)=>this.createUser(B,{actorUserId:A}),inviteExternalPeerPerson:(B,A)=>this.inviteExternalPeerPerson(B,{actorUserId:A}),resendInvitation:(B,A)=>this.resendInvitation(B,{actorUserId:A}),linkExternalPeer:(B,A)=>this.linkExternalPeer(B,{actorUserId:A}),updateUserRole:(B,A,w)=>this.updateUserRole(B,A,{actorUserId:w}),updateUserStatus:(B,A,w)=>this.updateUserStatus(B,A,{actorUserId:w}),deleteUser:(B,A)=>this.deleteSuspendedUser(B,{actorUserId:A}),attachIdentity:async(B,A)=>nX0(await this.attachIdentity(B,{actorUserId:A}),B.userId,this.getChannelDescriptor),detachIdentity:async(B,A)=>{let w=await this.detachIdentity(B,{actorUserId:A}),f=await this.runtime.getUserStore().getUserByPersonId(w.personId);if(!f)throw Error("Identity person has no auth user");return nX0(w,f.id,this.getChannelDescriptor)},revokePasskey:(B,A)=>this.revokePasskey(B,{actorUserId:A}),startPasskeyRegistration:(B,A,w)=>this.startPasskeyRegistrationForUser(B,{actorUserId:A},w),revokeUserSessionsAndRefreshTokens:(B,A)=>this.revokeUserSessionsAndRefreshTokens(B,{actorUserId:A})})}validateChannelSubject(x,B){let A=this.getChannelDescriptor?.(x);if(A?.subjectPattern&&!new RegExp(A.subjectPattern.source,A.subjectPattern.flags).test(B.trim()))throw Error(`Identity subject is invalid for channel: "${x}"`);return A}resolveRequestIssuer(x){return this.runtime.getPrincipalService().resolveRequestIssuer(x)}}function nX0(x,B,A){let w=x.label?.trim(),f=x.deliverySubject?.trim(),D=w&&w.length>0&&w!==A?.(x.type)?.subjectLabel?w:f;return{id:x.id,personId:x.personId,userId:B,type:x.type,visibility:x.visibility,evidence:x.evidence.map(($)=>({sourceKind:$.sourceKind,...$.sourceId?{sourceId:$.sourceId}:{},assurance:$.assurance,...$.verifiedAt!==null?{verifiedAt:$.verifiedAt}:{}})),...x.issuer?{issuer:x.issuer}:{},...D?{label:D}:{},...x.verifiedAt!==null?{verifiedAt:x.verifiedAt}:{},...x.revokedAt!==null?{revokedAt:x.revokedAt}:{},createdAt:x.createdAt}}import{join as qix}from"path";var dX0={name:"@brains/auth-service",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Embedded OAuth/OIDC authentication service for brain users",dependencies:{"@brains/contracts":"workspace:*","@brains/notification-contracts":"workspace:*","@brains/notifications":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@libsql/client":"^0.17.4","@simplewebauthn/server":"^13.3.1","drizzle-orm":"^0.45.2",jose:"^6.2.3"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43","drizzle-kit":"^0.31.10",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./account-contracts":"./src/account-contracts.ts","./admin-contracts":"./src/admin-contracts.ts"},files:["src"],main:"./src/index.ts",private:!0,scripts:{"db:generate":"drizzle-kit generate","db:studio":"drizzle-kit studio",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};var zix=X.union([X.string().email(),X.object({to:X.string().email(),subject:X.string().min(1),body:X.string().min(1)}).strict()]),bix=X.object({syncUrl:X.string().url().regex(/^(?:libsql|https):\/\//),authToken:X.string().min(1),syncIntervalMs:X.number().int().positive().optional()}).strict(),Vix=X.object({issuer:X.string().optional(),anchor:X.enum(_c).default("person"),trustedIssuers:X.array(X.string()).default([]),allowLocalhostIssuers:X.boolean().optional(),storageDir:X.string().optional(),replica:bix.optional(),setupTokenTtlSeconds:X.number().int().positive().default(_V),setupEmail:zix.optional()}),FL;function X6(){return FL}function Uix(x){return x??qix(".","data","auth")}async function Gix(x,B){if(B==="anchor-profile/anchor-profile"){let D=x.identity.getProfile().name.trim();return D&&D!=="Unknown"?D:void 0}let A=B.indexOf("/");if(A<=0||A===B.length-1)return;let f=(await x.entityService.getEntity({entityType:B.slice(0,A),id:B.slice(A+1),visibilityScope:"restricted"}))?.metadata.name;return typeof f==="string"?f:void 0}class Gu extends D8{service;unsubscribePrincipalResolver;constructor(x={}){super("auth-service",dX0,x,Vix)}async onRegister(x){await super.onRegister(x);let B=this.config.issuer??(x.preferLocalUrls?x.localSiteUrl??x.siteUrl:x.siteUrl??x.localSiteUrl);this.service=new HL({storageDir:Uix(this.config.storageDir),...this.config.replica?{replica:this.config.replica}:{},anchor:this.config.anchor,anchorProfileEntityId:"anchor-profile/anchor-profile",resolveProfileDisplayName:(w)=>Gix(x,w),...B?{issuer:B}:{},trustedIssuers:this.config.trustedIssuers,...this.config.allowLocalhostIssuers!==void 0?{allowLocalhostIssuers:this.config.allowLocalhostIssuers}:{},setupTokenTtlSeconds:this.config.setupTokenTtlSeconds,autoStartInvitationDeliveryRecovery:!1,getInvitationDeliveryProvider:(w)=>x.channels.getDeliveryProvider(w),getChannelDescriptor:(w)=>x.channels.getDescriptor(w),listChannelDescriptors:()=>x.channels.listDescriptors(),isChannelTypeRegistered:(w)=>Boolean(x.channels.getDescriptor(w)),logger:x.logger}),await this.service.initialize();let A=await this.service.initializeConfiguredInterfacePrincipals(x.permissions.getConfiguredPrincipalSeeds());x.permissions.replaceRuntimePrincipalState(A),FL=this.service,this.unsubscribePrincipalResolver=x.messaging.subscribe(KL,async(w)=>{let f=sX0.safeParse(w.payload);if(!f.success)return{success:!1,error:"Invalid auth principal request"};let D=await this.getService().resolveActorPrincipal(f.data.actor);return{success:!0,data:{principal:D?{userId:D.userId,personId:D.personId,...D.canonicalId?{canonicalId:D.canonicalId}:{},displayName:D.displayName,permissionLevel:D.permissionLevel}:null}}})}async onRegistrationComplete(){await this.getService().startInvitationDeliveryRecovery()}async onReady(x){await this.requestSetupEmailIfNeeded(x)}async onShutdown(){if(this.unsubscribePrincipalResolver?.(),this.unsubscribePrincipalResolver=void 0,FL===this.service)FL=void 0;await this.service?.close(),this.service=void 0}async getTools(){let x=await this.getService().hasPasskeyCredentials();return[{name:`${this.id}_get_passkey_setup_url`,description:"Get the first-passkey setup URL when passkey setup is required. Admin-only.",inputSchema:{},visibility:"admin",...x?{agentTool:!1}:{},handler:async()=>{let B=this.getService();if(await B.hasPasskeyCredentials())return{success:!0,data:{status:"complete"}};let A=await B.getPasskeySetupRequired();if(A)return{success:!0,data:{status:"setup_required",setupUrl:A.setupUrl,expiresAt:A.expiresAt}};return{success:!0,data:{status:"unavailable",reason:"Passkey setup URL is not available."}}},sideEffects:"none"}]}getWebRoutes(){let x=(B)=>this.getService().handleRequest(B);return[{path:"/.well-known/oauth-authorization-server",method:"GET",public:!0,handler:x},{path:"/.well-known/oauth-authorization-server",method:"OPTIONS",public:!0,handler:x},{path:"/.well-known/jwks.json",method:"GET",public:!0,handler:x},{path:"/.well-known/jwks.json",method:"OPTIONS",public:!0,handler:x},{path:"/.well-known/oauth-protected-resource",method:"GET",public:!0,handler:x},{path:"/.well-known/oauth-protected-resource",method:"OPTIONS",public:!0,handler:x},{path:"/setup",method:"GET",public:!0,handler:x},{path:"/login",method:"GET",public:!0,handler:x},{path:"/logout",method:"GET",public:!0,handler:x},{path:"/logout",method:"POST",public:!0,handler:x},{path:"/authorize",method:"GET",public:!0,handler:x},{path:"/authorize",method:"POST",public:!0,handler:x},{path:"/register",method:"POST",public:!0,handler:x},{path:"/register",method:"OPTIONS",public:!0,handler:x},{path:"/token",method:"POST",public:!0,handler:x},{path:"/token",method:"OPTIONS",public:!0,handler:x},{path:"/revoke",method:"POST",public:!0,handler:x},{path:"/revoke",method:"OPTIONS",public:!0,handler:x},{path:"/auth/account",method:"GET",public:!0,handler:x},{path:"/auth/account/mutations",method:"POST",public:!0,handler:x},{path:"/auth/account/passkeys/options",method:"POST",public:!0,handler:x},{path:"/auth/account/passkeys/verify",method:"POST",public:!0,handler:x},{path:"/auth/admin/anchor",method:"GET",public:!0,handler:x},{path:"/auth/admin/users",method:"GET",public:!0,handler:x},{path:"/auth/admin/audit",method:"GET",public:!0,handler:x},{path:"/auth/admin/channels",method:"GET",public:!0,handler:x},{path:"/auth/admin/mutations",method:"POST",public:!0,handler:x},{path:"/auth/admin/reconciliation",method:"POST",public:!0,handler:x},{path:"/webauthn/register/options",method:"POST",public:!0,handler:x},{path:"/webauthn/register/verify",method:"POST",public:!0,handler:x},{path:"/webauthn/auth/options",method:"POST",public:!0,handler:x},{path:"/webauthn/auth/verify",method:"POST",public:!0,handler:x}]}getService(){if(!this.service)throw Error("AuthServicePlugin has not been registered");return this.service}async requestSetupEmailIfNeeded(x){if(!this.config.setupEmail)return;let B=this.getService();if(await B.hasPasskeyCredentials())return;let A=await B.getPasskeySetupRequiredForDelivery();if(!A)return;let w=Eix(this.config.setupEmail,A);if(await B.hasSetupEmailDelivery(A.setupTokenId,w.to))return;let f=await x.messaging.send({type:PV,payload:{recipient:{type:"email",address:w.to},title:w.subject,body:w.body,sensitivity:"secret"}});if(!("success"in f)||!f.success||!f.data){x.logger.warn("Passkey setup email delivery was not confirmed");return}let D=Uu.safeParse(f.data);if(!D.success||D.data.status!=="sent"){x.logger.warn("Passkey setup email delivery was not confirmed");return}await B.recordSetupEmailDelivery(A.setupTokenId,w.to,D.data.deliveryId?{deliveryId:D.data.deliveryId}:{})}}function Eix(x,B){if(typeof x==="string"){let A=new Date(B.expiresAt*1000).toISOString(),w=new URL(B.setupUrl).origin;return{to:x,subject:"Set up your brain passkey",body:["Set up your brain passkey using this single-use link:","",B.setupUrl,"",`This link expires at ${A}.`,`Dashboard: ${w}/`,`MCP endpoint: ${w}/mcp`,"The first successful passkey registration completes setup and closes this link."].join(`
861
+ ${G}`)}if(w!==void 0&&D?.algorithms!==void 0){let b=D.algorithms.map((G)=>G.alg);if(b.indexOf(w)<0)throw Error(`Attestation statement alg ${w} did not match one of ${b}`)}let K=A.map(D5),q=$.map(D5),V=!1;if(K.length===1&&q.indexOf(K[0])>=0)V=!0;if(!V)try{await t1(K,q)}catch(b){throw Error(`Could not validate certificate path with any metadata root certificates: ${b.message}`)}return!0}var _X0={secp256r1_ecdsa_sha256_raw:{kty:2,alg:-7,crv:1},secp256r1_ecdsa_sha256_der:{kty:2,alg:-7,crv:1},rsassa_pss_sha256_raw:{kty:3,alg:-37},rsassa_pss_sha256_der:{kty:3,alg:-37},secp256k1_ecdsa_sha256_raw:{kty:2,alg:-47,crv:8},secp256k1_ecdsa_sha256_der:{kty:2,alg:-47,crv:8},rsassa_pss_sha384_raw:{kty:3,alg:-38},rsassa_pkcsv15_sha256_raw:{kty:3,alg:-257},rsassa_pkcsv15_sha384_raw:{kty:3,alg:-258},rsassa_pkcsv15_sha512_raw:{kty:3,alg:-259},rsassa_pkcsv15_sha1_raw:{kty:3,alg:-65535},secp384r1_ecdsa_sha384_raw:{kty:2,alg:-35,crv:2},secp512r1_ecdsa_sha256_raw:{kty:2,alg:-36,crv:3},ed25519_eddsa_sha512_raw:{kty:1,alg:-8,crv:6}};function PX0(x){let{kty:B,alg:A,crv:w}=x,f="";if(B!==r7.RSA)f=`{ kty: ${B}, alg: ${A}, crv: ${w} }`;else f=`{ kty: ${B}, alg: ${A} }`;return f}async function JX0(x){let{attStmt:B,clientDataHash:A,authData:w,credentialPublicKey:f,aaguid:D,rootCertificates:$}=x,Z=B.get("sig"),Q=B.get("x5c"),Y=B.get("alg");if(!Z)throw Error("No attestation signature provided in attestation statement (Packed)");if(!Y)throw Error("Attestation statement did not contain alg (Packed)");if(!e3(Y))throw Error(`Attestation statement contained invalid alg ${Y} (Packed)`);let W=jx.concat([w,A]),H=!1;if(Q){let{subject:F,basicConstraintsCA:K,version:q,notBefore:V,notAfter:b,parsedCertificate:G}=xH(Q[0]),{OU:E,CN:_,O:L,C:N}=F;if(E!=="Authenticator Attestation")throw Error('Certificate OU was not "Authenticator Attestation" (Packed|Full)');if(!_)throw Error("Certificate CN was empty (Packed|Full)");if(!L)throw Error("Certificate O was empty (Packed|Full)");if(!N||N.length!==2)throw Error("Certificate C was not two-character ISO 3166 code (Packed|Full)");if(K)throw Error("Certificate basic constraints CA was not `false` (Packed|Full)");if(q!==2)throw Error("Certificate version was not `3` (ASN.1 value of 2) (Packed|Full)");let y=new Date;if(V>y)throw Error(`Certificate not good before "${V.toString()}" (Packed|Full)`);if(y=new Date,b<y)throw Error(`Certificate not good after "${b.toString()}" (Packed|Full)`);try{await $L(G.tbsCertificate.extensions,D)}catch(n){throw Error(`${n.message} (Packed|Full)`)}let c=await TD.getStatement(D);if(c){if(c.attestationTypes.indexOf("basic_full")<0)throw Error("Metadata does not indicate support for full attestations (Packed|Full)");try{await pD({statement:c,credentialPublicKey:f,x5c:Q,attestationStatementAlg:Y})}catch(n){throw Error(`${n.message} (Packed|Full)`)}}else try{await t1(Q.map(D5),$)}catch(n){throw Error(`${n.message} (Packed|Full)`)}H=await w2({signature:Z,data:W,x509Certificate:Q[0],hashAlgorithm:Y})}else H=await w2({signature:Z,data:W,credentialPublicKey:f,hashAlgorithm:Y});return H}async function LX0(x){let{attStmt:B,clientDataHash:A,authData:w,aaguid:f,rootCertificates:D,verifyTimestampMS:$=!0,credentialPublicKey:Z,attestationSafetyNetEnforceCTSCheck:Q}=x,Y=B.get("alg"),W=B.get("response");if(!B.get("ver"))throw Error("No ver value in attestation (SafetyNet)");if(!W)throw Error("No response was included in attStmt by authenticator (SafetyNet)");let K=jx.toUTF8String(W).split("."),q=JSON.parse(Sx.toUTF8String(K[0])),V=JSON.parse(Sx.toUTF8String(K[1])),b=K[2],{nonce:G,ctsProfileMatch:E,timestampMs:_}=V;if($){let J0=Date.now();if(_>Date.now())throw Error(`Payload timestamp "${_}" was later than "${J0}" (SafetyNet)`);let v0=_+60000;if(J0=Date.now(),v0<J0)throw Error(`Payload timestamp "${v0}" has expired (SafetyNet)`)}let L=jx.concat([w,A]),N=await A2(L),y=Sx.fromBuffer(N,"base64");if(G!==y)throw Error("Could not verify payload nonce (SafetyNet)");if(Q&&!E)throw Error("Could not verify device integrity (SafetyNet)");let c=Sx.toBuffer(q.x5c[0],"base64"),n=xH(c),{subject:R}=n;if(R.CN!=="attest.android.com")throw Error('Certificate common name was not "attest.android.com" (SafetyNet)');let M=await TD.getStatement(f);if(M)try{await pD({statement:M,credentialPublicKey:Z,x5c:q.x5c,attestationStatementAlg:Y})}catch(J0){throw Error(`${J0.message} (SafetyNet)`)}else try{await t1(q.x5c.map(D5),D)}catch(J0){throw Error(`${J0.message} (SafetyNet)`)}let B0=jx.fromUTF8String(`${K[0]}.${K[1]}`),G0=Sx.toBuffer(b);return await w2({signature:G0,data:B0,x509Certificate:c,hashAlgorithm:Y})}var kX0={196:"TPM_ST_RSP_COMMAND",32768:"TPM_ST_NULL",32769:"TPM_ST_NO_SESSIONS",32770:"TPM_ST_SESSIONS",32788:"TPM_ST_ATTEST_NV",32789:"TPM_ST_ATTEST_COMMAND_AUDIT",32790:"TPM_ST_ATTEST_SESSION_AUDIT",32791:"TPM_ST_ATTEST_CERTIFY",32792:"TPM_ST_ATTEST_QUOTE",32793:"TPM_ST_ATTEST_TIME",32794:"TPM_ST_ATTEST_CREATION",32801:"TPM_ST_CREATION",32802:"TPM_ST_VERIFIED",32803:"TPM_ST_AUTH_SECRET",32804:"TPM_ST_HASHCHECK",32805:"TPM_ST_AUTH_SIGNED",32809:"TPM_ST_FU_MANIFEST"},HA={0:"TPM_ALG_ERROR",1:"TPM_ALG_RSA",4:"TPM_ALG_SHA",4:"TPM_ALG_SHA1",5:"TPM_ALG_HMAC",6:"TPM_ALG_AES",7:"TPM_ALG_MGF1",8:"TPM_ALG_KEYEDHASH",10:"TPM_ALG_XOR",11:"TPM_ALG_SHA256",12:"TPM_ALG_SHA384",13:"TPM_ALG_SHA512",16:"TPM_ALG_NULL",18:"TPM_ALG_SM3_256",19:"TPM_ALG_SM4",20:"TPM_ALG_RSASSA",21:"TPM_ALG_RSAES",22:"TPM_ALG_RSAPSS",23:"TPM_ALG_OAEP",24:"TPM_ALG_ECDSA",25:"TPM_ALG_ECDH",26:"TPM_ALG_ECDAA",27:"TPM_ALG_SM2",28:"TPM_ALG_ECSCHNORR",29:"TPM_ALG_ECMQV",32:"TPM_ALG_KDF1_SP800_56A",33:"TPM_ALG_KDF2",34:"TPM_ALG_KDF1_SP800_108",35:"TPM_ALG_ECC",37:"TPM_ALG_SYMCIPHER",38:"TPM_ALG_CAMELLIA",64:"TPM_ALG_CTR",65:"TPM_ALG_OFB",66:"TPM_ALG_CBC",67:"TPM_ALG_CFB",68:"TPM_ALG_ECB"},MX0={0:"TPM_ECC_NONE",1:"TPM_ECC_NIST_P192",2:"TPM_ECC_NIST_P224",3:"TPM_ECC_NIST_P256",4:"TPM_ECC_NIST_P384",5:"TPM_ECC_NIST_P521",16:"TPM_ECC_BN_P256",17:"TPM_ECC_BN_P638",32:"TPM_ECC_SM2_P256"},vX0={"id:414D4400":{name:"AMD",id:"AMD"},"id:414E5400":{name:"Ant Group",id:"ANT"},"id:41544D4C":{name:"Atmel",id:"ATML"},"id:4252434D":{name:"Broadcom",id:"BRCM"},"id:4353434F":{name:"Cisco",id:"CSCO"},"id:464C5953":{name:"Flyslice Technologies",id:"FLYS"},"id:524F4343":{name:"Fuzhou Rockchip",id:"ROCC"},"id:474F4F47":{name:"Google",id:"GOOG"},"id:48504900":{name:"HPI",id:"HPI"},"id:48504500":{name:"HPE",id:"HPE"},"id:48495349":{name:"Huawei",id:"HISI"},"id:49424d00":{name:"IBM",id:"IBM"},"id:49424D00":{name:"IBM",id:"IBM"},"id:49465800":{name:"Infineon",id:"IFX"},"id:494E5443":{name:"Intel",id:"INTC"},"id:4C454E00":{name:"Lenovo",id:"LEN"},"id:4D534654":{name:"Microsoft",id:"MSFT"},"id:4E534D20":{name:"National Semiconductor",id:"NSM"},"id:4E545A00":{name:"Nationz",id:"NTZ"},"id:4E534700":{name:"NSING",id:"NSG"},"id:4E544300":{name:"Nuvoton Technology",id:"NTC"},"id:51434F4D":{name:"Qualcomm",id:"QCOM"},"id:534D534E":{name:"Samsung",id:"SMSN"},"id:53454345":{name:"SecEdge",id:"SECE"},"id:534E5300":{name:"Sinosun",id:"SNS"},"id:534D5343":{name:"SMSC",id:"SMSC"},"id:53544D20":{name:"STMicroelectronics",id:"STM"},"id:54584E00":{name:"Texas Instruments",id:"TXN"},"id:57454300":{name:"Winbond",id:"WEC"},"id:5345414C":{name:"Wisekey",id:"SEAL"},"id:FFFFF1D0":{name:"FIDO Alliance",id:"FIDO"}},NX0={TPM_ECC_NIST_P256:1,TPM_ECC_NIST_P384:2,TPM_ECC_NIST_P521:3,TPM_ECC_BN_P256:1,TPM_ECC_SM2_P256:1};function IX0(x){let B=0,A=jx.toDataView(x),w=A.getUint32(B);B+=4;let f=A.getUint16(B);B+=2;let D=kX0[f],$=A.getUint16(B);B+=2;let Z=x.slice(B,B+=$),Q=A.getUint16(B);B+=2;let Y=x.slice(B,B+=Q),W=x.slice(B,B+=8),H=A.getUint32(B);B+=4;let F=A.getUint32(B);B+=4;let K=!!x.slice(B,B+=1),q={clock:W,resetCount:H,restartCount:F,safe:K},V=x.slice(B,B+=8),b=A.getUint16(B);B+=2;let G=x.slice(B,B+=b),E=jx.toDataView(G),_=A.getUint16(B);B+=2;let L=x.slice(B,B+=_),N={nameAlg:HA[E.getUint16(0)],nameAlgBuffer:G.slice(0,2),name:G,qualifiedName:L};return{magic:w,type:D,qualifiedSigner:Z,extraData:Y,clockInfo:q,firmwareVersion:V,attested:N}}function OX0(x){let B=0,A=jx.toDataView(x),w=HA[A.getUint16(B)];B+=2;let f=HA[A.getUint16(B)];B+=2;let D=A.getUint32(B);B+=4;let $={fixedTPM:!!(D&1),stClear:!!(D&2),fixedParent:!!(D&8),sensitiveDataOrigin:!!(D&16),userWithAuth:!!(D&32),adminWithPolicy:!!(D&64),noDA:!!(D&512),encryptedDuplication:!!(D&1024),restricted:!!(D&32768),decrypt:!!(D&65536),signOrEncrypt:!!(D&131072)},Z=A.getUint16(B);B+=2;let Q=x.slice(B,B+=Z),Y={},W=Uint8Array.from([]);if(w==="TPM_ALG_RSA"){let H=HA[A.getUint16(B)];B+=2;let F=HA[A.getUint16(B)];B+=2;let K=A.getUint16(B);B+=2;let q=A.getUint32(B);B+=4,Y.rsa={symmetric:H,scheme:F,keyBits:K,exponent:q};let V=A.getUint16(B);B+=2,W=x.slice(B,B+=V)}else if(w==="TPM_ALG_ECC"){let H=HA[A.getUint16(B)];B+=2;let F=HA[A.getUint16(B)];B+=2;let K=MX0[A.getUint16(B)];B+=2;let q=HA[A.getUint16(B)];B+=2,Y.ecc={symmetric:H,scheme:F,curveID:K,kdf:q};let V=A.getUint16(B);B+=2;let b=x.slice(B,B+=V),G=A.getUint16(B);B+=2;let E=x.slice(B,B+=G);W=jx.concat([b,E])}else throw Error(`Unexpected type "${w}" (TPM)`);return{type:w,nameAlg:f,objectAttributes:$,authPolicy:Q,parameters:Y,unique:W}}async function hX0(x){let{aaguid:B,attStmt:A,authData:w,credentialPublicKey:f,clientDataHash:D,rootCertificates:$}=x,Z=A.get("ver"),Q=A.get("sig"),Y=A.get("alg"),W=A.get("x5c"),H=A.get("pubArea"),F=A.get("certInfo");if(Z!=="2.0")throw Error(`Unexpected ver "${Z}", expected "2.0" (TPM)`);if(!Q)throw Error("No attestation signature provided in attestation statement (TPM)");if(!Y)throw Error("Attestation statement did not contain alg (TPM)");if(!e3(Y))throw Error(`Attestation statement contained invalid alg ${Y} (TPM)`);if(!W)throw Error("No attestation certificate provided in attestation statement (TPM)");if(!H)throw Error("Attestation statement did not contain pubArea (TPM)");if(!F)throw Error("Attestation statement did not contain certInfo (TPM)");let K=OX0(H),{unique:q,type:V,parameters:b}=K,G=zD(f);if(V==="TPM_ALG_RSA"){if(!_W(G))throw Error(`Credential public key with kty ${G.get(gx.kty)} did not match ${V}`);let X0=G.get(gx.n),Wx=G.get(gx.e);if(!X0)throw Error("COSE public key missing n (TPM|RSA)");if(!Wx)throw Error("COSE public key missing e (TPM|RSA)");if(!jx.areEqual(q,X0))throw Error("PubArea unique is not same as credentialPublicKey (TPM|RSA)");if(!b.rsa)throw Error("Parsed pubArea type is RSA, but missing parameters.rsa (TPM|RSA)");let A8=Wx,y8=b.rsa.exponent||65537,m8=A8[0]+(A8[1]<<8)+(A8[2]<<16);if(y8!==m8)throw Error(`Unexpected public key exp ${m8}, expected ${y8} (TPM|RSA)`)}else if(V==="TPM_ALG_ECC"){if(!KD(G))throw Error(`Credential public key with kty ${G.get(gx.kty)} did not match ${V}`);let X0=G.get(gx.crv),Wx=G.get(gx.x),A8=G.get(gx.y);if(!X0)throw Error("COSE public key missing crv (TPM|ECC)");if(!Wx)throw Error("COSE public key missing x (TPM|ECC)");if(!A8)throw Error("COSE public key missing y (TPM|ECC)");if(!jx.areEqual(q,jx.concat([Wx,A8])))throw Error("PubArea unique is not same as public key x and y (TPM|ECC)");if(!b.ecc)throw Error("Parsed pubArea type is ECC, but missing parameters.ecc (TPM|ECC)");let y8=b.ecc.curveID,m8=NX0[y8];if(m8!==X0)throw Error(`Public area key curve ID "${y8}" mapped to "${m8}" which did not match public key crv of "${X0}" (TPM|ECC)`)}else throw Error(`Unsupported pubArea.type "${V}"`);let E=IX0(F),{magic:_,type:L,attested:N,extraData:y}=E;if(_!==4283712327)throw Error(`Unexpected magic value "${_}", expected "0xff544347" (TPM)`);if(L!=="TPM_ST_ATTEST_CERTIFY")throw Error(`Unexpected type "${L}", expected "TPM_ST_ATTEST_CERTIFY" (TPM)`);let c=await A2(H,Zix(N.nameAlg)),n=jx.concat([N.nameAlgBuffer,c]);if(!jx.areEqual(N.name,n))throw Error("Attested name comparison failed (TPM)");let R=jx.concat([w,D]),M=await A2(R,Y);if(!jx.areEqual(y,M))throw Error("CertInfo extra data did not equal hashed attestation (TPM)");if(W.length<1)throw Error("No certificates present in x5c array (TPM)");let B0=xH(W[0]),{basicConstraintsCA:G0,version:I0,subject:J0,notAfter:v0,notBefore:Ex}=B0;if(G0)throw Error("Certificate basic constraints CA was not `false` (TPM)");if(I0!==2)throw Error("Certificate version was not `3` (ASN.1 value of 2) (TPM)");if(J0.combined.length>0)throw Error("Certificate subject was not empty (TPM)");let _0=new Date;if(Ex>_0)throw Error(`Certificate not good before "${Ex.toString()}" (TPM)`);if(_0=new Date,v0<_0)throw Error(`Certificate not good after "${v0.toString()}" (TPM)`);let Ax=o9.parse(W[0],i6);if(!Ax.tbsCertificate.extensions)throw Error("Certificate was missing extensions (TPM)");let u,t;if(Ax.tbsCertificate.extensions.forEach((X0)=>{if(X0.extnID===eW)u=o9.parse(X0.extnValue,tW);else if(X0.extnID===rW)t=o9.parse(X0.extnValue,nZ)}),!u)throw Error("Certificate did not contain subjectAltName extension (TPM)");if(!u[0].directoryName?.[0].length)throw Error("Certificate subjectAltName extension directoryName was empty (TPM)");let{tcgAtTpmManufacturer:F0,tcgAtTpmModel:$0,tcgAtTpmVersion:qx}=$ix(u[0].directoryName);if(!F0||!$0||!qx)throw Error("Certificate contained incomplete subjectAltName data (TPM)");if(!t)throw Error("Certificate did not contain ExtendedKeyUsage extension (TPM)");if(!vX0[F0])throw Error(`Could not match TPM manufacturer "${F0}" (TPM)`);if(t[0]!=="2.23.133.8.3")throw Error(`Unexpected extKeyUsage "${t[0]}", expected "2.23.133.8.3" (TPM)`);try{await $L(Ax.tbsCertificate.extensions,B)}catch(X0){throw Error(`${X0.message} (TPM)`)}let Nx=await TD.getStatement(B);if(Nx)try{await pD({statement:Nx,credentialPublicKey:f,x5c:W,attestationStatementAlg:Y})}catch(X0){throw Error(`${X0.message} (TPM)`)}else try{await t1(W.map(D5),$)}catch(X0){throw Error(`${X0.message} (TPM)`)}return w2({signature:Q,data:F,x509Certificate:W[0],hashAlgorithm:Y})}function $ix(x){let f,D,$;return x.forEach((Z)=>{Z.forEach((Q)=>{if(Q.type==="2.23.133.2.1")f=Q.value.toString();else if(Q.type==="2.23.133.2.2")D=Q.value.toString();else if(Q.type==="2.23.133.2.3")$=Q.value.toString()})}),{tcgAtTpmManufacturer:f,tcgAtTpmModel:D,tcgAtTpmVersion:$}}function Zix(x){if(x==="TPM_ALG_SHA256")return f8.ES256;else if(x==="TPM_ALG_SHA384")return f8.ES384;else if(x==="TPM_ALG_SHA512")return f8.ES512;throw Error(`Unexpected TPM attested name alg ${x}`)}var $u,RX0="1.3.6.1.4.1.11129.2.1.17",Zu;(function(x){x[x.verified=0]="verified",x[x.selfSigned=1]="selfSigned",x[x.unverified=2]="unverified",x[x.failed=3]="failed"})(Zu||(Zu={}));class hH{verifiedBootKey=new m0;deviceLocked=!1;verifiedBootState=Zu.verified;verifiedBootHash;constructor(x={}){Object.assign(this,x)}}U([j({type:m0})],hH.prototype,"verifiedBootKey",void 0);U([j({type:J.Boolean})],hH.prototype,"deviceLocked",void 0);U([j({type:J.Enumerated})],hH.prototype,"verifiedBootState",void 0);U([j({type:m0,optional:!0})],hH.prototype,"verifiedBootHash",void 0);var IH=$u=class extends Ux{constructor(B){super(B);Object.setPrototypeOf(this,$u.prototype)}};IH=$u=U([x0({type:a.Set,itemType:J.Integer})],IH);class cx{purpose;algorithm;keySize;digest;padding;ecCurve;rsaPublicExponent;mgfDigest;rollbackResistance;earlyBootOnly;activeDateTime;originationExpireDateTime;usageExpireDateTime;usageCountLimit;noAuthRequired;userAuthType;authTimeout;allowWhileOnBody;trustedUserPresenceRequired;trustedConfirmationRequired;unlockedDeviceRequired;allApplications;applicationId;creationDateTime;origin;rollbackResistant;rootOfTrust;osVersion;osPatchLevel;attestationApplicationId;attestationIdBrand;attestationIdDevice;attestationIdProduct;attestationIdSerial;attestationIdImei;attestationIdMeid;attestationIdManufacturer;attestationIdModel;vendorPatchLevel;bootPatchLevel;deviceUniqueAttestation;attestationIdSecondImei;moduleHash;constructor(x={}){Object.assign(this,x)}}U([j({context:1,type:IH,optional:!0})],cx.prototype,"purpose",void 0);U([j({context:2,type:J.Integer,optional:!0})],cx.prototype,"algorithm",void 0);U([j({context:3,type:J.Integer,optional:!0})],cx.prototype,"keySize",void 0);U([j({context:5,type:IH,optional:!0})],cx.prototype,"digest",void 0);U([j({context:6,type:IH,optional:!0})],cx.prototype,"padding",void 0);U([j({context:10,type:J.Integer,optional:!0})],cx.prototype,"ecCurve",void 0);U([j({context:200,type:J.Integer,optional:!0})],cx.prototype,"rsaPublicExponent",void 0);U([j({context:203,type:IH,optional:!0})],cx.prototype,"mgfDigest",void 0);U([j({context:303,type:J.Null,optional:!0})],cx.prototype,"rollbackResistance",void 0);U([j({context:305,type:J.Null,optional:!0})],cx.prototype,"earlyBootOnly",void 0);U([j({context:400,type:J.Integer,optional:!0})],cx.prototype,"activeDateTime",void 0);U([j({context:401,type:J.Integer,optional:!0})],cx.prototype,"originationExpireDateTime",void 0);U([j({context:402,type:J.Integer,optional:!0})],cx.prototype,"usageExpireDateTime",void 0);U([j({context:405,type:J.Integer,optional:!0})],cx.prototype,"usageCountLimit",void 0);U([j({context:503,type:J.Null,optional:!0})],cx.prototype,"noAuthRequired",void 0);U([j({context:504,type:J.Integer,optional:!0})],cx.prototype,"userAuthType",void 0);U([j({context:505,type:J.Integer,optional:!0})],cx.prototype,"authTimeout",void 0);U([j({context:506,type:J.Null,optional:!0})],cx.prototype,"allowWhileOnBody",void 0);U([j({context:507,type:J.Null,optional:!0})],cx.prototype,"trustedUserPresenceRequired",void 0);U([j({context:508,type:J.Null,optional:!0})],cx.prototype,"trustedConfirmationRequired",void 0);U([j({context:509,type:J.Null,optional:!0})],cx.prototype,"unlockedDeviceRequired",void 0);U([j({context:600,type:J.Null,optional:!0})],cx.prototype,"allApplications",void 0);U([j({context:601,type:m0,optional:!0})],cx.prototype,"applicationId",void 0);U([j({context:701,type:J.Integer,optional:!0})],cx.prototype,"creationDateTime",void 0);U([j({context:702,type:J.Integer,optional:!0})],cx.prototype,"origin",void 0);U([j({context:703,type:J.Null,optional:!0})],cx.prototype,"rollbackResistant",void 0);U([j({context:704,type:hH,optional:!0})],cx.prototype,"rootOfTrust",void 0);U([j({context:705,type:J.Integer,optional:!0})],cx.prototype,"osVersion",void 0);U([j({context:706,type:J.Integer,optional:!0})],cx.prototype,"osPatchLevel",void 0);U([j({context:709,type:m0,optional:!0})],cx.prototype,"attestationApplicationId",void 0);U([j({context:710,type:m0,optional:!0})],cx.prototype,"attestationIdBrand",void 0);U([j({context:711,type:m0,optional:!0})],cx.prototype,"attestationIdDevice",void 0);U([j({context:712,type:m0,optional:!0})],cx.prototype,"attestationIdProduct",void 0);U([j({context:713,type:m0,optional:!0})],cx.prototype,"attestationIdSerial",void 0);U([j({context:714,type:m0,optional:!0})],cx.prototype,"attestationIdImei",void 0);U([j({context:715,type:m0,optional:!0})],cx.prototype,"attestationIdMeid",void 0);U([j({context:716,type:m0,optional:!0})],cx.prototype,"attestationIdManufacturer",void 0);U([j({context:717,type:m0,optional:!0})],cx.prototype,"attestationIdModel",void 0);U([j({context:718,type:J.Integer,optional:!0})],cx.prototype,"vendorPatchLevel",void 0);U([j({context:719,type:J.Integer,optional:!0})],cx.prototype,"bootPatchLevel",void 0);U([j({context:720,type:J.Null,optional:!0})],cx.prototype,"deviceUniqueAttestation",void 0);U([j({context:723,type:m0,optional:!0})],cx.prototype,"attestationIdSecondImei",void 0);U([j({context:724,type:m0,optional:!0})],cx.prototype,"moduleHash",void 0);var nw;(function(x){x[x.software=0]="software",x[x.trustedEnvironment=1]="trustedEnvironment",x[x.strongBox=2]="strongBox"})(nw||(nw={}));var OH;(function(x){x[x.KM2=1]="KM2",x[x.KM3=2]="KM3",x[x.KM4=3]="KM4",x[x.KM4_1=4]="KM4_1",x[x.keyMint1=100]="keyMint1",x[x.keyMint2=200]="keyMint2",x[x.keyMint3=300]="keyMint3",x[x.keyMint4=400]="keyMint4"})(OH||(OH={}));class ZB{attestationVersion=OH.KM4;attestationSecurityLevel=nw.software;keymasterVersion=0;keymasterSecurityLevel=nw.software;attestationChallenge=new m0;uniqueId=new m0;softwareEnforced=new cx;teeEnforced=new cx;constructor(x={}){Object.assign(this,x)}}U([j({type:J.Integer})],ZB.prototype,"attestationVersion",void 0);U([j({type:J.Enumerated})],ZB.prototype,"attestationSecurityLevel",void 0);U([j({type:J.Integer})],ZB.prototype,"keymasterVersion",void 0);U([j({type:J.Enumerated})],ZB.prototype,"keymasterSecurityLevel",void 0);U([j({type:m0})],ZB.prototype,"attestationChallenge",void 0);U([j({type:m0})],ZB.prototype,"uniqueId",void 0);U([j({type:cx})],ZB.prototype,"softwareEnforced",void 0);U([j({type:cx})],ZB.prototype,"teeEnforced",void 0);class FA{attestationVersion=OH.keyMint4;attestationSecurityLevel=nw.software;keyMintVersion=0;keyMintSecurityLevel=nw.software;attestationChallenge=new m0;uniqueId=new m0;softwareEnforced=new cx;hardwareEnforced=new cx;constructor(x={}){Object.assign(this,x)}toLegacyKeyDescription(){return new ZB({attestationVersion:this.attestationVersion,attestationSecurityLevel:this.attestationSecurityLevel,keymasterVersion:this.keyMintVersion,keymasterSecurityLevel:this.keyMintSecurityLevel,attestationChallenge:this.attestationChallenge,uniqueId:this.uniqueId,softwareEnforced:this.softwareEnforced,teeEnforced:this.hardwareEnforced})}static fromLegacyKeyDescription(x){return new FA({attestationVersion:x.attestationVersion,attestationSecurityLevel:x.attestationSecurityLevel,keyMintVersion:x.keymasterVersion,keyMintSecurityLevel:x.keymasterSecurityLevel,attestationChallenge:x.attestationChallenge,uniqueId:x.uniqueId,softwareEnforced:x.softwareEnforced,hardwareEnforced:x.teeEnforced})}}U([j({type:J.Integer})],FA.prototype,"attestationVersion",void 0);U([j({type:J.Enumerated})],FA.prototype,"attestationSecurityLevel",void 0);U([j({type:J.Integer})],FA.prototype,"keyMintVersion",void 0);U([j({type:J.Enumerated})],FA.prototype,"keyMintSecurityLevel",void 0);U([j({type:m0})],FA.prototype,"attestationChallenge",void 0);U([j({type:m0})],FA.prototype,"uniqueId",void 0);U([j({type:cx})],FA.prototype,"softwareEnforced",void 0);U([j({type:cx})],FA.prototype,"hardwareEnforced",void 0);var Qu,Xu=class extends cx{};Xu=U([x0({type:a.Choice})],Xu);var RH=Qu=class extends Ux{constructor(B){super(B);Object.setPrototypeOf(this,Qu.prototype)}findProperty(B){let A=this.find((w)=>w[B]!==void 0);if(A)return A[B];return}};RH=Qu=U([x0({type:a.Sequence,itemType:Xu})],RH);class KA{attestationVersion=OH.KM4;attestationSecurityLevel=nw.software;keymasterVersion=0;keymasterSecurityLevel=nw.software;attestationChallenge=new m0;uniqueId=new m0;softwareEnforced=new RH;teeEnforced=new RH;get keyMintVersion(){return this.keymasterVersion}set keyMintVersion(x){this.keymasterVersion=x}get keyMintSecurityLevel(){return this.keymasterSecurityLevel}set keyMintSecurityLevel(x){this.keymasterSecurityLevel=x}get hardwareEnforced(){return this.teeEnforced}set hardwareEnforced(x){this.teeEnforced=x}constructor(x={}){Object.assign(this,x)}}U([j({type:J.Integer})],KA.prototype,"attestationVersion",void 0);U([j({type:J.Enumerated})],KA.prototype,"attestationSecurityLevel",void 0);U([j({type:J.Integer})],KA.prototype,"keymasterVersion",void 0);U([j({type:J.Enumerated})],KA.prototype,"keymasterSecurityLevel",void 0);U([j({type:m0})],KA.prototype,"attestationChallenge",void 0);U([j({type:m0})],KA.prototype,"uniqueId",void 0);U([j({type:RH})],KA.prototype,"softwareEnforced",void 0);U([j({type:RH})],KA.prototype,"teeEnforced",void 0);var yX0=class extends KA{constructor(B={}){if("keymasterVersion"in B&&!("keyMintVersion"in B))B.keyMintVersion=B.keymasterVersion;if("keymasterSecurityLevel"in B&&!("keyMintSecurityLevel"in B))B.keyMintSecurityLevel=B.keymasterSecurityLevel;if("teeEnforced"in B&&!("hardwareEnforced"in B))B.hardwareEnforced=B.teeEnforced;super(B)}};yX0=U([x0({type:a.Sequence})],yX0);class ZL{packageName;version;constructor(x={}){Object.assign(this,x)}}U([j({type:J.OctetString})],ZL.prototype,"packageName",void 0);U([j({type:J.Integer})],ZL.prototype,"version",void 0);class Yu{packageInfos;signatureDigests;constructor(x={}){Object.assign(this,x)}}U([j({type:ZL,repeated:"set"})],Yu.prototype,"packageInfos",void 0);U([j({type:J.OctetString,repeated:"set"})],Yu.prototype,"signatureDigests",void 0);async function mX0(x){let{authData:B,clientDataHash:A,attStmt:w,credentialPublicKey:f,aaguid:D,rootCertificates:$}=x,Z=w.get("x5c"),Q=w.get("sig"),Y=w.get("alg");if(!Z)throw Error("No attestation certificate provided in attestation statement (Android Key)");if(!Q)throw Error("No attestation signature provided in attestation statement (Android Key)");if(!Y)throw Error("Attestation statement did not contain alg (Android Key)");if(!e3(Y))throw Error(`Attestation statement contained invalid alg ${Y} (Android Key)`);let W=o9.parse(Z[0],i6),H=new Uint8Array(W.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey),F=JW(f);if(!jx.areEqual(F,H))throw Error("Credential public key does not equal leaf cert public key (Android Key)");let K=W.tbsCertificate.extensions?.find((L)=>L.extnID===RX0);if(!K)throw Error("Certificate did not contain extKeyStore (Android Key)");let q=o9.parse(K.extnValue,ZB),{attestationChallenge:V,teeEnforced:b,softwareEnforced:G}=q;if(!jx.areEqual(new Uint8Array(V.buffer),A))throw Error("Attestation challenge was not equal to client data hash (Android Key)");if(b.allApplications!==void 0)throw Error('teeEnforced contained "allApplications [600]" tag (Android Key)');if(G.allApplications!==void 0)throw Error('teeEnforced contained "allApplications [600]" tag (Android Key)');let E=await TD.getStatement(D);if(E)try{await pD({statement:E,credentialPublicKey:f,x5c:Z,attestationStatementAlg:Y})}catch(L){let N=L;throw Error(`${N.message} (Android Key)`,{cause:N})}else{let L=Z.slice(0,-1).map(D5),N=Z.slice(-1).map(D5);try{await t1(L,N)}catch(y){let c=y;throw Error(`${c.message} (Android Key)`,{cause:c})}if($.length>0&&$.indexOf(N[0])<0)throw Error("x5c root certificate was not a known root certificate (Android Key)")}let _=jx.concat([B,A]);return w2({signature:Q,data:_,x509Certificate:Z[0],hashAlgorithm:Y})}async function CX0(x){let{attStmt:B,authData:A,clientDataHash:w,credentialPublicKey:f,rootCertificates:D}=x,$=B.get("x5c");if(!$)throw Error("No attestation certificate provided in attestation statement (Apple)");try{await t1($.map(D5),D)}catch(b){throw Error(`${b.message} (Apple)`)}let Z=o9.parse($[0],i6),{extensions:Q,subjectPublicKeyInfo:Y}=Z.tbsCertificate;if(!Q)throw Error("credCert missing extensions (Apple)");let W=Q.find((b)=>b.extnID==="1.2.840.113635.100.8.2");if(!W)throw Error('credCert missing "1.2.840.113635.100.8.2" extension (Apple)');let H=jx.concat([A,w]),F=await A2(H),K=new Uint8Array(W.extnValue.buffer).slice(6);if(!jx.areEqual(F,K))throw Error("credCert nonce was not expected value (Apple)");let q=JW(f),V=new Uint8Array(Y.subjectPublicKey);if(!jx.areEqual(q,V))throw Error("Credential public key does not equal credCert public key (Apple)");return!0}async function cX0(x){let{response:B,expectedChallenge:A,expectedOrigin:w,expectedRPID:f,expectedType:D,requireUserPresence:$=!0,requireUserVerification:Z=!0,supportedAlgorithmIDs:Q=qX0,attestationSafetyNetEnforceCTSCheck:Y=!0}=x,{id:W,rawId:H,type:F,response:K}=B;if(!W)throw Error("Missing credential ID");if(W!==H)throw Error("Credential ID was not base64url-encoded");if(F!=="public-key")throw Error(`Unexpected credential type ${F}, expected "public-key"`);let q=pP(K.clientDataJSON),{type:V,origin:b,challenge:G,tokenBinding:E}=q;if(Array.isArray(D)){if(!D.includes(V)){let X0=D.join(", ");throw Error(`Unexpected registration response type "${V}", expected one of: ${X0}`)}}else if(D){if(V!==D)throw Error(`Unexpected registration response type "${V}", expected "${D}"`)}else if(V!=="webauthn.create")throw Error(`Unexpected registration response type: ${V}`);if(typeof A==="function"){if(!await A(G))throw Error(`Custom challenge verifier returned false for registration response challenge "${G}"`)}else if(G!==A)throw Error(`Unexpected registration response challenge "${G}", expected "${A}"`);if(Array.isArray(w)){if(!w.includes(b))throw Error(`Unexpected registration response origin "${b}", expected one of: ${w.join(", ")}`)}else if(b!==w)throw Error(`Unexpected registration response origin "${b}", expected "${w}"`);if(E){if(typeof E!=="object")throw Error(`Unexpected value for TokenBinding "${E}"`);if(["present","supported","not-supported"].indexOf(E.status)<0)throw Error(`Unexpected tokenBinding.status value of "${E.status}"`)}let _=Sx.toBuffer(K.attestationObject),L=cf0(_),N=L.get("fmt"),y=L.get("authData"),c=L.get("attStmt"),n=BL(y),{aaguid:R,rpIdHash:M,flags:B0,credentialID:G0,counter:I0,credentialPublicKey:J0,extensionsData:v0}=n,Ex;if(f){let X0=[];if(typeof f==="string")X0=[f];else X0=f;Ex=await DL(M,X0)}if($&&!B0.up)throw Error("User presence was required, but user was not present");if(Z&&!B0.uv)throw Error("User verification was required, but user could not be verified");if(!G0)throw Error("No credential ID was provided by authenticator");if(!J0)throw Error("No public key was provided by authenticator");if(!R)throw Error("No AAGUID was present during registration");let Ax=zD(J0).get(gx.alg);if(typeof Ax!=="number")throw Error("Credential public key was missing numeric alg");if(!Q.includes(Ax)){let X0=Q.join(", ");throw Error(`Unexpected public key alg "${Ax}", expected one of "${X0}"`)}let u=await A2(Sx.toBuffer(K.clientDataJSON)),t=gD.getRootCertificates({identifier:N}),F0={aaguid:R,attStmt:c,authData:y,clientDataHash:u,credentialID:G0,credentialPublicKey:J0,rootCertificates:t,rpIdHash:M,attestationSafetyNetEnforceCTSCheck:Y},$0=!1;if(N==="fido-u2f")$0=await UX0(F0);else if(N==="packed")$0=await JX0(F0);else if(N==="android-safetynet")$0=await LX0(F0);else if(N==="android-key")$0=await mX0(F0);else if(N==="tpm")$0=await hX0(F0);else if(N==="apple")$0=await CX0(F0);else if(N==="none"){if(c.size>0)throw Error("None attestation had unexpected attestation statement");$0=!0}else throw Error(`Unsupported Attestation Format: ${N}`);if(!$0)return{verified:!1};let{credentialDeviceType:qx,credentialBackedUp:Nx}=fL(B0);return{verified:!0,registrationInfo:{fmt:N,aaguid:TP(R),credentialType:F,credential:{id:Sx.fromBuffer(G0),publicKey:J0,counter:I0,transports:B.response.transports},attestationObject:_,userVerified:B0.uv,credentialDeviceType:qx,credentialBackedUp:Nx,origin:q.origin,rpID:Ex,authenticatorExtensionResults:v0}}}async function gX0(x){let{allowCredentials:B,challenge:A=await wL(),timeout:w=60000,userVerification:f="preferred",extensions:D,rpID:$}=x,Z=A;if(typeof Z==="string")Z=jx.fromUTF8String(Z);return{rpId:$,challenge:Sx.fromBuffer(Z),allowCredentials:B?.map((Q)=>{if(!Sx.isBase64URL(Q.id))throw Error(`allowCredential id "${Q.id}" is not a valid base64url string`);return{...Q,id:Sx.trimPadding(Q.id),type:"public-key"}}),timeout:w,userVerification:f,extensions:D}}async function TX0(x){let{response:B,expectedChallenge:A,expectedOrigin:w,expectedRPID:f,expectedType:D,credential:$,requireUserVerification:Z=!0,advancedFIDOConfig:Q}=x,{id:Y,rawId:W,type:H,response:F}=B;if(!Y)throw Error("Missing credential ID");if(Y!==W)throw Error("Credential ID was not base64url-encoded");if(H!=="public-key")throw Error(`Unexpected credential type ${H}, expected "public-key"`);if(!B)throw Error("Credential missing response");if(typeof F?.clientDataJSON!=="string")throw Error("Credential response clientDataJSON was not a string");let K=pP(F.clientDataJSON),{type:q,origin:V,challenge:b,tokenBinding:G}=K;if(Array.isArray(D)){if(!D.includes(q)){let Ex=D.join(", ");throw Error(`Unexpected authentication response type "${q}", expected one of: ${Ex}`)}}else if(D){if(q!==D)throw Error(`Unexpected authentication response type "${q}", expected "${D}"`)}else if(q!=="webauthn.get")throw Error(`Unexpected authentication response type: ${q}`);if(typeof A==="function"){if(!await A(b))throw Error(`Custom challenge verifier returned false for registration response challenge "${b}"`)}else if(b!==A)throw Error(`Unexpected authentication response challenge "${b}", expected "${A}"`);if(Array.isArray(w)){if(!w.includes(V)){let Ex=w.join(", ");throw Error(`Unexpected authentication response origin "${V}", expected one of: ${Ex}`)}}else if(V!==w)throw Error(`Unexpected authentication response origin "${V}", expected "${w}"`);if(!Sx.isBase64URL(F.authenticatorData))throw Error("Credential response authenticatorData was not a base64url string");if(!Sx.isBase64URL(F.signature))throw Error("Credential response signature was not a base64url string");if(F.userHandle&&typeof F.userHandle!=="string")throw Error("Credential response userHandle was not a string");if(G){if(typeof G!=="object")throw Error("ClientDataJSON tokenBinding was not an object");if(["present","supported","notSupported"].indexOf(G.status)<0)throw Error(`Unexpected tokenBinding status ${G.status}`)}let E=Sx.toBuffer(F.authenticatorData),_=BL(E),{rpIdHash:L,flags:N,counter:y,extensionsData:c}=_,n=[];if(typeof f==="string")n=[f];else n=f;let R=await DL(L,n);if(Q!==void 0){let{userVerification:Ex}=Q;if(Ex==="required"){if(!N.uv)throw Error("User verification required, but user could not be verified")}}else{if(!N.up)throw Error("User not present during authentication");if(Z&&!N.uv)throw Error("User verification required, but user could not be verified")}let M=await A2(Sx.toBuffer(F.clientDataJSON)),B0=jx.concat([E,M]),G0=Sx.toBuffer(F.signature);if((y>0||$.counter>0)&&y<=$.counter)throw Error(`Response counter value ${y} was lower than expected ${$.counter}`);let{credentialDeviceType:I0,credentialBackedUp:J0}=fL(N);return{verified:await w2({signature:G0,data:B0,credentialPublicKey:$.publicKey}),authenticationInfo:{newCounter:y,credentialID:$.id,userVerified:N.uv,credentialDeviceType:I0,credentialBackedUp:J0,authenticatorExtensionResults:c,origin:K.origin,rpID:R}}}var pX0="Anchor",Qix="Brain",Xix=X.looseObject({challenge:X.string().optional()});class QL{store;rpName;logger;constructor(x){this.store=new Qg(x.runtimeDatabase),this.rpName=x.rpName??Qix,this.logger=x.logger}async hasCredentials(){return this.store.hasCredentials()}async generateRegistrationOptions(x,B){let A=await this.store.listCredentials(B.subject),w=B.userName??pX0,f=B.userDisplayName??w,D=await zX0({rpName:this.rpName,rpID:x.rpID,userName:w,userDisplayName:f,attestationType:"none",authenticatorSelection:{residentKey:"required",userVerification:"required"},excludeCredentials:A.map(($)=>({id:$.id,...$.transports?{transports:$.transports}:{}}))});return await this.store.saveRegistrationChallenge(D.challenge,B.subject),D}async verifyRegistrationResponse(x,B,A){let w=x.response.clientDataJSON?uX0(x.response.clientDataJSON):void 0;if(!w)return{verified:!1};let f=await this.store.consumeRegistrationChallenge(w);if(!f||A!==void 0&&f.subject!==A)return{verified:!1};let D=await cX0({response:x,expectedChallenge:w,expectedOrigin:B.origin,expectedRPID:B.rpID,requireUserVerification:!0});if(!D.verified)return{verified:!1};let $=Math.floor(Date.now()/1000),Z=D.registrationInfo.credential;return await this.store.addCredential({id:Z.id,public_key:Yix(Z.publicKey),counter:Z.counter,...Z.transports?{transports:Z.transports}:{},subject:f.subject,user_name:pX0,credential_device_type:D.registrationInfo.credentialDeviceType,credential_backed_up:D.registrationInfo.credentialBackedUp,created_at:$,updated_at:$}),this.logger?.info("Registered passkey credential",{credentialId:Z.id}),{verified:!0,subject:f.subject}}async listCredentials(){return this.store.listCredentials()}async generateAuthenticationOptions(x){let B=await gX0({rpID:x.rpID,userVerification:"required"});return await this.store.saveAuthenticationChallenge(B.challenge),B}async verifyAuthenticationResponse(x,B){let A=x.response.clientDataJSON?uX0(x.response.clientDataJSON):void 0;if(!A)return{verified:!1};if(!await this.store.consumeAuthenticationChallenge(A))return{verified:!1};let f=await this.store.getCredential(x.id);if(!f)return{verified:!1};let D=await TX0({response:x,expectedChallenge:A,expectedOrigin:B.origin,expectedRPID:B.rpID,credential:Hix(f),requireUserVerification:!0});if(!D.verified)return{verified:!1};return await this.store.updateCredentialCounter(D.authenticationInfo.credentialID,D.authenticationInfo.newCounter),{verified:!0,subject:f.subject}}}function Yix(x){return Buffer.from(x).toString("base64url")}function Wix(x){let B=Buffer.from(x,"base64url"),A=B.buffer.slice(B.byteOffset,B.byteOffset+B.byteLength);return new Uint8Array(A)}function Hix(x){return{id:x.id,publicKey:Wix(x.public_key),counter:x.counter,...x.transports?{transports:x.transports}:{}}}function uX0(x){try{return Xix.parse(JSON.parse(Buffer.from(x,"base64url").toString("utf8"))).challenge}catch{return}}class Wu{issuer;users;identities;audit;setupFlow;targetedSetup;getChannelDescriptor;constructor(x){this.issuer=x.issuer,this.users=x.users,this.identities=x.identities,this.audit=x.audit,this.setupFlow=x.setupFlow,this.targetedSetup=x.targetedSetup,this.getChannelDescriptor=x.getChannelDescriptor}getSetupUrl(x=this.issuer){return this.setupFlow.getSetupUrl(x)}async startRegistration(x,B={},A){let w=await this.users.getUser(x);if(!w||w.status==="suspended")throw Error(`Eligible auth user not found: ${x}`);let f=A?await this.prepareDeliveryIdentity(x,A):await this.resolveStoredDeliveryIdentity(x),D=await this.setupFlow.createUserPasskeySetup(x,this.issuer,{deliveryClaimId:f.id});return await this.setupFlow.recordSetupDelivery(D.setupTokenId,f.deliverySubject),await this.audit.append({...H7(B),action:"auth.passkey.registration_started",targetType:"user",targetId:x,metadata:{expiresAt:D.expiresAt,deliveryType:f.type}}),{setupUrl:D.setupUrl,expiresAt:D.expiresAt,delivery:{type:f.type,label:this.getChannelDescriptor?.(f.type)?.subjectLabel??"Delivery channel"}}}async validateTargetedRegistration(x){await this.targetedSetup.validate({userId:x.targetUserId,setupTokenId:d1(x.token)})}async completeTargetedRegistration(x){let B=await this.users.getUser(x.targetUserId),A=await this.targetedSetup.complete({userId:x.targetUserId,setupTokenId:d1(x.token)});if(B?.status==="invited"&&A.user.status==="active")await this.audit.append({actorUserId:A.user.id,action:"auth.user.status_updated",targetType:"user",targetId:A.user.id,metadata:{status:"active"}});if(A.boundIdentity)await this.audit.append({actorUserId:A.user.id,action:"auth.identity.delivery_bound",targetType:"user",targetId:A.user.id,metadata:{type:A.boundIdentity.type}})}getPasskeySetupRequired(x=this.issuer){return this.setupFlow.getPasskeySetupRequired(x,{rotateHidden:!0})}getPasskeySetupRequiredForDelivery(x=this.issuer){return this.setupFlow.getPasskeySetupRequired(x)}hasSetupEmailDelivery(x,B){return this.setupFlow.hasSetupEmailDelivery(x,B)}recordSetupEmailDelivery(x,B,A={}){return this.setupFlow.recordSetupEmailDelivery(x,B,A)}async resolveStoredDeliveryIdentity(x){let A=(await this.identities.listIdentities(x)).filter((w)=>w.revokedAt===null&&Boolean(w.deliverySubject)&&w.evidence.some((f)=>f.sourceKind==="admin"||f.assurance==="verified"&&f.verifiedAt!==null)).at(-1);if(!A)throw Error("A confirmed delivery channel is required");return A}async prepareDeliveryIdentity(x,B){let A=B.subject.trim(),w=B.label?.trim(),{identity:f}=await this.identities.ensureIdentity({userId:x,type:B.type,subject:A,deliverySubject:A,label:w&&w.length>0?w:A,source:{kind:"admin"}});if(!f.deliverySubject)throw Error("Delivery identity subject was not persisted");return{...f,deliverySubject:f.deliverySubject}}}class XL{db;constructor(x){this.db=x}async invitePeerPerson(x){let B=Hu(x.peerId);return this.db.transaction(async(A)=>{await SX0(A,x.createdByUserId);let[w]=await A.select({peerId:O9.peerId}).from(O9).where(i(O9.peerId,B)).limit(1);if(w)throw Error("External peer is already linked");let f=Date.now(),D={id:i8("prsn"),displayName:x.displayName,profileEntityId:null,createdAt:f,updatedAt:f},$=i8("usr"),Z={id:$,personId:D.id,displayName:x.displayName,role:x.role,status:"invited",canonicalId:`user:${$.slice(4)}`,createdAt:f,updatedAt:f},Q={peerId:B,personId:D.id,verificationStatus:"unverified",createdByUserId:x.createdByUserId,createdAt:f,updatedAt:f};return await A.insert(w9).values(D),await A.insert(S0).values(Z),await A.insert(O9).values(Q),{person:D,user:Z,peer:Q}})}async linkPeer(x){let B=Hu(x.peerId);return this.db.transaction(async(A)=>{await SX0(A,x.createdByUserId);let[w]=await A.select().from(O9).where(i(O9.peerId,B)).limit(1);if(w){if(w.personId!==x.personId)throw Error("External peer is already linked to another person");return w}let[f]=await A.select({id:w9.id}).from(w9).where(i(w9.id,x.personId)).limit(1);if(!f)throw Error(`Auth person not found: ${x.personId}`);let D=Date.now(),$={peerId:B,personId:f.id,verificationStatus:"unverified",createdByUserId:x.createdByUserId,createdAt:D,updatedAt:D};return await A.insert(O9).values($),$})}async getByPeerId(x){let[B]=await this.db.select().from(O9).where(i(O9.peerId,Hu(x))).limit(1);return B}async listByPersonId(x){return this.db.select().from(O9).where(i(O9.personId,x)).orderBy(O9.createdAt,ux`rowid`)}async listAll(){return this.db.select().from(O9).orderBy(O9.createdAt,ux`rowid`)}}function Hu(x){let B=x.trim();if(!B)throw Error("External peer id is required");return B}async function SX0(x,B){let[A]=await x.select().from(S0).where(i(S0.id,B)).limit(1);if(A?.role!=="admin"||A.status!=="active")throw Error("An active Admin is required to link an external peer");return A}class YL{database;constructor(x){this.database=x}async get(x){let[B]=await this.database.db.select().from(bw).where(i(bw.domain,Fu(x))).limit(1);return B?{domain:B.domain,keyFingerprint:B.keyFingerprint,grantedLevel:B.grantedLevel}:void 0}async grant(x,B={}){if(x.grantedLevel==="admin")throw Error("A2A peer trust grants must be trusted or public");let A={domain:Fu(x.domain),keyFingerprint:x.keyFingerprint,grantedLevel:x.grantedLevel},w=Date.now();return await this.database.db.insert(bw).values({domain:A.domain,keyFingerprint:A.keyFingerprint,grantedLevel:A.grantedLevel,createdAt:w,updatedAt:w}).onConflictDoUpdate({target:bw.domain,set:{keyFingerprint:A.keyFingerprint,grantedLevel:A.grantedLevel,updatedAt:w}}),await new d2(this.database.db).append({...B.actorUserId?{actorUserId:B.actorUserId}:{},action:"auth.a2a_peer_trust.granted",targetType:"a2a_peer",targetId:A.domain,metadata:{keyFingerprint:A.keyFingerprint,grantedLevel:A.grantedLevel}}),A}async revoke(x,B={}){let A=Fu(x);if((await this.database.db.delete(bw).where(i(bw.domain,A)).returning({domain:bw.domain})).length>0)await new d2(this.database.db).append({...B.actorUserId?{actorUserId:B.actorUserId}:{},action:"auth.a2a_peer_trust.revoked",targetType:"a2a_peer",targetId:A})}}function Fu(x){let B=x.trim().toLowerCase();if(!B||B.includes(":")||B.includes("/"))throw Error("A2A peer trust domain must be a bare domain");return B}import{randomUUID as iX0}from"crypto";var _V=86400;class Ku{setupStateStore;passkeyService;setupTokenTtlSeconds;resolveSessionUserId;setupToken;constructor(x){this.setupStateStore=x.setupStateStore,this.passkeyService=x.passkeyService,this.setupTokenTtlSeconds=x.setupTokenTtlSeconds??_V,this.resolveSessionUserId=x.resolveSessionUserId}async ensureSetupToken(){let x=this.getValidSetupToken();if(x)return x;let B=await this.setupStateStore.getValidSetupToken(Math.floor(Date.now()/1000));if(B)return this.setupToken=B,B;let A=Math.floor(Date.now()/1000);if(await this.setupStateStore.hasActiveSetupToken(A))return await this.setupStateStore.hasActiveSetupDelivery(A)?void 0:this.createSetupToken();return this.createSetupToken()}async createSetupToken(){return this.setupToken={token:`setup_${iX0()}`,expiresAt:Math.floor(Date.now()/1000)+this.setupTokenTtlSeconds},await this.setupStateStore.saveSetupToken(this.setupToken),this.setupToken}getValidSetupToken(){if(!this.setupToken)return;if(this.setupToken.expiresAt<=Math.floor(Date.now()/1000)){this.setupToken=void 0;return}return this.setupToken}async resolveSetupToken(x){let B=new URL(x.url),A=B.searchParams.get("setup_token")??B.searchParams.get("token");if(!A)return;let w=await this.setupStateStore.getSetupTokenTarget(A,Math.floor(Date.now()/1000));return w?{token:A,...w}:void 0}async hasValidSetupToken(x){return Boolean(await this.resolveSetupToken(x))}async hasConflictingAccountSession(x,B){if(!B.targetUserId||!this.resolveSessionUserId)return!1;let A=await this.resolveSessionUserId(x);return A!==void 0&&A!==B.targetUserId}async consumeSetupToken(x){if(this.setupToken?.token===x)this.setupToken=void 0;await this.setupStateStore.consumeSetupToken(x)}async clearSetupState(){this.setupToken=void 0,await this.setupStateStore.clearSetupState()}getSetupUrl(x){let B=this.getValidSetupToken();if(!B)return;return Y7(x,`/setup?token=${encodeURIComponent(B.token)}`)}async getPasskeySetupRequired(x,B={}){if(await this.passkeyService.hasCredentials())return;let A=this.getValidSetupToken();if(!A&&B.rotateHidden){let w=Math.floor(Date.now()/1000);if(await this.setupStateStore.hasActiveSetupDelivery(w))return;A=await this.createSetupToken()}if(!A)return;return{setupUrl:Y7(x,`/setup?token=${encodeURIComponent(A.token)}`),expiresAt:A.expiresAt,setupTokenId:d1(A.token)}}async createUserPasskeySetup(x,B,A={}){let w={token:`setup_${iX0()}`,expiresAt:Math.floor(Date.now()/1000)+this.setupTokenTtlSeconds};return await this.setupStateStore.saveTargetedSetupToken(w,x,A),{setupUrl:Y7(B,`/setup?token=${encodeURIComponent(w.token)}`),expiresAt:w.expiresAt,setupTokenId:d1(w.token)}}consumeTargetedSetupTokensForUser(x){return this.setupStateStore.consumeTargetedSetupTokensForUser(x)}async handleSetupPage(x){let B=await this.resolveSetupToken(x);if(await this.passkeyService.hasCredentials()&&B?.targetUserId==null)return new Response("Setup already completed",{status:404});if(!B)return new Response("Not Found",{status:404});if(await this.hasConflictingAccountSession(x,B)){let A=new URL(x.url);return RZ(Ow0(`${A.pathname}${A.search}`),409)}return RZ(hw0(B.token))}async hasSetupDelivery(x,B){return this.setupStateStore.hasDelivery(x,B)}async recordSetupDelivery(x,B,A={}){await this.setupStateStore.recordDelivery(x,B,A)}async hasSetupEmailDelivery(x,B){return this.hasSetupDelivery(x,B)}async recordSetupEmailDelivery(x,B,A={}){await this.recordSetupDelivery(x,B,A)}}class qu{db;identityStore;constructor(x,B){this.db=x,this.identityStore=B}async validate(x){await lX0(this.db,x)}async complete(x){let B=Math.floor(Date.now()/1000),A=Date.now(),w=await this.db.transaction(async(f)=>{let D=await lX0(f,x),$=D.deliveryClaim;if($){let[Q]=await f.select({id:b6.id}).from(b6).where(i0(i(b6.claimId,$.id),i(b6.assurance,"verified"),FW(b6.verifiedAt))).limit(1);if(!Q)await f.insert(b6).values({id:i8("aev"),claimId:$.id,sourceKind:"provider",sourceId:null,assurance:"verified",verifiedAt:A,createdAt:A})}if(D.user.status==="invited")await f.update(S0).set({status:"active",updatedAt:A}).where(i(S0.id,D.user.id));if((await f.update(h0).set({consumedAt:B}).where(i0(i(h0.tokenHash,x.setupTokenId),Jx(h0.consumedAt))).returning({tokenHash:h0.tokenHash})).length!==1)throw Error("Invalid or consumed setup token");return await f.update(yx).set({state:"claimed",claimedAt:A,updatedAt:A}).where(i(yx.currentSetupTokenHash,x.setupTokenId)),$?.id});return{user:await this.requireUser(x.userId),...w?{boundIdentity:await this.identityStore.getIdentity(w)}:{}}}async requireUser(x){let[B]=await this.db.select().from(S0).where(i(S0.id,x)).limit(1);if(!B)throw Error(`Auth user not found: ${x}`);return B}}async function lX0(x,B){let A=Math.floor(Date.now()/1000),[w]=await x.select().from(h0).where(i0(i(h0.tokenHash,B.setupTokenId),i(h0.purpose,"passkey_setup"),i(h0.targetUserId,B.userId),Jx(h0.consumedAt),F1(h0.expiresAt,A))).limit(1);if(!w)throw Error("Invalid or consumed setup token");let[f]=await x.select().from(S0).where(i(S0.id,B.userId)).limit(1);if(!f||f.status==="suspended")throw Error("Passkey registration user is unavailable");if(!w.deliveryClaimId)return{user:f};let[D]=await x.select().from(Lx).where(i0(i(Lx.id,w.deliveryClaimId),Jx(Lx.revokedAt))).limit(1);if(!D)throw Error("Setup delivery identity is unavailable");if(D.personId!==f.personId)throw Error("Setup delivery identity does not belong to target user");if(D.type!=="email"&&D.type!=="discord"||!D.deliverySubject)throw Error("Setup delivery identity is unavailable");let[$]=await x.select({tokenHash:H1.tokenHash}).from(H1).where(i0(i(H1.tokenHash,B.setupTokenId),i(H1.recipientHash,CZ(D.deliverySubject)))).limit(1);if(!$)throw Error("Setup delivery was not confirmed");return{user:f,deliveryClaim:D}}class zu{users;audit;sessions;refreshTokens;consumeTargetedSetupTokensForUser;constructor(x){this.users=x.users,this.audit=x.audit,this.sessions=x.sessions,this.refreshTokens=x.refreshTokens,this.consumeTargetedSetupTokensForUser=x.consumeTargetedSetupTokensForUser}async createUser(x,B={}){let A=await this.users.createUser(x);return await this.audit.append({...H7(B),action:"auth.user.created",targetType:"user",targetId:A.id,metadata:{role:A.role,status:A.status}}),A}async updateRole(x,B,A={}){let w=await this.users.getUser(x),f=await this.users.updateUserRole(x,B);if(w&&w.role!==f.role)await this.revokeGrants(x),await this.audit.append({...H7(A),action:"auth.user.role_updated",targetType:"user",targetId:x,metadata:{from:w.role,to:f.role}});return f}async updateStatus(x,B,A={}){let w=await this.users.getUser(x),f=await this.users.updateUserStatus(x,B);if(w&&w.status!==f.status){let D=f.status==="suspended"?await this.consumeTargetedSetupTokensForUser(x):0;await this.revokeGrants(x),await this.audit.append({...H7(A),action:"auth.user.status_updated",targetType:"user",targetId:x,metadata:{from:w.status,to:f.status,...D>0?{consumedSetupTokens:D}:{}}})}return f}async deleteSuspendedUser(x,B={}){let A=await this.users.deleteSuspendedUser(x);return await this.audit.append({...H7(B),action:"auth.user.deleted",targetType:"user",targetId:x,metadata:{role:A.role,status:A.status}}),A}async revokeGrants(x,B={}){let[A,w]=await Promise.all([this.sessions.revokeSessionsForSubject(x),this.refreshTokens.revokeTokensForSubject(x)]);if(B.actorUserId)await this.audit.append({...H7(B),action:"auth.user.grants_revoked",targetType:"user",targetId:x,metadata:{sessions:A,refreshTokens:w}});return{sessions:A,refreshTokens:w}}}class bu{passkeyService;sessionStore;setupFlow;registrationUserProvider;validateTargetedRegistration;completeTargetedRegistration;recordAuditEvent;constructor(x){this.passkeyService=x.passkeyService,this.sessionStore=x.sessionStore,this.setupFlow=x.setupFlow,this.registrationUserProvider=x.registrationUserProvider,this.validateTargetedRegistration=x.validateTargetedRegistration,this.completeTargetedRegistration=x.completeTargetedRegistration,this.recordAuditEvent=x.recordAuditEvent}async handleRegistrationOptions(x){let B=await this.setupFlow.resolveSetupToken(x);if(await this.passkeyService.hasCredentials()&&B?.targetUserId==null)return V9("access_denied","Passkey setup already completed");if(!B)return V9("access_denied","Invalid setup token");if(await this.setupFlow.hasConflictingAccountSession(x,B))return V9("access_denied","Sign out before using a setup link for another account");try{let A=await this.passkeyService.generateRegistrationOptions(WL(x),await this.registrationUserProvider(B.targetUserId??void 0));return W7(A)}catch{return V9("access_denied","Passkey registration user is unavailable")}}async handleRegistrationVerify(x){let B=await this.setupFlow.resolveSetupToken(x);if(await this.passkeyService.hasCredentials()&&B?.targetUserId==null)return V9("access_denied","Passkey setup already completed");if(!B)return V9("access_denied","Invalid setup token");if(await this.setupFlow.hasConflictingAccountSession(x,B))return V9("access_denied","Sign out before using a setup link for another account");if(B.targetUserId)try{await this.registrationUserProvider(B.targetUserId),await this.validateTargetedRegistration?.({...B,targetUserId:B.targetUserId})}catch{return await this.recordRegistrationFailure(B.targetUserId),V9("access_denied","Passkey registration user is unavailable")}let A=await this.passkeyService.verifyRegistrationResponse(await x.json(),WL(x),B.targetUserId??void 0);if(!A.verified||B.targetUserId!==null&&A.subject!==B.targetUserId)return await this.recordRegistrationFailure(B.targetUserId),V9("access_denied","Passkey registration failed");if(B.targetUserId&&this.completeTargetedRegistration)try{await this.completeTargetedRegistration({...B,targetUserId:B.targetUserId})}catch{return await this.recordRegistrationFailure(B.targetUserId),V9("access_denied","Passkey registration user is unavailable")}else await this.setupFlow.consumeSetupToken(B.token);let w=await this.sessionStore.createSession(A.subject,{secure:OZ(x)});return W7({verified:!0},200,{"Set-Cookie":w.cookie})}async recordRegistrationFailure(x){await this.recordAuditEvent?.({action:"auth.passkey.registration_failed",...x?{targetType:"user",targetId:x}:{}})}async handleAuthenticationOptions(x){if(!await this.passkeyService.hasCredentials())return V9("access_denied","No passkey registered");let B=await this.passkeyService.generateAuthenticationOptions(WL(x));return W7(B)}async handleAuthenticationVerify(x){let B=await this.passkeyService.verifyAuthenticationResponse(await x.json(),WL(x));if(!B.verified)return await this.recordAuditEvent?.({action:"auth.passkey.authentication_failed"}),V9("access_denied","Passkey authentication failed");let A=await this.sessionStore.createSession(B.subject,{secure:OZ(x)});return W7({verified:!0},200,{"Set-Cookie":A.cookie})}}function WL(x){let B=s2(x),A=new URL(B);return{origin:A.origin,rpID:A.hostname}}class Vu{keyStore;a2aKeyStore;clientStore;authCodeStore;sessionStore;peerTrustStore;passkeyService;setupFlow;oauthEndpoints;webauthnEndpoints;runtimeDatabase;refreshTokenStore;issuer;trustedIssuers;allowLocalhostIssuers;anchor;anchorProfileEntityId;setupTokenTtlSeconds;getInvitationDeliveryProvider;getChannelDescriptor;isChannelTypeRegistered;autoStartInvitationDeliveryRecovery;invitationDeliveryRecoveryIntervalMs;invitationDeliveryRecoveryStaleMs;resolveProfileDisplayName;logger;userStore;identityReconciliationService;passkeySetupCoordinator;userManagementService;principalService;administrationService;accountService;invitationService;invitationDeliverySupervisor;interfacePrincipalStore;auditStore;initialization;firstAdminInitialization;closePromise;constructor(x){this.issuer=x.issuer,this.trustedIssuers=x.trustedIssuers,this.allowLocalhostIssuers=x.allowLocalhostIssuers,this.anchor=x.anchor,this.anchorProfileEntityId=x.anchorProfileEntityId,this.setupTokenTtlSeconds=x.setupTokenTtlSeconds??_V,this.getInvitationDeliveryProvider=x.getInvitationDeliveryProvider,this.getChannelDescriptor=x.getChannelDescriptor,this.isChannelTypeRegistered=x.isChannelTypeRegistered,this.autoStartInvitationDeliveryRecovery=x.autoStartInvitationDeliveryRecovery??!0,this.invitationDeliveryRecoveryIntervalMs=x.invitationDeliveryRecoveryIntervalMs??Gf0,this.invitationDeliveryRecoveryStaleMs=x.invitationDeliveryRecoveryStaleMs??Fg,this.resolveProfileDisplayName=x.resolveProfileDisplayName,this.logger=x.logger,this.runtimeDatabase=new HW({storageDir:x.storageDir,...x.replica?{replica:x.replica}:{}}),this.keyStore=new RP(this.runtimeDatabase),this.a2aKeyStore=new qg(this.runtimeDatabase),this.clientStore=new vP(this.runtimeDatabase),this.authCodeStore=new EP(this.runtimeDatabase),this.sessionStore=new Nz(this.runtimeDatabase),this.refreshTokenStore=new Mz(this.runtimeDatabase),this.peerTrustStore=new YL(this.runtimeDatabase),this.passkeyService=new QL({runtimeDatabase:this.runtimeDatabase,...x.logger?{logger:x.logger}:{}});let B=new Yg(this.runtimeDatabase);this.setupFlow=new Ku({setupStateStore:B,passkeyService:this.passkeyService,setupTokenTtlSeconds:this.setupTokenTtlSeconds,resolveSessionUserId:async(A)=>(await this.resolveActiveSession(A))?.user.id}),this.oauthEndpoints=new Vg({clientStore:this.clientStore,authCodeStore:this.authCodeStore,refreshTokenStore:this.refreshTokenStore,resolveSession:async(A)=>(await this.resolveActiveSession(A))?.session,keyStore:this.keyStore,...x.oauthClientMaintenanceIntervalMs!==void 0?{clientMaintenanceIntervalMs:x.oauthClientMaintenanceIntervalMs}:{},onClientMaintenanceError:(A)=>{this.logger?.warn("Failed to prune stale OAuth clients",{error:A})}}),this.webauthnEndpoints=new bu({passkeyService:this.passkeyService,sessionStore:this.sessionStore,setupFlow:this.setupFlow,recordAuditEvent:async(A)=>{await this.getAuditStore().append(A)},validateTargetedRegistration:async(A)=>{await this.getPasskeySetupCoordinator().validateTargetedRegistration(A)},completeTargetedRegistration:async(A)=>{await this.getPasskeySetupCoordinator().completeTargetedRegistration(A)},registrationUserProvider:async(A)=>{let w=A?await this.getUserStore().getUser(A):await this.ensureFirstAdminUser();if(!w||w.status==="suspended")throw Error("Passkey registration user is unavailable");return{subject:w.id,userName:w.displayName,userDisplayName:w.displayName}}})}async initialize(){if(this.closePromise)await this.closePromise,this.closePromise=void 0;if(this.initialization)return this.initialization;let x=this.initializeInternal();this.initialization=x;try{await x}catch(B){if(this.initialization===x)this.initialization=void 0;throw B}}close(){return this.closePromise??=this.closeInternal(),this.closePromise}async ensureStarted(){if(this.userStore)return;await this.runtimeDatabase.start();let x=new GW(this.runtimeDatabase.db,{...this.isChannelTypeRegistered?{isChannelTypeRegistered:this.isChannelTypeRegistered}:{}});this.userStore=new Oz(this.runtimeDatabase.db),this.identityReconciliationService=new Xg({identities:x,users:this.userStore});let B=new qu(this.runtimeDatabase.db,x);this.interfacePrincipalStore=new qP(this.runtimeDatabase.db);let A=new XL(this.runtimeDatabase.db);this.auditStore=new d2(this.runtimeDatabase.db),this.invitationService=new hP({db:this.runtimeDatabase.db,issuer:this.issuer,setupTokenTtlSeconds:this.setupTokenTtlSeconds,deliveryRecoveryStaleMs:this.invitationDeliveryRecoveryStaleMs,audit:this.auditStore,...this.getInvitationDeliveryProvider?{getDeliveryProvider:this.getInvitationDeliveryProvider}:{},...this.getChannelDescriptor?{getChannelDescriptor:this.getChannelDescriptor}:{}}),this.invitationDeliverySupervisor=new Kg(this.invitationDeliveryRecoveryIntervalMs,async(f)=>{await this.getInvitationService().recoverInterruptedDeliveries(f)},{onError:(f)=>{this.logger?.warn("Failed to recover invitation delivery",{error:f})}}),this.passkeySetupCoordinator=new Wu({issuer:this.issuer,users:this.userStore,identities:x,audit:this.auditStore,setupFlow:this.setupFlow,targetedSetup:B,...this.getChannelDescriptor?{getChannelDescriptor:this.getChannelDescriptor}:{}}),this.userManagementService=new zu({users:this.userStore,audit:this.auditStore,sessions:this.sessionStore,refreshTokens:this.refreshTokenStore,consumeTargetedSetupTokensForUser:(f)=>this.setupFlow.consumeTargetedSetupTokensForUser(f)}),this.principalService=new fg({issuer:this.issuer,trustedIssuers:this.trustedIssuers,allowLocalhostIssuers:this.allowLocalhostIssuers,users:this.userStore,identities:x,sessions:this.sessionStore,ensureFirstAdminUser:()=>this.ensureFirstAdminUser(),getJwks:()=>this.getJwks()});let w=new Tz(this.runtimeDatabase.db);this.accountService=new pc({users:this.userStore,identities:x,credentials:w,sessions:this.sessionStore,refreshTokens:this.refreshTokenStore,passkeys:this.passkeyService,audit:this.auditStore,...this.isChannelTypeRegistered?{isChannelTypeRegistered:this.isChannelTypeRegistered}:{}}),this.administrationService=new Dg({configuredAnchorKind:this.anchor,...this.resolveProfileDisplayName?{resolveProfileDisplayName:this.resolveProfileDisplayName}:{},users:this.userStore,identities:x,credentials:w,externalPeers:A,invitations:this.getInvitationService(),audit:this.auditStore,management:this.getUserManagementService(),...this.getChannelDescriptor?{getChannelDescriptor:this.getChannelDescriptor}:{},startPasskeyRegistration:(f,D,$)=>this.getPasskeySetupCoordinator().startRegistration(f,D,$)})}getUserStore(){return qA(this.userStore)}getIdentityReconciliationService(){return qA(this.identityReconciliationService)}getPasskeySetupCoordinator(){return qA(this.passkeySetupCoordinator)}getPrincipalService(){return qA(this.principalService)}getAdministrationService(){return qA(this.administrationService)}getAccountService(){return qA(this.accountService)}getInvitationService(){return qA(this.invitationService)}async startInvitationDeliveryRecovery(){await this.ensureStarted(),await this.invitationDeliverySupervisor?.start()}getInterfacePrincipalStore(){return qA(this.interfacePrincipalStore)}getAuditStore(){return qA(this.auditStore)}hasPasskeyCredentials(){return this.passkeyService.hasCredentials()}getSetupUrl(x=this.issuer){return this.setupFlow.getSetupUrl(x)}async getJwks(){let[x,B]=await Promise.all([this.keyStore.getPublicJwk(),this.a2aKeyStore.getPublicJwk()]);return{keys:[x,B]}}getUserManagementService(){return qA(this.userManagementService)}async initializeInternal(){if(await this.ensureStarted(),this.autoStartInvitationDeliveryRecovery)await this.startInvitationDeliveryRecovery();if(await this.projectConfiguredBrainAnchor(),await Promise.all([this.keyStore.getPrivateJwk(),this.a2aKeyStore.getPrivateJwk()]),this.logger?.debug("Auth service signing keys loaded"),!await this.hasPasskeyCredentials()){await this.setupFlow.ensureSetupToken();let x=this.getSetupUrl();if(x)if(r3(this.issuer))this.logger?.warn(`Passkey setup required: ${x}`);else this.logger?.warn("Passkey setup required. Ask through an Admin interface for the setup URL.")}await this.oauthEndpoints.startClientMaintenance()}async closeInternal(){await this.oauthEndpoints.stopClientMaintenance(),await this.invitationDeliverySupervisor?.close(),this.invitationDeliverySupervisor=void 0,this.userStore=void 0,this.identityReconciliationService=void 0,this.passkeySetupCoordinator=void 0,this.userManagementService=void 0,this.principalService=void 0,this.administrationService=void 0,this.accountService=void 0,this.invitationService=void 0,this.interfacePrincipalStore=void 0,this.auditStore=void 0,this.initialization=void 0,this.firstAdminInitialization=void 0,await this.runtimeDatabase.stop()}profileDisplayName(x){return kP(this.resolveProfileDisplayName,x,this.logger)}async projectConfiguredBrainAnchor(){let x=await this.getUserStore().getBrainAnchor(),B=await this.profileDisplayName(this.anchorProfileEntityId),A=B??x?.displayName??(this.anchor==="person"?"Admin":this.anchor==="team"?"Team":"Organization");await this.getUserStore().configureBrainAnchor({kind:this.anchor==="person"?"person":"collective",displayName:A,profileEntityId:this.anchorProfileEntityId,...B?{subjectDisplayName:B}:{}})}async ensureFirstAdminUser(){if(this.firstAdminInitialization)return this.firstAdminInitialization;let x=(async()=>{let B=await this.getUserStore().listUsers(),A=await this.getUserStore().ensureFirstAdminUser();if(await this.projectConfiguredBrainAnchor(),!B.some((w)=>w.id===A.id))await this.getAuditStore().append({action:"auth.user.created",targetType:"user",targetId:A.id,metadata:{role:A.role,status:A.status}});return A})();this.firstAdminInitialization=x;try{return await x}finally{if(this.firstAdminInitialization===x)this.firstAdminInitialization=void 0}}async resolveActiveSession(x){return await this.ensureStarted(),this.getPrincipalService().resolveActiveSession(x)}}function qA(x){if(!x)throw Error("Auth service has not been initialized");return x}var Fix="anchor-profile/anchor-profile";class HL{issuer;runtime;requestRouter;getInvitationDeliveryProvider;getChannelDescriptor;listChannelDescriptors;logger;constructor(x){this.issuer=a2(x.issuer),this.getInvitationDeliveryProvider=x.getInvitationDeliveryProvider,this.getChannelDescriptor=x.getChannelDescriptor,this.listChannelDescriptors=x.listChannelDescriptors,this.logger=x.logger;let B=x.isChannelTypeRegistered??(x.getChannelDescriptor?(A)=>Boolean(x.getChannelDescriptor?.(A)):void 0);this.runtime=new Vu({storageDir:x.storageDir,...x.replica?{replica:x.replica}:{},issuer:this.issuer,trustedIssuers:new Set([this.issuer,...(x.trustedIssuers??[]).map((A)=>a2(A))]),allowLocalhostIssuers:x.allowLocalhostIssuers??r3(this.issuer),anchor:x.anchor??"person",anchorProfileEntityId:x.anchorProfileEntityId??Fix,...x.resolveProfileDisplayName?{resolveProfileDisplayName:x.resolveProfileDisplayName}:{},...x.setupTokenTtlSeconds!==void 0?{setupTokenTtlSeconds:x.setupTokenTtlSeconds}:{},...x.getInvitationDeliveryProvider?{getInvitationDeliveryProvider:x.getInvitationDeliveryProvider}:{},...x.getChannelDescriptor?{getChannelDescriptor:x.getChannelDescriptor}:{},...B?{isChannelTypeRegistered:B}:{},...x.autoStartInvitationDeliveryRecovery!==void 0?{autoStartInvitationDeliveryRecovery:x.autoStartInvitationDeliveryRecovery}:{},...x.invitationDeliveryRecoveryIntervalMs!==void 0?{invitationDeliveryRecoveryIntervalMs:x.invitationDeliveryRecoveryIntervalMs}:{},...x.invitationDeliveryRecoveryStaleMs!==void 0?{invitationDeliveryRecoveryStaleMs:x.invitationDeliveryRecoveryStaleMs}:{},...x.oauthClientMaintenanceIntervalMs!==void 0?{oauthClientMaintenanceIntervalMs:x.oauthClientMaintenanceIntervalMs}:{},...x.logger?{logger:x.logger}:{}}),this.requestRouter=new Tc({setupFlow:this.runtime.setupFlow,oauthEndpoints:this.runtime.oauthEndpoints,webauthnEndpoints:this.runtime.webauthnEndpoints,handleAdminRequest:(A)=>this.handleAdminRequest(A),handleAccountRequest:(A)=>this.handleAccountRequest(A),revokeSession:async(A)=>{await this.runtime.sessionStore.revokeSessionFromRequest(A)},getAuthorizationServerMetadata:(A)=>this.getAuthorizationServerMetadata(A),getProtectedResourceMetadata:(A,w)=>this.getProtectedResourceMetadata(A,w),getJwks:()=>this.getJwks()})}getIssuer(){return this.issuer}initialize(){return this.runtime.initialize()}startInvitationDeliveryRecovery(){return this.runtime.startInvitationDeliveryRecovery()}close(){return this.runtime.close()}async initializeConfiguredInterfacePrincipals(x){await this.initialize();let B=this.runtime.getInterfacePrincipalStore();return await B.seedConfigOnce(x),B.listActiveState()}async resolveInterfacePrincipal(x,B){return await this.initialize(),this.runtime.getInterfacePrincipalStore().resolve(x,B)}async hasPasskeyCredentials(){return this.runtime.passkeyService.hasCredentials()}async revokePasskey(x,B={}){await this.runtime.ensureStarted(),await this.runtime.getAdministrationService().revokePasskey(x,B)}async getJwks(){let[x,B]=await Promise.all([this.runtime.keyStore.getPublicJwk(),this.runtime.a2aKeyStore.getPublicJwk()]);return{keys:[x,B]}}async getA2ASigningKey(){let x=await this.runtime.a2aKeyStore.getPrivateJwk();return{privateJwk:x,keyId:Y7(this.issuer,`/.well-known/jwks.json#${x.kid}`)}}async grantA2APeerTrust(x,B={}){return await this.initialize(),this.runtime.peerTrustStore.grant(x,B)}async getA2APeerTrust(x){return await this.initialize(),this.runtime.peerTrustStore.get(x)}async revokeA2APeerTrust(x,B={}){return await this.initialize(),this.runtime.peerTrustStore.revoke(x,B)}getAuthorizationServerMetadata(x=this.issuer){let B=a2(x);return{issuer:B,authorization_endpoint:Y7(B,"/authorize"),token_endpoint:Y7(B,"/token"),registration_endpoint:Y7(B,"/register"),revocation_endpoint:Y7(B,"/revoke"),jwks_uri:Y7(B,"/.well-known/jwks.json"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none","client_secret_basic","client_secret_post"],scopes_supported:["openid","profile","email","offline_access","mcp"],subject_types_supported:["public"],id_token_signing_alg_values_supported:["ES256"]}}getProtectedResourceMetadata(x,B=this.issuer){return{resource:x,authorization_servers:[a2(B)],bearer_methods_supported:["header"],resource_signing_alg_values_supported:["ES256"],scopes_supported:["mcp"]}}async registerClient(x){return await this.initialize(),this.runtime.clientStore.registerClient(x)}async getRegisteredClient(x){return await this.initialize(),this.runtime.clientStore.getClient(x)}async createUser(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().createUser(x,B)}async cancelInvitation(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().cancelInvitation(x,B)}async confirmManualInvitationDelivery(x,B,A){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().confirmManualInvitationDelivery(x,B,A)}async createInvitation(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().createInvitation(x,B)}async resendInvitation(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().resendInvitation(x,B)}async inviteExternalPeerPerson(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().inviteExternalPeerPerson(x,B)}async linkExternalPeer(x,B){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().linkExternalPeer(x,B)}async getBrainAnchor(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().getBrainAnchor()}async listUsers(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listUsers()}async listAdminUsers(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listAdminUsers()}async listInvitationChannels(){await this.runtime.ensureStarted();let x=this.listChannelDescriptors?.()??[];return await Promise.all(x.map(async(A)=>{let w=[];try{let f=this.getInvitationDeliveryProvider?.(A.type);if(f&&await f.isAvailable())w.push("automatic")}catch{}if(A.manualDelivery===!0)w.push("manual");return{type:A.type,displayName:A.displayName,subjectLabel:A.subjectLabel,...A.subjectPattern?{subjectPattern:A.subjectPattern}:{},deliveryModes:w}}))}async reconcileIdentityProposals(x){return await this.runtime.ensureStarted(),this.runtime.getIdentityReconciliationService().reconcile(x)}async listPersonExternalPeers(x){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listPersonExternalPeers(x)}async listUserIdentities(x){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listUserIdentities(x)}async listUserPasskeys(x){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listUserPasskeys(x)}async updateUserRole(x,B,A={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().updateUserRole(x,B,A)}async updateUserStatus(x,B,A={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().updateUserStatus(x,B,A)}suspendUser(x,B={}){return this.updateUserStatus(x,"suspended",B)}async deleteSuspendedUser(x,B={}){await this.runtime.ensureStarted(),await this.runtime.getAdministrationService().deleteSuspendedUser(x,B)}async revokeUserSessionsAndRefreshTokens(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().revokeUserGrants(x,B)}async attachIdentity(x,B={}){await this.runtime.ensureStarted();let A=this.validateChannelSubject(x.type,x.subject);return this.runtime.getAdministrationService().attachIdentity({...x,...A&&!x.deliverySubject?{deliverySubject:x.subject}:{}},B)}async detachIdentity(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().detachIdentity(x,B)}async recordAuditEvent(x){return await this.runtime.ensureStarted(),this.runtime.getAuditStore().append(x)}async listAuditEvents(){return await this.runtime.ensureStarted(),this.runtime.getAdministrationService().listAuditEvents()}async resolveActorPrincipal(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveActor(x)}async resolveIdentityAccess(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveIdentityAccess(x)}async createAuthSession(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().createSession(x,B)}async getAuthSession(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().getSession(x)}async resolveSession(x){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveSession(x)}createAuthLoginResponse(x){return hz(x)}async verifyBearerToken(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().verifyBearerToken(x,B)}async resolveBearerGrant(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveBearerGrant(x,B)}async resolveBearerToken(x,B={}){return await this.runtime.ensureStarted(),this.runtime.getPrincipalService().resolveBearerToken(x,B)}getSetupUrl(x=this.issuer){return this.runtime.setupFlow.getSetupUrl(x)}async startPasskeyRegistrationForUser(x,B={},A){if(await this.runtime.ensureStarted(),A)this.validateChannelSubject(A.type,A.subject);return this.runtime.getPasskeySetupCoordinator().startRegistration(x,B,A)}async getPasskeySetupRequired(x=this.issuer){return await this.runtime.ensureStarted(),this.runtime.getPasskeySetupCoordinator().getPasskeySetupRequired(x)}async getPasskeySetupRequiredForDelivery(x=this.issuer){return await this.runtime.ensureStarted(),this.runtime.getPasskeySetupCoordinator().getPasskeySetupRequiredForDelivery(x)}async hasSetupEmailDelivery(x,B){return await this.runtime.ensureStarted(),this.runtime.getPasskeySetupCoordinator().hasSetupEmailDelivery(x,B)}async recordSetupEmailDelivery(x,B,A={}){await this.runtime.ensureStarted(),await this.runtime.getPasskeySetupCoordinator().recordSetupEmailDelivery(x,B,A)}async handleRequest(x){await this.initialize();let B;try{B=this.resolveRequestIssuer(x)}catch(A){return this.logger?.warn("Rejected OAuth request from untrusted issuer",{error:g(A)}),new Response("Untrusted OAuth issuer",{status:400})}return this.requestRouter.handle(x,B)}async handleWellKnownRequest(x){return this.handleRequest(x)}handleAccountRequest(x){return Jw0(x,{resolveSession:async(B)=>{let A=await this.runtime.resolveActiveSession(B);return A?{userId:A.user.id,sessionId:A.session.id}:void 0},account:this.runtime.getAccountService()})}handleAdminRequest(x){return Nw0(x,{resolveSession:(B)=>this.resolveSession(B),listUsers:()=>this.listUsers(),getBrainAnchor:()=>this.getBrainAnchor(),listAuditEvents:()=>this.listAuditEvents(),listInvitationChannels:()=>this.listInvitationChannels(),listAdminUsers:()=>this.listAdminUsers(),reconcileIdentityProposals:(B)=>this.reconcileIdentityProposals(B),listPersonExternalPeers:(B)=>this.listPersonExternalPeers(B),listUserIdentities:(B)=>this.listUserIdentities(B),listUserPasskeys:(B)=>this.listUserPasskeys(B),cancelInvitation:(B,A)=>this.cancelInvitation(B,{actorUserId:A}),confirmManualInvitationDelivery:(B,A,w)=>this.confirmManualInvitationDelivery(B,A,{actorUserId:w}),createInvitation:(B,A)=>this.createInvitation(B,{actorUserId:A}),createUser:(B,A)=>this.createUser(B,{actorUserId:A}),inviteExternalPeerPerson:(B,A)=>this.inviteExternalPeerPerson(B,{actorUserId:A}),resendInvitation:(B,A)=>this.resendInvitation(B,{actorUserId:A}),linkExternalPeer:(B,A)=>this.linkExternalPeer(B,{actorUserId:A}),updateUserRole:(B,A,w)=>this.updateUserRole(B,A,{actorUserId:w}),updateUserStatus:(B,A,w)=>this.updateUserStatus(B,A,{actorUserId:w}),deleteUser:(B,A)=>this.deleteSuspendedUser(B,{actorUserId:A}),attachIdentity:async(B,A)=>nX0(await this.attachIdentity(B,{actorUserId:A}),B.userId,this.getChannelDescriptor),detachIdentity:async(B,A)=>{let w=await this.detachIdentity(B,{actorUserId:A}),f=await this.runtime.getUserStore().getUserByPersonId(w.personId);if(!f)throw Error("Identity person has no auth user");return nX0(w,f.id,this.getChannelDescriptor)},revokePasskey:(B,A)=>this.revokePasskey(B,{actorUserId:A}),startPasskeyRegistration:(B,A,w)=>this.startPasskeyRegistrationForUser(B,{actorUserId:A},w),revokeUserSessionsAndRefreshTokens:(B,A)=>this.revokeUserSessionsAndRefreshTokens(B,{actorUserId:A})})}validateChannelSubject(x,B){let A=this.getChannelDescriptor?.(x);if(A?.subjectPattern&&!new RegExp(A.subjectPattern.source,A.subjectPattern.flags).test(B.trim()))throw Error(`Identity subject is invalid for channel: "${x}"`);return A}resolveRequestIssuer(x){return this.runtime.getPrincipalService().resolveRequestIssuer(x)}}function nX0(x,B,A){let w=x.label?.trim(),f=x.deliverySubject?.trim(),D=w&&w.length>0&&w!==A?.(x.type)?.subjectLabel?w:f;return{id:x.id,personId:x.personId,userId:B,type:x.type,visibility:x.visibility,evidence:x.evidence.map(($)=>({sourceKind:$.sourceKind,...$.sourceId?{sourceId:$.sourceId}:{},assurance:$.assurance,...$.verifiedAt!==null?{verifiedAt:$.verifiedAt}:{}})),...x.issuer?{issuer:x.issuer}:{},...D?{label:D}:{},...x.verifiedAt!==null?{verifiedAt:x.verifiedAt}:{},...x.revokedAt!==null?{revokedAt:x.revokedAt}:{},createdAt:x.createdAt}}import{join as qix}from"path";var dX0={name:"@brains/auth-service",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Embedded OAuth/OIDC authentication service for brain users",dependencies:{"@brains/contracts":"workspace:*","@brains/notification-contracts":"workspace:*","@brains/notifications":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@libsql/client":"^0.17.4","@simplewebauthn/server":"^13.3.1","drizzle-orm":"^0.45.2",jose:"^6.2.3"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43","drizzle-kit":"^0.31.10",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./account-contracts":"./src/account-contracts.ts","./admin-contracts":"./src/admin-contracts.ts"},files:["src"],main:"./src/index.ts",private:!0,scripts:{"db:generate":"drizzle-kit generate","db:studio":"drizzle-kit studio",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};var zix=X.union([X.string().email(),X.object({to:X.string().email(),subject:X.string().min(1),body:X.string().min(1)}).strict()]),bix=X.object({syncUrl:X.string().url().regex(/^(?:libsql|https):\/\//),authToken:X.string().min(1),syncIntervalMs:X.number().int().positive().optional()}).strict(),Vix=X.object({issuer:X.string().optional(),anchor:X.enum(_c).default("person"),trustedIssuers:X.array(X.string()).default([]),allowLocalhostIssuers:X.boolean().optional(),storageDir:X.string().optional(),replica:bix.optional(),setupTokenTtlSeconds:X.number().int().positive().default(_V),setupEmail:zix.optional()}),FL;function X6(){return FL}function Uix(x){return x??qix(".","data","auth")}async function Gix(x,B){if(B==="anchor-profile/anchor-profile"){let D=x.identity.getProfile().name.trim();return D&&D!=="Unknown"?D:void 0}let A=B.indexOf("/");if(A<=0||A===B.length-1)return;let f=(await x.entityService.getEntity({entityType:B.slice(0,A),id:B.slice(A+1),visibilityScope:"restricted"}))?.metadata.name;return typeof f==="string"?f:void 0}class Gu extends D8{service;unsubscribePrincipalResolver;constructor(x={}){super("auth-service",dX0,x,Vix)}async onRegister(x){await super.onRegister(x);let B=this.config.issuer??(x.preferLocalUrls?x.localSiteUrl??x.siteUrl:x.siteUrl??x.localSiteUrl);this.service=new HL({storageDir:Uix(this.config.storageDir),...this.config.replica?{replica:this.config.replica}:{},anchor:this.config.anchor,anchorProfileEntityId:"anchor-profile/anchor-profile",resolveProfileDisplayName:(w)=>Gix(x,w),...B?{issuer:B}:{},trustedIssuers:this.config.trustedIssuers,...this.config.allowLocalhostIssuers!==void 0?{allowLocalhostIssuers:this.config.allowLocalhostIssuers}:{},setupTokenTtlSeconds:this.config.setupTokenTtlSeconds,autoStartInvitationDeliveryRecovery:!1,getInvitationDeliveryProvider:(w)=>x.channels.getDeliveryProvider(w),getChannelDescriptor:(w)=>x.channels.getDescriptor(w),listChannelDescriptors:()=>x.channels.listDescriptors(),isChannelTypeRegistered:(w)=>Boolean(x.channels.getDescriptor(w)),logger:x.logger}),await this.service.initialize();let A=await this.service.initializeConfiguredInterfacePrincipals(x.permissions.getConfiguredPrincipalSeeds());x.permissions.replaceRuntimePrincipalState(A),FL=this.service,this.unsubscribePrincipalResolver=x.messaging.subscribe(KL,async(w)=>{let f=sX0.safeParse(w.payload);if(!f.success)return{success:!1,error:"Invalid auth principal request"};let D=await this.getService().resolveActorPrincipal(f.data.actor);return{success:!0,data:{principal:D?{userId:D.userId,personId:D.personId,...D.canonicalId?{canonicalId:D.canonicalId}:{},displayName:D.displayName,permissionLevel:D.permissionLevel}:null}}})}async onRegistrationComplete(){await this.getService().startInvitationDeliveryRecovery()}async onReady(x){await this.requestSetupEmailIfNeeded(x)}async onShutdown(){if(this.unsubscribePrincipalResolver?.(),this.unsubscribePrincipalResolver=void 0,FL===this.service)FL=void 0;await this.service?.close(),this.service=void 0}async getTools(){let x=await this.getService().hasPasskeyCredentials();return[{name:`${this.id}_get_passkey_setup_url`,description:"Get the first-passkey setup URL when passkey setup is required. Admin-only.",inputSchema:{},visibility:"admin",...x?{agentTool:!1}:{},handler:async()=>{let B=this.getService();if(await B.hasPasskeyCredentials())return{success:!0,data:{status:"complete"}};let A=await B.getPasskeySetupRequired();if(A)return{success:!0,data:{status:"setup_required",setupUrl:A.setupUrl,expiresAt:A.expiresAt}};return{success:!0,data:{status:"unavailable",reason:"Passkey setup URL is not available."}}},sideEffects:"none"}]}getWebRoutes(){let x=(B)=>this.getService().handleRequest(B);return[{path:"/.well-known/oauth-authorization-server",method:"GET",public:!0,handler:x},{path:"/.well-known/oauth-authorization-server",method:"OPTIONS",public:!0,handler:x},{path:"/.well-known/jwks.json",method:"GET",public:!0,handler:x},{path:"/.well-known/jwks.json",method:"OPTIONS",public:!0,handler:x},{path:"/.well-known/oauth-protected-resource",method:"GET",public:!0,handler:x},{path:"/.well-known/oauth-protected-resource",method:"OPTIONS",public:!0,handler:x},{path:"/setup",method:"GET",public:!0,handler:x},{path:"/login",method:"GET",public:!0,handler:x},{path:"/logout",method:"GET",public:!0,handler:x},{path:"/logout",method:"POST",public:!0,handler:x},{path:"/authorize",method:"GET",public:!0,handler:x},{path:"/authorize",method:"POST",public:!0,handler:x},{path:"/register",method:"POST",public:!0,handler:x},{path:"/register",method:"OPTIONS",public:!0,handler:x},{path:"/token",method:"POST",public:!0,handler:x},{path:"/token",method:"OPTIONS",public:!0,handler:x},{path:"/revoke",method:"POST",public:!0,handler:x},{path:"/revoke",method:"OPTIONS",public:!0,handler:x},{path:"/auth/account",method:"GET",public:!0,handler:x},{path:"/auth/account/mutations",method:"POST",public:!0,handler:x},{path:"/auth/account/passkeys/options",method:"POST",public:!0,handler:x},{path:"/auth/account/passkeys/verify",method:"POST",public:!0,handler:x},{path:"/auth/admin/anchor",method:"GET",public:!0,handler:x},{path:"/auth/admin/users",method:"GET",public:!0,handler:x},{path:"/auth/admin/audit",method:"GET",public:!0,handler:x},{path:"/auth/admin/channels",method:"GET",public:!0,handler:x},{path:"/auth/admin/mutations",method:"POST",public:!0,handler:x},{path:"/auth/admin/reconciliation",method:"POST",public:!0,handler:x},{path:"/webauthn/register/options",method:"POST",public:!0,handler:x},{path:"/webauthn/register/verify",method:"POST",public:!0,handler:x},{path:"/webauthn/auth/options",method:"POST",public:!0,handler:x},{path:"/webauthn/auth/verify",method:"POST",public:!0,handler:x}]}getService(){if(!this.service)throw Error("AuthServicePlugin has not been registered");return this.service}async requestSetupEmailIfNeeded(x){if(!this.config.setupEmail)return;let B=this.getService();if(await B.hasPasskeyCredentials())return;let A=await B.getPasskeySetupRequiredForDelivery();if(!A)return;let w=Eix(this.config.setupEmail,A);if(await B.hasSetupEmailDelivery(A.setupTokenId,w.to))return;let f=await x.messaging.send({type:PV,payload:{recipient:{type:"email",address:w.to},title:w.subject,body:w.body,sensitivity:"secret"}});if(!("success"in f)||!f.success||!f.data){x.logger.warn("Passkey setup email delivery was not confirmed");return}let D=Uu.safeParse(f.data);if(!D.success||D.data.status!=="sent"){x.logger.warn("Passkey setup email delivery was not confirmed");return}await B.recordSetupEmailDelivery(A.setupTokenId,w.to,D.data.deliveryId?{deliveryId:D.data.deliveryId}:{})}}function Eix(x,B){if(typeof x==="string"){let A=new Date(B.expiresAt*1000).toISOString(),w=new URL(B.setupUrl).origin;return{to:x,subject:"Set up your brain passkey",body:["Set up your brain passkey using this single-use link:","",B.setupUrl,"",`This link expires at ${A}.`,`Dashboard: ${w}/`,`MCP endpoint: ${w}/mcp`,"The first successful passkey registration completes setup and closes this link."].join(`
862
862
  `)}}return{to:x.to,subject:aX0(x.subject,B),body:aX0(x.body,B)}}function aX0(x,B){let A=new Date(B.expiresAt*1000).toISOString(),w=new URL(B.setupUrl).origin;return x.replaceAll("{{setupUrl}}",B.setupUrl).replaceAll("{{expiresAt}}",A).replaceAll("{{origin}}",w)}function Eu(x={}){return new Gu(x)}import{createPrivateKey as jix,createPublicKey as _ix,createHash as oX0,sign as Pix,verify as Jix}from"crypto";var _u="sig1",tX0=["@method","@target-uri","host","date","content-digest"],Lix=60000,kix=3600000;class z1 extends Error{constructor(x){super(x);this.name="HttpSignatureVerificationError"}}class Ju{fetchFn;ttlMs;cache=new Map;constructor(x={}){this.fetchFn=x.fetch??fetch,this.ttlMs=x.ttlMs??kix}async resolveKey(x){let{jwksUrl:B,kid:A}=Oix(x),w=await this.getJwks(B,!1),f=rX0(w,A);if(f)return f;let D=await this.getJwks(B,!0),$=rX0(D,A);if($)return $;throw new z1(`No JWKS key found for ${x}`)}async getJwks(x,B){let A=Date.now(),w=this.cache.get(x);if(!B&&w&&w.expiresAt>A)return w.jwks;let f=await this.fetchFn(x);if(!f.ok)throw new z1(`Could not fetch JWKS from ${x}: HTTP ${f.status}`);let D=await f.json(),$=hix(f.headers.get("cache-control"))??this.ttlMs;return this.cache.set(x,{jwks:D,expiresAt:A+$}),D}}async function eX0(x,B,A,w={}){let f=Math.floor((w.now?.getTime()??Date.now())/1000),D=w.now??new Date(f*1000),$=await BY0(x.body);qL(x.headers,"date",D.toUTCString()),qL(x.headers,"content-digest",$);let Z=vix(f,A),Q=AY0(x,Z),Y=Pix(null,Buffer.from(Q),yix(B));qL(x.headers,"signature-input",`${_u}=${Z}`),qL(x.headers,"signature",`${_u}=:${Y.toString("base64")}:`)}async function xY0(x,B,A={}){let w=zL(x.headers,"signature-input"),f=zL(x.headers,"signature");if(!w&&!f)return null;if(!w||!f)throw new z1("Incomplete HTTP signature headers");let D=Nix(w);if(D.alg.toLowerCase()!=="ed25519")throw new z1(`Unsupported signature alg: ${D.alg}`);if(!Rix(D.components,tX0))throw new z1("Unsupported HTTP signature components");let $=A.freshnessWindowMs??Lix,Z=A.now?.getTime()??Date.now();if(Math.abs(Z-D.created*1000)>$)throw new z1("HTTP signature is outside freshness window");let Q=await BY0(x.body);if(Pu(x.headers,"content-digest")!==Q)throw new z1("Content-Digest mismatch");let W=Iix(f),H=AY0(x,D.params),F=await B.resolveKey(D.keyId);if(!Jix(null,Buffer.from(H),mix(F),W))throw new z1("HTTP signature verification failed");return{keyId:D.keyId,domain:new URL(D.keyId).hostname.toLowerCase(),keyFingerprint:Lu(F)}}function Lu(x){let B=JSON.stringify({crv:x.crv,kty:x.kty,x:x.x});return oX0("sha256").update(B).digest("base64url")}async function BY0(x){let B=Mix(x);return`sha-256=:${oX0("sha256").update(B).digest("base64")}:`}function Mix(x){if(x===void 0||x===null)return Buffer.alloc(0);if(typeof x==="string")return Buffer.from(x);if(x instanceof Uint8Array)return Buffer.from(x);return Buffer.from(x)}function AY0(x,B){let A=new URL(x.url);return[`"@method": ${x.method.toUpperCase()}`,`"@target-uri": ${A.toString()}`,`"host": ${zL(x.headers,"host")??A.host}`,`"date": ${Pu(x.headers,"date")}`,`"content-digest": ${Pu(x.headers,"content-digest")}`,`"@signature-params": ${B}`].join(`
863
863
  `)}function vix(x,B){return`(${tX0.map((w)=>`"${w}"`).join(" ")});created=${x};keyid="${cix(B)}";alg="ed25519"`}function Nix(x){let B=`${_u}=`;if(!x.startsWith(B))throw new z1("Unsupported HTTP signature label");let A=x.slice(B.length),w=A.match(/^\(([^)]*)\)/);if(!w?.[1])throw new z1("Invalid Signature-Input components");let f=[...w[1].matchAll(/"([^"\\]*(?:\\.[^"\\]*)*)"/g)].map((Q)=>ju(Q[1]??"")),D=Number(A.match(/(?:^|;)created=(\d+)(?:;|$)/)?.[1]),$=ju(A.match(/(?:^|;)keyid="([^"\\]*(?:\\.[^"\\]*)*)"(?:;|$)/)?.[1]??""),Z=ju(A.match(/(?:^|;)alg="([^"\\]*(?:\\.[^"\\]*)*)"(?:;|$)/)?.[1]??"");if(!Number.isFinite(D)||!$||!Z)throw new z1("Invalid Signature-Input parameters");return{params:A,components:f,created:D,keyId:$,alg:Z}}function Iix(x){let B=x.match(/^sig1=:([^:]+):$/);if(!B?.[1])throw new z1("Invalid Signature header");return Buffer.from(B[1],"base64")}function Oix(x){let B=new URL(x);if(B.protocol!=="https:")throw new z1("JWKS keyid must be https");if(B.pathname!=="/.well-known/jwks.json")throw new z1("JWKS keyid must point at /.well-known/jwks.json");let A=B.hash.slice(1);if(!A)throw new z1("JWKS keyid must include a kid fragment");return B.hash="",{jwksUrl:B.toString(),kid:A}}function rX0(x,B){return x.keys?.find((A)=>A.kid===B)}function hix(x){let B=x?.match(/(?:^|,)\s*max-age=(\d+)\s*(?:,|$)/)?.[1];return B?Number(B)*1000:void 0}function zL(x,B){if(x instanceof Headers)return x.get(B)??void 0;let A=Object.keys(x).find((w)=>w.toLowerCase()===B);return A?x[A]:void 0}function Pu(x,B){let A=zL(x,B);if(!A)throw new z1(`Missing required header: ${B}`);return A}function qL(x,B,A){if(x instanceof Headers){x.set(B,A);return}x[B]=A}function Rix(x,B){return x.length===B.length&&x.every((A,w)=>A===B[w])}function yix(x){return Cix(x)?x:jix({key:x,format:"jwk"})}function mix(x){return _ix({key:x,format:"jwk"})}function Cix(x){return typeof x.export==="function"}function cix(x){return x.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}function ju(x){return x.replace(/\\([\\"])/g,"$1")}var ku=(x,B,A)=>{return(w,f)=>{let D=-1;return $(0);async function $(Z){if(Z<=D)throw Error("next() called multiple times");D=Z;let Q,Y=!1,W;if(x[Z])W=x[Z][0][0],w.req.routeIndex=Z;else W=Z===x.length&&f||void 0;if(W)try{Q=await W(w,()=>$(Z+1))}catch(H){if(H instanceof Error&&B)w.error=H,Q=await B(H,w),Y=!0;else throw H}else if(w.finalized===!1&&A)Q=await A(w);if(Q&&(w.finalized===!1||Y))w.res=Q;return w}}};var wY0=Symbol();var fY0=(x,B)=>{return new Response(x,{headers:{"Content-Type":B.replace(/^[^;]+/,(w)=>w.toLowerCase())}}).formData()};var Mu=(x)=>("headers"in x),DY0=async(x,B=Object.create(null))=>{let{all:A=!1,dot:w=!1}=B,$=(Mu(x)?x.headers:x.raw.headers).get("Content-Type")?.split(";")[0].trim().toLowerCase();if($==="multipart/form-data"||$==="application/x-www-form-urlencoded")return gix(x,{all:A,dot:w});return{}};async function gix(x,B){let A=Mu(x)?x.headers:x.raw.headers,w=await x.arrayBuffer(),f=fY0(w,A.get("Content-Type")||"");if(!Mu(x))x.bodyCache.formData=f;let D=await f;if(D)return Tix(D,B);return{}}function Tix(x,B){let A=Object.create(null);if(x.forEach((w,f)=>{if(!(B.all||f.endsWith("[]")))A[f]=w;else pix(A,f,w)}),B.dot)Object.entries(A).forEach(([w,f])=>{if(w.includes("."))uix(A,w,f),delete A[w]});return A}var pix=(x,B,A)=>{if(x[B]!==void 0)if(Array.isArray(x[B]))x[B].push(A);else x[B]=[x[B],A];else if(!B.endsWith("[]"))x[B]=A;else x[B]=[A]},uix=(x,B,A)=>{if(/(?:^|\.)__proto__\./.test(B))return;let w=x,f=B.split(".");f.forEach((D,$)=>{if($===f.length-1)w[D]=A;else{if(!w[D]||typeof w[D]!=="object"||Array.isArray(w[D])||w[D]instanceof File)w[D]=Object.create(null);w=w[D]}})};var Nu=(x)=>{let B=x.split("/");if(B[0]==="")B.shift();return B},$Y0=(x)=>{let{groups:B,path:A}=Six(x),w=Nu(A);return iix(w,B)},Six=(x)=>{let B=[];return x=x.replace(/\{[^}]+\}/g,(A,w)=>{let f=`@${w}`;return B.push([f,A]),f}),{groups:B,path:x}},iix=(x,B)=>{for(let A=B.length-1;A>=0;A--){let[w]=B[A];for(let f=x.length-1;f>=0;f--)if(x[f].includes(w)){x[f]=x[f].replace(w,B[A][1]);break}}return x},bL={},ZY0=(x,B)=>{if(x==="*")return"*";let A=x.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);if(A){let w=`${x}#${B}`;if(!bL[w])if(A[2])bL[w]=B&&B[0]!==":"&&B[0]!=="*"?[w,A[1],new RegExp(`^${A[2]}(?=/${B})`)]:[x,A[1],new RegExp(`^${A[2]}$`)];else bL[w]=[x,A[1],!0];return bL[w]}return null},VL=(x,B)=>{try{return B(x)}catch{return x.replace(/(?:%[0-9A-Fa-f]{2})+/g,(A)=>{try{return B(A)}catch{return A}})}},Iu=(x)=>VL(x,decodeURI),Ou=(x)=>{let B=x.url,A=B.indexOf("/",B.indexOf(":")+4),w=A;for(;w<B.length;w++){let f=B.charCodeAt(w);if(f===37){let D=B.indexOf("?",w),$=B.indexOf("#",w),Z=D===-1?$===-1?void 0:$:$===-1?D:Math.min(D,$),Q=B.slice(A,Z);return Iu(Q.includes("%25")?Q.replace(/%25/g,"%2525"):Q)}else if(f===63||f===35)break}return B.slice(A,w)};var QY0=(x)=>{let B=Ou(x);return B.length>1&&B.at(-1)==="/"?B.slice(0,-1):B},uD=(x,B,...A)=>{if(A.length)B=uD(B,...A);return`${x?.[0]==="/"?"":"/"}${x}${B==="/"?"":`${x?.at(-1)==="/"?"":"/"}${B?.[0]==="/"?B.slice(1):B}`}`},UL=(x)=>{if(x.charCodeAt(x.length-1)!==63||!x.includes(":"))return null;let B=x.split("/"),A=[],w="";return B.forEach((f)=>{if(f!==""&&!/\:/.test(f))w+="/"+f;else if(/\:/.test(f))if(/\?/.test(f)){if(A.length===0&&w==="")A.push("/");else A.push(w);let D=f.replace("?","");w+="/"+D,A.push(w)}else w+="/"+f}),A.filter((f,D,$)=>$.indexOf(f)===D)},vu=(x)=>{if(!/[%+]/.test(x))return x;if(x.indexOf("+")!==-1)x=x.replace(/\+/g," ");return x.indexOf("%")!==-1?VL(x,hu):x},XY0=(x,B,A)=>{let w;if(!A&&B&&!/[%+]/.test(B)){let $=x.indexOf("?",8);if($===-1)return;if(!x.startsWith(B,$+1))$=x.indexOf(`&${B}`,$+1);while($!==-1){let Z=x.charCodeAt($+B.length+1);if(Z===61){let Q=$+B.length+2,Y=x.indexOf("&",Q);return vu(x.slice(Q,Y===-1?void 0:Y))}else if(Z==38||isNaN(Z))return"";$=x.indexOf(`&${B}`,$+1)}if(w=/[%+]/.test(x),!w)return}let f={};w??=/[%+]/.test(x);let D=x.indexOf("?",8);while(D!==-1){let $=x.indexOf("&",D+1),Z=x.indexOf("=",D);if(Z>$&&$!==-1)Z=-1;let Q=x.slice(D+1,Z===-1?$===-1?void 0:$:Z);if(w)Q=vu(Q);if(D=$,Q==="")continue;let Y;if(Z===-1)Y="";else if(Y=x.slice(Z+1,$===-1?void 0:$),w)Y=vu(Y);if(A){if(!(f[Q]&&Array.isArray(f[Q])))f[Q]=[];f[Q].push(Y)}else f[Q]??=Y}return B?f[B]:f},YY0=XY0,WY0=(x,B)=>{return XY0(x,B,!0)},hu=decodeURIComponent;var HY0=(x)=>VL(x,hu),FY0=class{raw;#x;#B;routeIndex=0;path;bodyCache={};constructor(x,B="/",A=[[]]){this.raw=x,this.path=B,this.#B=A,this.#x={}}param(x){return x?this.#A(x):this.#D()}#A(x){let B=this.#B[0][this.routeIndex][1][x],A=this.#f(B);return A&&/\%/.test(A)?HY0(A):A}#D(){let x={},B=Object.keys(this.#B[0][this.routeIndex][1]);for(let A of B){let w=this.#f(this.#B[0][this.routeIndex][1][A]);if(w!==void 0)x[A]=/\%/.test(w)?HY0(w):w}return x}#f(x){return this.#B[1]?this.#B[1][x]:x}query(x){return YY0(this.url,x)}queries(x){return WY0(this.url,x)}header(x){if(x)return this.raw.headers.get(x)??void 0;let B={};return this.raw.headers.forEach((A,w)=>{B[w]=A}),B}async parseBody(x){return DY0(this,x)}#w=(x)=>{let{bodyCache:B,raw:A}=this,w=B[x];if(w)return w;let f=Object.keys(B)[0];if(f)return B[f].then((D)=>{if(f==="json")D=JSON.stringify(D);return new Response(D)[x]()});return B[x]=A[x]()};json(){return this.#w("text").then((x)=>JSON.parse(x))}text(){return this.#w("text")}arrayBuffer(){return this.#w("arrayBuffer")}bytes(){return this.#w("arrayBuffer").then((x)=>new Uint8Array(x))}blob(){return this.#w("blob")}formData(){return this.#w("formData")}addValidatedData(x,B){this.#x[x]=B}valid(x){return this.#x[x]}get url(){return this.raw.url}get method(){return this.raw.method}get[wY0](){return this.#B}get matchedRoutes(){return this.#B[0].map(([[,x]])=>x)}get routePath(){return this.#B[0].map(([[,x]])=>x)[this.routeIndex].path}};var KY0={Stringify:1,BeforeStream:2,Stream:3},qY0=(x,B)=>{let A=new String(x);return A.isEscaped=!0,A.callbacks=B,A};var Ru=async(x,B,A,w,f)=>{if(typeof x==="object"&&!(x instanceof String)){if(!(x instanceof Promise))x=x.toString();if(x instanceof Promise)x=await x}let D=x.callbacks;if(!D?.length)return Promise.resolve(x);if(f)f[0]+=x;else f=[x];let $=Promise.all(D.map((Z)=>Z({phase:B,buffer:f,context:w}))).then((Z)=>Promise.all(Z.filter(Boolean).map((Q)=>Ru(Q,B,!1,w,f))).then(()=>f[0]));if(A)return qY0(await $,D);else return $};var lix="text/plain; charset=UTF-8",yu=(x,B)=>{return{"Content-Type":x,...B}},JV=(x,B)=>new Response(x,B),mu=class{#x;#B;env={};#A;finalized=!1;error;#D;#f;#w;#Y;#Q;#X;#Z;#W;#H;constructor(x,B){if(this.#x=x,B)this.#f=B.executionCtx,this.env=B.env,this.#X=B.notFoundHandler,this.#H=B.path,this.#W=B.matchResult}get req(){return this.#B??=new FY0(this.#x,this.#H,this.#W),this.#B}get event(){if(this.#f&&"respondWith"in this.#f)return this.#f;else throw Error("This context has no FetchEvent")}get executionCtx(){if(this.#f)return this.#f;else throw Error("This context has no ExecutionContext")}get res(){return this.#w||=JV(null,{headers:this.#Z??=new Headers})}set res(x){if(this.#w&&x){x=JV(x.body,x);for(let[B,A]of this.#w.headers.entries()){if(B==="content-type")continue;if(B==="set-cookie"){let w=this.#w.headers.getSetCookie();x.headers.delete("set-cookie");for(let f of w)x.headers.append("set-cookie",f)}else x.headers.set(B,A)}}this.#w=x,this.finalized=!0}render=(...x)=>{return this.#Q??=(B)=>this.html(B),this.#Q(...x)};setLayout=(x)=>this.#Y=x;getLayout=()=>this.#Y;setRenderer=(x)=>{this.#Q=x};header=(x,B,A)=>{if(this.finalized)this.#w=JV(this.#w.body,this.#w);let w=this.#w?this.#w.headers:this.#Z??=new Headers;if(B===void 0)w.delete(x);else if(A?.append)w.append(x,B);else w.set(x,B)};status=(x)=>{this.#D=x};set=(x,B)=>{this.#A??=new Map,this.#A.set(x,B)};get=(x)=>{return this.#A?this.#A.get(x):void 0};get var(){if(!this.#A)return{};return Object.fromEntries(this.#A)}#$(x,B,A){let w=this.#w?new Headers(this.#w.headers):this.#Z??new Headers;if(typeof B==="object"&&"headers"in B){let D=B.headers instanceof Headers?B.headers:new Headers(B.headers);for(let[$,Z]of D)if($.toLowerCase()==="set-cookie")w.append($,Z);else w.set($,Z)}if(A)for(let[D,$]of Object.entries(A))if(typeof $==="string")w.set(D,$);else{w.delete(D);for(let Z of $)w.append(D,Z)}let f=typeof B==="number"?B:B?.status??this.#D;return JV(x,{status:f,headers:w})}newResponse=(...x)=>this.#$(...x);body=(x,B,A)=>this.#$(x,B,A);text=(x,B,A)=>{return!this.#Z&&!this.#D&&!B&&!A&&!this.finalized?new Response(x):this.#$(x,B,yu(lix,A))};json=(x,B,A)=>{return this.#$(JSON.stringify(x),B,yu("application/json",A))};html=(x,B,A)=>{let w=(f)=>this.#$(f,B,yu("text/html; charset=UTF-8",A));return typeof x==="object"?Ru(x,KY0.Stringify,!1,{}).then(w):w(x)};redirect=(x,B)=>{let A=String(x);return this.header("Location",!/[^\x00-\xFF]/.test(A)?A:encodeURI(A)),this.newResponse(null,B??302)};notFound=()=>{return this.#X??=()=>JV(),this.#X(this)}};var P9="ALL",zY0="all",bY0=["get","post","put","delete","options","patch"],GL="Can not add a route since the matcher is already built.",EL=class extends Error{};var Cu="__COMPOSED_HANDLER";var nix=(x)=>{return x.text("404 Not Found",404)},VY0=(x,B)=>{if("getResponse"in x){let A=x.getResponse();return B.newResponse(A.body,A)}return console.error(x),B.text("Internal Server Error",500)},UY0=class x{get;post;put;delete;options;patch;all;on;use;router;getPath;_basePath="/";#x="/";routes=[];constructor(B={}){[...bY0,zY0].forEach((D)=>{this[D]=($,...Z)=>{if(typeof $==="string")this.#x=$;else this.#D(D,this.#x,$);return Z.forEach((Q)=>{this.#D(D,this.#x,Q)}),this}}),this.on=(D,$,...Z)=>{for(let Q of[$].flat()){this.#x=Q;for(let Y of[D].flat())Z.map((W)=>{this.#D(Y.toUpperCase(),this.#x,W)})}return this},this.use=(D,...$)=>{if(typeof D==="string")this.#x=D;else this.#x="*",$.unshift(D);return $.forEach((Z)=>{this.#D(P9,this.#x,Z)}),this};let{strict:w,...f}=B;Object.assign(this,f),this.getPath=w??!0?B.getPath??Ou:QY0}#B(){let B=new x({router:this.router,getPath:this.getPath});return B.errorHandler=this.errorHandler,B.#A=this.#A,B.routes=this.routes,B}#A=nix;errorHandler=VY0;route(B,A){let w=this.basePath(B);return A.routes.map((f)=>{let D;if(A.errorHandler===VY0)D=f.handler;else D=async($,Z)=>(await ku([],A.errorHandler)($,()=>f.handler($,Z))).res,D[Cu]=f.handler;w.#D(f.method,f.path,D,f.basePath)}),this}basePath(B){let A=this.#B();return A._basePath=uD(this._basePath,B),A}onError=(B)=>{return this.errorHandler=B,this};notFound=(B)=>{return this.#A=B,this};mount(B,A,w){let f,D;if(w)if(typeof w==="function")D=w;else if(D=w.optionHandler,w.replaceRequest===!1)f=(Q)=>Q;else f=w.replaceRequest;let $=D?(Q)=>{let Y=D(Q);return Array.isArray(Y)?Y:[Y]}:(Q)=>{let Y=void 0;try{Y=Q.executionCtx}catch{}return[Q.env,Y]};f||=(()=>{let Q=uD(this._basePath,B),Y=Q==="/"?0:Q.length;return(W)=>{let H=new URL(W.url);return H.pathname=this.getPath(W).slice(Y)||"/",new Request(H,W)}})();let Z=async(Q,Y)=>{let W=await A(f(Q.req.raw),...$(Q));if(W)return W;await Y()};return this.#D(P9,uD(B,"*"),Z),this}#D(B,A,w,f){B=B.toUpperCase(),A=uD(this._basePath,A);let D={basePath:f!==void 0?uD(this._basePath,f):this._basePath,path:A,method:B,handler:w};this.router.add(B,A,[w,D]),this.routes.push(D)}#f(B,A){if(B instanceof Error)return this.errorHandler(B,A);throw B}#w(B,A,w,f){if(f==="HEAD")return(async()=>new Response(null,await this.#w(B,A,w,"GET")))();let D=this.getPath(B,{env:w}),$=this.router.match(f,D),Z=new mu(B,{path:D,matchResult:$,env:w,executionCtx:A,notFoundHandler:this.#A});if($[0].length===1){let Y;try{Y=$[0][0][0][0](Z,async()=>{Z.res=await this.#A(Z)})}catch(W){return this.#f(W,Z)}return Y instanceof Promise?Y.then((W)=>W||(Z.finalized?Z.res:this.#A(Z))).catch((W)=>this.#f(W,Z)):Y??this.#A(Z)}let Q=ku($[0],this.errorHandler,this.#A);return(async()=>{try{let Y=await Q(Z);if(!Y.finalized)throw Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");return Y.res}catch(Y){return this.#f(Y,Z)}})()}fetch=(B,...A)=>{return this.#w(B,A[1],A[0],B.method)};request=(B,A,w,f)=>{if(B instanceof Request)return this.fetch(A?new Request(B,A):B,w,f);return B=B.toString(),this.fetch(new Request(/^https?:\/\//.test(B)?B:`http://localhost${uD("/",B)}`,A),w,f)};fire=()=>{addEventListener("fetch",(B)=>{B.respondWith(this.#w(B.request,B,void 0,B.request.method))})}};var LV=[];function jL(x,B){let A=this.buildAllMatchers(),w=(f,D)=>{let $=A[f]||A[P9],Z=$[2][D];if(Z)return Z;let Q=D.match($[0]);if(!Q)return[[],LV];let Y=Q.indexOf("",1);return[$[1][Y],Q]};return this.match=w,w(x,B)}var _L="[^/]+",kV=".*",MV="(?:|/.*)",EQ=Symbol(),dix=new Set(".\\+*[^]$()");function aix(x,B){if(x.length===1)return B.length===1?x<B?-1:1:-1;if(B.length===1)return 1;if(x===kV||x===MV)return 1;else if(B===kV||B===MV)return-1;if(x===_L)return 1;else if(B===_L)return-1;return x.length===B.length?x<B?-1:1:B.length-x.length}var GY0=class x{#x;#B;#A=Object.create(null);insert(B,A,w,f,D){if(B.length===0){if(this.#x!==void 0)throw EQ;if(D)return;this.#x=A;return}let[$,...Z]=B,Q=$==="*"?Z.length===0?["","",kV]:["","",_L]:$==="/*"?["","",MV]:$.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/),Y;if(Q){let W=Q[1],H=Q[2]||_L;if(W&&Q[2]){if(H===".*")throw EQ;if(H=H.replace(/^\((?!\?:)(?=[^)]+\)$)/,"(?:"),/\((?!\?:)/.test(H))throw EQ}if(Y=this.#A[H],!Y){if(Object.keys(this.#A).some((F)=>F!==kV&&F!==MV))throw EQ;if(D)return;if(Y=this.#A[H]=new x,W!=="")Y.#B=f.varIndex++}if(!D&&W!=="")w.push([W,Y.#B])}else if(Y=this.#A[$],!Y){if(Object.keys(this.#A).some((W)=>W.length>1&&W!==kV&&W!==MV))throw EQ;if(D)return;Y=this.#A[$]=new x}Y.insert(Z,A,w,f,D)}buildRegExpStr(){let A=Object.keys(this.#A).sort(aix).map((w)=>{let f=this.#A[w];return(typeof f.#B==="number"?`(${w})@${f.#B}`:dix.has(w)?`\\${w}`:w)+f.buildRegExpStr()});if(typeof this.#x==="number")A.unshift(`#${this.#x}`);if(A.length===0)return"";if(A.length===1)return A[0];return"(?:"+A.join("|")+")"}};var EY0=class{#x={varIndex:0};#B=new GY0;insert(x,B,A){let w=[],f=[];for(let $=0;;){let Z=!1;if(x=x.replace(/\{[^}]+\}/g,(Q)=>{let Y=`@\\${$}`;return f[$]=[Y,Q],$++,Z=!0,Y}),!Z)break}let D=x.match(/(?::[^\/]+)|(?:\/\*$)|./g)||[];for(let $=f.length-1;$>=0;$--){let[Z]=f[$];for(let Q=D.length-1;Q>=0;Q--)if(D[Q].indexOf(Z)!==-1){D[Q]=D[Q].replace(Z,f[$][1]);break}}return this.#B.insert(D,B,w,this.#x,A),w}buildRegExp(){let x=this.#B.buildRegExpStr();if(x==="")return[/^$/,[],[]];let B=0,A=[],w=[];return x=x.replace(/#(\d+)|@(\d+)|\.\*\$/g,(f,D,$)=>{if(D!==void 0)return A[++B]=Number(D),"$()";if($!==void 0)return w[Number($)]=++B,"";return""}),[new RegExp(`^${x}`),A,w]}};var six=[/^$/,[],Object.create(null)],jY0=Object.create(null);function _Y0(x){return jY0[x]??=new RegExp(x==="*"?"":`^${x.replace(/\/\*$|([.\\+*[^\]$()])/g,(B,A)=>A?`\\${A}`:"(?:|/.*)")}$`)}function rix(){jY0=Object.create(null)}function oix(x){let B=new EY0,A=[];if(x.length===0)return six;let w=x.map((Y)=>[!/\*|\/:/.test(Y[0]),...Y]).sort(([Y,W],[H,F])=>Y?1:H?-1:W.length-F.length),f=Object.create(null);for(let Y=0,W=-1,H=w.length;Y<H;Y++){let[F,K,q]=w[Y];if(F)f[K]=[q.map(([b])=>[b,Object.create(null)]),LV];else W++;let V;try{V=B.insert(K,W,F)}catch(b){throw b===EQ?new EL(K):b}if(F)continue;A[W]=q.map(([b,G])=>{let E=Object.create(null);G-=1;for(;G>=0;G--){let[_,L]=V[G];E[_]=L}return[b,E]})}let[D,$,Z]=B.buildRegExp();for(let Y=0,W=A.length;Y<W;Y++)for(let H=0,F=A[Y].length;H<F;H++){let K=A[Y][H]?.[1];if(!K)continue;let q=Object.keys(K);for(let V=0,b=q.length;V<b;V++)K[q[V]]=Z[K[q[V]]]}let Q=[];for(let Y in $)Q[Y]=A[$[Y]];return[D,Q,f]}function yH(x,B){if(!x)return;for(let A of Object.keys(x).sort((w,f)=>f.length-w.length))if(_Y0(A).test(B))return[...x[A]];return}var PL=class{name="RegExpRouter";#x;#B;constructor(){this.#x={[P9]:Object.create(null)},this.#B={[P9]:Object.create(null)}}add(x,B,A){let w=this.#x,f=this.#B;if(!w||!f)throw Error(GL);if(!w[x])[w,f].forEach((Z)=>{Z[x]=Object.create(null),Object.keys(Z[P9]).forEach((Q)=>{Z[x][Q]=[...Z[P9][Q]]})});if(B==="/*")B="*";let D=(B.match(/\/:/g)||[]).length;if(/\*$/.test(B)){let Z=_Y0(B);if(x===P9)Object.keys(w).forEach((Q)=>{w[Q][B]||=yH(w[Q],B)||yH(w[P9],B)||[]});else w[x][B]||=yH(w[x],B)||yH(w[P9],B)||[];Object.keys(w).forEach((Q)=>{if(x===P9||x===Q)Object.keys(w[Q]).forEach((Y)=>{Z.test(Y)&&w[Q][Y].push([A,D])})}),Object.keys(f).forEach((Q)=>{if(x===P9||x===Q)Object.keys(f[Q]).forEach((Y)=>Z.test(Y)&&f[Q][Y].push([A,D]))});return}let $=UL(B)||[B];for(let Z=0,Q=$.length;Z<Q;Z++){let Y=$[Z];Object.keys(f).forEach((W)=>{if(x===P9||x===W)f[W][Y]||=[...yH(w[W],Y)||yH(w[P9],Y)||[]],f[W][Y].push([A,D-Q+Z+1])})}}match=jL;buildAllMatchers(){let x=Object.create(null);return Object.keys(this.#B).concat(Object.keys(this.#x)).forEach((B)=>{x[B]||=this.#A(B)}),this.#x=this.#B=void 0,rix(),x}#A(x){let B=[],A=x===P9;if([this.#x,this.#B].forEach((w)=>{let f=w[x]?Object.keys(w[x]).map((D)=>[D,w[x][D]]):[];if(f.length!==0)A||=!0,B.push(...f);else if(x!==P9)B.push(...Object.keys(w[P9]).map((D)=>[D,w[P9][D]]))}),!A)return null;else return oix(B)}};var tix=class{name="PreparedRegExpRouter";#x;#B;constructor(x,B){this.#x=x,this.#B=B}#A(x,B){let A=this.#x[x];A[1].forEach((w)=>w&&w.push(B)),Object.values(A[2]).forEach((w)=>w[0].push(B))}#D(x,B,A,w,f){let D=this.#x[x];if(!f)D[2][B][0].push([A,{}]);else w.forEach(($)=>{if(typeof $==="number")D[1][$].push([A,f]);else D[2][$||B][0].push([A,f])})}add(x,B,A){if(!this.#x[x]){let f=this.#x[P9],D={};for(let $ in f[2])D[$]=[f[2][$][0].slice(),LV];this.#x[x]=[f[0],f[1].map(($)=>Array.isArray($)?$.slice():0),D]}if(B==="/*"||B==="*"){let f=[A,{}];if(x===P9)for(let D in this.#x)this.#A(D,f);else this.#A(x,f);return}let w=this.#B[B];if(!w)throw Error(`Path ${B} is not registered`);for(let[f,D]of w)if(x===P9)for(let $ in this.#x)this.#D($,B,A,f,D);else this.#D(x,B,A,f,D)}buildAllMatchers(){return this.#x}match=jL};var cu=class{name="SmartRouter";#x=[];#B=[];constructor(x){this.#x=x.routers}add(x,B,A){if(!this.#B)throw Error(GL);this.#B.push([x,B,A])}match(x,B){if(!this.#B)throw Error("Fatal error");let A=this.#x,w=this.#B,f=A.length,D=0,$;for(;D<f;D++){let Z=A[D];try{for(let Q=0,Y=w.length;Q<Y;Q++)Z.add(...w[Q]);$=Z.match(x,B)}catch(Q){if(Q instanceof EL)continue;throw Q}this.match=Z.match.bind(Z),this.#x=[Z],this.#B=void 0;break}if(D===f)throw Error("Fatal error");return this.name=`SmartRouter + ${this.activeRouter.name}`,$}get activeRouter(){if(this.#B||this.#x.length!==1)throw Error("No active router has been determined yet.");return this.#x[0]}};var vV=Object.create(null),eix=(x)=>{for(let B in x)return!0;return!1},PY0=class x{#x;#B;#A;#D=0;#f=vV;constructor(B,A,w){if(this.#B=w||Object.create(null),this.#x=[],B&&A){let f=Object.create(null);f[B]={handler:A,possibleKeys:[],score:0},this.#x=[f]}this.#A=[]}insert(B,A,w){this.#D=++this.#D;let f=this,D=$Y0(A),$=[];for(let Z=0,Q=D.length;Z<Q;Z++){let Y=D[Z],W=D[Z+1],H=ZY0(Y,W),F=Array.isArray(H)?H[0]:Y;if(F in f.#B){if(f=f.#B[F],H)$.push(H[1]);continue}if(f.#B[F]=new x,H)f.#A.push(H),$.push(H[1]);f=f.#B[F]}return f.#x.push({[B]:{handler:w,possibleKeys:$.filter((Z,Q,Y)=>Y.indexOf(Z)===Q),score:this.#D}}),f}#w(B,A,w,f,D){for(let $=0,Z=A.#x.length;$<Z;$++){let Q=A.#x[$],Y=Q[w]||Q[P9],W={};if(Y!==void 0){if(Y.params=Object.create(null),B.push(Y),f!==vV||D&&D!==vV)for(let H=0,F=Y.possibleKeys.length;H<F;H++){let K=Y.possibleKeys[H],q=W[Y.score];Y.params[K]=D?.[K]&&!q?D[K]:f[K]??D?.[K],W[Y.score]=!0}}}}search(B,A){let w=[];this.#f=vV;let D=[this],$=Nu(A),Z=[],Q=$.length,Y=null;for(let W=0;W<Q;W++){let H=$[W],F=W===Q-1,K=[];for(let V=0,b=D.length;V<b;V++){let G=D[V],E=G.#B[H];if(E)if(E.#f=G.#f,F){if(E.#B["*"])this.#w(w,E.#B["*"],B,G.#f);this.#w(w,E,B,G.#f)}else K.push(E);for(let _=0,L=G.#A.length;_<L;_++){let N=G.#A[_],y=G.#f===vV?{}:{...G.#f};if(N==="*"){let B0=G.#B["*"];if(B0)this.#w(w,B0,B,G.#f),B0.#f=y,K.push(B0);continue}let[c,n,R]=N;if(!H&&!(R instanceof RegExp))continue;let M=G.#B[c];if(R instanceof RegExp){if(Y===null){Y=Array(Q);let I0=A[0]==="/"?1:0;for(let J0=0;J0<Q;J0++)Y[J0]=I0,I0+=$[J0].length+1}let B0=A.substring(Y[W]),G0=R.exec(B0);if(G0){if(y[n]=G0[0],this.#w(w,M,B,G.#f,y),eix(M.#B)){M.#f=y;let I0=G0[0].match(/\//)?.length??0;(Z[I0]||=[]).push(M)}continue}}if(R===!0||R.test(H))if(y[n]=H,F){if(this.#w(w,M,B,y,G.#f),M.#B["*"])this.#w(w,M.#B["*"],B,y,G.#f)}else M.#f=y,K.push(M)}}let q=Z.shift();D=q?K.concat(q):K}if(w.length>1)w.sort((W,H)=>{return W.score-H.score});return[w.map(({handler:W,params:H})=>[W,H])]}};var gu=class{name="TrieRouter";#x;constructor(){this.#x=new PY0}add(x,B,A){let w=UL(B);if(w){for(let f=0,D=w.length;f<D;f++)this.#x.insert(x,w[f],A);return}this.#x.insert(x,B,A)}match(x,B){return this.#x.search(x,B)}};var mH=class extends UY0{constructor(x={}){super(x);this.router=x.router??new cu({routers:[new PL,new gu]})}};var JY0=X.object({port:X.number().default(3334),organization:X.string().optional(),requestTimeoutMs:X.number().positive().default(30000),streamIdleTimeoutMs:X.number().positive().default(60000),maxNetworkAttempts:X.number().int().positive().default(2)}).strict();function xlx(x,B){return`${x.name} is ${B.name}'s ${x.role}. Its purpose is: ${x.purpose}.`}function kY0(x){let{character:B,profile:A,version:w,domain:f,organization:D,tools:$}=x,Q=`${x.baseUrl??(f?`https://${f}`:"http://localhost:8080")}/a2a`,Y=x.skills&&x.skills.length>0?x.skills.map((F)=>({id:F.name.toLowerCase().replace(/\s+/g,"-"),name:F.name,description:F.description,tags:F.tags,examples:F.examples})):$.map((F)=>({id:F.name,name:F.name,description:F.description,tags:[],examples:[]})),W={name:A.name};if(x.profileKind)W.kind=x.profileKind.kind,W.category=x.profileKind.category;if(A.description)W.description=A.description;if(D)W.organization=D;let H=[{uri:LY0,description:"Anchor identity for this brain",params:W}];return{name:B.name,description:xlx(B,A),url:Q,version:w,protocolVersion:"0.2.2",capabilities:{streaming:!0,pushNotifications:!1,extensions:H},skills:Y,defaultInputModes:["text/plain"],defaultOutputModes:["text/plain"],...D&&{provider:{organization:D,url:Q}},...x.authEnabled&&{securitySchemes:{bearerAuth:{type:"http",scheme:"bearer"}},security:[{bearerAuth:[]}]}}}var Blx=X.object({name:X.string(),url:X.string(),status:X.string()}),Alx=X.object({name:X.string(),url:X.string()}),Rx6=X.object({agents:X.array(Alx)});async function MY0(x){if(!x.hasEntityType("agent"))return{agents:[]};return{agents:(await x.listEntities({entityType:"agent",options:{filter:{visibilityScope:"public"}}})).map((w)=>Blx.safeParse(w.metadata)).filter((w)=>w.success).map((w)=>w.data).filter((w)=>w.status==="approved").map(({name:w,url:f})=>({name:w,url:f})).sort((w,f)=>w.name.localeCompare(f.name))}}var NV=new Set(["completed","failed","canceled","rejected"]);class Tu{tasks=new Map;clientMessageIndex=new Map;ttlMs;processingTimeoutMs;constructor(x=3600000,B=300000){this.ttlMs=x,this.processingTimeoutMs=B}evictExpired(){for(let[B,A]of this.tasks)if(this.isOverdueWorking(A))this.updateState(B,"failed","Processing timed out");let x=Date.now();for(let[B,A]of this.tasks)if(NV.has(A.task.status.state)&&x-new Date(A.updatedAt).getTime()>=this.ttlMs)this.removeTask(B)}clientMessageKey(x,B){return JSON.stringify([x,B])}removeTask(x){let B=this.tasks.get(x);if(!B)return!1;if(B.clientMessageId)this.clientMessageIndex.delete(this.clientMessageKey(B.callerDomain,B.clientMessageId));return this.tasks.delete(x)}isOverdueWorking(x){return x.task.status.state==="working"&&x.workingStartedAt!==void 0&&Date.now()-new Date(x.workingStartedAt).getTime()>=this.processingTimeoutMs}createTask(x,B,A={}){this.evictExpired();let w=crypto.randomUUID(),f=B??crypto.randomUUID(),D=new Date().toISOString(),$=A.callerDomain??null,Z=A.messageId,Q={kind:"message",messageId:Z??crypto.randomUUID(),role:"user",parts:[{kind:"text",text:x}],contextId:f,taskId:w},W={task:{id:w,contextId:f,kind:"task",status:{state:"submitted",timestamp:D},history:[Q]},conversationId:`a2a:${w}`,createdAt:D,updatedAt:D,callerDomain:$,...Z?{clientMessageId:Z}:{}};if(this.tasks.set(w,W),Z)this.clientMessageIndex.set(this.clientMessageKey($,Z),w);return W}getTask(x){return this.tasks.get(x)}getTaskByClientMessageId(x,B){if(!B)return;let A=this.clientMessageIndex.get(this.clientMessageKey(x,B));return A?this.tasks.get(A):void 0}updateState(x,B,A){let w=this.tasks.get(x);if(!w)return;let f=new Date().toISOString();if(w.task.status={state:B,timestamp:f},w.updatedAt=f,B==="working")w.workingStartedAt=f;if(A){let D={kind:"message",messageId:crypto.randomUUID(),role:"agent",parts:[{kind:"text",text:A}],contextId:w.task.contextId,taskId:x};w.task.status.message=D,w.task.history??=[],w.task.history.push(D)}return w}addArtifact(x,B,A){let w=this.tasks.get(x);if(!w)return;return w.task.artifacts??=[],w.task.artifacts.push({artifactId:crypto.randomUUID(),name:B,parts:A}),w.updatedAt=new Date().toISOString(),w}getTaskWithHistory(x,B){let A=this.tasks.get(x);if(!A)return;if(this.isOverdueWorking(A))this.updateState(x,"failed","Processing timed out");if(B===void 0||!A.task.history)return A.task;return{...A.task,history:A.task.history.slice(-B)}}deleteTask(x){return this.removeTask(x)}get size(){return this.tasks.size}}class pu{scope;fibers;active=new Map;clock;closePromise=null;closed=!1;constructor(x={}){this.clock=x.clock,this.scope=H0.runSync(y9.make()),this.fibers=H0.runSync(y9.extend(QB.make(),this.scope))}start(x,B,A){if(this.closed)return A.onCancel(),!1;if(this.active.has(x))throw Error(`A2A task is already active: ${x}`);let w={controller:new AbortController,onCancel:A.onCancel,canceled:!1};this.active.set(x,w);let f=H0.tryPromise({try:(W)=>B(AbortSignal.any([W,w.controller.signal])),catch:()=>{return}}).pipe(H0.catchAll(()=>H0.void)),D=A.heartbeat,$=D?H0.scoped(H0.gen(function*(){let W=H0.sleep(D.intervalMs).pipe(H0.andThen(H0.sync(()=>D.tick())),H0.forever);yield*H0.forkScoped(W),yield*f})):f,Q=(this.clock?H0.withClock($,this.clock):$).pipe(H0.ensuring(H0.sync(()=>{if(this.active.get(x)===w)this.active.delete(x)}))),Y=H0.runFork(Q);return w.fiber=Y,QB.unsafeSet(this.fibers,x,Y),!0}cancel(x,B=Error("A2A task canceled")){let A=this.active.get(x);if(!A)return!1;if(!A.canceled)A.canceled=!0,A.onCancel(),A.controller.abort(B);if(A.fiber)H0.runSync(jQ.interruptFork(A.fiber));return!0}close(){return this.closed=!0,this.closePromise??=this.closeSupervisor(),this.closePromise}async closeSupervisor(){for(let B of[...this.active.keys()])this.cancel(B,Error("A2A interface stopped"));let x=await H0.runPromiseExit(y9.close(this.scope,f5.void));if(f5.isFailure(x))throw _4.squash(x.cause)}}var wlx=15000,vY0=X.array(X.object({kind:X.string(),text:X.string().optional(),data:X.record(X.string(),X.unknown()).optional()})),flx=X.object({message:X.object({kind:X.literal("message").optional(),messageId:X.string().optional(),role:X.enum(["user","agent"]).optional(),parts:vY0,contextId:X.string().optional(),taskId:X.string().optional()}),configuration:X.object({historyLength:X.number().optional()}).optional()}),NY0=X.object({id:X.string(),historyLength:X.number().optional()});function JL(x,B){return{jsonrpc:"2.0",id:x,result:B}}function XB(x,B,A){return{jsonrpc:"2.0",id:x,error:{code:B,message:A}}}var IY0=X.object({jsonrpc:X.string(),id:X.union([X.string(),X.number()]),method:X.string(),params:X.record(X.string(),X.unknown()).optional()});async function OY0(x,B){let{id:A,method:w,params:f}=x;switch(w){case"message/send":return Dlx(A,f??{},B);case"tasks/get":return Qlx(A,f??{},B);case"tasks/cancel":return Xlx(A,f??{},B);default:return XB(A,-32601,`Method not found: ${w}`)}}async function Dlx(x,B,A){let w=flx.safeParse(B);if(!w.success)return XB(x,-32602,`Invalid params: ${w.error.message}`);let f=w.data.message.parts.filter((K)=>K.kind==="text"&&typeof K.text==="string");if(f.length===0)return XB(x,-32602,"Message must contain at least one text part");let D=f.map((K)=>K.text).join(`
864
864
  `),$=w.data.message.contextId,Z=A.callerDomain??null,Q=Z?w.data.message.messageId:void 0,Y=A.taskManager.getTaskByClientMessageId(Z,Q);if(Y)return JL(x,Y.task);let W=A.taskManager.createTask(D,$,{callerDomain:Z,messageId:Q}),H=W.task.id;A.taskManager.updateState(H,"working"),$lx(H,D,W.conversationId,A);let F=A.taskManager.getTask(H);if(!F)return XB(x,-32603,"Internal error: task disappeared");return JL(x,F.task)}function $lx(x,B,A,w){w.turnSupervisor.start(x,async(f)=>{try{let D=await w.agentService.chat(B,A,{userPermissionLevel:w.callerPermissionLevel,isAnchor:w.callerIsAnchor??!1,interfaceType:"a2a"},f);if(f.aborted||hY0(x,w.taskManager))return;w.taskManager.updateState(x,"completed",D.text)}catch(D){if(f.aborted)return;let $=g(D,"Unknown error");w.taskManager.updateState(x,"failed",`Error: ${$}`)}},{onCancel:()=>{RY0(x,w.taskManager)}})}function hY0(x,B){return B.getTask(x)?.task.status.state==="canceled"}function RY0(x,B){let A=B.getTask(x);if(A&&!NV.has(A.task.status.state))B.updateState(x,"canceled")}var yY0=X.object({message:X.object({kind:X.string(),messageId:X.string().optional(),parts:vY0,contextId:X.string().optional()})});function mY0(x,B,A,w={}){let f=B.parts.filter((V)=>V.kind==="text"&&typeof V.text==="string");if(f.length===0)return XB(x,-32602,"Message must contain at least one text part");let D=f.map((V)=>V.text).join(`
@@ -873,7 +873,7 @@ ${G}`)}if(w!==void 0&&D?.algorithms!==void 0){let b=D.algorithms.map((G)=>G.alg)
873
873
  `);D=Z.pop()??"";for(let Q of Z){let Y=Q.split(`
874
874
  `).find((b)=>b.startsWith("data: "));if(!Y)continue;let W;try{let b=Wlx.safeParse(JSON.parse(Y.slice(6)));if(!b.success)continue;W=b.data}catch{return await iu(w),{success:!1,error:"Malformed SSE event from remote agent"}}let H=W.result;if(!H?.final)continue;await iu(w);let F=H.status,K=F?.state??"unknown",V=(F?.message?.parts??[]).filter((b)=>b.kind==="text"&&typeof b.text==="string").map((b)=>b.text).join(`
875
875
  `)||"No response text";return{success:!0,data:{state:K,response:V}}}$=await pY0(w,B,A)}return{success:!1,error:"Stream ended without a terminal event"}}class lu extends Error{timeoutMs;constructor(x){super(`request timed out after ${x}ms`);this.timeoutMs=x,this.name="A2ARequestTimeoutError"}}class IV extends Error{timeoutMs;constructor(x){super(`A2A stream stalled waiting for final event after ${x}ms`);this.timeoutMs=x,this.name="A2AStreamIdleTimeoutError"}}async function SY0(x,B,A,w,f){return uu((D)=>x(B,{...A,signal:D}),{timeoutMs:w,onTimeout:()=>new lu(w),signal:f})}async function pY0(x,B,A){try{return await uu(()=>x.read(),{timeoutMs:B,onTimeout:()=>new IV(B),signal:A})}catch(w){if(w instanceof IV||A?.aborted)await iu(x,w);throw w}}async function iu(x,B){try{await x.cancel(B)}catch{}}function Glx(x){if(x instanceof lu||x instanceof IV)return!1;return x instanceof Error}function Su(x,B){let A=B>1?` after ${B} attempts`:"";if(x instanceof IV)return`${x.message}${A}`;let w=g(x,"Unknown network error");return`Failed to reach remote agent${A}: ${w}`}async function nu(x,B={},A={}){let w=B.fetch??globalThis.fetch,f=A.signal;f?.throwIfAborted();let D={requestTimeoutMs:B.requestTimeoutMs??Hlx,streamIdleTimeoutMs:B.streamIdleTimeoutMs??Flx,maxNetworkAttempts:B.maxNetworkAttempts??Klx},$=blx(x.agent);if(!$.ok)return{success:!1,error:$.error};let{agentId:Z}=$;if(!B.entityService)return{success:!1,error:"Agent directory is unavailable. Add the agent first, then try again."};let Q=await B.entityService.getEntity({entityType:"agent",id:Z,visibilityScope:zA("agent_call is admin-only and resolves saved remote agents at any visibility")});if(f?.throwIfAborted(),!Q){if(A.requireSaved)return{success:!1,error:`Agent ${Z} is not saved or approved.`,code:"agent_not_saved"};if(!Vlx(Z))return{success:!1,error:`Agent ${x.agent} is not an exact domain-like id and is not saved. Connect or clarify the agent first.`,code:"agent_not_saved"};let F=`https://${Z}`,K=await gY0(F,w,D.requestTimeoutMs,f);if(!K)return{success:!1,error:`Could not verify an A2A Agent Card for ${Z}. Connect/save it first if you want to add it to the directory.`,code:"agent_card_unavailable"};let q=cY0(K.url,Z);if(!q.ok)return{success:!1,error:q.error};let V=await TY0(K.url,x.message,w,B.requestSigner,D,f);if("success"in V&&V.success===!0){let b=typeof V.data==="object"&&V.data!==null?V.data:{};return{...V,data:{...b,agentCall:{mode:"one-shot",agent:Z},agentContactCandidate:{source:{kind:"url",url:$.sourceUrl??Z}}}}}return V}if(Q.metadata.status==="archived")return{success:!1,error:`Agent ${Z} is archived and cannot be contacted until it is restored and approved.`,code:"agent_archived"};if(Q.metadata.status!=="approved")return{success:!1,error:`Agent ${Z} is discovered but not approved yet. Approve it first.`,code:"agent_not_approved"};let Y=`https://${Z}`,W=await gY0(Y,w,D.requestTimeoutMs,f);if(!W)return{success:!1,error:`Could not fetch Agent Card from ${Y}`};let H=cY0(W.url,Z);if(!H.ok)return{success:!1,error:H.error};return TY0(W.url,x.message,w,B.requestSigner,D,f)}function iY0(x={}){return{name:"agent_call",description:"Call a remote A2A agent by exact domain-like target or saved local agent id. Use this when the user asks what an exact domain-like agent id has to say, asks to talk/message/contact that id, or asks that agent for its skills/capabilities. For saved agents, the tool enforces approved/not-archived status before network contact. For unsaved exact domains, the tool verifies the A2A Agent Card over HTTPS and may perform a one-shot call without saving; it returns a typed save/connect candidate after success. Use bare ids such as yeehaa.io, docs.rizom.ai, or save-it-regression.example; .example test domains are exact domain-like ids. If the user provides an HTTPS URL such as https://docs.rizom.ai/a2a, pass only the hostname docs.rizom.ai. For follow-ups to a prior exact-id call, call again with the same id so the tool revalidates current state. Never pass a full URL, a display name like Brain, or a non-HTTPS URL. If the user gives an ambiguous name, ask them to connect/save or clarify the agent first.",inputSchema:qlx,visibility:"trusted",sideEffects:"external",handler:async(B,A)=>{let w=zlx.safeParse(B);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};return nu(w.data,x,{...A.signal?{signal:A.signal}:{}})}}}var Elx=X.object({agent:X.string().trim().min(1).max(253),instruction:X.string().trim().min(1).max(2000),selection:X.string().min(1).max(8000)});function lY0(x,B){x.messaging.subscribe(CH.callRequest,async(A)=>{let w=Elx.safeParse(A.payload);if(!w.success)return{success:!1,error:"Invalid A2A call request"};let{agent:f,instruction:D,selection:$}=w.data,Z=await nu({agent:f,message:["A CMS author is asking about selected markdown.",`Instruction: ${D}`,"","Selected markdown:",$].join(`
876
- `)},B,{requireSaved:!0});if("success"in Z&&Z.success===!0)return{success:!0,data:Z.data};return{success:!1,error:"error"in Z?Z.error:"Agent call failed"}}),x.messaging.subscribe(CH.callAgents,async()=>{if(!x.entityService.hasEntityType("agent"))return{success:!0,data:{agents:[]}};return{success:!0,data:{agents:(await x.entityService.listEntities({entityType:"agent",options:{filter:{visibilityScope:zA("Admin CMS lists approved A2A contacts at any visibility")}}})).filter((f)=>f.metadata.status==="approved").map((f)=>{let D=f.metadata.name;return{id:f.id,label:typeof D==="string"&&D.length>0?D:f.id}}).sort((f,D)=>f.label.localeCompare(D.label))}}})}var du={name:"@brains/a2a",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",dependencies:{"@a2a-js/sdk":"^0.3.13","@brains/auth-service":"workspace:*","@brains/contracts":"workspace:*","@brains/http-signatures":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",hono:"^4.12.25"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},files:["src"],main:"./src/index.ts",module:"./src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};var _lx={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Signature, Signature-Input, Content-Digest, Date","X-Content-Type-Options":"nosniff"};class ML extends cH{agentCard;taskManager=new Tu;turnSupervisor=new pu;agentService;jwksResolver=new Ju;app;hasWebserver=!1;constructor(x={}){if(Object.prototype.hasOwnProperty.call(x,"trustedTokens"))throw Error("trustedTokens legacy config is no longer supported");if(Object.prototype.hasOwnProperty.call(x,"outboundTokens"))throw Error("outboundTokens legacy config is no longer supported");super("a2a",du,x,JY0)}async onRegister(x){if(await super.onRegister(x),this.hasWebserver=x.plugins.has("webserver"),this.agentService=x.agent,lY0(x,this.createClientDeps(x)),this.hasWebserver)x.endpoints.register({label:"A2A",url:"/a2a",priority:25}),x.interactions.register({id:"a2a",label:"A2A",description:"Let other agents discover and talk to this brain.",href:"/a2a",kind:"agent",priority:25}),this.logger.info("A2A interface registered",{domain:x.domain});else this.logger.info("A2A interface registered in tool-only mode",{domain:x.domain})}async onReady(x){await this.rebuildAgentCard(x)}async rebuildAgentCard(x){let B=x.identity.get(),A=x.identity.getProfile(),w=x.tools.listForPermissionLevel("public"),f;if(x.entityService.hasEntityType("skill"))try{let D=await x.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}});if(D.length>0)f=D.map(($)=>kL.safeParse($.metadata)).filter(($)=>$.success).map(($)=>$.data)}catch{}this.agentCard=kY0({character:B,profile:A,version:du.version,domain:x.domain,organization:this.config.organization,profileKind:x.profileKinds.getResolved(),tools:w,skills:f,authEnabled:!1}),this.logger.debug("Agent Card rebuilt",{skills:this.agentCard.skills.length})}getAgentCard(){return this.agentCard}async resolveCaller(x,B){let A=new URL(x.url),w=new URL(`${A.pathname}${A.search}`,s2(x)),f=await xY0({method:x.method,url:w.toString(),headers:x.headers,body:B},this.jwksResolver);if(f){let D=await X6()?.getA2APeerTrust(f.domain);return{permissionLevel:D?.keyFingerprint===f.keyFingerprint?D.grantedLevel:"public",isAnchor:this.getContext().permissions.isAnchor("a2a",f.domain),callerDomain:f.domain}}return{permissionLevel:"public",isAnchor:!1,callerDomain:null}}withCors(x){let B=new Headers(x.headers);for(let[A,w]of Object.entries(_lx))B.set(A,w);return new Response(x.body,{status:x.status,statusText:x.statusText,headers:B})}getOrCreateApp(){if(this.app)return this.app;let x=new mH;return x.get("/.well-known/agent-card.json",(B)=>{if(!this.agentCard)return this.withCors(B.json({error:"Agent Card not ready"},503));return this.withCors(B.json(this.agentCard))}),x.get("/.well-known/agent-directory.json",async(B)=>{let A=await MY0(this.getContext().entityService);return this.withCors(B.json(A))}),x.get("/a2a",(B)=>{return this.withCors(B.json({error:"Use POST with JSON-RPC 2.0 requests.",agentCard:"/.well-known/agent-card.json"},405))}),x.options("/a2a",()=>this.withCors(new Response(null,{status:204}))),x.post("/a2a",async(B)=>{if(!this.agentService)return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503));let A=await B.req.text(),w;try{w=await this.resolveCaller(B.req.raw,A)}catch{return this.withCors(B.json({error:"Invalid HTTP signature"},401))}let f;try{f=JSON.parse(A)}catch{return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null}))}let D=IY0.safeParse(f);if(!D.success)return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null}));if(D.data.method==="message/stream"){let Z=yY0.safeParse(D.data.params??{});if(!Z.success)return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${Z.error.message}`},id:D.data.id}));let Q=mY0(D.data.id,Z.data.message,{taskManager:this.taskManager,turnSupervisor:this.turnSupervisor,agentService:this.agentService,callerPermissionLevel:w.permissionLevel,callerIsAnchor:w.isAnchor,callerDomain:w.callerDomain});if("error"in Q)return this.withCors(B.json(Q));let{stream:Y}=Q;return this.withCors(new Response(Y,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}))}let $=await OY0(D.data,{taskManager:this.taskManager,turnSupervisor:this.turnSupervisor,agentService:this.agentService,callerPermissionLevel:w.permissionLevel,callerIsAnchor:w.isAnchor,callerDomain:w.callerDomain});return this.withCors(B.json($))}),this.app=x,x}getWebRoutes(){if(!this.hasWebserver)return[];let x=(B)=>Promise.resolve(this.getOrCreateApp().fetch(B));return[{path:"/.well-known/agent-card.json",method:"GET",public:!0,handler:x},{path:"/.well-known/agent-directory.json",method:"GET",public:!0,handler:x},{path:"/a2a",method:"GET",public:!0,handler:x},{path:"/a2a",method:"POST",public:!0,handler:x},{path:"/a2a",method:"OPTIONS",public:!0,handler:x}]}createRequestSigner(){let x=X6();if(!x)return;let B=x.getIssuer();if(r3(B)||new URL(B).protocol!=="https:")return;return async(A)=>{let w=await x.getA2ASigningKey();await eX0(A,w.privateJwk,w.keyId)}}createClientDeps(x){return{requestSigner:this.createRequestSigner(),requestTimeoutMs:this.config.requestTimeoutMs,streamIdleTimeoutMs:this.config.streamIdleTimeoutMs,maxNetworkAttempts:this.config.maxNetworkAttempts,entityService:x.entityService}}async getTools(){return[iY0(this.createClientDeps(this.getContext()))]}async getInstructions(){return"## Agent-to-agent calls\n- Use `agent_call` for exact domain-like agent ids (for example `yeehaa.io`, `docs.rizom.ai`, or `save-it-regression.example`). A domain-like id is bare text with a dot and no slash/protocol; `.example` test domains are still exact domain-like ids. For saved agents, the tool validates approval before network contact. For unsaved exact domains, it verifies the Agent Card over HTTPS and may perform a one-shot call without saving.\n- Pass only an exact domain-like agent id to `agent_call`. If the user provides an HTTPS URL, pass only its hostname as the agent id (for `https://docs.rizom.ai/a2a`, pass `docs.rizom.ai`). Never pass a full URL, a non-HTTPS URL, or a display name like `Brain`.\n- If the user names an exact domain-like agent id such as `yeehaa.io`, `docs.rizom.ai`, or `refusal-followup.example`, call `agent_call` directly with that id. Do not preflight with `system_list` or `system_get`; the tool reports structured errors such as invalid Agent Card, not approved, or archived.\n- If the user asks you to ask, message, contact, hear what an exact domain-like agent id has to say, or ask that agent for its own skills/capabilities, treat that as an agent call request first and call `agent_call` in the same turn. Do not stop after listing the agent, drafting the question, searching general content locally, or reading saved agent entity metadata.\n- After `agent_call` returns within a turn, answer that turn from its response. Do **not** supplement with `system_get` (or any other read tool) on the agent entity, unless the user explicitly asks for directory/profile details about the agent itself.\n- Do not create, capture, or generate a note containing the user's question in the same turn as an agent contact request. The user asked to ask the agent, not to persist the question.\n- If `agent_call` succeeds for an unsaved one-shot domain, you may offer to save/connect that agent for future calls, but do not auto-save it.\n- If `agent_call` fails because auth, re-authentication, network, invalid Agent Card, or the remote agent is unavailable, report that failure directly. Do not say the agent was saved, connected, or may need to be saved/connected first. If useful, offer to add the agent contact using the word \"add\". Do not answer from memory, local docs, onboarding docs, or general knowledge; the requested agent was the source.\n- Each new turn that asks the same exact domain-like agent id something \u2014 including short follow-ups like \"what skills does it have\", \"and what about X\", \"tell me more\" \u2014 is a **new** contact request and needs its **own** fresh `agent_call`. Do not assume the previous turn's agent response already covers a new question, and do not substitute `system_list`/`system_get` or a no-tool answer for the fresh call. If the previous turn targeted an exact domain-like id such as `yeehaa.io`, use that same id again for the follow-up even if the previous response was a refusal or error; let `agent_call` validate the current directory state again.\n- When the user provides an HTTPS URL for an agent, use its hostname as the exact domain-like id for `agent_call`; the runtime verifies/contact over HTTPS. If the user provides a non-HTTPS URL, ask for the HTTPS agent URL or exact domain-like id instead.\n- If the user refers to an agent by name, first make sure that name resolves to exactly one saved agent id. If multiple saved agents could match, ask a concise clarification question naming the matching saved agent ids and do not call any agent yet. Never choose the first match.\n- After asking that clarification question, end the turn. Do not call `agent_call` later in the same turn.\n- If `agent_call` reports that an exact domain-like agent id cannot be verified, tell the user the agent could not be verified/contacted. Do not create a wish, reminder, todo, note, fallback task, or any new entity.\n- For non-HTTPS URLs and ambiguous display names, do not call `agent_call`; ask the user for the HTTPS agent URL, exact domain-like id, or a clarification first.\n- Use `agent_connect`, not generic entity creation, when the user explicitly asks you to add, save, or connect an agent contact.\n- If the target agent is discovered but not approved yet, do not call it and do not create a wish. Tell the user it must be approved first."}createDaemon(){return{start:async()=>{if(this.hasWebserver)this.logger.info("A2A mounted on shared webserver host");else this.logger.info("A2A running without webserver routes")},stop:async()=>{await this.turnSupervisor.close(),this.logger.info("A2A server stopped")}}}}import{join as Llx}from"path";var nY0=`/*
876
+ `)},B,{requireSaved:!0});if("success"in Z&&Z.success===!0)return{success:!0,data:Z.data};return{success:!1,error:"error"in Z?Z.error:"Agent call failed"}}),x.messaging.subscribe(CH.callAgents,async()=>{if(!x.entityService.hasEntityType("agent"))return{success:!0,data:{agents:[]}};return{success:!0,data:{agents:(await x.entityService.listEntities({entityType:"agent",options:{filter:{visibilityScope:zA("Admin CMS lists approved A2A contacts at any visibility")}}})).filter((f)=>f.metadata.status==="approved").map((f)=>{let D=f.metadata.name;return{id:f.id,label:typeof D==="string"&&D.length>0?D:f.id}}).sort((f,D)=>f.label.localeCompare(D.label))}}})}var du={name:"@brains/a2a",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",dependencies:{"@a2a-js/sdk":"^0.3.13","@brains/auth-service":"workspace:*","@brains/contracts":"workspace:*","@brains/http-signatures":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",hono:"^4.12.25"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},files:["src"],main:"./src/index.ts",module:"./src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};var _lx={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Signature, Signature-Input, Content-Digest, Date","X-Content-Type-Options":"nosniff"};class ML extends cH{agentCard;taskManager=new Tu;turnSupervisor=new pu;agentService;jwksResolver=new Ju;app;hasWebserver=!1;constructor(x={}){if(Object.prototype.hasOwnProperty.call(x,"trustedTokens"))throw Error("trustedTokens legacy config is no longer supported");if(Object.prototype.hasOwnProperty.call(x,"outboundTokens"))throw Error("outboundTokens legacy config is no longer supported");super("a2a",du,x,JY0)}async onRegister(x){if(await super.onRegister(x),this.hasWebserver=x.plugins.has("webserver"),this.agentService=x.agent,lY0(x,this.createClientDeps(x)),this.hasWebserver)x.endpoints.register({label:"A2A",url:"/a2a",priority:25}),x.interactions.register({id:"a2a",label:"A2A",description:"Let other agents discover and talk to this brain.",href:"/a2a",kind:"agent",priority:25}),this.logger.info("A2A interface registered",{domain:x.domain});else this.logger.info("A2A interface registered in tool-only mode",{domain:x.domain})}async onReady(x){await this.rebuildAgentCard(x)}async rebuildAgentCard(x){let B=x.identity.get(),A=x.identity.getProfile(),w=x.tools.listForPermissionLevel("public"),f;if(x.entityService.hasEntityType("skill"))try{let D=await x.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}});if(D.length>0)f=D.map(($)=>kL.safeParse($.metadata)).filter(($)=>$.success).map(($)=>$.data)}catch{}this.agentCard=kY0({character:B,profile:A,version:du.version,domain:x.domain,organization:this.config.organization,profileKind:x.profileKinds.getResolved(),tools:w,skills:f,authEnabled:!1}),this.logger.debug("Agent Card rebuilt",{skills:this.agentCard.skills.length})}getAgentCard(){return this.agentCard}async resolveCaller(x,B){let A=new URL(x.url),w=new URL(`${A.pathname}${A.search}`,s2(x)),f=await xY0({method:x.method,url:w.toString(),headers:x.headers,body:B},this.jwksResolver);if(f){let D=await X6()?.getA2APeerTrust(f.domain);return{permissionLevel:D?.keyFingerprint===f.keyFingerprint?D.grantedLevel:"public",isAnchor:this.getContext().permissions.isAnchor("a2a",f.domain),callerDomain:f.domain}}return{permissionLevel:"public",isAnchor:!1,callerDomain:null}}withCors(x){let B=new Headers(x.headers);for(let[A,w]of Object.entries(_lx))B.set(A,w);return new Response(x.body,{status:x.status,statusText:x.statusText,headers:B})}getOrCreateApp(){if(this.app)return this.app;let x=new mH;return x.get("/.well-known/agent-card.json",(B)=>{if(!this.agentCard)return this.withCors(B.json({error:"Agent Card not ready"},503));return this.withCors(B.json(this.agentCard))}),x.get("/.well-known/agent-directory.json",async(B)=>{let A=await MY0(this.getContext().entityService);return this.withCors(B.json(A))}),x.get("/a2a",(B)=>{return this.withCors(B.json({error:"Use POST with JSON-RPC 2.0 requests.",agentCard:"/.well-known/agent-card.json"},405))}),x.options("/a2a",()=>this.withCors(new Response(null,{status:204}))),x.post("/a2a",async(B)=>{if(!this.agentService)return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503));let A=await B.req.text(),w;try{w=await this.resolveCaller(B.req.raw,A)}catch{return this.withCors(B.json({error:"Invalid HTTP signature"},401))}let f;try{f=JSON.parse(A)}catch{return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null}))}let D=IY0.safeParse(f);if(!D.success)return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null}));if(D.data.method==="message/stream"){let Z=yY0.safeParse(D.data.params??{});if(!Z.success)return this.withCors(B.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${Z.error.message}`},id:D.data.id}));let Q=mY0(D.data.id,Z.data.message,{taskManager:this.taskManager,turnSupervisor:this.turnSupervisor,agentService:this.agentService,callerPermissionLevel:w.permissionLevel,callerIsAnchor:w.isAnchor,callerDomain:w.callerDomain});if("error"in Q)return this.withCors(B.json(Q));let{stream:Y}=Q;return this.withCors(new Response(Y,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}))}let $=await OY0(D.data,{taskManager:this.taskManager,turnSupervisor:this.turnSupervisor,agentService:this.agentService,callerPermissionLevel:w.permissionLevel,callerIsAnchor:w.isAnchor,callerDomain:w.callerDomain});return this.withCors(B.json($))}),this.app=x,x}getWebRoutes(){if(!this.hasWebserver)return[];let x=(B)=>Promise.resolve(this.getOrCreateApp().fetch(B));return[{path:"/.well-known/agent-card.json",method:"GET",public:!0,handler:x},{path:"/.well-known/agent-directory.json",method:"GET",public:!0,handler:x},{path:"/a2a",method:"GET",public:!0,handler:x},{path:"/a2a",method:"POST",public:!0,handler:x},{path:"/a2a",method:"OPTIONS",public:!0,handler:x}]}createRequestSigner(){let x=X6();if(!x)return;let B=x.getIssuer();if(r3(B)||new URL(B).protocol!=="https:")return;return async(A)=>{let w=await x.getA2ASigningKey();await eX0(A,w.privateJwk,w.keyId)}}createClientDeps(x){return{requestSigner:this.createRequestSigner(),requestTimeoutMs:this.config.requestTimeoutMs,streamIdleTimeoutMs:this.config.streamIdleTimeoutMs,maxNetworkAttempts:this.config.maxNetworkAttempts,entityService:x.entityService}}async getTools(){return[iY0(this.createClientDeps(this.getContext()))]}async getInstructions(){return"## Agent-to-agent calls\n- Use `agent_call` for exact domain-like agent ids (for example `yeehaa.io`, `docs.rizom.ai`, or `save-it-regression.example`). A domain-like id is bare text with a dot and no slash/protocol; `.example` test domains are still exact domain-like ids. For saved agents, the tool validates approval before network contact. For unsaved exact domains, it verifies the Agent Card over HTTPS and may perform a one-shot call without saving.\n- Pass only an exact domain-like agent id to `agent_call`. If the user provides an HTTPS URL, pass only its hostname as the agent id (for `https://docs.rizom.ai/a2a`, pass `docs.rizom.ai`). Never pass a full URL, a non-HTTPS URL, or a display name like `Brain`.\n- If the user names an exact domain-like agent id such as `yeehaa.io`, `docs.rizom.ai`, or `refusal-followup.example`, call `agent_call` directly with that id. Do not preflight with `system_list` or `system_get`; the tool reports structured errors such as invalid Agent Card, not approved, or archived.\n- If the user asks you to ask, message, contact, hear what an exact domain-like agent id has to say, or ask that agent for its own skills/capabilities, treat that as an agent call request first and call `agent_call` in the same turn. Do not stop after listing the agent, drafting the question, searching general content locally, or reading saved agent entity metadata.\n- After `agent_call` returns within a turn, answer that turn from its response. Do **not** supplement with `system_get` (or any other read tool) on the agent entity, unless the user explicitly asks for directory/profile details about the agent itself.\n- Do not create, capture, or generate a note containing the user's question in the same turn as an agent contact request. The user asked to ask the agent, not to persist the question.\n- If `agent_call` succeeds for an unsaved one-shot domain, you may offer to save/connect that agent for future calls, but do not auto-save it.\n- If `agent_call` fails because auth, re-authentication, network, invalid Agent Card, or the remote agent is unavailable, report that failure directly. Do not say the agent was saved, connected, or may need to be saved/connected first. If useful, offer to add the agent contact using the word \"add\". Do not answer from memory, local docs, onboarding docs, or general knowledge; the requested agent was the source.\n- Each new turn that asks the same exact domain-like agent id something \u2014 including short follow-ups like \"what skills does it have\", \"and what about X\", \"tell me more\" \u2014 is a **new** contact request and needs its **own** fresh `agent_call`. Do not assume the previous turn's agent response already covers a new question, and do not substitute `system_list`/`system_get` or a no-tool answer for the fresh call. If the previous turn targeted an exact domain-like id such as `yeehaa.io`, use that same id again for the follow-up even if the previous response was a refusal or error; let `agent_call` validate the current directory state again.\n- When the user provides an HTTPS URL for an agent, use its hostname as the exact domain-like id for `agent_call`; the runtime verifies/contact over HTTPS. If the user provides a non-HTTPS URL, ask for the HTTPS agent URL or exact domain-like id instead.\n- If the user refers to an agent by name, first make sure that name resolves to exactly one saved agent id. If multiple saved agents could match, ask a concise clarification question naming the matching saved agent ids and do not call any agent yet. Never choose the first match.\n- After asking that clarification question, end the turn. Do not call `agent_call` later in the same turn.\n- If `agent_call` reports that an exact domain-like agent id cannot be verified, tell the user the agent could not be verified/contacted. Do not create a wish, reminder, todo, note, fallback task, or any new entity.\n- For non-HTTPS URLs and ambiguous display names, do not call `agent_call`; ask the user for the HTTPS agent URL, exact domain-like id, or a clarification first.\n- Use `agent_connect`, not generic entity creation, when the user explicitly asks you to add, save, or connect an agent contact.\n- If the target agent is discovered but not approved yet, do not call it and do not create a wish. Tell the user it must be approved first."}createDaemon(){return{start:async()=>{if(this.hasWebserver)this.logger.info("A2A mounted on shared webserver host");else this.logger.info("A2A running without webserver routes")},stop:async()=>{await this.turnSupervisor.close(),this.logger.info("A2A server stopped")}}}}import{join as Llx}from"path";var nY0=`/*
877
877
  * Shared operator-console tokens and chrome.
878
878
  *
879
879
  * Instrument is the console's fixed bioluminescent identity. Paper is the
@@ -1678,7 +1678,7 @@ ${bA}
1678
1678
  ><p class="boot">Opening the admin console\u2026</p></main>
1679
1679
  <script type="module" src="${x.assetPath}"></script>
1680
1680
  </body>
1681
- </html>`}var klx=Llx(import.meta.dir,"..","dist","ui","admin-app.js");function su(x){let B=`${x.routePath}/assets/app.js`,A=`${B}?v=${Date.now().toString(36)}`;return[{path:x.routePath,method:"GET",public:!0,handler:async(w)=>{let f=await x.resolvePrincipal(w);if(!f)return new Response(null,{status:302,headers:{Location:`/login?return_to=${encodeURIComponent(x.routePath)}`,"Cache-Control":"no-store"}});if(f.permissionLevel!=="admin")return new Response(null,{status:302,headers:{Location:"/account","Cache-Control":"no-store"}});let D=x.getContext(),$=await D.appInfo();return new Response(au({assetPath:A,routePath:x.routePath,userId:f.userId,displayName:f.displayName,role:f.role,isAnchor:f.isAnchor,brainName:$.model,surfaces:YB(D.webRoutes.getRoutes(),{activeId:"admin",permissionLevel:f.permissionLevel,self:{id:"admin",href:x.routePath}}),sessionHref:`/logout?return_to=${encodeURIComponent(x.routePath)}`}),{headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}})}},{path:B,method:"GET",public:!0,handler:async()=>{let w=Bun.file(klx);if(!await w.exists())return new Response("Admin console UI asset not built",{status:503});return new Response(w,{headers:{"Content-Type":"text/javascript; charset=utf-8","Cache-Control":"no-store"}})}}]}var NL={name:"@brains/admin",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Authenticated administration console for people, invitations, peers, and audit",dependencies:{"@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@tanstack/react-query":"^5.0.0",react:"^19.2.7","react-dom":"^19.2.7"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.0.3","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json"},type:"module"};var vlx=X.object({routePath:X.string().default("/admin")});class ru extends D8{constructor(x={}){super("admin",NL,x,vlx)}async onRegister(x){await super.onRegister(x),x.endpoints.register({label:"Admin",url:this.config.routePath,priority:50,visibility:"admin"}),x.interactions.register({id:"admin",label:"Admin",description:"Manage people, access, invitations, external peers, and audit history.",href:this.config.routePath,kind:"admin",priority:50,visibility:"admin"})}getWebRoutes(){return su({routePath:this.config.routePath,getContext:()=>this.getContext(),resolvePrincipal:async(x)=>X6()?.resolveSession(x)})}}function ou(x={}){return new ru(x)}import{join as Nlx}from"path";function aY0(x){return x.replaceAll("&","&amp;").replaceAll('"',"&quot;").replaceAll("<","&lt;").replaceAll(">","&gt;")}function tu(x){return`<!doctype html>
1681
+ </html>`}var klx=Llx(import.meta.dir,"..","dist","ui","admin-app.js");function su(x){let B=`${x.routePath}/assets/app.js`,A=`${B}?v=${Date.now().toString(36)}`;return[{path:x.routePath,method:"GET",public:!0,handler:async(w)=>{let f=await x.resolvePrincipal(w);if(!f)return new Response(null,{status:302,headers:{Location:`/login?return_to=${encodeURIComponent(x.routePath)}`,"Cache-Control":"no-store"}});if(f.permissionLevel!=="admin")return new Response(null,{status:302,headers:{Location:"/account","Cache-Control":"no-store"}});let D=x.getContext(),$=await D.appInfo();return new Response(au({assetPath:A,routePath:x.routePath,userId:f.userId,displayName:f.displayName,role:f.role,isAnchor:f.isAnchor,brainName:$.model,surfaces:YB(D.webRoutes.getRoutes(),{activeId:"admin",permissionLevel:f.permissionLevel,self:{id:"admin",href:x.routePath}}),sessionHref:`/logout?return_to=${encodeURIComponent(x.routePath)}`}),{headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}})}},{path:B,method:"GET",public:!0,handler:async()=>{let w=Bun.file(klx);if(!await w.exists())return new Response("Admin console UI asset not built",{status:503});return new Response(w,{headers:{"Content-Type":"text/javascript; charset=utf-8","Cache-Control":"no-store"}})}}]}var NL={name:"@brains/admin",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Authenticated administration console for people, invitations, peers, and audit",dependencies:{"@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@tanstack/react-query":"^5.0.0",react:"^19.2.7","react-dom":"^19.2.7"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.0.3","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json"},type:"module"};var vlx=X.object({routePath:X.string().default("/admin")});class ru extends D8{constructor(x={}){super("admin",NL,x,vlx)}async onRegister(x){await super.onRegister(x),x.endpoints.register({label:"Admin",url:this.config.routePath,priority:50,visibility:"admin"}),x.interactions.register({id:"admin",label:"Admin",description:"Manage people, access, invitations, external peers, and audit history.",href:this.config.routePath,kind:"admin",priority:50,visibility:"admin"})}getWebRoutes(){return su({routePath:this.config.routePath,getContext:()=>this.getContext(),resolvePrincipal:async(x)=>X6()?.resolveSession(x)})}}function ou(x={}){return new ru(x)}import{join as Nlx}from"path";function aY0(x){return x.replaceAll("&","&amp;").replaceAll('"',"&quot;").replaceAll("<","&lt;").replaceAll(">","&gt;")}function tu(x){return`<!doctype html>
1682
1682
  <html lang="en" data-climate="instrument">
1683
1683
  <head>
1684
1684
  <meta charset="utf-8" />
@@ -3795,7 +3795,7 @@ ${JW0}`;var pL=`(function () {
3795
3795
  `);function knx(x){return`${x.replace(/\/+$/,"")}/assets`}class HS{basePath;assets=new Map;dashboardStylesUrl;dashboardScriptUrl;constructor(x){this.basePath=knx(x),this.dashboardStylesUrl=this.register("dashboard","css","text/css; charset=utf-8",TL),this.dashboardScriptUrl=this.register("dashboard","js","text/javascript; charset=utf-8",Lnx)}createRenderUrls(x){return{dashboardStyles:this.dashboardStylesUrl,dashboardScript:this.dashboardScriptUrl,...x.themeCSS!==void 0&&{themeStyles:this.register("theme","css","text/css; charset=utf-8",x.themeCSS)},widgetStyles:Array.from(new Set(x.widgetStyles)).map((B)=>this.register("widget","css","text/css; charset=utf-8",B)),widgetScripts:Array.from(new Set(x.widgetScripts)).map((B)=>this.register("widget","js","text/javascript; charset=utf-8",B))}}getRoutes(){return Array.from(this.assets.values()).map((x)=>({path:x.path,method:"GET",public:!0,handler:(B)=>{let A={"Cache-Control":Jnx,"Content-Type":x.contentType,ETag:x.etag,"X-Content-Type-Options":"nosniff"};if(B.headers.get("If-None-Match")===x.etag)return new Response(null,{status:304,headers:A});return new Response(x.content,{headers:A})}}))}register(x,B,A,w){let f=_8(w),D=`${this.basePath}/${x}.${f}.${B}`;if(!this.assets.has(D))this.assets.set(D,{path:D,content:w,contentType:A,etag:`"${f}"`});return D}}class uL{id="dashboard:dashboard";name="Dashboard DataSource";description="Aggregates dashboard widgets from all plugins";registry;logger;constructor(x,B){this.registry=x,this.logger=B.child("DashboardDataSource")}async getDashboardData(x={}){let B={},A=x.widgets??this.registry.list({...x.permissionLevel!==void 0&&{permissionLevel:x.permissionLevel}}),w=await Promise.allSettled(A.map(async(f)=>{let D=await f.dataProvider(),{dataProvider:$,digestProvider:Z,component:Q,clientStyles:Y,clientScript:W,visibility:H="public",...F}=f;return{key:`${f.pluginId}:${f.id}`,widget:{...F,visibility:H,...this.deriveLiveDigest(f,D)},data:D}}));for(let f=0;f<w.length;f++){let D=w[f],$=A[f];if(!D||!$)continue;if(D.status==="fulfilled")B[D.value.key]={widget:D.value.widget,data:D.value.data};else this.logger.error("Widget data provider failed",{widgetId:$.id,pluginId:$.pluginId,error:g(D.reason)})}return{widgets:B}}deriveLiveDigest(x,B){if(!x.digestProvider)return{};try{let A=x.digestProvider(B),w=A.needsAttention??A.needsOperator;return{...A.digest!==void 0&&{digest:A.digest},...w!==void 0&&{needsAttention:w}}}catch(A){return this.logger.error("Widget digest provider failed",{widgetId:x.id,pluginId:x.pluginId,error:g(A)}),{}}}async fetch(x,B,A){return await this.getDashboardData()}}import{render as bdx}from"preact-render-to-string";import{jsxDEV as SL}from"preact/jsx-dev-runtime";function Mnx(x,B){let A=x.endpoints.find((w)=>w.label.toLowerCase().includes("doc"));if(!A)return null;return uH(A.url,B)}function NW0(x){let{title:B,appInfo:A,baseUrl:w}=x,f=Mnx(A,w);return SL("footer",{class:"colophon",children:[SL("span",{class:"colophon-mark",children:[B," \xB7 dashboard"]},void 0,!0,void 0,this),SL("span",{class:"colophon-actions",children:f&&SL("a",{href:f,target:"_blank",rel:"noopener noreferrer",children:"Docs \u2197"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as b1}from"preact/jsx-dev-runtime";function IW0(x){return`${x.slice(0,1).toUpperCase()}${x.slice(1)}`}function vnx(x){return x.split(/\s+/).filter(Boolean).slice(0,2).map((B)=>B.slice(0,1).toUpperCase()).join("")}function OW0({dashboardPath:x,surfaces:B,authAccess:A}){let w=A?.principal,f=w?A.logoutUrl:A?.loginUrl??"/login",D=w?.displayName??"Visitor",$=w?"Sign out":"Sign in";return b1("header",{class:"console-strip","aria-label":"Console surfaces",children:[b1("a",{class:"console-mark",href:x,"aria-label":"Dashboard home",children:[b1("span",{class:"pulse"},void 0,!1,void 0,this),b1("span",{children:["Brain"," ",b1("span",{class:"console-mark-long",children:["\xB7 ",b1("b",{children:"Console"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),b1("nav",{class:"surface-nav","aria-label":"Console surfaces",children:B.map((Z)=>b1("a",{class:Z.isActive?"surface-nav-link is-active":"surface-nav-link",href:Z.href,children:Z.label},Z.id,!1,void 0,this))},void 0,!1,void 0,this),b1("button",{class:"command-chip",type:"button","aria-label":"Search or jump",children:[b1("span",{class:"command-chip-hint",children:"Search or jump\u2026"},void 0,!1,void 0,this),b1("kbd",{children:"\u2318K"},void 0,!1,void 0,this),b1("span",{class:"command-chip-icon","aria-hidden":"true",children:"\u2315"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),b1("button",{id:"climateToggle",class:"climate-chip",type:"button","aria-label":"Toggle climate",children:"\u25D0"},void 0,!1,void 0,this),b1("a",{class:w?"session-chip":"session-chip is-visitor",href:f,"aria-label":`${D} \xB7 ${w?IW0(w.role):$} \xB7 ${$}`,children:[b1("span",{children:[D,w?` \xB7 ${IW0(w.role)}`:""]},void 0,!0,void 0,this),b1("strong",{children:$},void 0,!1,void 0,this),b1("span",{class:"session-chip-avatar","aria-hidden":"true",children:w?vnx(w.displayName):"VI"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var Nnx=["knowledge","publishing","network","system"],Inx={knowledge:"Knowledge",publishing:"Publishing",network:"Network",system:"System"};function SH(x){let B=Inx[x];if(B)return B;return x.split(/[-_\s]+/).filter(Boolean).map((A)=>`${A.slice(0,1).toUpperCase()}${A.slice(1)}`).join(" ")}function iL(x){let B=new Map(Nnx.map((A,w)=>[A,w]));return[...x].sort((A,w)=>{let f=B.get(A),D=B.get(w);if(f!==void 0||D!==void 0)return(f??Number.MAX_SAFE_INTEGER)-(D??Number.MAX_SAFE_INTEGER);return SH(A).localeCompare(SH(w))})}import{jsxDEV as iH}from"preact/jsx-dev-runtime";function FS(){return{primary:[],secondary:[],sidebar:[]}}function lL(x){return[...x.widgets.primary,...x.widgets.secondary,...x.widgets.sidebar]}function nL(x){return lL(x).length}function Onx(x){return lL(x).reduce((B,A)=>B+(A.widget.needsAttention??0),0)}function hnx(x){return x.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"group"}function hW0(x){let B=new Map;for(let w of Object.values(x)){let f=w.widget.group,D=B.get(f)??FS();D[w.widget.section].push(w),B.set(f,D)}for(let w of B.values())for(let f of Object.keys(w))w[f].sort((D,$)=>D.widget.priority-$.widget.priority);let A=new Map;for(let w of["knowledge","system"])if(!B.has(w))B.set(w,FS());return iL(Array.from(B.keys())).map((w)=>{let f=hnx(w),D=A.get(f)??0,$=B.get(w)??FS(),Z={id:D===0?f:`${f}-${D+1}`,group:w,label:SH(w),widgets:$,widgetCount:0,needsAttention:0};return A.set(f,D+1),{...Z,widgetCount:nL(Z),needsAttention:Onx(Z)}})}function RW0({tabs:x}){return iH("nav",{class:"dashboard-tabs","aria-label":"Dashboard sections",role:"tablist",children:[iH("a",{id:"dashboard-tab-overview",class:"dashboard-tab is-active",href:"#overview",role:"tab","aria-selected":"true","data-dashboard-tab-link":"overview","data-ui-tab":"overview",children:"Overview"},void 0,!1,void 0,this),x.map((B)=>iH("a",{id:`dashboard-tab-${B.id}`,class:"dashboard-tab",href:`#${B.id}`,role:"tab","aria-selected":"false","data-dashboard-tab-link":B.id,"data-ui-tab":B.id,children:[iH("span",{children:B.label},void 0,!1,void 0,this),B.needsAttention>0?iH("span",{class:"tab-badge tab-badge--needs",children:B.needsAttention},void 0,!1,void 0,this):B.widgetCount>0?iH("span",{class:"tab-badge tab-badge--muted",children:B.widgetCount},void 0,!1,void 0,this):null]},B.id,!0,void 0,this))]},void 0,!0,void 0,this)}import{jsxDEV as _Q,Fragment as yW0}from"preact/jsx-dev-runtime";function Rnx({title:x}){let B=x.trim(),A=B.lastIndexOf(" ");if(A<=0)return _Q(yW0,{children:B},void 0,!1,void 0,this);return _Q(yW0,{children:[B.slice(0,A)," ",_Q("em",{children:B.slice(A+1)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function mW0(x){let{title:B,tagline:A}=x;return _Q("header",{class:"masthead",children:[_Q("h1",{class:"brand",children:_Q(Rnx,{title:B},void 0,!1,void 0,this)},void 0,!1,void 0,this),A&&_Q("p",{class:"tagline",children:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as P8,Fragment as CW0}from"preact/jsx-dev-runtime";import{createElement as KS}from"preact";function GA(...x){return x.filter(Boolean).join(" ")}function qS(x,B){return`widget-${`${x}-${B}`.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"custom"}`}function N5({title:x,source:B,subtitle:A,children:w}){return P8("div",{class:"card-head",children:[P8("span",{class:"card-title",children:x},void 0,!1,void 0,this),B?P8("span",{class:"card-from",children:B},void 0,!1,void 0,this):A?P8("span",{class:"card-subtitle",children:A},void 0,!1,void 0,this):w]},void 0,!0,void 0,this)}function EA({items:x}){return P8("dl",{class:"kv",children:x.map((B,A)=>P8("div",{class:"kv-row",children:[P8("dt",{children:B.label},void 0,!1,void 0,this),P8("dd",{children:B.value},void 0,!1,void 0,this)]},A,!0,void 0,this))},void 0,!1,void 0,this)}function z3({children:x="Nothing to show yet.",className:B}){return P8("p",{class:GA("muted",B),children:x},void 0,!1,void 0,this)}var $2=z3;function PQ({label:x,children:B,className:A}){return P8("nav",{class:GA("widget-actions",A),"aria-label":x,children:B},void 0,!1,void 0,this)}function JQ({href:x,children:B,external:A=!1,emphasis:w="secondary"}){return P8("a",{class:GA("widget-action",`widget-action--${w}`),href:x,...A?{target:"_blank",rel:"noreferrer"}:{},children:[P8("span",{children:B},void 0,!1,void 0,this),P8("span",{class:"widget-action-arrow","aria-hidden":"true",children:A?"\u2197":"\u2192"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function lH({id:x,label:B,defaultValue:A,tabs:w,variant:f="line",compact:D=!1,stateAttribute:$,rootClassName:Z,rootProps:Q}){let Y=f==="line"?"widget-tabs":GA("widget-filter-tabs",D&&"widget-filter-tabs--compact"),W=f==="line"?"widget-tab":"widget-filter-tab",H=f==="line"?"widget-tab-count":"widget-filter-count",F=f==="pill"?"widget-filter-label":void 0;return P8("div",{...Q,class:Z,"data-ui-tabs":!0,"data-ui-tabs-default":A,...$?{"data-ui-tabs-state-attribute":$}:{},children:[P8("div",{class:Y,role:"tablist","aria-label":B,children:w.map((K)=>{let q=K.value===A,V=`${x}-tab-${K.value}`,b=`${x}-panel-${K.value}`;return KS("button",{...K.triggerProps,id:V,key:K.value,class:GA(W,q&&"is-active"),type:"button",role:"tab","data-ui-tab":K.value,"aria-controls":b,"aria-selected":q?"true":"false"},f==="pill"?P8(CW0,{children:[K.count!==void 0&&P8("span",{class:H,children:K.count},void 0,!1,void 0,this),P8("span",{class:F,children:K.label},void 0,!1,void 0,this)]},void 0,!0,void 0,this):P8(CW0,{children:[K.label,K.count!==void 0&&P8("span",{class:H,children:K.count},void 0,!1,void 0,this)]},void 0,!0,void 0,this))})},void 0,!1,void 0,this),w.map((K)=>{let q=K.value===A;return KS("div",{...K.panelProps,id:`${x}-panel-${K.value}`,key:K.value,class:GA(K.panelClassName,q&&"is-active"),"data-ui-panel":K.value,role:"tabpanel","aria-labelledby":`${x}-tab-${K.value}`,hidden:!q},K.content)})]},void 0,!0,void 0,this)}function zS({label:x,defaultValue:B,options:A,children:w,emptyState:f,className:D,allValue:$="all"}){return P8("div",{class:D,"data-ui-filter":!0,"data-ui-filter-default":B,"data-ui-filter-all":$,children:[P8("div",{class:"widget-filter-tabs widget-filter-tabs--compact","aria-label":x,children:A.map((Z)=>{let Q=Z.value===B;return KS("button",{...Z.triggerProps,key:Z.value,class:GA("widget-filter-tab",Q&&"is-active",Z.tone==="gap"&&"is-gap"),type:"button","data-ui-filter-value":Z.value,"aria-pressed":Q?"true":"false"},Z.count!==void 0&&P8("span",{class:"widget-filter-count",children:Z.count},void 0,!1,void 0,this),P8("span",{class:"widget-filter-label",children:Z.label},void 0,!1,void 0,this))})},void 0,!1,void 0,this),w,f!==void 0&&P8("div",{"data-ui-filter-empty":!0,hidden:!0,children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function nD({children:x,className:B}){return P8("ul",{class:GA("list",B),children:x},void 0,!1,void 0,this)}function cW0({segments:x}){if(x.length===0)return null;return P8("span",{class:"list-meta-text",children:x.map((B,A)=>P8("span",{children:[A>0&&P8("span",{class:"sep",children:"\xB7"},void 0,!1,void 0,this),B]},`${B}:${A}`,!0,void 0,this))},void 0,!1,void 0,this)}function gW0({tags:x}){if(x.length===0)return null;return P8("div",{class:"list-tags",children:x.map((B,A)=>P8("span",{class:"tag",children:B},`${B}:${A}`,!1,void 0,this))},void 0,!1,void 0,this)}function LQ({children:x,tone:B="plain"}){let A={plain:"",warn:"pill--warn",error:"pill--err",ok:"pill--ok",muted:"pill--mute"}[B];return P8("span",{class:GA("pill",A),children:x},void 0,!1,void 0,this)}function dD({title:x,description:B,meta:A=[],tags:w=[],trailing:f,filterValues:D,className:$,itemProps:Z}){return P8("li",{...Z,class:GA("list-item",$),...D?{"data-ui-filter-values":JSON.stringify(D)}:{},children:[P8("div",{class:"list-main",children:[P8("span",{class:"list-name",children:x},void 0,!1,void 0,this),B&&P8("span",{class:"list-desc",children:B},void 0,!1,void 0,this),P8(cW0,{segments:A},void 0,!1,void 0,this),P8(gW0,{tags:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),f&&P8("div",{class:"list-meta",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function TW0(x){let B=new Date(x);if(Number.isNaN(B.getTime()))return"\u2014";return B.toLocaleString("en",{month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit"})}function mV(x){let B=new Date(x);if(Number.isNaN(B.getTime()))return"\u2014";return B.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"})}import{jsxDEV as k8}from"preact/jsx-dev-runtime";function dL(x){return x.indexStatus?.ready??x.indexReady??x.appInfo.embeddings>0}function ynx(x){let B=(x.activeEmbeddingJobs??0)+(x.missingEmbeddings??0)+(x.staleEmbeddings??0);if(x.ready&&!x.degraded)return 100;if(x.ready)return 92;if(B===0)return 50;return Math.max(8,Math.min(88,100-B*12))}function mnx(x){return["Semantic index",x.ready?x.degraded?"ready, degraded":"ready":"pending",x.activeEmbeddingJobs!==void 0?`${x.activeEmbeddingJobs} active`:void 0,x.missingEmbeddings!==void 0?`${x.missingEmbeddings} missing`:void 0,x.staleEmbeddings!==void 0?`${x.staleEmbeddings} stale`:void 0,x.failedEmbeddings!==void 0?`${x.failedEmbeddings} failed`:void 0].filter(Boolean).join(" \xB7 ")}function Cnx({status:x}){let B=ynx(x),A=x.ready?x.degraded?"Degraded":"Ready":"Indexing";return k8("div",{class:"index-gauge",style:`--index-percent: ${B}%`,children:[k8("div",{class:"index-gauge-ring","aria-hidden":"true",children:k8("span",{children:[B,"%"]},void 0,!0,void 0,this)},void 0,!1,void 0,this),k8("div",{class:"index-gauge-copy",children:[k8("strong",{children:A},void 0,!1,void 0,this),k8("span",{children:mnx(x)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function pW0({input:x}){let B=dL(x);return k8("section",{class:"card semantic-index-card",children:[k8(N5,{title:"Semantic index",source:"entity-service"},void 0,!1,void 0,this),x.indexStatus?k8(Cnx,{status:x.indexStatus},void 0,!1,void 0,this):k8(EA,{items:[{label:"Semantic index",value:B?"Ready":"Pending"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function uW0({status:x}){let B=x.totalFiles===void 0?"\u2014":x.totalFiles===1?"1 file":`${x.totalFiles} files`,A=x.byEntityType?Object.entries(x.byEntityType).sort(([,w],[,f])=>f-w).slice(0,2).map(([w,f])=>`${w} ${f}`).join(", "):void 0;return k8("section",{class:"card content-sync-card",children:[k8(N5,{title:"Content sync",source:"directory-sync"},void 0,!1,void 0,this),k8(EA,{items:[{label:"Path",value:x.syncPath},{label:"Files",value:A?`${B} \xB7 ${A}`:B},{label:"Watch",value:x.watchEnabled?"Watching":x.isInitialized?"Manual":"Not initialized"},{label:"Last sync",value:x.lastSync?`last sync ${TW0(x.lastSync)}`:"\u2014"}]},void 0,!1,void 0,this),k8("div",{class:"pipeline-mini","aria-label":"Write pipeline",children:[k8("span",{class:`pipeline-step${x.isInitialized?" is-done":""}`,children:"entity db"},void 0,!1,void 0,this),k8("span",{class:"pipeline-track"},void 0,!1,void 0,this),k8("span",{class:`pipeline-step${(x.totalFiles??0)>0?" is-done":""}`,children:"exported"},void 0,!1,void 0,this),k8("span",{class:"pipeline-track"},void 0,!1,void 0,this),k8("span",{class:`pipeline-step${x.lastSync?" is-done":""}`,children:"committed"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x.managementUrl&&k8(PQ,{label:"Content sync actions",children:k8(JQ,{href:x.managementUrl,emphasis:"primary",children:"Open in CMS"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var cnx={pending:"run",processing:"run",completed:"done",failed:"fail"},gnx={pending:"pending",processing:"running",completed:"done",failed:"failed"};function SW0({jobs:x}){return k8("section",{class:"card widget-card--wide job-queue-card",children:[k8(N5,{title:"Job queue",source:"job-queue"},void 0,!1,void 0,this),x.length===0?k8($2,{children:"No recent job progress observed."},void 0,!1,void 0,this):k8("table",{class:"jobs",children:[k8("thead",{children:k8("tr",{children:[k8("th",{children:"Job"},void 0,!1,void 0,this),k8("th",{children:"Type"},void 0,!1,void 0,this),k8("th",{children:"Updated"},void 0,!1,void 0,this),k8("th",{children:"Status"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),k8("tbody",{children:x.map((B)=>k8("tr",{children:[k8("td",{class:"mono",children:B.id.slice(0,8)},void 0,!1,void 0,this),k8("td",{children:B.jobType??B.kind},void 0,!1,void 0,this),k8("td",{class:"mono",children:mV(B.updatedAt)},void 0,!1,void 0,this),k8("td",{children:k8("span",{class:`status-pill status-pill--${cnx[B.status]}`,children:[gnx[B.status],B.progressLabel?` \xB7 ${B.progressLabel}`:""]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},`${B.kind}:${B.id}`,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as vx}from"preact/jsx-dev-runtime";function Tnx(x,B){if(x.group==="system"){let A=dL(B);return[{label:"Runtime",value:"Active",tone:"good"},{label:"Endpoints",value:String(B.appInfo.endpoints.length)},{label:"Semantic index",value:A?"Ready":"Pending",tone:A?"good":"warn"}]}return[{label:nL(x)===1?"Widget":"Widgets",value:String(nL(x))}]}function pnx(x,B){return x.map((A)=>{let w=lL(A).flatMap((f)=>f.widget.digest??[]).slice(0,4);return{id:A.id,label:A.label,href:`#${A.id}`,lines:w.length>0?w:Tnx(A,B)}})}function unx(x){return`${x.slice(0,1).toUpperCase()}${x.slice(1)}`}function Snx({hiddenWidgetCount:x,loginUrl:B,principal:A}){return vx("section",{class:"card access-gate",children:[vx("div",{children:[vx("div",{class:"card-title",children:"Restricted access"},void 0,!1,void 0,this),vx("p",{children:[x===1?"1 private console widget is hidden.":`${x} private console widgets are hidden.`," ",A?`Your ${unx(A.role)} role does not include this layer.`:"Sign in with your passkey to unlock the restricted layer."]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),!A&&vx("a",{class:"access-gate-link",href:B,children:"Sign in"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function inx({input:x}){let B=dL(x),A=x.activityLog?.[0],w=x.appInfo.entityCounts.length,f=x.appInfo.interactions.map((H)=>H.id).slice(0,3).join(" / "),D=x.indexStatus?.embeddedEntities??x.appInfo.embeddings,$=x.indexStatus?.embeddableEntities,Z=x.indexStatus?(x.indexStatus.activeEmbeddingJobs??0)+(x.indexStatus.missingEmbeddings??0)+(x.indexStatus.staleEmbeddings??0):0,Q=$===void 0?`${D}`:`${D}/${$}`,Y=Z>0?`${Q} embedded \xB7 ${Z} queued`:`${Q} embedded`,W=(x.jobProgress??[]).some((H)=>H.status==="processing"||H.status==="pending");return vx("section",{class:"overview-vitals","aria-label":"Runtime vitals",children:[vx("article",{class:"vital-card",children:[vx("span",{class:"vital-label",children:"Entities"},void 0,!1,void 0,this),vx("strong",{class:"vital-num",children:x.appInfo.entities},void 0,!1,void 0,this),vx("span",{class:"vital-sub",children:w===1?"1 type":`${w} types`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),vx("article",{class:"vital-card",children:[vx("span",{class:"vital-label",children:"Interactions"},void 0,!1,void 0,this),vx("strong",{class:"vital-num",children:x.appInfo.interactions.length},void 0,!1,void 0,this),vx("span",{class:"vital-sub",children:f||"no channels"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),vx("article",{class:`vital-card ${B?"vital-card--ok":"vital-card--warm"}`,children:[vx("span",{class:"vital-label",children:"Semantic index"},void 0,!1,void 0,this),vx("strong",{class:"vital-num vital-num--text",children:B?"Ready":"Pending"},void 0,!1,void 0,this),vx("span",{class:"vital-sub",children:Y},void 0,!1,void 0,this)]},void 0,!0,void 0,this),vx("article",{class:`vital-card${W?" vital-card--warm":""}`,children:[vx("span",{class:"vital-label",children:"Last write"},void 0,!1,void 0,this),vx("strong",{class:"vital-num vital-num--text",children:A?mV(A.timestamp):"\u2014"},void 0,!1,void 0,this),vx("span",{class:"vital-sub",children:A?`${A.entityType}/${A.entityId}`:"no writes observed"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function lnx({input:x}){let{role:B,purpose:A,values:w}=x.character;if(!B&&!A&&w.length===0)return null;return vx("aside",{class:"card identity-capsule",children:[vx(N5,{title:"Identity",source:"identity"},void 0,!1,void 0,this),vx("div",{class:"identity-capsule-body",children:[B&&vx("span",{class:"identity-capsule-role",children:["\u201C",B,"\u201D"]},void 0,!0,void 0,this),w.length>0&&vx("span",{class:"values",children:w.map((f)=>vx("span",{class:"value",children:f},f,!1,void 0,this))},void 0,!1,void 0,this),A&&vx("span",{class:"identity-capsule-purpose",children:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function nnx({cards:x}){if(x.length===0)return vx("section",{class:"card overview-empty-digest",children:[vx(N5,{title:"Group digests"},void 0,!1,void 0,this),vx($2,{children:"No plugin groups are visible yet."},void 0,!1,void 0,this)]},void 0,!0,void 0,this);return vx("section",{class:"digests","aria-label":"Group digests",children:x.map((B)=>vx("a",{class:"card digest-card",href:B.href,children:[vx("div",{class:"digest-head",children:[vx("h4",{children:B.label},void 0,!1,void 0,this),vx("span",{class:"digest-go",children:"open \u2192"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),vx("dl",{class:"digest-lines",children:B.lines.map((A)=>vx("div",{class:`digest-line digest-line--${A.tone??"plain"}`,children:[vx("dt",{children:A.label},void 0,!1,void 0,this),vx("dd",{children:A.value},void 0,!1,void 0,this)]},`${A.label}:${A.value}`,!0,void 0,this))},void 0,!1,void 0,this)]},B.id,!0,void 0,this))},void 0,!1,void 0,this)}var iW0={created:{glyph:"\uFF0B",tone:""},updated:{glyph:"\u2713",tone:" ledger-glyph--ok"},deleted:{glyph:"\u2212",tone:" ledger-glyph--warn"}};function dnx({events:x}){return vx("section",{class:"card activity-ledger",children:[vx(N5,{title:"Activity",source:"entity events"},void 0,!1,void 0,this),x.length===0?vx($2,{children:"No entity activity has been observed this session."},void 0,!1,void 0,this):vx("ol",{class:"ledger",children:x.map((B)=>vx("li",{class:"ledger-entry",children:[vx("time",{class:"ledger-time",dateTime:B.timestamp,children:mV(B.timestamp)},void 0,!1,void 0,this),vx("span",{class:`ledger-glyph${iW0[B.action].tone}`,"aria-hidden":"true",children:iW0[B.action].glyph},void 0,!1,void 0,this),vx("span",{class:"ledger-what",children:[vx("b",{children:B.entityType},void 0,!1,void 0,this)," ",B.action," \u2014"," ",vx("code",{children:[B.entityType,"/",B.entityId]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},`${B.timestamp}:${B.action}:${B.entityType}:${B.entityId}`,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function lW0({input:x,tabs:B,showAccessGate:A}){let w=pnx(B,x),f=x.activityLog??[];return vx("section",{id:"overview",class:"dashboard-tab-panel is-active","data-dashboard-tab-panel":!0,"data-ui-panel":"overview",role:"tabpanel","aria-labelledby":"dashboard-tab-overview",children:[vx(inx,{input:x},void 0,!1,void 0,this),vx(lnx,{input:x},void 0,!1,void 0,this),A&&x.authAccess&&vx(Snx,{hiddenWidgetCount:x.authAccess.hiddenWidgetCount,loginUrl:x.authAccess.loginUrl,principal:x.authAccess.principal},void 0,!1,void 0,this),vx("div",{class:"overview-grid",children:[vx(nnx,{cards:w},void 0,!1,void 0,this),vx(dnx,{events:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as kQ}from"preact/jsx-dev-runtime";function anx(x){try{let B=new URL(x);return B.host+B.pathname.replace(/\/$/,"")}catch{return x}}function nW0(x){let{endpoints:B,baseUrl:A}=x;if(B.length===0)return null;let w=[...B].sort((f,D)=>f.priority-D.priority||f.label.localeCompare(D.label));return kQ("aside",{class:"card",children:[kQ(N5,{title:"Endpoints"},void 0,!1,void 0,this),kQ("dl",{class:"links",children:w.map((f)=>{let D=uH(f.url,A);return kQ("a",{class:"link",href:D,target:"_blank",rel:"noopener noreferrer",children:[kQ("dt",{children:aL(f.label)},void 0,!1,void 0,this),kQ("dd",{children:anx(D)},void 0,!1,void 0,this),kQ("span",{class:"arrow",children:"\u2197"},void 0,!1,void 0,this)]},`${f.label}:${f.url}`,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as e1}from"preact/jsx-dev-runtime";function snx({entityType:x,count:B,max:A}){let w=Math.max(4,Math.round(B/A*100));return e1("div",{class:"breakdown-row",children:[e1("span",{class:"breakdown-name",children:aD(x)},void 0,!1,void 0,this),e1("span",{class:"breakdown-count",children:B},void 0,!1,void 0,this),e1("div",{class:"breakdown-bar",children:e1("i",{style:{width:`${w}%`}},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function dW0(x){let{total:B,entityCounts:A}=x;if(A.length===0)return e1("article",{class:"card card--entity-summary",children:[e1(N5,{title:"Entities"},void 0,!1,void 0,this),e1($2,{children:"No indexed entities yet."},void 0,!1,void 0,this)]},void 0,!0,void 0,this);let w=[...A].sort((D,$)=>$.count-D.count),f=w[0]?.count??1;return e1("article",{class:"card card--entity-summary",children:[e1(N5,{title:"Entities",subtitle:"corpus \xB7 sorted by volume"},void 0,!1,void 0,this),e1("div",{class:"entities",children:[e1("div",{children:[e1("div",{class:"entity-summary-number",children:B},void 0,!1,void 0,this),e1("div",{class:"entity-summary-label",children:"indexed entities"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),e1("div",{class:"breakdown",children:w.map((D)=>e1(snx,{entityType:D.entityType,count:D.count,max:f},D.entityType,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as sD}from"preact/jsx-dev-runtime";var rnx={human:"Human",agent:"Agent",admin:"Admin",protocol:"Protocol"};function aW0(x){let{interactions:B,baseUrl:A}=x;if(B.length===0)return null;return sD("aside",{class:"card interactions-card",children:[sD(N5,{title:"Ways to connect"},void 0,!1,void 0,this),sD("div",{class:"interactions-list",children:B.slice(0,5).map((w)=>{let f=uH(w.href,A);return sD("a",{class:`interaction-link interaction-link--${w.kind}`,href:f,target:"_blank",rel:"noopener noreferrer",children:[sD("span",{children:[sD("strong",{children:aL(w.label)},void 0,!1,void 0,this),w.description&&sD("em",{children:w.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),sD("small",{children:rnx[w.kind]},void 0,!1,void 0,this)]},`${w.pluginId}:${w.id}`,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as bS}from"preact/jsx-dev-runtime";function onx(x){let B=Math.max(0,Math.floor(x)),A=Math.floor(B/86400),w=Math.floor(B%86400/3600),f=Math.floor(B%3600/60);if(A>0)return`${A}d ${String(w).padStart(2,"0")}h ${String(f).padStart(2,"0")}m`;if(w>0)return`${w}h ${String(f).padStart(2,"0")}m`;return`${f}m`}function tnx(x){let B=(A)=>String(A).padStart(2,"0");return`${x.getFullYear()}-${B(x.getMonth()+1)}-${B(x.getDate())} ${B(x.getHours())}:${B(x.getMinutes())}`}function sW0(x){let{appInfo:B,now:A}=x,w=B.daemons.length,f=B.daemons.filter((D)=>D.health?.status==="healthy").length;return bS("aside",{class:"card runtime-card",children:[bS(N5,{title:"Runtime",source:"core"},void 0,!1,void 0,this),bS(EA,{items:[{label:"Version",value:`v${B.version}`},{label:"Daemons",value:w===0?"\u2014":`${f}/${w} healthy`},{label:"Model",value:B.model},{label:"Uptime",value:onx(B.uptime)},{label:"Embeddings",value:B.embeddings},{label:"Rendered",value:tnx(A)}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as v8,Fragment as qdx}from"preact/jsx-dev-runtime";var enx=new Set(["rendered","version"]),xdx=new Set(["StatsWidget","SystemWidget"]),Bdx=X.object({id:X.string(),name:X.string(),description:X.string().optional(),meta:X.array(X.string()).optional(),tags:X.array(X.string()).optional(),count:X.number().optional(),priority:X.string().optional(),status:X.string().optional()}),Adx=X.object({items:X.array(Bdx)}),wdx=X.record(X.string(),X.unknown()),fdx=X.object({summary:X.object({draft:X.number().int().nonnegative(),queued:X.number().int().nonnegative(),generating:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),published:X.number().int().nonnegative(),needsOperator:X.number().int().nonnegative()}),failures:X.array(X.object({entityId:X.string(),entityType:X.string(),title:X.string(),error:X.string(),retryCount:X.number().int().nonnegative()})).default([]),managementUrl:X.string().optional()}),Ddx={crit:"error",critical:"error",high:"warn",med:"plain",medium:"plain",low:"muted"};function $dx(x){if(x===void 0||x===null||x==="")return!0;if(Array.isArray(x))return x.length===0;if(typeof x==="object")return Object.keys(x).length===0;return!1}function Zdx(x){if(typeof x==="object")return JSON.stringify(x);return String(x)}function rW0(x){let B=Adx.safeParse(x);if(!B.success||B.data.items.length===0)return[];return B.data.items}function Qdx(x){let B=wdx.safeParse(x);return B.success?B.data:null}function Xdx({widget:x}){if(x.widget.rendererName!=="ListWidget")return null;let B=rW0(x.data);if(B.length===0)return null;return v8("span",{class:"tab-badge tab-badge--muted",children:B.length},void 0,!1,void 0,this)}function Ydx({widget:x}){let B=Qdx(x.data);if(!B)return v8($2,{},void 0,!1,void 0,this);let A=Object.entries(B).filter(([w,f])=>!enx.has(w)&&!$dx(f));if(A.length===0)return v8($2,{},void 0,!1,void 0,this);return v8(EA,{items:A.map(([w,f])=>({label:aD(w),value:Zdx(f)}))},void 0,!1,void 0,this)}function Wdx({item:x}){let B=x.priority?Ddx[x.priority.toLowerCase()]??"plain":"plain",A=typeof x.count==="number"||Boolean(x.priority??x.status);return v8(dD,{title:x.name,description:x.description,meta:x.meta,tags:x.tags,trailing:A?v8(qdx,{children:[typeof x.count==="number"&&v8("span",{class:"list-count",children:x.count},void 0,!1,void 0,this),x.priority&&v8(LQ,{tone:B,children:x.priority},void 0,!1,void 0,this),x.status&&v8(LQ,{tone:"ok",children:x.status},void 0,!1,void 0,this)]},void 0,!0,void 0,this):void 0},void 0,!1,void 0,this)}function Hdx({widget:x}){let B=rW0(x.data);if(B.length===0)return v8($2,{},void 0,!1,void 0,this);return v8(nD,{children:B.map((A)=>v8(Wdx,{item:A},A.id,!1,void 0,this))},void 0,!1,void 0,this)}function sL({label:x,value:B,tone:A=""}){return v8("div",{class:`pipeline-metric${A?` pipeline-metric--${A}`:""}`,children:[v8("dt",{children:x},void 0,!1,void 0,this),v8("dd",{children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Fdx({widget:x}){let B=fdx.safeParse(x.data);if(!B.success)return v8($2,{},void 0,!1,void 0,this);let{summary:A,failures:w,managementUrl:f}=B.data;return v8("div",{class:"pipeline-digest",children:[v8("dl",{class:"pipeline-metrics",children:[v8(sL,{label:"Queued",value:A.queued},void 0,!1,void 0,this),v8(sL,{label:"Generating",value:A.generating},void 0,!1,void 0,this),v8(sL,{label:"Awaiting review",value:A.needsOperator,tone:A.needsOperator>0?"warn":""},void 0,!1,void 0,this),v8(sL,{label:"Published",value:A.published,tone:"ok"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w.length>0&&v8("section",{class:"pipeline-failures","aria-label":"Publication failures",children:[v8("h4",{children:"Needs attention"},void 0,!1,void 0,this),w.slice(0,3).map((D)=>v8("div",{class:"pipeline-failure",children:[v8("strong",{children:D.title},void 0,!1,void 0,this),v8("span",{children:D.error},void 0,!1,void 0,this)]},`${D.entityType}:${D.entityId}`,!0,void 0,this))]},void 0,!0,void 0,this),f&&v8(PQ,{label:"Publication actions",children:v8(JQ,{href:f,emphasis:"primary",children:"Open in CMS"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Kdx({widget:x}){if(x.component){let B=x.component;return v8(B,{title:x.widget.title,...x.widget.description?{description:x.widget.description}:{},data:x.data,pluginId:x.widget.pluginId,widgetId:x.widget.id,instanceId:qS(x.widget.pluginId,x.widget.id)},void 0,!1,void 0,this)}switch(x.widget.rendererName){case"PipelineWidget":return v8(Fdx,{widget:x},void 0,!1,void 0,this);case"ListWidget":return v8(Hdx,{widget:x},void 0,!1,void 0,this);default:return v8(Ydx,{widget:x},void 0,!1,void 0,this)}}function VS({widget:x,featured:B=!1}){let A=xdx.has(x.widget.rendererName);return v8("article",{class:B?"card card--entity-summary":`card${A?"":" widget-card--wide"}`,children:[v8(N5,{title:x.widget.title,children:v8(Xdx,{widget:x},void 0,!1,void 0,this)},void 0,!1,void 0,this),v8(Kdx,{widget:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as V1,Fragment as oW0}from"preact/jsx-dev-runtime";function tW0({tab:x,input:B,now:A}){let w=[...x.widgets.primary,...x.widgets.secondary],f=x.group==="system",D=x.group==="knowledge",$=x.widgets.sidebar.length>0||f;return V1("section",{id:x.id,class:"dashboard-tab-panel","data-dashboard-tab-panel":!0,"data-dashboard-group":x.group,"data-ui-panel":x.id,role:"tabpanel","aria-labelledby":`dashboard-tab-${x.id}`,children:[V1("header",{class:"tab-section-head",children:V1("h2",{children:x.label},void 0,!1,void 0,this)},void 0,!1,void 0,this),V1("div",{class:`layout tab-layout${$?"":" tab-layout--main-only"}`,children:[V1("div",{class:"main-column",children:[D&&V1(dW0,{total:B.appInfo.entities,entityCounts:B.appInfo.entityCounts},void 0,!1,void 0,this),f&&V1(oW0,{children:[V1(pW0,{input:B},void 0,!1,void 0,this),B.directorySyncStatus&&V1(uW0,{status:B.directorySyncStatus},void 0,!1,void 0,this),V1(SW0,{jobs:B.jobProgress??[]},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w.map((Z)=>V1(VS,{widget:Z},`${Z.widget.pluginId}:${Z.widget.id}`,!1,void 0,this))]},void 0,!0,void 0,this),$&&V1("div",{class:"sidebar-column",children:[f&&V1(oW0,{children:[V1(nW0,{endpoints:B.appInfo.endpoints,baseUrl:B.baseUrl},void 0,!1,void 0,this),V1(sW0,{appInfo:B.appInfo,now:A},void 0,!1,void 0,this),V1(aW0,{interactions:B.appInfo.interactions,baseUrl:B.baseUrl},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x.widgets.sidebar.map((Z)=>V1(VS,{widget:Z},`${Z.widget.pluginId}:${Z.widget.id}`,!1,void 0,this))]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as f9,Fragment as zdx}from"preact/jsx-dev-runtime";function eW0({input:x}){let B=hW0(x.widgets),A=x.authAccess!==void 0&&x.authAccess.hiddenWidgetCount>0,w=x.dashboardPath??"/dashboard",f=new Date;return f9("html",{lang:"en","data-climate":"instrument","data-theme":"dark",children:[f9("head",{children:[f9("meta",{charSet:"utf-8"},void 0,!1,void 0,this),f9("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0, viewport-fit=cover"},void 0,!1,void 0,this),f9("title",{children:x.title},void 0,!1,void 0,this),f9("script",{dangerouslySetInnerHTML:{__html:K3}},void 0,!1,void 0,this),f9("link",{rel:"preconnect",href:"https://fonts.googleapis.com"},void 0,!1,void 0,this),f9("link",{rel:"preconnect",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"},void 0,!1,void 0,this),f9("link",{href:dw,rel:"stylesheet"},void 0,!1,void 0,this),x.assetUrls?.themeStyles?f9("link",{"data-dashboard-theme":!0,rel:"stylesheet",href:x.assetUrls.themeStyles},void 0,!1,void 0,this):x.themeCSS!==void 0&&f9("style",{"data-dashboard-theme":!0,dangerouslySetInnerHTML:{__html:x.themeCSS}},void 0,!1,void 0,this),x.assetUrls?f9("link",{"data-dashboard-styles":!0,rel:"stylesheet",href:x.assetUrls.dashboardStyles},void 0,!1,void 0,this):f9("style",{"data-dashboard-styles":!0,dangerouslySetInnerHTML:{__html:TL}},void 0,!1,void 0,this),x.assetUrls?x.assetUrls.widgetStyles.map((D)=>f9("link",{"data-dashboard-widget-styles":!0,rel:"stylesheet",href:D},D,!1,void 0,this)):x.widgetStyles&&x.widgetStyles.length>0&&f9("style",{"data-dashboard-widget-styles":!0,dangerouslySetInnerHTML:{__html:x.widgetStyles.join(`
3796
3796
 
3797
3797
  `)}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),f9("body",{"data-auth-role":x.authAccess?.principal?.role,children:[f9(OW0,{dashboardPath:w,surfaces:x.surfaces??[{id:"dashboard",label:"Dashboard",href:w,isActive:!0}],authAccess:x.authAccess},void 0,!1,void 0,this),f9("main",{class:"console","data-component":"dashboard:dashboard",children:[f9("div",{class:"frame","data-ui-tabs":!0,"data-ui-tabs-default":"overview","data-ui-tabs-hash":"true",children:[f9(mW0,{title:x.title,tagline:x.profile.description},void 0,!1,void 0,this),f9(RW0,{tabs:B},void 0,!1,void 0,this),f9("div",{class:"canvas",children:f9("div",{class:"dashboard-tab-panels",children:[f9(lW0,{input:x,tabs:B,showAccessGate:A},void 0,!1,void 0,this),B.map((D)=>f9(tW0,{tab:D,input:x,now:f},D.id,!1,void 0,this))]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),f9(NW0,{title:x.title,appInfo:x.appInfo,baseUrl:x.baseUrl},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x.assetUrls?f9("script",{"data-dashboard-script":!0,src:x.assetUrls.dashboardScript},void 0,!1,void 0,this):f9(zdx,{children:[f9("script",{dangerouslySetInnerHTML:{__html:D2}},void 0,!1,void 0,this),f9("script",{dangerouslySetInnerHTML:{__html:pL}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x.assetUrls?x.assetUrls.widgetScripts.map((D)=>f9("script",{"data-dashboard-widget-script":!0,src:D},D,!1,void 0,this)):x.widgetScripts.map((D,$)=>f9("script",{dangerouslySetInnerHTML:{__html:D}},`widget-script:${$}`,!1,void 0,this))]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as Vdx}from"preact/jsx-dev-runtime";function US(x){return`<!doctype html>
3798
- ${bdx(Vdx(eW0,{input:x},void 0,!1,void 0,this))}`}function Udx(x){return x.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"group"}function xH0(x){let B=x.query.trim().toLowerCase(),A=[];if(x.adminPath!==void 0&&(B===""||"admin people access identity".includes(B)))A.push({id:"surfaces",label:"Console",items:[{id:"surface/admin",title:"Admin",sub:"People, access and identity",href:x.adminPath,tag:"console"}]});if(x.cmsPath!==void 0&&x.entities.length>0){let f=x.cmsPath;A.push({id:"entities",label:"Entities",items:x.entities.map((D)=>({id:`${D.entityType}/${D.id}`,title:D.title,sub:D.entityType,href:`${f==="/"?"":f.replace(/\/+$/,"")}/entities/${encodeURIComponent(D.entityType)}/${encodeURIComponent(D.id)}`,tag:"edit in cms"}))})}let w=iL([...new Set(x.groups)]).map((f)=>({group:f,label:SH(f)})).filter(({group:f,label:D})=>B===""||D.toLowerCase().includes(B)||f.toLowerCase().includes(B)).map(({group:f,label:D})=>({id:`tab/${f}`,title:D,sub:"tab",href:`${x.dashboardPath}#${Udx(f)}`,tag:"dashboard"}));if(w.length>0)A.push({id:"tabs",label:"Dashboard",items:w});return A}function BH0(x,B){let A={},w=new Set,f=new Set;for(let[D,$]of Object.entries(x)){let Z=B?.get($.widget.pluginId,$.widget.id);if(A[D]={...$,...Z?.component?{component:Z.component}:{}},Z?.clientStyles)w.add(Z.clientStyles);if(Z?.clientScript)f.add(Z.clientScript)}return{widgets:A,widgetStyles:Array.from(w),widgetScripts:Array.from(f)}}var AH0={name:"@brains/dashboard",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Dashboard plugin with extensible widget system",dependencies:{"@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2","preact-render-to-string":"^6.7.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0","happy-dom":"^20.10.6",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Edx=X.object({version:X.string().default("1.0.0"),routePath:X.string().default("/dashboard"),themeCSS:X.string().optional()}),jdx=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),group:X.string().min(1),priority:X.number().default(50),section:X.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:X.string(),visibility:X.enum(["public","trusted","admin"]).default("public"),needsAttention:X.number().int().nonnegative().optional(),needsOperator:X.number().int().nonnegative().optional(),digest:X.array(X.object({label:X.string(),value:X.string(),tone:X.enum(["plain","good","warn"]).optional()})).max(4).optional(),component:X.custom().optional(),clientStyles:X.string().optional(),clientScript:X.string().optional(),dataProvider:X.custom((x)=>typeof x==="function",{message:"Expected dashboard widget data provider function"}),digestProvider:X.custom((x)=>typeof x==="function",{message:"Expected dashboard widget digest provider function"}).optional()}).superRefine((x,B)=>{if(!WS(x.rendererName)&&!x.component)B.addIssue({code:"custom",message:"Custom dashboard widgets must register a Preact component.",path:["component"]})}).transform(({needsOperator:x,...B})=>({...B,...B.needsAttention===void 0&&x!==void 0?{needsAttention:x}:{}})),_dx=X.object({pluginId:X.string(),widgetId:X.string().optional()}),Pdx=X.object({entityType:X.string(),entityId:X.string(),conversationId:X.string().optional()}),Jdx=X.object({id:X.string(),type:X.enum(["job","batch"]),status:X.enum(["pending","processing","completed","failed"]),message:X.string().optional(),progress:X.object({current:X.number(),total:X.number(),percentage:X.number()}).optional(),jobDetails:X.object({jobType:X.string(),priority:X.number(),retryCount:X.number()}).optional()}),Ldx=X.object({success:X.literal(!0),data:X.object({syncPath:X.string(),isInitialized:X.boolean(),watchEnabled:X.boolean(),lastSync:X.string().datetime().nullable().optional().transform((x)=>x??void 0),totalFiles:X.number().int().nonnegative().optional(),byEntityType:X.record(X.string(),X.number().int().nonnegative()).optional(),managementUrl:X.string().optional()})});function kdx(x){return{id:x.id,pluginId:x.pluginId,title:x.title,...x.description?{description:x.description}:{},group:x.group,priority:x.priority,section:x.section,rendererName:x.rendererName,visibility:x.visibility,...x.needsAttention!==void 0&&{needsAttention:x.needsAttention},...x.digest?{digest:x.digest}:{},...x.component?{component:x.component}:{},...x.clientStyles?{clientStyles:x.clientStyles}:{},...x.clientScript?{clientScript:x.clientScript}:{},dataProvider:x.dataProvider,...x.digestProvider?{digestProvider:x.digestProvider}:{}}}class ES extends D8{assetRegistry;widgetRegistry=null;datasource=null;siteUrl;ctx;activityLog=[];jobProgress=[];constructor(x={}){super("dashboard",AH0,x,Edx);this.assetRegistry=new HS(this.config.routePath)}recordActivity(x,B){let A=Pdx.safeParse(B);if(!A.success)return;this.activityLog=[{action:x,entityType:A.data.entityType,entityId:A.data.entityId,timestamp:new Date().toISOString(),...A.data.conversationId?{conversationId:A.data.conversationId}:{}},...this.activityLog].slice(0,12)}recordJobProgress(x){let B=Jdx.safeParse(x);if(!B.success)return;let A=B.data.progress?`${B.data.progress.current}/${B.data.progress.total}`:void 0,w={id:B.data.id,kind:B.data.type,status:B.data.status,updatedAt:new Date().toISOString(),...B.data.message?{message:B.data.message}:{},...B.data.jobDetails?.jobType?{jobType:B.data.jobDetails.jobType}:{},...A?{progressLabel:A}:{}};this.jobProgress=[w,...this.jobProgress.filter((f)=>f.id!==w.id||f.kind!==w.kind)].slice(0,8)}async getIndexStatus(){if(!this.ctx)return;let x=this.ctx.entityService;try{if(typeof x.awaitIndexReady==="function")return await x.awaitIndexReady({timeoutMs:0,intervalMs:0});if(typeof x.isIndexReady==="function")return{ready:x.isIndexReady()}}catch(B){this.logger.debug("Semantic index status unavailable",{error:g(B)})}return}async getDirectorySyncStatus(){if(!this.ctx)return;try{let x=await this.ctx.messaging.send({type:HB.statusRequest,payload:{}}),B=Ldx.safeParse(x);return B.success?B.data.data:void 0}catch(x){this.logger.debug("Directory sync status unavailable",{error:g(x)});return}}async onRegister(x){this.siteUrl=x.siteUrl,this.ctx=x,this.widgetRegistry=new gL(this.logger),this.datasource=new uL(this.widgetRegistry,this.logger),x.entities.registerDataSource(this.datasource),x.endpoints.register({label:"Dashboard",url:this.config.routePath,priority:30,visibility:"public"}),x.interactions.register({id:"dashboard",label:"Dashboard",description:"Inspect runtime status, endpoints, and dashboard widgets.",href:this.config.routePath,kind:"admin",priority:30,visibility:"public"}),x.messaging.subscribe(l8.created,async(B)=>{return this.recordActivity("created",B.payload),{success:!0}}),x.messaging.subscribe(l8.updated,async(B)=>{return this.recordActivity("updated",B.payload),{success:!0}}),x.messaging.subscribe(l8.deleted,async(B)=>{return this.recordActivity("deleted",B.payload),{success:!0}}),x.messaging.subscribe(rL.progress,async(B)=>{return this.recordJobProgress(B.payload),{success:!0}}),x.messaging.subscribe(GS.registerWidget,async(B)=>{try{let A=jdx.parse(B.payload),w=kdx(A);return this.widgetRegistry?.register(w),this.logger.debug("Widget registered via messaging",{widgetId:A.id,pluginId:A.pluginId,rendererName:A.rendererName,builtIn:cL.includes(A.rendererName)}),{success:!0}}catch(A){return this.logger.error("Failed to register widget",{error:g(A),payload:B.payload}),{success:!1,error:"Widget registration failed"}}}),x.messaging.subscribe(GS.unregisterWidget,async(B)=>{try{let A=_dx.parse(B.payload);return this.widgetRegistry?.unregister(A.pluginId,A.widgetId),this.logger.debug("Widget unregistered via messaging",{pluginId:A.pluginId,widgetId:A.widgetId}),{success:!0}}catch(A){return this.logger.error("Failed to unregister widget",{error:g(A),payload:B.payload}),{success:!1,error:"Widget unregistration failed"}}}),this.logger.info("Dashboard plugin registered")}getWebRoutes(){return[{path:this.config.routePath,method:"GET",public:!0,handler:async(x)=>{if(!this.datasource||!this.ctx)return new Response("Dashboard unavailable",{status:503,headers:{"Content-Type":"text/plain; charset=utf-8"}});let B=this.ctx,A=await X6()?.resolveSession(x),w=A?.permissionLevel??"public",f=this.widgetRegistry?.list({permissionLevel:"admin"})??[],D=f.filter((y)=>_7.hasPermission(w,y.visibility)),$=f.length-D.length,[Z,Q,Y,W]=await Promise.all([this.datasource.getDashboardData({permissionLevel:w,widgets:D}),B.appInfo(),this.getDirectorySyncStatus(),this.getIndexStatus()]),H=B.identity.get(),F=B.identity.getProfile(),K=this.siteUrl??(()=>{try{return new URL(x.url).origin}catch{return}})(),q={...Q,endpoints:Q.endpoints.filter((y)=>_7.hasPermission(w,y.visibility)),interactions:Q.interactions.filter((y)=>_7.hasPermission(w,y.visibility))},V=F.name||Q.model||"Brain Dashboard",b=new URL(x.url),G=`${b.pathname}${b.search}`,E=encodeURIComponent(G),_=BH0(Z.widgets,this.widgetRegistry),L=this.assetRegistry.createRenderUrls({themeCSS:this.config.themeCSS,widgetStyles:_.widgetStyles,widgetScripts:_.widgetScripts}),N={title:V,baseUrl:K,widgets:_.widgets,widgetStyles:_.widgetStyles,widgetScripts:_.widgetScripts,assetUrls:L,dashboardPath:this.config.routePath,surfaces:YB(B.webRoutes.getRoutes(),{activeId:"dashboard",permissionLevel:w,self:{id:"dashboard",href:this.config.routePath}}),character:H,profile:F,appInfo:q,activityLog:this.activityLog,jobProgress:this.jobProgress,...W!==void 0&&{indexStatus:W},...Y!==void 0&&{directorySyncStatus:Y},...this.config.themeCSS!==void 0&&{themeCSS:this.config.themeCSS},authAccess:{...A?{principal:{displayName:A.displayName,role:A.role,permissionLevel:A.permissionLevel}}:{},hiddenWidgetCount:$,loginUrl:`/login?return_to=${E}`,logoutUrl:`/logout?return_to=${E}`}};return new Response(US(N),{headers:{"Cache-Control":"private, no-store","Content-Type":"text/html; charset=utf-8"}})}},{path:"/api/console/jump",method:"GET",public:!0,handler:async(x)=>{let B=await X6()?.resolveSession(x);if(!B)return Response.json({error:"Authentication required"},{status:401});if(B.permissionLevel!=="admin")return Response.json({error:"Admin access required"},{status:403});let A=this.ctx;if(!A)return Response.json({groups:[]});let w=new URL(x.url).searchParams.get("q")?.trim()??"",f=[];if(w.length>=2)try{f=(await A.entityService.search({query:w,options:{limit:6}})).map((W)=>({entityType:W.entity.entityType,id:W.entity.id,title:W.entity.title??W.entity.id}))}catch{}let D=(this.widgetRegistry?.list({permissionLevel:"admin"})??[]).map((Y)=>Y.group),$=YB(A.webRoutes.getRoutes(),{activeId:"dashboard",permissionLevel:B.permissionLevel}),Z=$.find((Y)=>Y.id==="cms")?.href,Q=$.find((Y)=>Y.id==="admin")?.href;return Response.json({groups:xH0({query:w,groups:[...D,"knowledge","system"],dashboardPath:this.config.routePath,cmsPath:Z,adminPath:Q,entities:f})})}},...this.assetRegistry.getRoutes()]}async getTools(){return[]}getWidgetRegistry(){return this.widgetRegistry}}function jS(x={}){return new ES(x)}var Mdx=X.enum(["public","trusted","admin"]),vdx=X.object({label:X.string(),value:X.string(),tone:X.enum(["plain","good","warn"]).optional()}),Ndx=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),group:X.string().min(1),priority:X.number(),section:X.enum(["primary","secondary","sidebar"]),rendererName:X.string(),visibility:Mdx,needsAttention:X.number().int().nonnegative().optional(),digest:X.array(vdx).max(4).optional(),component:X.custom().optional()}),Idx=X.object({widget:Ndx,data:X.unknown()}),Odx=X.object({widgets:X.record(X.string(),Idx)});var _S=`/* Compatibility aliases for agent-network widgets authored before the generic
3798
+ ${bdx(Vdx(eW0,{input:x},void 0,!1,void 0,this))}`}function Udx(x){return x.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"group"}function xH0(x){let B=x.query.trim().toLowerCase(),A=[];if(x.adminPath!==void 0&&(B===""||"admin people access identity".includes(B)))A.push({id:"surfaces",label:"Console",items:[{id:"surface/admin",title:"Admin",sub:"People, access and identity",href:x.adminPath,tag:"console"}]});if(x.cmsPath!==void 0&&x.entities.length>0){let f=x.cmsPath;A.push({id:"entities",label:"Entities",items:x.entities.map((D)=>({id:`${D.entityType}/${D.id}`,title:D.title,sub:D.entityType,href:`${f==="/"?"":f.replace(/\/+$/,"")}/entities/${encodeURIComponent(D.entityType)}/${encodeURIComponent(D.id)}`,tag:"edit in cms"}))})}let w=iL([...new Set(x.groups)]).map((f)=>({group:f,label:SH(f)})).filter(({group:f,label:D})=>B===""||D.toLowerCase().includes(B)||f.toLowerCase().includes(B)).map(({group:f,label:D})=>({id:`tab/${f}`,title:D,sub:"tab",href:`${x.dashboardPath}#${Udx(f)}`,tag:"dashboard"}));if(w.length>0)A.push({id:"tabs",label:"Dashboard",items:w});return A}function BH0(x,B){let A={},w=new Set,f=new Set;for(let[D,$]of Object.entries(x)){let Z=B?.get($.widget.pluginId,$.widget.id);if(A[D]={...$,...Z?.component?{component:Z.component}:{}},Z?.clientStyles)w.add(Z.clientStyles);if(Z?.clientScript)f.add(Z.clientScript)}return{widgets:A,widgetStyles:Array.from(w),widgetScripts:Array.from(f)}}var AH0={name:"@brains/dashboard",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Dashboard plugin with extensible widget system",dependencies:{"@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2","preact-render-to-string":"^6.7.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0","happy-dom":"^20.10.6",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Edx=X.object({version:X.string().default("1.0.0"),routePath:X.string().default("/dashboard"),themeCSS:X.string().optional()}),jdx=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),group:X.string().min(1),priority:X.number().default(50),section:X.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:X.string(),visibility:X.enum(["public","trusted","admin"]).default("public"),needsAttention:X.number().int().nonnegative().optional(),needsOperator:X.number().int().nonnegative().optional(),digest:X.array(X.object({label:X.string(),value:X.string(),tone:X.enum(["plain","good","warn"]).optional()})).max(4).optional(),component:X.custom().optional(),clientStyles:X.string().optional(),clientScript:X.string().optional(),dataProvider:X.custom((x)=>typeof x==="function",{message:"Expected dashboard widget data provider function"}),digestProvider:X.custom((x)=>typeof x==="function",{message:"Expected dashboard widget digest provider function"}).optional()}).superRefine((x,B)=>{if(!WS(x.rendererName)&&!x.component)B.addIssue({code:"custom",message:"Custom dashboard widgets must register a Preact component.",path:["component"]})}).transform(({needsOperator:x,...B})=>({...B,...B.needsAttention===void 0&&x!==void 0?{needsAttention:x}:{}})),_dx=X.object({pluginId:X.string(),widgetId:X.string().optional()}),Pdx=X.object({entityType:X.string(),entityId:X.string(),conversationId:X.string().optional()}),Jdx=X.object({id:X.string(),type:X.enum(["job","batch"]),status:X.enum(["pending","processing","completed","failed"]),message:X.string().optional(),progress:X.object({current:X.number(),total:X.number(),percentage:X.number()}).optional(),jobDetails:X.object({jobType:X.string(),priority:X.number(),retryCount:X.number()}).optional()}),Ldx=X.object({success:X.literal(!0),data:X.object({syncPath:X.string(),isInitialized:X.boolean(),watchEnabled:X.boolean(),lastSync:X.string().datetime().nullable().optional().transform((x)=>x??void 0),totalFiles:X.number().int().nonnegative().optional(),byEntityType:X.record(X.string(),X.number().int().nonnegative()).optional(),managementUrl:X.string().optional()})});function kdx(x){return{id:x.id,pluginId:x.pluginId,title:x.title,...x.description?{description:x.description}:{},group:x.group,priority:x.priority,section:x.section,rendererName:x.rendererName,visibility:x.visibility,...x.needsAttention!==void 0&&{needsAttention:x.needsAttention},...x.digest?{digest:x.digest}:{},...x.component?{component:x.component}:{},...x.clientStyles?{clientStyles:x.clientStyles}:{},...x.clientScript?{clientScript:x.clientScript}:{},dataProvider:x.dataProvider,...x.digestProvider?{digestProvider:x.digestProvider}:{}}}class ES extends D8{assetRegistry;widgetRegistry=null;datasource=null;siteUrl;ctx;activityLog=[];jobProgress=[];constructor(x={}){super("dashboard",AH0,x,Edx);this.assetRegistry=new HS(this.config.routePath)}recordActivity(x,B){let A=Pdx.safeParse(B);if(!A.success)return;this.activityLog=[{action:x,entityType:A.data.entityType,entityId:A.data.entityId,timestamp:new Date().toISOString(),...A.data.conversationId?{conversationId:A.data.conversationId}:{}},...this.activityLog].slice(0,12)}recordJobProgress(x){let B=Jdx.safeParse(x);if(!B.success)return;let A=B.data.progress?`${B.data.progress.current}/${B.data.progress.total}`:void 0,w={id:B.data.id,kind:B.data.type,status:B.data.status,updatedAt:new Date().toISOString(),...B.data.message?{message:B.data.message}:{},...B.data.jobDetails?.jobType?{jobType:B.data.jobDetails.jobType}:{},...A?{progressLabel:A}:{}};this.jobProgress=[w,...this.jobProgress.filter((f)=>f.id!==w.id||f.kind!==w.kind)].slice(0,8)}async getIndexStatus(){if(!this.ctx)return;let x=this.ctx.entityService;try{if(typeof x.awaitIndexReady==="function")return await x.awaitIndexReady({timeoutMs:0,intervalMs:0});if(typeof x.isIndexReady==="function")return{ready:x.isIndexReady()}}catch(B){this.logger.debug("Semantic index status unavailable",{error:g(B)})}return}async getDirectorySyncStatus(){if(!this.ctx)return;try{let x=await this.ctx.messaging.send({type:HB.statusRequest,payload:{}}),B=Ldx.safeParse(x);return B.success?B.data.data:void 0}catch(x){this.logger.debug("Directory sync status unavailable",{error:g(x)});return}}async onRegister(x){this.siteUrl=x.siteUrl,this.ctx=x,this.widgetRegistry=new gL(this.logger),this.datasource=new uL(this.widgetRegistry,this.logger),x.entities.registerDataSource(this.datasource),x.endpoints.register({label:"Dashboard",url:this.config.routePath,priority:30,visibility:"public"}),x.interactions.register({id:"dashboard",label:"Dashboard",description:"Inspect runtime status, endpoints, and dashboard widgets.",href:this.config.routePath,kind:"admin",priority:30,visibility:"public"}),x.messaging.subscribe(l8.created,async(B)=>{return this.recordActivity("created",B.payload),{success:!0}}),x.messaging.subscribe(l8.updated,async(B)=>{return this.recordActivity("updated",B.payload),{success:!0}}),x.messaging.subscribe(l8.deleted,async(B)=>{return this.recordActivity("deleted",B.payload),{success:!0}}),x.messaging.subscribe(rL.progress,async(B)=>{return this.recordJobProgress(B.payload),{success:!0}}),x.messaging.subscribe(GS.registerWidget,async(B)=>{try{let A=jdx.parse(B.payload),w=kdx(A);return this.widgetRegistry?.register(w),this.logger.debug("Widget registered via messaging",{widgetId:A.id,pluginId:A.pluginId,rendererName:A.rendererName,builtIn:cL.includes(A.rendererName)}),{success:!0}}catch(A){return this.logger.error("Failed to register widget",{error:g(A),payload:B.payload}),{success:!1,error:"Widget registration failed"}}}),x.messaging.subscribe(GS.unregisterWidget,async(B)=>{try{let A=_dx.parse(B.payload);return this.widgetRegistry?.unregister(A.pluginId,A.widgetId),this.logger.debug("Widget unregistered via messaging",{pluginId:A.pluginId,widgetId:A.widgetId}),{success:!0}}catch(A){return this.logger.error("Failed to unregister widget",{error:g(A),payload:B.payload}),{success:!1,error:"Widget unregistration failed"}}}),this.logger.info("Dashboard plugin registered")}getWebRoutes(){return[{path:this.config.routePath,method:"GET",public:!0,handler:async(x)=>{if(!this.datasource||!this.ctx)return new Response("Dashboard unavailable",{status:503,headers:{"Content-Type":"text/plain; charset=utf-8"}});let B=this.ctx,A=await X6()?.resolveSession(x),w=A?.permissionLevel??"public",f=this.widgetRegistry?.list({permissionLevel:"admin"})??[],D=f.filter((y)=>_7.hasPermission(w,y.visibility)),$=f.length-D.length,[Z,Q,Y,W]=await Promise.all([this.datasource.getDashboardData({permissionLevel:w,widgets:D}),B.appInfo(),this.getDirectorySyncStatus(),this.getIndexStatus()]),H=B.identity.get(),F=B.identity.getProfile(),K=this.siteUrl??(()=>{try{return new URL(x.url).origin}catch{return}})(),q={...Q,endpoints:Q.endpoints.filter((y)=>_7.hasPermission(w,y.visibility)),interactions:Q.interactions.filter((y)=>_7.hasPermission(w,y.visibility))},V=F.name||Q.model||"Brain Dashboard",b=new URL(x.url),G=`${b.pathname}${b.search}`,E=encodeURIComponent(G),_=BH0(Z.widgets,this.widgetRegistry),L=this.assetRegistry.createRenderUrls({themeCSS:this.config.themeCSS,widgetStyles:_.widgetStyles,widgetScripts:_.widgetScripts}),N={title:V,baseUrl:K,widgets:_.widgets,widgetStyles:_.widgetStyles,widgetScripts:_.widgetScripts,assetUrls:L,dashboardPath:this.config.routePath,surfaces:YB(B.webRoutes.getRoutes(),{activeId:"dashboard",permissionLevel:w,self:{id:"dashboard",href:this.config.routePath}}),character:H,profile:F,appInfo:q,activityLog:this.activityLog,jobProgress:this.jobProgress,...W!==void 0&&{indexStatus:W},...Y!==void 0&&{directorySyncStatus:Y},...this.config.themeCSS!==void 0&&{themeCSS:this.config.themeCSS},authAccess:{...A?{principal:{displayName:A.displayName,role:A.role,permissionLevel:A.permissionLevel}}:{},hiddenWidgetCount:$,loginUrl:`/login?return_to=${E}`,logoutUrl:`/logout?return_to=${E}`}};return new Response(US(N),{headers:{"Cache-Control":"private, no-store","Content-Type":"text/html; charset=utf-8"}})}},{path:"/api/console/jump",method:"GET",public:!0,handler:async(x)=>{let B=await X6()?.resolveSession(x);if(!B)return Response.json({error:"Authentication required"},{status:401});if(B.permissionLevel!=="admin")return Response.json({error:"Admin access required"},{status:403});let A=this.ctx;if(!A)return Response.json({groups:[]});let w=new URL(x.url).searchParams.get("q")?.trim()??"",f=[];if(w.length>=2)try{f=(await A.entityService.search({query:w,options:{limit:6}})).map((W)=>({entityType:W.entity.entityType,id:W.entity.id,title:W.entity.title??W.entity.id}))}catch{}let D=(this.widgetRegistry?.list({permissionLevel:"admin"})??[]).map((Y)=>Y.group),$=YB(A.webRoutes.getRoutes(),{activeId:"dashboard",permissionLevel:B.permissionLevel}),Z=$.find((Y)=>Y.id==="cms")?.href,Q=$.find((Y)=>Y.id==="admin")?.href;return Response.json({groups:xH0({query:w,groups:[...D,"knowledge","system"],dashboardPath:this.config.routePath,cmsPath:Z,adminPath:Q,entities:f})})}},...this.assetRegistry.getRoutes()]}async getTools(){return[]}getWidgetRegistry(){return this.widgetRegistry}}function jS(x={}){return new ES(x)}var Mdx=X.enum(["public","trusted","admin"]),vdx=X.object({label:X.string(),value:X.string(),tone:X.enum(["plain","good","warn"]).optional()}),Ndx=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),group:X.string().min(1),priority:X.number(),section:X.enum(["primary","secondary","sidebar"]),rendererName:X.string(),visibility:Mdx,needsAttention:X.number().int().nonnegative().optional(),digest:X.array(vdx).max(4).optional(),component:X.custom().optional()}),Idx=X.object({widget:Ndx,data:X.unknown()}),Odx=X.object({widgets:X.record(X.string(),Idx)});var _S=`/* Compatibility aliases for agent-network widgets authored before the generic
3799
3799
  widget control classes. Current markup uses .widget-* primitives. */
3800
3800
  .agent-network-view-tabs {
3801
3801
  display: flex;
@@ -4801,7 +4801,7 @@ ${bdx(Vdx(eW0,{input:x},void 0,!1,void 0,this))}`}function Udx(x){return x.trim(
4801
4801
  /* the shimmer delay is inlined per node, so the override needs force */
4802
4802
  .agent-proximity-site .proximity-agent { animation: none !important; }
4803
4803
  }
4804
- `,rH={kicker:"Agent network",headingLead:"The rhizome grows",headingAccent:"beneath this brain",lede:"Every agent this brain has met, mapped by how close its work runs to ours \u2014 distance measured in meaning, not geography. Threads thicken where practices touch; where several lights gather, a constellation forms.",ctaLabel:"Meet the agents",ctaHref:"/agents"};function Max(x){return x.split(/\*([^*]+)\*/g).map((B,A)=>A%2===1?O5("b",{children:B},B,!1,void 0,this):B)}function IS(x){let B=x.nodes.filter((Q)=>Q.status!=="archived").length,A=x.kicker??rH.kicker,w=x.headingLead??rH.headingLead,f=x.headingAccent??rH.headingAccent,D=x.lede??rH.lede,$=x.ctaLabel??rH.ctaLabel,Z=x.ctaHref??rH.ctaHref;return O5("section",{class:"agent-proximity-site","aria-label":"Agent proximity map",children:[O5("style",{children:kax},void 0,!1,void 0,this),O5("div",{class:"agent-proximity-site__grid",children:[O5("div",{class:"agent-proximity-site__copy",children:[O5("p",{class:"agent-proximity-site__kicker",children:A},void 0,!1,void 0,this),O5("h2",{class:"agent-proximity-site__heading",children:[w," ",O5("em",{children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this),O5("p",{class:"agent-proximity-site__lede",children:Max(D)},void 0,!1,void 0,this),O5("a",{class:"agent-proximity-site__cta",href:Z,children:$},void 0,!1,void 0,this),x.pendingCount>0&&O5("p",{class:"agent-proximity-site__note",children:[x.pendingCount," pending semantic indexing"]},void 0,!0,void 0,this),x.center.kind==="centroid"&&O5("p",{class:"agent-proximity-site__note",children:"Identity not indexed yet \u2014 using network centroid"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),O5("div",{class:"agent-proximity-site__map",children:[O5(xk,{data:x,surface:"site"},void 0,!1,void 0,this),O5("div",{class:"agent-proximity-site__foot","aria-label":"Network summary",children:[O5("span",{class:"agent-proximity-site__count",children:[O5("b",{children:B},void 0,!1,void 0,this)," agents \xB7 ",O5("b",{children:x.clusters.length},void 0,!1,void 0,this)," ","constellations discovered"]},void 0,!0,void 0,this),O5("span",{class:"agent-proximity-site__live",children:"the map is live"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var vax=X.enum(["discovered","approved","archived"]),Zk=RL,Nax=X.object({agents:X.array(Zk),pageTitle:X.string().nullable().default(null),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null),selectedStatus:X.union([X.literal("all"),vax])}),_H0="/scripts/agent-proximity-map.js",Iax=new q9(WW0,{title:"Network",mappings:[{key:"kicker",label:"Kicker",type:"string"},{key:"headingLead",label:"Heading Lead",type:"string"},{key:"headingAccent",label:"Heading Accent",type:"string"},{key:"lede",label:"Lede",type:"string"},{key:"ctaLabel",label:"Cta Label",type:"string"},{key:"ctaHref",label:"Cta Href",type:"string"}]});function PH0(){return{[AS]:mx({name:AS,description:"Semantic agent proximity map site section",schema:rw,dataSourceId:IL,overlayFormatter:Iax,requiredPermission:"public",runtimeScripts:[{src:_H0,defer:!0}],staticAssets:{[_H0]:nH},layout:{component:IS}}),[wS]:mx({name:wS,description:"Agent directory list page template",schema:Nax,dataSourceId:OV,requiredPermission:"public",layout:{component:GH0}}),[fS]:mx({name:fS,description:"Individual agent profile template",schema:X.object({agent:Zk,prevAgent:Zk.nullable(),nextAgent:Zk.nullable()}),dataSourceId:OV,requiredPermission:"public",layout:{component:jH0}})}}var oH={name:"@brains/agent-discovery",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Agent discovery \u2014 brain+anchor contacts and skills",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/auth-service":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/http-signatures":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var hax=new Y5;class OS extends g8{entityType=U9;schema=hV;adapter=hax;fetchFn;resolveHostname;constructor(x,B){super(sY0,oH,{},qB);this.fetchFn=x,this.resolveHostname=B}getEntityTypeConfig(){return{projectionSourceRole:"supporting"}}createGenerationHandler(x){return new QS(this.logger.child("AgentGenerationJobHandler"),x)}getTemplates(){return PH0()}getDataSources(){return[new yL(this.logger.child("AgentDataSource")),new CL]}async onRegister(x){KH0(x),x.recurringChecks.register({id:"agent-card-refresh",cadence:"daily",deliverAlerts:!1,run:async({signal:B})=>{return await FH0(x,this.fetchFn,B,new Date().toISOString(),this.resolveHostname),{}}}),ZH0(x)}async getInstructions(){return qH0()}}function hS(){return new OS}var JH0=X.object({source:X.object({kind:X.literal("url"),url:X.string().min(1).describe("Remote agent domain or URL to verify and connect. Preserve bare domains as bare domains.")}),confirmed:X.boolean().optional(),confirmationToken:X.string().optional()}),Rax=new Y5;function yax(x){let B=ow(x);if(!B)return null;return{domain:B,fetchTarget:x.trim().startsWith("http")?x.trim():B}}function max(x,B){return(ow(B)||x).toLowerCase()}async function Cax(x){let{context:B,entityId:A,card:w}=x,f=new Date().toISOString(),D=await B.entityService.getEntity({entityType:U9,id:A}),$=pH(w,{status:"approved"}),Q={...Rax.fromMarkdown($.content).metadata,...$.metadata,a2aEndpoint:w.url};if(D){let W={...D,content:$.content,metadata:Q,updated:f};return await B.entityService.updateEntity({entity:W}),{entity:W,created:!1}}let Y={id:A,entityType:U9,content:$.content,metadata:Q,contentHash:"",visibility:"public",created:f,updated:f};return await B.entityService.createEntity({entity:Y}),{entity:Y,created:!0}}function LH0(x,B=globalThis.fetch){let w=new Qk;return{name:"agent_connect",description:"Verify and connect a remote A2A agent by fetching its Agent Card from /.well-known/agent-card.json, then save the verified contact in the local agent directory as approved for future outbound calls. Never use this tool for a request to approve or archive an existing saved contact; update that contact's status with system_update instead. This adds a directory contact; it does not message the remote agent or grant it inbound trusted access. Requires confirmation before verification and persistence. Call this tool without confirmed on the initial request; the tool returns confirmation args for the user to approve.",inputSchema:JH0.shape,visibility:"trusted",sideEffects:"external",handler:async(f,D)=>{let $=JH0.safeParse(f);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.issues.map((W)=>`${W.path.join(".")}: ${W.message}`).join(", ")}`};let Z=$.data,Q=yax(Z.source.url);if(!Q)return{success:!1,error:"Provide a valid remote agent domain or URL to connect.",code:"invalid_agent_url"};try{x.permissions.assertEntityActionAllowed(U9,"create",D)}catch(W){return{success:!1,error:g(W)}}if(Z.confirmed){let W=Z.confirmationToken,H=w.validate(W,Z);if(H.status==="missing")return{success:!1,error:"No pending agent connection confirmation found. Please request connection again and confirm the new approval."};if(H.status==="mismatch")return{success:!1,error:"Confirmed agent connection arguments do not match the pending approval. Please request connection again and confirm the new approval."};let F=await TH(Q.fetchTarget,B);if(!F)return{success:!1,error:`Could not verify an A2A Agent Card for ${Q.domain}.`,code:"not_an_agent"};let K=max(Q.domain,F.url),{entity:q,created:V}=await Cax({context:x,entityId:K,sourceUrl:Z.source.url,card:F});return{success:!0,data:{status:q.metadata.status,entityId:q.id,connected:!0,created:V,a2aEndpoint:F.url,skills:F.skills.map((b)=>({name:b.name,description:b.description,tags:b.tags}))}}}let Y=w.create((W)=>({source:Z.source,confirmed:!0,confirmationToken:W}));return{needsConfirmation:!0,toolName:"agent_connect",summary:`Verify and connect agent ${Q.domain}?`,preview:`This will fetch and validate ${Q.domain}'s A2A Agent Card, then save the verified contact as approved for future outbound calls. It will not message the remote agent or grant it inbound trusted access.`,args:Y}}}}var kH0=X.object({}),cax=X.object({agents:X.array(X.object({name:X.string(),url:X.string()}))}),RS=new Y5;async function gax(x,B,A){let w=`https://${x}/.well-known/agent-directory.json`;try{let f=await B(w,A?{signal:A}:void 0);if(!f.ok)return null;let D=cax.safeParse(await f.json());return D.success?D.data:null}catch{if(A?.aborted)throw A.reason;return null}}async function yS(x,B=globalThis.fetch,A){let w=await x.entityService.listEntities({entityType:U9}),f=w.filter((b)=>b.metadata.status==="approved"),D=x.domain?.toLowerCase(),$=new Map,Z=0;for(let b of f){A?.throwIfAborted();let G=await gax(b.id,B,A);if(!G){Z+=1;continue}for(let E of G.agents){let _=ow(E.url).toLowerCase();if(!_||_===D||_===b.id)continue;let L=$.get(_)??new Set;L.add(b.id),$.set(_,L)}}let Q=new Map(w.map((b)=>[b.id,b])),Y=new Date().toISOString(),W=[],H=new Set,F=0,K=0,q=0,V=0;for(let[b,G]of $){A?.throwIfAborted();let E=Q.get(b);if(E){let{frontmatter:y,body:c}=RS.parseEntity(E),n=y.introducedBy??[];if(y.status!=="discovered"||n.length===0){q+=1;continue}let R=[...n,...[...G].filter((M)=>!n.includes(M))];if(R.length===n.length)continue;await x.entityService.updateEntity({entity:{...E,content:RS.createAgentContent({...y,introducedBy:R,about:c.about,skills:c.skills,notes:c.notes}),updated:Y}}),K+=1;continue}let _=await TH(b,B,A);if(!_){V+=1;continue}let L=pH(_,{status:"discovered",provenance:{introducedBy:[...G],hops:2}}),N=RS.fromMarkdown(L.content);await x.entityService.createEntity({entity:{id:b,entityType:U9,content:L.content,metadata:{...N.metadata,...L.metadata},visibility:"public",created:Y,updated:Y}}),F+=1,W.push(b);for(let y of G)H.add(y)}return{peersScanned:f.length,unreachablePeers:Z,created:F,updated:K,alreadyKnown:q,unverified:V,createdDomains:W,introducingPeers:[...H],observedAt:Y}}function MH0(x,B=globalThis.fetch){return{name:"agent_scan_directories",description:"Walk each approved agent's public directory at /.well-known/agent-directory.json and record second-order sightings: agents your peers list that you are not connected to. A sighting is saved as a discovered agent with provenance (which peers introduced it, hop count) and data from its own verified Agent Card. Re-scanning is idempotent: connected agents are skipped and repeat sightings only merge new introducers. Never approves anything; promotion stays with agent_connect.",inputSchema:kH0.shape,visibility:"trusted",sideEffects:"external",handler:async(A,w)=>{let f=kH0.safeParse(A);if(!f.success)return{success:!1,error:`Invalid input: ${f.error.message}`};try{x.permissions.assertEntityActionAllowed(U9,"create",w)}catch($){return{success:!1,error:g($)}}let D=await yS(x,B,w.signal);return{success:!0,data:{peersScanned:D.peersScanned,unreachablePeers:D.unreachablePeers,created:D.created,updated:D.updated,alreadyKnown:D.alreadyKnown,unverified:D.unverified}}}}}var Tax=X.enum(["public","trusted"]),vH0=X.object({agent:X.string().min(1).describe("Saved agent id, domain, or URL whose inbound A2A trust to set."),level:Tax.describe("Inbound A2A trust level. Use trusted to grant trusted inbound access, public to revoke it."),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),keyFingerprint:X.string().optional()}),pax=X.object({keys:X.array(X.unknown())}),uax=X.object({kty:X.literal("OKP"),crv:X.literal("Ed25519"),x:X.string(),kid:X.string().optional(),alg:X.literal("EdDSA").optional()}).passthrough();function NH0(x){return(ow(x)||x.trim()).toLowerCase()}async function Sax(x,B){let A=NH0(B),w=await x.entityService.getEntity({entityType:U9,id:A});if(!w)return null;let f=NH0(w.metadata.a2aEndpoint??w.metadata.url);if(!f)return null;return{domain:f}}async function iax(x,B){try{let A=await B(`https://${x}/.well-known/jwks.json`);if(!A.ok)return null;let w=pax.safeParse(await A.json());if(!w.success)return null;let f=w.data.keys.map((D)=>uax.safeParse(D)).find((D)=>D.success);if(!f?.success)return null;return Lu(f.data)}catch{return null}}function IH0(x,B=globalThis.fetch){let w=new Qk;return{name:"agent_set_trust_level",description:"Grant or revoke inbound A2A trust for a saved contact; this is the only tool for inbound trust changes. To revoke, call directly with level public\u2014no key fingerprint or preliminary lookup is needed. To grant, use level trusted; the tool resolves and pins the peer key. This does not add or remove directory contacts or change outbound calling. Requires confirmation.",inputSchema:vH0.shape,visibility:"admin",sideEffects:"external",handler:async(f,D)=>{let $=vH0.safeParse(f);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.issues.map((q)=>`${q.path.join(".")}: ${q.message}`).join(", ")}`};let Z=X6(),Q=tH(D);if(!Z)return{success:!1,error:"Auth service is required to set inbound A2A trust.",code:"auth_service_unavailable"};let Y=await Sax(x,$.data.agent);if(!Y)return{success:!1,error:`No saved agent contact found for ${$.data.agent}. Connect the agent before setting inbound trust.`,code:"agent_not_found"};let W=$.data;if(W.confirmed){let q=w.validate(W.confirmationToken,W);if(q.status==="missing")return{success:!1,error:"No pending agent trust confirmation found. Please request the trust change again and confirm the new approval."};if(q.status==="mismatch")return{success:!1,error:"Confirmed agent trust arguments do not match the pending approval. Please request the trust change again and confirm the new approval."};if(W.level==="trusted"){if(!W.keyFingerprint)return{success:!1,error:"Missing key fingerprint for trusted A2A grant."};let V=await Z.grantA2APeerTrust({domain:Y.domain,keyFingerprint:W.keyFingerprint,grantedLevel:"trusted"},Q?{actorUserId:Q}:{});return{success:!0,data:{agent:Y.domain,level:V.grantedLevel,keyFingerprint:V.keyFingerprint}}}return await Z.revokeA2APeerTrust(Y.domain,Q?{actorUserId:Q}:{}),{success:!0,data:{agent:Y.domain,level:"public"}}}let H=W.level==="trusted"?await iax(Y.domain,B):void 0;if(W.level==="trusted"&&!H)return{success:!1,error:`Could not fetch an A2A signing key from ${Y.domain}.`,code:"jwks_unavailable"};let F=w.create((q)=>({agent:Y.domain,level:W.level,confirmed:!0,confirmationToken:q,...H?{keyFingerprint:H}:{}})),K=W.level==="trusted";return{needsConfirmation:!0,toolName:"agent_set_trust_level",summary:K?`Grant inbound trusted A2A access to ${Y.domain}?`:`Revoke inbound trusted A2A access from ${Y.domain}?`,preview:K?`This will grant inbound trusted A2A access to ${Y.domain} and pin key fingerprint ${H}. It will not add or remove the directory contact.`:`This will revoke inbound trusted A2A access from ${Y.domain}. The directory contact remains saved for outbound calls.`,args:F}}}}var lax=X.object({agentId:X.string().min(1),name:X.string().min(1),repoDid:X.string().min(1).optional(),cardCid:X.string().min(1).optional(),observedAt:X.string().datetime(),status:X.enum(["pending","notified"])}).strict(),nax=X.object({domain:X.string().min(1),existingRepoDid:X.string().min(1).optional(),candidateRepoDid:X.string().min(1),observedAt:X.string().datetime(),reason:X.string().min(1)}).strict(),Xk=X.object({notifyOnNewAgents:X.boolean().default(!1).describe("Notify when directory scans discover new agents")}).strict();class mS extends D8{fetchFn;constructor(x,B={}){super("agent",oH,B,Xk);this.fetchFn=x}async onRegister(x){let B=x.runtimeState.scoped({namespace:"agent-discovery.atproto-notifications",schema:lax}),A=x.runtimeState.scoped({namespace:"agent-discovery.atproto-conflicts",schema:nax});x.messaging.subscribe(fk,async(w)=>{if(!this.config.notifyOnNewAgents)return{success:!0};let f=OH0.parse(w.payload);if(f.status!=="discovered")return{success:!0};let D=`candidate:${f.cardCid??f.repoDid??f.agentId}`;return await B.setIfNotExists(D,{agentId:f.agentId,name:f.name,...f.repoDid&&{repoDid:f.repoDid},...f.cardCid&&{cardCid:f.cardCid},observedAt:new Date().toISOString(),status:"pending"}),{success:!0}}),x.messaging.subscribe(dH,async(w)=>{if(!this.config.notifyOnNewAgents)return{success:!0};let f=hH0.parse(w.payload),D=`conflict:${_8(`${f.domain}\x00${f.existingRepoDid??""}\x00${f.candidateRepoDid}`)}`;return await A.setIfNotExists(D,f),{success:!0}}),x.recurringChecks.register({id:"directory-scan",cadence:"daily",deliverAlerts:this.config.notifyOnNewAgents,run:async({signal:w})=>{let f=await yS(x,this.fetchFn,w);if(!this.config.notifyOnNewAgents)return{};let D=[];if(f.created>0){let Y=[...f.createdDomains].sort(),W=[...f.introducingPeers].sort(),H=`${f.created} agent${f.created===1?"":"s"}`;D.push({dedupeKey:`sightings:${_8(`${f.observedAt}\x00${Y.join("\x00")}`)}`,title:"New agent sightings",body:`${H} sighted through ${W.join(", ")}`})}let Z=(await B.list({keyPrefix:"candidate:"})).filter((Y)=>Y.value.status==="pending").sort((Y,W)=>Y.value.observedAt.localeCompare(W.value.observedAt));if(Z.length>0){let Y=Z.slice(0,5).map((K)=>K.value.name).join(", "),W=Z.length>5?` +${Z.length-5}`:"",H=`${Z.length} new agent${Z.length===1?"":"s"}`,F=Z.map((K)=>K.key).join("\x00");D.push({dedupeKey:`atproto:${_8(F)}`,title:"New ATProto agents awaiting review",body:`${H} awaiting review: ${Y}${W}. Review: /agents?status=discovered`});for(let K of Z)await B.delete(K.key)}let Q=await A.list({keyPrefix:"conflict:"});if(Q.length>0){let Y=[...new Set(Q.map((W)=>W.value.domain))].sort();D.push({dedupeKey:`atproto-conflict:${_8(Q.map((W)=>W.key).sort().join("\x00"))}`,title:"ATProto identity conflict",body:`${Q.length} conflicting repo claim${Q.length===1?"":"s"} blocked for ${Y.join(", ")}. Existing approvals were preserved.`});for(let W of Q)await A.delete(W.key)}return D.length>0?{alerts:D}:{}}})}async getTools(){return[LH0(this.getContext(),this.fetchFn),MH0(this.getContext(),this.fetchFn),IH0(this.getContext(),this.fetchFn)]}}function CS(x={}){return new mS(void 0,x)}var vQ=X.object({name:X.string(),description:X.string(),tags:X.array(X.string()),examples:X.array(X.string())}),RH0=vQ,pV=q3.extend({entityType:X.literal(R6),metadata:RH0});class eH extends ox{constructor(){super({entityType:R6,purpose:"A capability advertised by a remote agent.",schema:pV,frontmatterSchema:vQ})}fromMarkdown(x){let B=this.parseFrontMatter(x,vQ);return{content:x,entityType:R6,metadata:B}}createSkillContent(x){return this.buildMarkdown("",x)}}var dax=X.object({skills:X.array(vQ).max(8)}),yH0=mx({name:"skill:skill-derivation",description:"Derive skills from topic titles and brain capabilities",dataSourceId:"shell:ai-content",schema:dax,useKnowledgeContext:!0,basePrompt:`You are analyzing a brain's content to identify its high-level capabilities.
4804
+ `,rH={kicker:"Agent network",headingLead:"The rhizome grows",headingAccent:"beneath this brain",lede:"Every agent this brain has met, mapped by how close its work runs to ours \u2014 distance measured in meaning, not geography. Threads thicken where practices touch; where several lights gather, a constellation forms.",ctaLabel:"Meet the agents",ctaHref:"/agents"};function Max(x){return x.split(/\*([^*]+)\*/g).map((B,A)=>A%2===1?O5("b",{children:B},B,!1,void 0,this):B)}function IS(x){let B=x.nodes.filter((Q)=>Q.status!=="archived").length,A=x.kicker??rH.kicker,w=x.headingLead??rH.headingLead,f=x.headingAccent??rH.headingAccent,D=x.lede??rH.lede,$=x.ctaLabel??rH.ctaLabel,Z=x.ctaHref??rH.ctaHref;return O5("section",{class:"agent-proximity-site","aria-label":"Agent proximity map",children:[O5("style",{children:kax},void 0,!1,void 0,this),O5("div",{class:"agent-proximity-site__grid",children:[O5("div",{class:"agent-proximity-site__copy",children:[O5("p",{class:"agent-proximity-site__kicker",children:A},void 0,!1,void 0,this),O5("h2",{class:"agent-proximity-site__heading",children:[w," ",O5("em",{children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this),O5("p",{class:"agent-proximity-site__lede",children:Max(D)},void 0,!1,void 0,this),O5("a",{class:"agent-proximity-site__cta",href:Z,children:$},void 0,!1,void 0,this),x.pendingCount>0&&O5("p",{class:"agent-proximity-site__note",children:[x.pendingCount," pending semantic indexing"]},void 0,!0,void 0,this),x.center.kind==="centroid"&&O5("p",{class:"agent-proximity-site__note",children:"Identity not indexed yet \u2014 using network centroid"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),O5("div",{class:"agent-proximity-site__map",children:[O5(xk,{data:x,surface:"site"},void 0,!1,void 0,this),O5("div",{class:"agent-proximity-site__foot","aria-label":"Network summary",children:[O5("span",{class:"agent-proximity-site__count",children:[O5("b",{children:B},void 0,!1,void 0,this)," agents \xB7 ",O5("b",{children:x.clusters.length},void 0,!1,void 0,this)," ","constellations discovered"]},void 0,!0,void 0,this),O5("span",{class:"agent-proximity-site__live",children:"the map is live"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var vax=X.enum(["discovered","approved","archived"]),Zk=RL,Nax=X.object({agents:X.array(Zk),pageTitle:X.string().nullable().default(null),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null),selectedStatus:X.union([X.literal("all"),vax])}),_H0="/scripts/agent-proximity-map.js",Iax=new q9(WW0,{title:"Network",mappings:[{key:"kicker",label:"Kicker",type:"string"},{key:"headingLead",label:"Heading Lead",type:"string"},{key:"headingAccent",label:"Heading Accent",type:"string"},{key:"lede",label:"Lede",type:"string"},{key:"ctaLabel",label:"Cta Label",type:"string"},{key:"ctaHref",label:"Cta Href",type:"string"}]});function PH0(){return{[AS]:mx({name:AS,description:"Semantic agent proximity map site section",schema:rw,dataSourceId:IL,overlayFormatter:Iax,requiredPermission:"public",runtimeScripts:[{src:_H0,defer:!0}],staticAssets:{[_H0]:nH},layout:{component:IS}}),[wS]:mx({name:wS,description:"Agent directory list page template",schema:Nax,dataSourceId:OV,requiredPermission:"public",layout:{component:GH0}}),[fS]:mx({name:fS,description:"Individual agent profile template",schema:X.object({agent:Zk,prevAgent:Zk.nullable(),nextAgent:Zk.nullable()}),dataSourceId:OV,requiredPermission:"public",layout:{component:jH0}})}}var oH={name:"@brains/agent-discovery",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Agent discovery \u2014 brain+anchor contacts and skills",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/auth-service":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/http-signatures":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var hax=new Y5;class OS extends g8{entityType=U9;schema=hV;adapter=hax;fetchFn;resolveHostname;constructor(x,B){super(sY0,oH,{},qB);this.fetchFn=x,this.resolveHostname=B}getEntityTypeConfig(){return{projectionSourceRole:"supporting"}}createGenerationHandler(x){return new QS(this.logger.child("AgentGenerationJobHandler"),x)}getTemplates(){return PH0()}getDataSources(){return[new yL(this.logger.child("AgentDataSource")),new CL]}async onRegister(x){KH0(x),x.recurringChecks.register({id:"agent-card-refresh",cadence:"daily",deliverAlerts:!1,run:async({signal:B})=>{return await FH0(x,this.fetchFn,B,new Date().toISOString(),this.resolveHostname),{}}}),ZH0(x)}async getInstructions(){return qH0()}}function hS(){return new OS}var JH0=X.object({source:X.object({kind:X.literal("url"),url:X.string().min(1).describe("Remote agent domain or URL to verify and connect. Preserve bare domains as bare domains.")}),confirmed:X.boolean().optional(),confirmationToken:X.string().optional()}),Rax=new Y5;function yax(x){let B=ow(x);if(!B)return null;return{domain:B,fetchTarget:x.trim().startsWith("http")?x.trim():B}}function max(x,B){return(ow(B)||x).toLowerCase()}async function Cax(x){let{context:B,entityId:A,card:w}=x,f=new Date().toISOString(),D=await B.entityService.getEntity({entityType:U9,id:A}),$=pH(w,{status:"approved"}),Q={...Rax.fromMarkdown($.content).metadata,...$.metadata,a2aEndpoint:w.url};if(D){let W={...D,content:$.content,metadata:Q,updated:f};return await B.entityService.updateEntity({entity:W}),{entity:W,created:!1}}let Y={id:A,entityType:U9,content:$.content,metadata:Q,contentHash:"",visibility:"public",created:f,updated:f};return await B.entityService.createEntity({entity:Y}),{entity:Y,created:!0}}function LH0(x,B=globalThis.fetch){let w=new Qk;return{name:"agent_connect",description:"Verify and connect a remote A2A agent by fetching its Agent Card from /.well-known/agent-card.json, then save the verified contact in the local agent directory as approved for future outbound calls. Never use this tool for a request to approve or archive an existing saved contact; update that contact's status with system_update instead. This adds a directory contact; it does not message the remote agent or grant it inbound trusted access. Requires confirmation before verification and persistence. Call this tool without confirmed on the initial request; the tool returns confirmation args for the user to approve.",inputSchema:JH0.shape,visibility:"trusted",sideEffects:"external",handler:async(f,D)=>{let $=JH0.safeParse(f);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.issues.map((W)=>`${W.path.join(".")}: ${W.message}`).join(", ")}`};let Z=$.data,Q=yax(Z.source.url);if(!Q)return{success:!1,error:"Provide a valid remote agent domain or URL to connect.",code:"invalid_agent_url"};try{x.permissions.assertEntityActionAllowed(U9,"create",D)}catch(W){return{success:!1,error:g(W)}}if(Z.confirmed){let W=Z.confirmationToken,H=w.validate(W,Z);if(H.status==="missing")return{success:!1,error:"No pending agent connection confirmation found. Please request connection again and confirm the new approval."};if(H.status==="mismatch")return{success:!1,error:"Confirmed agent connection arguments do not match the pending approval. Please request connection again and confirm the new approval."};let F=await TH(Q.fetchTarget,B);if(!F)return{success:!1,error:`Could not verify an A2A Agent Card for ${Q.domain}.`,code:"not_an_agent"};let K=max(Q.domain,F.url),{entity:q,created:V}=await Cax({context:x,entityId:K,sourceUrl:Z.source.url,card:F});return{success:!0,data:{status:q.metadata.status,entityId:q.id,connected:!0,created:V,a2aEndpoint:F.url,skills:F.skills.map((b)=>({name:b.name,description:b.description,tags:b.tags}))}}}let Y=w.create((W)=>({source:Z.source,confirmed:!0,confirmationToken:W}));return{needsConfirmation:!0,toolName:"agent_connect",summary:`Verify and connect agent ${Q.domain}?`,preview:`This will fetch and validate ${Q.domain}'s A2A Agent Card, then save the verified contact as approved for future outbound calls. It will not message the remote agent or grant it inbound trusted access.`,args:Y}}}}var kH0=X.object({}),cax=X.object({agents:X.array(X.object({name:X.string(),url:X.string()}))}),RS=new Y5;async function gax(x,B,A){let w=`https://${x}/.well-known/agent-directory.json`;try{let f=await B(w,A?{signal:A}:void 0);if(!f.ok)return null;let D=cax.safeParse(await f.json());return D.success?D.data:null}catch{if(A?.aborted)throw A.reason;return null}}async function yS(x,B=globalThis.fetch,A){let w=await x.entityService.listEntities({entityType:U9}),f=w.filter((b)=>b.metadata.status==="approved"),D=x.domain?.toLowerCase(),$=new Map,Z=0;for(let b of f){A?.throwIfAborted();let G=await gax(b.id,B,A);if(!G){Z+=1;continue}for(let E of G.agents){let _=ow(E.url).toLowerCase();if(!_||_===D||_===b.id)continue;let L=$.get(_)??new Set;L.add(b.id),$.set(_,L)}}let Q=new Map(w.map((b)=>[b.id,b])),Y=new Date().toISOString(),W=[],H=new Set,F=0,K=0,q=0,V=0;for(let[b,G]of $){A?.throwIfAborted();let E=Q.get(b);if(E){let{frontmatter:y,body:c}=RS.parseEntity(E),n=y.introducedBy??[];if(y.status!=="discovered"||n.length===0){q+=1;continue}let R=[...n,...[...G].filter((M)=>!n.includes(M))];if(R.length===n.length)continue;await x.entityService.updateEntity({entity:{...E,content:RS.createAgentContent({...y,introducedBy:R,about:c.about,skills:c.skills,notes:c.notes}),updated:Y}}),K+=1;continue}let _=await TH(b,B,A);if(!_){V+=1;continue}let L=pH(_,{status:"discovered",provenance:{introducedBy:[...G],hops:2}}),N=RS.fromMarkdown(L.content);await x.entityService.createEntity({entity:{id:b,entityType:U9,content:L.content,metadata:{...N.metadata,...L.metadata},visibility:"public",created:Y,updated:Y}}),F+=1,W.push(b);for(let y of G)H.add(y)}return{peersScanned:f.length,unreachablePeers:Z,created:F,updated:K,alreadyKnown:q,unverified:V,createdDomains:W,introducingPeers:[...H],observedAt:Y}}function MH0(x,B=globalThis.fetch){return{name:"agent_scan_directories",description:"Walk each approved agent's public directory at /.well-known/agent-directory.json and record second-order sightings: agents your peers list that you are not connected to. A sighting is saved as a discovered agent with provenance (which peers introduced it, hop count) and data from its own verified Agent Card. Re-scanning is idempotent: connected agents are skipped and repeat sightings only merge new introducers. Never approves anything; promotion stays with agent_connect.",inputSchema:kH0.shape,visibility:"trusted",sideEffects:"external",handler:async(A,w)=>{let f=kH0.safeParse(A);if(!f.success)return{success:!1,error:`Invalid input: ${f.error.message}`};try{x.permissions.assertEntityActionAllowed(U9,"create",w)}catch($){return{success:!1,error:g($)}}let D=await yS(x,B,w.signal);return{success:!0,data:{peersScanned:D.peersScanned,unreachablePeers:D.unreachablePeers,created:D.created,updated:D.updated,alreadyKnown:D.alreadyKnown,unverified:D.unverified}}}}}var Tax=X.enum(["public","trusted"]),vH0=X.object({agent:X.string().min(1).describe("Saved agent id, domain, or URL whose inbound A2A trust to set."),level:Tax.describe("Inbound A2A trust level. Use trusted to grant trusted inbound access, public to revoke it."),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),keyFingerprint:X.string().optional()}),pax=X.object({keys:X.array(X.unknown())}),uax=X.object({kty:X.literal("OKP"),crv:X.literal("Ed25519"),x:X.string(),kid:X.string().optional(),alg:X.literal("EdDSA").optional()}).passthrough();function NH0(x){return(ow(x)||x.trim()).toLowerCase()}async function Sax(x,B){let A=NH0(B),w=await x.entityService.getEntity({entityType:U9,id:A});if(!w)return null;let f=NH0(w.metadata.a2aEndpoint??w.metadata.url);if(!f)return null;return{domain:f}}async function iax(x,B){try{let A=await B(`https://${x}/.well-known/jwks.json`);if(!A.ok)return null;let w=pax.safeParse(await A.json());if(!w.success)return null;let f=w.data.keys.map((D)=>uax.safeParse(D)).find((D)=>D.success);if(!f?.success)return null;return Lu(f.data)}catch{return null}}function IH0(x,B=globalThis.fetch){let w=new Qk;return{name:"agent_set_trust_level",description:"Grant or revoke inbound A2A trust for a saved contact; this is the only tool for inbound trust changes. To revoke, call directly with level public\u2014no key fingerprint or preliminary lookup is needed. To grant, use level trusted; the tool resolves and pins the peer key. This does not add or remove directory contacts or change outbound calling. Requires confirmation.",inputSchema:vH0.shape,visibility:"admin",sideEffects:"external",handler:async(f,D)=>{let $=vH0.safeParse(f);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.issues.map((q)=>`${q.path.join(".")}: ${q.message}`).join(", ")}`};let Z=X6(),Q=tH(D);if(!Z)return{success:!1,error:"Auth service is required to set inbound A2A trust.",code:"auth_service_unavailable"};let Y=await Sax(x,$.data.agent);if(!Y)return{success:!1,error:`No saved agent contact found for ${$.data.agent}. Connect the agent before setting inbound trust.`,code:"agent_not_found"};let W=$.data;if(W.confirmed){let q=w.validate(W.confirmationToken,W);if(q.status==="missing")return{success:!1,error:"No pending agent trust confirmation found. Please request the trust change again and confirm the new approval."};if(q.status==="mismatch")return{success:!1,error:"Confirmed agent trust arguments do not match the pending approval. Please request the trust change again and confirm the new approval."};if(W.level==="trusted"){if(!W.keyFingerprint)return{success:!1,error:"Missing key fingerprint for trusted A2A grant."};let V=await Z.grantA2APeerTrust({domain:Y.domain,keyFingerprint:W.keyFingerprint,grantedLevel:"trusted"},Q?{actorUserId:Q}:{});return{success:!0,data:{agent:Y.domain,level:V.grantedLevel,keyFingerprint:V.keyFingerprint}}}return await Z.revokeA2APeerTrust(Y.domain,Q?{actorUserId:Q}:{}),{success:!0,data:{agent:Y.domain,level:"public"}}}let H=W.level==="trusted"?await iax(Y.domain,B):void 0;if(W.level==="trusted"&&!H)return{success:!1,error:`Could not fetch an A2A signing key from ${Y.domain}.`,code:"jwks_unavailable"};let F=w.create((q)=>({agent:Y.domain,level:W.level,confirmed:!0,confirmationToken:q,...H?{keyFingerprint:H}:{}})),K=W.level==="trusted";return{needsConfirmation:!0,toolName:"agent_set_trust_level",summary:K?`Grant inbound trusted A2A access to ${Y.domain}?`:`Revoke inbound trusted A2A access from ${Y.domain}?`,preview:K?`This will grant inbound trusted A2A access to ${Y.domain} and pin key fingerprint ${H}. It will not add or remove the directory contact.`:`This will revoke inbound trusted A2A access from ${Y.domain}. The directory contact remains saved for outbound calls.`,args:F}}}}var lax=X.object({agentId:X.string().min(1),name:X.string().min(1),repoDid:X.string().min(1).optional(),cardCid:X.string().min(1).optional(),observedAt:X.string().datetime(),status:X.enum(["pending","notified"])}).strict(),nax=X.object({domain:X.string().min(1),existingRepoDid:X.string().min(1).optional(),candidateRepoDid:X.string().min(1),observedAt:X.string().datetime(),reason:X.string().min(1)}).strict(),Xk=X.object({notifyOnNewAgents:X.boolean().default(!1).describe("Notify when directory scans discover new agents")}).strict();class mS extends D8{fetchFn;constructor(x,B={}){super("agent",oH,B,Xk);this.fetchFn=x}async onRegister(x){let B=x.runtimeState.scoped({namespace:"agent-discovery.atproto-notifications",schema:lax}),A=x.runtimeState.scoped({namespace:"agent-discovery.atproto-conflicts",schema:nax});x.messaging.subscribe(fk,async(w)=>{if(!this.config.notifyOnNewAgents)return{success:!0};let f=OH0.parse(w.payload);if(f.status!=="discovered")return{success:!0};let D=`candidate:${f.cardCid??f.repoDid??f.agentId}`;return await B.setIfNotExists(D,{agentId:f.agentId,name:f.name,...f.repoDid&&{repoDid:f.repoDid},...f.cardCid&&{cardCid:f.cardCid},observedAt:new Date().toISOString(),status:"pending"}),{success:!0}}),x.messaging.subscribe(dH,async(w)=>{if(!this.config.notifyOnNewAgents)return{success:!0};let f=hH0.parse(w.payload),D=`conflict:${_8(`${f.domain}\x00${f.existingRepoDid??""}\x00${f.candidateRepoDid}`)}`;return await A.setIfNotExists(D,f),{success:!0}}),x.recurringChecks.register({id:"directory-scan",cadence:"daily",deliverAlerts:this.config.notifyOnNewAgents,run:async({signal:w})=>{let f=await yS(x,this.fetchFn,w);if(!this.config.notifyOnNewAgents)return{};let D=[];if(f.created>0){let Y=[...f.createdDomains].sort(),W=[...f.introducingPeers].sort(),H=`${f.created} agent${f.created===1?"":"s"}`;D.push({dedupeKey:`sightings:${_8(`${f.observedAt}\x00${Y.join("\x00")}`)}`,title:"New agent sightings",body:`${H} sighted through ${W.join(", ")}`})}let Z=(await B.list({keyPrefix:"candidate:"})).filter((Y)=>Y.value.status==="pending").sort((Y,W)=>Y.value.observedAt.localeCompare(W.value.observedAt));if(Z.length>0){let Y=Z.slice(0,5).map((K)=>K.value.name).join(", "),W=Z.length>5?` +${Z.length-5}`:"",H=`${Z.length} new agent${Z.length===1?"":"s"}`,F=Z.map((K)=>K.key).join("\x00");D.push({dedupeKey:`atproto:${_8(F)}`,title:"New ATProto agents awaiting review",body:`${H} awaiting review: ${Y}${W}. Review: /agents?status=discovered`});for(let K of Z)await B.delete(K.key)}let Q=await A.list({keyPrefix:"conflict:"});if(Q.length>0){let Y=[...new Set(Q.map((W)=>W.value.domain))].sort();D.push({dedupeKey:`atproto-conflict:${_8(Q.map((W)=>W.key).sort().join("\x00"))}`,title:"ATProto identity conflict",body:`${Q.length} conflicting repo claim${Q.length===1?"":"s"} blocked for ${Y.join(", ")}. Existing approvals were preserved.`});for(let W of Q)await A.delete(W.key)}return D.length>0?{alerts:D}:{}}})}async getTools(){return[LH0(this.getContext(),this.fetchFn),MH0(this.getContext(),this.fetchFn),IH0(this.getContext(),this.fetchFn)]}}function CS(x={}){return new mS(void 0,x)}var vQ=X.object({name:X.string(),description:X.string(),tags:X.array(X.string()),examples:X.array(X.string())}),RH0=vQ,pV=q3.extend({entityType:X.literal(R6),metadata:RH0});class eH extends ox{constructor(){super({entityType:R6,purpose:"A capability advertised by a remote agent.",schema:pV,frontmatterSchema:vQ})}fromMarkdown(x){let B=this.parseFrontMatter(x,vQ);return{content:x,entityType:R6,metadata:B}}createSkillContent(x){return this.buildMarkdown("",x)}}var dax=X.object({skills:X.array(vQ).max(8)}),yH0=mx({name:"skill:skill-derivation",description:"Derive skills from topic titles and brain capabilities",dataSourceId:"shell:ai-content",schema:dax,useKnowledgeContext:!0,basePrompt:`You are analyzing a brain's content to identify its high-level capabilities.
4805
4805
 
4806
4806
  Given knowledge domains, CONSOLIDATE related topics into broader skills.
4807
4807
  There should be FEWER skills than topics \u2014 combine related domains.
@@ -4986,7 +4986,7 @@ Returns pageviews, visitors, top pages, referrers, devices, and countries.`,xsx,
4986
4986
  }
4987
4987
  }
4988
4988
  }
4989
- `,{...this.baseVariables(x),limit:x.limit??20})).map((w)=>({country:w.dimensions.countryName,visits:w.sum.visits}))}}var uS=7,Asx=10;function dH0(x){return async()=>{if(!x)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let B=zP(),A=Qw0(uS),w=WW(A),f=WW(B);try{let[D,$]=await Promise.all([x.getWebsiteStats({startDate:w,endDate:f}),x.getTopPages({startDate:w,endDate:f,limit:Asx})]);return{days:uS,startDate:w,endDate:f,pageviews:D.pageviews,visitors:D.visitors,topPages:$}}catch(D){return{error:g(D,"Failed to fetch analytics"),days:uS}}}}var aH0={name:"@brains/analytics",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Analytics plugin for collecting website and social media metrics",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class sH0 extends D8{cloudflareClient;constructor(x={}){super("analytics",aH0,x,TS)}async onRegister(x){this.cloudflareClient=this.config.cloudflare?new pS(this.config.cloudflare):void 0,x.insights.register("traffic-overview",dH0(this.cloudflareClient))}async onReady(x){let B=this.config.cloudflare?.siteTag;if(!B)return;await x.messaging.send({type:O4.headScriptRegister,payload:{pluginId:this.id,script:nH0(B)}})}async getTools(){return lH0(this.id,this.getContext(),this.cloudflareClient)}}function fsx(x={}){return new sH0(x)}var rH0=fsx;var uV=X.object({title:X.string(),detail:X.string().optional()}),NQ=X.object({strengths:X.array(uV).default([]),weaknesses:X.array(uV).default([]),opportunities:X.array(uV).default([]),threats:X.array(uV).default([]),derivedAt:X.string().datetime()}),oH0=NQ.pick({derivedAt:!0}),BF=q3.extend({entityType:X.literal("swot"),metadata:oH0});class ew extends ox{constructor(){super({entityType:"swot",purpose:"A SWOT analysis of strengths, weaknesses, opportunities, and threats.",schema:BF,frontmatterSchema:NQ})}fromMarkdown(x){let B=this.parseFrontMatter(x,NQ);return{content:x,entityType:"swot",metadata:{derivedAt:B.derivedAt}}}createSwotContent(x){return this.buildMarkdown("",x)}parseSwotContent(x){return{frontmatter:NQ.parse(this.parseFrontMatter(x,NQ))}}}var Dsx=new ew;var SS=X.object({reason:X.string().default("entity-change")}),Fk=X.object({theme:X.string(),evidence:X.string(),action:X.string()}),iS=X.object({strengths:X.array(Fk),weaknesses:X.array(Fk),opportunities:X.array(Fk),threats:X.array(Fk)}),Kk=X.object({sourceTheme:X.string(),title:X.string(),detail:X.string().nullable()}),qk=X.object({strengths:X.array(Kk),weaknesses:X.array(Kk),opportunities:X.array(Kk),threats:X.array(Kk)});function $sx(x){return x.trim().toLowerCase().replace(/[_\s]+/g,"-")}function AF(x){let B=new Set,A=[];for(let w of x){let f=$sx(w);if(!f||B.has(f))continue;B.add(f),A.push(f)}return A}var Zsx=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),lS=X.object({name:X.string(),kind:sw,organization:X.string().optional(),brainName:X.string(),url:X.string().url(),did:X.string().optional(),status:X.enum(["approved","discovered","archived"]),discoveredAt:X.string().datetime().optional()}),Qsx=q3.extend({entityType:X.literal("agent"),metadata:X.record(X.string(),X.unknown())}),Xsx=X.object({about:X.string(),skills:X.array(Zsx),notes:X.string()});function Ysx(x){if(!Array.isArray(x)||x.length===0)return"";return x.map((A)=>{let w=A.tags.length>0?` [${A.tags.join(", ")}]`:"";return`- ${A.name}: ${A.description}${w}`}).join(`
4989
+ `,{...this.baseVariables(x),limit:x.limit??20})).map((w)=>({country:w.dimensions.countryName,visits:w.sum.visits}))}}var uS=7,Asx=10;function dH0(x){return async()=>{if(!x)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let B=zP(),A=Qw0(uS),w=WW(A),f=WW(B);try{let[D,$]=await Promise.all([x.getWebsiteStats({startDate:w,endDate:f}),x.getTopPages({startDate:w,endDate:f,limit:Asx})]);return{days:uS,startDate:w,endDate:f,pageviews:D.pageviews,visitors:D.visitors,topPages:$}}catch(D){return{error:g(D,"Failed to fetch analytics"),days:uS}}}}var aH0={name:"@brains/analytics",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Analytics plugin for collecting website and social media metrics",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class sH0 extends D8{cloudflareClient;constructor(x={}){super("analytics",aH0,x,TS)}async onRegister(x){this.cloudflareClient=this.config.cloudflare?new pS(this.config.cloudflare):void 0,x.insights.register("traffic-overview",dH0(this.cloudflareClient))}async onReady(x){let B=this.config.cloudflare?.siteTag;if(!B)return;await x.messaging.send({type:O4.headScriptRegister,payload:{pluginId:this.id,script:nH0(B)}})}async getTools(){return lH0(this.id,this.getContext(),this.cloudflareClient)}}function fsx(x={}){return new sH0(x)}var rH0=fsx;var uV=X.object({title:X.string(),detail:X.string().optional()}),NQ=X.object({strengths:X.array(uV).default([]),weaknesses:X.array(uV).default([]),opportunities:X.array(uV).default([]),threats:X.array(uV).default([]),derivedAt:X.string().datetime()}),oH0=NQ.pick({derivedAt:!0}),BF=q3.extend({entityType:X.literal("swot"),metadata:oH0});class ew extends ox{constructor(){super({entityType:"swot",purpose:"A SWOT analysis of strengths, weaknesses, opportunities, and threats.",schema:BF,frontmatterSchema:NQ})}fromMarkdown(x){let B=this.parseFrontMatter(x,NQ);return{content:x,entityType:"swot",metadata:{derivedAt:B.derivedAt}}}createSwotContent(x){return this.buildMarkdown("",x)}parseSwotContent(x){return{frontmatter:NQ.parse(this.parseFrontMatter(x,NQ))}}}var Dsx=new ew;var SS=X.object({reason:X.string().default("entity-change")}),Fk=X.object({theme:X.string(),evidence:X.string(),action:X.string()}),iS=X.object({strengths:X.array(Fk),weaknesses:X.array(Fk),opportunities:X.array(Fk),threats:X.array(Fk)}),Kk=X.object({sourceTheme:X.string(),title:X.string(),detail:X.string().nullable()}),qk=X.object({strengths:X.array(Kk),weaknesses:X.array(Kk),opportunities:X.array(Kk),threats:X.array(Kk)});function $sx(x){return x.trim().toLowerCase().replace(/[_\s]+/g,"-")}function AF(x){let B=new Set,A=[];for(let w of x){let f=$sx(w);if(!f||B.has(f))continue;B.add(f),A.push(f)}return A}var Zsx=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),lS=X.object({name:X.string(),kind:sw,organization:X.string().optional(),brainName:X.string(),url:X.string().url(),did:X.string().optional(),status:X.enum(["approved","discovered","archived"]),discoveredAt:X.string().datetime().optional()}),Qsx=q3.extend({entityType:X.literal("agent"),metadata:X.record(X.string(),X.unknown())}),Xsx=X.object({about:X.string(),skills:X.array(Zsx),notes:X.string()});function Ysx(x){if(!Array.isArray(x)||x.length===0)return"";return x.map((A)=>{let w=A.tags.length>0?` [${A.tags.join(", ")}]`:"";return`- ${A.name}: ${A.description}${w}`}).join(`
4990
4990
  `)}function Wsx(x){if(!x.trim())return[];let B=[];for(let A of x.split(`
4991
4991
  `)){let w=A.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/);if(!w)continue;let f=w[1]??"",D=w[2]??"",$=w[3],Z=$?$.split(",").map((Q)=>Q.trim()).filter(Boolean):[];B.push({name:f,description:D,tags:Z})}return B}var Hsx=new q9(Xsx,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:Ysx,parser:Wsx},{key:"notes",label:"Notes",type:"string"}]});class tH0 extends ox{constructor(){super({entityType:"agent",purpose:"An assessed profile of a subject's capabilities.",schema:Qsx,frontmatterSchema:lS})}fromMarkdown(x){return{content:x,entityType:"agent"}}parseAgent(x){let B=lS.safeParse(this.parseFrontMatter(x.content,lS));if(!B.success)return null;let A=this.extractBody(x.content);if(!A.trim())return{frontmatter:B.data,body:{about:"",skills:[],notes:""}};try{return{frontmatter:B.data,body:Hsx.parse(A)}}catch{return{frontmatter:B.data,body:{about:"",skills:[],notes:""}}}}}var Fsx=new tH0;function Ksx(x){return{name:x.name,description:x.description,tags:AF(x.tags),examples:x.examples}}function qsx(x){let B=kL.safeParse(x.metadata);return B.success?B.data:null}function nS(x){let B=x.identity,A=B?.brainName??"This brain",w=B?.profileName??A,f=B?.role&&B.purpose?`${A} is ${B.role}. Its purpose is: ${B.purpose}.`:B?.purpose,D=[B?.profileDescription,f].filter((Q)=>Boolean(Q?.trim())),$={id:"self",source:"self",name:w,brainName:A,...B?.profileCategory&&{kind:B.profileCategory},...D.length>0&&{description:D.join(`
4992
4992
 
@@ -5201,10 +5201,10 @@ ${JSON.stringify(A,null,2)}`}function Vk(x){return x.map((B)=>B.detail===null?{t
5201
5201
  border-bottom: none;
5202
5202
  }
5203
5203
  }
5204
- `;import{jsxDEV as x4}from"preact/jsx-dev-runtime";var DF0=fF0,Gk=X.object({title:X.string(),detail:X.string().optional()}),_sx=X.discriminatedUnion("status",[X.object({status:X.literal("generating")}),X.object({status:X.literal("ready"),strengths:X.array(Gk).default([]),weaknesses:X.array(Gk).default([]),opportunities:X.array(Gk).default([]),threats:X.array(Gk).default([]),derivedAt:X.string()})]);function Psx({items:x}){if(x.length===0)return x4("p",{class:"swot-empty",children:"\u2014"},void 0,!1,void 0,this);return x4("ul",{class:"swot-list",children:x.map((B)=>x4("li",{class:"swot-item",children:[x4("b",{children:B.title},void 0,!1,void 0,this),B.detail?x4("span",{children:[" \u2014 ",B.detail]},void 0,!0,void 0,this):null]},`${B.title}:${B.detail??""}`,!0,void 0,this))},void 0,!1,void 0,this)}function Ek({title:x,tone:B,items:A}){return x4("section",{class:`swot-cell is-${B}`,children:[x4("div",{class:"swot-head",children:x},void 0,!1,void 0,this),x4(Psx,{items:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function oS({data:x}){let B=_sx.safeParse(x);if(!B.success||B.data.status==="generating")return x4("div",{"data-swot-widget":!0,children:x4("p",{class:"muted",children:"generating assessment\u2026"},void 0,!1,void 0,this)},void 0,!1,void 0,this);let A=B.data;return x4("div",{"data-swot-widget":!0,children:x4("div",{class:"swot",role:"grid","aria-label":"SWOT analysis of agent network",children:[x4(Ek,{title:"Strengths",tone:"s",items:A.strengths},void 0,!1,void 0,this),x4(Ek,{title:"Weaknesses",tone:"w",items:A.weaknesses},void 0,!1,void 0,this),x4(Ek,{title:"Opportunities",tone:"o",items:A.opportunities},void 0,!1,void 0,this),x4(Ek,{title:"Threats",tone:"t",items:A.threats},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var tS={name:"@brains/assessment",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Assessment outputs and capability-profile analysis",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Lsx=X.object({status:X.enum(["ready","generating"])}),eS=new ew;class xi extends g8{entityType="swot";schema=BF;adapter=eS;initialSyncComplete=!1;constructor(){super("swot",tS,{},qB)}getEntityTypeConfig(){return{projectionSourceRole:"supporting"}}async onRegister(x){let B=new Uk(this.logger.child("SwotDerivationHandler"),x);x.jobs.registerHandler("derive",B),x.eval.registerHandler("deriveSwot",async()=>{let D=IQ.from(async()=>{});if(!D)throw Error("Expected progress reporter to be created");await B.process({reason:"eval"},"eval-swot-derive",D);let $=await x.entityService.getEntity({entityType:"swot",id:"swot"});if(!$)throw Error("Expected SWOT entity to be created during eval");return eS.parseSwotContent($.content).frontmatter});let A=async(D)=>{try{return await x.jobs.enqueue({type:"derive",data:{reason:D},options:{source:this.id,priority:10,deduplication:"coalesce",deduplicationKey:"swot",metadata:{operationType:"data_processing",operationTarget:`swot:${D}`}}})}catch($){return this.logger.error("Failed to queue SWOT derivation",{error:$,reason:D}),null}},w=async(D)=>{if(!await x.entityService.getEntity({entityType:"swot",id:"swot"}))await A(D)};x.messaging.subscribe(HB.initialCompleted,async()=>{return this.initialSyncComplete=!0,await w("initial-missing-entity"),{success:!0}}),x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.dashboard.registerWidget({id:"swot",title:"SWOT",group:"network",section:"secondary",priority:14,rendererName:"SwotWidget",digestProvider:(D)=>{let{status:$}=Lsx.parse(D);return{digest:[{label:"SWOT",value:$==="ready"?"Ready":"Generating",tone:$==="ready"?"good":"warn"}]}},component:oS,clientStyles:DF0,dataProvider:async()=>{let D=await x.entityService.getEntity({entityType:"swot",id:"swot"});if(!D)return{status:"generating"};let{frontmatter:$}=eS.parseSwotContent(D.content);return{status:"ready",...$}}}),{success:!0}});let f=async(D)=>{let{entityType:$}=D.payload;if(!this.initialSyncComplete)return{success:!0};if($!=="agent"&&$!=="skill")return{success:!0};return await A("entity-change"),{success:!0}};x.messaging.subscribe(l8.created,f),x.messaging.subscribe(l8.updated,f),x.messaging.subscribe(l8.deleted,f)}}function Bi(){return new xi}var B36=new ew,$F0=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),ZF0=X.enum(["discovered","approved"]),ksx=X.object({name:X.string(),kind:sw,organization:X.string().optional(),brainName:X.string(),url:X.string().url(),did:X.string().optional(),status:ZF0,discoveredAt:X.string().datetime()}),Msx=q3.extend({entityType:X.literal("agent"),metadata:X.object({name:X.string(),url:X.string().url(),status:ZF0,slug:X.string()})}),Ai=X.object({name:X.string(),description:X.string(),tags:X.array(X.string()),examples:X.array(X.string())}),vsx=q3.extend({entityType:X.literal("skill"),metadata:Ai}),Nsx=X.object({about:X.string(),skills:X.array($F0),notes:X.string()});function Isx(x){if(!Array.isArray(x)||x.length===0)return"";return x.map((A)=>{let w=A.tags.length>0?` [${A.tags.join(", ")}]`:"";return`- ${A.name}: ${A.description}${w}`}).join(`
5204
+ `;import{jsxDEV as x4}from"preact/jsx-dev-runtime";var DF0=fF0,Gk=X.object({title:X.string(),detail:X.string().optional()}),_sx=X.discriminatedUnion("status",[X.object({status:X.literal("generating")}),X.object({status:X.literal("ready"),strengths:X.array(Gk).default([]),weaknesses:X.array(Gk).default([]),opportunities:X.array(Gk).default([]),threats:X.array(Gk).default([]),derivedAt:X.string()})]);function Psx({items:x}){if(x.length===0)return x4("p",{class:"swot-empty",children:"\u2014"},void 0,!1,void 0,this);return x4("ul",{class:"swot-list",children:x.map((B)=>x4("li",{class:"swot-item",children:[x4("b",{children:B.title},void 0,!1,void 0,this),B.detail?x4("span",{children:[" \u2014 ",B.detail]},void 0,!0,void 0,this):null]},`${B.title}:${B.detail??""}`,!0,void 0,this))},void 0,!1,void 0,this)}function Ek({title:x,tone:B,items:A}){return x4("section",{class:`swot-cell is-${B}`,children:[x4("div",{class:"swot-head",children:x},void 0,!1,void 0,this),x4(Psx,{items:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function oS({data:x}){let B=_sx.safeParse(x);if(!B.success||B.data.status==="generating")return x4("div",{"data-swot-widget":!0,children:x4("p",{class:"muted",children:"generating assessment\u2026"},void 0,!1,void 0,this)},void 0,!1,void 0,this);let A=B.data;return x4("div",{"data-swot-widget":!0,children:x4("div",{class:"swot",role:"grid","aria-label":"SWOT analysis of agent network",children:[x4(Ek,{title:"Strengths",tone:"s",items:A.strengths},void 0,!1,void 0,this),x4(Ek,{title:"Weaknesses",tone:"w",items:A.weaknesses},void 0,!1,void 0,this),x4(Ek,{title:"Opportunities",tone:"o",items:A.opportunities},void 0,!1,void 0,this),x4(Ek,{title:"Threats",tone:"t",items:A.threats},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var tS={name:"@brains/assessment",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Assessment outputs and capability-profile analysis",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Lsx=X.object({status:X.enum(["ready","generating"])}),eS=new ew;class xi extends g8{entityType="swot";schema=BF;adapter=eS;initialSyncComplete=!1;constructor(){super("swot",tS,{},qB)}getEntityTypeConfig(){return{projectionSourceRole:"supporting"}}async onRegister(x){let B=new Uk(this.logger.child("SwotDerivationHandler"),x);x.jobs.registerHandler("derive",B),x.eval.registerHandler("deriveSwot",async()=>{let D=IQ.from(async()=>{});if(!D)throw Error("Expected progress reporter to be created");await B.process({reason:"eval"},"eval-swot-derive",D);let $=await x.entityService.getEntity({entityType:"swot",id:"swot"});if(!$)throw Error("Expected SWOT entity to be created during eval");return eS.parseSwotContent($.content).frontmatter});let A=async(D)=>{try{return await x.jobs.enqueue({type:"derive",data:{reason:D},options:{source:this.id,priority:10,deduplication:"coalesce",deduplicationKey:"swot",metadata:{operationType:"data_processing",operationTarget:`swot:${D}`}}})}catch($){return this.logger.error("Failed to queue SWOT derivation",{error:$,reason:D}),null}},w=async(D)=>{if(!await x.entityService.getEntity({entityType:"swot",id:"swot"}))await A(D)};x.messaging.subscribe(HB.initialCompleted,async()=>{return this.initialSyncComplete=!0,await w("initial-missing-entity"),{success:!0}}),x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.dashboard.registerWidget({id:"swot",title:"SWOT",group:"network",section:"secondary",priority:14,rendererName:"SwotWidget",digestProvider:(D)=>{let{status:$}=Lsx.parse(D);return{digest:[{label:"SWOT",value:$==="ready"?"Ready":"Generating",tone:$==="ready"?"good":"warn"}]}},component:oS,clientStyles:DF0,dataProvider:async()=>{let D=await x.entityService.getEntity({entityType:"swot",id:"swot"});if(!D)return{status:"generating"};let{frontmatter:$}=eS.parseSwotContent(D.content);return{status:"ready",...$}}}),{success:!0}});let f=async(D)=>{let{entityType:$}=D.payload;if(!this.initialSyncComplete)return{success:!0};if($!=="agent"&&$!=="skill")return{success:!0};return await A("entity-change"),{success:!0}};x.messaging.subscribe(l8.created,f),x.messaging.subscribe(l8.updated,f),x.messaging.subscribe(l8.deleted,f)}}function Bi(){return new xi}var B36=new ew,$F0=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),ZF0=X.enum(["discovered","approved"]),ksx=X.object({name:X.string(),kind:sw,organization:X.string().optional(),brainName:X.string(),url:X.string().url(),did:X.string().optional(),status:ZF0,discoveredAt:X.string().datetime()}),Msx=q3.extend({entityType:X.literal("agent"),metadata:X.object({name:X.string(),url:X.string().url(),status:ZF0,slug:X.string()})}),Ai=X.object({name:X.string(),description:X.string(),tags:X.array(X.string()),examples:X.array(X.string())}),vsx=q3.extend({entityType:X.literal("skill"),metadata:Ai}),Nsx=X.object({about:X.string(),skills:X.array($F0),notes:X.string()});function Isx(x){if(!Array.isArray(x)||x.length===0)return"";return x.map((A)=>{let w=A.tags.length>0?` [${A.tags.join(", ")}]`:"";return`- ${A.name}: ${A.description}${w}`}).join(`
5205
5205
  `)}function Osx(x){if(!x.trim())return[];return x.split(`
5206
- `).map((B)=>B.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/)).filter((B)=>B!==null).map((B)=>({name:B[1]??"",description:B[2]??"",tags:B[3]?B[3].split(",").map((A)=>A.trim()).filter(Boolean):[]}))}var hsx=new q9(Nsx,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:Isx,parser:Osx},{key:"notes",label:"Notes",type:"string"}]});class QF0 extends ox{constructor(){super({entityType:"agent",purpose:"An agent entity used for SWOT evaluation.",schema:Msx,frontmatterSchema:ksx})}fromMarkdown(x){return{content:x,entityType:"agent"}}createAgentContent(x){let B=hsx.format({about:x.about,skills:x.skills,notes:x.notes});return this.buildMarkdown(B,{name:x.name,kind:x.kind,...x.organization?{organization:x.organization}:{},brainName:x.brainName,url:x.url,...x.did?{did:x.did}:{},status:x.status,discoveredAt:x.discoveredAt})}}class XF0 extends ox{constructor(){super({entityType:"skill",purpose:"A skill entity used for SWOT evaluation.",schema:vsx,frontmatterSchema:Ai})}fromMarkdown(x){let B=this.parseFrontMatter(x,Ai);return{content:x,entityType:"skill",metadata:B}}createSkillContent(x){return this.buildMarkdown("",x)}}var A36=new QF0,w36=new XF0,Rsx=X.object({name:X.string(),description:X.string(),tags:X.array(X.string()),examples:X.array(X.string())}),f36=X.object({skills:X.array(Rsx),agents:X.array(X.object({id:X.string().optional(),name:X.string(),kind:sw,organization:X.string().optional(),brainName:X.string(),url:X.url(),did:X.string().optional(),status:X.enum(["discovered","approved"]),discoveredAt:X.string().datetime().optional(),about:X.string(),skills:X.array($F0),notes:X.string().default("")}))});var ysx=X.object({}).strict();function YF0(x={}){return ysx.parse(x),[Bi()]}var wi=X.object({enabled:X.boolean().default(!1).describe("Opt in to bounded Jetstream brain-card discovery"),endpoint:X.url().refine((x)=>new URL(x).protocol==="wss:",{message:"Jetstream endpoint must use wss"}).default("wss://jetstream2.us-east.bsky.network/subscribe"),replayWindowSeconds:X.number().int().min(60).max(604800).default(21600),denyDids:X.array(X.string().startsWith("did:plc:")).default([]),denyDomains:X.array(X.string().min(1)).default([]),skillKeywords:X.array(X.string().min(1)).default([]),queueLimit:X.number().int().min(1).max(1e4).default(256),concurrency:X.number().int().min(1).max(32).default(2),perDidCooldownSeconds:X.number().int().min(0).max(86400).default(300),fetchBudgetPerMinute:X.number().int().min(1).max(1e4).default(60),newAgentsPerHour:X.number().int().min(1).max(1e4).default(20),pendingCandidateCeiling:X.number().int().min(1).max(1e5).default(200),staleCandidateRetentionDays:X.number().int().min(1).max(3650).default(30),requestTimeoutMs:X.number().int().min(100).max(120000).default(1e4),maxResponseBytes:X.number().int().min(1024).max(10485760).default(262144),maxRedirects:X.number().int().min(0).max(10).default(3),retryAttempts:X.number().int().min(1).max(10).default(3),heartbeatIntervalHours:X.number().min(1).max(168).default(24)}).strict(),msx=wi.parse({}),fi=X.object({enabled:X.boolean().default(!0),pdsEndpoint:X.url().default("https://bsky.social").describe("AT Protocol PDS service endpoint"),identifier:X.string().optional().describe("PDS login identifier, usually a handle or account DID"),repoDid:X.string().optional().describe("DID of the PDS repo that owns records"),appPassword:X.string().optional().describe("App password for prototype authentication; supply via ${ENV_VAR} interpolation, never a committed literal"),anchorDid:X.string().optional().describe("Optional Anchor DID referenced from records; defaults to did:web:<site-host>:anchor when omitted"),brainDid:X.string().optional().describe("Optional public brain DID referenced from records; defaults to did:web:<site-host> when omitted"),accountDid:X.string().optional().describe("Owner's atproto account DID (did:plc:\u2026). When set, the brain serves it at /.well-known/atproto-did so the owner's handle can verify against this domain (HTTP method) \u2014 member handles under the fleet domain"),lexiconAuthority:X.boolean().default(!1).describe("Publish canonical ai.rizom.brain.* schemas from this PDS repo; enable only for the DNS-designated lexicon authority account"),jetstream:wi.default(msx)});var Csx=30000;function csx(x,B){return(A,w)=>x(A,{...w,signal:w?.signal?AbortSignal.any([w.signal,AbortSignal.timeout(B)]):AbortSignal.timeout(B)})}var gsx=X.looseObject({message:X.string()}),Tsx=X.looseObject({did:X.string(),handle:X.string(),accessJwt:X.string(),refreshJwt:X.string()}),Di=X.looseObject({uri:X.string(),cid:X.string()}),psx=Di.extend({value:X.record(X.string(),X.unknown())}),usx=X.looseObject({$type:X.literal("blob").optional(),ref:X.looseObject({$link:X.string()}),mimeType:X.string(),size:X.number().int().nonnegative()}).transform((x)=>({...x.$type!==void 0?{$type:x.$type}:{},ref:{$link:x.ref.$link},mimeType:x.mimeType,size:x.size})),Ssx=X.looseObject({blob:usx});function isx(x){return x.replace(/\/+$/,"")}var lsx=(x,B)=>fetch(x,B);async function SV(x,B){let A=await x.text(),w=WF0(x,A);return HF0(x,w),B.parse(w)}function WF0(x,B){try{return B.length>0?JSON.parse(B):void 0}catch{if(!x.ok)throw Error(`AT Protocol request failed with ${x.status}`);throw Error("Failed to parse JSON")}}function HF0(x,B){if(x.ok)return;let A=gsx.safeParse(B);throw Error(A.success?A.data.message:`AT Protocol request failed with ${x.status}`)}class wF{pdsEndpoint;identifier;appPassword;fetchFn;session;constructor(x){this.pdsEndpoint=isx(x.pdsEndpoint),this.identifier=x.identifier,this.appPassword=x.appPassword,this.fetchFn=csx(x.fetch??lsx,x.requestTimeoutMs??Csx)}async createSession(){let x=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.server.createSession`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({identifier:this.identifier,password:this.appPassword})}),B=await SV(x,Tsx);return this.session=B,B}async createRecord(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.createRecord`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:x.repo,collection:x.collection,record:x.record,...x.rkey&&{rkey:x.rkey},...x.validate!==void 0&&{validate:x.validate}})});return SV(A,Di)}async putRecord(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.putRecord`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:x.repo,collection:x.collection,record:x.record,rkey:x.rkey,...x.validate!==void 0&&{validate:x.validate},...x.swapRecord!==void 0&&{swapRecord:x.swapRecord}})});return SV(A,Di)}async getRecord(x){let B=new URLSearchParams({repo:x.repo,collection:x.collection,rkey:x.rkey}),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.getRecord?${B.toString()}`,{method:"GET"});return SV(A,psx)}async deleteRecord(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.deleteRecord`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify(x)}),w=await A.text(),f=WF0(A,w);HF0(A,f)}async uploadBlob(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.uploadBlob`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":x.mimeType},body:new Blob([new Uint8Array(x.data)],{type:x.mimeType})});return SV(A,Ssx)}async getSession(){return this.session??=await this.createSession(),this.session}}class W5 extends Error{}var nsx=X.looseObject({did:X.string()}),FF0=X.looseObject({id:X.string().optional(),alsoKnownAs:X.array(X.string()).optional(),service:X.array(X.looseObject({id:X.string().optional(),type:X.string().optional(),serviceEndpoint:X.string().optional()})).optional()});class $i{options;constructor(x){this.options=x}createPublicPdsClient(x){let{createPdsClient:B,identifier:A,appPassword:w,fetch:f}=this.options;if(B)return B({pdsEndpoint:x,identifier:A,appPassword:w,fetch:f});return new wF({pdsEndpoint:x,identifier:A,appPassword:w,fetch:f,requestTimeoutMs:this.options.requestTimeoutMs})}async resolveRepoPdsEndpoint(x){let B=x.startsWith("did:")?x:await this.resolveHandleToDid(x);if(!B)throw Error(`Could not resolve AT Protocol repo: ${x}`);let A=await this.resolveDidToPdsEndpoint(B);if(!A)throw Error(`Could not resolve AT Protocol PDS for repo: ${B}`);return{repoDid:B,pdsEndpoint:A}}async resolveHandleToDid(x){let B=new URL("/xrpc/com.atproto.identity.resolveHandle",this.options.pdsEndpoint);B.searchParams.set("handle",x);let A=await this.options.fetch(B.toString());if(!A.ok)return;let w=nsx.safeParse(await A.json());return w.success?w.data.did:void 0}async resolveDidToPdsEndpoint(x){let B=x.startsWith("did:plc:")?await this.fetchJson(`https://plc.directory/${encodeURIComponent(x)}`):x.startsWith("did:web:")?await this.fetchJson(KF0(x)):void 0,A=FF0.safeParse(B);if(!A.success)return;return A.data.service?.find((f)=>f.id==="#atproto_pds"||f.type==="AtprotoPersonalDataServer")?.serviceEndpoint}async verifyBrainCardIdentity(x,B){let A;try{A=new URL(B.siteUrl)}catch{throw new W5("Brain card siteUrl is invalid")}if(A.protocol!=="https:")throw new W5("Brain card siteUrl must use HTTPS");let w=B.brain.did;if(!w.startsWith("did:web:"))throw new W5("Brain card brain DID must be did:web");let f=dsx(w);if(A.hostname.toLowerCase()!==f.toLowerCase())throw new W5("Brain card siteUrl and did:web hostname do not match");let D=await this.options.fetch(KF0(w));if(!D.ok){let Z=`Brain did:web document returned HTTP ${String(D.status)}`;if(D.status>=500)throw Error(Z);throw new W5(Z)}let $=FF0.safeParse(await D.json());if(!$.success||$.data.id!==w)throw new W5("Brain did:web document does not identify itself correctly");for(let Z of $.data.alsoKnownAs??[]){if(!Z.startsWith("at://"))continue;let Q=Z.slice(5).replace(/\/$/,"");if(Q===x)return;if(!Q.startsWith("did:")){if(await this.resolveHandleToDid(Q)===x)return}}throw new W5("Brain did:web document is not bound to the candidate repo DID")}async fetchJson(x){let B=await this.options.fetch(x);if(!B.ok)return;return B.json()}}function dsx(x){let[B]=x.slice(8).split(":");if(!B)throw new W5(`Invalid did:web value: ${x}`);return decodeURIComponent(B)}function KF0(x){let B=x.slice(8).split(":").map(decodeURIComponent),[A,...w]=B;if(!A)throw Error(`Invalid did:web value: ${x}`);if(w.length===0)return`https://${A}/.well-known/did.json`;return`https://${A}/${w.join("/")}/did.json`}var Zi="atproto:publish:failed";class Qi{active=new Set;chains=new Map;logger;canPublish;constructor(x,B){this.logger=x,this.canPublish=B}run(x,B){let w=(this.chains.get(x)??Promise.resolve()).then(B).catch((f)=>{this.logger.error("Unexpected AT Protocol publishing task failure",{error:g(f)})});return this.chains.set(x,w),this.active.add(w),w.then(()=>{if(this.active.delete(w),this.chains.get(x)===w)this.chains.delete(x)}),w}async settle(){while(this.active.size>0)await Promise.all(this.active)}async runTrigger(x,B,A){if(!this.canPublish())return;try{await A()}catch(w){await this.reportFailure(x,B,w)}}async reportFailure(x,B,A){let w=g(A);this.logger.error("AT Protocol ambient publishing failed",{...B,error:w});try{await x.messaging.send({type:Zi,payload:{...B,error:w},broadcast:!0})}catch(f){this.logger.error("Failed to report AT Protocol publishing failure",{error:g(f)})}}}function OQ(x){return x?.startsWith("did:web:")??!1}function jk(x){if(!OQ(x))return;let B=x.slice(8);if(!B)return;let[A]=B.split(":");if(!A)return;try{return decodeURIComponent(A)}catch{return A}}function zF0(x){if(!OQ(x))return;let B=x.slice(8);if(!B)return;let[,...A]=B.split(":");if(A.length===0)return"/.well-known/did.json";return`/${A.map((f)=>{try{return decodeURIComponent(f)}catch{return f}}).join("/")}/did.json`}function bF0(x){return x.replace(/\/+$/,"")}function iV(x){return`did:web:${encodeURIComponent(x)}`}function _k(x){return`${iV(x)}:anchor`}function Xi(x){return{"@context":["https://www.w3.org/ns/did/v1"],id:x}}function VF0(x,B){let A=x.identifier?.startsWith("did:")?void 0:x.identifier?[`at://${x.identifier}`]:void 0;return{...Xi(B),...A&&{alsoKnownAs:A},service:[{id:"#atproto_pds",type:"AtprotoPersonalDataServer",serviceEndpoint:bF0(x.pdsEndpoint)}]}}function UF0(x){if(!OQ(x.brainDid))return null;return VF0(x,x.brainDid)}function qF0(x,B){if(!x||!B)return;let A=jk(x),w=zF0(x);if(!A||!w)return;return{path:w,hostname:A,document:B}}function Pk(x){let B=[],A=qF0(x.brainDid,UF0(x));if(A)B.push(A);if(OQ(x.anchorDid)&&x.anchorDid!==x.brainDid){let w=qF0(x.anchorDid,Xi(x.anchorDid));if(w)B.push(w)}return B}function Yi(x,B){let A=[];if(!x.brainDid){let w=iV(B);A.push({path:"/.well-known/did.json",hostname:B,document:VF0(x,w)})}if(!x.anchorDid){let w=_k(B);A.push({path:"/anchor/did.json",hostname:B,document:Xi(w)})}return A}function GF0(x){if(!x.enabled)return[];let B=Pk(x),A=[...!x.brainDid?["/.well-known/did.json"]:[],...!x.anchorDid?["/anchor/did.json"]:[]],f=[...new Set([...B.map(($)=>$.path),...A])].map(($)=>({path:$,method:"GET",public:!0,handler:(Z)=>{let Q=new URL(Z.url).hostname,Y=[...Pk(x),...Yi(x,Q)].filter((H)=>H.path===$),W=Y.find((H)=>H.hostname===Q)??Y[0];if(!W)return new Response("Not found",{status:404});return new Response(JSON.stringify(W.document),{headers:{"Content-Type":"application/did+json"}})}})),D=x.accountDid;if(D)f.push({path:"/.well-known/atproto-did",method:"GET",public:!0,handler:()=>new Response(D,{headers:{"Content-Type":"text/plain"}})});return f}function asx(x,B){if(!x)return;try{return new URL(x,B).toString()}catch{return}}function ssx(x){let B=x.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,200);return B.length>0?B:"skill"}function EF0(x,B){let A=x[B];return typeof A==="string"&&A.length>0?A:void 0}function jF0(x,B){let A=x[B];if(!Array.isArray(A))return;let w=A.filter((f)=>typeof f==="string"&&f.length>0);return w.length>0?w:void 0}function rsx(x){let B=x.metadata,A=EF0(B,"name"),w=EF0(B,"description");if(!A||!w)return;let f=jF0(B,"tags"),D=jF0(B,"examples");return{id:ssx(A),name:A,description:w,...f&&{tags:f},...D&&{examples:D}}}async function osx(x){if(!x.entityService.hasEntityType("skill"))return[];return(await x.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}})).map((A)=>rsx(A)).filter((A)=>A!==void 0).slice(0,100)}async function Wi(x,B,A=new Date){let w=x.identity.get(),f=x.identity.getProfile(),D=x.profileKinds.getResolved();if(!D)throw Error("AT Protocol brain card publishing requires a configured profile kind");let $=await x.identity.getAppInfo(),Z=asx(x.siteUrl??f.website,void 0);if(!Z)throw Error("AT Protocol brain card publishing requires siteUrl");let Q=new URL(Z).hostname,Y=B.brainDid??iV(Q),W=B.anchorDid??_k(Q);if(OQ(Y)){if(jk(Y)!==Q)throw Error("AT Protocol brain card did:web host must match siteUrl host")}let H=await osx(x);return{$type:"ai.rizom.brain.card",siteUrl:Z,brain:{did:Y,name:w.name,role:w.role,purpose:w.purpose,values:w.values},anchor:{did:W,name:f.name,category:D.category,kind:D.kind},skills:H,model:$.model,version:$.version,createdAt:A.toISOString(),updatedAt:A.toISOString()}}var _F0="ai.rizom.brain.card",tsx="self",Hi="checkpoint",esx=4096,xrx=604800,Brx=X.looseObject({did:X.string().min(1),time_us:X.number().int().nonnegative(),kind:X.string(),commit:X.looseObject({rev:X.string().min(1).optional(),operation:X.string(),collection:X.string(),rkey:X.string(),cid:X.string().min(1).optional()}).optional()}),PF0=X.object({cursorTimeUs:X.number().int().nonnegative().optional(),dedupe:X.array(X.object({key:X.string().min(1),timeUs:X.number().int().nonnegative()})).default([]),didCooldowns:X.record(X.string(),X.number().int().nonnegative()).default({}),fetchTimestamps:X.array(X.number().int().nonnegative()).default([]),creationTimestamps:X.array(X.number().int().nonnegative()).default([])}).strict();function JF0(){return{dedupe:[],didCooldowns:{},fetchTimestamps:[],creationTimestamps:[]}}function Arx(x){return[x.did,x.operation,x.rev??"",x.cid??"",String(x.timeUs)].join("\x00")}async function wrx(x){if(typeof x==="string")return x;if(x instanceof ArrayBuffer)return new TextDecoder().decode(x);if(ArrayBuffer.isView(x))return new TextDecoder().decode(new Uint8Array(x.buffer,x.byteOffset,x.byteLength));if(x instanceof Blob)return x.text();throw Error("Unsupported Jetstream websocket message")}function frx(x){let B=new WebSocket(x);return{onOpen:(A)=>B.addEventListener("open",A),onMessage:(A)=>B.addEventListener("message",(w)=>A({data:w.data})),onClose:(A)=>B.addEventListener("close",A),onError:(A)=>B.addEventListener("error",A),close:(A,w)=>B.close(A,w)}}class Fi{context;config;callbacks;createSocket;now;random;store;queue=[];queuedByDid=new Map;terminal=new Map;activeTasks=new Set;state=JF0();dedupeKeys=new Set;nextSequence=1;nextCheckpointSequence=1;activeCount=0;socket;reconnectTimer;heartbeatTimer;reconnectAttempt=0;stopping=!1;persistTail=Promise.resolve();constructor(x){this.context=x.context,this.config=x.config,this.callbacks=x.callbacks,this.createSocket=x.createSocket??frx,this.now=x.now??Date.now,this.random=x.random??Math.random,this.store=x.context.runtimeState.scoped({namespace:"atproto.jetstream",schema:PF0})}async start(){if(this.stopping||this.socket)return;this.state=await this.store.get(Hi)??JF0(),this.pruneState();let x=Math.max(0,this.now()*1000-xrx*1e6);if(this.state.cursorTimeUs!==void 0&&this.state.cursorTimeUs<x){let B=this.state.cursorTimeUs;this.state.cursorTimeUs=x,await this.store.set(Hi,this.state),this.context.logger.warn("ATProto Jetstream cursor predates retained history; clamping",{previousCursorTimeUs:B,clampedCursorTimeUs:x}),await this.callbacks.reportGap?.({previousCursorTimeUs:B,clampedCursorTimeUs:x})}this.connect(),this.scheduleHeartbeat()}async stop(){if(this.stopping=!0,this.reconnectTimer)clearTimeout(this.reconnectTimer);if(this.heartbeatTimer)clearTimeout(this.heartbeatTimer);this.reconnectTimer=void 0,this.heartbeatTimer=void 0,this.socket?.close(1000,"shutdown"),this.socket=void 0,this.queue.length=0,this.queuedByDid.clear(),await Promise.allSettled(this.activeTasks),await this.persistTail}getSubscriptionUrl(){let x=new URL(this.config.endpoint);x.searchParams.set("wantedCollections",_F0);let B=Math.max(0,Math.floor(this.now()*1000-this.config.replayWindowSeconds*1e6));return x.searchParams.set("cursor",String(this.state.cursorTimeUs??B)),x.toString()}async handleRawMessage(x){let B;try{B=await wrx(x)}catch(Y){this.context.logger.warn("Ignoring unreadable Jetstream message",{error:g(Y)});return}let A;try{A=JSON.parse(B)}catch{this.context.logger.warn("Ignoring malformed Jetstream JSON");return}let w=Brx.safeParse(A);if(!w.success){this.context.logger.warn("Ignoring invalid Jetstream event");return}let f=w.data.commit,D={did:w.data.did,timeUs:w.data.time_us,operation:f?.operation??"",collection:f?.collection??"",rkey:f?.rkey??"",...f?.rev&&{rev:f.rev},...f?.cid&&{cid:f.cid}},$={sequence:this.nextSequence++,event:D,dedupeKey:Arx(D)};if(this.dedupeKeys.has($.dedupeKey)){await this.markTerminal([$]);return}if(w.data.kind!=="commit"||D.collection!==_F0||D.rkey!==tsx||!["create","update","delete"].includes(D.operation)||!D.did.startsWith("did:plc:")||this.config.denyDids.includes(D.did)){await this.markTerminal([$]);return}let Z=this.queuedByDid.get(D.did);if(Z){Z.latest=D,Z.events.push($),this.context.logger.debug("Coalesced Jetstream candidate",{repoDid:D.did,operation:D.operation});return}if(this.queue.length>=this.config.queueLimit){this.context.logger.warn("Jetstream candidate queue is full; dropping event",{repoDid:D.did,queueLimit:this.config.queueLimit}),await this.markTerminal([$]);return}let Q={did:D.did,latest:D,events:[$]};this.queue.push(Q),this.queuedByDid.set(D.did,Q),this.context.logger.debug("Queued Jetstream candidate",{repoDid:D.did,queueDepth:this.queue.length,activeCount:this.activeCount}),this.pump()}connect(){if(this.stopping)return;let x=this.getSubscriptionUrl();try{let B=this.createSocket(x);this.socket=B,B.onOpen(()=>{this.reconnectAttempt=0,this.context.logger.info("ATProto Jetstream connected",{url:x})}),B.onMessage((A)=>{this.handleRawMessage(A.data)}),B.onError(()=>{this.context.logger.warn("ATProto Jetstream websocket error")}),B.onClose(()=>{if(this.socket===B)this.socket=void 0;if(!this.stopping)this.scheduleReconnect()})}catch(B){this.context.logger.warn("ATProto Jetstream connection failed",{error:g(B)}),this.scheduleReconnect()}}scheduleReconnect(){if(this.reconnectTimer||this.stopping)return;let x=Math.min(this.reconnectAttempt++,8),B=Math.min(60000,1000*2**x),A=Math.floor(B*(0.8+this.random()*0.4));this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.connect()},A)}scheduleHeartbeat(){if(this.stopping)return;let x=this.config.heartbeatIntervalHours*60*60*1000,B=Math.floor(x*(0.9+this.random()*0.2));this.heartbeatTimer=setTimeout(()=>{this.heartbeatTimer=void 0;let A=this.callbacks.publishHeartbeat().catch((w)=>{this.context.logger.warn("ATProto brain-card heartbeat failed",{error:g(w)})}).finally(()=>this.scheduleHeartbeat());this.trackTask(A)},B)}pump(){while(!this.stopping&&this.activeCount<this.config.concurrency&&this.queue.length>0){let x=this.queue.shift();if(!x)break;this.queuedByDid.delete(x.did),this.activeCount+=1;let B=this.processCandidate(x).catch((A)=>{this.context.logger.error("Jetstream candidate processing failed",{repoDid:x.did,error:g(A)})}).finally(()=>{this.activeCount-=1,this.pump()});this.trackTask(B)}}async processCandidate(x){let B=x.latest;if(B.operation==="delete"){await this.callbacks.markUnavailable(B.did,new Date(Math.floor(B.timeUs/1000)).toISOString()),await this.markTerminal(x.events);return}let A=(this.state.didCooldowns[B.did]??0)+this.config.perDidCooldownSeconds*1000;if(this.now()<A){this.context.logger.debug("Jetstream candidate skipped by DID cooldown",{repoDid:B.did}),await this.markTerminal(x.events);return}let w={status:"skipped",retryable:!0,error:"Discovery did not run"};for(let f=0;f<this.config.retryAttempts;f+=1){if(!this.reserveFetch()){w={status:"skipped",retryable:!1,error:"Jetstream global fetch budget exhausted"};break}this.state.didCooldowns[B.did]=this.now();let D=this.canCreateCandidate();if(!D)this.context.logger.warn("Jetstream new-agent creation budget exhausted",{repoDid:B.did});if(w=await this.callbacks.discover(B.did,{allowNewCandidate:D}),w.status==="discovered"||!w.retryable)break;if(f+1<this.config.retryAttempts)await Bun.sleep(Math.min(2000,500*2**f))}if(w.created)this.state.creationTimestamps.push(this.now());if(this.context.logger.debug("Jetstream candidate reached terminal outcome",{repoDid:B.did,status:w.status,created:w.created??!1,retryable:w.retryable??!1,queueDepth:this.queue.length,activeCount:this.activeCount}),w.status==="skipped")this.context.logger.warn("Jetstream brain-card candidate skipped",{repoDid:B.did,error:w.error??"unknown error"});await this.markTerminal(x.events)}reserveFetch(){let x=this.now()-60000;if(this.state.fetchTimestamps=this.state.fetchTimestamps.filter((B)=>B>=x),this.state.fetchTimestamps.length>=this.config.fetchBudgetPerMinute)return!1;return this.state.fetchTimestamps.push(this.now()),!0}canCreateCandidate(){let x=this.now()-3600000;return this.state.creationTimestamps=this.state.creationTimestamps.filter((B)=>B>=x),this.state.creationTimestamps.length<this.config.newAgentsPerHour}async markTerminal(x){for(let w of x)this.terminal.set(w.sequence,{timeUs:w.event.timeUs,dedupeKey:w.dedupeKey});let B=!1;for(;;){let w=this.terminal.get(this.nextCheckpointSequence);if(!w)break;this.terminal.delete(this.nextCheckpointSequence),this.nextCheckpointSequence+=1,this.state.cursorTimeUs=Math.max(this.state.cursorTimeUs??0,w.timeUs),this.state.dedupe.push({key:w.dedupeKey,timeUs:w.timeUs}),this.dedupeKeys.add(w.dedupeKey),B=!0}if(!B)return;this.pruneState();let A=PF0.parse(structuredClone(this.state));this.persistTail=this.persistTail.then(()=>this.store.set(Hi,A)),await this.persistTail}pruneState(){let x=Math.max(0,this.now()*1000-this.config.replayWindowSeconds*1e6);this.state.dedupe=this.state.dedupe.filter((A)=>A.timeUs>=x).slice(-esx),this.state.fetchTimestamps=this.state.fetchTimestamps.filter((A)=>A>=this.now()-60000),this.state.creationTimestamps=this.state.creationTimestamps.filter((A)=>A>=this.now()-3600000);let B=this.now()-Math.max(this.config.perDidCooldownSeconds*2000,60000);this.state.didCooldowns=Object.fromEntries(Object.entries(this.state.didCooldowns).filter(([,A])=>A>=B)),this.dedupeKeys=new Set(this.state.dedupe.map((A)=>A.key))}trackTask(x){this.activeTasks.add(x);let B=()=>{this.activeTasks.delete(x)};x.then(B,B)}}var LF0={name:"@brains/atproto",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"AT Protocol integration for identity, publishing, discovery, and feeds",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var kF0=h4["ai.rizom.brain.card"],Ki=X.looseObject({entityType:X.string().min(1),entityId:X.string().min(1),entity:X.looseObject({visibility:X.string()}).optional()});function qi(x){return`${x.entityType}/${x.entityId}`}var fF="ai.rizom.brain.card",DF="self",lV="com.atproto.lexicon.schema",$rx=d5.completed,MF0=50,Zrx=new Set(["brain-character","anchor-profile","skill"]);class zi extends D8{deps;projectionRegistry;publishingTasks;discoveryFetch;identity;jetstreamConsumer;fullBootObserved=!1;constructor(x={},B={}){super("atproto",LF0,x,fi);this.deps=B,this.projectionRegistry=B.projectionRegistry??R4.getInstance(),this.discoveryFetch=Ak({...B.fetch&&{fetchFn:B.fetch},...B.resolveHostname&&{resolveHostname:B.resolveHostname},timeoutMs:this.config.jetstream.requestTimeoutMs,maxResponseBytes:this.config.jetstream.maxResponseBytes,maxRedirects:this.config.jetstream.maxRedirects}),this.publishingTasks=new Qi(this.logger,()=>this.hasPublishingCredentials()),this.identity=new $i({fetch:this.discoveryFetch,pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:this.config.appPassword??"",requestTimeoutMs:this.config.jetstream.requestTimeoutMs,createPdsClient:B.createPdsClient})}async onRegister(x){if(await super.onRegister(x),!this.config.enabled)return;x.messaging.subscribe(e8.pluginsRegistered,async()=>{return this.fullBootObserved=!0,{success:!0}}),x.messaging.subscribe($rx,async(B)=>{let A=Ki.safeParse(B.payload);if(A.success)this.publishingTasks.run(qi(A.data),()=>this.reconcileProjectedEntity(x,A.data));return{success:!0}}),x.messaging.subscribe(l8.updated,async(B)=>{let A=Ki.safeParse(B.payload);if(A.success){if(this.publishingTasks.run(qi(A.data),()=>this.reconcileProjectedEntity(x,A.data)),this.fullBootObserved&&Zrx.has(A.data.entityType))this.publishingTasks.run(`${fF}/${DF}`,()=>this.publishingTasks.runTrigger(x,{operation:"publish-card",entityType:"brain-card",entityId:DF,collection:fF},()=>this.publishBrainCard(x)))}return{success:!0}}),x.messaging.subscribe(l8.deleted,async(B)=>{let A=Ki.safeParse(B.payload);if(A.success)this.publishingTasks.run(qi(A.data),()=>this.deleteProjectedEntityFromTrigger(x,A.data));return{success:!0}})}async onReady(x){if(!this.config.enabled||!this.fullBootObserved)return;if(this.publishingTasks.run(fF+"/"+DF,()=>this.publishingTasks.runTrigger(x,{operation:"publish-card",entityType:"brain-card",entityId:DF,collection:fF},()=>this.publishBrainCard(x))),this.config.lexiconAuthority)this.publishingTasks.run(lV,()=>this.publishCanonicalLexiconSchemas(x));if(this.config.jetstream.enabled&&!this.jetstreamConsumer)this.jetstreamConsumer=new Fi({context:x,config:this.config.jetstream,callbacks:{discover:async(B,A)=>{let w=(await this.discoverBrainCards(x,{repos:[B],allowNewCandidates:A.allowNewCandidate})).results[0];return w?{status:w.status,...w.created!==void 0&&{created:w.created},...w.retryable!==void 0&&{retryable:w.retryable},...w.error&&{error:w.error}}:{status:"skipped",retryable:!0,error:"Discovery returned no result"}},markUnavailable:async(B,A)=>{let w=new Date(Date.parse(A)+this.config.jetstream.staleCandidateRetentionDays*24*60*60*1000).toISOString();await x.messaging.send({type:Dk,payload:{repoDid:B,observedAt:A,staleAfter:w,reason:"deleted"},broadcast:!0})},publishHeartbeat:async()=>{if(!this.hasPublishingCredentials())return;await this.publishBrainCard(x)},reportGap:async(B)=>{await x.messaging.send({type:NF0,payload:{...B,observedAt:new Date(this.deps.now?.()??Date.now()).toISOString()},broadcast:!0})}},...this.deps.createJetstreamSocket&&{createSocket:this.deps.createJetstreamSocket},...this.deps.now&&{now:this.deps.now},...this.deps.random&&{random:this.deps.random}}),await this.jetstreamConsumer.start()}async onShutdown(){await this.jetstreamConsumer?.stop(),this.jetstreamConsumer=void 0,await this.publishingTasks.settle()}getWebRoutes(){return GF0(this.config)}async publishBrainCard(x,B={}){let A=await Wi(x,this.config);tD(kF0,A);let w=this.config.repoDid;if(B.dryRun)return{record:A,dryRun:!0,...w&&{repo:w}};let f=this.resolveAppPassword();if(!this.config.identifier||!f)throw Error("AT Protocol publishing requires identifier and app password configuration");let D=this.createPdsClient(f),$=await D.createSession(),Z=w??$.did;if(!D.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let Q=await D.putRecord({repo:Z,collection:"ai.rizom.brain.card",rkey:"self",validate:!1,record:A});return{record:A,repo:Z,uri:Q.uri,cid:Q.cid,dryRun:!1}}async publishEntity(x,B){let A=this.projectionRegistry.get(B.entityType);if(!A)throw Error(`No AT Protocol projection registered for ${B.entityType}`);return this.publishProjectedEntity(x,B,A)}async publishPost(x,B){let A=this.projectionRegistry.get("post");if(!A)throw Error("No AT Protocol projection registered for post");return this.publishProjectedEntity(x,{entityType:"post",...B},A)}async discoverBrainCards(x,B){let A=[...new Set(B.repos.map((D)=>D.trim()))].filter((D)=>D.length>0);if(A.length===0)throw Error("AT Protocol discovery requires at least one repo DID or handle");if(A.length>MF0)throw Error(`AT Protocol discovery accepts at most ${MF0} repos per batch`);let w=new Set,f=[];for(let D of A)try{let $=await this.identity.resolveRepoPdsEndpoint(D);await Bk($.pdsEndpoint,this.deps.resolveHostname);let Z=this.identity.createPublicPdsClient($.pdsEndpoint);if(!Z.getRecord)throw new W5("AT Protocol PDS client does not support record reads");let Q=await Z.getRecord({repo:$.repoDid,collection:fF,rkey:DF});if(Qrx(Q.uri)!==$.repoDid)throw new W5(`Returned AT URI repo does not match candidate ${$.repoDid}`);if(Q.uri!==`at://${$.repoDid}/${fF}/${DF}`)throw new W5("Returned AT URI is not the canonical brain-card record");try{tD(kF0,Q.value)}catch(K){throw new W5(g(K))}let W=cV.parse({repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,record:Q.value}).record;await this.identity.verifyBrainCardIdentity($.repoDid,W);let H=await this.applyDiscoveryAdmission(x,$.repoDid,W,B.allowNewCandidates??!0),F=`${$.repoDid}:${Q.uri}:${Q.cid}`;if(w.has(F)){f.push({repo:D,status:"skipped",repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,retryable:!1,error:"Duplicate brain card in discovery batch"});continue}w.add(F),await x.messaging.send({type:wk,payload:{repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,record:W},broadcast:!0}),f.push({repo:D,status:"discovered",repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,created:H})}catch($){f.push({repo:D,status:"skipped",retryable:!($ instanceof W5)&&!($ instanceof FB),error:g($)})}return{discovered:f.filter((D)=>D.status==="discovered").length,skipped:f.filter((D)=>D.status==="skipped").length,results:f}}async validatePdsCredentials(){let x=this.resolveAppPassword();if(!this.config.identifier||!x)return!1;try{return await this.createPdsClient(x).createSession(),!0}catch(B){return this.logger.warn("AT Protocol PDS authentication failed",{error:g(B)}),!1}}async publishProjectedEntity(x,B,A){let w=await this.findPublishEntity(x,B),f=B.entityId??B.slug;if(!f)throw Error(`${B.entityType} publish requires entityId or slug`);if(!w)throw Error(`${B.entityType} not found: ${f}`);if(w.visibility!=="public")throw Error(`Cannot publish non-public ${B.entityType}: ${f}`);let D=this.config.repoDid;if(B.dryRun){let F=await A.buildRecord({entity:w,context:x,config:this.config,...B.topics&&{topics:B.topics},dryRun:!0});return tD(A.lexicon,F),{record:F,dryRun:!0,...D&&{repo:D}}}let $=this.resolveAppPassword();if(!this.config.identifier||!$)throw Error("AT Protocol publishing requires identifier and app password configuration");let Z=this.createPdsClient($),Q=await Z.createSession(),Y=D??Q.did,W=await A.buildRecord({entity:w,context:x,config:this.config,client:Z,...B.topics&&{topics:B.topics}});if(tD(A.lexicon,W),!Z.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let H=await Z.putRecord({repo:Y,collection:A.collection,rkey:vF0(w.id),...A.validate!==void 0&&{validate:A.validate},record:W});return await A.onPublished?.({entity:w,context:x,record:W,uri:H.uri,cid:H.cid}),{record:W,repo:Y,uri:H.uri,cid:H.cid,dryRun:!1}}async publishCanonicalLexiconSchemas(x){await this.publishingTasks.runTrigger(x,{operation:"upsert-record",entityType:"lexicon-schema",entityId:"*",collection:lV},async()=>{let B=this.resolveAppPassword();if(!this.config.identifier||!B)throw Error("AT Protocol publishing requires identifier and app password configuration");let A=this.createPdsClient(B),w=await A.createSession(),f=this.config.repoDid??w.did;if(!A.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let D=A.putRecord.bind(A);for(let $ of hQ())await this.publishingTasks.runTrigger(x,{operation:"upsert-record",entityType:"lexicon-schema",entityId:$.id,collection:lV},()=>D({repo:f,collection:lV,rkey:$.id,record:{$type:lV,...$}}))})}async reconcileProjectedEntity(x,B){let A=this.projectionRegistry.get(B.entityType);if(!A||!this.hasPublishingCredentials())return;let w;try{w=await x.entityService.getEntity({entityType:B.entityType,id:B.entityId})}catch(f){await this.publishingTasks.reportFailure(x,{operation:"upsert-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},f);return}if(w?.visibility==="public"){await this.publishingTasks.runTrigger(x,{operation:"upsert-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},()=>this.publishEntity(x,{entityType:B.entityType,entityId:B.entityId}));return}await this.publishingTasks.runTrigger(x,{operation:"delete-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},()=>this.deleteProjectedRecord(A,B.entityId))}async deleteProjectedEntityFromTrigger(x,B){let A=this.projectionRegistry.get(B.entityType);if(!A||!this.hasPublishingCredentials()||B.entity&&B.entity.visibility!=="public")return;await this.publishingTasks.runTrigger(x,{operation:"delete-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},()=>this.deleteProjectedRecord(A,B.entityId))}async deleteProjectedRecord(x,B){let A=this.resolveAppPassword();if(!this.config.identifier||!A)throw Error("AT Protocol publishing requires identifier and app password configuration");let w=this.createPdsClient(A),f=await w.createSession(),D=this.config.repoDid??f.did;if(!w.deleteRecord)throw Error("AT Protocol PDS client does not support record deletion");await w.deleteRecord({repo:D,collection:x.collection,rkey:vF0(B)})}hasPublishingCredentials(){return Boolean(this.config.enabled&&this.config.identifier&&this.resolveAppPassword())}async findPublishEntity(x,B){if(B.entityId)return x.entityService.getEntity({entityType:B.entityType,id:B.entityId});if(B.slug)return(await x.entityService.listEntities({entityType:B.entityType,options:{filter:{metadata:{slug:B.slug}}}}))[0]??null;return null}async applyDiscoveryAdmission(x,B,A,w){let f=new URL(A.siteUrl).hostname.toLowerCase(),D=this.config.jetstream.denyDomains.map((G)=>G.toLowerCase()).find((G)=>f===G||f.endsWith(`.${G}`));if(D)throw new W5(`Brain card matched denied domain ${D}`);let $=this.config.jetstream.skillKeywords.map((G)=>G.toLowerCase());if($.length>0){let G=A.skills.flatMap((E)=>[E.name,E.description,...E.tags??[]]).join(`
5207
- `).toLowerCase();if(!$.some((E)=>G.includes(E)))throw new W5("Brain card did not match configured skill keywords")}let Z=await x.entityService.listEntities({entityType:"agent"}),Q=Z.find((G)=>G.id===f),Y=Z.find((G)=>G.metadata.repoDid===B),W=Q?.metadata.repoDid,H=Q?.metadata.brainDid,F=typeof W==="string"&&W!==B,K=W===void 0&&typeof H==="string"&&H!==A.brain.did,q=Y!==void 0&&Y.id!==f;if(F||K||q){let G=typeof W==="string"?W:void 0;throw await x.messaging.send({type:dH,payload:{domain:f,...G&&{existingRepoDid:G},candidateRepoDid:B,observedAt:new Date().toISOString(),reason:"ATProto agent identity collision"},broadcast:!0}),new W5(`ATProto agent identity collision for ${f}`)}if(Q??Y)return!1;if(!w)throw new W5("Jetstream new-agent creation rate cap reached");if(Z.filter((G)=>G.metadata.status==="discovered").length>=this.config.jetstream.pendingCandidateCeiling)throw new W5("Jetstream pending-candidate ceiling reached");return!0}createPdsClient(x){if(this.deps.createPdsClient)return this.deps.createPdsClient({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:x});return new wF({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:x})}resolveAppPassword(){return this.config.appPassword}}function vF0(x){let B=x.replace(/[^A-Za-z0-9._~:-]/g,"_").slice(0,512);return B.length>0?B:"self"}function Qrx(x){return/^at:\/\/([^/]+)/.exec(x)?.[1]}function Jk(x,B){return new zi(x,B)}var IF0={name:"@brains/atproto-registry",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Canonical Rizom AT Protocol lexicon registry",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var OF0=X.object({enabled:X.boolean().default(!0)}),Vi="/atproto/lexicons";class Gi extends D8{constructor(x={}){super("atproto-registry",IF0,x,OF0)}getWebRoutes(){if(!this.config.enabled)return[];return[{path:`${Vi}/index.json`,method:"GET",public:!0,handler:()=>nV(this.getIndex())},...hQ().map((x)=>({path:`${Vi}/${x.id}.json`,method:"GET",public:!0,handler:()=>nV(x)}))]}getIndex(){return{lexicons:Ui().map((x)=>({...x,path:`${Vi}/${x.id}.json`}))}}getLexicon(x){return bi(x)}async getTools(){return[this.createListLexiconsTool(),this.createValidateLexiconTool(),this.createCheckContractsTool()]}createListLexiconsTool(){return E1(this.id,"list_lexicons","List canonical Rizom AT Protocol lexicons.",X.object({}),async()=>({success:!0,data:this.getIndex()}))}createValidateLexiconTool(){return E1(this.id,"validate_lexicon","Validate a record payload against a canonical Rizom AT Protocol lexicon.",X.strictObject({nsid:X.string().describe("Canonical lexicon NSID"),record:X.record(X.string(),X.unknown()).describe("Record payload to validate")}),async(x)=>{let B=this.getLexicon(x.nsid);if(!B)return{success:!1,error:`Unknown AT Protocol lexicon: ${x.nsid}`};let A;try{tD(B,x.record),A={valid:!0}}catch(w){A={valid:!1,error:g(w,"Invalid record")}}return{success:!0,data:A}})}createCheckContractsTool(){return E1(this.id,"check_contracts","Check that canonical Rizom AT Protocol lexicon contracts are available.",X.object({}),async()=>({success:!0,data:{lexiconCount:hQ().length,nsids:hQ().map((x)=>x.id),metadata:Ui()}}))}}function Ei(x={}){return new Gi(x)}var hF0=["meet.google.com","zoom.us","teams.microsoft.com","whereby.com","gather.town","calendly.com","cal.com","discord.com","discord.gg","cdn.discordapp.com","media.discordapp.net","giphy.com","tenor.com","wetransfer.com","file.io"],Yrx=X.object({botToken:X.string().min(1).describe("Discord bot token"),publicKey:X.string().min(1).describe("Discord application public key"),applicationId:X.string().min(1).describe("Discord application ID"),mentionRoleIds:X.array(X.string()).default([]),allowedChannels:X.array(X.string()).default([]),requireMention:X.boolean().default(!0),allowDMs:X.boolean().default(!0),showTypingIndicator:X.boolean().default(!0),useThreads:X.boolean().default(!0),captureUrls:X.boolean().default(!1),blockedUrlDomains:X.array(X.string()).default(hF0),captureUrlEmoji:X.string().default("\uD83D\uDD16")}),Wrx=X.object({botToken:X.string().min(1).describe("Slack bot token"),mode:X.enum(["webhook","socket"]).default("webhook"),signingSecret:X.string().min(1).optional().describe("Slack signing secret"),appToken:X.string().min(1).optional().describe("Slack app-level token"),allowedChannels:X.array(X.string()).default([]),requireMention:X.boolean().default(!0),allowDMs:X.boolean().default(!0),showTypingIndicator:X.boolean().default(!0),captureUrls:X.boolean().default(!1),blockedUrlDomains:X.array(X.string()).default(hF0)}).superRefine((x,B)=>{if(x.mode==="webhook"&&!x.signingSecret)B.addIssue({code:"custom",message:"Slack signing secret is required in webhook mode",path:["signingSecret"]});if(x.mode==="socket"&&!x.appToken)B.addIssue({code:"custom",message:"Slack app token is required in socket mode",path:["appToken"]})}),ji=X.object({userName:X.string().default("brain"),adapters:X.object({discord:Yrx.optional(),slack:Wrx.optional()}).default({}),gatewayRunMs:X.number().int().positive().default(540000),gatewayRestartDelayMs:X.number().int().nonnegative().default(1000)}).superRefine((x,B)=>{if(!x.adapters.discord&&!x.adapters.slack)B.addIssue({code:"custom",message:"At least one chat adapter must be configured",path:["adapters"]})});class _i{actions=new Map;maxEntries;constructor(x=1000){this.maxEntries=x}register(x,B){let A=i8("action");this.actions.set(A,{threadId:x,...B});while(this.actions.size>this.maxEntries){let w=this.actions.keys().next().value;if(w===void 0)break;this.actions.delete(w)}return A}get(x){return this.actions.get(x)}consume(x){this.actions.delete(x)}get size(){return this.actions.size}}class Lk{threads=new Map;sentMessages=new Map;ttlMs;constructor(x=3600000){this.ttlMs=x}set(x){this.cleanup(),this.threads.set(x.id,{thread:x,expiresAt:Date.now()+this.ttlMs})}get(x){if(!x)return;let B=this.threads.get(x);if(!B)return;if(B.expiresAt<=Date.now()){this.threads.delete(x);return}return B.expiresAt=Date.now()+this.ttlMs,B.thread}trackMessage(x,B){this.sentMessages.set(this.messageKey(x,B.id),B)}getMessage(x,B){if(!x)return;return this.sentMessages.get(this.messageKey(x,B))}clear(){this.threads.clear(),this.sentMessages.clear()}cleanup(){let x=Date.now();for(let[B,A]of this.threads)if(A.expiresAt<=x)this.threads.delete(B)}messageKey(x,B){return`${x}:${B}`}}class Pi{threadRegistry;messages=new Map;constructor(x){this.threadRegistry=x}clear(){this.messages.clear()}async handle(x){let B=dV(x);if(x.state==="running"){await this.send(B,x);return}await this.update(B,x)}async dismiss(x){let B=dV(x),A=this.messages.get(B);if(!A)return;this.messages.delete(B),await A.message.delete()}async send(x,B){let A=B.channelId;if(!A)return;let w=this.threadRegistry.get(A);if(!w)return;let f=await w.post(RF0(B));this.threadRegistry.trackMessage(A,f),this.messages.set(x,{channelId:A,message:f})}async update(x,B){let A=RF0(B),w=this.messages.get(x);if(w){let Z=await w.message.edit(A);this.threadRegistry.trackMessage(w.channelId,Z),this.messages.delete(x);return}let f=B.channelId;if(!f)return;let D=this.threadRegistry.get(f);if(!D)return;let $=await D.post(A);this.threadRegistry.trackMessage(f,$)}}function RF0(x){let B=kk(x),A=[{type:"text",content:B.label}];if(x.error)A.push({type:"text",content:x.error});return{card:{type:"card",title:B.title,children:A},fallbackText:B.fallback}}var vk="approval.confirm",Ji="approval.cancel",aV="chat.prompt",Hrx="chat.event.unavailable",Frx=5,Krx=5,yF0=Frx*Krx,mF0=80;function Li(x){let B=Mk(x),A=[{type:"text",content:B.label}];if(B.amount)A.push({type:"text",content:B.amount});if(B.message)A.push({type:"text",content:B.message});return{card:{type:"card",title:B.title,children:A},fallbackText:B.fallback}}class ki{deps;constructor(x){this.deps=x}buildSupplementalCard(x,B){switch(B.kind){case"attachment":return;case"tool-approval":return this.buildToolApprovalSummaryCard(B);case"sources":return this.buildSourcesSummaryCard(B);case"actions":return this.buildActionsSummaryCard(x,B)}}buildToolApprovalSummaryCard(x){let B=[{type:"text",content:x.summary||CF0(x.toolName)},{type:"text",content:`Status: ${x.state}`}];if(x.preview)B.push({type:"text",content:x.preview});let A=cF0(x.output);if(A)B.push({type:"text",content:`Result: ${A}`});if(x.error)B.push({type:"text",content:`Error: ${x.error}`});return{type:"card",title:x.state==="approval-requested"?"Approval required":"Approval status",children:B}}buildSourcesSummaryCard(x){let B=x.sources.map((w)=>({type:"text",content:w.title??w.source})),A=x.sources.map((w,f)=>this.buildSourceLinkButton(x.sources.length===1?"Open source":`Open ${f+1}`,w.url)).filter((w)=>Boolean(w)).slice(0,yF0);if(A.length>0)B.push({type:"actions",children:A});return{type:"card",title:x.title??"Sources",children:B}}buildActionsSummaryCard(x,B){let A=x.startsWith("slack:")?[]:B.actions.map((f)=>({type:"text",content:this.formatActionCardText(f)})),w=[];for(let f of B.actions){if(w.length>=yF0)break;if(f.type==="prompt"){let D=this.deps.registerPromptAction(x,{label:f.label,prompt:f.prompt});w.push({type:"button",id:x.startsWith("slack:")?`${aV}:${D}`:aV,label:this.truncateDiscordButtonLabel(f.label),value:D});continue}w.push({type:"button",id:Hrx,label:this.truncateDiscordButtonLabel(f.label),value:f.event,disabled:!0})}if(w.length>0)A.push({type:"actions",children:w});return{type:"card",title:B.title??"Suggested actions",children:A}}buildArtifactCard(x){let B=[];if(x.description)B.push({type:"text",content:x.description});let A=[x.filename?{type:"field",label:"File",value:x.filename}:void 0,x.mediaType?{type:"field",label:"Type",value:x.mediaType}:void 0,x.sizeLabel?{type:"field",label:"Size",value:x.sizeLabel}:void 0].filter((f)=>Boolean(f));if(A.length>0)B.push({type:"fields",children:A});let w=[this.buildArtifactLinkButton("Preview",x.previewUrl),this.buildArtifactLinkButton("Open",x.url),this.buildArtifactLinkButton("Download",x.downloadUrl)].filter((f)=>Boolean(f));if(w.length>0)B.push({type:"actions",children:w});return{type:"card",title:x.title,children:B}}formatArtifactFallback(x){let B=[`Artifact: ${x.title}`];if(x.description)B.push(x.description);if(x.filename)B.push(`File: ${x.filename}`);if(x.mediaType)B.push(`Type: ${x.mediaType}`);if(x.sizeLabel)B.push(`Size: ${x.sizeLabel}`);return B.join(`
5206
+ `).map((B)=>B.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/)).filter((B)=>B!==null).map((B)=>({name:B[1]??"",description:B[2]??"",tags:B[3]?B[3].split(",").map((A)=>A.trim()).filter(Boolean):[]}))}var hsx=new q9(Nsx,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:Isx,parser:Osx},{key:"notes",label:"Notes",type:"string"}]});class QF0 extends ox{constructor(){super({entityType:"agent",purpose:"An agent entity used for SWOT evaluation.",schema:Msx,frontmatterSchema:ksx})}fromMarkdown(x){return{content:x,entityType:"agent"}}createAgentContent(x){let B=hsx.format({about:x.about,skills:x.skills,notes:x.notes});return this.buildMarkdown(B,{name:x.name,kind:x.kind,...x.organization?{organization:x.organization}:{},brainName:x.brainName,url:x.url,...x.did?{did:x.did}:{},status:x.status,discoveredAt:x.discoveredAt})}}class XF0 extends ox{constructor(){super({entityType:"skill",purpose:"A skill entity used for SWOT evaluation.",schema:vsx,frontmatterSchema:Ai})}fromMarkdown(x){let B=this.parseFrontMatter(x,Ai);return{content:x,entityType:"skill",metadata:B}}createSkillContent(x){return this.buildMarkdown("",x)}}var A36=new QF0,w36=new XF0,Rsx=X.object({name:X.string(),description:X.string(),tags:X.array(X.string()),examples:X.array(X.string())}),f36=X.object({skills:X.array(Rsx),agents:X.array(X.object({id:X.string().optional(),name:X.string(),kind:sw,organization:X.string().optional(),brainName:X.string(),url:X.url(),did:X.string().optional(),status:X.enum(["discovered","approved"]),discoveredAt:X.string().datetime().optional(),about:X.string(),skills:X.array($F0),notes:X.string().default("")}))});var ysx=X.object({}).strict();function YF0(x={}){return ysx.parse(x),[Bi()]}var wi=X.object({enabled:X.boolean().default(!1).describe("Opt in to bounded Jetstream brain-card discovery"),endpoint:X.url().refine((x)=>new URL(x).protocol==="wss:",{message:"Jetstream endpoint must use wss"}).default("wss://jetstream2.us-east.bsky.network/subscribe"),replayWindowSeconds:X.number().int().min(60).max(604800).default(21600),denyDids:X.array(X.string().startsWith("did:plc:")).default([]),denyDomains:X.array(X.string().min(1)).default([]),skillKeywords:X.array(X.string().min(1)).default([]),queueLimit:X.number().int().min(1).max(1e4).default(256),concurrency:X.number().int().min(1).max(32).default(2),perDidCooldownSeconds:X.number().int().min(0).max(86400).default(300),fetchBudgetPerMinute:X.number().int().min(1).max(1e4).default(60),newAgentsPerHour:X.number().int().min(1).max(1e4).default(20),pendingCandidateCeiling:X.number().int().min(1).max(1e5).default(200),staleCandidateRetentionDays:X.number().int().min(1).max(3650).default(30),requestTimeoutMs:X.number().int().min(100).max(120000).default(1e4),maxResponseBytes:X.number().int().min(1024).max(10485760).default(262144),maxRedirects:X.number().int().min(0).max(10).default(3),retryAttempts:X.number().int().min(1).max(10).default(3),heartbeatIntervalHours:X.number().min(1).max(168).default(24)}).strict(),msx=wi.parse({}),fi=X.object({enabled:X.boolean().default(!0),pdsEndpoint:X.url().default("https://bsky.social").describe("AT Protocol PDS service endpoint"),identifier:X.string().optional().describe("PDS login identifier, usually a handle or account DID"),repoDid:X.string().optional().describe("DID of the PDS repo that owns records"),appPassword:X.string().optional().describe("App password for prototype authentication; supply via ${ENV_VAR} interpolation, never a committed literal"),anchorDid:X.string().optional().describe("Optional Anchor DID referenced from records; defaults to did:web:<site-host>:anchor when omitted"),brainDid:X.string().optional().describe("Optional public brain DID referenced from records; defaults to did:web:<site-host> when omitted"),accountDid:X.string().optional().describe("Owner's atproto account DID (did:plc:\u2026). When set, the brain serves it at /.well-known/atproto-did so the owner's handle can verify against this domain (HTTP method) \u2014 member handles under the fleet domain"),lexiconAuthority:X.boolean().default(!1).describe("Publish canonical ai.rizom.brain.* schemas from this PDS repo; enable only for the DNS-designated lexicon authority account"),jetstream:wi.default(msx)});var Csx=30000;function csx(x,B){return(A,w)=>x(A,{...w,signal:w?.signal?AbortSignal.any([w.signal,AbortSignal.timeout(B)]):AbortSignal.timeout(B)})}var gsx=X.looseObject({message:X.string()}),Tsx=X.looseObject({did:X.string(),handle:X.string(),accessJwt:X.string(),refreshJwt:X.string()}),Di=X.looseObject({uri:X.string(),cid:X.string()}),psx=Di.extend({value:X.record(X.string(),X.unknown())}),usx=X.looseObject({$type:X.literal("blob").optional(),ref:X.looseObject({$link:X.string()}),mimeType:X.string(),size:X.number().int().nonnegative()}).transform((x)=>({...x.$type!==void 0?{$type:x.$type}:{},ref:{$link:x.ref.$link},mimeType:x.mimeType,size:x.size})),Ssx=X.looseObject({blob:usx});function isx(x){return x.replace(/\/+$/,"")}var lsx=(x,B)=>fetch(x,B);async function SV(x,B){let A=await x.text(),w=WF0(x,A);return HF0(x,w),B.parse(w)}function WF0(x,B){try{return B.length>0?JSON.parse(B):void 0}catch{if(!x.ok)throw Error(`AT Protocol request failed with ${x.status}`);throw Error("Failed to parse JSON")}}function HF0(x,B){if(x.ok)return;let A=gsx.safeParse(B);throw Error(A.success?A.data.message:`AT Protocol request failed with ${x.status}`)}class wF{pdsEndpoint;identifier;appPassword;fetchFn;session;constructor(x){this.pdsEndpoint=isx(x.pdsEndpoint),this.identifier=x.identifier,this.appPassword=x.appPassword,this.fetchFn=csx(x.fetch??lsx,x.requestTimeoutMs??Csx)}async createSession(){let x=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.server.createSession`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({identifier:this.identifier,password:this.appPassword})}),B=await SV(x,Tsx);return this.session=B,B}async createRecord(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.createRecord`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:x.repo,collection:x.collection,record:x.record,...x.rkey&&{rkey:x.rkey},...x.validate!==void 0&&{validate:x.validate}})});return SV(A,Di)}async putRecord(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.putRecord`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:x.repo,collection:x.collection,record:x.record,rkey:x.rkey,...x.validate!==void 0&&{validate:x.validate},...x.swapRecord!==void 0&&{swapRecord:x.swapRecord}})});return SV(A,Di)}async getRecord(x){let B=new URLSearchParams({repo:x.repo,collection:x.collection,rkey:x.rkey}),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.getRecord?${B.toString()}`,{method:"GET"});return SV(A,psx)}async deleteRecord(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.deleteRecord`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify(x)}),w=await A.text(),f=WF0(A,w);HF0(A,f)}async uploadBlob(x){let B=await this.getSession(),A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.uploadBlob`,{method:"POST",headers:{Authorization:`Bearer ${B.accessJwt}`,"Content-Type":x.mimeType},body:new Blob([new Uint8Array(x.data)],{type:x.mimeType})});return SV(A,Ssx)}async getSession(){return this.session??=await this.createSession(),this.session}}class W5 extends Error{}var nsx=X.looseObject({did:X.string()}),FF0=X.looseObject({id:X.string().optional(),alsoKnownAs:X.array(X.string()).optional(),service:X.array(X.looseObject({id:X.string().optional(),type:X.string().optional(),serviceEndpoint:X.string().optional()})).optional()});class $i{options;constructor(x){this.options=x}createPublicPdsClient(x){let{createPdsClient:B,identifier:A,appPassword:w,fetch:f}=this.options;if(B)return B({pdsEndpoint:x,identifier:A,appPassword:w,fetch:f});return new wF({pdsEndpoint:x,identifier:A,appPassword:w,fetch:f,requestTimeoutMs:this.options.requestTimeoutMs})}async resolveRepoPdsEndpoint(x){let B=x.startsWith("did:")?x:await this.resolveHandleToDid(x);if(!B)throw Error(`Could not resolve AT Protocol repo: ${x}`);let A=await this.resolveDidToPdsEndpoint(B);if(!A)throw Error(`Could not resolve AT Protocol PDS for repo: ${B}`);return{repoDid:B,pdsEndpoint:A}}async resolveHandleToDid(x){let B=new URL("/xrpc/com.atproto.identity.resolveHandle",this.options.pdsEndpoint);B.searchParams.set("handle",x);let A=await this.options.fetch(B.toString());if(!A.ok)return;let w=nsx.safeParse(await A.json());return w.success?w.data.did:void 0}async resolveDidToPdsEndpoint(x){let B=x.startsWith("did:plc:")?await this.fetchJson(`https://plc.directory/${encodeURIComponent(x)}`):x.startsWith("did:web:")?await this.fetchJson(KF0(x)):void 0,A=FF0.safeParse(B);if(!A.success)return;return A.data.service?.find((f)=>f.id==="#atproto_pds"||f.type==="AtprotoPersonalDataServer")?.serviceEndpoint}async verifyBrainCardIdentity(x,B){let A;try{A=new URL(B.siteUrl)}catch{throw new W5("Brain card siteUrl is invalid")}if(A.protocol!=="https:")throw new W5("Brain card siteUrl must use HTTPS");let w=B.brain.did;if(!w.startsWith("did:web:"))throw new W5("Brain card brain DID must be did:web");let f=dsx(w);if(A.hostname.toLowerCase()!==f.toLowerCase())throw new W5("Brain card siteUrl and did:web hostname do not match");let D=await this.options.fetch(KF0(w));if(!D.ok){let Z=`Brain did:web document returned HTTP ${String(D.status)}`;if(D.status>=500)throw Error(Z);throw new W5(Z)}let $=FF0.safeParse(await D.json());if(!$.success||$.data.id!==w)throw new W5("Brain did:web document does not identify itself correctly");for(let Z of $.data.alsoKnownAs??[]){if(!Z.startsWith("at://"))continue;let Q=Z.slice(5).replace(/\/$/,"");if(Q===x)return;if(!Q.startsWith("did:")){if(await this.resolveHandleToDid(Q)===x)return}}throw new W5("Brain did:web document is not bound to the candidate repo DID")}async fetchJson(x){let B=await this.options.fetch(x);if(!B.ok)return;return B.json()}}function dsx(x){let[B]=x.slice(8).split(":");if(!B)throw new W5(`Invalid did:web value: ${x}`);return decodeURIComponent(B)}function KF0(x){let B=x.slice(8).split(":").map(decodeURIComponent),[A,...w]=B;if(!A)throw Error(`Invalid did:web value: ${x}`);if(w.length===0)return`https://${A}/.well-known/did.json`;return`https://${A}/${w.join("/")}/did.json`}var Zi="atproto:publish:failed";class Qi{active=new Set;chains=new Map;logger;canPublish;constructor(x,B){this.logger=x,this.canPublish=B}run(x,B){let w=(this.chains.get(x)??Promise.resolve()).then(B).catch((f)=>{this.logger.error("Unexpected AT Protocol publishing task failure",{error:g(f)})});return this.chains.set(x,w),this.active.add(w),w.then(()=>{if(this.active.delete(w),this.chains.get(x)===w)this.chains.delete(x)}),w}async settle(){while(this.active.size>0)await Promise.all(this.active)}async runTrigger(x,B,A){if(!this.canPublish())return;try{await A()}catch(w){await this.reportFailure(x,B,w)}}async reportFailure(x,B,A){let w=g(A);this.logger.error("AT Protocol ambient publishing failed",{...B,error:w});try{await x.messaging.send({type:Zi,payload:{...B,error:w},broadcast:!0})}catch(f){this.logger.error("Failed to report AT Protocol publishing failure",{error:g(f)})}}}function OQ(x){return x?.startsWith("did:web:")??!1}function jk(x){if(!OQ(x))return;let B=x.slice(8);if(!B)return;let[A]=B.split(":");if(!A)return;try{return decodeURIComponent(A)}catch{return A}}function zF0(x){if(!OQ(x))return;let B=x.slice(8);if(!B)return;let[,...A]=B.split(":");if(A.length===0)return"/.well-known/did.json";return`/${A.map((f)=>{try{return decodeURIComponent(f)}catch{return f}}).join("/")}/did.json`}function bF0(x){return x.replace(/\/+$/,"")}function iV(x){return`did:web:${encodeURIComponent(x)}`}function _k(x){return`${iV(x)}:anchor`}function Xi(x){return{"@context":["https://www.w3.org/ns/did/v1"],id:x}}function VF0(x,B){let A=x.identifier?.startsWith("did:")?void 0:x.identifier?[`at://${x.identifier}`]:void 0;return{...Xi(B),...A&&{alsoKnownAs:A},service:[{id:"#atproto_pds",type:"AtprotoPersonalDataServer",serviceEndpoint:bF0(x.pdsEndpoint)}]}}function UF0(x){if(!OQ(x.brainDid))return null;return VF0(x,x.brainDid)}function qF0(x,B){if(!x||!B)return;let A=jk(x),w=zF0(x);if(!A||!w)return;return{path:w,hostname:A,document:B}}function Pk(x){let B=[],A=qF0(x.brainDid,UF0(x));if(A)B.push(A);if(OQ(x.anchorDid)&&x.anchorDid!==x.brainDid){let w=qF0(x.anchorDid,Xi(x.anchorDid));if(w)B.push(w)}return B}function Yi(x,B){let A=[];if(!x.brainDid){let w=iV(B);A.push({path:"/.well-known/did.json",hostname:B,document:VF0(x,w)})}if(!x.anchorDid){let w=_k(B);A.push({path:"/anchor/did.json",hostname:B,document:Xi(w)})}return A}function GF0(x){if(!x.enabled)return[];let B=Pk(x),A=[...!x.brainDid?["/.well-known/did.json"]:[],...!x.anchorDid?["/anchor/did.json"]:[]],f=[...new Set([...B.map(($)=>$.path),...A])].map(($)=>({path:$,method:"GET",public:!0,handler:(Z)=>{let Q=new URL(Z.url).hostname,Y=[...Pk(x),...Yi(x,Q)].filter((H)=>H.path===$),W=Y.find((H)=>H.hostname===Q)??Y[0];if(!W)return new Response("Not found",{status:404});return new Response(JSON.stringify(W.document),{headers:{"Content-Type":"application/did+json"}})}})),D=x.accountDid;if(D)f.push({path:"/.well-known/atproto-did",method:"GET",public:!0,handler:()=>new Response(D,{headers:{"Content-Type":"text/plain"}})});return f}function asx(x,B){if(!x)return;try{return new URL(x,B).toString()}catch{return}}function ssx(x){let B=x.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,200);return B.length>0?B:"skill"}function EF0(x,B){let A=x[B];return typeof A==="string"&&A.length>0?A:void 0}function jF0(x,B){let A=x[B];if(!Array.isArray(A))return;let w=A.filter((f)=>typeof f==="string"&&f.length>0);return w.length>0?w:void 0}function rsx(x){let B=x.metadata,A=EF0(B,"name"),w=EF0(B,"description");if(!A||!w)return;let f=jF0(B,"tags"),D=jF0(B,"examples");return{id:ssx(A),name:A,description:w,...f&&{tags:f},...D&&{examples:D}}}async function osx(x){if(!x.entityService.hasEntityType("skill"))return[];return(await x.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}})).map((A)=>rsx(A)).filter((A)=>A!==void 0).slice(0,100)}async function Wi(x,B,A=new Date){let w=x.identity.get(),f=x.identity.getProfile(),D=x.profileKinds.getResolved();if(!D)throw Error("AT Protocol brain card publishing requires a configured profile kind");let $=await x.identity.getAppInfo(),Z=asx(x.siteUrl??f.website,void 0);if(!Z)throw Error("AT Protocol brain card publishing requires siteUrl");let Q=new URL(Z).hostname,Y=B.brainDid??iV(Q),W=B.anchorDid??_k(Q);if(OQ(Y)){if(jk(Y)!==Q)throw Error("AT Protocol brain card did:web host must match siteUrl host")}let H=await osx(x);return{$type:"ai.rizom.brain.card",siteUrl:Z,brain:{did:Y,name:w.name,role:w.role,purpose:w.purpose,values:w.values},anchor:{did:W,name:f.name,category:D.category,kind:D.kind},skills:H,model:$.model,version:$.version,createdAt:A.toISOString(),updatedAt:A.toISOString()}}var _F0="ai.rizom.brain.card",tsx="self",Hi="checkpoint",esx=4096,xrx=604800,Brx=X.looseObject({did:X.string().min(1),time_us:X.number().int().nonnegative(),kind:X.string(),commit:X.looseObject({rev:X.string().min(1).optional(),operation:X.string(),collection:X.string(),rkey:X.string(),cid:X.string().min(1).optional()}).optional()}),PF0=X.object({cursorTimeUs:X.number().int().nonnegative().optional(),dedupe:X.array(X.object({key:X.string().min(1),timeUs:X.number().int().nonnegative()})).default([]),didCooldowns:X.record(X.string(),X.number().int().nonnegative()).default({}),fetchTimestamps:X.array(X.number().int().nonnegative()).default([]),creationTimestamps:X.array(X.number().int().nonnegative()).default([])}).strict();function JF0(){return{dedupe:[],didCooldowns:{},fetchTimestamps:[],creationTimestamps:[]}}function Arx(x){return[x.did,x.operation,x.rev??"",x.cid??"",String(x.timeUs)].join("\x00")}async function wrx(x){if(typeof x==="string")return x;if(x instanceof ArrayBuffer)return new TextDecoder().decode(x);if(ArrayBuffer.isView(x))return new TextDecoder().decode(new Uint8Array(x.buffer,x.byteOffset,x.byteLength));if(x instanceof Blob)return x.text();throw Error("Unsupported Jetstream websocket message")}function frx(x){let B=new WebSocket(x);return{onOpen:(A)=>B.addEventListener("open",A),onMessage:(A)=>B.addEventListener("message",(w)=>A({data:w.data})),onClose:(A)=>B.addEventListener("close",A),onError:(A)=>B.addEventListener("error",A),close:(A,w)=>B.close(A,w)}}class Fi{context;config;callbacks;createSocket;now;random;store;queue=[];queuedByDid=new Map;terminal=new Map;activeTasks=new Set;state=JF0();dedupeKeys=new Set;nextSequence=1;nextCheckpointSequence=1;activeCount=0;socket;reconnectTimer;heartbeatTimer;reconnectAttempt=0;stopping=!1;persistTail=Promise.resolve();constructor(x){this.context=x.context,this.config=x.config,this.callbacks=x.callbacks,this.createSocket=x.createSocket??frx,this.now=x.now??Date.now,this.random=x.random??Math.random,this.store=x.context.runtimeState.scoped({namespace:"atproto.jetstream",schema:PF0})}async start(){if(this.stopping||this.socket)return;this.state=await this.store.get(Hi)??JF0(),this.pruneState();let x=Math.max(0,this.now()*1000-xrx*1e6);if(this.state.cursorTimeUs!==void 0&&this.state.cursorTimeUs<x){let B=this.state.cursorTimeUs;this.state.cursorTimeUs=x,await this.store.set(Hi,this.state),this.context.logger.warn("ATProto Jetstream cursor predates retained history; clamping",{previousCursorTimeUs:B,clampedCursorTimeUs:x}),await this.callbacks.reportGap?.({previousCursorTimeUs:B,clampedCursorTimeUs:x})}this.connect(),this.scheduleHeartbeat()}async stop(){if(this.stopping=!0,this.reconnectTimer)clearTimeout(this.reconnectTimer);if(this.heartbeatTimer)clearTimeout(this.heartbeatTimer);this.reconnectTimer=void 0,this.heartbeatTimer=void 0,this.socket?.close(1000,"shutdown"),this.socket=void 0,this.queue.length=0,this.queuedByDid.clear(),await Promise.allSettled(this.activeTasks),await this.persistTail}getSubscriptionUrl(){let x=new URL(this.config.endpoint);x.searchParams.set("wantedCollections",_F0);let B=Math.max(0,Math.floor(this.now()*1000-this.config.replayWindowSeconds*1e6));return x.searchParams.set("cursor",String(this.state.cursorTimeUs??B)),x.toString()}async handleRawMessage(x){let B;try{B=await wrx(x)}catch(Y){this.context.logger.warn("Ignoring unreadable Jetstream message",{error:g(Y)});return}let A;try{A=JSON.parse(B)}catch{this.context.logger.warn("Ignoring malformed Jetstream JSON");return}let w=Brx.safeParse(A);if(!w.success){this.context.logger.warn("Ignoring invalid Jetstream event");return}let f=w.data.commit,D={did:w.data.did,timeUs:w.data.time_us,operation:f?.operation??"",collection:f?.collection??"",rkey:f?.rkey??"",...f?.rev&&{rev:f.rev},...f?.cid&&{cid:f.cid}},$={sequence:this.nextSequence++,event:D,dedupeKey:Arx(D)};if(this.dedupeKeys.has($.dedupeKey)){await this.markTerminal([$]);return}if(w.data.kind!=="commit"||D.collection!==_F0||D.rkey!==tsx||!["create","update","delete"].includes(D.operation)||!D.did.startsWith("did:plc:")||this.config.denyDids.includes(D.did)){await this.markTerminal([$]);return}let Z=this.queuedByDid.get(D.did);if(Z){Z.latest=D,Z.events.push($),this.context.logger.debug("Coalesced Jetstream candidate",{repoDid:D.did,operation:D.operation});return}if(this.queue.length>=this.config.queueLimit){this.context.logger.warn("Jetstream candidate queue is full; dropping event",{repoDid:D.did,queueLimit:this.config.queueLimit}),await this.markTerminal([$]);return}let Q={did:D.did,latest:D,events:[$]};this.queue.push(Q),this.queuedByDid.set(D.did,Q),this.context.logger.debug("Queued Jetstream candidate",{repoDid:D.did,queueDepth:this.queue.length,activeCount:this.activeCount}),this.pump()}connect(){if(this.stopping)return;let x=this.getSubscriptionUrl();try{let B=this.createSocket(x);this.socket=B,B.onOpen(()=>{this.reconnectAttempt=0,this.context.logger.info("ATProto Jetstream connected",{url:x})}),B.onMessage((A)=>{this.handleRawMessage(A.data)}),B.onError(()=>{this.context.logger.warn("ATProto Jetstream websocket error")}),B.onClose(()=>{if(this.socket===B)this.socket=void 0;if(!this.stopping)this.scheduleReconnect()})}catch(B){this.context.logger.warn("ATProto Jetstream connection failed",{error:g(B)}),this.scheduleReconnect()}}scheduleReconnect(){if(this.reconnectTimer||this.stopping)return;let x=Math.min(this.reconnectAttempt++,8),B=Math.min(60000,1000*2**x),A=Math.floor(B*(0.8+this.random()*0.4));this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=void 0,this.connect()},A)}scheduleHeartbeat(){if(this.stopping)return;let x=this.config.heartbeatIntervalHours*60*60*1000,B=Math.floor(x*(0.9+this.random()*0.2));this.heartbeatTimer=setTimeout(()=>{this.heartbeatTimer=void 0;let A=this.callbacks.publishHeartbeat().catch((w)=>{this.context.logger.warn("ATProto brain-card heartbeat failed",{error:g(w)})}).finally(()=>this.scheduleHeartbeat());this.trackTask(A)},B)}pump(){while(!this.stopping&&this.activeCount<this.config.concurrency&&this.queue.length>0){let x=this.queue.shift();if(!x)break;this.queuedByDid.delete(x.did),this.activeCount+=1;let B=this.processCandidate(x).catch((A)=>{this.context.logger.error("Jetstream candidate processing failed",{repoDid:x.did,error:g(A)})}).finally(()=>{this.activeCount-=1,this.pump()});this.trackTask(B)}}async processCandidate(x){let B=x.latest;if(B.operation==="delete"){await this.callbacks.markUnavailable(B.did,new Date(Math.floor(B.timeUs/1000)).toISOString()),await this.markTerminal(x.events);return}let A=(this.state.didCooldowns[B.did]??0)+this.config.perDidCooldownSeconds*1000;if(this.now()<A){this.context.logger.debug("Jetstream candidate skipped by DID cooldown",{repoDid:B.did}),await this.markTerminal(x.events);return}let w={status:"skipped",retryable:!0,error:"Discovery did not run"};for(let f=0;f<this.config.retryAttempts;f+=1){if(!this.reserveFetch()){w={status:"skipped",retryable:!1,error:"Jetstream global fetch budget exhausted"};break}this.state.didCooldowns[B.did]=this.now();let D=this.canCreateCandidate();if(!D)this.context.logger.warn("Jetstream new-agent creation budget exhausted",{repoDid:B.did});if(w=await this.callbacks.discover(B.did,{allowNewCandidate:D}),w.status==="discovered"||!w.retryable)break;if(f+1<this.config.retryAttempts)await Bun.sleep(Math.min(2000,500*2**f))}if(w.created)this.state.creationTimestamps.push(this.now());if(this.context.logger.debug("Jetstream candidate reached terminal outcome",{repoDid:B.did,status:w.status,created:w.created??!1,retryable:w.retryable??!1,queueDepth:this.queue.length,activeCount:this.activeCount}),w.status==="skipped")this.context.logger.warn("Jetstream brain-card candidate skipped",{repoDid:B.did,error:w.error??"unknown error"});await this.markTerminal(x.events)}reserveFetch(){let x=this.now()-60000;if(this.state.fetchTimestamps=this.state.fetchTimestamps.filter((B)=>B>=x),this.state.fetchTimestamps.length>=this.config.fetchBudgetPerMinute)return!1;return this.state.fetchTimestamps.push(this.now()),!0}canCreateCandidate(){let x=this.now()-3600000;return this.state.creationTimestamps=this.state.creationTimestamps.filter((B)=>B>=x),this.state.creationTimestamps.length<this.config.newAgentsPerHour}async markTerminal(x){for(let w of x)this.terminal.set(w.sequence,{timeUs:w.event.timeUs,dedupeKey:w.dedupeKey});let B=!1;for(;;){let w=this.terminal.get(this.nextCheckpointSequence);if(!w)break;this.terminal.delete(this.nextCheckpointSequence),this.nextCheckpointSequence+=1,this.state.cursorTimeUs=Math.max(this.state.cursorTimeUs??0,w.timeUs),this.state.dedupe.push({key:w.dedupeKey,timeUs:w.timeUs}),this.dedupeKeys.add(w.dedupeKey),B=!0}if(!B)return;this.pruneState();let A=PF0.parse(structuredClone(this.state));this.persistTail=this.persistTail.then(()=>this.store.set(Hi,A)),await this.persistTail}pruneState(){let x=Math.max(0,this.now()*1000-this.config.replayWindowSeconds*1e6);this.state.dedupe=this.state.dedupe.filter((A)=>A.timeUs>=x).slice(-esx),this.state.fetchTimestamps=this.state.fetchTimestamps.filter((A)=>A>=this.now()-60000),this.state.creationTimestamps=this.state.creationTimestamps.filter((A)=>A>=this.now()-3600000);let B=this.now()-Math.max(this.config.perDidCooldownSeconds*2000,60000);this.state.didCooldowns=Object.fromEntries(Object.entries(this.state.didCooldowns).filter(([,A])=>A>=B)),this.dedupeKeys=new Set(this.state.dedupe.map((A)=>A.key))}trackTask(x){this.activeTasks.add(x);let B=()=>{this.activeTasks.delete(x)};x.then(B,B)}}var LF0={name:"@brains/atproto",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"AT Protocol integration for identity, publishing, discovery, and feeds",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var kF0=h4["ai.rizom.brain.card"],Ki=X.looseObject({entityType:X.string().min(1),entityId:X.string().min(1),entity:X.looseObject({visibility:X.string()}).optional()});function qi(x){return`${x.entityType}/${x.entityId}`}var fF="ai.rizom.brain.card",DF="self",lV="com.atproto.lexicon.schema",$rx=d5.completed,MF0=50,Zrx=new Set(["brain-character","anchor-profile","skill"]);class zi extends D8{deps;projectionRegistry;publishingTasks;discoveryFetch;identity;jetstreamConsumer;fullBootObserved=!1;constructor(x={},B={}){super("atproto",LF0,x,fi);this.deps=B,this.projectionRegistry=B.projectionRegistry??R4.getInstance(),this.discoveryFetch=Ak({...B.fetch&&{fetchFn:B.fetch},...B.resolveHostname&&{resolveHostname:B.resolveHostname},timeoutMs:this.config.jetstream.requestTimeoutMs,maxResponseBytes:this.config.jetstream.maxResponseBytes,maxRedirects:this.config.jetstream.maxRedirects}),this.publishingTasks=new Qi(this.logger,()=>this.hasPublishingCredentials()),this.identity=new $i({fetch:this.discoveryFetch,pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:this.config.appPassword??"",requestTimeoutMs:this.config.jetstream.requestTimeoutMs,createPdsClient:B.createPdsClient})}async onRegister(x){if(await super.onRegister(x),!this.config.enabled)return;x.messaging.subscribe(e8.pluginsRegistered,async()=>{return this.fullBootObserved=!0,{success:!0}}),x.messaging.subscribe($rx,async(B)=>{let A=Ki.safeParse(B.payload);if(A.success)this.publishingTasks.run(qi(A.data),()=>this.reconcileProjectedEntity(x,A.data));return{success:!0}}),x.messaging.subscribe(l8.updated,async(B)=>{let A=Ki.safeParse(B.payload);if(A.success){if(this.publishingTasks.run(qi(A.data),()=>this.reconcileProjectedEntity(x,A.data)),this.fullBootObserved&&Zrx.has(A.data.entityType))this.publishingTasks.run(`${fF}/${DF}`,()=>this.publishingTasks.runTrigger(x,{operation:"publish-card",entityType:"brain-card",entityId:DF,collection:fF},()=>this.publishBrainCard(x)))}return{success:!0}}),x.messaging.subscribe(l8.deleted,async(B)=>{let A=Ki.safeParse(B.payload);if(A.success)this.publishingTasks.run(qi(A.data),()=>this.deleteProjectedEntityFromTrigger(x,A.data));return{success:!0}})}async onReady(x){if(!this.config.enabled||!this.fullBootObserved)return;if(this.publishingTasks.run(fF+"/"+DF,()=>this.publishingTasks.runTrigger(x,{operation:"publish-card",entityType:"brain-card",entityId:DF,collection:fF},()=>this.publishBrainCard(x))),this.config.lexiconAuthority)this.publishingTasks.run(lV,()=>this.publishCanonicalLexiconSchemas(x));if(this.config.jetstream.enabled&&!this.jetstreamConsumer)this.jetstreamConsumer=new Fi({context:x,config:this.config.jetstream,callbacks:{discover:async(B,A)=>{let w=(await this.discoverBrainCards(x,{repos:[B],allowNewCandidates:A.allowNewCandidate})).results[0];return w?{status:w.status,...w.created!==void 0&&{created:w.created},...w.retryable!==void 0&&{retryable:w.retryable},...w.error&&{error:w.error}}:{status:"skipped",retryable:!0,error:"Discovery returned no result"}},markUnavailable:async(B,A)=>{let w=new Date(Date.parse(A)+this.config.jetstream.staleCandidateRetentionDays*24*60*60*1000).toISOString();await x.messaging.send({type:Dk,payload:{repoDid:B,observedAt:A,staleAfter:w,reason:"deleted"},broadcast:!0})},publishHeartbeat:async()=>{if(!this.hasPublishingCredentials())return;await this.publishBrainCard(x)},reportGap:async(B)=>{await x.messaging.send({type:NF0,payload:{...B,observedAt:new Date(this.deps.now?.()??Date.now()).toISOString()},broadcast:!0})}},...this.deps.createJetstreamSocket&&{createSocket:this.deps.createJetstreamSocket},...this.deps.now&&{now:this.deps.now},...this.deps.random&&{random:this.deps.random}}),await this.jetstreamConsumer.start()}async onShutdown(){await this.jetstreamConsumer?.stop(),this.jetstreamConsumer=void 0,await this.publishingTasks.settle()}getWebRoutes(){return GF0(this.config)}async publishBrainCard(x,B={}){let A=await Wi(x,this.config);tD(kF0,A);let w=this.config.repoDid;if(B.dryRun)return{record:A,dryRun:!0,...w&&{repo:w}};let f=this.resolveAppPassword();if(!this.config.identifier||!f)throw Error("AT Protocol publishing requires identifier and app password configuration");let D=this.createPdsClient(f),$=await D.createSession(),Z=w??$.did;if(!D.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let Q=await D.putRecord({repo:Z,collection:"ai.rizom.brain.card",rkey:"self",validate:!1,record:A});return{record:A,repo:Z,uri:Q.uri,cid:Q.cid,dryRun:!1}}async publishEntity(x,B){let A=this.projectionRegistry.get(B.entityType);if(!A)throw Error(`No AT Protocol projection registered for ${B.entityType}`);return this.publishProjectedEntity(x,B,A)}async publishPost(x,B){let A=this.projectionRegistry.get("post");if(!A)throw Error("No AT Protocol projection registered for post");return this.publishProjectedEntity(x,{entityType:"post",...B},A)}async discoverBrainCards(x,B){let A=[...new Set(B.repos.map((D)=>D.trim()))].filter((D)=>D.length>0);if(A.length===0)throw Error("AT Protocol discovery requires at least one repo DID or handle");if(A.length>MF0)throw Error(`AT Protocol discovery accepts at most ${MF0} repos per batch`);let w=new Set,f=[];for(let D of A)try{let $=await this.identity.resolveRepoPdsEndpoint(D);await Bk($.pdsEndpoint,this.deps.resolveHostname);let Z=this.identity.createPublicPdsClient($.pdsEndpoint);if(!Z.getRecord)throw new W5("AT Protocol PDS client does not support record reads");let Q=await Z.getRecord({repo:$.repoDid,collection:fF,rkey:DF});if(Qrx(Q.uri)!==$.repoDid)throw new W5(`Returned AT URI repo does not match candidate ${$.repoDid}`);if(Q.uri!==`at://${$.repoDid}/${fF}/${DF}`)throw new W5("Returned AT URI is not the canonical brain-card record");try{tD(kF0,Q.value)}catch(K){throw new W5(g(K))}let W=cV.parse({repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,record:Q.value}).record;await this.identity.verifyBrainCardIdentity($.repoDid,W);let H=await this.applyDiscoveryAdmission(x,$.repoDid,W,B.allowNewCandidates??!0),F=`${$.repoDid}:${Q.uri}:${Q.cid}`;if(w.has(F)){f.push({repo:D,status:"skipped",repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,retryable:!1,error:"Duplicate brain card in discovery batch"});continue}w.add(F),await x.messaging.send({type:wk,payload:{repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,record:W},broadcast:!0}),f.push({repo:D,status:"discovered",repoDid:$.repoDid,uri:Q.uri,cid:Q.cid,created:H})}catch($){f.push({repo:D,status:"skipped",retryable:!($ instanceof W5)&&!($ instanceof FB),error:g($)})}return{discovered:f.filter((D)=>D.status==="discovered").length,skipped:f.filter((D)=>D.status==="skipped").length,results:f}}async validatePdsCredentials(){let x=this.resolveAppPassword();if(!this.config.identifier||!x)return!1;try{return await this.createPdsClient(x).createSession(),!0}catch(B){return this.logger.warn("AT Protocol PDS authentication failed",{error:g(B)}),!1}}async publishProjectedEntity(x,B,A){let w=await this.findPublishEntity(x,B),f=B.entityId??B.slug;if(!f)throw Error(`${B.entityType} publish requires entityId or slug`);if(!w)throw Error(`${B.entityType} not found: ${f}`);if(w.visibility!=="public")throw Error(`Cannot publish non-public ${B.entityType}: ${f}`);let D=this.config.repoDid;if(B.dryRun){let F=await A.buildRecord({entity:w,context:x,config:this.config,...B.topics&&{topics:B.topics},dryRun:!0});return tD(A.lexicon,F),{record:F,dryRun:!0,...D&&{repo:D}}}let $=this.resolveAppPassword();if(!this.config.identifier||!$)throw Error("AT Protocol publishing requires identifier and app password configuration");let Z=this.createPdsClient($),Q=await Z.createSession(),Y=D??Q.did,W=await A.buildRecord({entity:w,context:x,config:this.config,client:Z,...B.topics&&{topics:B.topics}});if(tD(A.lexicon,W),!Z.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let H=await Z.putRecord({repo:Y,collection:A.collection,rkey:vF0(w.id),...A.validate!==void 0&&{validate:A.validate},record:W});return await A.onPublished?.({entity:w,context:x,record:W,uri:H.uri,cid:H.cid}),{record:W,repo:Y,uri:H.uri,cid:H.cid,dryRun:!1}}async publishCanonicalLexiconSchemas(x){await this.publishingTasks.runTrigger(x,{operation:"upsert-record",entityType:"lexicon-schema",entityId:"*",collection:lV},async()=>{let B=this.resolveAppPassword();if(!this.config.identifier||!B)throw Error("AT Protocol publishing requires identifier and app password configuration");let A=this.createPdsClient(B),w=await A.createSession(),f=this.config.repoDid??w.did;if(!A.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let D=A.putRecord.bind(A);for(let $ of hQ())await this.publishingTasks.runTrigger(x,{operation:"upsert-record",entityType:"lexicon-schema",entityId:$.id,collection:lV},()=>D({repo:f,collection:lV,rkey:$.id,record:{$type:lV,...$}}))})}async reconcileProjectedEntity(x,B){let A=this.projectionRegistry.get(B.entityType);if(!A||!this.hasPublishingCredentials())return;let w;try{w=await x.entityService.getEntity({entityType:B.entityType,id:B.entityId})}catch(f){await this.publishingTasks.reportFailure(x,{operation:"upsert-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},f);return}if(w?.visibility==="public"){await this.publishingTasks.runTrigger(x,{operation:"upsert-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},()=>this.publishEntity(x,{entityType:B.entityType,entityId:B.entityId}));return}await this.publishingTasks.runTrigger(x,{operation:"delete-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},()=>this.deleteProjectedRecord(A,B.entityId))}async deleteProjectedEntityFromTrigger(x,B){let A=this.projectionRegistry.get(B.entityType);if(!A||!this.hasPublishingCredentials()||B.entity&&B.entity.visibility!=="public")return;await this.publishingTasks.runTrigger(x,{operation:"delete-record",entityType:B.entityType,entityId:B.entityId,collection:A.collection},()=>this.deleteProjectedRecord(A,B.entityId))}async deleteProjectedRecord(x,B){let A=this.resolveAppPassword();if(!this.config.identifier||!A)throw Error("AT Protocol publishing requires identifier and app password configuration");let w=this.createPdsClient(A),f=await w.createSession(),D=this.config.repoDid??f.did;if(!w.deleteRecord)throw Error("AT Protocol PDS client does not support record deletion");await w.deleteRecord({repo:D,collection:x.collection,rkey:vF0(B)})}hasPublishingCredentials(){return Boolean(this.config.enabled&&this.config.identifier&&this.resolveAppPassword())}async findPublishEntity(x,B){if(B.entityId)return x.entityService.getEntity({entityType:B.entityType,id:B.entityId});if(B.slug)return(await x.entityService.listEntities({entityType:B.entityType,options:{filter:{metadata:{slug:B.slug}}}}))[0]??null;return null}async applyDiscoveryAdmission(x,B,A,w){let f=new URL(A.siteUrl).hostname.toLowerCase(),D=this.config.jetstream.denyDomains.map((G)=>G.toLowerCase()).find((G)=>f===G||f.endsWith(`.${G}`));if(D)throw new W5(`Brain card matched denied domain ${D}`);let $=this.config.jetstream.skillKeywords.map((G)=>G.toLowerCase());if($.length>0){let G=A.skills.flatMap((E)=>[E.name,E.description,...E.tags??[]]).join(`
5207
+ `).toLowerCase();if(!$.some((E)=>G.includes(E)))throw new W5("Brain card did not match configured skill keywords")}let Z=await x.entityService.listEntities({entityType:"agent"}),Q=Z.find((G)=>G.id===f),Y=Z.find((G)=>G.metadata.repoDid===B),W=Q?.metadata.repoDid,H=Q?.metadata.brainDid,F=typeof W==="string"&&W!==B,K=W===void 0&&typeof H==="string"&&H!==A.brain.did,q=Y!==void 0&&Y.id!==f;if(F||K||q){let G=typeof W==="string"?W:void 0;throw await x.messaging.send({type:dH,payload:{domain:f,...G&&{existingRepoDid:G},candidateRepoDid:B,observedAt:new Date().toISOString(),reason:"ATProto agent identity collision"},broadcast:!0}),new W5(`ATProto agent identity collision for ${f}`)}if(Q??Y)return!1;if(!w)throw new W5("Jetstream new-agent creation rate cap reached");if(Z.filter((G)=>G.metadata.status==="discovered").length>=this.config.jetstream.pendingCandidateCeiling)throw new W5("Jetstream pending-candidate ceiling reached");return!0}createPdsClient(x){if(this.deps.createPdsClient)return this.deps.createPdsClient({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:x});return new wF({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:x})}resolveAppPassword(){return this.config.appPassword}}function vF0(x){let B=x.replace(/[^A-Za-z0-9._~:-]/g,"_").slice(0,512);return B.length>0?B:"self"}function Qrx(x){return/^at:\/\/([^/]+)/.exec(x)?.[1]}function Jk(x,B){return new zi(x,B)}var IF0={name:"@brains/atproto-registry",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Canonical Rizom AT Protocol lexicon registry",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var OF0=X.object({enabled:X.boolean().default(!0)}),Vi="/atproto/lexicons";class Gi extends D8{constructor(x={}){super("atproto-registry",IF0,x,OF0)}getWebRoutes(){if(!this.config.enabled)return[];return[{path:`${Vi}/index.json`,method:"GET",public:!0,handler:()=>nV(this.getIndex())},...hQ().map((x)=>({path:`${Vi}/${x.id}.json`,method:"GET",public:!0,handler:()=>nV(x)}))]}getIndex(){return{lexicons:Ui().map((x)=>({...x,path:`${Vi}/${x.id}.json`}))}}getLexicon(x){return bi(x)}async getTools(){return[this.createListLexiconsTool(),this.createValidateLexiconTool(),this.createCheckContractsTool()]}createListLexiconsTool(){return E1(this.id,"list_lexicons","List canonical Rizom AT Protocol lexicons.",X.object({}),async()=>({success:!0,data:this.getIndex()}))}createValidateLexiconTool(){return E1(this.id,"validate_lexicon","Validate a record payload against a canonical Rizom AT Protocol lexicon.",X.strictObject({nsid:X.string().describe("Canonical lexicon NSID"),record:X.record(X.string(),X.unknown()).describe("Record payload to validate")}),async(x)=>{let B=this.getLexicon(x.nsid);if(!B)return{success:!1,error:`Unknown AT Protocol lexicon: ${x.nsid}`};let A;try{tD(B,x.record),A={valid:!0}}catch(w){A={valid:!1,error:g(w,"Invalid record")}}return{success:!0,data:A}})}createCheckContractsTool(){return E1(this.id,"check_contracts","Check that canonical Rizom AT Protocol lexicon contracts are available.",X.object({}),async()=>({success:!0,data:{lexiconCount:hQ().length,nsids:hQ().map((x)=>x.id),metadata:Ui()}}))}}function Ei(x={}){return new Gi(x)}var hF0=["meet.google.com","zoom.us","teams.microsoft.com","whereby.com","gather.town","calendly.com","cal.com","discord.com","discord.gg","cdn.discordapp.com","media.discordapp.net","giphy.com","tenor.com","wetransfer.com","file.io"],Yrx=X.object({botToken:X.string().min(1).describe("Discord bot token"),publicKey:X.string().min(1).describe("Discord application public key"),applicationId:X.string().min(1).describe("Discord application ID"),mentionRoleIds:X.array(X.string()).default([]),allowedChannels:X.array(X.string()).default([]),requireMention:X.boolean().default(!0),allowDMs:X.boolean().default(!0),showTypingIndicator:X.boolean().default(!0),useThreads:X.boolean().default(!0),captureUrls:X.boolean().default(!1),blockedUrlDomains:X.array(X.string()).default(hF0),captureUrlEmoji:X.string().default("\uD83D\uDD16")}),Wrx=X.object({botToken:X.string().min(1).describe("Slack bot token"),mode:X.enum(["webhook","socket"]).default("webhook"),signingSecret:X.string().min(1).optional().describe("Slack signing secret"),appToken:X.string().min(1).optional().describe("Slack app-level token"),allowedChannels:X.array(X.string()).default([]),requireMention:X.boolean().default(!0),allowDMs:X.boolean().default(!0),showTypingIndicator:X.boolean().default(!0),captureUrls:X.boolean().default(!1),blockedUrlDomains:X.array(X.string()).default(hF0)}).superRefine((x,B)=>{if(x.mode==="webhook"&&!x.signingSecret)B.addIssue({code:"custom",message:"Slack signing secret is required in webhook mode",path:["signingSecret"]});if(x.mode==="socket"&&!x.appToken)B.addIssue({code:"custom",message:"Slack app token is required in socket mode",path:["appToken"]})}),ji=X.object({userName:X.string().default("brain"),adapters:X.object({discord:Yrx.optional(),slack:Wrx.optional()}).default({}),gatewayRunMs:X.number().int().positive().default(540000),gatewayRestartDelayMs:X.number().int().nonnegative().default(1000)}).superRefine((x,B)=>{if(!x.adapters.discord&&!x.adapters.slack)B.addIssue({code:"custom",message:"At least one chat adapter must be configured",path:["adapters"]})});class _i{actions=new Map;maxEntries;constructor(x=1000){this.maxEntries=x}register(x,B){let A=i8("action");this.actions.set(A,{threadId:x,...B});while(this.actions.size>this.maxEntries){let w=this.actions.keys().next().value;if(w===void 0)break;this.actions.delete(w)}return A}get(x){return this.actions.get(x)}consume(x){this.actions.delete(x)}get size(){return this.actions.size}}class Lk{threads=new Map;sentMessages=new Map;ttlMs;constructor(x=3600000){this.ttlMs=x}set(x){this.cleanup(),this.threads.set(x.id,{thread:x,expiresAt:Date.now()+this.ttlMs})}get(x){if(!x)return;let B=this.threads.get(x);if(!B)return;if(B.expiresAt<=Date.now()){this.threads.delete(x);return}return B.expiresAt=Date.now()+this.ttlMs,B.thread}trackMessage(x,B){this.sentMessages.set(this.messageKey(x,B.id),B)}getMessage(x,B){if(!x)return;return this.sentMessages.get(this.messageKey(x,B))}clear(){this.threads.clear(),this.sentMessages.clear()}cleanup(){let x=Date.now();for(let[B,A]of this.threads)if(A.expiresAt<=x)this.threads.delete(B)}messageKey(x,B){return`${x}:${B}`}}class Pi{threadRegistry;messages=new Map;constructor(x){this.threadRegistry=x}clear(){this.messages.clear()}async handle(x){let B=dV(x);if(x.state==="running"){await this.send(B,x);return}await this.update(B,x)}async dismiss(x){let B=dV(x),A=this.messages.get(B);if(!A)return;this.messages.delete(B),await A.message.delete()}async send(x,B){let A=B.channelId;if(!A)return;let w=this.threadRegistry.get(A);if(!w)return;let f=await w.post(RF0(B));this.threadRegistry.trackMessage(A,f),this.messages.set(x,{channelId:A,message:f})}async update(x,B){let A=RF0(B),w=this.messages.get(x);if(w){let Z=await w.message.edit(A);this.threadRegistry.trackMessage(w.channelId,Z),this.messages.delete(x);return}let f=B.channelId;if(!f)return;let D=this.threadRegistry.get(f);if(!D)return;let $=await D.post(A);this.threadRegistry.trackMessage(f,$)}}function RF0(x){let B=kk(x),A=[{type:"text",content:B.label}];if(x.error)A.push({type:"text",content:x.error});return{card:{type:"card",title:B.title,children:A},fallbackText:B.fallback}}var vk="approval.confirm",Ji="approval.cancel",aV="chat.prompt",Hrx="chat.event.unavailable",Frx=5,Krx=5,yF0=Frx*Krx,mF0=80;function Li(x){let B=Mk(x),A=[{type:"text",content:B.label}];if(B.amount)A.push({type:"text",content:B.amount});if(B.message)A.push({type:"text",content:B.message});return{card:{type:"card",title:B.title,children:A},fallbackText:B.fallback}}class ki{deps;constructor(x){this.deps=x}buildSupplementalCard(x,B){switch(B.kind){case"attachment":return;case"tool-approval":return this.buildToolApprovalSummaryCard(B);case"sources":return this.buildSourcesSummaryCard(B);case"actions":return this.buildActionsSummaryCard(x,B)}}buildToolApprovalSummaryCard(x){let B=[{type:"text",content:x.summary||CF0(x.toolName)},{type:"text",content:`Status: ${x.state}`}];if(x.preview)B.push({type:"text",content:x.preview});let A=cF0(x.output);if(A)B.push({type:"text",content:`Result: ${A}`});if(x.error)B.push({type:"text",content:`Error: ${x.error}`});return{type:"card",title:x.state==="approval-requested"?"Approval required":"Approval status",children:B}}buildSourcesSummaryCard(x){let B=x.sources.map((w)=>({type:"text",content:w.title??w.source})),A=x.sources.map((w,f)=>this.buildSourceLinkButton(x.sources.length===1?"Open source":`Open ${f+1}`,w.url)).filter((w)=>Boolean(w)).slice(0,yF0);if(A.length>0)B.push({type:"actions",children:A});return{type:"card",title:x.title??"Sources",children:B}}buildActionsSummaryCard(x,B){let A=x.startsWith("slack:")?[]:B.actions.map((f)=>({type:"text",content:this.formatActionCardText(f)})),w=[];for(let f of B.actions){if(w.length>=yF0)break;if(f.type==="prompt"){let D=this.deps.registerPromptAction(x,{label:f.label,prompt:f.prompt});w.push({type:"button",id:x.startsWith("slack:")?`${aV}:${D}`:aV,label:this.truncateDiscordButtonLabel(f.label),value:D});continue}w.push({type:"button",id:Hrx,label:this.truncateDiscordButtonLabel(f.label),value:f.event,disabled:!0})}if(w.length>0)A.push({type:"actions",children:w});return{type:"card",title:B.title??"Suggested actions",children:A}}buildArtifactCard(x){let B=[];if(x.description)B.push({type:"text",content:x.description});let A=[x.filename?{type:"field",label:"File",value:x.filename}:void 0,x.mediaType?{type:"field",label:"Type",value:x.mediaType}:void 0,x.sizeLabel?{type:"field",label:"Size",value:x.sizeLabel}:void 0].filter((f)=>Boolean(f));if(A.length>0)B.push({type:"fields",children:A});let w=[this.buildArtifactLinkButton("Preview",x.previewUrl),this.buildArtifactLinkButton("Open",x.url),this.buildArtifactLinkButton("Download",x.downloadUrl)].filter((f)=>Boolean(f));if(w.length>0)B.push({type:"actions",children:w});return{type:"card",title:x.title,children:B}}formatArtifactFallback(x){let B=[`Artifact: ${x.title}`];if(x.description)B.push(x.description);if(x.filename)B.push(`File: ${x.filename}`);if(x.mediaType)B.push(`Type: ${x.mediaType}`);if(x.sizeLabel)B.push(`Size: ${x.sizeLabel}`);return B.join(`
5208
5208
  `)}buildPendingConfirmationsCard(x){return{type:"card",title:"Approvals pending",children:[...x.map((B)=>({type:"text",content:`${B.id}: ${B.summary}`})),{type:"text",content:"Reply yes <approval-id> to confirm one item, or no <approval-id> to abort it."}]}}buildPendingConfirmationCard(x){return{type:"card",title:"Approval required",children:[{type:"text",content:x.summary},{type:"text",content:"Confirm this action, or cancel it. You can also reply yes/no."},{type:"actions",children:[{type:"button",id:vk,label:"Confirm",style:"primary",value:x.id},{type:"button",id:Ji,label:"Cancel",style:"danger",value:x.id}]}]}}buildResolvedApprovalCard(x,B){return{type:"card",title:B.title,children:[{type:"text",content:x},{type:"text",content:B.detail}]}}formatStructuredCard(x,B){return gF0(x,{deniedCardIds:B,resolveUrl:(A)=>this.resolveDisplayUrl(A),isHiddenUrl:(A)=>this.isLocalDisplayUrl(A),eventActionUnavailableLabel:"not available in Discord"})}buildSourceLinkButton(x,B){let A=this.resolveDisplayUrl(B);if(!A||this.isLocalDisplayUrl(A))return;return{type:"link-button",label:this.truncateDiscordButtonLabel(x),url:A}}buildArtifactLinkButton(x,B){let A=this.resolveDisplayUrl(B);if(!A||this.isLocalDisplayUrl(A))return;return{type:"link-button",label:x,url:A}}formatActionCardText(x){let B=x.description?` \u2014 ${x.description}`:"",A=x.type==="event"?" (not available in Discord)":"";return`${x.label}${B}${A}`}truncateDiscordButtonLabel(x){if(x.length<=mF0)return x;return`${x.slice(0,mF0-1)}\u2026`}resolveDisplayUrl(x){if(!x)return;try{return new URL(x).toString()}catch{if(!x.startsWith("/"))return x;let B=this.deps.getDisplayBaseUrl();if(!B)return x;return new URL(x,B).toString()}}isLocalDisplayUrl(x){try{let B=new URL(x);return B.hostname==="localhost"||B.hostname==="127.0.0.1"}catch{return x.startsWith("/")}}}function TF0(x,B=2000){if(x.length<=B)return[x];let A=brx(x),w=[],f="";for(let D of A){let $=f?`
5209
5209
 
5210
5210
  `:"";if(f.length+$.length+D.length<=B){f+=$+D;continue}if(f)w.push(f),f="";if(D.length<=B){f=D;continue}qrx(D,B,w,(Z)=>{f=Z})}if(f)w.push(f);return w}function qrx(x,B,A,w){let f="",D=x.split(`
@@ -5307,7 +5307,7 @@ ${KU(x)}
5307
5307
  \`\`\``;return this.defaultNodeToText(x,(B)=>this.nodeToMrkdwn(B))}};function xHx(x){return uQ(x,(B,A)=>`<@${A}>`)}function Jx0(x){if(!(x.contextId||x.privateMetadata))return;return JSON.stringify({c:x.contextId,m:x.privateMetadata})}function BHx(x){if(!x)return{};try{let B=JSON.parse(x);if(typeof B==="object"&&B!==null&&(("c"in B)||("m"in B)))return{contextId:B.c||void 0,privateMetadata:B.m||void 0}}catch{}return{contextId:x}}function oI(x,B){return{type:"modal",callback_id:x.callbackId,title:{type:"plain_text",text:x.title.slice(0,24)},submit:x.submitLabel?{type:"plain_text",text:x.submitLabel}:{type:"plain_text",text:"Submit"},close:x.closeLabel?{type:"plain_text",text:x.closeLabel}:{type:"plain_text",text:"Cancel"},notify_on_close:x.notifyOnClose,private_metadata:B,blocks:x.children.map(Qn8)}}function Qn8(x){switch(x.type){case"text_input":return Xn8(x);case"select":return Yn8(x);case"external_select":return Wn8(x);case"radio_select":return Hn8(x);case"text":return ZHx(x);case"fields":return XHx(x);default:throw Error(`Unknown modal child type: ${x.type}`)}}function tI(x){return{text:{type:"plain_text",text:x.label},value:x.value,...x.description?{description:{type:"plain_text",text:x.description}}:{}}}function Xn8(x){let B={type:"plain_text_input",action_id:x.id,multiline:x.multiline??!1};if(x.placeholder)B.placeholder={type:"plain_text",text:x.placeholder};if(x.initialValue)B.initial_value=x.initialValue;if(x.maxLength)B.max_length=x.maxLength;return{type:"input",block_id:x.id,optional:x.optional??!1,label:{type:"plain_text",text:x.label},element:B}}function Yn8(x){let B=x.options.map(tI),A={type:"static_select",action_id:x.id,options:B};if(x.placeholder)A.placeholder={type:"plain_text",text:x.placeholder};if(x.initialOption){let w=B.find((f)=>f.value===x.initialOption);if(w)A.initial_option=w}return{type:"input",block_id:x.id,optional:x.optional??!1,label:{type:"plain_text",text:x.label},element:A}}function Wn8(x){let B={type:"external_select",action_id:x.id};if(x.placeholder)B.placeholder={type:"plain_text",text:x.placeholder};if(x.minQueryLength!==void 0)B.min_query_length=x.minQueryLength;if(x.initialOption)B.initial_option=tI(x.initialOption);return{type:"input",block_id:x.id,optional:x.optional??!1,label:{type:"plain_text",text:x.label},element:B}}function Hn8(x){let A=x.options.slice(0,10).map((f)=>{let D={text:{type:"mrkdwn",text:f.label},value:f.value};if(f.description)D.description={type:"mrkdwn",text:f.description};return D}),w={type:"radio_buttons",action_id:x.id,options:A};if(x.initialOption){let f=A.find((D)=>D.value===x.initialOption);if(f)w.initial_option=f}return{type:"input",block_id:x.id,optional:x.optional??!1,label:{type:"plain_text",text:x.label},element:w}}var Lx0=/^[A-Z0-9_]+$/,AHx=/^U[A-Z0-9]+$/,wHx=2500;function Fn8(x,B){let A=Buffer.from(x,"utf8"),w=Buffer.from(B,"utf8");if(A.length!==w.length)return!1;return hl8(A,w)}function Kn8(x,B,A){let w=x;if(w.code!=="slack_webapi_platform_error"||w.data?.error!=="invalid_blocks")return x;let f=[...w.data.errors??[],...w.data.response_metadata?.messages??[]];A.error("Slack rejected blocks (invalid_blocks)",{details:f,blocks:JSON.stringify(B)});let D=Error(`Slack rejected blocks (invalid_blocks): ${JSON.stringify(f)}`);return D.cause=x,D}function fHx(x){let B=x.indexOf("<@"),A=x.indexOf("<#");if(B===-1)return A;if(A===-1)return B;return Math.min(B,A)}var DHx=/\/$/,qn8=2000,zn8=150,bn8=/^https?:\/\/[^/]+\.slack\.com\/archives\/([A-Z0-9]+)\/p(\d+)(?:\?.*)?$/;function Vn8(x={}){return{type:"context_actions",elements:[{type:"feedback_buttons",action_id:x.actionId??"message_feedback",positive_button:{text:{type:"plain_text",text:x.positiveLabel??"Good response"},value:x.positiveValue??"positive"},negative_button:{text:{type:"plain_text",text:x.negativeLabel??"Bad response"},value:x.negativeValue??"negative"}}]}}var kx0=4,Un8=new Set(["feature_not_enabled","method_deprecated","unknown_method"]);function Gn8(x){let B=x;return B?.code==="slack_webapi_platform_error"?B.data?.error:void 0}function En8(x){if(x===void 0)return;if(typeof x==="function")return x;return()=>x}var jn8=class x{name="slack";userName;_client;tokenClientCache=new Map;slackApiUrl;webClientOptions;signingSecret;webhookVerifier;defaultBotTokenProvider;chat=null;logger;_botUserId=null;_botId=null;formatConverter=new Zn8;static USER_CACHE_TTL_MS=691200000;static CHANNEL_CACHE_TTL_MS=691200000;static REVERSE_INDEX_TTL_MS=691200000;_externalChannels=new Set;appToken;agentView;suggestedPrompts;loadingMessages;feedbackButtons;nativeStreaming;nativeStreamingBroken=!1;mode;socketForwardingSecret;socketClient=null;clientId;clientSecret;encryptionKey;installationKeyPrefix;installationProvider;requestContext=new Ol8;get botUserId(){let B=this.requestContext.getStore();if(B?.botUserId)return B.botUserId;return this._botUserId||void 0}get isSocketMode(){return this.mode==="socket"}get webClient(){let B=this.requestContext.getStore();if(B?.token)return this.getClientForToken(B.token);if(this.defaultBotTokenProvider){let A=this.defaultBotTokenProvider();if(typeof A==="string")return this.getClientForToken(A);throw new zF("slack","botToken is configured as an async resolver and cannot be resolved synchronously for `.webClient`. Wrap the work in `adapter.withBotToken(token, () => adapter.webClient...)` after awaiting the token.")}throw new zF("slack","No bot token available. In multi-workspace mode, ensure the webhook is being processed or use `adapter.withBotToken(token, fn)` to bind a token explicitly.")}get client(){return this.webClient}getClientForToken(B){let A=this.tokenClientCache.get(B);if(!A)A=new vx0.WebClient(B,{...this.webClientOptions,...this.webClientOptions?.headers?{headers:{...this.webClientOptions.headers}}:{},...this.slackApiUrl?{slackApiUrl:this.slackApiUrl}:{}}),this.tokenClientCache.set(B,A);return A}constructor(B={}){let A=B.webhookVerifier,w=A?void 0:B.signingSecret??process.env.SLACK_SIGNING_SECRET;if(!(w||A)&&(B.mode??"webhook")==="webhook")throw new n8("slack","signingSecret or webhookVerifier is required for webhook mode. Set SLACK_SIGNING_SECRET, provide signingSecret in config, or provide a webhookVerifier.");let f=!(B.signingSecret||B.botToken||B.clientId||B.clientSecret),D=B.botToken??(f?process.env.SLACK_BOT_TOKEN:void 0),$=En8(D);if(this.slackApiUrl=B.apiUrl??process.env.SLACK_API_URL,this.webClientOptions=B.webClientOptions,this._client=new vx0.WebClient(void 0,{...this.webClientOptions,...this.webClientOptions?.headers?{headers:{...this.webClientOptions.headers}}:{},...this.slackApiUrl?{slackApiUrl:this.slackApiUrl}:{}}),this.signingSecret=w,this.webhookVerifier=A,this.defaultBotTokenProvider=$,this.logger=B.logger??new pQ("info").child("slack"),this.userName=B.userName||"bot",this._botUserId=B.botUserId||null,this.appToken=B.appToken,this.agentView=B.agentView??!1,this.suggestedPrompts=B.suggestedPrompts,this.loadingMessages=B.loadingMessages,this.nativeStreaming=B.nativeStreaming??!0,B.feedbackButtons)this.feedbackButtons=B.feedbackButtons===!0?{}:B.feedbackButtons;this.mode=B.mode??"webhook",this.socketForwardingSecret=B.socketForwardingSecret??B.appToken,this.clientId=B.clientId??(f?process.env.SLACK_CLIENT_ID:void 0),this.clientSecret=B.clientSecret??(f?process.env.SLACK_CLIENT_SECRET:void 0),this.installationKeyPrefix=B.installationKeyPrefix??"slack:installation";let Z=B.encryptionKey??process.env.SLACK_ENCRYPTION_KEY;if(Z)this.encryptionKey=Rq0(Z);this.installationProvider=B.installationProvider}async getToken(){let B=this.requestContext.getStore();if(B?.token)return B.token;if(this.defaultBotTokenProvider)return await this.defaultBotTokenProvider();throw new zF("slack","No bot token available. In multi-workspace mode, ensure the webhook is being processed.")}async withToken(B){return{...B,token:await this.getToken()}}async initialize(B){if(this.chat=B,this.defaultBotTokenProvider&&!this._botUserId)try{let A=await this._client.auth.test(await this.withToken({}));if(this._botUserId=A.user_id,this._botId=A.bot_id||null,A.user)this.userName=A.user;this.logger.info("Slack auth completed",{botUserId:this._botUserId,botId:this._botId})}catch(A){this.logger.warn("Could not fetch bot user ID",{error:A})}if(!this.defaultBotTokenProvider)this.logger.info("Slack adapter initialized in multi-workspace mode");if(this.mode==="socket")await this.startSocketMode()}installationKey(B){return`${this.installationKeyPrefix}:${B}`}async setInstallation(B,A){if(!this.chat)throw new n8("slack","Adapter not initialized. Ensure chat.initialize() has been called first.");let w=this.chat.getState(),f=this.installationKey(B),D=this.encryptionKey?{...A,botToken:Iq0(A.botToken,this.encryptionKey)}:A;await w.set(f,D),this.logger.info("Slack installation saved",{teamId:B,teamName:A.teamName})}async getInstallation(B){if(!this.chat)throw new n8("slack","Adapter not initialized. Ensure chat.initialize() has been called first.");let A=this.chat.getState(),w=this.installationKey(B),f=await A.get(w);if(!f)return null;if(this.encryptionKey&&hq0(f.botToken))return{...f,botToken:Oq0(f.botToken,this.encryptionKey)};return f}async handleOAuthCallback(B,A){if(!(this.clientId&&this.clientSecret))throw new n8("slack","clientId and clientSecret are required for OAuth. Pass them in createSlackAdapter().");let w=new URL(B.url),f=w.searchParams.get("code");if(!f)throw new n8("slack","Missing 'code' query parameter in OAuth callback request.");let D=A?.redirectUri??w.searchParams.get("redirect_uri")??void 0,$=await this._client.oauth.v2.access({client_id:this.clientId,client_secret:this.clientSecret,code:f,...D?{redirect_uri:D}:{}});if(!($.ok&&$.access_token&&$.team?.id))throw new zF("slack",`Slack OAuth failed: ${$.error||"missing access_token or team.id"}`);let Z=$.team.id,Q={botToken:$.access_token,botUserId:$.bot_user_id,teamName:$.team.name};return await this.setInstallation(Z,Q),{teamId:Z,installation:Q}}async deleteInstallation(B){if(!this.chat)throw new n8("slack","Adapter not initialized. Ensure chat.initialize() has been called first.");await this.chat.getState().delete(this.installationKey(B)),this.logger.info("Slack installation deleted",{teamId:B})}withBotToken(B,A){return this.requestContext.run({token:B},A)}async resolveTokenForTeam(B,A=!1){try{if(this.installationProvider){let f=await this.installationProvider.getInstallation(B,A);if(f)return{token:f.botToken,botUserId:f.botUserId};return this.logger.warn("No installation found from provider",{installationId:B,isEnterpriseInstall:A}),null}let w=await this.getInstallation(B);if(w)return{token:w.botToken,botUserId:w.botUserId};return this.logger.warn("No installation found for team",{installationId:B,isEnterpriseInstall:A}),null}catch(w){return this.logger.error("Failed to resolve token for team",{installationId:B,isEnterpriseInstall:A,error:w}),null}}extractInstallationFromInteractive(B){try{let w=new URLSearchParams(B).get("payload");if(!w)return null;let f=JSON.parse(w),D=Boolean(f.is_enterprise_install),$=f.enterprise?.id||f.enterprise_id||void 0,Z=f.team?.id||f.team_id||void 0,Q=D?$:Z;if(!Q)return null;return{installationId:Q,isEnterpriseInstall:D,enterpriseId:$}}catch{return null}}async lookupUser(B){let A=`slack:user:${B}`;if(this.chat){let w=await this.chat.getState().get(A);if(w)return w}try{let f=(await this._client.users.info(await this.withToken({user:B}))).user,D=f?.profile?.display_name||f?.profile?.real_name||f?.real_name||f?.name||B,$=f?.real_name||f?.profile?.real_name||D,Z={avatarUrl:f?.profile?.image_192,displayName:D,email:f?.profile?.email,isBot:f?.is_bot,realName:$};if(this.chat){await this.chat.getState().set(A,Z,x.USER_CACHE_TTL_MS);let Y=`slack:user-by-name:${D.toLowerCase()}`;if(!(await this.chat.getState().getList(Y)).includes(B))await this.chat.getState().appendToList(Y,B,{maxLength:50,ttlMs:x.REVERSE_INDEX_TTL_MS})}return this.logger.debug("Fetched user info",{userId:B,displayName:D,realName:$}),Z}catch(w){return this.logger.warn("Could not fetch user info",{userId:B,error:w}),null}}async lookupChannel(B){let A=`slack:channel:${B}`;if(this.chat){let w=await this.chat.getState().get(A);if(w)return w.name}try{let f=(await this._client.conversations.info(await this.withToken({channel:B}))).channel?.name||B;if(this.chat)await this.chat.getState().set(A,{name:f},x.CHANNEL_CACHE_TTL_MS);return this.logger.debug("Fetched channel info",{channelId:B,name:f}),f}catch(w){return this.logger.warn("Could not fetch channel info",{channelId:B,error:w}),B}}async getUser(B){try{let A=await this.lookupUser(B);if(!A)return null;return{avatarUrl:A.avatarUrl,email:A.email,fullName:A.realName,isBot:A.isBot??!1,userId:B,userName:A.displayName}}catch{return null}}async handleWebhook(B,A){let w=B.headers.get("x-slack-socket-token");if(w){if(!(this.socketForwardingSecret&&Fn8(w,this.socketForwardingSecret)))return this.logger.warn("Invalid socket forwarding token"),new Response("Invalid socket token",{status:401});this.logger.info("Slack forwarded socket event received");try{let Z=await B.text(),Q=JSON.parse(Z),Y=async()=>{};return await this.routeSocketEvent(Q.body,Q.eventType,Y,A),new Response("ok",{status:200})}catch{return new Response("Invalid JSON",{status:400})}}if(this.mode==="socket")return new Response("Webhooks are disabled in socket mode",{status:405});let f;try{f=await KDx(B,{signingSecret:this.signingSecret,webhookVerifier:this.webhookVerifier})}catch(Z){return this.logger.warn("Webhook verifier rejected request",{error:Z}),new Response("Invalid signature",{status:401})}if(this.logger.debug("Slack webhook raw body",{body:f}),(B.headers.get("content-type")||"").includes("application/x-www-form-urlencoded")){let Z=new URLSearchParams(f);if(Z.has("command")&&!Z.has("payload")){if(!this.defaultBotTokenProvider){let Q=Z.get("is_enterprise_install")==="true",Y=Q?Z.get("enterprise_id"):Z.get("team_id");if(Y){let W=await this.resolveTokenForTeam(Y,Q);if(W)return this.requestContext.run({...W,enterpriseId:Z.get("enterprise_id")??void 0,isEnterpriseInstall:Q},()=>this.handleSlashCommand(Z,A));this.logger.warn("Could not resolve token for slash command",{installationId:Y,isEnterpriseInstall:Q})}}return this.handleSlashCommand(Z,A)}if(!this.defaultBotTokenProvider){let Q=this.extractInstallationFromInteractive(f);if(Q){let Y=await this.resolveTokenForTeam(Q.installationId,Q.isEnterpriseInstall);if(Y)return this.requestContext.run({...Y,enterpriseId:Q.enterpriseId,isEnterpriseInstall:Q.isEnterpriseInstall},()=>this.handleInteractivePayload(f,A))}this.logger.warn("Could not resolve token for interactive payload")}return this.handleInteractivePayload(f,A)}let $;try{$=JSON.parse(f)}catch{return new Response("Invalid JSON",{status:400})}if($.type==="url_verification"&&$.challenge)return Response.json({challenge:$.challenge});if(!this.defaultBotTokenProvider&&$.type==="event_callback"){let Z=Boolean($.is_enterprise_install),Q=Z?$.enterprise_id:$.team_id;if(Q){let Y=await this.resolveTokenForTeam(Q,Z);if(Y)return this.requestContext.run({...Y,enterpriseId:$.enterprise_id,isEnterpriseInstall:Z},()=>{return this.processEventPayload($,A),new Response("ok",{status:200})});return this.logger.warn("Could not resolve token for installation",{installationId:Q,isEnterpriseInstall:Z}),new Response("ok",{status:200})}}return this.processEventPayload($,A),new Response("ok",{status:200})}processEventPayload(B,A){if(B.type==="event_callback"&&B.event){let w=B.event;if(B.is_ext_shared_channel){let f;if("channel"in w)f=w.channel;else if("item"in w)f=w.item.channel;if(f)this._externalChannels.add(f)}if(w.type==="message"||w.type==="app_mention"){let f=w;if(!(f.team||f.team_id)&&B.team_id)f.team_id=B.team_id;this.handleMessageEvent(f,A)}else if(w.type==="reaction_added"||w.type==="reaction_removed"){let f=this.handleReactionEvent(w,A);A?.waitUntil?.(f)}else if(w.type==="assistant_thread_started")this.handleAssistantThreadStarted(w,A);else if(w.type==="assistant_thread_context_changed")this.handleAssistantContextChanged(w,A);else if(w.type==="app_context_changed")this.handleAppContextChanged(w,A);else if(w.type==="app_home_opened"){let f=w;if(this.agentView||f.tab==="home")this.handleAppHomeOpened(f,A)}else if(w.type==="member_joined_channel")this.handleMemberJoinedChannel(w,A);else if(w.type==="user_change")this.handleUserChange(w)}}handleInteractivePayload(B,A){let f=new URLSearchParams(B).get("payload");if(!f)return new Response("Missing payload",{status:400});let D;try{D=JSON.parse(f)}catch{return new Response("Invalid payload JSON",{status:400})}return this.dispatchInteractivePayload(D,A)}dispatchInteractivePayload(B,A){switch(B.type){case"block_actions":return this.handleBlockActions(B,A),new Response("",{status:200});case"block_suggestion":return this.handleBlockSuggestion(B,A);case"view_submission":return this.handleViewSubmission(B,A);case"view_closed":return this.handleViewClosed(B,A),new Response("",{status:200});default:return new Response("",{status:200})}}async handleSlashCommand(B,A){if(!this.chat)return this.logger.warn("Chat instance not initialized, ignoring slash command"),new Response("",{status:200});let w=B.get("command")||"",f=B.get("text")||"",D=B.get("user_id")||"",$=B.get("channel_id")||"",Z=B.get("trigger_id")||void 0;this.logger.debug("Processing Slack slash command",{command:w,text:f,userId:D,channelId:$,triggerId:Z});let Q=await this.lookupUser(D),Y={command:w,text:f,user:{userId:D,userName:Q?.displayName??D,fullName:Q?.realName??D,isBot:!1,isMe:!1},adapter:this,raw:Object.fromEntries(B),triggerId:Z,channelId:$?`slack:${$}`:""};return this.chat.processSlashCommand(Y,A),new Response("",{status:200})}handleBlockActions(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring action");return}let w=B.channel?.id||B.container?.channel_id,f=B.message?.ts||B.container?.message_ts,D=B.message?.thread_ts||B.container?.thread_ts||f;if(!(B.container?.type==="view"||w)){this.logger.warn("Missing channel in block_actions",{channel:w});return}let Z=w&&(D||f)?this.encodeThreadId({channel:w,threadTs:D||f||""}):"",Q=B.container?.is_ephemeral===!0,Y=B.response_url,W=Q&&Y&&f?this.encodeEphemeralMessageId(f,Y,B.user.id):f||"";for(let H of B.actions){let F=H.selected_option?.value??H.value,K={actionId:H.action_id,value:F,user:{userId:B.user.id,userName:B.user.username||B.user.name||"unknown",fullName:B.user.name||B.user.username||"unknown",isBot:!1,isMe:!1},messageId:W,threadId:Z,adapter:this,raw:B,triggerId:B.trigger_id};this.logger.debug("Processing Slack block action",{actionId:H.action_id,value:H.value,messageId:f,threadId:Z,triggerId:B.trigger_id}),this.chat.processAction(K,A)}}async handleBlockSuggestion(B,A){if(!this.chat)return this.logger.warn("Chat instance not initialized, ignoring block suggestion"),this.optionsLoadResponse([]);let w=this.chat.processOptionsLoad({actionId:B.action_id,query:B.value??"",user:{userId:B.user.id,userName:B.user.username||B.user.name||B.user.id,fullName:B.user.name||B.user.username||B.user.id,isBot:!1,isMe:!1},adapter:this,raw:B},A),f=Symbol("options_load_timeout"),D,$=new Promise((Q)=>{D=setTimeout(()=>Q(f),wHx)}),Z=await Promise.race([w,$]);if(D)clearTimeout(D);if(Z===f)return this.logger.warn("Options load handler timed out",{actionId:B.action_id,timeoutMs:wHx}),w.catch((Q)=>this.logger.error("Options load handler error after timeout",{error:Q,actionId:B.action_id})),this.optionsLoadResponse([]);return this.optionsLoadResponse(Z??[])}optionsLoadResponse(B){if(B.length>0&&"options"in B[0]&&Array.isArray(B[0].options)){let f=B.slice(0,100).map((D)=>({label:{type:"plain_text",text:D.label.slice(0,75)},options:D.options.slice(0,100).map(tI)}));return new Response(JSON.stringify({option_groups:f}),{status:200,headers:{"Content-Type":"application/json"}})}let w=B.slice(0,100).map(tI);return new Response(JSON.stringify({options:w}),{status:200,headers:{"Content-Type":"application/json"}})}async handleViewSubmission(B,A){if(!this.chat)return this.logger.warn("Chat instance not initialized, ignoring view submission"),new Response("",{status:200});let w={};for(let Q of Object.values(B.view.state.values))for(let[Y,W]of Object.entries(Q))w[Y]=W.value??W.selected_option?.value??"";let{contextId:f,privateMetadata:D}=BHx(B.view.private_metadata||void 0),$={callbackId:B.view.callback_id,viewId:B.view.id,values:w,privateMetadata:D,user:{userId:B.user.id,userName:B.user.username||B.user.name||"unknown",fullName:B.user.name||B.user.username||"unknown",isBot:!1,isMe:!1},adapter:this,raw:B},Z=await this.chat.processModalSubmit($,f,A);if(Z){let Q=this.modalResponseToSlack(Z,f);return new Response(JSON.stringify(Q),{status:200,headers:{"Content-Type":"application/json"}})}return new Response("",{status:200})}handleViewClosed(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring view closed");return}let{contextId:w,privateMetadata:f}=BHx(B.view.private_metadata||void 0),D={callbackId:B.view.callback_id,viewId:B.view.id,privateMetadata:f,user:{userId:B.user.id,userName:B.user.username||B.user.name||"unknown",fullName:B.user.name||B.user.username||"unknown",isBot:!1,isMe:!1},adapter:this,raw:B};this.chat.processModalClose(D,w,A)}modalResponseToSlack(B,A){switch(B.action){case"close":return{};case"clear":return{response_action:"clear"};case"errors":return{response_action:"errors",errors:B.errors};case"update":{let w=this.convertModalJSX(B.modal),f=Jx0({contextId:A,privateMetadata:w.privateMetadata});return{response_action:"update",view:oI(w,f)}}case"push":{let w=this.convertModalJSX(B.modal),f=Jx0({contextId:A,privateMetadata:w.privateMetadata});return{response_action:"push",view:oI(w,f)}}default:return{}}}convertModalJSX(B){if(Vq0(B)){let A=Uq0(B);if(!A)throw new n8("slack","Invalid JSX element: must be a Modal element");return A}return B}async startSocketMode(){if(!this.appToken)throw new n8("slack","appToken is required for socket mode. Set SLACK_APP_TOKEN or provide it in config.");this.socketClient=new Mx0.SocketModeClient({appToken:this.appToken}),this.socketClient.on("slack_event",async({ack:B,body:A,type:w,retry_num:f,retry_reason:D})=>{if(f&&f>0)this.logger.info("Processing socket mode retry",{retry_num:f,retry_reason:D,type:w});await this.routeSocketEvent(A,w,B)}),await this.socketClient.start(),this.logger.info("Slack socket mode connected")}async routeSocketEvent(B,A,w,f){let D=($)=>{if(f?.waitUntil)f.waitUntil($);else $.catch((Z)=>{this.logger.error("Error in socket mode async handler",{error:Z})})};switch(A){case"events_api":{if(await w(),!B.event||typeof B.event!=="object"){this.logger.warn("Socket mode events_api missing event field",{body:B});break}let $={type:"event_callback",event:B.event,team_id:B.team_id,event_id:B.event_id,event_time:B.event_time};try{this.processEventPayload($,f)}catch(Z){this.logger.error("Error processing socket mode events_api",{error:Z})}break}case"slash_commands":{await w();let $=new URLSearchParams;for(let[Z,Q]of Object.entries(B))if(typeof Q==="string")$.set(Z,Q);D(this.handleSlashCommand($,f));break}case"interactive":{let $=B,Z=this.dispatchInteractivePayload($,f),Q=Z instanceof Promise?await Z:Z,Y=Q.headers.get("content-type")?.includes("application/json")?await Q.json():void 0;await w(Y);break}default:await w(),this.logger.debug("Unhandled socket mode event type",{type:A})}}async startSocketModeListener(B,A=180000,w,f){if(!this.appToken)return new Response("appToken is required for socket mode listener",{status:500});if(!B.waitUntil)return new Response("waitUntil not provided",{status:500});this.logger.info("Starting Slack socket mode listener",{durationMs:A,webhookUrl:f?"configured":"not configured"});let D=this.runSocketModeListener(A,w,f,B);return B.waitUntil(D),new Response(JSON.stringify({status:"listening",durationMs:A,message:`Socket mode listener started, will run for ${A/1000} seconds`}),{status:200,headers:{"Content-Type":"application/json"}})}async runSocketModeListener(B,A,w,f){let D=this.appToken,$=new Mx0.SocketModeClient({appToken:D}),Z=!1;$.on("slack_event",async({ack:Q,body:Y,type:W,retry_num:H,retry_reason:F})=>{if(Z)return;if(H&&H>0)this.logger.info("Processing socket mode retry",{retry_num:H,retry_reason:F,type:W});let K=W;if(w)await Q(),await this.forwardSocketEvent(w,{type:"socket_event",eventType:K,body:Y,timestamp:Date.now()});else await this.routeSocketEvent(Y,K,Q,f)});try{await $.start(),this.logger.info("Slack socket mode listener connected"),await new Promise((Q)=>{let Y=setTimeout(Q,B);if(A){if(A.aborted){clearTimeout(Y),Q();return}A.addEventListener("abort",()=>{this.logger.info("Slack socket mode listener received abort signal"),clearTimeout(Y),Q()},{once:!0})}}),this.logger.info("Slack socket mode listener duration elapsed, disconnecting")}catch(Q){this.logger.error("Slack socket mode listener error",{error:String(Q)})}finally{Z=!0,await $.disconnect(),this.logger.info("Slack socket mode listener stopped")}}async forwardSocketEvent(B,A){try{this.logger.debug("Forwarding socket event to webhook",{type:A.body.type||"unknown",webhookUrl:B});let w=await fetch(B,{method:"POST",headers:{"Content-Type":"application/json","x-slack-socket-token":this.socketForwardingSecret},body:JSON.stringify(A)});if(w.ok)this.logger.debug("Socket event forwarded successfully",{type:A.body.type||"unknown"});else{let f=await w.text();this.logger.error("Failed to forward socket event",{type:A.body.type||"unknown",status:w.status,error:f})}}catch(w){this.logger.error("Error forwarding socket event",{type:A.body.type||"unknown",error:String(w)})}}async disconnect(){if(this.socketClient)await this.socketClient.disconnect(),this.socketClient=null,this.logger.info("Slack socket mode disconnected")}handleMessageEvent(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring event");return}let w=new Set(["message_deleted","message_replied","channel_join","channel_leave","channel_topic","channel_purpose","channel_name","channel_archive","channel_unarchive","group_join","group_leave","group_topic","group_purpose","group_name","group_archive","group_unarchive","ekm_access_denied","tombstone"]);if(B.subtype==="message_changed"){this.handleMessageChanged(B,A);return}if(B.subtype&&w.has(B.subtype)){this.logger.debug("Ignoring message subtype",{subtype:B.subtype});return}if(!(B.channel&&B.ts)){this.logger.debug("Ignoring event without channel or ts",{channel:B.channel,ts:B.ts});return}let f=B.channel_type==="im",D=f&&!this.agentView?B.thread_ts||"":B.thread_ts||B.ts,$=this.encodeThreadId({channel:B.channel,threadTs:D}),Z=B.type==="app_mention",Q=(Y)=>async()=>{let W=await this.parseSlackMessage(B,Y);if(Z)W.isMention=!0;return W};if(this.agentView&&f&&!B.thread_ts){let Y=this.chat,W=this.encodeThreadId({channel:B.channel,threadTs:""}),H=(async()=>{let F=$;try{if(await Y.getState().isSubscribed(W))F=W}catch(K){this.logger.warn("agent_view DM subscription check failed; using per-message thread",{error:String(K),threadId:$})}Y.processMessage(this,F,Q(F),A)})();A?.waitUntil?.(H);return}this.chat.processMessage(this,$,Q($),A)}handleMessageChanged(B,A){let w=B.message;if(!(w&&B.channel))return;if(!w.attachments?.some(($)=>$.from_url||$.original_url)){this.logger.debug("Ignoring message_changed without unfurl data");return}if(this.logger.debug("Processing message_changed for link unfurls",{channel:B.channel,ts:w.ts,attachmentCount:w.attachments?.length}),!(this.chat&&w.ts&&w.attachments))return;let D={};for(let $ of w.attachments){let Z=$.from_url||$.original_url;if(Z&&($.title||$.text))D[Z]={title:$.title,description:$.text,imageUrl:$.image_url||$.thumb_url,siteName:$.service_name}}if(Object.keys(D).length>0)this.chat.getState().set(`slack:unfurls:${w.ts}`,D,3600000).catch(($)=>{this.logger.error("Failed to cache unfurl metadata",{error:$})})}async handleReactionEvent(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring reaction");return}if(B.item.type!=="message"){this.logger.debug("Ignoring reaction to non-message item",{itemType:B.item.type});return}let w=B.item.ts;try{let V=(await this._client.conversations.replies(await this.withToken({channel:B.item.channel,ts:B.item.ts,limit:1}))).messages?.[0];if(V?.thread_ts)w=V.thread_ts}catch(q){this.logger.warn("Failed to resolve parent thread for reaction, using message ts",{error:String(q),channel:B.item.channel,ts:B.item.ts})}let f=this.encodeThreadId({channel:B.item.channel,threadTs:w}),D=B.item.ts,$=B.reaction,Z=Df.fromSlack($),Q=this.requestContext.getStore(),Y=Q?.botUserId&&B.user===Q.botUserId||this._botUserId!==null&&B.user===this._botUserId||this._botId!==null&&B.user===this._botId,W=await this.lookupUser(B.user),H=W?.displayName??B.user,F=W?.realName??H,K={emoji:Z,rawEmoji:$,added:B.type==="reaction_added",user:{userId:B.user,userName:H,fullName:F,isBot:W?.isBot??!1,isMe:Y},messageId:D,threadId:f,raw:B};this.chat.processReaction({...K,adapter:this},A)}handleAssistantThreadStarted(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring assistant_thread_started");return}if(!B.assistant_thread){this.logger.warn("Malformed assistant_thread_started: missing assistant_thread");return}let{channel_id:w,thread_ts:f,user_id:D,context:$}=B.assistant_thread,Z=this.encodeThreadId({channel:w,threadTs:f}),Q=this.applyConfiguredSuggestedPrompts({channelId:w,enterpriseId:$.enterprise_id,teamId:$.team_id,threadTs:f,userId:D});A?.waitUntil?.(Q),this.chat.processAssistantThreadStarted({threadId:Z,userId:D,channelId:w,threadTs:f,context:{channelId:$.channel_id,teamId:$.team_id,enterpriseId:$.enterprise_id,threadEntryPoint:$.thread_entry_point,forceSearch:$.force_search},adapter:this},A)}handleAssistantContextChanged(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring assistant_thread_context_changed");return}if(!B.assistant_thread){this.logger.warn("Malformed assistant_thread_context_changed: missing assistant_thread");return}let{channel_id:w,thread_ts:f,user_id:D,context:$}=B.assistant_thread,Z=this.encodeThreadId({channel:w,threadTs:f});this.chat.processAssistantContextChanged({threadId:Z,userId:D,channelId:w,threadTs:f,context:{channelId:$.channel_id,teamId:$.team_id,enterpriseId:$.enterprise_id,threadEntryPoint:$.thread_entry_point,forceSearch:$.force_search},adapter:this},A)}handleAppHomeOpened(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring app_home_opened");return}if(this.agentView&&B.tab==="messages"){let w=this.applyConfiguredSuggestedPrompts({channelId:B.channel,userId:B.user,...B.context?{entities:jx0(B.context)}:{}});A?.waitUntil?.(w)}this.chat.processAppHomeOpened({userId:B.user,channelId:B.channel,tab:B.tab,adapter:this,...B.context?{entities:jx0(B.context)}:{}},A)}handleAppContextChanged(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring app_context_changed");return}this.chat.processAppContextChanged({channelId:B.channel,userId:B.user,entities:jx0(B.context),raw:B,adapter:this},A)}handleMemberJoinedChannel(B,A){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring member_joined_channel");return}this.chat.processMemberJoinedChannel({userId:B.user,channelId:this.encodeThreadId({channel:B.channel,threadTs:""}),inviterId:B.inviter,adapter:this},A)}async handleUserChange(B){if(!this.chat)return;try{await this.chat.getState().delete(`slack:user:${B.user.id}`)}catch(A){this.logger.warn("Failed to invalidate user cache",{userId:B.user.id,error:A})}}async publishHomeView(B,A){await this._client.views.publish(await this.withToken({user_id:B,view:A}))}async setSuggestedPrompts(B,A,w,f){await this._client.assistant.threads.setSuggestedPrompts(await this.withToken({channel_id:B,prompts:w,...A?{thread_ts:A}:{},...f?{title:f}:{}}))}async applyConfiguredSuggestedPrompts(B){if(!this.suggestedPrompts)return;try{let A=typeof this.suggestedPrompts==="function"?await this.suggestedPrompts(B):this.suggestedPrompts;if(!A||A.prompts.length===0)return;let w=A.prompts;if(w.length>kx0)this.logger.warn(`Slack shows at most ${kx0} suggested prompts; dropping the rest`,{configured:w.length}),w=w.slice(0,kx0);await this.setSuggestedPrompts(B.channelId,B.threadTs,w,A.title)}catch(A){this.logger.warn("Failed to apply configured suggested prompts",{channelId:B.channelId,error:A})}}async setAssistantStatus(B,A,w,f){let D=f??this.loadingMessages;await this._client.assistant.threads.setStatus(await this.withToken({channel_id:B,thread_ts:A,status:w,...D&&{loading_messages:D}}))}async setAssistantTitle(B,A,w){await this._client.assistant.threads.setTitle(await this.withToken({channel_id:B,thread_ts:A,title:w}))}async resolveInlineMentions(B,A){let w=new Set,f=new Set;for(let K of B.split("<")){let q=K.indexOf(">");if(q===-1)continue;let V=K.slice(0,q);if(V.startsWith("@")){let b=V.slice(1),G=b.indexOf("|"),E=G>=0?b.slice(0,G):b;if(Lx0.test(E))w.add(E)}else if(V.startsWith("#")){let b=V.slice(1);if(b.indexOf("|")===-1&&Lx0.test(b))f.add(b)}}if(w.size===0&&f.size===0)return B;let D=this.botUserId;if(A&&D)w.delete(D);if(w.size===0&&f.size===0)return B;let[$,Z]=await Promise.all([Promise.all([...w].map(async(K)=>{let q=await this.lookupUser(K);return[K,q?.displayName??K]})),Promise.all([...f].map(async(K)=>{let q=await this.lookupChannel(K);return[K,q]}))]),Q=new Map($),Y=new Map(Z),W="",H=B,F=fHx(H);while(F!==-1){W+=H.slice(0,F),H=H.slice(F);let K=H.indexOf(">");if(K===-1)break;let q=H[1],V=H.slice(2,K),b=V.indexOf("|"),G=b>=0?V.slice(0,b):V;if(q==="@"&&Lx0.test(G)){let E=Q.get(G);W+=E?`<@${G}|${E}>`:`<@${G}>`}else if(q==="#"&&b===-1&&Y.has(G)){let E=Y.get(G);W+=`<#${G}|${E}>`}else W+=H.slice(0,K+1);H=H.slice(K+1),F=fHx(H)}return W+H}extractLinks(B){let A=new Set;if(B.blocks){for(let f of B.blocks)if(f.type==="rich_text"&&f.elements){for(let D of f.elements)if(D.elements){for(let $ of D.elements)if($.type==="link"&&$.url)A.add($.url)}}}if(A.size===0&&B.text){let f=/<(https?:\/\/[^>]+)>/g;for(let D of B.text.matchAll(f)){let $=D[1],Z=$.indexOf("|");A.add(Z>=0?$.slice(0,Z):$)}}let w=new Map;if(B.attachments)for(let f of B.attachments){let D=f.from_url||f.original_url;if(D&&(f.title||f.text))w.set(D,{title:f.title,description:f.text,imageUrl:f.image_url||f.thumb_url,siteName:f.service_name}),A.add(D)}return[...A].map((f)=>{let D=this.createLinkPreview(f),$=w.get(f)||w.get(f.replace(DHx,""))||w.get(`${f}/`);if($)return{...D,...$};return D})}createLinkPreview(B){let A=bn8.exec(B);if(!A)return{url:B};let w=A[1],f=A[2],D=`${f.slice(0,f.length-6)}.${f.slice(f.length-6)}`,$=this.encodeThreadId({channel:w,threadTs:D});return{url:B,fetchMessage:async()=>{let Y=((await this._client.conversations.history(await this.withToken({channel:w,latest:D,inclusive:!0,limit:1}))).messages||[]).find((W)=>W.ts===D);if(!Y)throw Error(`Message not found: ${B}`);return this.parseSlackMessage(Y,$)}}}async parseSlackMessage(B,A,w){let f=this.isMessageFromSelf(B),D=w?.skipSelfMention??!0,$=B.text||"",Z=B.username||"unknown",Q=B.username||"unknown";if(B.user&&!B.username){let W=await this.lookupUser(B.user);Z=W?.displayName??B.user,Q=W?.realName??Z}if(B.user&&this.chat)try{let W=`slack:thread-participants:${A}`;if(!(await this.chat.getState().getList(W)).includes(B.user))await this.chat.getState().appendToList(W,B.user,{maxLength:100,ttlMs:x.REVERSE_INDEX_TTL_MS})}catch(W){this.logger.warn("Failed to track thread participant",{threadId:A,userId:B.user,error:W})}let Y=await this.resolveInlineMentions($,D);return new Y6({id:B.ts||"",threadId:A,text:this.formatConverter.extractPlainText(Y),formatted:this.formatConverter.toAst(Y),raw:B,author:{userId:B.user||B.bot_id||"unknown",userName:Z,fullName:Q,isBot:!!B.bot_id,isMe:f},metadata:{dateSent:new Date(Number.parseFloat(B.ts||"0")*1000),edited:!!B.edited,editedAt:B.edited?new Date(Number.parseFloat(B.edited.ts)*1000):void 0},attachments:(B.files||[]).map((W)=>this.createAttachment(W,B.team_id??B.team)),links:await this.enrichLinks(this.extractLinks(B),B.ts)})}async enrichLinks(B,A){if(!(this.chat&&A)||B.length===0)return B;if(B.every((Z)=>Z.title||Z.fetchMessage))return B;let f=Date.now()+qn8,D=this.chat.getState(),$=null;while(!0){try{$=await D.get(`slack:unfurls:${A}`)}catch{return B}if($||Date.now()>=f)break;await new Promise((Z)=>setTimeout(Z,zn8))}if(!$)return B;return B.map((Z)=>{if(Z.title)return Z;let Q=$[Z.url]||$[Z.url.replace(DHx,"")]||$[`${Z.url}/`];if(Q)return{...Z,...Q};return Z})}createAttachment(B,A){let w=B.url_private,f=this.requestContext.getStore(),D=f?.token,$=f?.enterpriseId,Z=f?.isEnterpriseInstall,Q="file";if(B.mimetype?.startsWith("image/"))Q="image";else if(B.mimetype?.startsWith("video/"))Q="video";else if(B.mimetype?.startsWith("audio/"))Q="audio";let Y={};if(w)Y.url=w;if(A)Y.teamId=A;if($)Y.enterpriseId=$;if(Z)Y.isEnterpriseInstall="true";return{type:Q,url:w,name:B.name,mimeType:B.mimetype,size:B.size,width:B.original_w,height:B.original_h,fetchMetadata:Object.keys(Y).length>0?Y:void 0,fetchData:w?async()=>this.fetchSlackFile(w,D??await this.getToken()):void 0}}async fetchSlackFile(B,A){let w=await fetch(B,{headers:{Authorization:`Bearer ${A}`}});if(!w.ok)throw new X2("slack",`Failed to fetch file: ${w.status} ${w.statusText}`);if((w.headers.get("content-type")??"").includes("text/html"))throw new X2("slack",`Failed to download file from Slack: received HTML login page instead of file data. Ensure your Slack app has the "files:read" OAuth scope. URL: ${B}`);let D=await w.arrayBuffer();return Buffer.from(D)}rehydrateAttachment(B){let A=B.fetchMetadata?.url??B.url,w=B.fetchMetadata?.teamId,f=B.fetchMetadata?.enterpriseId,D=B.fetchMetadata?.isEnterpriseInstall==="true";if(!A)return B;return{...B,fetchData:async()=>{let $,Z=D?f:w;if(Z){let Q=await this.resolveTokenForTeam(Z,D);if(!Q)throw new zF("slack",`Installation not found for ${D?"enterprise":"team"} ${Z}`);$=Q.token}else $=await this.getToken();return this.fetchSlackFile(A,$)}}}async resolveOutgoingMentions(B,A){if(!this.chat)return B;let w=this.chat.getState(),f=new Map;if(uQ(B,(Z,Q)=>{if(AHx.test(Q))return Z;if(!f.has(Q.toLowerCase()))f.set(Q.toLowerCase(),[]);return Z}),f.size===0)return B;for(let Z of f.keys()){let Q=await w.getList(`slack:user-by-name:${Z}`),Y=[...new Set(Q)];f.set(Z,Y)}let D=null;if([...f.values()].some((Z)=>Z.length>1)){let Z=await w.getList(`slack:thread-participants:${A}`);D=new Set(Z)}return uQ(B,(Z,Q)=>{if(AHx.test(Q))return Z;let Y=f.get(Q.toLowerCase());if(!Y||Y.length===0)return Z;if(Y.length===1)return`<@${Y[0]}>`;if(D){let W=Y.filter((H)=>D.has(H));if(W.length===1)return`<@${W[0]}>`}return Z})}async resolveMessageMentions(B,A){if(!this.chat)return B;if(typeof B==="string")return this.resolveOutgoingMentions(B,A);if(typeof B==="object"&&B!==null){if("raw"in B&&typeof B.raw==="string")return{...B,raw:await this.resolveOutgoingMentions(B.raw,A)};if("markdown"in B&&typeof B.markdown==="string")return{...B,markdown:await this.resolveOutgoingMentions(B.markdown,A)}}return B}async postMessage(B,A){let w=await this.resolveMessageMentions(A,B),{channel:f,threadTs:D}=this.decodeThreadId(B),$=D||void 0;try{let Z,Q=qF(w);if(Q.length>0){Z=await this.uploadFiles(Q,f,$);let F=typeof w==="string"||typeof w==="object"&&w!==null&&(("raw"in w)&&w.raw||("markdown"in w)&&w.markdown||("ast"in w)&&w.ast),K=$f(w);if(!(F||K))return{id:`file-${Date.now()}`,threadId:B,raw:{files:Q,uploadedFileIds:Z}}}let Y=$f(w);if(Y){let F=TE(Y),K=pE(Y);this.logger.debug("Slack API: chat.postMessage (blocks)",{channel:f,threadTs:$,blockCount:F.length});let q;try{q=await this._client.chat.postMessage(await this.withToken({channel:f,thread_ts:$,text:K,blocks:F,unfurl_links:!1,unfurl_media:!1}))}catch(V){throw Kn8(V,F,this.logger)}return this.logger.debug("Slack API: chat.postMessage response",{messageId:q.ts,ok:q.ok}),{id:q.ts,threadId:B,raw:Z===void 0?q:{...q,uploadedFileIds:Z}}}let W=this.formatConverter.toSlackPayload(w);this.logger.debug("Slack API: chat.postMessage",{channel:f,threadTs:$,payloadKey:"markdown_text"in W?"markdown_text":"text"});let H=await this._client.chat.postMessage(await this.withToken({channel:f,thread_ts:$,...W,unfurl_links:!1,unfurl_media:!1}));return this.logger.debug("Slack API: chat.postMessage response",{messageId:H.ts,ok:H.ok}),{id:H.ts,threadId:B,raw:Z===void 0?H:{...H,uploadedFileIds:Z}}}catch(Z){this.handleSlackError(Z)}}async postEphemeral(B,A,w){let f=await this.resolveMessageMentions(w,B),{channel:D,threadTs:$}=this.decodeThreadId(B),Z=$||void 0;try{let Q=$f(f);if(Q){let H=TE(Q),F=pE(Q);this.logger.debug("Slack API: chat.postEphemeral (blocks)",{channel:D,threadTs:Z,userId:A,blockCount:H.length});let K=await this._client.chat.postEphemeral(await this.withToken({channel:D,thread_ts:Z,user:A,text:F,blocks:H}));return this.logger.debug("Slack API: chat.postEphemeral response",{messageTs:K.message_ts,ok:K.ok}),{id:K.message_ts||"",threadId:B,usedFallback:!1,raw:K}}let Y=this.formatConverter.toSlackPayload(f);this.logger.debug("Slack API: chat.postEphemeral",{channel:D,threadTs:Z,userId:A,payloadKey:"markdown_text"in Y?"markdown_text":"text"});let W=await this._client.chat.postEphemeral(await this.withToken({channel:D,thread_ts:Z,user:A,...Y}));return this.logger.debug("Slack API: chat.postEphemeral response",{messageTs:W.message_ts,ok:W.ok}),{id:W.message_ts||"",threadId:B,usedFallback:!1,raw:W}}catch(Q){this.handleSlackError(Q)}}async scheduleMessage(B,A,w){let f=await this.resolveMessageMentions(A,B),{channel:D,threadTs:$}=this.decodeThreadId(B),Z=$||void 0,Q=Math.floor(w.postAt.getTime()/1000);if(Q<=Math.floor(Date.now()/1000))throw new n8("slack","postAt must be in the future");if(qF(f).length>0)throw new n8("slack","File uploads are not supported in scheduled messages");let W=this.requestContext.getStore()?.token,H=W?()=>Promise.resolve(W):()=>this.getToken(),F=W??await this.getToken();try{let K=$f(f);if(K){let E=TE(K),_=pE(K);this.logger.debug("Slack API: chat.scheduleMessage (blocks)",{channel:D,threadTs:Z,postAt:Q,blockCount:E.length});let L=await this._client.chat.scheduleMessage({token:F,channel:D,thread_ts:Z,post_at:Q,text:_,blocks:E,unfurl_links:!1,unfurl_media:!1}),N=L.scheduled_message_id,y=this;return{scheduledMessageId:N,channelId:D,postAt:w.postAt,raw:L,async cancel(){await y._client.chat.deleteScheduledMessage({token:await H(),channel:D,scheduled_message_id:N})}}}let q=this.formatConverter.toSlackPayload(f);this.logger.debug("Slack API: chat.scheduleMessage",{channel:D,threadTs:Z,postAt:Q,payloadKey:"markdown_text"in q?"markdown_text":"text"});let V=await this._client.chat.scheduleMessage({token:F,channel:D,thread_ts:Z,post_at:Q,...q,unfurl_links:!1,unfurl_media:!1}),b=V.scheduled_message_id,G=this;return{scheduledMessageId:b,channelId:D,postAt:w.postAt,raw:V,async cancel(){await G._client.chat.deleteScheduledMessage({token:await H(),channel:D,scheduled_message_id:b})}}}catch(K){this.handleSlackError(K)}}async openModal(B,A,w){let f=Jx0({contextId:w,privateMetadata:A.privateMetadata}),D=oI(A,f);this.logger.debug("Slack API: views.open",{triggerId:B,callbackId:A.callbackId});try{let $=await this._client.views.open(await this.withToken({trigger_id:B,view:D}));return this.logger.debug("Slack API: views.open response",{viewId:$.view?.id,ok:$.ok}),{viewId:$.view?.id}}catch($){this.handleSlackError($)}}async updateModal(B,A){let w=oI(A);this.logger.debug("Slack API: views.update",{viewId:B,callbackId:A.callbackId});try{let f=await this._client.views.update(await this.withToken({view_id:B,view:w}));return this.logger.debug("Slack API: views.update response",{viewId:f.view?.id,ok:f.ok}),{viewId:f.view?.id}}catch(f){this.handleSlackError(f)}}async uploadFiles(B,A,w){let D=(await Promise.all(B.map(async(Y)=>{try{let W=await jU(Y.data,{platform:"slack"});if(!W)return null;return{file:W,filename:Y.filename}}catch(W){return this.logger.error("Failed to convert file to buffer",{filename:Y.filename,error:W}),null}}))).filter((Y)=>Y!==null);if(D.length===0)return[];this.logger.debug("Slack API: files.uploadV2 (batch)",{fileCount:D.length,filenames:D.map((Y)=>Y.filename)});let $={channel_id:A,file_uploads:D};if(w)$.thread_ts=w;$.token=await this.getToken();let Z=await this._client.files.uploadV2($);this.logger.debug("Slack API: files.uploadV2 response",{ok:Z.ok});let Q=[];if(Z.files?.[0]?.files){for(let Y of Z.files[0].files)if(Y.id)Q.push(Y.id)}return Q}async editMessage(B,A,w){let f=await this.resolveMessageMentions(w,B),D=this.decodeEphemeralMessageId(A);if(D){let{threadTs:Z}=this.decodeThreadId(B),Q=await this.sendToResponseUrl(D.responseUrl,"replace",{message:f,threadTs:Z});return{id:D.messageTs,threadId:B,raw:{ephemeral:!0,...Q}}}let{channel:$}=this.decodeThreadId(B);try{let Z=$f(f);if(Z){let W=TE(Z),H=pE(Z);this.logger.debug("Slack API: chat.update (blocks)",{channel:$,messageId:A,blockCount:W.length});let F=await this._client.chat.update(await this.withToken({channel:$,ts:A,text:H,blocks:W}));return this.logger.debug("Slack API: chat.update response",{messageId:F.ts,ok:F.ok}),{id:F.ts,threadId:B,raw:F}}let Q=this.formatConverter.toSlackPayload(f);this.logger.debug("Slack API: chat.update",{channel:$,messageId:A,payloadKey:"markdown_text"in Q?"markdown_text":"text"});let Y=await this._client.chat.update(await this.withToken({channel:$,ts:A,...Q}));return this.logger.debug("Slack API: chat.update response",{messageId:Y.ts,ok:Y.ok}),{id:Y.ts,threadId:B,raw:Y}}catch(Z){this.handleSlackError(Z)}}async postObject(B,A,w){if(A!=="plan")return this.postMessage(B,`[${A}]`);let f=w,{channel:D,threadTs:$}=this.decodeThreadId(B),Z=this.renderPlanFallbackText(f),Q=this.planToBlockKit(f);try{this.logger.debug("Slack API: chat.postMessage (plan)",{channel:D,threadTs:$,blockCount:Q.length});let Y=await this._client.chat.postMessage(await this.withToken({channel:D,thread_ts:$,text:Z,blocks:Q,unfurl_links:!1,unfurl_media:!1}));return{id:Y.ts,threadId:B,raw:Y}}catch(Y){this.handleSlackError(Y)}}async editObject(B,A,w,f){if(w!=="plan")return this.editMessage(B,A,`[${w}]`);let D=f,{channel:$}=this.decodeThreadId(B),Z=this.renderPlanFallbackText(D),Q=this.planToBlockKit(D);try{this.logger.debug("Slack API: chat.update (plan)",{channel:$,messageId:A,blockCount:Q.length});let Y=await this._client.chat.update(await this.withToken({channel:$,ts:A,text:Z,blocks:Q}));return{id:Y.ts,threadId:B,raw:Y}}catch(Y){this.handleSlackError(Y)}}renderPlanFallbackText(B){let A=[];A.push(B.title||"Plan");for(let w of B.tasks)A.push(`- (${w.status}) ${w.title}`);return A.join(`
5308
5308
  `)}planToBlockKit(B){let A=B.tasks.map((w)=>{let f=this.planContentToRichText(w.details),D=this.planContentToRichText(w.output);return{type:"task_card",task_id:w.id,title:w.title,status:w.status,...f?{details:f}:null,...D?{output:D}:null}});return[{type:"plan",title:B.title||"Plan",tasks:A}]}planContentToPlainText(B){if(!B)return"";if(Array.isArray(B))return B.join(`
5309
5309
  `);if(typeof B==="string")return B;if("markdown"in B)return Bf(zB(B.markdown));if("ast"in B)return Bf(B.ast);return""}planContentToRichText(B){if(!B)return;if(Array.isArray(B))return{type:"rich_text",elements:[{type:"rich_text_list",style:"bullet",elements:B.map((w)=>({type:"rich_text_section",elements:[{type:"text",text:String(w)}]}))}]};let A=this.planContentToPlainText(B);if(!A)return;return{type:"rich_text",elements:[{type:"rich_text_section",elements:[{type:"text",text:A}]}]}}async deleteMessage(B,A){let w=this.decodeEphemeralMessageId(A);if(w){await this.sendToResponseUrl(w.responseUrl,"delete");return}let{channel:f}=this.decodeThreadId(B);try{this.logger.debug("Slack API: chat.delete",{channel:f,messageId:A}),await this._client.chat.delete(await this.withToken({channel:f,ts:A})),this.logger.debug("Slack API: chat.delete response",{ok:!0})}catch(D){this.handleSlackError(D)}}async addReaction(B,A,w){let{channel:f}=this.decodeThreadId(B),$=Df.toSlack(w).replace(/:/g,"");try{this.logger.debug("Slack API: reactions.add",{channel:f,messageId:A,emoji:$}),await this._client.reactions.add(await this.withToken({channel:f,timestamp:A,name:$})),this.logger.debug("Slack API: reactions.add response",{ok:!0})}catch(Z){this.handleSlackError(Z)}}async removeReaction(B,A,w){let{channel:f}=this.decodeThreadId(B),$=Df.toSlack(w).replace(/:/g,"");try{this.logger.debug("Slack API: reactions.remove",{channel:f,messageId:A,emoji:$}),await this._client.reactions.remove(await this.withToken({channel:f,timestamp:A,name:$})),this.logger.debug("Slack API: reactions.remove response",{ok:!0})}catch(Z){this.handleSlackError(Z)}}async startTyping(B,A){let{channel:w,threadTs:f}=this.decodeThreadId(B);if(!f){this.logger.debug("Slack: startTyping skipped - no thread context");return}this.logger.debug("Slack API: assistant.threads.setStatus",{channel:w,threadTs:f,status:A});try{let D=A?[A]:this.loadingMessages??["Typing..."];await this._client.assistant.threads.setStatus(await this.withToken({channel_id:w,thread_ts:f,status:A??this.loadingMessages?.[0]??"Typing...",loading_messages:D}))}catch(D){this.logger.warn("Slack API: assistant.threads.setStatus failed",{channel:w,threadTs:f,error:D})}}async stream(B,A,w){let{channel:f,threadTs:D}=this.decodeThreadId(B),$=D||void 0;if(!$)return this.logger.debug("Slack: using fallback stream - no thread context"),null;if(!(f.startsWith("D")||w?.recipientUserId&&w?.recipientTeamId))return this.logger.debug("Slack: using fallback stream - no recipient context"),null;if(!this.nativeStreaming||this.nativeStreamingBroken)return this.logger.debug("Slack: using fallback stream - native streaming disabled",{configured:this.nativeStreaming,broken:this.nativeStreamingBroken}),null;this.logger.debug("Slack: starting stream",{channel:f,threadTs:$});let Z=await this.getToken(),Q=this._client.chatStream({channel:f,thread_ts:$,...w?.recipientUserId&&{recipient_user_id:w.recipientUserId},...w?.recipientTeamId&&{recipient_team_id:w.recipientTeamId},...w?.taskDisplayMode&&{task_display_mode:w.taskDisplayMode}}),Y="",W=new al({wrapTablesForAppend:!1}),H={message:null,mode:"native",nativeRendered:!1},F=w?.updateIntervalMs??1000,K="",q=0,V=async(c)=>{let n=W.getCommittableText();if(n.length===0||n===K)return;let R=Date.now();if(!(c||R-q>=F))return;if(H.message)await this.editMessage(B,H.message.id,n);else H.message=await this.postMessage(B,n);K=n,q=R},b=(c)=>{H.mode="fallback";let n=Gn8(c);if(n&&Un8.has(n))this.nativeStreamingBroken=!0;this.logger.warn("Slack native streaming unavailable, falling back to post-and-edit",{channel:f,error:c})},G=async(c=!1)=>{if(H.mode==="fallback"){await V(c);return}let n=W.getCommittableText(),R=n.slice(Y.length);if(R.length===0)return;try{if(await Q.append({markdown_text:R,token:Z}))H.nativeRendered=!0;Y=n}catch(M){if(H.nativeRendered)throw M;b(M),await V(c)}},E=!0,_=async(c)=>{if(await G(),H.mode==="fallback"||!E){this.logger.debug("Slack: structured chunk skipped",{chunkType:c.type,mode:H.mode});return}try{await Q.append({chunks:[c],token:Z}),H.nativeRendered=!0}catch(n){E=!1,this.logger.warn("Structured streaming chunk failed, falling back to text-only streaming. Ensure your Slack app manifest includes the agent/assistant feature and the assistant:write scope",{chunkType:c.type,error:n})}};for await(let c of A)if(typeof c==="string")W.push(c),await G();else if(c.type==="markdown_text")W.push(c.text),await G();else await _(c);if(W.finish(),await G(!0),H.mode==="fallback"){if(w?.stopBlocks||this.feedbackButtons)this.logger.warn("Slack: stream-end blocks (stopBlocks/feedbackButtons) skipped - post-and-edit fallback cannot attach stream blocks",{channel:f});return this.logger.debug("Slack: fallback stream complete",{messageId:H.message?.id}),H.message}let L=[...w?.stopBlocks??[],...this.feedbackButtons?[Vn8(this.feedbackButtons)]:[]],N;try{N=await Q.stop({token:Z,...L.length>0?{blocks:L}:{}})}catch(c){if(H.nativeRendered)throw c;return b(c),await V(!0),this.logger.debug("Slack: fallback stream complete",{messageId:H.message?.id}),H.message}let y=N.message?.ts??N.ts;return this.logger.debug("Slack: stream complete",{messageId:y}),{id:y,threadId:B,raw:N}}async openDM(B){try{this.logger.debug("Slack API: conversations.open",{userId:B});let A=await this._client.conversations.open(await this.withToken({users:B}));if(!A.channel?.id)throw new X2("slack","Failed to open DM - no channel returned");let w=A.channel.id;return this.logger.debug("Slack API: conversations.open response",{channelId:w,ok:A.ok}),this.encodeThreadId({channel:w,threadTs:""})}catch(A){this.handleSlackError(A)}}async fetchMessages(B,A={}){let{channel:w,threadTs:f}=this.decodeThreadId(B),D=A.direction??"backward",$=A.limit||100;try{if(D==="forward")return await this.fetchMessagesForward(w,f,B,$,A.cursor);return await this.fetchMessagesBackward(w,f,B,$,A.cursor)}catch(Z){this.handleSlackError(Z)}}async fetchMessagesForward(B,A,w,f,D){this.logger.debug("Slack API: conversations.replies (forward)",{channel:B,threadTs:A,limit:f,cursor:D});let $=await this._client.conversations.replies(await this.withToken({channel:B,ts:A,limit:f,cursor:D})),Z=$.messages||[],Q=$.response_metadata?.next_cursor;return this.logger.debug("Slack API: conversations.replies response",{messageCount:Z.length,ok:$.ok,hasNextCursor:!!Q}),{messages:await Promise.all(Z.map((W)=>this.parseSlackMessage(W,w))),nextCursor:Q||void 0}}async fetchMessagesBackward(B,A,w,f,D){let $=D||void 0;this.logger.debug("Slack API: conversations.replies (backward)",{channel:B,threadTs:A,limit:f,latest:$});let Z=Math.min(1000,Math.max(f*2,200)),Q=await this._client.conversations.replies(await this.withToken({channel:B,ts:A,limit:Z,latest:$,inclusive:!1})),Y=Q.messages||[];this.logger.debug("Slack API: conversations.replies response (backward)",{messageCount:Y.length,ok:Q.ok,hasMore:Q.has_more});let W=Math.max(0,Y.length-f),H=Y.slice(W),F=await Promise.all(H.map((q)=>this.parseSlackMessage(q,w))),K;if(W>0||Q.has_more){let q=H[0];if(q?.ts)K=q.ts}return{messages:F,nextCursor:K}}async fetchThread(B){let{channel:A,threadTs:w}=this.decodeThreadId(B);try{this.logger.debug("Slack API: conversations.info",{channel:A});let f=await this._client.conversations.info(await this.withToken({channel:A})),D=f.channel;if(D?.is_ext_shared)this._externalChannels.add(A);this.logger.debug("Slack API: conversations.info response",{channelName:D?.name,ok:f.ok});let $="unknown";if(D?.is_ext_shared)$="external";else if(D?.is_private||A.startsWith("D"))$="private";else if(A.startsWith("C"))$="workspace";return{id:B,channelId:A,channelName:D?.name,channelVisibility:$,metadata:{threadTs:w,channel:f.channel}}}catch(f){this.handleSlackError(f)}}async fetchMessage(B,A){let{channel:w,threadTs:f}=this.decodeThreadId(B);try{let Z=((await this._client.conversations.replies(await this.withToken({channel:w,ts:f,oldest:A,inclusive:!0,limit:1}))).messages||[]).find((Q)=>Q.ts===A);if(!Z)return null;return this.parseSlackMessage(Z,B)}catch(D){this.handleSlackError(D)}}encodeThreadId(B){return`slack:${B.channel}:${B.threadTs}`}isDM(B){let{channel:A}=this.decodeThreadId(B);return A.startsWith("D")}getChannelVisibility(B){let{channel:A}=this.decodeThreadId(B);if(this._externalChannels.has(A))return"external";if(A.startsWith("G")||A.startsWith("D"))return"private";if(A.startsWith("C"))return"workspace";return"unknown"}decodeThreadId(B){let A=B.split(":");if(A.length<2||A.length>3||A[0]!=="slack")throw new n8("slack",`Invalid Slack thread ID: ${B}`);return{channel:A[1],threadTs:A.length===3?A[2]:""}}parseMessage(B){let A=B,w=A.thread_ts||A.ts||"",f=this.encodeThreadId({channel:A.channel||"",threadTs:w});return this.parseSlackMessageSync(A,f)}parseSlackMessageSync(B,A){let w=this.isMessageFromSelf(B),f=B.text||"",D=B.username||B.user||"unknown",$=B.username||B.user||"unknown";return new Y6({id:B.ts||"",threadId:A,text:this.formatConverter.extractPlainText(f),formatted:this.formatConverter.toAst(f),raw:B,author:{userId:B.user||B.bot_id||"unknown",userName:D,fullName:$,isBot:!!B.bot_id,isMe:w},metadata:{dateSent:new Date(Number.parseFloat(B.ts||"0")*1000),edited:!!B.edited,editedAt:B.edited?new Date(Number.parseFloat(B.edited.ts)*1000):void 0},attachments:(B.files||[]).map((Z)=>this.createAttachment(Z,B.team_id??B.team)),links:this.extractLinks(B)})}channelIdFromThreadId(B){let{channel:A}=this.decodeThreadId(B);return`slack:${A}`}async fetchChannelMessages(B,A={}){let w=B.split(":")[1];if(!w)throw new n8("slack",`Invalid Slack channel ID: ${B}`);let f=A.direction??"backward",D=A.limit||100;try{if(f==="forward")return await this.fetchChannelMessagesForward(w,D,A.cursor);return await this.fetchChannelMessagesBackward(w,D,A.cursor)}catch($){this.handleSlackError($)}}async fetchChannelMessagesForward(B,A,w){this.logger.debug("Slack API: conversations.history (forward)",{channel:B,limit:A,cursor:w});let f=await this._client.conversations.history(await this.withToken({channel:B,limit:A,oldest:w,inclusive:w?!1:void 0})),D=(f.messages||[]).reverse(),$=await Promise.all(D.map((Q)=>{let Y=Q.thread_ts||Q.ts||"",W=`slack:${B}:${Y}`;return this.parseSlackMessage(Q,W,{skipSelfMention:!1})})),Z;if(f.has_more&&D.length>0){let Q=D.at(-1);if(Q?.ts)Z=Q.ts}return{messages:$,nextCursor:Z}}async fetchChannelMessagesBackward(B,A,w){this.logger.debug("Slack API: conversations.history (backward)",{channel:B,limit:A,cursor:w});let f=await this._client.conversations.history(await this.withToken({channel:B,limit:A,latest:w,inclusive:w?!1:void 0})),$=[...f.messages||[]].reverse(),Z=await Promise.all($.map((Y)=>{let W=Y.thread_ts||Y.ts||"",H=`slack:${B}:${W}`;return this.parseSlackMessage(Y,H,{skipSelfMention:!1})})),Q;if(f.has_more&&$.length>0){let Y=$[0];if(Y?.ts)Q=Y.ts}return{messages:Z,nextCursor:Q}}async listThreads(B,A={}){let w=B.split(":")[1];if(!w)throw new n8("slack",`Invalid Slack channel ID: ${B}`);let f=A.limit||50;try{this.logger.debug("Slack API: conversations.history (listThreads)",{channel:w,limit:f,cursor:A.cursor});let D=await this._client.conversations.history(await this.withToken({channel:w,limit:Math.min(f*3,200),cursor:A.cursor})),Q=(D.messages||[]).filter((H)=>(H.reply_count??0)>0).slice(0,f),Y=await Promise.all(Q.map(async(H)=>{let F=H.ts||"",K=`slack:${w}:${F}`,q=await this.parseSlackMessage(H,K,{skipSelfMention:!1});return{id:K,rootMessage:q,replyCount:H.reply_count,lastReplyAt:H.latest_reply?new Date(Number.parseFloat(H.latest_reply)*1000):void 0}})),W=D.response_metadata?.next_cursor;return{threads:Y,nextCursor:W||void 0}}catch(D){this.handleSlackError(D)}}async fetchChannelInfo(B){let A=B.split(":")[1];if(!A)throw new n8("slack",`Invalid Slack channel ID: ${B}`);try{this.logger.debug("Slack API: conversations.info (channel)",{channel:A});let f=(await this._client.conversations.info(await this.withToken({channel:A}))).channel;if(f?.is_ext_shared)this._externalChannels.add(A);let D="unknown";if(f?.is_ext_shared)D="external";else if(f?.is_im||f?.is_mpim||f?.is_private||A.startsWith("D"))D="private";else if(A.startsWith("C"))D="workspace";return{id:B,name:f?.name?`#${f.name}`:void 0,isDM:Boolean(f?.is_im||f?.is_mpim),channelVisibility:D,memberCount:f?.num_members,metadata:{purpose:f?.purpose?.value,topic:f?.topic?.value}}}catch(w){this.handleSlackError(w)}}async postChannelMessage(B,A){let w=B.split(":")[1];if(!w)throw new n8("slack",`Invalid Slack channel ID: ${B}`);let f=`slack:${w}:`;return await this.postMessage(f,A)}renderFormatted(B){return this.formatConverter.fromAst(B)}isMessageFromSelf(B){let A=this.requestContext.getStore();if(A?.botUserId&&B.user===A.botUserId)return!0;if(this._botUserId&&B.user===this._botUserId)return!0;if(this._botId&&B.bot_id===this._botId)return!0;return!1}handleSlackError(B){let A=B;if(A.code==="slack_webapi_platform_error"&&A.data?.error==="ratelimited")throw new Jq0("slack");throw B}encodeEphemeralMessageId(B,A,w){let f=JSON.stringify({responseUrl:A,userId:w});return`ephemeral:${B}:${btoa(f)}`}decodeEphemeralMessageId(B){if(!B.startsWith("ephemeral:"))return null;let A=B.split(":");if(A.length<3)return null;let w=A[1],f=A.slice(2).join(":");try{let D=atob(f);try{let $=JSON.parse(D);if($.responseUrl&&$.userId)return{messageTs:w,responseUrl:$.responseUrl,userId:$.userId}}catch{return{messageTs:w,responseUrl:D,userId:""}}return null}catch{return this.logger.warn("Failed to decode ephemeral messageId",{messageId:B}),null}}async sendToResponseUrl(B,A,w){let f;if(A==="delete")f={delete_original:!0};else{let Z=w?.message;if(!Z)throw new n8("slack","Message required for replace action");let Q=$f(Z);if(Q)f={replace_original:!0,text:pE(Q),blocks:TE(Q)};else f={replace_original:!0,text:this.formatConverter.toResponseUrlText(Z)};if(w?.threadTs)f.thread_ts=w.threadTs}this.logger.debug("Slack response_url request",{action:A,threadTs:w?.threadTs});let D=await fetch(B,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)});if(!D.ok){let Z=await D.text();throw this.logger.error("Slack response_url failed",{action:A,status:D.status,body:Z}),new X2("slack",`Failed to ${A} via response_url: ${Z}`)}let $=await D.text();if($)try{return JSON.parse($)}catch{return{raw:$}}return{}}};function YHx(x){let B=x?.mode??"webhook",A=x?.appToken??process.env.SLACK_APP_TOKEN;if(B==="socket"){if(!A)throw new n8("slack","appToken is required for socket mode. Set SLACK_APP_TOKEN or provide it in config.");if(x?.clientId||x?.clientSecret)throw new n8("slack","Multi-workspace (clientId/clientSecret) is not supported in socket mode.")}let w=x?.webhookVerifier,f=w?void 0:x?.signingSecret??process.env.SLACK_SIGNING_SECRET;if(B==="webhook"&&!(f||w))throw new n8("slack","signingSecret or webhookVerifier is required. Set SLACK_SIGNING_SECRET, provide signingSecret in config, or provide a webhookVerifier.");let D=!(x?.botToken||x?.clientId||x?.clientSecret||x?.installationProvider||x?.signingSecret||x?.webhookVerifier),$={agentView:x?.agentView,apiUrl:x?.apiUrl,appToken:A,mode:B,signingSecret:f,botToken:x?.botToken??(D?process.env.SLACK_BOT_TOKEN:void 0),clientId:x?.clientId??(D?process.env.SLACK_CLIENT_ID:void 0),clientSecret:x?.clientSecret??(D?process.env.SLACK_CLIENT_SECRET:void 0),encryptionKey:x?.encryptionKey??process.env.SLACK_ENCRYPTION_KEY,installationKeyPrefix:x?.installationKeyPrefix,feedbackButtons:x?.feedbackButtons,installationProvider:x?.installationProvider,loadingMessages:x?.loadingMessages,logger:x?.logger??new pQ("info").child("slack"),nativeStreaming:x?.nativeStreaming,suggestedPrompts:x?.suggestedPrompts,socketForwardingSecret:x?.socketForwardingSecret??process.env.SLACK_SOCKET_FORWARDING_SECRET,userName:x?.userName,botUserId:x?.botUserId,webClientOptions:x?.webClientOptions,webhookVerifier:w};return new jn8($)}var _n8=class{subscriptions=new Set;locks=new Map;cache=new Map;queues=new Map;connected=!1;connectPromise=null;async connect(){if(this.connected)return;if(!this.connectPromise)this.connectPromise=Promise.resolve().then(()=>{this.connected=!0});await this.connectPromise}async disconnect(){this.connected=!1,this.connectPromise=null,this.subscriptions.clear(),this.locks.clear(),this.queues.clear()}async subscribe(x){this.ensureConnected(),this.subscriptions.add(x)}async unsubscribe(x){this.ensureConnected(),this.subscriptions.delete(x)}async isSubscribed(x){return this.ensureConnected(),this.subscriptions.has(x)}async acquireLock(x,B){this.ensureConnected(),this.cleanExpiredLocks();let A=this.locks.get(x);if(A&&A.expiresAt>Date.now())return null;let w={threadId:x,token:Pn8(),expiresAt:Date.now()+B};return this.locks.set(x,w),w}async forceReleaseLock(x){this.ensureConnected(),this.locks.delete(x)}async releaseLock(x){this.ensureConnected();let B=this.locks.get(x.threadId);if(B&&B.token===x.token)this.locks.delete(x.threadId)}async extendLock(x,B){this.ensureConnected();let A=this.locks.get(x.threadId);if(!A||A.token!==x.token)return!1;if(A.expiresAt<Date.now())return this.locks.delete(x.threadId),!1;return A.expiresAt=Date.now()+B,!0}async get(x){this.ensureConnected();let B=this.cache.get(x);if(!B)return null;if(B.expiresAt!==null&&B.expiresAt<=Date.now())return this.cache.delete(x),null;return B.value}async set(x,B,A){this.ensureConnected(),this.cache.set(x,{value:B,expiresAt:A?Date.now()+A:null})}async setIfNotExists(x,B,A){this.ensureConnected();let w=this.cache.get(x);if(w)if(w.expiresAt!==null&&w.expiresAt<=Date.now())this.cache.delete(x);else return!1;return this.cache.set(x,{value:B,expiresAt:A?Date.now()+A:null}),!0}async delete(x){this.ensureConnected(),this.cache.delete(x)}async appendToList(x,B,A){this.ensureConnected();let w=this.cache.get(x),f;if(w&&w.expiresAt!==null&&w.expiresAt<=Date.now())f=[];else if(w&&Array.isArray(w.value))f=w.value;else f=[];if(f.push(B),A?.maxLength&&f.length>A.maxLength)f=f.slice(f.length-A.maxLength);this.cache.set(x,{value:f,expiresAt:A?.ttlMs?Date.now()+A.ttlMs:null})}async enqueue(x,B,A){this.ensureConnected();let w=this.queues.get(x);if(!w)w=[],this.queues.set(x,w);if(w.push(B),w.length>A)w.splice(0,w.length-A);return w.length}async dequeue(x){this.ensureConnected();let B=this.queues.get(x);if(!B||B.length===0)return null;let A=B.shift();if(B.length===0)this.queues.delete(x);return A??null}async queueDepth(x){return this.ensureConnected(),this.queues.get(x)?.length??0}async getList(x){this.ensureConnected();let B=this.cache.get(x);if(!B)return[];if(B.expiresAt!==null&&B.expiresAt<=Date.now())return this.cache.delete(x),[];if(Array.isArray(B.value))return B.value;return[]}ensureConnected(){if(!this.connected)throw Error("MemoryStateAdapter is not connected. Call connect() first.")}cleanExpiredLocks(){let x=Date.now();for(let[B,A]of this.locks)if(A.expiresAt<=x)this.locks.delete(B)}_getSubscriptionCount(){return this.subscriptions.size}_getLockCount(){return this.cleanExpiredLocks(),this.locks.size}};function Pn8(){return`mem_${Date.now()}_${Math.random().toString(36).substring(2,15)}`}function eI(x){return new _n8}var Jn8=X.object({subscribedAt:X.string().datetime(),routingMode:X.enum(["auto","mention-required"]).optional(),mentionRequiredNoticeSent:X.boolean().optional()});var Ln8="chat.discord.subscriptions",kn8="chat.slack.subscriptions";function Mn8(x){return x==="discord"?Ln8:kn8}function Nx0(x,B){return x.scoped({namespace:Mn8(B),schema:Jn8})}function WHx(x){return Nx0(x,"discord")}function HHx(x){return Nx0(x,"slack")}function FHx(x,B,A=eI()){let w=new Map;for(let f of B)w.set(f,Nx0(x,f));return new KHx(A,w)}class KHx{memoryState;subscriptions;constructor(x,B){this.memoryState=x,this.subscriptions=B}connect(){return this.memoryState.connect()}disconnect(){return this.memoryState.disconnect()}async subscribe(x){let B=this.getSubscriptionStore(x);if(!B)return this.memoryState.subscribe(x);await B.set(x,{subscribedAt:new Date().toISOString()})}async unsubscribe(x){let B=this.getSubscriptionStore(x);if(!B)return this.memoryState.unsubscribe(x);await B.delete(x)}isSubscribed(x){let B=this.getSubscriptionStore(x);return B?B.has(x):this.memoryState.isSubscribed(x)}acquireLock(x,B){return this.memoryState.acquireLock(x,B)}appendToList(x,B,A){return this.memoryState.appendToList(x,B,A)}delete(x){return this.memoryState.delete(x)}dequeue(x){return this.memoryState.dequeue(x)}enqueue(x,B,A){return this.memoryState.enqueue(x,B,A)}extendLock(x,B){return this.memoryState.extendLock(x,B)}forceReleaseLock(x){return this.memoryState.forceReleaseLock(x)}get(x){return this.memoryState.get(x)}getList(x){return this.memoryState.getList(x)}queueDepth(x){return this.memoryState.queueDepth(x)}releaseLock(x){return this.memoryState.releaseLock(x)}set(x,B,A){return this.memoryState.set(x,B,A)}setIfNotExists(x,B,A){return this.memoryState.setIfNotExists(x,B,A)}getSubscriptionStore(x){let B=x.split(":")[0];if(B!=="discord"&&B!=="slack")return;return this.subscriptions.get(B)}}function qHx(x,B){if(!x)throw Error(B);return x}function zHx(x){let{discord:B,slack:A}=x,w=B?WDx({botToken:B.botToken,publicKey:B.publicKey,applicationId:B.applicationId,mentionRoleIds:B.mentionRoleIds}):void 0;if(w)x.gatewayLoop.setAdapter(w);let D=A?YHx(A.mode==="socket"?{botToken:A.botToken,mode:"socket",appToken:qHx(A.appToken,"Slack app token is required in socket mode")}:{botToken:A.botToken,signingSecret:qHx(A.signingSecret,"Slack signing secret is required in webhook mode")}):void 0;if(D&&A?.mode==="socket")x.slackSocketLoop.setAdapter(D);let $={...w?{discord:w}:{},...D?{slack:D}:{}},Z=[...B?["discord"]:[],...A?["slack"]:[]],Q=Z.length>0?FHx(x.runtimeState,Z):eI();return new zq0({userName:x.userName,adapters:$,...B||A?{concurrency:{strategy:"queue",maxQueueSize:5,onQueueFull:"drop-oldest"}}:{},state:Q})}class Ix0{deps;constructor(x){this.deps=x}async subscribeOwnedThread(x,B){if(!this.deps.isBotCreatedThread(x,B))return;await this.subscribeThread(x)}async subscribeThread(x){try{await x.subscribe(),await this.getSubscriptions(x)?.set(x.id,{subscribedAt:new Date().toISOString()})}catch(B){this.deps.logger.debug("Chat thread subscription failed",{error:B,threadId:x.id})}}async shouldRouteSubscribedMessage(x,B){let A=this.getSubscriptions(x);if(!A)return!1;if(x.isDM)return!0;let w=await A.get(x.id);if(!w)return!1;if(w.routingMode==="mention-required"){if(!B.isMention&&!w.mentionRequiredNoticeSent)await this.postMentionRequiredNotice(x,w);return Boolean(B.isMention)}if(!await this.shouldRequireMentionInSubscribedThread(x))return!0;let D={...w,routingMode:"mention-required"};if(!B.isMention&&!w.mentionRequiredNoticeSent)await this.postMentionRequiredNotice(x,D);else await A.set(x.id,D);return Boolean(B.isMention)}async postMentionRequiredNotice(x,B){await x.post("I\u2019ll stop auto-replying now that more people joined. Mention me if you need me."),await this.getSubscriptions(x)?.set(x.id,{...B,routingMode:"mention-required",mentionRequiredNoticeSent:!0})}async shouldRequireMentionInSubscribedThread(x){try{return(await x.getParticipants()).filter((w)=>!w.isBot&&!w.isMe).length>1}catch(B){return this.deps.logger.debug("Failed to inspect chat thread participants",{error:B,threadId:x.id}),!1}}getSubscriptions(x){return this.deps.getSubscriptions(this.deps.getPlatform(x))}}function I3(x){let B=x.split(":");if(B[0]!=="discord")return{};return{...B[1]?{guildId:B[1]}:{},...B[2]?{channelId:B[2]}:{},...B[3]?{threadId:B[3]}:{}}}function bHx(x){return x.channelId}function VHx(x,B){let A=I3(B.id);return A.channelId?`${x}:${A.channelId}`:B.channelId}function vn8(x){let B=x.raw;if(typeof B!=="object"||B===null)return;let A=B.channel_id;return typeof A==="string"?A:void 0}function UHx(x,B){if(x.isDM)return!1;let A=I3(x.id);if(!A.threadId)return!1;let w=vn8(B);return w!==void 0&&w!==A.threadId}function uE(x,B){if(B.allowedChannels.length===0||x.isDM)return!0;let A=I3(x.id),w=x.id.split(":")[0]==="slack"?x.id.split(":")[1]:void 0;return[x.id,x.channelId,A.channelId,A.threadId,w].some((f)=>typeof f==="string"&&B.allowedChannels.includes(f))}function SE(x,B,A){if(x.isDM&&!A.allowDMs)return!1;if(B.author.isMe)return!1;if(B.author.isBot&&!B.isMention)return!1;return uE(x,A)}function Ox0(x,B){if(!B)return!1;if(x.isDM&&!B.allowDMs)return!1;return uE(x,B)}function uK(x,B){let A=I3(x.id),w=x.id.split(":")[0]==="slack"?x.id.split(":")[1]:void 0;return{channelId:A.channelId??w??x.channelId,isBot:Boolean(B.author.isBot)}}function n$(x){return x.isDM?"DM":x.channelId}async function iE(x,B,A,w,f){if(B==="discord"){let D=await f?.resolveIdentityAccess({type:"discord",subject:A});if(D?.state==="resolved")return{permissionLevel:D.principal.permissionLevel,isAnchor:D.principal.isAnchor,principal:D.principal};if(D?.state==="denied")return{permissionLevel:"public",isAnchor:!1}}return{permissionLevel:x.getUserLevel(B,A,w),isAnchor:x.isAnchor(B,A)}}function nE(x,B){return`${x}-${B}`}function EHx(x,B){let A=GHx({message:x,skippedMessages:(B?.skipped??[]).map((w)=>({id:w.id,text:w.text,authorName:w.author.fullName||w.author.userName}))});return A.metadata?{message:A.message,metadata:{...A.metadata}}:{message:A.message}}function hx0(x,B,A,w,f){return{actor:yx0(x,{userId:A.author.userId,userName:A.author.userName,fullName:A.author.fullName,isBot:A.author.isBot},f),source:_Hx(B,{messageId:A.id,channelName:n$(B),...w?{metadata:w}:{}})}}function jHx(x,B,A,w,f){let D=I3(B.id);return{actor:yx0(x,{userId:w.author.userId,userName:w.author.userName,fullName:w.author.fullName,isBot:w.author.isBot},f),source:lE({messageId:w.id,channelId:A,channelName:n$(B),...D.threadId?{threadId:D.threadId}:{},metadata:{...D.guildId?{guildId:D.guildId}:{}}})}}function Rx0(x,B,A,w){return{actor:yx0(x,{userId:A.user.userId,userName:A.user.userName,fullName:A.user.fullName,isBot:A.user.isBot},w),source:_Hx(B,{messageId:A.messageId,channelName:n$(B),metadata:{actionId:A.actionId,...A.value?{actionValue:A.value}:{}}})}}function yx0(x,B,A){return xO({identity:A?{kind:"user",userId:A.userId,...A.canonicalId?{canonicalId:A.canonicalId}:{}}:{kind:"external",externalActorId:pA(x,B.userId)},interfaceType:x,displayName:A?.displayName??(B.fullName||B.userName),username:B.userName,isBot:B.isBot})}function _Hx(x,B){let A=I3(x.id);return lE({messageId:B.messageId,channelId:x.id,channelName:B.channelName,...A.threadId?{threadId:A.threadId}:{},metadata:{...B.metadata??{},...A.guildId?{guildId:A.guildId}:{}}})}var Nn8=/https?:\/\/\S+/i,In8=/[\s\S]+/;class mx0{deps;constructor(x){this.deps=x}registerHandlers(x){x.onDirectMessage(async(B,A,w,f)=>{await this.handleRoutedMessage(B,A,f)}),x.onNewMention(async(B,A,w)=>{let f=this.getPlatformConfig(B),D=this.getPlatform(B);if(D==="discord"&&this.deps.config.adapters.discord&&f&&SE(B,A,f)&&!B.isDM&&this.deps.config.adapters.discord.useThreads)await this.deps.subscriptionRouter.subscribeOwnedThread(B,A);else if(D==="slack"&&f&&SE(B,A,f)&&!B.isDM)await this.deps.subscriptionRouter.subscribeThread(B);await this.handleRoutedMessage(B,A,w)}),x.onSubscribedMessage(async(B,A,w)=>{if(!await this.deps.subscriptionRouter.shouldRouteSubscribedMessage(B,A))return;await this.handleRoutedMessage(B,A,w)}),x.onNewMessage(Nn8,async(B,A)=>{await this.handlePassiveUrlCapture(B,A)}),x.onNewMessage(In8,async(B,A,w)=>{let f=this.getPlatformConfig(B);if(f&&!f.requireMention)await this.handleRoutedMessage(B,A,w);await this.capturePassiveSpaceMessage(B,A).catch((D)=>this.deps.logger.error("Passive space capture failed",{error:D,channelId:B.channelId}))}),x.onAction([vk,Ji],async(B)=>{await this.handleApprovalAction(B)}),x.onAction(aV,async(B)=>{await this.handlePromptAction(B)}),x.onAction(async(B)=>{if(!B.actionId.startsWith(`${aV}:`))return;await this.handlePromptAction(B)})}async handlePromptAction(x){let B=this.deps.host.getContext();if(!B||!x.thread||!x.value)return;let A=x.adapter.name;if(!d$(this.deps.config,A))return;let w=x.thread;if(!Ox0(w,this.getPlatformConfig(w)))return;let f=this.deps.promptActions.get(x.value);if(f?.threadId!==w.id){await w.post($F("That suggested action is no longer available.","Action unavailable"));return}this.deps.promptActions.consume(x.value);let D=await iE(B.permissions,A,x.user.userId,uK(w,{author:{isMe:x.user.isMe,isBot:x.user.isBot}}),this.deps.identityAccess()),{permissionLevel:$,isAnchor:Z}=D,Q=nE(A,w.id),Y=w.id;await this.runAgentTurn({thread:w,channelId:Y,logLabel:"Error handling chat prompt action",body:async()=>{let W=this.deps.host.getContext();if(!W)return;let H=await this.deps.uploadCoordinator.selectPriorUploads({platform:A,conversationId:Q,currentAttachments:[],canRestore:$==="admin"||$==="trusted"}),F=await W.agent.chat(f.prompt,Q,{userPermissionLevel:$,isAnchor:Z,interfaceType:A,channelId:Y,channelName:n$(w),...Rx0(A,w,x,D.principal),...H.length>0?{attachments:H}:{}});await this.deps.responseCoordinator.renderAgentResponse({thread:w,channelId:Y,conversationId:Q,response:F,userPermissionLevel:$})}})}async handleApprovalAction(x){let B=this.deps.host.getContext();if(!B||!x.thread||!x.value)return;let A=x.adapter.name;if(!d$(this.deps.config,A))return;let w=x.thread;if(!Ox0(w,this.getPlatformConfig(w)))return;let f=nE(A,w.id);if(!(await this.deps.responseCoordinator.getPendingApprovalIds(f)).has(x.value)){await w.post($F("That approval is no longer pending."));return}let $=await iE(B.permissions,A,x.user.userId,uK(w,{author:{isMe:x.user.isMe,isBot:x.user.isBot}}),this.deps.identityAccess());await this.deps.responseCoordinator.confirmApproval({thread:w,conversationId:f,approvalId:x.value,confirmed:x.actionId===vk,userPermissionLevel:$.permissionLevel,isAnchor:$.isAnchor,metadata:Rx0(A,w,x,$.principal)})}async handleRoutedMessage(x,B,A){if(!this.deps.host.getContext())return;let w=this.getPlatform(x);if(!d$(this.deps.config,w))return;let f=this.getPlatformConfig(x);if(!f)return;if(!SE(x,B,f))return;await this.routeToAgent(w,x,B,A)}async runAgentTurn(x){this.deps.host.startProcessingInput(x.channelId);try{if(this.getPlatformConfig(x.thread)?.showTypingIndicator)await x.thread.startTyping().catch((B)=>this.deps.logger.debug("Typing indicator failed",{error:B,channelId:x.channelId}));await x.body()}catch(B){this.deps.logger.error(x.logLabel,{error:B,channelId:x.channelId}),await this.postTurnError(x.thread,x.channelId,B)}finally{this.deps.host.endProcessingInput()}}async postTurnError(x,B,A){let w=lF0(A),f=yQ(B,w);if(f!==void 0){await x.post(f);return}let D=typeof w==="string"?w:"Message failed.";for(let $ of RQ(B,D))await x.post($)}async routeToAgent(x,B,A,w){let f=this.deps.host.getContext();if(!f)return;this.deps.threadRegistry.set(B);let D=nE(x,B.id),$=B.id,Z=uK(B,A),Q=await iE(f.permissions,x,A.author.userId,Z,this.deps.identityAccess()),{permissionLevel:Y,isAnchor:W}=Q,H=await this.deps.chatInputBuilder.build(x,B,A,Y),F=[...H.attachments];if(await this.deps.uploadCoordinator.attachPriorUploads(x,D,H,Y),await this.postUploadNotices(B,H.notices),!H.message&&H.attachments.length===0)return;this.deps.uploadCoordinator.remember(x,D,F),await this.runAgentTurn({thread:B,channelId:$,logLabel:"Error handling chat message",body:async()=>{let K=this.deps.host.getContext();if(!K)return;let q=await this.deps.responseCoordinator.getPendingApprovalIds(D);if(q.size>0){if(await this.deps.responseCoordinator.handleConfirmationResponse({message:H.message,conversationId:D,thread:B,approvalIds:q,userPermissionLevel:Y,isAnchor:W,metadata:hx0(x,B,A,void 0,Q.principal)}))return}let V=EHx(H.message,w),b=await K.agent.chat(V.message,D,{userPermissionLevel:Y,isAnchor:W,interfaceType:x,channelId:$,channelName:n$(B),...hx0(x,B,A,V.metadata,Q.principal),...H.attachments.length>0?{attachments:H.attachments}:{}});await this.deps.responseCoordinator.renderAgentResponse({thread:B,channelId:$,conversationId:D,response:b,userPermissionLevel:Y})}})}async capturePassiveSpaceMessage(x,B){let A=this.deps.host.getContext();if(!A)return;let w=this.getPlatform(x);if(!d$(this.deps.config,w))return;let f=this.getPlatformConfig(x);if(!f)return;if(x.isDM)return;if(B.author.isMe||B.author.isBot)return;if(!uE(x,f))return;let D=VHx(w,x);if(!A.spaces.some((F)=>BO(F,D)))return;let $=bHx(x),Z=SE(x,B,f)&&(!f.requireMention||B.isMention);if($===x.id&&Z)return;let Q=B.text.trim();if(!Q)return;let Y=nE(w,$),W=await iE(A.permissions,w,B.author.userId,uK(x,B),this.deps.identityAccess()),H=n$(x);await A.conversations.start({sessionId:Y,interfaceType:w,channelId:$,metadata:{channelName:H,interfaceType:w,channelId:$}}),await A.conversations.addMessage({conversationId:Y,role:"user",content:Q,metadata:jHx(w,x,$,B,W.principal)})}async handlePassiveUrlCapture(x,B){let A=this.getPlatform(x);if(!d$(this.deps.config,A))return;let w=this.getPlatformConfig(x);if(!w?.captureUrls)return;if(!w.requireMention)return;if(!uE(x,w))return;if(B.author.isMe)return;if(B.author.isBot)return;if(B.isMention)return;let f=this.deps.host.extractCaptureableUrls(B.text,w.blockedUrlDomains);if(f.length===0)return;this.deps.threadRegistry.set(x);let D=uK(x,B);for(let $ of f)await this.deps.host.captureUrlViaAgent($,x.id,B.author.userId,A,D).catch((Z)=>this.deps.logger.error("URL capture failed",{error:Z,url:$}))}async postUploadNotices(x,B){let A=[...new Set(B)];if(A.length===0)return;await x.post(["Some uploads were skipped:",...A.map((w)=>`- ${w}`)].join(`
5310
- `))}getPlatform(x){return x.adapter.name}getPlatformConfig(x){let B=this.getPlatform(x);if(B==="discord")return this.deps.config.adapters.discord;if(B==="slack")return this.deps.config.adapters.slack;return}}function d$(x,B){let A=new Set;if(x.adapters.discord)A.add("discord");if(x.adapters.slack)A.add("slack");return pF0(B,A)}var On8="https://discord.com/api/v10";async function PHx(x){let B=I3(x.threadId),A=B.threadId??B.channelId;if(!A)return;let w=x.fetchFn??fetch;try{let f=await w(`${On8}/channels/${A}/messages/${x.messageId}`,{method:"PATCH",headers:{Authorization:`Bot ${x.botToken}`,"Content-Type":"application/json"},body:JSON.stringify({components:[]})});if(!f.ok)x.logger.debug("Failed to clear Discord message components",{messageId:x.messageId,channelId:A,status:f.status})}catch(f){x.logger.debug("Failed to clear Discord message components",{error:f,messageId:x.messageId,channelId:A})}}var JHx={name:"@brains/chat",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Multi-platform Chat SDK interface for Brains",dependencies:{"@brains/auth-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@chat-adapter/discord":"^4.34.0","@chat-adapter/slack":"^4.34.0","@chat-adapter/state-memory":"^4.34.0",chat:"^4.34.0"},devDependencies:{"@brains/core":"workspace:*","@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix","slack:preflight":"bun scripts/slack-preflight.ts",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Rn8=1000;class AO extends SK{threadRegistry=new Lk;promptActions=new _i(Rn8);toolStatusMessenger=new Pi(this.threadRegistry);compactingSlackApprovalToolStatuses=new Set;uploadCoordinator=new pi({getContext:()=>this.context,logger:this.logger});responseCoordinator=new Oi({getContext:()=>this.context,getDisplayBaseUrl:()=>this.getPreferredDisplayBaseUrl(),registerPromptAction:(x,B)=>this.promptActions.register(x,B),clearMessageComponents:async(x,B)=>{let A=this.config.adapters.discord?.botToken;if(!A)return;await PHx({threadId:x,messageId:B,botToken:A,logger:this.logger})},sendMessageWithId:(x)=>this.sendMessageWithId(x),handleAgentResponseToolStatuses:(x,B)=>this.handleAgentResponseToolStatuses(x,B),trackAgentResponseForJob:(x,B,A)=>this.trackAgentResponseForJob(x,B,A),threadRegistry:this.threadRegistry,logger:this.logger});subscriptionRouter=new Ix0({getSubscriptions:(x)=>x==="discord"?this.discordSubscriptions:x==="slack"?this.slackSubscriptions:void 0,getPlatform:(x)=>x.adapter.name,isBotCreatedThread:UHx,logger:this.logger});chatInputBuilder=new yi({getUploadStore:(x)=>x==="discord"||x==="slack"?this.uploadCoordinator.getCanonicalStore():void 0,getThreadIdParts:I3,logger:this.logger});turnController;gatewayLoop;slackSocketLoop;chatApp;discordSubscriptions;slackSubscriptions;chatAppRunning=!1;constructor(x={},B=X6){super("chat",JHx,x,ji);this.turnController=new mx0({identityAccess:B,config:this.config,host:{getContext:()=>this.context,startProcessingInput:(A)=>this.startProcessingInput(A),endProcessingInput:()=>this.endProcessingInput(),extractCaptureableUrls:(A,w)=>this.extractCaptureableUrls(A,w),captureUrlViaAgent:(A,w,f,D,$)=>this.captureUrlViaAgent(A,w,f,D,$)},promptActions:this.promptActions,threadRegistry:this.threadRegistry,subscriptionRouter:this.subscriptionRouter,chatInputBuilder:this.chatInputBuilder,uploadCoordinator:this.uploadCoordinator,responseCoordinator:this.responseCoordinator,logger:{debug:(A,w)=>this.logger.debug(A,w),error:(A,w)=>this.logger.error(A,w)}}),this.gatewayLoop=new ui({getApp:()=>this.chatApp.instance,gatewayRunMs:this.config.gatewayRunMs,gatewayRestartDelayMs:this.config.gatewayRestartDelayMs,logger:this.logger}),this.slackSocketLoop=new Si({listenerRunMs:this.config.gatewayRunMs,restartDelayMs:this.config.gatewayRestartDelayMs,logger:this.logger}),this.chatApp=new ii({discord:this.config.adapters.discord,slack:this.config.adapters.slack,getUploadStore:(A)=>this.uploadCoordinator.getPlatformStore(A),buildApp:(A)=>zHx({userName:this.config.userName,discord:this.config.adapters.discord,slack:this.config.adapters.slack,gatewayLoop:this.gatewayLoop,slackSocketLoop:this.slackSocketLoop,runtimeState:A})})}async onRegister(x){if(await super.onRegister(x),this.config.adapters.discord)x.channels.registerDescriptor({type:"discord",displayName:"Discord",subjectLabel:"Discord user ID",subjectPattern:{source:"^[0-9]{17,20}$"},manualDelivery:!0}),this.discordSubscriptions=WHx(x.runtimeState);if(this.config.adapters.slack)x.channels.registerDescriptor({type:"slack",displayName:"Slack",subjectLabel:"Slack member ID",subjectPattern:{source:"^[UW][A-Z0-9]+$"},manualDelivery:!0}),this.slackSubscriptions=HHx(x.runtimeState);this.turnController.registerHandlers(this.chatApp.build(x.runtimeState))}getWebRoutes(){return this.chatApp.getWebRoutes()}createDaemon(){let x=Boolean(this.config.adapters.discord),B=this.config.adapters.slack?.mode==="socket";if(!x&&!this.config.adapters.slack)return;return{start:async()=>{if(await this.chatApp.initialize(),this.chatAppRunning=!0,x)this.gatewayLoop.start();if(B)this.slackSocketLoop.start()},stop:async()=>{await this.gatewayLoop.stop(),await this.slackSocketLoop.stop(),this.threadRegistry.clear(),this.uploadCoordinator.clear(),this.responseCoordinator.clear(),this.toolStatusMessenger.clear(),await this.chatApp.shutdown(),this.chatAppRunning=!1},healthCheck:async()=>{let A=this.chatAppRunning&&(!x||this.gatewayLoop.isRunning())&&(!B||this.slackSocketLoop.isRunning());return{status:A?"healthy":"error",message:A?"Chat SDK app running":"Chat SDK app stopped",lastCheck:new Date}}}}sendMessageToChannel({channelId:x,message:B}){let A=this.threadRegistry.get(x);if(!A)return;let w=this.toPlatformPostOutput(x,B);if(w!==void 0){A.post(w).catch((f)=>this.logger.error("Failed to send chat message",{error:f,channelId:x}));return}if(typeof B!=="string")return;for(let f of RQ(x,B))A.post(f).catch((D)=>this.logger.error("Failed to send chat message",{error:D,channelId:x}))}async sendMessageWithId({channelId:x,message:B}){let A=this.threadRegistry.get(x);if(!A)return;let w=this.toPlatformPostOutput(x,B);if(w!==void 0){let D=await A.post(w);return this.threadRegistry.trackMessage(A.id,D),D.id}if(typeof B!=="string")return;let f;for(let D of RQ(x,B))f=await A.post(D),this.threadRegistry.trackMessage(A.id,f);return f?.id}async editMessage({channelId:x,messageId:B,newMessage:A}){let w=this.threadRegistry.getMessage(x,B);if(!w)return!1;try{let f=await w.edit(this.toPlatformPostOutput(x,A)??(typeof A==="string"?A:""));if(x)this.threadRegistry.trackMessage(x,f);return!0}catch{return!1}}supportsMessageEditing(){return!0}toPlatformPostOutput(x,B){return yQ(x,B)}formatProgressOutput(x){return Li(x)}formatCompletionOutput(x){return Li(x)}async handleProgressEvent(x,B){let A=x.metadata.interfaceType,w=x,f=B;if(A&&A!==this.id){if(!d$(this.config,A))return;w={...x,metadata:{...x.metadata,interfaceType:this.id}},f=w.metadata}await super.handleProgressEvent(w,f),await this.responseCoordinator.deliverCompletedJobArtifacts(w)}async handleToolActivityEvent(x){if(x.interfaceType===this.id){await super.handleToolActivityEvent(x);return}if(!d$(this.config,x.interfaceType))return;await super.handleToolActivityEvent({...x,interfaceType:this.id})}async handleToolStatusUpdate(x){if(x.interfaceType!==this.id||!x.channelId)return;let B=sV(x.channelId)==="slack",A=B&&this.responseCoordinator.isActiveSlackConfirmation(x.conversationId);if(B&&this.compactingSlackApprovalToolStatuses.has(dV(x))||A||B&&x.state==="completed"){await this.toolStatusMessenger.dismiss(x);return}await this.toolStatusMessenger.handle(x)}async handleAgentResponseToolStatuses(x,B){let A=new Set([...(x.pendingConfirmations??[]).map((f)=>f.toolName),...(x.cards??[]).filter((f)=>f.kind==="tool-approval").map((f)=>f.toolName)]),w=B.startsWith("slack-")?[...A].map((f)=>`${B}:${f}`):[];for(let f of w)this.compactingSlackApprovalToolStatuses.add(f);try{await super.handleAgentResponseToolStatuses(x,B)}finally{for(let f of w)this.compactingSlackApprovalToolStatuses.delete(f)}}getPreferredDisplayBaseUrl(){if(this.context?.preferLocalUrls&&this.context.localSiteUrl)return this.context.localSiteUrl;return this.context?.siteUrl??this.context?.localSiteUrl}}function Cx0(x,B={}){let{DISCORD_BOT_TOKEN:A,DISCORD_PUBLIC_KEY:w,DISCORD_APPLICATION_ID:f}=x;if(!A||!w||!f)return{};return{adapters:{discord:{botToken:A,publicKey:w,applicationId:f,...B}}}}function cx0(x){let B=x.startsWith("/")?x:`/${x}`;return B==="/"?"":B.replace(/\/+$/,"")}function LHx(x,B){return`${cx0(x)}/workspaces/${encodeURIComponent(B)}`}import{join as rn8}from"path";function wO(x){return x instanceof X.ZodType?x.def.type:void 0}function yn8(x){return typeof x==="function"?x():x}function fO(x){let B=x,A=!0,w,f=!1;for(;;){if(B instanceof X.ZodOptional||B instanceof X.ZodNullable){A=!1,B=B.unwrap();continue}if(B instanceof X.ZodDefault){A=!1,f=!0,w=yn8(B.def.defaultValue),B=B.def.innerType;continue}if(B instanceof X.ZodPipe){B=B.def.out;continue}break}let D={inner:B,required:A};if(f&&w!==void 0)D.defaultValue=w;return D}function DO(x){if(!(x instanceof X.ZodEnum))return;let B=Object.values(x.def.entries);if(B.every((A)=>typeof A==="string"))return B;return}function $O(x){return x instanceof X.ZodLiteral?x.def.values[0]:void 0}function kHx(x){return x instanceof X.ZodObject?x.shape:void 0}function MHx(x){return x instanceof X.ZodArray?x.def.element:void 0}function vHx(x,B){if(x instanceof X.ZodStringFormat)return x.def.format===B;if(!(x instanceof X.ZodString))return!1;return(x.def.checks??[]).some((w)=>w instanceof X.ZodStringFormat&&w.def.format===B)}function NHx(x){return x instanceof X.ZodType?x.meta():void 0}var IHx="note",mn8=new Set(["description","excerpt","summary","tagline","story"]);function Cn8(x){if(x.endsWith("s"))return x;return ZO(x)}function rX(x){return x===IHx}function OHx(x,B){let A=x===IHx?"Note":aD(x),w=B?.label??A;return{label:w,pluralLabel:B?.pluralName??Cn8(w)}}function cn8(x){return typeof x==="object"&&x!==null}function gn8(x){let B=NHx(x)?.cmsCondition;if(!cn8(B)||typeof B.field!=="string"||!Object.hasOwn(B,"value"))return;return{field:B.field,value:B.value}}function Tn8(x){return x==="imageId"||x.endsWith("ImageId")}function iK(x,B){let{inner:A,required:w,defaultValue:f}=fO(B),D=wO(A),$=f??$O(A),Z=gn8(B),Q={name:x,label:aD(x),widget:"string",...!w&&{required:!1},...$!==void 0&&{default:$},...Z&&{condition:Z}};switch(D){case"string":{if(Tn8(x))return{...Q,widget:"image"};if(vHx(A,"datetime"))return{...Q,widget:"datetime"};if(mn8.has(x))return{...Q,widget:"text"};return{...Q,widget:"string"}}case"number":return{...Q,widget:"number"};case"boolean":return{...Q,widget:"boolean"};case"enum":{let Y=DO(A);return{...Q,widget:"select",...Y?{options:Y}:{}}}case"array":{let Y=MHx(A),W=iK("item",Y);if(W.widget==="object"&&W.fields)return{...Q,widget:"list",fields:W.fields};return{...Q,widget:"list",field:{name:x,label:aD(x),widget:W.widget}}}case"object":{let Y=Object.entries(kHx(A)??{}).map(([W,H])=>iK(W,H));return{...Q,widget:"object",fields:Y}}case"literal":return{...Q,widget:"string"};default:return{...Q,widget:"string"}}}function gx0(x){let B=x.basePath.replaceAll("&","&amp;").replaceAll('"',"&quot;").replaceAll("<","&lt;").replaceAll(">","&gt;");return`<!doctype html>
5310
+ `))}getPlatform(x){return x.adapter.name}getPlatformConfig(x){let B=this.getPlatform(x);if(B==="discord")return this.deps.config.adapters.discord;if(B==="slack")return this.deps.config.adapters.slack;return}}function d$(x,B){let A=new Set;if(x.adapters.discord)A.add("discord");if(x.adapters.slack)A.add("slack");return pF0(B,A)}var On8="https://discord.com/api/v10";async function PHx(x){let B=I3(x.threadId),A=B.threadId??B.channelId;if(!A)return;let w=x.fetchFn??fetch;try{let f=await w(`${On8}/channels/${A}/messages/${x.messageId}`,{method:"PATCH",headers:{Authorization:`Bot ${x.botToken}`,"Content-Type":"application/json"},body:JSON.stringify({components:[]})});if(!f.ok)x.logger.debug("Failed to clear Discord message components",{messageId:x.messageId,channelId:A,status:f.status})}catch(f){x.logger.debug("Failed to clear Discord message components",{error:f,messageId:x.messageId,channelId:A})}}var JHx={name:"@brains/chat",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Multi-platform Chat SDK interface for Brains",dependencies:{"@brains/auth-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@chat-adapter/discord":"^4.34.0","@chat-adapter/slack":"^4.34.0","@chat-adapter/state-memory":"^4.34.0",chat:"^4.34.0"},devDependencies:{"@brains/core":"workspace:*","@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix","slack:preflight":"bun scripts/slack-preflight.ts",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Rn8=1000;class AO extends SK{threadRegistry=new Lk;promptActions=new _i(Rn8);toolStatusMessenger=new Pi(this.threadRegistry);compactingSlackApprovalToolStatuses=new Set;uploadCoordinator=new pi({getContext:()=>this.context,logger:this.logger});responseCoordinator=new Oi({getContext:()=>this.context,getDisplayBaseUrl:()=>this.getPreferredDisplayBaseUrl(),registerPromptAction:(x,B)=>this.promptActions.register(x,B),clearMessageComponents:async(x,B)=>{let A=this.config.adapters.discord?.botToken;if(!A)return;await PHx({threadId:x,messageId:B,botToken:A,logger:this.logger})},sendMessageWithId:(x)=>this.sendMessageWithId(x),handleAgentResponseToolStatuses:(x,B)=>this.handleAgentResponseToolStatuses(x,B),trackAgentResponseForJob:(x,B,A)=>this.trackAgentResponseForJob(x,B,A),threadRegistry:this.threadRegistry,logger:this.logger});subscriptionRouter=new Ix0({getSubscriptions:(x)=>x==="discord"?this.discordSubscriptions:x==="slack"?this.slackSubscriptions:void 0,getPlatform:(x)=>x.adapter.name,isBotCreatedThread:UHx,logger:this.logger});chatInputBuilder=new yi({getUploadStore:(x)=>x==="discord"||x==="slack"?this.uploadCoordinator.getCanonicalStore():void 0,getThreadIdParts:I3,logger:this.logger});turnController;gatewayLoop;slackSocketLoop;chatApp;discordSubscriptions;slackSubscriptions;chatAppRunning=!1;constructor(x={},B=X6){super("chat",JHx,x,ji);this.turnController=new mx0({identityAccess:B,config:this.config,host:{getContext:()=>this.context,startProcessingInput:(A)=>this.startProcessingInput(A),endProcessingInput:()=>this.endProcessingInput(),extractCaptureableUrls:(A,w)=>this.extractCaptureableUrls(A,w),captureUrlViaAgent:(A,w,f,D,$)=>this.captureUrlViaAgent(A,w,f,D,$)},promptActions:this.promptActions,threadRegistry:this.threadRegistry,subscriptionRouter:this.subscriptionRouter,chatInputBuilder:this.chatInputBuilder,uploadCoordinator:this.uploadCoordinator,responseCoordinator:this.responseCoordinator,logger:{debug:(A,w)=>this.logger.debug(A,w),error:(A,w)=>this.logger.error(A,w)}}),this.gatewayLoop=new ui({getApp:()=>this.chatApp.instance,gatewayRunMs:this.config.gatewayRunMs,gatewayRestartDelayMs:this.config.gatewayRestartDelayMs,logger:this.logger}),this.slackSocketLoop=new Si({listenerRunMs:this.config.gatewayRunMs,restartDelayMs:this.config.gatewayRestartDelayMs,logger:this.logger}),this.chatApp=new ii({discord:this.config.adapters.discord,slack:this.config.adapters.slack,getUploadStore:(A)=>this.uploadCoordinator.getPlatformStore(A),buildApp:(A)=>zHx({userName:this.config.userName,discord:this.config.adapters.discord,slack:this.config.adapters.slack,gatewayLoop:this.gatewayLoop,slackSocketLoop:this.slackSocketLoop,runtimeState:A})})}async onRegister(x){if(await super.onRegister(x),this.config.adapters.discord)x.channels.registerDescriptor({type:"discord",displayName:"Discord",subjectLabel:"Discord user ID",subjectPattern:{source:"^[0-9]{17,20}$"},manualDelivery:!0}),this.discordSubscriptions=WHx(x.runtimeState);if(this.config.adapters.slack)x.channels.registerDescriptor({type:"slack",displayName:"Slack",subjectLabel:"Slack member ID",subjectPattern:{source:"^[UW][A-Z0-9]+$"},manualDelivery:!0}),this.slackSubscriptions=HHx(x.runtimeState);this.turnController.registerHandlers(this.chatApp.build(x.runtimeState))}getWebRoutes(){return this.chatApp.getWebRoutes()}createDaemon(){let x=Boolean(this.config.adapters.discord),B=this.config.adapters.slack?.mode==="socket";if(!x&&!this.config.adapters.slack)return;return{start:async()=>{if(await this.chatApp.initialize(),this.chatAppRunning=!0,x)this.gatewayLoop.start();if(B)this.slackSocketLoop.start()},stop:async()=>{await this.gatewayLoop.stop(),await this.slackSocketLoop.stop(),this.threadRegistry.clear(),this.uploadCoordinator.clear(),this.responseCoordinator.clear(),this.toolStatusMessenger.clear(),await this.chatApp.shutdown(),this.chatAppRunning=!1},healthCheck:async()=>{let A=this.chatAppRunning&&(!x||this.gatewayLoop.isRunning())&&(!B||this.slackSocketLoop.isRunning());return{status:A?"healthy":"error",message:A?"Chat SDK app running":"Chat SDK app stopped",lastCheck:new Date}}}}sendMessageToChannel({channelId:x,message:B}){let A=this.threadRegistry.get(x);if(!A)return;let w=this.toPlatformPostOutput(x,B);if(w!==void 0){A.post(w).catch((f)=>this.logger.error("Failed to send chat message",{error:f,channelId:x}));return}if(typeof B!=="string")return;for(let f of RQ(x,B))A.post(f).catch((D)=>this.logger.error("Failed to send chat message",{error:D,channelId:x}))}async sendMessageWithId({channelId:x,message:B}){let A=this.threadRegistry.get(x);if(!A)return;let w=this.toPlatformPostOutput(x,B);if(w!==void 0){let D=await A.post(w);return this.threadRegistry.trackMessage(A.id,D),D.id}if(typeof B!=="string")return;let f;for(let D of RQ(x,B))f=await A.post(D),this.threadRegistry.trackMessage(A.id,f);return f?.id}async editMessage({channelId:x,messageId:B,newMessage:A}){let w=this.threadRegistry.getMessage(x,B);if(!w)return!1;try{let f=await w.edit(this.toPlatformPostOutput(x,A)??(typeof A==="string"?A:""));if(x)this.threadRegistry.trackMessage(x,f);return!0}catch{return!1}}supportsMessageEditing(){return!0}toPlatformPostOutput(x,B){return yQ(x,B)}formatProgressOutput(x){return Li(x)}formatCompletionOutput(x){return Li(x)}async handleProgressEvent(x,B){let A=x.metadata.interfaceType,w=x,f=B;if(A&&A!==this.id){if(!d$(this.config,A))return;w={...x,metadata:{...x.metadata,interfaceType:this.id}},f=w.metadata}await super.handleProgressEvent(w,f),await this.responseCoordinator.deliverCompletedJobArtifacts(w)}async handleToolActivityEvent(x){if(x.interfaceType===this.id){await super.handleToolActivityEvent(x);return}if(!d$(this.config,x.interfaceType))return;await super.handleToolActivityEvent({...x,interfaceType:this.id})}async handleToolStatusUpdate(x){if(x.interfaceType!==this.id||!x.channelId)return;let B=sV(x.channelId)==="slack",A=B&&this.responseCoordinator.isActiveSlackConfirmation(x.conversationId);if(B&&this.compactingSlackApprovalToolStatuses.has(dV(x))||A||B&&x.state==="completed"){await this.toolStatusMessenger.dismiss(x);return}await this.toolStatusMessenger.handle(x)}async handleAgentResponseToolStatuses(x,B){let A=new Set([...(x.pendingConfirmations??[]).map((f)=>f.toolName),...(x.cards??[]).filter((f)=>f.kind==="tool-approval").map((f)=>f.toolName)]),w=B.startsWith("slack-")?[...A].map((f)=>`${B}:${f}`):[];for(let f of w)this.compactingSlackApprovalToolStatuses.add(f);try{await super.handleAgentResponseToolStatuses(x,B)}finally{for(let f of w)this.compactingSlackApprovalToolStatuses.delete(f)}}getPreferredDisplayBaseUrl(){if(this.context?.preferLocalUrls&&this.context.localSiteUrl)return this.context.localSiteUrl;return this.context?.siteUrl??this.context?.localSiteUrl}}function Cx0(x,B={}){let{DISCORD_BOT_TOKEN:A,DISCORD_PUBLIC_KEY:w,DISCORD_APPLICATION_ID:f}=x;if(!A||!w||!f)return{};return{adapters:{discord:{botToken:A,publicKey:w,applicationId:f,...B}}}}function cx0(x){let B=x.startsWith("/")?x:`/${x}`;return B==="/"?"":B.replace(/\/+$/,"")}function LHx(x,B){return`${cx0(x)}/workspaces/${encodeURIComponent(B)}`}import{join as rn8}from"path";function wO(x){return x instanceof X.ZodType?x.def.type:void 0}function yn8(x){return typeof x==="function"?x():x}function fO(x){let B=x,A=!0,w,f=!1;for(;;){if(B instanceof X.ZodOptional||B instanceof X.ZodNullable){A=!1,B=B.unwrap();continue}if(B instanceof X.ZodDefault){A=!1,f=!0,w=yn8(B.def.defaultValue),B=B.def.innerType;continue}if(B instanceof X.ZodPipe){B=B.def.out;continue}break}let D={inner:B,required:A};if(f&&w!==void 0)D.defaultValue=w;return D}function DO(x){if(!(x instanceof X.ZodEnum))return;let B=Object.values(x.def.entries);if(B.every((A)=>typeof A==="string"))return B;return}function $O(x){return x instanceof X.ZodLiteral?x.def.values[0]:void 0}function kHx(x){return x instanceof X.ZodObject?x.shape:void 0}function MHx(x){return x instanceof X.ZodArray?x.def.element:void 0}function vHx(x,B){if(x instanceof X.ZodStringFormat)return x.def.format===B;if(!(x instanceof X.ZodString))return!1;return(x.def.checks??[]).some((w)=>w instanceof X.ZodStringFormat&&w.def.format===B)}function NHx(x){return x instanceof X.ZodType?x.meta():void 0}var IHx="note",mn8=new Set(["description","excerpt","summary","tagline","story"]);function Cn8(x){if(x.endsWith("s"))return x;return ZO(x)}function rX(x){return x===IHx}function OHx(x,B){let A=x===IHx?"Note":aD(x),w=B?.label??A;return{label:w,pluralLabel:B?.pluralName??Cn8(w)}}function cn8(x){return typeof x==="object"&&x!==null}function gn8(x){let B=NHx(x)?.cmsCondition;if(!cn8(B)||typeof B.field!=="string"||!Object.hasOwn(B,"value"))return;return{field:B.field,value:B.value}}function Tn8(x){return x==="imageId"||x.endsWith("ImageId")}function iK(x,B){let{inner:A,required:w,defaultValue:f}=fO(B),D=wO(A),$=f??$O(A),Z=gn8(B),Q={name:x,label:aD(x),widget:"string",...!w&&{required:!1},...$!==void 0&&{default:$},...Z&&{condition:Z}};switch(D){case"string":{if(Tn8(x))return{...Q,widget:"image"};if(vHx(A,"datetime"))return{...Q,widget:"datetime"};if(mn8.has(x))return{...Q,widget:"text"};return{...Q,widget:"string"}}case"number":return{...Q,widget:"number"};case"boolean":return{...Q,widget:"boolean"};case"enum":{let Y=DO(A);return{...Q,widget:"select",...Y?{options:Y}:{}}}case"array":{let Y=MHx(A),W=iK("item",Y);if(W.widget==="object"&&W.fields)return{...Q,widget:"list",fields:W.fields};return{...Q,widget:"list",field:{name:x,label:aD(x),widget:W.widget}}}case"object":{let Y=Object.entries(kHx(A)??{}).map(([W,H])=>iK(W,H));return{...Q,widget:"object",fields:Y}}case"literal":return{...Q,widget:"string"};default:return{...Q,widget:"string"}}}function gx0(x){let B=x.basePath.replaceAll("&","&amp;").replaceAll('"',"&quot;").replaceAll("<","&lt;").replaceAll(">","&gt;");return`<!doctype html>
5311
5311
  <html lang="en" data-climate="paper">
5312
5312
  <head>
5313
5313
  <meta charset="utf-8" />
@@ -5365,7 +5365,7 @@ ${bA}
5365
5365
  </html>`}function d0(x,B=200){return nV(x,{status:B,headers:{"Cache-Control":"no-store"}})}function QO(x){return{interfaceType:"cms",userId:x.principal.userId,actor:x.actor,userPermissionLevel:x.permissionLevel,visibilityScope:x.visibilityScope,isAnchor:x.isAnchor}}async function u7(x,B,A,w,f,D,$){if(!x)return;await x({actorUserId:B.principal.userId,action:`cms.entity.${A}.${w}`,targetType:"entity",...D?{targetId:D}:{},metadata:{entityType:f,interfaceType:"cms",outcome:w,...$?{reason:$}:{}}})}function XO(x){return{eventContext:{actor:x.actor,interfaceType:"cms"}}}function hHx(x){return x.permissionLevel==="admin"?null:d0({error:"Admin CMS capability required"},403)}function uA(x,B,A,w){try{return x.permissions.assertEntityActionAllowed(B,A,{userPermissionLevel:w.permissionLevel}),null}catch(f){return d0({error:g(f,`CMS ${A} permission denied`)},403)}}function dE(x,B,A,w){try{return x.permissions.assertEntityActionAllowed(B,A,{userPermissionLevel:w.permissionLevel}),!0}catch{return!1}}function Tx0(x,B,A,w){let f=dE(x,B,"create",w),D=dE(x,B,"update",w),$=dE(x,B,"delete",w),Z=dE(x,B,"extract",w),Q=dE(x,B,"publish",w),Y=A>0||f||D||$||Z||Q;if(!Y)return;return{canRead:Y,canCreate:f,canUpdate:D,canDelete:$,canExtract:Z,canPublish:Q,canAssist:D}}async function YO(x,B,A){if(!x.entities.getEffectiveFrontmatterSchema(B))return;let w=await x.entityService.countEntities({entityType:B,options:{filter:{visibilityScope:A.visibilityScope}}});return Tx0(x,B,w,A)}function px0(x){let{visibility:B,...A}=x;return A}function ux0(x,B){if(!Object.hasOwn(x,"visibility"))return{success:!0,visibility:B};let A=Z2.safeParse(x.visibility);return A.success?{success:!0,visibility:A.data}:{success:!1,response:d0({error:"Invalid content visibility"},400)}}function Sx0(x,B){let{visibility:A,...w}=x;return B==="public"?w:{...w,visibility:B}}function ix0(x,B,A){if(A===void 0)return null;if(x.entities.getAdapter(B)?.hasBody===!1)return d0({error:`Entity type ${B} does not have a body`},400);return null}function lK(x,B){if(rX(x))return{frontmatter:{},body:B};try{let A=G9(B,X.record(X.string(),X.unknown()));return{frontmatter:A.metadata,body:A.content}}catch{return{frontmatter:{},body:B}}}var pn8=X.object({entityType:X.string(),id:X.string(),frontmatter:X.record(X.string(),X.unknown()),body:X.string().optional(),baseContentHash:X.string().optional()}),un8=X.object({entityType:X.string(),frontmatter:X.record(X.string(),X.unknown()),body:X.string().optional()}),Sn8=X.object({confirmed:X.literal(!0)});async function yHx(x,B,A){let w=new URL(B.url).searchParams,f=w.get("type");if(!f)return d0({error:"type query parameter is required"},400);if(!await YO(x,f,A))return d0({error:`Unknown entity type: ${f}`},404);let D=w.get("id");if(D){let Z=await x.entityService.getEntity({entityType:f,id:D,visibilityScope:A.visibilityScope});if(!Z)return d0({error:`Entity not found: ${D}`},404);let{frontmatter:Q,body:Y}=lK(f,Z.content);return d0({entity:{id:Z.id,entityType:Z.entityType,frontmatter:Q,body:Y,contentHash:Z.contentHash,created:Z.created,updated:Z.updated}})}let $=await x.entityService.listEntities({entityType:f,options:{filter:{visibilityScope:A.visibilityScope}}});return d0({entities:$.map((Z)=>({id:Z.id,entityType:Z.entityType,frontmatter:lK(f,Z.content).frontmatter,updated:Z.updated}))})}async function mHx(x,B,A,w){let f;try{f=pn8.parse(await B.json())}catch{return d0({error:"Invalid update payload"},400)}let{entityType:D,id:$}=f,Z=x.entities.getEffectiveFrontmatterSchema(D);if(!Z)return d0({error:`Unknown entity type: ${D}`},404);let Q=await x.entityService.getEntity({entityType:D,id:$,visibilityScope:A.visibilityScope});if(!Q)return d0({error:`Entity not found: ${$}`},404);let Y=ix0(x,D,f.body);if(Y)return Y;let W=rX(D);if(W&&Object.keys(f.frontmatter).length>0)return d0({error:`Entity type ${D} is raw markdown without frontmatter`},400);let H=ux0(f.frontmatter,Q.visibility);if(!H.success)return H.response;let F=W?X.object({}).safeParse({}):Z.safeParse(f.frontmatter);if(!F.success)return d0({error:"Invalid frontmatter",issues:F.error.issues},400);let K=f.body??lK(D,Q.content).body,q=W?K:O3(K,Sx0(F.data,H.visibility)),V=x.entities.getAdapter(D)?.fromMarkdown(q),b={...Q,...V,id:Q.id,entityType:Q.entityType,content:q,metadata:px0(V?.metadata??Q.metadata),visibility:H.visibility},E=RHx(D,Q.metadata.status,b.metadata.status,x.entityService)==="non-publish"?"update":"publish",_=uA(x,D,E,A);if(_)return await u7(w,A,"update","denied",D,$,"entity-action-policy"),_;if(!lx0(A.permissionLevel,b.visibility))return await u7(w,A,"update","denied",D,$,"visibility-policy"),d0({error:`Cannot set entity visibility to "${b.visibility}" at ${A.permissionLevel} permission.`},403);if(f.baseContentHash!==void 0&&f.baseContentHash!==Q.contentHash)return d0({error:"This entry changed since it was opened \u2014 likely updated by "+"another writer (an agent, or a git import via directory-sync). Reload to review before saving again.",currentContentHash:Q.contentHash},409);let L=uA(x,D,E,A);if(L)return await u7(w,A,"update","denied",D,$,"entity-action-policy"),L;let N=await x.entityService.updateEntity({entity:b,options:XO(A)});return await u7(w,A,"update","allowed",D,$),d0({entityId:N.entityId,jobId:N.jobId,skipped:N.skipped})}async function CHx(x,B,A,w){let f;try{f=un8.parse(await B.json())}catch{return d0({error:"Invalid create payload"},400)}let{entityType:D}=f,$=x.entities.getEffectiveFrontmatterSchema(D);if(!$)return d0({error:`Unknown entity type: ${D}`},404);let Z=uA(x,D,"create",A);if(Z)return await u7(w,A,"create","denied",D,void 0,"entity-action-policy"),Z;let Q=ix0(x,D,f.body);if(Q)return Q;let Y=rX(D);if(Y&&Object.keys(f.frontmatter).length>0)return d0({error:`Entity type ${D} is raw markdown without frontmatter`},400);let W=ux0(f.frontmatter,"public");if(!W.success)return W.response;let H=Y?X.object({}).safeParse({}):$.safeParse(f.frontmatter);if(!H.success)return d0({error:"Invalid frontmatter",issues:H.error.issues},400);let F=Y?f.body??"":O3(f.body??"",Sx0(H.data,W.visibility)),K=x.entities.getAdapter(D)?.fromMarkdown(F),q={...K,entityType:D,content:F,metadata:px0(K?.metadata??{}),visibility:W.visibility};if(!lx0(A.permissionLevel,q.visibility))return await u7(w,A,"create","denied",D,void 0,"visibility-policy"),d0({error:`Cannot set entity visibility to "${q.visibility}" at ${A.permissionLevel} permission.`},403);let V=uA(x,D,"create",A);if(V)return await u7(w,A,"create","denied",D,void 0,"entity-action-policy"),V;let b=await x.entityService.createEntity({entity:q,options:XO(A)});return await u7(w,A,"create","allowed",D,b.entityId),d0({entityId:b.entityId,jobId:b.jobId},201)}async function cHx(x,B,A,w){try{Sn8.parse(await B.json())}catch{return d0({error:"Explicit delete confirmation required"},400)}let f=new URL(B.url).searchParams,D=f.get("type"),$=f.get("id");if(!D||!$)return d0({error:"type and id query parameters are required"},400);if(!await x.entityService.getEntity({entityType:D,id:$,visibilityScope:A.visibilityScope}))return d0({error:`Entity not found: ${$}`},404);let Q=uA(x,D,"delete",A);if(Q)return await u7(w,A,"delete","denied",D,$,"entity-action-policy"),Q;let Y=await x.entityService.deleteEntity({entityType:D,id:$,options:XO(A)});if(Y)await u7(w,A,"delete","allowed",D,$);return d0({deleted:Y})}var in8="file",gHx=10485760;async function THx(x,B,A,w,f){let D=Number(B.headers.get("content-length"));if(Number.isFinite(D)&&D>gHx)return d0({error:"Upload too large"},400);let $;try{$=await B.formData()}catch{return d0({error:"Invalid multipart upload"},400)}let Z=$.get(in8);if(!(Z instanceof File))return d0({error:"Missing upload file"},400);if(Z.size>gHx)return d0({error:"Upload too large"},400);let Q=x.entities.getUploadSaveHandler(Z.type);if(!Q)return d0({error:`No handler accepts uploads of type ${Z.type}`},415);let Y=uA(x,Q.entityType,"create",w);if(Y)return await u7(f,w,"upload","denied",Q.entityType,void 0,"entity-action-policy"),Y;let W=x.uploads.scoped({namespace:"upload",refKind:"upload",routePath:A}),H=await W.save({filename:Z.name,mediaType:Z.type,content:Buffer.from(await Z.arrayBuffer())}),F;try{F=await Q.handler({upload:{kind:"upload",id:H.id}},{interfaceType:"cms",actor:w.actor})}catch{return await W.remove(H.id),d0({error:"Upload promotion failed"},502)}if(!F.success)return await W.remove(H.id),d0({error:F.error},502);return await u7(f,w,"upload","allowed",Q.entityType,F.data.entityId),d0({entityId:F.data.entityId,jobId:F.data.jobId},201)}var nx0={entityType:X.string(),id:X.string()},ln8=X.union([X.object({...nx0,variant:X.literal("rewrite").optional(),instruction:X.string().trim().min(1),selection:X.string().min(1).max(8000)}),X.object({...nx0,variant:X.literal("summarise"),targetField:X.string().trim().min(1)}),X.object({...nx0,variant:X.literal("tag-suggest"),targetField:X.string().trim().min(1)})]),pHx=X.object({suggestion:X.string()}),nn8=X.object({suggestions:X.array(X.string().trim().min(1)).max(12)}),dn8=X.object({entityType:X.string(),id:X.string(),selection:X.string().min(1).max(8000),instruction:X.string().trim().min(1).max(2000),agent:X.string().trim().min(1).max(253)}),an8=X.looseObject({response:X.string()}),sn8=X.object({agents:X.array(X.object({id:X.string(),label:X.string()}))});async function dx0(x,B,A,w){if(!x.entities.getEffectiveFrontmatterSchema(B))return d0({error:`Unknown entity type: ${B}`},404);let f=await x.entityService.getEntity({entityType:B,id:A,visibilityScope:w.visibilityScope});if(!f)return d0({error:`Entity not found: ${A}`},404);let D=uA(x,B,"update",w);if(D)return D;let $=lK(B,f.content);return{entity:f,...$}}function uHx(x,B){return x.body.includes(B)?null:d0({error:"Selection no longer matches the stored entity"},409)}async function SHx(x,B,A){let w;try{w=ln8.parse(await B.json())}catch{return d0({error:"Invalid assist payload or selection length"},400)}let f=await dx0(x,w.entityType,w.id,A);if(f instanceof Response)return f;let D=x.entities.getEffectiveFrontmatterSchema(w.entityType);if(!D)return d0({error:`Unknown entity type: ${w.entityType}`},404);if(w.variant==="summarise"||w.variant==="tag-suggest"){let Y=D.shape[w.targetField];if(!Y)return d0({error:`Unknown frontmatter field: ${w.targetField}`},400);let W=iK(w.targetField,Y);if(!(w.variant==="summarise"?W.widget==="string"||W.widget==="text":W.widget==="list"&&W.field?.widget==="string"))return d0({error:`Field ${w.targetField} is incompatible with ${w.variant}`},400);let F=["You are editing CMS frontmatter from an existing markdown body.",`Entity type: ${w.entityType}`,`Target field: ${w.targetField}`,`Existing frontmatter JSON: ${JSON.stringify(f.frontmatter)}`,"","Full markdown body:",f.body];if(w.variant==="summarise"){let{object:q}=await x.ai.generateObject(["Summarise the body for the target frontmatter field.","Return only the field value in the suggestion field.",...F].join(`
5366
5366
  `),pHx);return d0({variant:w.variant,targetField:w.targetField,suggestion:q.suggestion})}let{object:K}=await x.ai.generateObject(["Suggest tags for the target frontmatter field.","Return concise tag strings in the suggestions field without duplicates.",...F].join(`
5367
5367
  `),nn8);return d0({variant:w.variant,targetField:w.targetField,suggestions:[...new Set(K.suggestions)]})}let $=uHx(f,w.selection);if($)return $;let Z=["You are editing markdown for the CMS.","Rewrite only the selected text according to the instruction.","Return only replacement markdown in the suggestion field.","Do not include commentary, code fences, or unchanged surrounding body text.","",`Entity type: ${w.entityType}`,`Frontmatter JSON: ${JSON.stringify(f.frontmatter)}`,`Instruction: ${w.instruction}`,"","Selected markdown:",w.selection,"","Full body for context:",f.body].join(`
5368
- `),{object:Q}=await x.ai.generateObject(Z,pHx);return d0({suggestion:Q.suggestion})}async function iHx(x,B,A){let w=new URL(B.url).searchParams,f=w.get("type"),D=w.get("id");if(!f||!D)return d0({error:"type and id query parameters are required"},400);let $=await dx0(x,f,D,A);if($ instanceof Response)return $;let Z=await x.messaging.send({type:CH.callAgents,payload:{entityType:f,entityId:$.entity.id,actor:A.actor,interfaceType:"cms"}});if(!("success"in Z)||!Z.success)return d0({agents:[]});let Q=sn8.safeParse(Z.data);return d0(Q.success?Q.data:{agents:[]})}async function lHx(x,B,A){let w;try{w=dn8.parse(await B.json())}catch{return d0({error:"Invalid agent ask payload or selection length"},400)}let f=await dx0(x,w.entityType,w.id,A);if(f instanceof Response)return f;let D=uHx(f,w.selection);if(D)return D;let $=await x.messaging.send({type:CH.callRequest,payload:{agent:w.agent,instruction:w.instruction,selection:w.selection,entityType:w.entityType,entityId:f.entity.id,actor:A.actor,interfaceType:"cms"}});if(!("success"in $)||!$.success){let Q="error"in $&&typeof $.error==="string"?$.error:"Agent call failed",Y=Q.startsWith("No handler found");return d0({error:Y?"Agent asking is unavailable":Q},Y?503:400)}if($.data===void 0)return d0({error:"Agent asking is unavailable"},503);let Z=an8.safeParse($.data);if(!Z.success)return d0({error:"Invalid response from agent"},502);return d0({agentId:w.agent,response:Z.data.response})}var on8=rn8(import.meta.dir,"..","dist","ui","cms-app.js"),tn8=X.object({id:X.string().trim().min(1),action:X.unknown()}),en8=X.object({watchEnabled:X.boolean(),lastSync:X.string().nullable(),git:X.object({branch:X.string(),hasChanges:X.boolean(),ahead:X.number(),behind:X.number(),lastCommit:X.string().nullable(),remote:X.string().nullable()}).nullable()});function nHx(x){let{routePath:B,getContext:A,resolveAuthPrincipal:w,minimumPermissionLevel:f,getEntityDisplay:D,workspaceRegistry:$}=x,Z=cx0(B),Q=Z||"/",Y=`${Z}/assets/app.js`,W=(q)=>`${Z}/api/${q}`,H=async(q)=>{let V=await w(q);if(V?.status!=="active")return{state:"unauthenticated"};if(V.permissionLevel==="public")return{state:"forbidden"};if(f==="admin"&&V.permissionLevel!=="admin")return{state:"forbidden"};let b=oX(V.permissionLevel);if(b==="public")return{state:"forbidden"};return{state:"allowed",access:{principal:V,actor:{kind:"user",userId:V.userId,...V.canonicalId?{canonicalId:V.canonicalId}:{}},permissionLevel:V.permissionLevel,visibilityScope:b,isAnchor:V.isAnchor}}},F=async(q)=>{let V=await H(q);if(V.state==="unauthenticated")return d0({error:"Authentication required"},401);if(V.state==="forbidden")return d0({error:"CMS access forbidden"},403);return V.access},K=async(q)=>{let V=new URL(q.url),b=`${V.pathname}${V.search}`,G=await H(q);if(G.state==="unauthenticated")return new Response(null,{status:302,headers:{Location:`/login?return_to=${encodeURIComponent(b)}`,"Cache-Control":"no-store"}});if(G.state==="forbidden")return new Response("CMS access forbidden",{status:403,headers:{"Cache-Control":"no-store"}});return new Response(gx0({assetPath:Y,basePath:Q,surfaces:YB(A().webRoutes.getRoutes(),{activeId:"cms",permissionLevel:G.access.permissionLevel,self:{id:"cms",href:Q}}),sessionHref:`/logout?return_to=${encodeURIComponent(b)}`}),{headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}})};return[{path:Q,method:"GET",public:!0,handler:K},{path:`${Z}/entities`,match:"prefix",method:"GET",public:!0,handler:K},{path:`${Z}/workspaces`,match:"prefix",method:"GET",public:!0,handler:K},{path:Y,method:"GET",public:!0,handler:async()=>{let q=Bun.file(on8);if(!await q.exists())return new Response("CMS editor UI asset not built",{status:404});return new Response(q,{headers:{"Content-Type":"text/javascript; charset=utf-8","Cache-Control":"no-cache"}})}},{path:W("types"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return Bd8(A(),D(),$,V)}},{path:W("workspace"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return Ad8($,q,V)}},{path:W("workspace"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return wd8($,q,V)}},{path:W("schema"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return fd8(A(),q,V)}},{path:W("entities"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return yHx(A(),q,V)}},{path:W("entities"),method:"PUT",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return mHx(A(),q,V,x.recordAuditEvent)}},{path:W("entities"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return CHx(A(),q,V,x.recordAuditEvent)}},{path:W("entities"),method:"DELETE",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return cHx(A(),q,V,x.recordAuditEvent)}},{path:W("upload"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=GP(q);if(b)return b;return THx(A(),q,W("upload"),V,x.recordAuditEvent)}},{path:W("assist"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return SHx(A(),q,V)}},{path:W("agents"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return iHx(A(),q,V)}},{path:W("ask-agent"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return lHx(A(),q,V)}},{path:W("sync-status"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=hHx(V);if(b)return b;return xd8(A())}}]}async function xd8(x){let B={directorySync:null,git:null},A=await x.messaging.send({type:HB.statusRequest,payload:{}});if(!("success"in A)||!A.success)return d0(B);let w=en8.safeParse(A.data);if(!w.success)return d0(B);return d0({directorySync:{lastSync:w.data.lastSync,watching:w.data.watchEnabled},git:w.data.git})}async function Bd8(x,B,A,w){let f=new Map((await x.entityService.getEntityCounts(w.visibilityScope)).map(($)=>[$.entityType,$.count])),D=x.entityService.getEntityTypes().flatMap(($)=>{if(!x.entities.getEffectiveFrontmatterSchema($))return[];let Q=f.get($)??0,Y=Tx0(x,$,Q,w);if(!Y)return[];let W=x.entities.getAdapter($);return[{entityType:$,label:OHx($,B?.[$]).pluralLabel,isSingleton:W?.isSingleton===!0,hasBody:W?.hasBody!==!1,count:Q,capabilities:Y}]});return d0({types:D,workspaces:await A.listDescriptors(QO(w))})}async function Ad8(x,B,A){let w=new URL(B.url).searchParams.get("id");if(!w)return d0({error:"id query parameter is required"},400);let f=x.get(w);if(!f)return d0({error:`Unknown CMS workspace: ${w}`},404);let D=QO(A);if(!await f.accessHandler(D))return d0({error:`Unknown CMS workspace: ${w}`},404);try{return d0({workspace:{id:f.id,rendererName:f.rendererName,data:await f.dataProvider(D)}})}catch($){return d0({error:g($,"CMS workspace data provider failed")},502)}}async function wd8(x,B,A){let w;try{w=tn8.parse(await B.json())}catch{return d0({error:"Invalid workspace action payload"},400)}let f=x.get(w.id);if(!f)return d0({error:`Unknown CMS workspace: ${w.id}`},404);let D=QO(A);if(!await f.accessHandler(D))return d0({error:`Unknown CMS workspace: ${w.id}`},404);if(!f.actionHandler)return d0({error:`CMS workspace ${w.id} does not provide actions`},405);try{return d0({result:await f.actionHandler(w.action,D)})}catch($){return d0({error:g($,"CMS workspace action failed")},400)}}async function fd8(x,B,A){let w=new URL(B.url).searchParams.get("type");if(!w)return d0({error:"type query parameter is required"},400);let D=await YO(x,w,A)?x.entities.getEffectiveFrontmatterSchema(w):void 0;if(!D)return d0({error:`Unknown entity type: ${w}`},404);let $=x.entities.getAdapter(w),Z=rX(w),Q=Z?[]:Object.keys(D.shape).map((Y)=>iK(Y,D.shape[Y]));return d0({entityType:w,format:Z?"raw":"frontmatter",isSingleton:$?.isSingleton===!0,hasBody:Z||$?.hasBody!==!1,fields:Q})}var Dd8=X.object({id:X.string().trim().min(1),pluginId:X.string().trim().min(1),label:X.string().trim().min(1),rendererName:X.enum(["PublishingWorkspace","SiteWorkspace","DirectorySyncWorkspace","EmailTriageWorkspace"]),priority:X.number().int(),entityTypes:X.union([X.array(X.string().trim().min(1)),X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace entity types resolver function"})]).default([]),accessHandler:X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace access handler function"}),dataProvider:X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace data provider function"}),actionHandler:X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace action handler function"}).optional()});class ax0{workspaces=new Map;register(x){let B=Dd8.parse(x);if(this.workspaces.has(B.id))throw Error(`CMS workspace already registered: ${B.id}`);let A={id:B.id,pluginId:B.pluginId,label:B.label,rendererName:B.rendererName,priority:B.priority,entityTypes:B.entityTypes,accessHandler:B.accessHandler,dataProvider:B.dataProvider,...B.actionHandler?{actionHandler:B.actionHandler}:{}};return this.workspaces.set(A.id,A),A}get(x){return this.workspaces.get(x)}async listDescriptors(x){let B=Array.from(this.workspaces.values()).sort((w,f)=>w.priority-f.priority||w.id.localeCompare(f.id)),A=await Promise.all(B.map(async(w)=>({workspace:w,admitted:await w.accessHandler(x)})));return Promise.all(A.filter(({admitted:w})=>w).map(async({workspace:w})=>({id:w.id,pluginId:w.pluginId,label:w.label,rendererName:w.rendererName,priority:w.priority,entityTypes:typeof w.entityTypes==="function"?await w.entityTypes(x):w.entityTypes})))}}var dHx={name:"@brains/cms",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"CMS plugin for config and browser authoring routes",dependencies:{"@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@codemirror/lang-markdown":"^6.5.0","@codemirror/language":"^6.12.4","@codemirror/state":"^6.7.1","@codemirror/view":"^6.43.6","@lezer/highlight":"^1.2.3","@tanstack/react-query":"^5.0.0","@tanstack/react-router":"^1.0.0",react:"^19.2.7","react-dom":"^19.2.7",streamdown:"^2.5.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/templates":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.0.3","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json"},type:"module"};var Zd8=X.looseObject({label:X.string().optional(),pluralName:X.string().optional()}),aHx=X.record(X.string(),Zd8),Qd8=X.object({entityDisplay:aHx.optional(),routePath:X.string().default("/cms")});function Xd8(x){let B=aHx.safeParse(x);return B.success?B.data:void 0}class sx0 extends D8{workspaceRegistry=new ax0;constructor(x={}){super("cms",dHx,x,Qd8)}async onRegister(x){await super.onRegister(x),x.endpoints.register({label:"CMS",url:this.config.routePath,priority:40,visibility:"trusted"}),x.interactions.register({id:"cms",label:"CMS",description:"Edit and manage content through the browser CMS.",href:this.config.routePath,kind:"admin",priority:40,visibility:"trusted"}),x.messaging.subscribe(WO,async(B)=>{try{let A=this.workspaceRegistry.register(B.payload);return{success:!0,data:{workspaceUrl:LHx(this.config.routePath,A.id)}}}catch(A){return{success:!1,error:g(A)}}})}getWebRoutes(){return nHx({routePath:this.config.routePath,getContext:()=>this.getContext(),resolveAuthPrincipal:(x)=>X6()?.resolveSession(x)??Promise.resolve(void 0),minimumPermissionLevel:"trusted",getEntityDisplay:()=>this.config.entityDisplay??Xd8(this.getContext().entityDisplay),workspaceRegistry:this.workspaceRegistry,recordAuditEvent:async(x)=>{let B=X6();if(B)await B.recordAuditEvent(x)}})}}function rx0(x={}){return new sx0(x)}var Yd8=X.enum(["draft","queued","published","failed"]),sHx=X.object({status:Yd8.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class ox0{name="internal";async publish(x,B){return{id:"internal"}}}var Lf={interfaceType:"system",actor:{kind:"service",serviceId:"content-pipeline"},userPermissionLevel:"admin",authorization:"system"},N1={REGISTER:"publish:register",EXECUTE:"publish:execute",QUEUE:"publish:queue",DIRECT:"publish:direct",REMOVE:"publish:remove",REORDER:"publish:reorder",LIST:"publish:list",REPORT_SUCCESS:"publish:report:success",REPORT_FAILURE:"publish:report:failure",QUEUED:"publish:queued",COMPLETED:"publish:completed",FAILED:"publish:failed",LIST_RESPONSE:"publish:list:response"},a$={REGISTER:"generate:register",REPORT_SUCCESS:"generate:report:success",REPORT_FAILURE:"generate:report:failure",EXECUTE:"generate:execute",COMPLETED:"generate:completed",FAILED:"generate:failed",SKIPPED:"generate:skipped"},rHx={REGISTER:"publish-assets:register"};var Wd8=X.enum(["provider"]),oHx=X.object({executionMode:Wd8.optional(),publishResultIdField:X.string().min(1).optional(),publishTimestampField:X.string().min(1).optional(),enabled:X.boolean().optional()}).strict();var Hd8=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),tHx=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),Hd8).optional()});class aE{queues=new Map;static createFresh(){return new aE}constructor(){}async add(x,B,A=Lf){let w=this.getOrCreateQueue(x),f=w.find((Z)=>Z.entityId===B);if(f)return{position:f.position};let D=w.length+1,$={entityId:B,entityType:x,position:D,queuedAt:new Date().toISOString(),authContext:{...A}};return w.push($),{position:D}}async remove(x,B){let A=this.queues.get(x);if(!A)return;let w=A.findIndex((f)=>f.entityId===B);if(w===-1)return;A.splice(w,1),this.recalculatePositions(A)}async reorder(x,B,A){let w=this.queues.get(x);if(!w)return;let f=w.findIndex((Z)=>Z.entityId===B);if(f===-1)return;let[D]=w.splice(f,1);if(!D)return;let $=Math.max(0,Math.min(A-1,w.length));w.splice($,0,D),this.recalculatePositions(w)}async list(x){let B=this.queues.get(x);if(!B)return[];return[...B]}async getNext(x){let B=this.queues.get(x);if(!B||B.length===0)return null;return B[0]??null}async getNextAcrossTypes(){let x=null;for(let B of this.queues.values()){let A=B[0];if(!A)continue;if(!x||A.queuedAt<x.queuedAt)x=A}return x}async popNext(x){let B=this.queues.get(x);if(!B||B.length===0)return null;let A=B.shift()??null;if(A)this.recalculatePositions(B);return A}replace(x){this.queues.clear();let B=[...x].sort((A,w)=>A.entityType.localeCompare(w.entityType)||A.position-w.position);for(let A of B)this.getOrCreateQueue(A.entityType).push({...A,authContext:{...A.authContext}});for(let A of this.queues.values())this.recalculatePositions(A)}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let x=[];for(let[B,A]of this.queues.entries())if(A.length>0)x.push(B);return x}getOrCreateQueue(x){let B=this.queues.get(x);if(!B)B=[],this.queues.set(x,B);return B}recalculatePositions(x){x.forEach((B,A)=>{B.position=A+1})}}class sE{providers=new Map;executionModes=new Map;publishResultIdFields=new Map;publishTimestampFields=new Map;defaultProvider=new ox0;static createFresh(){return new sE}constructor(){}register(x,B,A){let w=this.providers.get(x);if(w&&w.name!=="internal"&&B.name==="internal")return;if(this.providers.set(x,B),this.executionModes.set(x,A?.executionMode??"provider"),A?.publishResultIdField)this.publishResultIdFields.set(x,A.publishResultIdField);else this.publishResultIdFields.delete(x);if(A?.publishTimestampField)this.publishTimestampFields.set(x,A.publishTimestampField);else this.publishTimestampFields.delete(x)}get(x){return this.providers.get(x)??this.defaultProvider}getExecutionMode(x){return this.executionModes.get(x)??"provider"}getPublishResultIdField(x){return this.publishResultIdFields.get(x)}getPublishTimestampField(x){return this.publishTimestampFields.get(x)}has(x){return this.providers.has(x)}unregister(x){this.providers.delete(x),this.executionModes.delete(x),this.publishResultIdFields.delete(x),this.publishTimestampFields.delete(x)}getRegisteredTypes(){return Array.from(this.providers.keys())}}async function eHx(x,B){if(!B.publishExecutor){B.onFailed?.({entityType:x.entityType,entityId:x.entityId,error:"Publish executor not configured",retryCount:0,willRetry:!1});return}await Fd8(x,B)}async function Fd8(x,B){if(!B.publishExecutor)return;try{let A=await B.publishExecutor.publish({entityType:x.entityType,id:x.entityId});if("error"in A){let w={entityType:x.entityType,entityId:x.entityId,error:A.error,retryCount:0,willRetry:!1};if(B.messageBus)await B.messageBus.send({type:N1.FAILED,payload:w,sender:"publish-service",broadcast:!0});B.onFailed?.(w);return}tx0(x.entityType,x.entityId,A.result,B)}catch(A){let w=g(A);B.retryTracker.recordFailure(x.entityId,w);let f=B.retryTracker.getRetryInfo(x.entityId);B.onFailed?.({entityType:x.entityType,entityId:x.entityId,error:w,retryCount:f?.retryCount??1,willRetry:!1})}}function tx0(x,B,A,w){if(w.retryTracker.clearRetries(B),w.messageBus)w.messageBus.send({type:N1.COMPLETED,payload:{entityType:x,entityId:B,result:A},sender:"publish-service",broadcast:!0});w.onPublish?.({entityType:x,entityId:B,result:A})}function xFx(x,B,A,w){w.retryTracker.recordFailure(B,A);let f=w.retryTracker.getRetryInfo(B),D={entityType:x,entityId:B,error:A,retryCount:f?.retryCount??1,willRetry:!1};if(w.messageBus)w.messageBus.send({type:N1.FAILED,payload:D,sender:"publish-service",broadcast:!0});w.onFailed?.(D)}async function BFx(x,B){let A=B.generationConditions[x];if(A&&B.onCheckGenerationConditions){let f=await B.onCheckGenerationConditions(x,A);if(!f.shouldGenerate){if(B.messageBus)B.messageBus.send({type:a$.SKIPPED,payload:{entityType:x,reason:f.reason??"Conditions not met"},sender:"content-pipeline"});return}}let w={entityType:x};if(B.messageBus)await B.messageBus.send({type:a$.EXECUTE,payload:w,sender:"content-pipeline"});B.onGenerate?.(w)}function AFx(x,B,A){if(A)A.send({type:a$.COMPLETED,payload:{entityType:x,entityId:B},sender:"content-pipeline"})}function wFx(x,B,A){if(A)A.send({type:a$.FAILED,payload:{entityType:x,error:B},sender:"content-pipeline"})}var Kd8=1000;class ex0{deps;publishJobs=new Map;immediateIntervalJob=null;constructor(x){this.deps=x}start(){for(let[x,B]of Object.entries(this.entitySchedules)){let A=this.deps.config.backend.scheduleCron(B,()=>this.processEntityType(x));this.publishJobs.set(x,A)}this.immediateIntervalJob=this.deps.config.backend.scheduleInterval(Kd8,()=>this.processUnscheduledTypes())}async stop(){let x=Array.from(this.publishJobs.values());if(this.publishJobs.clear(),this.immediateIntervalJob)x.push(this.immediateIntervalJob),this.immediateIntervalJob=null;await Promise.all(x.map((B)=>B.stop()))}async processEntityType(x){if(!this.deps.isRunning())return;try{let B=await this.deps.config.queueManager.getNext(x);if(B)await this.processEntry(B)}catch(B){this.deps.config.logger.error(`Scheduler error for ${x}:`,B)}}async processUnscheduledTypes(){if(!this.deps.isRunning())return;try{let x=await this.deps.config.queueManager.getQueuedEntityTypes();for(let B of x)if(!this.entitySchedules[B]){let A=await this.deps.config.queueManager.getNext(B);if(A){await this.processEntry(A);break}}}catch(x){this.deps.config.logger.error("Scheduler error for unscheduled types:",x)}}async processEntry(x){await this.deps.config.queueManager.remove(x.entityType,x.entityId);let B=this.deps.getPublishDeps();await eHx(x,B)}get entitySchedules(){return this.deps.config.entitySchedules}}class x80{deps;generationJobs=new Map;constructor(x){this.deps=x}start(){for(let[x,B]of Object.entries(this.generationSchedules)){let A=this.deps.config.backend.scheduleCron(B,()=>this.handleTriggerGeneration(x));this.generationJobs.set(x,A)}}async stop(){let x=Array.from(this.generationJobs.values());this.generationJobs.clear(),await Promise.all(x.map((B)=>B.stop()))}async handleTriggerGeneration(x){if(!this.deps.isRunning())return;try{await BFx(x,this.deps.getGenerationDeps())}catch(B){this.deps.config.logger.error(`Generation trigger error for ${x}:`,B)}}get generationSchedules(){return this.deps.config.generationSchedules}}class rE{config;publishRunner;generationRunner;running=!1;stopPromise=null;static createFresh(x){return new rE(x)}constructor(x){this.config={...x,entitySchedules:x.entitySchedules??{},generationSchedules:x.generationSchedules??{},generationConditions:x.generationConditions??{}},this.validateCronExpressions(),this.publishRunner=new ex0({config:this.config,getPublishDeps:()=>this.publishDeps,isRunning:()=>this.running}),this.generationRunner=new x80({config:this.config,getGenerationDeps:()=>this.generationDeps,isRunning:()=>this.running})}async start(){if(this.running)return;if(this.stopPromise)await this.stopPromise,this.stopPromise=null;this.running=!0,this.publishRunner.start(),this.generationRunner.start()}stop(){if(this.stopPromise)return this.stopPromise;return this.running=!1,this.stopPromise=Promise.all([this.publishRunner.stop(),this.generationRunner.stop()]).then(()=>{return}),this.stopPromise}isRunning(){return this.running}completePublish(x,B,A){tx0(x,B,A,this.publishDeps)}failPublish(x,B,A){xFx(x,B,A,this.publishDeps)}completeGeneration(x,B){AFx(x,B,this.config.messageBus)}failGeneration(x,B){wFx(x,B,this.config.messageBus)}get entitySchedules(){return this.config.entitySchedules}get generationSchedules(){return this.config.generationSchedules}get publishDeps(){return{retryTracker:this.config.retryTracker,messageBus:this.config.messageBus,publishExecutor:this.config.publishExecutor,onPublish:this.config.onPublish,onFailed:this.config.onFailed}}get generationDeps(){return{logger:this.config.logger,messageBus:this.config.messageBus,generationConditions:this.config.generationConditions,onCheckGenerationConditions:this.config.onCheckGenerationConditions,onGenerate:this.config.onGenerate}}validateCronExpressions(){for(let[x,B]of Object.entries(this.entitySchedules))this.validateCronExpression(x,B,"publish");for(let[x,B]of Object.entries(this.generationSchedules))this.validateCronExpression(x,B,"generation")}validateCronExpression(x,B,A){try{this.config.backend.validateCron(B)}catch(w){throw Error(`Invalid ${A} cron expression for ${x}: "${B}" - ${g(w)}`,{cause:w})}}}class oE{retries=new Map;static createFresh(){return new oE}constructor(){}recordFailure(x,B){let w=(this.retries.get(x)?.retryCount??0)+1;this.retries.set(x,{entityId:x,retryCount:w,lastError:B})}clearRetries(x){this.retries.delete(x)}getRetryInfo(x){let B=this.retries.get(x);if(!B)return null;return{entityId:B.entityId,retryCount:B.retryCount,lastError:B.lastError}}}var fFx=X.union([X.string().min(1),X.object({location:X.enum(["metadata","frontmatter"]),field:X.string().min(1)})]),FO=X.object({entityType:X.string().min(1),attachmentType:X.string().min(1),mediaEntityType:X.enum(["image","document"]),targetEntityField:fFx.optional(),requiredWhen:X.object({status:X.string().min(1).optional(),visibility:X.string().min(1).optional()}).optional(),autoGenerate:X.boolean().optional(),requiredForPublish:X.boolean().optional(),jobType:X.string().min(1).optional()});function B80(x){return`${x.entityType}:${x.attachmentType}`}class tE{definitions=new Map;static createFresh(){return new tE}constructor(){}register(x){let B=FO.parse(x),A=B80(B);return this.definitions.set(A,B),()=>this.unregister(B.entityType,B.attachmentType)}get(x,B){return this.definitions.get(B80({entityType:x,attachmentType:B}))}list(x){let B=Array.from(this.definitions.values());return x?B.filter((A)=>A.entityType===x):B}has(x,B){return this.get(x,B)!==void 0}unregister(x,B){this.definitions.delete(B80({entityType:x,attachmentType:B}))}clear(){this.definitions.clear()}}class KO{deps;constructor(x){this.deps=x}async ensureForEntity(x,B={}){let A=this.deps.registry.list(x.entityType).filter((f)=>f.autoGenerate===!0).filter((f)=>!B.attachmentType||f.attachmentType===B.attachmentType),w={checked:A.length,enqueued:0,skipped:0};for(let f of A)if(await this.ensureDefinition(x,f))w.enqueued+=1;else w.skipped+=1;return w}async ensureDefinition(x,B){if(!this.matchesPolicy(x,B))return!1;if(this.hasTargetField(x,B.targetEntityField))return!1;if(!this.deps.context.attachments.hasProvider(x.entityType,B.attachmentType))return!1;let A=this.resolveJobType(B);if(!A)return!1;let w=this.getPredictedMediaId(x,B),f=this.getDeduplicationKey(x,B);return await this.deps.context.jobs.enqueue({type:A,data:{sourceEntityType:x.entityType,sourceEntityId:x.id,attachmentType:B.attachmentType,imageId:w,dedupKey:f,targetEntityType:x.entityType,targetEntityId:x.id,...this.getTargetImageFieldData(B.targetEntityField)},options:{source:"content-pipeline",metadata:{operationType:"content_operations"},deduplication:"skip",deduplicationKey:f}}),this.deps.context.logger.debug("Queued publish asset generation",{entityType:x.entityType,entityId:x.id,attachmentType:B.attachmentType,jobType:A}),!0}matchesPolicy(x,B){let{requiredWhen:A}=B;if(!A)return!0;if(A.status&&x.metadata.status!==A.status)return!1;if(A.visibility&&x.visibility!==A.visibility)return!1;return!0}hasTargetField(x,B){if(!B)return!1;if(typeof B==="string")return A80(x.metadata[B]);if(B.location==="metadata")return A80(x.metadata[B.field]);let{frontmatter:A}=I1(x.content);return A80(A[B.field])}resolveJobType(x){if(x.jobType)return x.jobType;if(x.mediaEntityType==="image")return"image:image-render-source";return}getPredictedMediaId(x,B){let A=B.attachmentType==="og-image"?"og":B.attachmentType;return Gx(`${A}-${x.entityType}-${x.id}`)}getDeduplicationKey(x,B){return`publish-asset:${B.attachmentType}:${x.entityType}:${x.id}`}getTargetImageFieldData(x){let B=typeof x==="string"?x:x?.field;if(B==="coverImageId"||B==="ogImageId")return{targetImageField:B};return{}}}function A80(x){return typeof x==="string"?x.length>0:x!==void 0}var qd8=X.object({id:X.string().min(1)});async function $Fx(x,B){let{bodyContent:A,coverImageId:w,documents:f,sourceEntityType:D,sourceEntityId:$}=zd8(B.content),Z=w?await Ud8(x,w):void 0,Q;if(f&&f.length>0){let W=await Gd8(x,f);if(W.length>0)Q=W}Q??=await Vd8(x,D,$);let Y={bodyContent:A};if(Z)Y.imageData=Z;if(Q&&Q.length>0)Y.documentData=Q;return Y}function zd8(x){try{let B=G9(x,X.record(X.string(),X.unknown())),A=B.metadata.coverImageId,w=typeof A==="string"?A:void 0,f=bd8(B.metadata.documents),D=DFx(B.metadata.sourceEntityType),$=DFx(B.metadata.sourceEntityId);return{bodyContent:B.content,...w&&{coverImageId:w},...f.length>0&&{documents:f},...D&&{sourceEntityType:D},...$&&{sourceEntityId:$}}}catch{return{bodyContent:x}}}function bd8(x){if(!Array.isArray(x))return[];return x.flatMap((B)=>{let A=qd8.safeParse(B);return A.success?[A.data]:[]})}function DFx(x){return typeof x==="string"&&x.length>0?x:void 0}async function Vd8(x,B,A){if(!B||!A)return;let w=await x.attachments.resolve({sourceEntityType:B,sourceEntityId:A,attachmentType:"carousel"});return w?[w]:void 0}async function Ud8(x,B){let A=await x.entityService.getEntity({entityType:"image",id:B});if(!A?.content)return;let w=ZFx(A.content);if(!w?.mimeType.startsWith("image/"))return;return{data:w.data,mimeType:w.mimeType}}async function Gd8(x,B){return(await Promise.all(B.map((w)=>Ed8(x,w)))).filter((w)=>w!==void 0)}async function Ed8(x,B){let A=await x.entityService.getEntity({entityType:"document",id:B.id});if(!A?.content)return;let w=ZFx(A.content);if(w?.mimeType!=="application/pdf")return;return{type:"document",data:w.data,mimeType:"application/pdf",filename:jd8(A,B.id)}}function ZFx(x){let B=x.match(/^data:([^;]+);base64,(.+)$/);if(!B?.[1]||!B[2])return;return{mimeType:B[1],data:Buffer.from(B[2],"base64")}}function jd8(x,B){let A=x.metadata.filename;return typeof A==="string"&&A.length>0?A:`${B}.pdf`}var _d8=/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/;async function w80(x,B,A,w={}){let f=w.publishTimestampField??"publishedAt",D=B.metadata[f],$=w.publishedAt??(typeof D==="string"?D:void 0)??new Date().toISOString(),Z={...B.metadata,status:"published",[f]:$,platformId:A.id,...Pd8(A.id,w.publishResultIdField)},Q={...B,content:QFx(B.content,$,A.id,w.publishResultIdField,f),metadata:Z};return await x.entityService.updateEntity({entity:Q}),Q}function QFx(x,B,A,w,f="publishedAt"){if(!_d8.test(x))return x;let D=h3(h3(x,"status","published"),f,B);if(!A||!w)return D;return h3(D,w,A)}function Pd8(x,B){if(!B||B==="platformId")return{};return{[B]:x}}class tX{deps;constructor(x){this.deps=x}async resolveCandidate(x){let{entityType:B,id:A,slug:w}=x;if(!A&&!w)return{error:"Either 'id' or 'slug' must be provided"};let f=await this.findPublishableEntity(B,A,w);if(!f)return{error:`Entity not found: ${B}:${A??w}`};if(f.visibility!=="public")return{error:`Cannot publish ${B}:${f.id} to a public provider because visibility is ${f.visibility}`};if(f.metadata.status==="published")return{error:"Entity is already published"};if(!this.deps.providerRegistry.has(B))return{error:`No publish provider registered for ${B}. Check that the required credentials are configured.`};return{entity:f}}async publish(x){let B=await this.resolveCandidate(x);if("error"in B)return B;let{entity:A}=B,{entityType:w}=x,f=this.deps.providerRegistry.get(w),{bodyContent:D,imageData:$,documentData:Z}=await $Fx(this.deps.context,A),Q=await f.publish(D,A.metadata,$,Z),Y=this.deps.providerRegistry.getPublishResultIdField(w),W=this.deps.providerRegistry.getPublishTimestampField(w),H=await w80(this.deps.context,A,Q,{...Y?{publishResultIdField:Y}:{},...W?{publishTimestampField:W}:{}});return await this.runPublishAssetPreflight(H),{entity:H,result:Q}}async runPublishAssetPreflight(x){if(!this.deps.publishAssetPreflight)return;try{await this.deps.publishAssetPreflight.ensureForEntity(x)}catch(B){this.deps.context.logger.warn("Publish asset preflight failed",{entityType:x.entityType,entityId:x.id,error:g(B)})}}async findPublishableEntity(x,B,A){if(B)return this.deps.context.entityService.getEntity({entityType:x,id:B});if(!A)return null;return(await this.deps.context.entityService.listEntities({entityType:x,options:{filter:{metadata:{slug:A}},limit:1}}))[0]??null}}var eI6=X.object({action:X.enum(["list","add","remove","reorder"]).describe("Queue action to perform"),entityType:X.string().optional().describe("Entity type (required for add/remove/reorder, optional for list)"),entityId:X.string().optional().describe("Entity ID (required for add/remove/reorder)"),position:X.number().optional().describe("New position for reorder action (1-based)")}),f80=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),Jd8=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array(f80).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),Ld8=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),qO=X.union([Jd8,Ld8]);async function zO(x,B,A,w,f){let{action:D,entityType:$,entityId:Z,position:Q}=w;switch(D){case"list":return kd8(B,$);case"add":return vd8(x,A,$,Z,f);case"remove":return Nd8(x,A,$,Z,f);case"reorder":return Id8(x,A,$,Z,Q,f)}}async function kd8(x,B){let A=[];if(B)A=await x.list(B);else{let f=x.getRegisteredTypes();for(let D of f){let $=await x.list(D);A.push(...$)}A.sort((D,$)=>new Date(D.queuedAt).getTime()-new Date($.queuedAt).getTime())}if(A.length===0)return{success:!0,data:{queue:Md8()},message:"No items in queue"};return{success:!0,data:{queue:A.map((f,D)=>({position:D+1,entityType:f.entityType,entityId:f.entityId,queuedAt:f.queuedAt}))},message:`${A.length} items in queue`}}function Md8(){return[]}async function vd8(x,B,A,w,f){let D=D80("add",A,w);if(!D.success)return D.error;x.permissions.assertEntityActionAllowed(D.entityType,"publish",f??{});let $=await B.add(D.entityType,D.entityId,{...f,authorization:"user"});return{success:!0,data:{entityType:D.entityType,entityId:D.entityId,position:$.position},message:`Added to queue at position ${$.position}`}}async function Nd8(x,B,A,w,f){let D=D80("remove",A,w);if(!D.success)return D.error;return x.permissions.assertEntityActionAllowed(D.entityType,"update",f??{}),await B.remove(D.entityType,D.entityId),{success:!0,data:{entityType:D.entityType,entityId:D.entityId},message:"Removed from queue"}}async function Id8(x,B,A,w,f,D){let $=D80("reorder",A,w);if(!$.success)return $.error;let Z=Od8(f);if(!Z.success)return Z.error;return x.permissions.assertEntityActionAllowed($.entityType,"update",D??{}),await B.reorder($.entityType,$.entityId,Z.position),{success:!0,data:{entityType:$.entityType,entityId:$.entityId,position:Z.position},message:`Moved to position ${Z.position}`}}function D80(x,B,A){if(!B)return{success:!1,error:{success:!1,error:`entityType is required for ${x} action`}};if(!A)return{success:!1,error:{success:!1,error:`entityId is required for ${x} action`}};return{success:!0,entityType:B,entityId:A}}function Od8(x){if(x===void 0)return{success:!1,error:{success:!1,error:"position is required for reorder action"}};if(x<1)return{success:!1,error:{success:!1,error:"position must be a positive number"}};return{success:!0,position:x}}import{createHash as hd8}from"crypto";var DO6=X.object({entityType:X.string().describe("Entity type to publish (e.g., social-post, post, deck)"),id:X.string().optional().describe("Entity ID to publish"),slug:X.string().optional().describe("Entity slug to publish"),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()}),Rd8=X.object({entityType:X.string(),id:X.string().optional(),slug:X.string().optional(),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()}),yd8=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({entityType:X.string().optional(),entityId:X.string().optional(),platformId:X.string().optional(),url:X.string().optional()}).optional()}),md8=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),Cd8=X.object({success:X.literal(!1).optional(),error:X.string().optional(),needsConfirmation:X.literal(!0),toolName:X.string(),summary:X.string(),preview:X.string().optional(),args:X.custom()}),bO=X.union([yd8,md8,Cd8]),cd8=900000;async function nK(x){let B=Rd8.safeParse(x.rawInput);if(!B.success)return{success:!1,error:`Invalid input: ${B.error.issues.map((Q)=>`${Q.path.join(".")}: ${Q.message}`).join(", ")}`};let A=B.data,{entityType:w,id:f,slug:D}=A;try{x.context.permissions.assertEntityActionAllowed(w,"publish",x.toolContext)}catch(Q){return{success:!1,error:g(Q)}}let $=await x.executor.resolveCandidate({entityType:w,id:f,slug:D});if("error"in $)return{success:!1,error:$.error};let{entity:Z}=$;if(A.confirmed){let Q=Td8(x.toolName,A,Z);if(Q!==null)return Q;let Y;try{Y=await x.executor.publish({entityType:w,id:Z.id})}catch(F){return{success:!1,error:g(F)}}if("error"in Y)return{success:!1,error:Y.error};let{entity:W,result:H}=Y;return{success:!0,data:{entityType:w,entityId:W.id,platformId:H.id,url:H.url},message:`Published ${w}:${W.id}`}}return gd8(x.toolName,A,Z)}function gd8(x,B,A){let w=new Date(Date.now()+cd8).toISOString(),f=XFx(x,A,w),D=pd8(A);return{needsConfirmation:!0,toolName:x,summary:`Publish "${D}"?`,preview:`This will publish ${A.entityType}:${A.id} to its registered public publish provider.`,args:{...B,id:A.id,slug:void 0,confirmed:!0,confirmationToken:f,contentHash:A.contentHash,expiresAt:w}}}function Td8(x,B,A){let{confirmationToken:w,contentHash:f,expiresAt:D}=B;if(!w||!D)return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};let $=Date.parse(D);if(Number.isNaN($))return{success:!1,error:"Invalid publish confirmation expiry. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};if($<=Date.now())return{success:!1,error:"Publish confirmation expired. Request confirmation again before publishing.",code:"EXPIRED_CONFIRMATION_TOKEN"};if(f&&f!==A.contentHash)return{success:!1,error:`Cannot publish ${A.entityType}:${A.id} because it changed after confirmation. Review it and try again.`};if(w!==XFx(x,A,D))return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};return null}function XFx(x,B,A){return hd8("sha256").update(x).update("\x00").update(B.entityType).update("\x00").update(B.id).update("\x00").update(B.contentHash).update("\x00").update(A).digest("hex")}function pd8(x){let B=x.metadata.title;if(typeof B==="string"&&B.length>0)return B;let A=x.metadata.subject;if(typeof A==="string"&&A.length>0)return A;let w=x.metadata.slug;if(typeof w==="string"&&w.length>0)return w;return x.id}var $80=X.object({action:X.enum(["queue-list","queue-add","queue-remove","queue-reorder","publish"]).describe("Publishing action to perform"),entityType:X.string().optional().describe("Entity type for queue operations or direct publish, such as social-post, post, newsletter, or deck"),entityId:X.string().optional().describe("Entity ID for queue add/remove/reorder operations"),position:X.number().optional().describe("New 1-based position for queue-reorder"),id:X.string().optional().describe("Entity ID to publish"),slug:X.string().optional().describe("Entity slug to publish"),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()}),ud8=X.discriminatedUnion("action",[X.object({action:X.literal("queue-list"),entityType:X.string().optional()}),X.object({action:X.literal("queue-add"),entityType:X.string().min(1),entityId:X.string().min(1)}),X.object({action:X.literal("queue-remove"),entityType:X.string().min(1),entityId:X.string().min(1)}),X.object({action:X.literal("queue-reorder"),entityType:X.string().min(1),entityId:X.string().min(1),position:X.number().int().positive()}),X.object({action:X.literal("publish"),entityType:X.string().min(1),id:X.string().optional(),slug:X.string().optional(),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()})]),Z80=X.union([qO,bO]);function UO(x,B){let A=B.publicationQueueService??B.queueManager,w=B.publishExecutor??new tX({context:x,providerRegistry:B.providerRegistry});return{name:"publishing_manage",description:"Manage publishing with an action discriminator. Use action=queue-list to inspect the publish queue; action=queue-add to queue an entity for publication; action=queue-remove to remove a queued entity; action=queue-reorder to change queue order; action=publish to publish one entity directly. Direct publish requests confirmation inside this tool; call action=publish without confirmed first, then retry with the returned confirmation args.",inputSchema:$80.shape,outputSchema:Z80,visibility:"admin",sideEffects:"external",handler:async(f,D)=>{let $=ud8.safeParse(f);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.issues.map((Z)=>`${Z.path.join(".")}: ${Z.message}`).join(", ")}`};return Sd8({context:x,queueManager:B.queueManager,queueMutations:A,publishExecutor:w,input:$.data,toolContext:D})}}}async function Sd8(x){switch(x.input.action){case"queue-list":return VO(x,{action:"list",entityType:x.input.entityType});case"queue-add":return VO(x,{action:"add",entityType:x.input.entityType,entityId:x.input.entityId});case"queue-remove":return VO(x,{action:"remove",entityType:x.input.entityType,entityId:x.input.entityId});case"queue-reorder":return VO(x,{action:"reorder",entityType:x.input.entityType,entityId:x.input.entityId,position:x.input.position});case"publish":return ld8(await nK({context:x.context,executor:x.publishExecutor,toolName:"publishing_manage",rawInput:id8(x.input),toolContext:x.toolContext}))}}function VO(x,B){return zO(x.context,x.queueManager,x.queueMutations,B,x.toolContext)}function id8(x){let B={entityType:x.entityType};if(x.id!==void 0)B.id=x.id;if(x.slug!==void 0)B.slug=x.slug;if(x.confirmed!==void 0)B.confirmed=x.confirmed;if(x.confirmationToken!==void 0)B.confirmationToken=x.confirmationToken;if(x.contentHash!==void 0)B.contentHash=x.contentHash;if(x.expiresAt!==void 0)B.expiresAt=x.expiresAt;return B}function ld8(x){if(!("needsConfirmation"in x))return x;return{...x,toolName:"publishing_manage",args:{action:"publish",...x.args}}}var YFx=X.object({entityType:X.string().min(1).describe("Entity type to reconcile"),status:X.string().min(1).optional().describe("Optional metadata status filter, e.g. published"),assetType:X.string().min(1).optional().describe("Optional attachment type filter, e.g. og-image")}),WFx=X.object({success:X.literal(!0),data:X.object({entityType:X.string(),assetType:X.string().optional(),checkedEntities:X.number(),checkedAssets:X.number(),enqueued:X.number(),skipped:X.number()}),message:X.string().optional()});var dd8="content-pipeline.queue.v1",Q80=1024,ad8=/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/,sd8=X.object({interfaceType:X.string().optional(),actor:SA.optional(),userPermissionLevel:X.enum(["public","trusted","admin"]).optional(),authorization:X.enum(["user","system"]).optional()}),rd8=X.object({entityType:X.string(),entityId:X.string(),rank:X.number().int().positive(),queuedAt:X.string().datetime(),contentHashAtEnqueue:X.string(),authContext:sd8,revision:X.number().int().positive()});class X80{context;queueManager;store;mutationTail=Promise.resolve();constructor(x,B){this.context=x,this.queueManager=B,this.store=x.runtimeState.scoped({namespace:dd8,schema:rd8})}async add(x,B,A=Lf){return this.enqueue(x,B,A)}async enqueue(x,B,A=Lf){return this.runExclusive(async()=>{let w=await this.requireEntity(x,B);await this.persistStatus(w,"queued");let f=await this.queueManager.add(x,B,A);if(!await this.store.get(NB(x,B))){let $=(await this.queueManager.list(x)).find((Q)=>Q.entityId===B),Z=await this.requireEntity(x,B);await this.store.set(NB(x,B),{entityType:x,entityId:B,rank:f.position*Q80,queuedAt:$?.queuedAt??new Date().toISOString(),contentHashAtEnqueue:Z.contentHash,authContext:{...A},revision:1})}return f})}async remove(x,B){await this.runExclusive(async()=>{let A=await this.requireEntity(x,B);if(A.metadata.status==="queued")await this.persistStatus(A,"draft");await this.queueManager.remove(x,B),await this.store.delete(NB(x,B)),await this.persistCurrentOrder(x)})}async reorder(x,B,A){await this.runExclusive(async()=>{await this.requireEntity(x,B),await this.queueManager.reorder(x,B,A),await this.persistCurrentOrder(x)})}async complete(x,B){await this.runExclusive(async()=>{await this.queueManager.remove(x,B),await this.store.delete(NB(x,B)),await this.persistCurrentOrder(x)})}async fail(x,B,A){await this.runExclusive(async()=>{let w=await this.context.entityService.getEntity({entityType:x,id:B});if(w)await this.persistStatus(w,"failed",A);await this.queueManager.remove(x,B),await this.store.delete(NB(x,B)),await this.persistCurrentOrder(x)})}async reconcile(x){await this.runExclusive(async()=>{let B=new Map;for(let Q of x){let Y=await this.context.entityService.listEntities({entityType:Q,options:{filter:{metadata:{status:"queued"}}}});for(let W of Y)B.set(NB(Q,W.id),W)}let A=await this.listStored();for(let Q of A)if(!B.has(NB(Q.entityType,Q.entityId)))await this.store.delete(NB(Q.entityType,Q.entityId));let w=(await this.listStored()).filter((Q)=>B.has(NB(Q.entityType,Q.entityId))),f=new Map;for(let Q of w)f.set(Q.entityType,Math.max(f.get(Q.entityType)??0,Q.rank));for(let[Q,Y]of B){if(w.some((H)=>NB(H.entityType,H.entityId)===Q))continue;let W=(f.get(Y.entityType)??0)+Q80;f.set(Y.entityType,W),await this.store.set(Q,{entityType:Y.entityType,entityId:Y.id,rank:W,queuedAt:typeof Y.updated==="string"?Y.updated:new Date().toISOString(),contentHashAtEnqueue:Y.contentHash,authContext:{...Lf},revision:1})}let D=await this.listStored(),$=new Map,Z=D.map((Q)=>{let Y=($.get(Q.entityType)??0)+1;return $.set(Q.entityType,Y),{entityType:Q.entityType,entityId:Q.entityId,position:Y,queuedAt:Q.queuedAt,authContext:{...Q.authContext}}});this.queueManager.replace(Z)})}async listStored(x){return(await this.store.list()).map((B)=>B.value).filter((B)=>!x||B.entityType===x).sort((B,A)=>B.entityType.localeCompare(A.entityType)||B.rank-A.rank||B.queuedAt.localeCompare(A.queuedAt)||B.entityId.localeCompare(A.entityId))}async deleteStored(x,B){return this.store.delete(NB(x,B))}async persistCurrentOrder(x){let B=new Map((await this.listStored(x)).map((A)=>[A.entityId,A]));for(let A of await this.queueManager.list(x)){let w=B.get(A.entityId);if(!w)continue;let f=A.position*Q80;if(w.rank===f)continue;await this.store.set(NB(x,A.entityId),{...w,rank:f,revision:w.revision+1})}}async persistStatus(x,B,A){let w={...x.metadata,status:B};if(A)w.error=A;else delete w.error;let f=ad8.test(x.content)?h3(x.content,"status",B):x.content;await this.context.entityService.updateEntity({entity:{...x,metadata:w,content:f}})}async requireEntity(x,B){let A=await this.context.entityService.getEntity({entityType:x,id:B});if(!A)throw Error(`Entity not found: ${x}:${B}`);return A}runExclusive(x){let B=this.mutationTail.then(x);return this.mutationTail=B.then(()=>{return},()=>{return}),B}}function NB(x,B){return`${encodeURIComponent(x)}/${encodeURIComponent(B)}`}function HFx(x,B){od8(x,B),td8(x,B),ed8(x,B),xa8(x,B)}function od8(x,B){x.messaging.subscribe(N1.REGISTER,async(A)=>Ba8(B,A.payload)),x.messaging.subscribe(N1.QUEUE,async(A)=>Da8(x,B,A.payload)),x.messaging.subscribe(N1.DIRECT,async(A)=>$a8(x,B,A.payload)),x.messaging.subscribe(N1.REMOVE,async(A)=>Za8(B,A.payload)),x.messaging.subscribe(N1.REORDER,async(A)=>Qa8(B,A.payload)),x.messaging.subscribe(N1.LIST,async(A)=>Xa8(x,B,A.payload)),x.messaging.subscribe(N1.REPORT_SUCCESS,async(A)=>Ya8(B,A.payload)),x.messaging.subscribe(N1.REPORT_FAILURE,async(A)=>Wa8(B,A.payload)),x.messaging.subscribe(N1.COMPLETED,async(A)=>{return await B.publicationQueueService.complete(A.payload.entityType,A.payload.entityId),{success:!0}}),x.messaging.subscribe(N1.FAILED,async(A)=>{return await B.publicationQueueService.fail(A.payload.entityType,A.payload.entityId,A.payload.error),{success:!0}}),B.logger.debug("Subscribed to publish messages")}function td8(x,B){x.messaging.subscribe(a$.REPORT_SUCCESS,async(A)=>Ha8(B,A.payload)),x.messaging.subscribe(a$.REPORT_FAILURE,async(A)=>Fa8(B,A.payload)),B.logger.debug("Subscribed to generation messages")}function ed8(x,B){x.messaging.subscribe(rHx.REGISTER,async(A)=>Aa8(B,A.payload)),B.logger.debug("Subscribed to publish asset messages")}function xa8(x,B){let A=async(w)=>wa8(x,B,w.payload);x.messaging.subscribe(l8.created,A),x.messaging.subscribe(l8.updated,A),B.logger.debug("Subscribed to entity change messages for publish assets")}async function Ba8(x,B){let{entityType:A,provider:w,config:f}=B;try{let D=f?oHx.safeParse(f):void 0;if(D&&!D.success)return x.logger.warn("Invalid publish provider config",{entityType:A,error:D.error.message}),{success:!1};if(w)x.providerRegistry.register(A,w,D?.data),x.logger.info(`Registered provider for entity type: ${A}`,{providerName:w.name,executionMode:x.providerRegistry.getExecutionMode(A)});return{success:!0}}catch(D){let $=g(D);return x.logger.error(`Failed to register provider: ${$}`),{success:!1}}}async function Aa8(x,B){let A=FO.safeParse(B);if(!A.success)return x.logger.warn("Invalid publish asset registration",{error:A.error.message}),{success:!1};return x.publishAssetRegistry.register(A.data),x.logger.info("Registered publish asset",{entityType:A.data.entityType,attachmentType:A.data.attachmentType,mediaEntityType:A.data.mediaEntityType}),{success:!0}}async function wa8(x,B,A){try{if(B.publishAssetRegistry.list(A.entityType).length===0)return{success:!0};let w=A.entity??await x.entityService.getEntity({entityType:A.entityType,id:A.entityId});if(!fa8(w))return{success:!0};return await B.publishAssetPreflight.ensureForEntity(w),{success:!0}}catch(w){return B.logger.warn("Failed to run publish asset preflight for entity event",{entityType:A.entityType,entityId:A.entityId,error:g(w)}),{success:!1}}}function fa8(x){if(!x)return!1;let B=sHx.safeParse(x.metadata);return B.success&&B.data.status==="published"}async function Da8(x,B,A){let{entityType:w,entityId:f}=A;try{let D=A.authContext??Lf;x.permissions.assertEntityActionAllowed(w,"publish",D);let $=await B.publicationQueueService.enqueue(w,f,D);return await x.messaging.send({type:N1.QUEUED,payload:{entityType:w,entityId:f,position:$.position}}),B.logger.debug(`Entity queued: ${f}`,{entityType:w,position:$.position}),{success:!0}}catch(D){let $=g(D);return B.logger.error(`Failed to queue entity: ${$}`),{success:!1}}}async function $a8(x,B,A){let{entityType:w,entityId:f}=A,D=A.authContext??Lf;try{if(x.permissions.assertEntityActionAllowed(w,"publish",D),!B.providerRegistry.has(w))return B.scheduler.failPublish(w,f,`No publish provider registered for ${w}`),{success:!1};let $=await B.publishExecutor.publish({entityType:w,id:f});if("error"in $)return B.scheduler.failPublish(w,f,$.error),{success:!1};return B.scheduler.completePublish(w,f,$.result),B.logger.debug(`Direct publish completed: ${f}`,{entityType:w}),{success:!0}}catch($){let Z=g($);return B.logger.error(`Failed direct publish request: ${Z}`),{success:!1}}}async function Za8(x,B){let{entityType:A,entityId:w}=B;try{return await x.publicationQueueService.remove(A,w),x.logger.debug(`Entity removed from queue: ${w}`,{entityType:A}),{success:!0}}catch(f){let D=g(f);return x.logger.error(`Failed to remove entity: ${D}`),{success:!1}}}async function Qa8(x,B){let{entityType:A,entityId:w,position:f}=B;try{return await x.publicationQueueService.reorder(A,w,f),x.logger.debug(`Entity reordered: ${w}`,{entityType:A,newPosition:f}),{success:!0}}catch(D){let $=g(D);return x.logger.error(`Failed to reorder entity: ${$}`),{success:!1}}}async function Xa8(x,B,A){let{entityType:w}=A;try{let f=await B.queueManager.list(w);return await x.messaging.send({type:N1.LIST_RESPONSE,payload:{entityType:w,queue:f.map((D)=>({entityId:D.entityId,position:D.position,queuedAt:D.queuedAt}))}}),{success:!0}}catch(f){let D=g(f);return B.logger.error(`Failed to list queue: ${D}`),{success:!1}}}async function Ya8(x,B){let{entityType:A,entityId:w,result:f}=B;return x.scheduler.completePublish(A,w,f),x.logger.info(`Publish reported success: ${w}`,{entityType:A}),{success:!0}}async function Wa8(x,B){let{entityType:A,entityId:w,error:f}=B;x.scheduler.failPublish(A,w,f);let D=x.retryTracker.getRetryInfo(w);return x.logger.info(`Publish reported failure: ${w}`,{entityType:A,error:f,retryCount:D?.retryCount}),{success:!0}}async function Ha8(x,B){let{entityType:A,entityId:w}=B;return x.scheduler.completeGeneration(A,w),x.logger.info("Generation completed",{entityType:A,entityId:w}),{success:!0}}async function Fa8(x,B){let{entityType:A,error:w}=B;return x.scheduler.failGeneration(A,w),x.logger.warn("Generation failed",{entityType:A,error:w}),{success:!0}}async function FFx(x,B,A,w){try{if(w.skipIfDraftExists!==!1){if((await x.listEntities({entityType:A,options:{filter:{metadata:{status:"draft"}},limit:1}})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(w.maxUnpublishedDrafts!==void 0){let f=await x.listEntities({entityType:A,options:{filter:{metadata:{status:"draft"}},limit:w.maxUnpublishedDrafts+1}});if(f.length>=w.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${f.length}/${w.maxUnpublishedDrafts})`}}if(w.minSourceEntities!==void 0&&w.sourceEntityType){let f=await x.listEntities({entityType:w.sourceEntityType,options:{publishedOnly:!0,limit:w.minSourceEntities}});if(f.length<w.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${f.length}/${w.minSourceEntities} ${w.sourceEntityType})`}}return{shouldGenerate:!0}}catch(f){return B.error("Failed to check generation conditions",{entityType:A,error:g(f)}),{shouldGenerate:!1,reason:`Condition check failed: ${g(f)}`}}}function KFx(x){let{context:B,config:A,queueManager:w,providerRegistry:f,retryTracker:D,publishExecutor:$,logger:Z}=x,Q=Ka8(B);return rE.createFresh({queueManager:w,providerRegistry:f,retryTracker:D,logger:Z,backend:new HO({onOverlapSkipped:(Y)=>{Z.debug("Skipping overlapping content scheduler cycle",{jobKey:Y})},onCallbackError:(Y,W)=>{Z.error("Unhandled content scheduler callback error",{jobKey:Y,error:W})}}),...A.entitySchedules&&{entitySchedules:A.entitySchedules},...A.generationSchedules&&{generationSchedules:A.generationSchedules},...A.generationConditions&&{generationConditions:A.generationConditions},messageBus:Q,publishExecutor:$,onCheckGenerationConditions:(Y,W)=>FFx(B.entityService,Z,Y,W)})}function Ka8(x){return{send:async(f)=>{return x.messaging.send({type:f.type,payload:f.payload,...f.target!==void 0?{target:f.target}:{},...f.metadata!==void 0?{metadata:f.metadata}:{},...f.broadcast!==void 0?{broadcast:f.broadcast}:{}})},subscribe:()=>()=>{},unsubscribe:()=>{}}}var qFx=X.enum(["draft","queued","published","failed"]),qa8=X.object({entityId:X.string(),entityType:X.string(),title:X.string(),position:X.number().int().positive(),queuedAt:X.string(),destination:X.string(),scheduledFor:X.string().optional()}),za8=X.object({id:X.string(),label:X.string(),target:X.string(),status:X.enum(["pending","processing"])}),ba8=X.object({entityId:X.string(),entityType:X.string(),title:X.string(),error:X.string(),retryCount:X.number().int().nonnegative()}),Va8=X.object({summary:X.object({draft:X.number().int().nonnegative(),queued:X.number().int().nonnegative(),generating:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),published:X.number().int().nonnegative(),needsOperator:X.number().int().nonnegative()}),queue:X.array(qa8),generating:X.array(za8),failures:X.array(ba8),publishableEntityTypes:X.array(X.string())}),Ua8=X.object({sourceEntityType:X.string(),sourceEntityId:X.string(),attachmentType:X.string().optional()});async function GO(x,B,A,w,f={}){let D=(f.entityTypes??B.getRegisteredTypes()).sort(),$=new Map,Z={draft:0,queued:0,generating:0,failed:0,published:0,needsOperator:0};for(let H of D){let F=await x.entityService.listEntities({entityType:H,...f.visibilityScope?{options:{filter:{visibilityScope:f.visibilityScope}}}:{}});for(let K of F){let q=qFx.safeParse(K.metadata.status);if(!q.success)continue;Z[q.data]+=1;let V=K.metadata.scheduledFor,b=K.metadata.error;$.set(Y80(H,K.id),{entityId:K.id,entityType:H,title:Ea8(K.id,K.metadata),status:q.data,...typeof V==="string"?{scheduledFor:V}:{},...typeof b==="string"?{error:b}:{}})}}let Q=[];for(let H of D){let F=B.get(H).name,K=0;for(let q of await A.list(H)){let V=$.get(Y80(H,q.entityId));if(!V)continue;K+=1,Q.push({entityId:q.entityId,entityType:H,title:V.title,position:K,queuedAt:q.queuedAt,destination:F,...V.scheduledFor?{scheduledFor:V.scheduledFor}:{}})}}let Y=await Ga8(x,f.visibilityScope&&f.visibilityScope!=="restricted"?$:void 0);Z.generating=Y.length;let W=Array.from($.values()).filter((H)=>H.status==="failed").map((H)=>{let F=w.getRetryInfo(H.entityId);return{entityId:H.entityId,entityType:H.entityType,title:H.title,error:H.error??F?.lastError??"Publication failed",retryCount:F?.retryCount??0}}).sort((H,F)=>H.title.localeCompare(F.title));return Z.needsOperator=Z.draft+Z.failed,Va8.parse({summary:Z,queue:Q,generating:Y,failures:W,publishableEntityTypes:D})}async function Ga8(x,B){let A=[];for(let w of await x.jobs.getActiveJobs()){if(w.source!=="content-pipeline")continue;if(w.status!=="pending"&&w.status!=="processing")continue;let f;try{f=JSON.parse(w.data)}catch{continue}let D=Ua8.safeParse(f);if(!D.success)continue;if(B&&!B.has(Y80(D.data.sourceEntityType,D.data.sourceEntityId)))continue;A.push({id:w.id,label:D.data.attachmentType??w.type,target:`${D.data.sourceEntityType}/${D.data.sourceEntityId}`,status:w.status})}return A}function Y80(x,B){return`${x}\x00${B}`}function zFx(x){return qFx.safeParse(x).success}function Ea8(x,B){for(let A of["title","subject","slug"]){let w=B[A];if(typeof w==="string"&&w.length>0)return w}return x}async function bFx(x,B,A){await x.dashboard.registerWidget({id:"publication-pipeline",title:"Publication Pipeline",group:"publishing",section:"primary",priority:100,rendererName:"PipelineWidget",visibility:"admin",dataProvider:async()=>({...await GO(x,A.providerRegistry,A.queueManager,A.retryTracker),...A.managementUrl?{managementUrl:A.managementUrl}:{}}),digestProvider:_a8})}var ja8=X.object({summary:X.object({draft:X.number(),queued:X.number(),generating:X.number(),published:X.number(),failed:X.number(),needsOperator:X.number()})});function _a8(x){let{summary:B}=ja8.parse(x),A=B.queued+B.generating,w=A===0?"idle":`${B.queued} queued \xB7 ${B.generating} generating`,f=B.failed>0?`${B.draft} drafts \xB7 ${B.failed} failed`:`${B.draft} drafts`;return{digest:[{label:"Pipeline",value:w,...A>0?{tone:"warn"}:{}},{label:"Awaiting review",value:f,...B.needsOperator>0?{tone:"warn"}:{}},{label:"Published",value:String(B.published),tone:"good"}],needsAttention:B.needsOperator}}var Pa8=X.object({workspaceUrl:X.string()}),Ja8=X.object({confirmed:X.literal(!0),confirmationToken:X.string().min(1),contentHash:X.string().min(1),expiresAt:X.string().datetime()}),La8=X.discriminatedUnion("type",[X.object({type:X.literal("queue"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1)}),X.object({type:X.literal("remove"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1)}),X.object({type:X.literal("retry"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1)}),X.object({type:X.literal("reorder"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1),position:X.number().int().positive()}),X.object({type:X.literal("publish"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1),confirmation:Ja8.optional()})]);async function VFx(x,B,A){let w={id:"publishing",pluginId:B,label:"Publishing",rendererName:"PublishingWorkspace",priority:40,entityTypes:($)=>W80(x,A.providerRegistry,$),accessHandler:($)=>W80(x,A.providerRegistry,$).length>0,dataProvider:($)=>GO(x,A.providerRegistry,A.queueManager,A.retryTracker,{visibilityScope:$.visibilityScope,entityTypes:W80(x,A.providerRegistry,$)}),actionHandler:async($,Z)=>{let Q=La8.safeParse($);if(!Q.success)throw Error("Invalid publishing workspace action");return ka8(x,A,Q.data,Z)}},f=await x.messaging.send({type:WO,payload:w});if(!("success"in f)||!f.success)return;let D=Pa8.safeParse(f.data);return D.success?D.data.workspaceUrl:void 0}function UFx(x){return{interfaceType:x.interfaceType,actor:x.actor,userPermissionLevel:x.userPermissionLevel}}function W80(x,B,A){let w=UFx(A),f=["update","publish"];return B.getRegisteredTypes().filter((D)=>{for(let $ of f)try{return x.permissions.assertEntityActionAllowed(D,$,w),!0}catch{}return!1})}async function ka8(x,B,A,w){if(!B.providerRegistry.has(A.entityType))throw Error(`No publish provider registered for ${A.entityType}`);let f=await x.entityService.getEntity({entityType:A.entityType,id:A.entityId,visibilityScope:w.visibilityScope});if(!f)throw Error(`Entity not found: ${A.entityType}:${A.entityId}`);let D=UFx(w);if(A.type==="publish"){let Q=await nK({context:x,executor:B.publishExecutor,toolName:"publishing_manage",rawInput:{entityType:A.entityType,id:A.entityId,...A.confirmation??{}},toolContext:D});if("success"in Q&&Q.success===!0)await B.publicationQueueService.complete(A.entityType,A.entityId),B.retryTracker.clearRetries(A.entityId);return Q}let $=A.type==="queue"||A.type==="retry"?"publish":"update";x.permissions.assertEntityActionAllowed(A.entityType,$,D);let Z=f.metadata.status;switch(A.type){case"queue":if(Z!=="draft")throw Error("Only draft entities can be queued");return B.publicationQueueService.enqueue(A.entityType,A.entityId,{...D,authorization:"user"});case"remove":if(Z!=="queued")throw Error("Only queued entities can be removed from the queue");return await B.publicationQueueService.remove(A.entityType,A.entityId),{success:!0};case"retry":if(Z!=="failed")throw Error("Only failed publications can be retried");return await B.publicationQueueService.enqueue(A.entityType,A.entityId,{...D,authorization:"user"}),{success:!0};case"reorder":if(Z!=="queued")throw Error("Only queued entities can be reordered");return await B.publicationQueueService.reorder(A.entityType,A.entityId,await Ma8(x,B.queueManager,A.entityType,w,A.position)),{success:!0}}}async function Ma8(x,B,A,w,f){let D=[];for(let Z of await B.list(A)){let Q=await x.entityService.getEntity({entityType:A,id:Z.entityId,visibilityScope:w.visibilityScope});if(Q&&zFx(Q.metadata.status))D.push(Z)}let $=Math.min(Math.max(f,1),D.length);return D[$-1]?.position??f}var GFx={name:"@brains/content-pipeline",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Content pipeline plugin for managing entity publishing queues, scheduling, and generation",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/scheduler":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},exports:{".":{types:"./src/index.ts",default:"./src/index.ts"}},files:["src"],main:"src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"src/index.ts"};class H80 extends D8{pluginContext;queueManager;publicationQueueService;providerRegistry;retryTracker;publishExecutor;publishAssetRegistry;publishAssetPreflight;scheduler;constructor(x={}){super("content-pipeline",GFx,x,tHx)}async onRegister(x){this.pluginContext=x,this.queueManager=aE.createFresh(),this.publicationQueueService=new X80(x,this.queueManager),this.providerRegistry=sE.createFresh(),this.retryTracker=oE.createFresh(),this.publishAssetRegistry=tE.createFresh(),this.publishAssetPreflight=new KO({context:x,registry:this.publishAssetRegistry}),this.publishExecutor=new tX({context:x,providerRegistry:this.providerRegistry,publishAssetPreflight:this.publishAssetPreflight}),this.scheduler=KFx({context:x,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,logger:this.logger}),HFx(x,{queueManager:this.queueManager,publicationQueueService:this.publicationQueueService,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,publishAssetRegistry:this.publishAssetRegistry,publishAssetPreflight:this.publishAssetPreflight,scheduler:this.scheduler,logger:this.logger})}async onReady(x){await this.publicationQueueService.reconcile(this.providerRegistry.getRegisteredTypes());let B=await VFx(x,this.id,{providerRegistry:this.providerRegistry,queueManager:this.queueManager,publicationQueueService:this.publicationQueueService,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor});await bFx(x,this.id,{providerRegistry:this.providerRegistry,queueManager:this.queueManager,retryTracker:this.retryTracker,...B?{managementUrl:B}:{}}),await this.scheduler.start(),this.logger.info("Content pipeline plugin started")}async getTools(){if(!this.pluginContext)throw Error("Plugin context not initialized");return[UO(this.pluginContext,{queueManager:this.queueManager,publicationQueueService:this.publicationQueueService,providerRegistry:this.providerRegistry,publishExecutor:this.publishExecutor})]}async getInstructions(){return'## Publishing\n- Use `publishing_manage` to manage publishing actions.\n- Use `publishing_manage` with `action=queue-list`, `action=queue-add`, `action=queue-remove`, or `action=queue-reorder` for publish queue requests.\n- Use `publishing_manage` with `action=publish` to publish an entity directly to its platform (e.g. LinkedIn, Buttondown). This tool has its own confirmation flow; call it without `confirmed` when the user asks to publish instead of asking for plain-text confirmation. Follow-up requests like "publish it now" should target the entity just read, generated, or updated in the conversation, including a post just changed to draft.\n- Missing publish assets such as generated OG images are reconciled automatically during publishing; do not call a separate asset reconciliation tool.'}getQueueManager(){return this.queueManager}getPublicationQueueService(){return this.publicationQueueService}getProviderRegistry(){return this.providerRegistry}getRetryTracker(){return this.retryTracker}getPublishAssetRegistry(){return this.publishAssetRegistry}getScheduler(){return this.scheduler}async onShutdown(){await this.scheduler.stop()}}function F80(x={}){return new H80(x)}var EO="conversation-memory",k6="summary",k2="decision",IB="action-item",EFx="conversation-memory:project",K80="conversation-memory",jO="conversation-memory:ai-response",dK="conversation-memory:entities";var kf=X.object({start:X.string().datetime(),end:X.string().datetime()}),_Fx=X.object({title:X.string().min(1).describe("Brief topic or phase title"),summary:X.string().min(1).describe("Grounded prose summary"),timeRange:kf,sourceMessageCount:X.number().int().min(0),keyPoints:X.array(X.string())}),Na8=X.object({entries:X.array(_Fx)}),q80=X.object({identity:SA,identityAliases:X.array(SA).optional(),displayName:X.string().optional(),roles:X.array(X.enum(["user","assistant","system"])).min(1)}),_O=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),timeRange:kf.optional(),messageCount:X.number().int().min(0),entryCount:X.number().int().min(0),participants:X.array(q80).optional(),sourceHash:X.string(),projectionVersion:X.number().int().min(1)}),Ia8=X.preprocess((x)=>Oa8(x),q80);function Oa8(x){if(!ha8(x)||"identity"in x)return x;let{actorId:B,roles:A}=x;if(typeof B!=="string"||!Array.isArray(A))return x;let w=x.canonicalId,f=A.includes("assistant")?"assistant":"user",D=Array.isArray(x.sourceActorIds)?x.sourceActorIds.filter((Z)=>typeof Z==="string"):[],$=Array.from(new Map([B,...D].map((Z)=>{let Q=s$({actorId:Z,interfaceType:jFx(Z),role:f});return[O1(Q),Q]})).values());return{identity:s$({actorId:B,interfaceType:jFx(B),role:f,...typeof w==="string"?{canonicalId:w}:{}}),...$.length>0?{identityAliases:$}:{},...typeof x.displayName==="string"?{displayName:x.displayName}:{},roles:A}}function jFx(x){let B=x.indexOf(":");return B>0?x.slice(0,B):"legacy"}function ha8(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}var Ra8=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),timeRange:kf.optional(),messageCount:X.number().int().min(0),entryCount:X.number().int().min(0),participants:X.array(Ia8).optional(),sourceHash:X.string(),projectionVersion:X.number().int().min(1)}),eX=j8.extend({entityType:X.literal("summary"),metadata:Ra8});var eE=X.object({identity:SA,identityAliases:X.array(SA).optional(),displayName:X.string().optional()}),z80=X.preprocess((x)=>PFx(x,!0),eE),b80=X.object({identity:SA.optional(),identityAliases:X.array(SA).optional(),displayName:X.string().min(1)}),ya8=X.preprocess((x)=>PFx(x,!1),b80);function PFx(x,B){if(!ma8(x)||"identity"in x)return x;let A=x.actorId;if(typeof A!=="string")return B?x:{displayName:x.displayName};let w=A.indexOf(":"),f=x.canonicalId,D=A.startsWith("brain:")?"assistant":"user",$=Array.isArray(x.sourceActorIds)?x.sourceActorIds.filter((Q)=>typeof Q==="string"):[],Z=Array.from(new Map([A,...$].map((Q)=>{let Y=Q.indexOf(":"),W=s$({actorId:Q,interfaceType:Y>0?Q.slice(0,Y):"legacy",role:D});return[O1(W),W]})).values());return{identity:s$({actorId:A,interfaceType:w>0?A.slice(0,w):"legacy",role:D,...typeof f==="string"?{canonicalId:f}:{}}),...Z.length>0?{identityAliases:Z}:{},...typeof x.displayName==="string"?{displayName:x.displayName}:{}}}function ma8(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}var PO=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["active","superseded"]),decidedBy:X.array(eE).optional(),mentionedBy:X.array(eE).optional()}),Ca8=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["active","superseded"]),decidedBy:X.array(z80).optional(),mentionedBy:X.array(z80).optional()}),xY=j8.extend({entityType:X.literal("decision"),metadata:Ca8}),JO=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["open","done","dropped"]),assignedTo:X.array(b80).optional(),requestedBy:X.array(eE).optional()}),ca8=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["open","done","dropped"]),assignedTo:X.array(ya8).optional(),requestedBy:X.array(z80).optional()}),BY=j8.extend({entityType:X.literal("action-item"),metadata:ca8});var ga8=X.record(X.string(),X.unknown());class V80 extends ox{metadataSchema;constructor(x){super({entityType:x.entityType,purpose:x.purpose,schema:x.schema,frontmatterSchema:x.metadataSchema});this.metadataSchema=x.parseMetadata}composeContent(x,B,A){return this.buildMarkdown([`# ${x}`,"",B.trim(),""].join(`
5368
+ `),{object:Q}=await x.ai.generateObject(Z,pHx);return d0({suggestion:Q.suggestion})}async function iHx(x,B,A){let w=new URL(B.url).searchParams,f=w.get("type"),D=w.get("id");if(!f||!D)return d0({error:"type and id query parameters are required"},400);let $=await dx0(x,f,D,A);if($ instanceof Response)return $;let Z=await x.messaging.send({type:CH.callAgents,payload:{entityType:f,entityId:$.entity.id,actor:A.actor,interfaceType:"cms"}});if(!("success"in Z)||!Z.success)return d0({agents:[]});let Q=sn8.safeParse(Z.data);return d0(Q.success?Q.data:{agents:[]})}async function lHx(x,B,A){let w;try{w=dn8.parse(await B.json())}catch{return d0({error:"Invalid agent ask payload or selection length"},400)}let f=await dx0(x,w.entityType,w.id,A);if(f instanceof Response)return f;let D=uHx(f,w.selection);if(D)return D;let $=await x.messaging.send({type:CH.callRequest,payload:{agent:w.agent,instruction:w.instruction,selection:w.selection,entityType:w.entityType,entityId:f.entity.id,actor:A.actor,interfaceType:"cms"}});if(!("success"in $)||!$.success){let Q="error"in $&&typeof $.error==="string"?$.error:"Agent call failed",Y=Q.startsWith("No handler found");return d0({error:Y?"Agent asking is unavailable":Q},Y?503:400)}if($.data===void 0)return d0({error:"Agent asking is unavailable"},503);let Z=an8.safeParse($.data);if(!Z.success)return d0({error:"Invalid response from agent"},502);return d0({agentId:w.agent,response:Z.data.response})}var on8=rn8(import.meta.dir,"..","dist","ui","cms-app.js"),tn8=X.object({id:X.string().trim().min(1),action:X.unknown()}),en8=X.object({watchEnabled:X.boolean(),lastSync:X.string().nullable(),git:X.object({branch:X.string(),hasChanges:X.boolean(),ahead:X.number(),behind:X.number(),lastCommit:X.string().nullable(),remote:X.string().nullable()}).nullable()});function nHx(x){let{routePath:B,getContext:A,resolveAuthPrincipal:w,minimumPermissionLevel:f,getEntityDisplay:D,workspaceRegistry:$}=x,Z=cx0(B),Q=Z||"/",Y=`${Z}/assets/app.js`,W=(q)=>`${Z}/api/${q}`,H=async(q)=>{let V=await w(q);if(V?.status!=="active")return{state:"unauthenticated"};if(V.permissionLevel==="public")return{state:"forbidden"};if(f==="admin"&&V.permissionLevel!=="admin")return{state:"forbidden"};let b=oX(V.permissionLevel);if(b==="public")return{state:"forbidden"};return{state:"allowed",access:{principal:V,actor:{kind:"user",userId:V.userId,...V.canonicalId?{canonicalId:V.canonicalId}:{}},permissionLevel:V.permissionLevel,visibilityScope:b,isAnchor:V.isAnchor}}},F=async(q)=>{let V=await H(q);if(V.state==="unauthenticated")return d0({error:"Authentication required"},401);if(V.state==="forbidden")return d0({error:"CMS access forbidden"},403);return V.access},K=async(q)=>{let V=new URL(q.url),b=`${V.pathname}${V.search}`,G=await H(q);if(G.state==="unauthenticated")return new Response(null,{status:302,headers:{Location:`/login?return_to=${encodeURIComponent(b)}`,"Cache-Control":"no-store"}});if(G.state==="forbidden")return new Response("CMS access forbidden",{status:403,headers:{"Cache-Control":"no-store"}});return new Response(gx0({assetPath:Y,basePath:Q,surfaces:YB(A().webRoutes.getRoutes(),{activeId:"cms",permissionLevel:G.access.permissionLevel,self:{id:"cms",href:Q}}),sessionHref:`/logout?return_to=${encodeURIComponent(b)}`}),{headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}})};return[{path:Q,method:"GET",public:!0,handler:K},{path:`${Z}/entities`,match:"prefix",method:"GET",public:!0,handler:K},{path:`${Z}/workspaces`,match:"prefix",method:"GET",public:!0,handler:K},{path:Y,method:"GET",public:!0,handler:async()=>{let q=Bun.file(on8);if(!await q.exists())return new Response("CMS editor UI asset not built",{status:404});return new Response(q,{headers:{"Content-Type":"text/javascript; charset=utf-8","Cache-Control":"no-cache"}})}},{path:W("types"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return Bd8(A(),D(),$,V)}},{path:W("workspace"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return Ad8($,q,V)}},{path:W("workspace"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return wd8($,q,V)}},{path:W("schema"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return fd8(A(),q,V)}},{path:W("entities"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return yHx(A(),q,V)}},{path:W("entities"),method:"PUT",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return mHx(A(),q,V,x.recordAuditEvent)}},{path:W("entities"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return CHx(A(),q,V,x.recordAuditEvent)}},{path:W("entities"),method:"DELETE",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return cHx(A(),q,V,x.recordAuditEvent)}},{path:W("upload"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=GP(q);if(b)return b;return THx(A(),q,W("upload"),V,x.recordAuditEvent)}},{path:W("assist"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return SHx(A(),q,V)}},{path:W("agents"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;return iHx(A(),q,V)}},{path:W("ask-agent"),method:"POST",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=j4(q);if(b)return b;return lHx(A(),q,V)}},{path:W("sync-status"),method:"GET",public:!0,handler:async(q)=>{let V=await F(q);if(V instanceof Response)return V;let b=hHx(V);if(b)return b;return xd8(A())}}]}async function xd8(x){let B={directorySync:null,git:null},A=await x.messaging.send({type:HB.statusRequest,payload:{}});if(!("success"in A)||!A.success)return d0(B);let w=en8.safeParse(A.data);if(!w.success)return d0(B);return d0({directorySync:{lastSync:w.data.lastSync,watching:w.data.watchEnabled},git:w.data.git})}async function Bd8(x,B,A,w){let f=new Map((await x.entityService.getEntityCounts(w.visibilityScope)).map(($)=>[$.entityType,$.count])),D=x.entityService.getEntityTypes().flatMap(($)=>{if(!x.entities.getEffectiveFrontmatterSchema($))return[];let Q=f.get($)??0,Y=Tx0(x,$,Q,w);if(!Y)return[];let W=x.entities.getAdapter($);return[{entityType:$,label:OHx($,B?.[$]).pluralLabel,isSingleton:W?.isSingleton===!0,hasBody:W?.hasBody!==!1,count:Q,capabilities:Y}]});return d0({types:D,workspaces:await A.listDescriptors(QO(w))})}async function Ad8(x,B,A){let w=new URL(B.url).searchParams.get("id");if(!w)return d0({error:"id query parameter is required"},400);let f=x.get(w);if(!f)return d0({error:`Unknown CMS workspace: ${w}`},404);let D=QO(A);if(!await f.accessHandler(D))return d0({error:`Unknown CMS workspace: ${w}`},404);try{return d0({workspace:{id:f.id,rendererName:f.rendererName,data:await f.dataProvider(D)}})}catch($){return d0({error:g($,"CMS workspace data provider failed")},502)}}async function wd8(x,B,A){let w;try{w=tn8.parse(await B.json())}catch{return d0({error:"Invalid workspace action payload"},400)}let f=x.get(w.id);if(!f)return d0({error:`Unknown CMS workspace: ${w.id}`},404);let D=QO(A);if(!await f.accessHandler(D))return d0({error:`Unknown CMS workspace: ${w.id}`},404);if(!f.actionHandler)return d0({error:`CMS workspace ${w.id} does not provide actions`},405);try{return d0({result:await f.actionHandler(w.action,D)})}catch($){return d0({error:g($,"CMS workspace action failed")},400)}}async function fd8(x,B,A){let w=new URL(B.url).searchParams.get("type");if(!w)return d0({error:"type query parameter is required"},400);let D=await YO(x,w,A)?x.entities.getEffectiveFrontmatterSchema(w):void 0;if(!D)return d0({error:`Unknown entity type: ${w}`},404);let $=x.entities.getAdapter(w),Z=rX(w),Q=Z?[]:Object.keys(D.shape).map((Y)=>iK(Y,D.shape[Y]));return d0({entityType:w,format:Z?"raw":"frontmatter",isSingleton:$?.isSingleton===!0,hasBody:Z||$?.hasBody!==!1,fields:Q})}var Dd8=X.object({id:X.string().trim().min(1),pluginId:X.string().trim().min(1),label:X.string().trim().min(1),rendererName:X.enum(["PublishingWorkspace","SiteWorkspace","DirectorySyncWorkspace","EmailTriageWorkspace"]),priority:X.number().int(),entityTypes:X.union([X.array(X.string().trim().min(1)),X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace entity types resolver function"})]).default([]),accessHandler:X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace access handler function"}),dataProvider:X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace data provider function"}),actionHandler:X.custom((x)=>typeof x==="function",{message:"Expected CMS workspace action handler function"}).optional()});class ax0{workspaces=new Map;register(x){let B=Dd8.parse(x);if(this.workspaces.has(B.id))throw Error(`CMS workspace already registered: ${B.id}`);let A={id:B.id,pluginId:B.pluginId,label:B.label,rendererName:B.rendererName,priority:B.priority,entityTypes:B.entityTypes,accessHandler:B.accessHandler,dataProvider:B.dataProvider,...B.actionHandler?{actionHandler:B.actionHandler}:{}};return this.workspaces.set(A.id,A),A}get(x){return this.workspaces.get(x)}async listDescriptors(x){let B=Array.from(this.workspaces.values()).sort((w,f)=>w.priority-f.priority||w.id.localeCompare(f.id)),A=await Promise.all(B.map(async(w)=>({workspace:w,admitted:await w.accessHandler(x)})));return Promise.all(A.filter(({admitted:w})=>w).map(async({workspace:w})=>({id:w.id,pluginId:w.pluginId,label:w.label,rendererName:w.rendererName,priority:w.priority,entityTypes:typeof w.entityTypes==="function"?await w.entityTypes(x):w.entityTypes})))}}var dHx={name:"@brains/cms",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"CMS plugin for config and browser authoring routes",dependencies:{"@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@codemirror/lang-markdown":"^6.5.0","@codemirror/language":"^6.12.4","@codemirror/state":"^6.7.1","@codemirror/view":"^6.43.6","@lezer/highlight":"^1.2.3","@tanstack/react-query":"^5.0.0","@tanstack/react-router":"^1.0.0",react:"^19.2.7","react-dom":"^19.2.7",streamdown:"^2.5.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/templates":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.0.3","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json"},type:"module"};var Zd8=X.looseObject({label:X.string().optional(),pluralName:X.string().optional()}),aHx=X.record(X.string(),Zd8),Qd8=X.object({entityDisplay:aHx.optional(),routePath:X.string().default("/cms")});function Xd8(x){let B=aHx.safeParse(x);return B.success?B.data:void 0}class sx0 extends D8{workspaceRegistry=new ax0;constructor(x={}){super("cms",dHx,x,Qd8)}async onRegister(x){await super.onRegister(x),x.endpoints.register({label:"CMS",url:this.config.routePath,priority:40,visibility:"trusted"}),x.interactions.register({id:"cms",label:"CMS",description:"Edit and manage content through the browser CMS.",href:this.config.routePath,kind:"admin",priority:40,visibility:"trusted"}),x.messaging.subscribe(WO,async(B)=>{try{let A=this.workspaceRegistry.register(B.payload);return{success:!0,data:{workspaceUrl:LHx(this.config.routePath,A.id)}}}catch(A){return{success:!1,error:g(A)}}})}getWebRoutes(){return nHx({routePath:this.config.routePath,getContext:()=>this.getContext(),resolveAuthPrincipal:(x)=>X6()?.resolveSession(x)??Promise.resolve(void 0),minimumPermissionLevel:"trusted",getEntityDisplay:()=>this.config.entityDisplay??Xd8(this.getContext().entityDisplay),workspaceRegistry:this.workspaceRegistry,recordAuditEvent:async(x)=>{let B=X6();if(B)await B.recordAuditEvent(x)}})}}function rx0(x={}){return new sx0(x)}var Yd8=X.enum(["draft","queued","published","failed"]),sHx=X.object({status:Yd8.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class ox0{name="internal";async publish(x,B){return{id:"internal"}}}var Lf={interfaceType:"system",actor:{kind:"service",serviceId:"content-pipeline"},userPermissionLevel:"admin",authorization:"system"},N1={REGISTER:"publish:register",EXECUTE:"publish:execute",QUEUE:"publish:queue",DIRECT:"publish:direct",REMOVE:"publish:remove",REORDER:"publish:reorder",LIST:"publish:list",REPORT_SUCCESS:"publish:report:success",REPORT_FAILURE:"publish:report:failure",QUEUED:"publish:queued",COMPLETED:"publish:completed",FAILED:"publish:failed",LIST_RESPONSE:"publish:list:response"},a$={REGISTER:"generate:register",REPORT_SUCCESS:"generate:report:success",REPORT_FAILURE:"generate:report:failure",EXECUTE:"generate:execute",COMPLETED:"generate:completed",FAILED:"generate:failed",SKIPPED:"generate:skipped"},rHx={REGISTER:"publish-assets:register"};var Wd8=X.enum(["provider"]),oHx=X.object({executionMode:Wd8.optional(),publishResultIdField:X.string().min(1).optional(),publishTimestampField:X.string().min(1).optional(),enabled:X.boolean().optional()}).strict();var Hd8=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),tHx=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),Hd8).optional()});class aE{queues=new Map;static createFresh(){return new aE}constructor(){}async add(x,B,A=Lf){let w=this.getOrCreateQueue(x),f=w.find((Z)=>Z.entityId===B);if(f)return{position:f.position};let D=w.length+1,$={entityId:B,entityType:x,position:D,queuedAt:new Date().toISOString(),authContext:{...A}};return w.push($),{position:D}}async remove(x,B){let A=this.queues.get(x);if(!A)return;let w=A.findIndex((f)=>f.entityId===B);if(w===-1)return;A.splice(w,1),this.recalculatePositions(A)}async reorder(x,B,A){let w=this.queues.get(x);if(!w)return;let f=w.findIndex((Z)=>Z.entityId===B);if(f===-1)return;let[D]=w.splice(f,1);if(!D)return;let $=Math.max(0,Math.min(A-1,w.length));w.splice($,0,D),this.recalculatePositions(w)}async list(x){let B=this.queues.get(x);if(!B)return[];return[...B]}async getNext(x){let B=this.queues.get(x);if(!B||B.length===0)return null;return B[0]??null}async getNextAcrossTypes(){let x=null;for(let B of this.queues.values()){let A=B[0];if(!A)continue;if(!x||A.queuedAt<x.queuedAt)x=A}return x}async popNext(x){let B=this.queues.get(x);if(!B||B.length===0)return null;let A=B.shift()??null;if(A)this.recalculatePositions(B);return A}replace(x){this.queues.clear();let B=[...x].sort((A,w)=>A.entityType.localeCompare(w.entityType)||A.position-w.position);for(let A of B)this.getOrCreateQueue(A.entityType).push({...A,authContext:{...A.authContext}});for(let A of this.queues.values())this.recalculatePositions(A)}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let x=[];for(let[B,A]of this.queues.entries())if(A.length>0)x.push(B);return x}getOrCreateQueue(x){let B=this.queues.get(x);if(!B)B=[],this.queues.set(x,B);return B}recalculatePositions(x){x.forEach((B,A)=>{B.position=A+1})}}class sE{providers=new Map;executionModes=new Map;publishResultIdFields=new Map;publishTimestampFields=new Map;defaultProvider=new ox0;static createFresh(){return new sE}constructor(){}register(x,B,A){let w=this.providers.get(x);if(w&&w.name!=="internal"&&B.name==="internal")return;if(this.providers.set(x,B),this.executionModes.set(x,A?.executionMode??"provider"),A?.publishResultIdField)this.publishResultIdFields.set(x,A.publishResultIdField);else this.publishResultIdFields.delete(x);if(A?.publishTimestampField)this.publishTimestampFields.set(x,A.publishTimestampField);else this.publishTimestampFields.delete(x)}get(x){return this.providers.get(x)??this.defaultProvider}getExecutionMode(x){return this.executionModes.get(x)??"provider"}getPublishResultIdField(x){return this.publishResultIdFields.get(x)}getPublishTimestampField(x){return this.publishTimestampFields.get(x)}has(x){return this.providers.has(x)}unregister(x){this.providers.delete(x),this.executionModes.delete(x),this.publishResultIdFields.delete(x),this.publishTimestampFields.delete(x)}getRegisteredTypes(){return Array.from(this.providers.keys())}}async function eHx(x,B){if(!B.publishExecutor){B.onFailed?.({entityType:x.entityType,entityId:x.entityId,error:"Publish executor not configured",retryCount:0,willRetry:!1});return}await Fd8(x,B)}async function Fd8(x,B){if(!B.publishExecutor)return;try{let A=await B.publishExecutor.publish({entityType:x.entityType,id:x.entityId});if("error"in A){let w={entityType:x.entityType,entityId:x.entityId,error:A.error,retryCount:0,willRetry:!1};if(B.messageBus)await B.messageBus.send({type:N1.FAILED,payload:w,sender:"publish-service",broadcast:!0});B.onFailed?.(w);return}tx0(x.entityType,x.entityId,A.result,B)}catch(A){let w=g(A);B.retryTracker.recordFailure(x.entityId,w);let f=B.retryTracker.getRetryInfo(x.entityId);B.onFailed?.({entityType:x.entityType,entityId:x.entityId,error:w,retryCount:f?.retryCount??1,willRetry:!1})}}function tx0(x,B,A,w){if(w.retryTracker.clearRetries(B),w.messageBus)w.messageBus.send({type:N1.COMPLETED,payload:{entityType:x,entityId:B,result:A},sender:"publish-service",broadcast:!0});w.onPublish?.({entityType:x,entityId:B,result:A})}function xFx(x,B,A,w){w.retryTracker.recordFailure(B,A);let f=w.retryTracker.getRetryInfo(B),D={entityType:x,entityId:B,error:A,retryCount:f?.retryCount??1,willRetry:!1};if(w.messageBus)w.messageBus.send({type:N1.FAILED,payload:D,sender:"publish-service",broadcast:!0});w.onFailed?.(D)}async function BFx(x,B){let A=B.generationConditions[x];if(A&&B.onCheckGenerationConditions){let f=await B.onCheckGenerationConditions(x,A);if(!f.shouldGenerate){if(B.messageBus)B.messageBus.send({type:a$.SKIPPED,payload:{entityType:x,reason:f.reason??"Conditions not met"},sender:"content-pipeline"});return}}let w={entityType:x};if(B.messageBus)await B.messageBus.send({type:a$.EXECUTE,payload:w,sender:"content-pipeline"});B.onGenerate?.(w)}function AFx(x,B,A){if(A)A.send({type:a$.COMPLETED,payload:{entityType:x,entityId:B},sender:"content-pipeline"})}function wFx(x,B,A){if(A)A.send({type:a$.FAILED,payload:{entityType:x,error:B},sender:"content-pipeline"})}var Kd8=1000;class ex0{deps;publishJobs=new Map;immediateIntervalJob=null;constructor(x){this.deps=x}start(){for(let[x,B]of Object.entries(this.entitySchedules)){let A=this.deps.config.backend.scheduleCron(B,()=>this.processEntityType(x));this.publishJobs.set(x,A)}this.immediateIntervalJob=this.deps.config.backend.scheduleInterval(Kd8,()=>this.processUnscheduledTypes())}async stop(){let x=Array.from(this.publishJobs.values());if(this.publishJobs.clear(),this.immediateIntervalJob)x.push(this.immediateIntervalJob),this.immediateIntervalJob=null;await Promise.all(x.map((B)=>B.stop()))}async processEntityType(x){if(!this.deps.isRunning())return;try{let B=await this.deps.config.queueManager.getNext(x);if(B)await this.processEntry(B)}catch(B){this.deps.config.logger.error(`Scheduler error for ${x}:`,B)}}async processUnscheduledTypes(){if(!this.deps.isRunning())return;try{let x=await this.deps.config.queueManager.getQueuedEntityTypes();for(let B of x)if(!this.entitySchedules[B]){let A=await this.deps.config.queueManager.getNext(B);if(A){await this.processEntry(A);break}}}catch(x){this.deps.config.logger.error("Scheduler error for unscheduled types:",x)}}async processEntry(x){await this.deps.config.queueManager.remove(x.entityType,x.entityId);let B=this.deps.getPublishDeps();await eHx(x,B)}get entitySchedules(){return this.deps.config.entitySchedules}}class x80{deps;generationJobs=new Map;constructor(x){this.deps=x}start(){for(let[x,B]of Object.entries(this.generationSchedules)){let A=this.deps.config.backend.scheduleCron(B,()=>this.handleTriggerGeneration(x));this.generationJobs.set(x,A)}}async stop(){let x=Array.from(this.generationJobs.values());this.generationJobs.clear(),await Promise.all(x.map((B)=>B.stop()))}async handleTriggerGeneration(x){if(!this.deps.isRunning())return;try{await BFx(x,this.deps.getGenerationDeps())}catch(B){this.deps.config.logger.error(`Generation trigger error for ${x}:`,B)}}get generationSchedules(){return this.deps.config.generationSchedules}}class rE{config;publishRunner;generationRunner;running=!1;stopPromise=null;static createFresh(x){return new rE(x)}constructor(x){this.config={...x,entitySchedules:x.entitySchedules??{},generationSchedules:x.generationSchedules??{},generationConditions:x.generationConditions??{}},this.validateCronExpressions(),this.publishRunner=new ex0({config:this.config,getPublishDeps:()=>this.publishDeps,isRunning:()=>this.running}),this.generationRunner=new x80({config:this.config,getGenerationDeps:()=>this.generationDeps,isRunning:()=>this.running})}async start(){if(this.running)return;if(this.stopPromise)await this.stopPromise,this.stopPromise=null;this.running=!0,this.publishRunner.start(),this.generationRunner.start()}stop(){if(this.stopPromise)return this.stopPromise;return this.running=!1,this.stopPromise=Promise.all([this.publishRunner.stop(),this.generationRunner.stop()]).then(()=>{return}),this.stopPromise}isRunning(){return this.running}completePublish(x,B,A){tx0(x,B,A,this.publishDeps)}failPublish(x,B,A){xFx(x,B,A,this.publishDeps)}completeGeneration(x,B){AFx(x,B,this.config.messageBus)}failGeneration(x,B){wFx(x,B,this.config.messageBus)}get entitySchedules(){return this.config.entitySchedules}get generationSchedules(){return this.config.generationSchedules}get publishDeps(){return{retryTracker:this.config.retryTracker,messageBus:this.config.messageBus,publishExecutor:this.config.publishExecutor,onPublish:this.config.onPublish,onFailed:this.config.onFailed}}get generationDeps(){return{logger:this.config.logger,messageBus:this.config.messageBus,generationConditions:this.config.generationConditions,onCheckGenerationConditions:this.config.onCheckGenerationConditions,onGenerate:this.config.onGenerate}}validateCronExpressions(){for(let[x,B]of Object.entries(this.entitySchedules))this.validateCronExpression(x,B,"publish");for(let[x,B]of Object.entries(this.generationSchedules))this.validateCronExpression(x,B,"generation")}validateCronExpression(x,B,A){try{this.config.backend.validateCron(B)}catch(w){throw Error(`Invalid ${A} cron expression for ${x}: "${B}" - ${g(w)}`,{cause:w})}}}class oE{retries=new Map;static createFresh(){return new oE}constructor(){}recordFailure(x,B){let w=(this.retries.get(x)?.retryCount??0)+1;this.retries.set(x,{entityId:x,retryCount:w,lastError:B})}clearRetries(x){this.retries.delete(x)}getRetryInfo(x){let B=this.retries.get(x);if(!B)return null;return{entityId:B.entityId,retryCount:B.retryCount,lastError:B.lastError}}}var fFx=X.union([X.string().min(1),X.object({location:X.enum(["metadata","frontmatter"]),field:X.string().min(1)})]),FO=X.object({entityType:X.string().min(1),attachmentType:X.string().min(1),mediaEntityType:X.enum(["image","document"]),targetEntityField:fFx.optional(),requiredWhen:X.object({status:X.string().min(1).optional(),visibility:X.string().min(1).optional()}).optional(),autoGenerate:X.boolean().optional(),requiredForPublish:X.boolean().optional(),jobType:X.string().min(1).optional()});function B80(x){return`${x.entityType}:${x.attachmentType}`}class tE{definitions=new Map;static createFresh(){return new tE}constructor(){}register(x){let B=FO.parse(x),A=B80(B);return this.definitions.set(A,B),()=>this.unregister(B.entityType,B.attachmentType)}get(x,B){return this.definitions.get(B80({entityType:x,attachmentType:B}))}list(x){let B=Array.from(this.definitions.values());return x?B.filter((A)=>A.entityType===x):B}has(x,B){return this.get(x,B)!==void 0}unregister(x,B){this.definitions.delete(B80({entityType:x,attachmentType:B}))}clear(){this.definitions.clear()}}class KO{deps;constructor(x){this.deps=x}async ensureForEntity(x,B={}){let A=this.deps.registry.list(x.entityType).filter((f)=>f.autoGenerate===!0).filter((f)=>!B.attachmentType||f.attachmentType===B.attachmentType),w={checked:A.length,enqueued:0,skipped:0};for(let f of A)if(await this.ensureDefinition(x,f))w.enqueued+=1;else w.skipped+=1;return w}async ensureDefinition(x,B){if(!this.matchesPolicy(x,B))return!1;if(this.hasTargetField(x,B.targetEntityField))return!1;if(!this.deps.context.attachments.hasProvider(x.entityType,B.attachmentType))return!1;let A=this.resolveJobType(B);if(!A)return!1;let w=this.getPredictedMediaId(x,B),f=this.getDeduplicationKey(x,B);return await this.deps.context.jobs.enqueue({type:A,data:{sourceEntityType:x.entityType,sourceEntityId:x.id,attachmentType:B.attachmentType,imageId:w,dedupKey:f,targetEntityType:x.entityType,targetEntityId:x.id,...this.getTargetImageFieldData(B.targetEntityField)},options:{source:"content-pipeline",metadata:{operationType:"content_operations"},deduplication:"skip",deduplicationKey:f}}),this.deps.context.logger.debug("Queued publish asset generation",{entityType:x.entityType,entityId:x.id,attachmentType:B.attachmentType,jobType:A}),!0}matchesPolicy(x,B){let{requiredWhen:A}=B;if(!A)return!0;if(A.status&&x.metadata.status!==A.status)return!1;if(A.visibility&&x.visibility!==A.visibility)return!1;return!0}hasTargetField(x,B){if(!B)return!1;if(typeof B==="string")return A80(x.metadata[B]);if(B.location==="metadata")return A80(x.metadata[B.field]);let{frontmatter:A}=I1(x.content);return A80(A[B.field])}resolveJobType(x){if(x.jobType)return x.jobType;if(x.mediaEntityType==="image")return"image:image-render-source";return}getPredictedMediaId(x,B){let A=B.attachmentType==="og-image"?"og":B.attachmentType;return Gx(`${A}-${x.entityType}-${x.id}`)}getDeduplicationKey(x,B){return`publish-asset:${B.attachmentType}:${x.entityType}:${x.id}`}getTargetImageFieldData(x){let B=typeof x==="string"?x:x?.field;if(B==="coverImageId"||B==="ogImageId")return{targetImageField:B};return{}}}function A80(x){return typeof x==="string"?x.length>0:x!==void 0}var qd8=X.object({id:X.string().min(1)});async function $Fx(x,B){let{bodyContent:A,coverImageId:w,documents:f,sourceEntityType:D,sourceEntityId:$}=zd8(B.content),Z=w?await Ud8(x,w):void 0,Q;if(f&&f.length>0){let W=await Gd8(x,f);if(W.length>0)Q=W}Q??=await Vd8(x,D,$);let Y={bodyContent:A};if(Z)Y.imageData=Z;if(Q&&Q.length>0)Y.documentData=Q;return Y}function zd8(x){try{let B=G9(x,X.record(X.string(),X.unknown())),A=B.metadata.coverImageId,w=typeof A==="string"?A:void 0,f=bd8(B.metadata.documents),D=DFx(B.metadata.sourceEntityType),$=DFx(B.metadata.sourceEntityId);return{bodyContent:B.content,...w&&{coverImageId:w},...f.length>0&&{documents:f},...D&&{sourceEntityType:D},...$&&{sourceEntityId:$}}}catch{return{bodyContent:x}}}function bd8(x){if(!Array.isArray(x))return[];return x.flatMap((B)=>{let A=qd8.safeParse(B);return A.success?[A.data]:[]})}function DFx(x){return typeof x==="string"&&x.length>0?x:void 0}async function Vd8(x,B,A){if(!B||!A)return;let w=await x.attachments.resolve({sourceEntityType:B,sourceEntityId:A,attachmentType:"carousel"});return w?[w]:void 0}async function Ud8(x,B){let A=await x.entityService.getEntity({entityType:"image",id:B});if(!A?.content)return;let w=ZFx(A.content);if(!w?.mimeType.startsWith("image/"))return;return{data:w.data,mimeType:w.mimeType}}async function Gd8(x,B){return(await Promise.all(B.map((w)=>Ed8(x,w)))).filter((w)=>w!==void 0)}async function Ed8(x,B){let A=await x.entityService.getEntity({entityType:"document",id:B.id});if(!A?.content)return;let w=ZFx(A.content);if(w?.mimeType!=="application/pdf")return;return{type:"document",data:w.data,mimeType:"application/pdf",filename:jd8(A,B.id)}}function ZFx(x){let B=x.match(/^data:([^;]+);base64,(.+)$/);if(!B?.[1]||!B[2])return;return{mimeType:B[1],data:Buffer.from(B[2],"base64")}}function jd8(x,B){let A=x.metadata.filename;return typeof A==="string"&&A.length>0?A:`${B}.pdf`}var _d8=/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/;async function w80(x,B,A,w={}){let f=w.publishTimestampField??"publishedAt",D=B.metadata[f],$=w.publishedAt??(typeof D==="string"?D:void 0)??new Date().toISOString(),Z={...B.metadata,status:"published",[f]:$,platformId:A.id,...Pd8(A.id,w.publishResultIdField)},Q={...B,content:QFx(B.content,$,A.id,w.publishResultIdField,f),metadata:Z};return await x.entityService.updateEntity({entity:Q}),Q}function QFx(x,B,A,w,f="publishedAt"){if(!_d8.test(x))return x;let D=h3(h3(x,"status","published"),f,B);if(!A||!w)return D;return h3(D,w,A)}function Pd8(x,B){if(!B||B==="platformId")return{};return{[B]:x}}class tX{deps;constructor(x){this.deps=x}async resolveCandidate(x){let{entityType:B,id:A,slug:w}=x;if(!A&&!w)return{error:"Either 'id' or 'slug' must be provided"};let f=await this.findPublishableEntity(B,A,w);if(!f)return{error:`Entity not found: ${B}:${A??w}`};if(f.visibility!=="public")return{error:`Cannot publish ${B}:${f.id} to a public provider because visibility is ${f.visibility}`};if(f.metadata.status==="published")return{error:"Entity is already published"};if(!this.deps.providerRegistry.has(B))return{error:`No publish provider registered for ${B}. Check that the required credentials are configured.`};return{entity:f}}async publish(x){let B=await this.resolveCandidate(x);if("error"in B)return B;let{entity:A}=B,{entityType:w}=x,f=this.deps.providerRegistry.get(w),{bodyContent:D,imageData:$,documentData:Z}=await $Fx(this.deps.context,A),Q=await f.publish(D,A.metadata,$,Z),Y=this.deps.providerRegistry.getPublishResultIdField(w),W=this.deps.providerRegistry.getPublishTimestampField(w),H=await w80(this.deps.context,A,Q,{...Y?{publishResultIdField:Y}:{},...W?{publishTimestampField:W}:{}});return await this.runPublishAssetPreflight(H),{entity:H,result:Q}}async runPublishAssetPreflight(x){if(!this.deps.publishAssetPreflight)return;try{await this.deps.publishAssetPreflight.ensureForEntity(x)}catch(B){this.deps.context.logger.warn("Publish asset preflight failed",{entityType:x.entityType,entityId:x.id,error:g(B)})}}async findPublishableEntity(x,B,A){if(B)return this.deps.context.entityService.getEntity({entityType:x,id:B});if(!A)return null;return(await this.deps.context.entityService.listEntities({entityType:x,options:{filter:{metadata:{slug:A}},limit:1}}))[0]??null}}var eI6=X.object({action:X.enum(["list","add","remove","reorder"]).describe("Queue action to perform"),entityType:X.string().optional().describe("Entity type (required for add/remove/reorder, optional for list)"),entityId:X.string().optional().describe("Entity ID (required for add/remove/reorder)"),position:X.number().optional().describe("New position for reorder action (1-based)")}),f80=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),Jd8=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array(f80).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),Ld8=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),qO=X.union([Jd8,Ld8]);async function zO(x,B,A,w,f){let{action:D,entityType:$,entityId:Z,position:Q}=w;switch(D){case"list":return kd8(B,$);case"add":return vd8(x,A,$,Z,f);case"remove":return Nd8(x,A,$,Z,f);case"reorder":return Id8(x,A,$,Z,Q,f)}}async function kd8(x,B){let A=[];if(B)A=await x.list(B);else{let f=x.getRegisteredTypes();for(let D of f){let $=await x.list(D);A.push(...$)}A.sort((D,$)=>new Date(D.queuedAt).getTime()-new Date($.queuedAt).getTime())}if(A.length===0)return{success:!0,data:{queue:Md8()},message:"No items in queue"};return{success:!0,data:{queue:A.map((f,D)=>({position:D+1,entityType:f.entityType,entityId:f.entityId,queuedAt:f.queuedAt}))},message:`${A.length} items in queue`}}function Md8(){return[]}async function vd8(x,B,A,w,f){let D=D80("add",A,w);if(!D.success)return D.error;x.permissions.assertEntityActionAllowed(D.entityType,"publish",f??{});let $=await B.add(D.entityType,D.entityId,{...f,authorization:"user"});return{success:!0,data:{entityType:D.entityType,entityId:D.entityId,position:$.position},message:`Added to queue at position ${$.position}`}}async function Nd8(x,B,A,w,f){let D=D80("remove",A,w);if(!D.success)return D.error;return x.permissions.assertEntityActionAllowed(D.entityType,"update",f??{}),await B.remove(D.entityType,D.entityId),{success:!0,data:{entityType:D.entityType,entityId:D.entityId},message:"Removed from queue"}}async function Id8(x,B,A,w,f,D){let $=D80("reorder",A,w);if(!$.success)return $.error;let Z=Od8(f);if(!Z.success)return Z.error;return x.permissions.assertEntityActionAllowed($.entityType,"update",D??{}),await B.reorder($.entityType,$.entityId,Z.position),{success:!0,data:{entityType:$.entityType,entityId:$.entityId,position:Z.position},message:`Moved to position ${Z.position}`}}function D80(x,B,A){if(!B)return{success:!1,error:{success:!1,error:`entityType is required for ${x} action`}};if(!A)return{success:!1,error:{success:!1,error:`entityId is required for ${x} action`}};return{success:!0,entityType:B,entityId:A}}function Od8(x){if(x===void 0)return{success:!1,error:{success:!1,error:"position is required for reorder action"}};if(x<1)return{success:!1,error:{success:!1,error:"position must be a positive number"}};return{success:!0,position:x}}import{createHash as hd8}from"crypto";var DO6=X.object({entityType:X.string().describe("Entity type to publish (e.g., social-post, post, deck)"),id:X.string().optional().describe("Entity ID to publish"),slug:X.string().optional().describe("Entity slug to publish"),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()}),Rd8=X.object({entityType:X.string(),id:X.string().optional(),slug:X.string().optional(),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()}),yd8=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({entityType:X.string().optional(),entityId:X.string().optional(),platformId:X.string().optional(),url:X.string().optional()}).optional()}),md8=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),Cd8=X.object({success:X.literal(!1).optional(),error:X.string().optional(),needsConfirmation:X.literal(!0),toolName:X.string(),summary:X.string(),preview:X.string().optional(),args:X.custom()}),bO=X.union([yd8,md8,Cd8]),cd8=900000;async function nK(x){let B=Rd8.safeParse(x.rawInput);if(!B.success)return{success:!1,error:`Invalid input: ${B.error.issues.map((Q)=>`${Q.path.join(".")}: ${Q.message}`).join(", ")}`};let A=B.data,{entityType:w,id:f,slug:D}=A;try{x.context.permissions.assertEntityActionAllowed(w,"publish",x.toolContext)}catch(Q){return{success:!1,error:g(Q)}}let $=await x.executor.resolveCandidate({entityType:w,id:f,slug:D});if("error"in $)return{success:!1,error:$.error};let{entity:Z}=$;if(A.confirmed){let Q=Td8(x.toolName,A,Z);if(Q!==null)return Q;let Y;try{Y=await x.executor.publish({entityType:w,id:Z.id})}catch(F){return{success:!1,error:g(F)}}if("error"in Y)return{success:!1,error:Y.error};let{entity:W,result:H}=Y;return{success:!0,data:{entityType:w,entityId:W.id,platformId:H.id,url:H.url},message:`Published ${w}:${W.id}`}}return gd8(x.toolName,A,Z)}function gd8(x,B,A){let w=new Date(Date.now()+cd8).toISOString(),f=XFx(x,A,w),D=pd8(A);return{needsConfirmation:!0,toolName:x,summary:`Publish "${D}"?`,preview:`This will publish ${A.entityType}:${A.id} to its registered public publish provider.`,args:{...B,id:A.id,slug:void 0,confirmed:!0,confirmationToken:f,contentHash:A.contentHash,expiresAt:w}}}function Td8(x,B,A){let{confirmationToken:w,contentHash:f,expiresAt:D}=B;if(!w||!D)return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};let $=Date.parse(D);if(Number.isNaN($))return{success:!1,error:"Invalid publish confirmation expiry. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};if($<=Date.now())return{success:!1,error:"Publish confirmation expired. Request confirmation again before publishing.",code:"EXPIRED_CONFIRMATION_TOKEN"};if(f&&f!==A.contentHash)return{success:!1,error:`Cannot publish ${A.entityType}:${A.id} because it changed after confirmation. Review it and try again.`};if(w!==XFx(x,A,D))return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};return null}function XFx(x,B,A){return hd8("sha256").update(x).update("\x00").update(B.entityType).update("\x00").update(B.id).update("\x00").update(B.contentHash).update("\x00").update(A).digest("hex")}function pd8(x){let B=x.metadata.title;if(typeof B==="string"&&B.length>0)return B;let A=x.metadata.subject;if(typeof A==="string"&&A.length>0)return A;let w=x.metadata.slug;if(typeof w==="string"&&w.length>0)return w;return x.id}var $80=X.object({action:X.enum(["queue-list","queue-add","queue-remove","queue-reorder","publish"]).describe("Publishing action to perform"),entityType:X.string().optional().describe("Entity type for queue operations or direct publish, such as social-post, post, newsletter, or deck"),entityId:X.string().optional().describe("Entity ID for queue add/remove/reorder operations"),position:X.number().optional().describe("New 1-based position for queue-reorder"),id:X.string().optional().describe("Entity ID to publish"),slug:X.string().optional().describe("Entity slug to publish"),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()}),ud8=X.discriminatedUnion("action",[X.object({action:X.literal("queue-list"),entityType:X.string().optional()}),X.object({action:X.literal("queue-add"),entityType:X.string().min(1),entityId:X.string().min(1)}),X.object({action:X.literal("queue-remove"),entityType:X.string().min(1),entityId:X.string().min(1)}),X.object({action:X.literal("queue-reorder"),entityType:X.string().min(1),entityId:X.string().min(1),position:X.number().int().positive()}),X.object({action:X.literal("publish"),entityType:X.string().min(1),id:X.string().optional(),slug:X.string().optional(),confirmed:X.boolean().optional(),confirmationToken:X.string().optional(),contentHash:X.string().optional(),expiresAt:X.string().datetime().optional()})]),Z80=X.union([qO,bO]);function UO(x,B){let A=B.publicationQueueService??B.queueManager,w=B.publishExecutor??new tX({context:x,providerRegistry:B.providerRegistry});return{name:"publishing_manage",description:"Manage publishing with an action discriminator. Use action=queue-list to inspect the publish queue; action=queue-add to queue an entity for publication; action=queue-remove to remove a queued entity; action=queue-reorder to change queue order; action=publish to publish one entity directly. Direct publish requests confirmation inside this tool; call action=publish without confirmed first, then retry with the returned confirmation args.",inputSchema:$80.shape,outputSchema:Z80,visibility:"admin",sideEffects:"external",handler:async(f,D)=>{let $=ud8.safeParse(f);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.issues.map((Z)=>`${Z.path.join(".")}: ${Z.message}`).join(", ")}`};return Sd8({context:x,queueManager:B.queueManager,queueMutations:A,publishExecutor:w,input:$.data,toolContext:D})}}}async function Sd8(x){switch(x.input.action){case"queue-list":return VO(x,{action:"list",entityType:x.input.entityType});case"queue-add":return VO(x,{action:"add",entityType:x.input.entityType,entityId:x.input.entityId});case"queue-remove":return VO(x,{action:"remove",entityType:x.input.entityType,entityId:x.input.entityId});case"queue-reorder":return VO(x,{action:"reorder",entityType:x.input.entityType,entityId:x.input.entityId,position:x.input.position});case"publish":return ld8(await nK({context:x.context,executor:x.publishExecutor,toolName:"publishing_manage",rawInput:id8(x.input),toolContext:x.toolContext}))}}function VO(x,B){return zO(x.context,x.queueManager,x.queueMutations,B,x.toolContext)}function id8(x){let B={entityType:x.entityType};if(x.id!==void 0)B.id=x.id;if(x.slug!==void 0)B.slug=x.slug;if(x.confirmed!==void 0)B.confirmed=x.confirmed;if(x.confirmationToken!==void 0)B.confirmationToken=x.confirmationToken;if(x.contentHash!==void 0)B.contentHash=x.contentHash;if(x.expiresAt!==void 0)B.expiresAt=x.expiresAt;return B}function ld8(x){if(!("needsConfirmation"in x))return x;return{...x,toolName:"publishing_manage",args:{action:"publish",...x.args}}}var YFx=X.object({entityType:X.string().min(1).describe("Entity type to reconcile"),status:X.string().min(1).optional().describe("Optional metadata status filter, e.g. published"),assetType:X.string().min(1).optional().describe("Optional attachment type filter, e.g. og-image")}),WFx=X.object({success:X.literal(!0),data:X.object({entityType:X.string(),assetType:X.string().optional(),checkedEntities:X.number(),checkedAssets:X.number(),enqueued:X.number(),skipped:X.number()}),message:X.string().optional()});var dd8="content-pipeline.queue.v1",Q80=1024,ad8=/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/,sd8=X.object({interfaceType:X.string().optional(),actor:SA.optional(),userPermissionLevel:X.enum(["public","trusted","admin"]).optional(),authorization:X.enum(["user","system"]).optional()}),rd8=X.object({entityType:X.string(),entityId:X.string(),rank:X.number().int().positive(),queuedAt:X.string().datetime(),contentHashAtEnqueue:X.string(),authContext:sd8,revision:X.number().int().positive()});class X80{context;queueManager;store;mutationTail=Promise.resolve();constructor(x,B){this.context=x,this.queueManager=B,this.store=x.runtimeState.scoped({namespace:dd8,schema:rd8})}async add(x,B,A=Lf){return this.enqueue(x,B,A)}async enqueue(x,B,A=Lf){return this.runExclusive(async()=>{let w=await this.requireEntity(x,B);await this.persistStatus(w,"queued");let f=await this.queueManager.add(x,B,A);if(!await this.store.get(NB(x,B))){let $=(await this.queueManager.list(x)).find((Q)=>Q.entityId===B),Z=await this.requireEntity(x,B);await this.store.set(NB(x,B),{entityType:x,entityId:B,rank:f.position*Q80,queuedAt:$?.queuedAt??new Date().toISOString(),contentHashAtEnqueue:Z.contentHash,authContext:{...A},revision:1})}return f})}async remove(x,B){await this.runExclusive(async()=>{let A=await this.requireEntity(x,B);if(A.metadata.status==="queued")await this.persistStatus(A,"draft");await this.queueManager.remove(x,B),await this.store.delete(NB(x,B)),await this.persistCurrentOrder(x)})}async reorder(x,B,A){await this.runExclusive(async()=>{await this.requireEntity(x,B),await this.queueManager.reorder(x,B,A),await this.persistCurrentOrder(x)})}async complete(x,B){await this.runExclusive(async()=>{await this.queueManager.remove(x,B),await this.store.delete(NB(x,B)),await this.persistCurrentOrder(x)})}async fail(x,B,A){await this.runExclusive(async()=>{let w=await this.context.entityService.getEntity({entityType:x,id:B});if(w)await this.persistStatus(w,"failed",A);await this.queueManager.remove(x,B),await this.store.delete(NB(x,B)),await this.persistCurrentOrder(x)})}async reconcile(x){await this.runExclusive(async()=>{let B=new Map;for(let Q of x){let Y=await this.context.entityService.listEntities({entityType:Q,options:{filter:{metadata:{status:"queued"}}}});for(let W of Y)B.set(NB(Q,W.id),W)}let A=await this.listStored();for(let Q of A)if(!B.has(NB(Q.entityType,Q.entityId)))await this.store.delete(NB(Q.entityType,Q.entityId));let w=(await this.listStored()).filter((Q)=>B.has(NB(Q.entityType,Q.entityId))),f=new Map;for(let Q of w)f.set(Q.entityType,Math.max(f.get(Q.entityType)??0,Q.rank));for(let[Q,Y]of B){if(w.some((H)=>NB(H.entityType,H.entityId)===Q))continue;let W=(f.get(Y.entityType)??0)+Q80;f.set(Y.entityType,W),await this.store.set(Q,{entityType:Y.entityType,entityId:Y.id,rank:W,queuedAt:typeof Y.updated==="string"?Y.updated:new Date().toISOString(),contentHashAtEnqueue:Y.contentHash,authContext:{...Lf},revision:1})}let D=await this.listStored(),$=new Map,Z=D.map((Q)=>{let Y=($.get(Q.entityType)??0)+1;return $.set(Q.entityType,Y),{entityType:Q.entityType,entityId:Q.entityId,position:Y,queuedAt:Q.queuedAt,authContext:{...Q.authContext}}});this.queueManager.replace(Z)})}async listStored(x){return(await this.store.list()).map((B)=>B.value).filter((B)=>!x||B.entityType===x).sort((B,A)=>B.entityType.localeCompare(A.entityType)||B.rank-A.rank||B.queuedAt.localeCompare(A.queuedAt)||B.entityId.localeCompare(A.entityId))}async deleteStored(x,B){return this.store.delete(NB(x,B))}async persistCurrentOrder(x){let B=new Map((await this.listStored(x)).map((A)=>[A.entityId,A]));for(let A of await this.queueManager.list(x)){let w=B.get(A.entityId);if(!w)continue;let f=A.position*Q80;if(w.rank===f)continue;await this.store.set(NB(x,A.entityId),{...w,rank:f,revision:w.revision+1})}}async persistStatus(x,B,A){let w={...x.metadata,status:B};if(A)w.error=A;else delete w.error;let f=ad8.test(x.content)?h3(x.content,"status",B):x.content;await this.context.entityService.updateEntity({entity:{...x,metadata:w,content:f}})}async requireEntity(x,B){let A=await this.context.entityService.getEntity({entityType:x,id:B});if(!A)throw Error(`Entity not found: ${x}:${B}`);return A}runExclusive(x){let B=this.mutationTail.then(x);return this.mutationTail=B.then(()=>{return},()=>{return}),B}}function NB(x,B){return`${encodeURIComponent(x)}/${encodeURIComponent(B)}`}function HFx(x,B){od8(x,B),td8(x,B),ed8(x,B),xa8(x,B)}function od8(x,B){x.messaging.subscribe(N1.REGISTER,async(A)=>Ba8(B,A.payload)),x.messaging.subscribe(N1.QUEUE,async(A)=>Da8(x,B,A.payload)),x.messaging.subscribe(N1.DIRECT,async(A)=>$a8(x,B,A.payload)),x.messaging.subscribe(N1.REMOVE,async(A)=>Za8(B,A.payload)),x.messaging.subscribe(N1.REORDER,async(A)=>Qa8(B,A.payload)),x.messaging.subscribe(N1.LIST,async(A)=>Xa8(x,B,A.payload)),x.messaging.subscribe(N1.REPORT_SUCCESS,async(A)=>Ya8(B,A.payload)),x.messaging.subscribe(N1.REPORT_FAILURE,async(A)=>Wa8(B,A.payload)),x.messaging.subscribe(N1.COMPLETED,async(A)=>{return await B.publicationQueueService.complete(A.payload.entityType,A.payload.entityId),{success:!0}}),x.messaging.subscribe(N1.FAILED,async(A)=>{return await B.publicationQueueService.fail(A.payload.entityType,A.payload.entityId,A.payload.error),{success:!0}}),B.logger.debug("Subscribed to publish messages")}function td8(x,B){x.messaging.subscribe(a$.REPORT_SUCCESS,async(A)=>Ha8(B,A.payload)),x.messaging.subscribe(a$.REPORT_FAILURE,async(A)=>Fa8(B,A.payload)),B.logger.debug("Subscribed to generation messages")}function ed8(x,B){x.messaging.subscribe(rHx.REGISTER,async(A)=>Aa8(B,A.payload)),B.logger.debug("Subscribed to publish asset messages")}function xa8(x,B){let A=async(w)=>wa8(x,B,w.payload);x.messaging.subscribe(l8.created,A),x.messaging.subscribe(l8.updated,A),B.logger.debug("Subscribed to entity change messages for publish assets")}async function Ba8(x,B){let{entityType:A,provider:w,config:f}=B;try{let D=f?oHx.safeParse(f):void 0;if(D&&!D.success)return x.logger.warn("Invalid publish provider config",{entityType:A,error:D.error.message}),{success:!1};if(w)x.providerRegistry.register(A,w,D?.data),x.logger.info(`Registered provider for entity type: ${A}`,{providerName:w.name,executionMode:x.providerRegistry.getExecutionMode(A)});return{success:!0}}catch(D){let $=g(D);return x.logger.error(`Failed to register provider: ${$}`),{success:!1}}}async function Aa8(x,B){let A=FO.safeParse(B);if(!A.success)return x.logger.warn("Invalid publish asset registration",{error:A.error.message}),{success:!1};return x.publishAssetRegistry.register(A.data),x.logger.info("Registered publish asset",{entityType:A.data.entityType,attachmentType:A.data.attachmentType,mediaEntityType:A.data.mediaEntityType}),{success:!0}}async function wa8(x,B,A){try{if(B.publishAssetRegistry.list(A.entityType).length===0)return{success:!0};let w=A.entity??await x.entityService.getEntity({entityType:A.entityType,id:A.entityId});if(!fa8(w))return{success:!0};return await B.publishAssetPreflight.ensureForEntity(w),{success:!0}}catch(w){return B.logger.warn("Failed to run publish asset preflight for entity event",{entityType:A.entityType,entityId:A.entityId,error:g(w)}),{success:!1}}}function fa8(x){if(!x)return!1;let B=sHx.safeParse(x.metadata);return B.success&&B.data.status==="published"}async function Da8(x,B,A){let{entityType:w,entityId:f}=A;try{let D=A.authContext??Lf;x.permissions.assertEntityActionAllowed(w,"publish",D);let $=await B.publicationQueueService.enqueue(w,f,D);return await x.messaging.send({type:N1.QUEUED,payload:{entityType:w,entityId:f,position:$.position}}),B.logger.debug(`Entity queued: ${f}`,{entityType:w,position:$.position}),{success:!0}}catch(D){let $=g(D);return B.logger.error(`Failed to queue entity: ${$}`),{success:!1}}}async function $a8(x,B,A){let{entityType:w,entityId:f}=A,D=A.authContext??Lf;try{if(x.permissions.assertEntityActionAllowed(w,"publish",D),!B.providerRegistry.has(w))return B.scheduler.failPublish(w,f,`No publish provider registered for ${w}`),{success:!1};let $=await B.publishExecutor.publish({entityType:w,id:f});if("error"in $)return B.scheduler.failPublish(w,f,$.error),{success:!1};return B.scheduler.completePublish(w,f,$.result),B.logger.debug(`Direct publish completed: ${f}`,{entityType:w}),{success:!0}}catch($){let Z=g($);return B.logger.error(`Failed direct publish request: ${Z}`),{success:!1}}}async function Za8(x,B){let{entityType:A,entityId:w}=B;try{return await x.publicationQueueService.remove(A,w),x.logger.debug(`Entity removed from queue: ${w}`,{entityType:A}),{success:!0}}catch(f){let D=g(f);return x.logger.error(`Failed to remove entity: ${D}`),{success:!1}}}async function Qa8(x,B){let{entityType:A,entityId:w,position:f}=B;try{return await x.publicationQueueService.reorder(A,w,f),x.logger.debug(`Entity reordered: ${w}`,{entityType:A,newPosition:f}),{success:!0}}catch(D){let $=g(D);return x.logger.error(`Failed to reorder entity: ${$}`),{success:!1}}}async function Xa8(x,B,A){let{entityType:w}=A;try{let f=await B.queueManager.list(w);return await x.messaging.send({type:N1.LIST_RESPONSE,payload:{entityType:w,queue:f.map((D)=>({entityId:D.entityId,position:D.position,queuedAt:D.queuedAt}))}}),{success:!0}}catch(f){let D=g(f);return B.logger.error(`Failed to list queue: ${D}`),{success:!1}}}async function Ya8(x,B){let{entityType:A,entityId:w,result:f}=B;return x.scheduler.completePublish(A,w,f),x.logger.info(`Publish reported success: ${w}`,{entityType:A}),{success:!0}}async function Wa8(x,B){let{entityType:A,entityId:w,error:f}=B;x.scheduler.failPublish(A,w,f);let D=x.retryTracker.getRetryInfo(w);return x.logger.info(`Publish reported failure: ${w}`,{entityType:A,error:f,retryCount:D?.retryCount}),{success:!0}}async function Ha8(x,B){let{entityType:A,entityId:w}=B;return x.scheduler.completeGeneration(A,w),x.logger.info("Generation completed",{entityType:A,entityId:w}),{success:!0}}async function Fa8(x,B){let{entityType:A,error:w}=B;return x.scheduler.failGeneration(A,w),x.logger.warn("Generation failed",{entityType:A,error:w}),{success:!0}}async function FFx(x,B,A,w){try{if(w.skipIfDraftExists!==!1){if((await x.listEntities({entityType:A,options:{filter:{metadata:{status:"draft"}},limit:1}})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(w.maxUnpublishedDrafts!==void 0){let f=await x.listEntities({entityType:A,options:{filter:{metadata:{status:"draft"}},limit:w.maxUnpublishedDrafts+1}});if(f.length>=w.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${f.length}/${w.maxUnpublishedDrafts})`}}if(w.minSourceEntities!==void 0&&w.sourceEntityType){let f=await x.listEntities({entityType:w.sourceEntityType,options:{publishedOnly:!0,limit:w.minSourceEntities}});if(f.length<w.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${f.length}/${w.minSourceEntities} ${w.sourceEntityType})`}}return{shouldGenerate:!0}}catch(f){return B.error("Failed to check generation conditions",{entityType:A,error:g(f)}),{shouldGenerate:!1,reason:`Condition check failed: ${g(f)}`}}}function KFx(x){let{context:B,config:A,queueManager:w,providerRegistry:f,retryTracker:D,publishExecutor:$,logger:Z}=x,Q=Ka8(B);return rE.createFresh({queueManager:w,providerRegistry:f,retryTracker:D,logger:Z,backend:new HO({onOverlapSkipped:(Y)=>{Z.debug("Skipping overlapping content scheduler cycle",{jobKey:Y})},onCallbackError:(Y,W)=>{Z.error("Unhandled content scheduler callback error",{jobKey:Y,error:W})}}),...A.entitySchedules&&{entitySchedules:A.entitySchedules},...A.generationSchedules&&{generationSchedules:A.generationSchedules},...A.generationConditions&&{generationConditions:A.generationConditions},messageBus:Q,publishExecutor:$,onCheckGenerationConditions:(Y,W)=>FFx(B.entityService,Z,Y,W)})}function Ka8(x){return{send:async(f)=>{return x.messaging.send({type:f.type,payload:f.payload,...f.target!==void 0?{target:f.target}:{},...f.metadata!==void 0?{metadata:f.metadata}:{},...f.broadcast!==void 0?{broadcast:f.broadcast}:{}})},subscribe:()=>()=>{},unsubscribe:()=>{}}}var qFx=X.enum(["draft","queued","published","failed"]),qa8=X.object({entityId:X.string(),entityType:X.string(),title:X.string(),position:X.number().int().positive(),queuedAt:X.string(),destination:X.string(),scheduledFor:X.string().optional()}),za8=X.object({id:X.string(),label:X.string(),target:X.string(),status:X.enum(["pending","processing"])}),ba8=X.object({entityId:X.string(),entityType:X.string(),title:X.string(),error:X.string(),retryCount:X.number().int().nonnegative()}),Va8=X.object({summary:X.object({draft:X.number().int().nonnegative(),queued:X.number().int().nonnegative(),generating:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),published:X.number().int().nonnegative(),needsOperator:X.number().int().nonnegative()}),queue:X.array(qa8),generating:X.array(za8),failures:X.array(ba8),publishableEntityTypes:X.array(X.string())}),Ua8=X.object({sourceEntityType:X.string(),sourceEntityId:X.string(),attachmentType:X.string().optional()});async function GO(x,B,A,w,f={}){let D=(f.entityTypes??B.getRegisteredTypes()).sort(),$=new Map,Z={draft:0,queued:0,generating:0,failed:0,published:0,needsOperator:0};for(let H of D){let F=await x.entityService.listEntities({entityType:H,...f.visibilityScope?{options:{filter:{visibilityScope:f.visibilityScope}}}:{}});for(let K of F){let q=qFx.safeParse(K.metadata.status);if(!q.success)continue;Z[q.data]+=1;let V=K.metadata.scheduledFor,b=K.metadata.error;$.set(Y80(H,K.id),{entityId:K.id,entityType:H,title:Ea8(K.id,K.metadata),status:q.data,...typeof V==="string"?{scheduledFor:V}:{},...typeof b==="string"?{error:b}:{}})}}let Q=[];for(let H of D){let F=B.get(H).name,K=0;for(let q of await A.list(H)){let V=$.get(Y80(H,q.entityId));if(!V)continue;K+=1,Q.push({entityId:q.entityId,entityType:H,title:V.title,position:K,queuedAt:q.queuedAt,destination:F,...V.scheduledFor?{scheduledFor:V.scheduledFor}:{}})}}let Y=await Ga8(x,f.visibilityScope&&f.visibilityScope!=="restricted"?$:void 0);Z.generating=Y.length;let W=Array.from($.values()).filter((H)=>H.status==="failed").map((H)=>{let F=w.getRetryInfo(H.entityId);return{entityId:H.entityId,entityType:H.entityType,title:H.title,error:H.error??F?.lastError??"Publication failed",retryCount:F?.retryCount??0}}).sort((H,F)=>H.title.localeCompare(F.title));return Z.needsOperator=Z.draft+Z.failed,Va8.parse({summary:Z,queue:Q,generating:Y,failures:W,publishableEntityTypes:D})}async function Ga8(x,B){let A=[];for(let w of await x.jobs.getActiveJobs()){if(w.source!=="content-pipeline")continue;if(w.status!=="pending"&&w.status!=="processing")continue;let f;try{f=JSON.parse(w.data)}catch{continue}let D=Ua8.safeParse(f);if(!D.success)continue;if(B&&!B.has(Y80(D.data.sourceEntityType,D.data.sourceEntityId)))continue;A.push({id:w.id,label:D.data.attachmentType??w.type,target:`${D.data.sourceEntityType}/${D.data.sourceEntityId}`,status:w.status})}return A}function Y80(x,B){return`${x}\x00${B}`}function zFx(x){return qFx.safeParse(x).success}function Ea8(x,B){for(let A of["title","subject","slug"]){let w=B[A];if(typeof w==="string"&&w.length>0)return w}return x}async function bFx(x,B,A){await x.dashboard.registerWidget({id:"publication-pipeline",title:"Publication Pipeline",group:"publishing",section:"primary",priority:100,rendererName:"PipelineWidget",visibility:"admin",dataProvider:async()=>({...await GO(x,A.providerRegistry,A.queueManager,A.retryTracker),...A.managementUrl?{managementUrl:A.managementUrl}:{}}),digestProvider:_a8})}var ja8=X.object({summary:X.object({draft:X.number(),queued:X.number(),generating:X.number(),published:X.number(),failed:X.number(),needsOperator:X.number()})});function _a8(x){let{summary:B}=ja8.parse(x),A=B.queued+B.generating,w=A===0?"idle":`${B.queued} queued \xB7 ${B.generating} generating`,f=B.failed>0?`${B.draft} drafts \xB7 ${B.failed} failed`:`${B.draft} drafts`;return{digest:[{label:"Pipeline",value:w,...A>0?{tone:"warn"}:{}},{label:"Awaiting review",value:f,...B.needsOperator>0?{tone:"warn"}:{}},{label:"Published",value:String(B.published),tone:"good"}],needsAttention:B.needsOperator}}var Pa8=X.object({workspaceUrl:X.string()}),Ja8=X.object({confirmed:X.literal(!0),confirmationToken:X.string().min(1),contentHash:X.string().min(1),expiresAt:X.string().datetime()}),La8=X.discriminatedUnion("type",[X.object({type:X.literal("queue"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1)}),X.object({type:X.literal("remove"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1)}),X.object({type:X.literal("retry"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1)}),X.object({type:X.literal("reorder"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1),position:X.number().int().positive()}),X.object({type:X.literal("publish"),entityType:X.string().trim().min(1),entityId:X.string().trim().min(1),confirmation:Ja8.optional()})]);async function VFx(x,B,A){let w={id:"publishing",pluginId:B,label:"Publishing",rendererName:"PublishingWorkspace",priority:40,entityTypes:($)=>W80(x,A.providerRegistry,$),accessHandler:($)=>W80(x,A.providerRegistry,$).length>0,dataProvider:($)=>GO(x,A.providerRegistry,A.queueManager,A.retryTracker,{visibilityScope:$.visibilityScope,entityTypes:W80(x,A.providerRegistry,$)}),actionHandler:async($,Z)=>{let Q=La8.safeParse($);if(!Q.success)throw Error("Invalid publishing workspace action");return ka8(x,A,Q.data,Z)}},f=await x.messaging.send({type:WO,payload:w});if(!("success"in f)||!f.success)return;let D=Pa8.safeParse(f.data);return D.success?D.data.workspaceUrl:void 0}function UFx(x){return{interfaceType:x.interfaceType,actor:x.actor,userPermissionLevel:x.userPermissionLevel}}function W80(x,B,A){let w=UFx(A),f=["update","publish"];return B.getRegisteredTypes().filter((D)=>{for(let $ of f)try{return x.permissions.assertEntityActionAllowed(D,$,w),!0}catch{}return!1})}async function ka8(x,B,A,w){if(!B.providerRegistry.has(A.entityType))throw Error(`No publish provider registered for ${A.entityType}`);let f=await x.entityService.getEntity({entityType:A.entityType,id:A.entityId,visibilityScope:w.visibilityScope});if(!f)throw Error(`Entity not found: ${A.entityType}:${A.entityId}`);let D=UFx(w);if(A.type==="publish"){let Q=await nK({context:x,executor:B.publishExecutor,toolName:"publishing_manage",rawInput:{entityType:A.entityType,id:A.entityId,...A.confirmation??{}},toolContext:D});if("success"in Q&&Q.success===!0)await B.publicationQueueService.complete(A.entityType,A.entityId),B.retryTracker.clearRetries(A.entityId);return Q}let $=A.type==="queue"||A.type==="retry"?"publish":"update";x.permissions.assertEntityActionAllowed(A.entityType,$,D);let Z=f.metadata.status;switch(A.type){case"queue":if(Z!=="draft")throw Error("Only draft entities can be queued");return B.publicationQueueService.enqueue(A.entityType,A.entityId,{...D,authorization:"user"});case"remove":if(Z!=="queued")throw Error("Only queued entities can be removed from the queue");return await B.publicationQueueService.remove(A.entityType,A.entityId),{success:!0};case"retry":if(Z!=="failed")throw Error("Only failed publications can be retried");return await B.publicationQueueService.enqueue(A.entityType,A.entityId,{...D,authorization:"user"}),{success:!0};case"reorder":if(Z!=="queued")throw Error("Only queued entities can be reordered");return await B.publicationQueueService.reorder(A.entityType,A.entityId,await Ma8(x,B.queueManager,A.entityType,w,A.position)),{success:!0}}}async function Ma8(x,B,A,w,f){let D=[];for(let Z of await B.list(A)){let Q=await x.entityService.getEntity({entityType:A,id:Z.entityId,visibilityScope:w.visibilityScope});if(Q&&zFx(Q.metadata.status))D.push(Z)}let $=Math.min(Math.max(f,1),D.length);return D[$-1]?.position??f}var GFx={name:"@brains/content-pipeline",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Content pipeline plugin for managing entity publishing queues, scheduling, and generation",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/scheduler":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},exports:{".":{types:"./src/index.ts",default:"./src/index.ts"}},files:["src"],main:"src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"src/index.ts"};class H80 extends D8{pluginContext;queueManager;publicationQueueService;providerRegistry;retryTracker;publishExecutor;publishAssetRegistry;publishAssetPreflight;scheduler;constructor(x={}){super("content-pipeline",GFx,x,tHx)}async onRegister(x){this.pluginContext=x,this.queueManager=aE.createFresh(),this.publicationQueueService=new X80(x,this.queueManager),this.providerRegistry=sE.createFresh(),this.retryTracker=oE.createFresh(),this.publishAssetRegistry=tE.createFresh(),this.publishAssetPreflight=new KO({context:x,registry:this.publishAssetRegistry}),this.publishExecutor=new tX({context:x,providerRegistry:this.providerRegistry,publishAssetPreflight:this.publishAssetPreflight}),this.scheduler=KFx({context:x,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,logger:this.logger}),HFx(x,{queueManager:this.queueManager,publicationQueueService:this.publicationQueueService,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,publishAssetRegistry:this.publishAssetRegistry,publishAssetPreflight:this.publishAssetPreflight,scheduler:this.scheduler,logger:this.logger})}async onReady(x){await this.publicationQueueService.reconcile(this.providerRegistry.getRegisteredTypes());let B=await VFx(x,this.id,{providerRegistry:this.providerRegistry,queueManager:this.queueManager,publicationQueueService:this.publicationQueueService,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor});await bFx(x,this.id,{providerRegistry:this.providerRegistry,queueManager:this.queueManager,retryTracker:this.retryTracker,...B?{managementUrl:B}:{}}),await this.scheduler.start(),this.logger.info("Content pipeline plugin started")}async getTools(){if(!this.pluginContext)throw Error("Plugin context not initialized");return[UO(this.pluginContext,{queueManager:this.queueManager,publicationQueueService:this.publicationQueueService,providerRegistry:this.providerRegistry,publishExecutor:this.publishExecutor})]}async getInstructions(){return'## Publishing\n- Use `publishing_manage` to manage publishing actions.\n- Use `publishing_manage` with `action=queue-list`, `action=queue-add`, `action=queue-remove`, or `action=queue-reorder` for publish queue requests.\n- Use `publishing_manage` with `action=publish` to publish an entity directly to its platform (e.g. LinkedIn, Buttondown). This tool has its own confirmation flow; call it without `confirmed` when the user asks to publish instead of asking for plain-text confirmation. Follow-up requests like "publish it now" should target the entity just read, generated, or updated in the conversation, including a post just changed to draft.\n- Missing publish assets such as generated OG images are reconciled automatically during publishing; do not call a separate asset reconciliation tool.'}getQueueManager(){return this.queueManager}getPublicationQueueService(){return this.publicationQueueService}getProviderRegistry(){return this.providerRegistry}getRetryTracker(){return this.retryTracker}getPublishAssetRegistry(){return this.publishAssetRegistry}getScheduler(){return this.scheduler}async onShutdown(){await this.scheduler.stop()}}function F80(x={}){return new H80(x)}var EO="conversation-memory",k6="summary",k2="decision",IB="action-item",EFx="conversation-memory:project",K80="conversation-memory",jO="conversation-memory:ai-response",dK="conversation-memory:entities";var kf=X.object({start:X.string().datetime(),end:X.string().datetime()}),_Fx=X.object({title:X.string().min(1).describe("Brief topic or phase title"),summary:X.string().min(1).describe("Grounded prose summary"),timeRange:kf,sourceMessageCount:X.number().int().min(0),keyPoints:X.array(X.string())}),Na8=X.object({entries:X.array(_Fx)}),q80=X.object({identity:SA,identityAliases:X.array(SA).optional(),displayName:X.string().optional(),roles:X.array(X.enum(["user","assistant","system"])).min(1)}),_O=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),timeRange:kf.optional(),messageCount:X.number().int().min(0),entryCount:X.number().int().min(0),participants:X.array(q80).optional(),sourceHash:X.string(),projectionVersion:X.number().int().min(1)}),Ia8=X.preprocess((x)=>Oa8(x),q80);function Oa8(x){if(!ha8(x)||"identity"in x)return x;let{actorId:B,roles:A}=x;if(typeof B!=="string"||!Array.isArray(A))return x;let w=x.canonicalId,f=A.includes("assistant")?"assistant":"user",D=Array.isArray(x.sourceActorIds)?x.sourceActorIds.filter((Z)=>typeof Z==="string"):[],$=Array.from(new Map([B,...D].map((Z)=>{let Q=s$({actorId:Z,interfaceType:jFx(Z),role:f});return[O1(Q),Q]})).values());return{identity:s$({actorId:B,interfaceType:jFx(B),role:f,...typeof w==="string"?{canonicalId:w}:{}}),...$.length>0?{identityAliases:$}:{},...typeof x.displayName==="string"?{displayName:x.displayName}:{},roles:A}}function jFx(x){let B=x.indexOf(":");return B>0?x.slice(0,B):"legacy"}function ha8(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}var Ra8=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),timeRange:kf.optional(),messageCount:X.number().int().min(0),entryCount:X.number().int().min(0),participants:X.array(Ia8).optional(),sourceHash:X.string(),projectionVersion:X.number().int().min(1)}),eX=j8.extend({entityType:X.literal("summary"),metadata:Ra8});var eE=X.object({identity:SA,identityAliases:X.array(SA).optional(),displayName:X.string().optional()}),z80=X.preprocess((x)=>PFx(x,!0),eE),b80=X.object({identity:SA.optional(),identityAliases:X.array(SA).optional(),displayName:X.string().min(1)}),ya8=X.preprocess((x)=>PFx(x,!1),b80);function PFx(x,B){if(!ma8(x)||"identity"in x)return x;let A=x.actorId;if(typeof A!=="string")return B?x:{displayName:x.displayName};let w=A.indexOf(":"),f=x.canonicalId,D=A.startsWith("brain:")?"assistant":"user",$=Array.isArray(x.sourceActorIds)?x.sourceActorIds.filter((Q)=>typeof Q==="string"):[],Z=Array.from(new Map([A,...$].map((Q)=>{let Y=Q.indexOf(":"),W=s$({actorId:Q,interfaceType:Y>0?Q.slice(0,Y):"legacy",role:D});return[O1(W),W]})).values());return{identity:s$({actorId:A,interfaceType:w>0?A.slice(0,w):"legacy",role:D,...typeof f==="string"?{canonicalId:f}:{}}),...Z.length>0?{identityAliases:Z}:{},...typeof x.displayName==="string"?{displayName:x.displayName}:{}}}function ma8(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}var PO=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["active","superseded"]),decidedBy:X.array(eE).optional(),mentionedBy:X.array(eE).optional()}),Ca8=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["active","superseded"]),decidedBy:X.array(z80).optional(),mentionedBy:X.array(z80).optional()}),xY=j8.extend({entityType:X.literal("decision"),metadata:Ca8}),JO=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["open","done","dropped"]),assignedTo:X.array(b80).optional(),requestedBy:X.array(eE).optional()}),ca8=X.object({conversationId:X.string(),channelId:X.string(),channelName:X.string().optional(),interfaceType:X.string(),spaceId:X.string(),timeRange:kf,sourceSummaryId:X.string(),sourceMessageCount:X.number().int().min(0),projectionVersion:X.number().int().min(1),status:X.enum(["open","done","dropped"]),assignedTo:X.array(ya8).optional(),requestedBy:X.array(z80).optional()}),BY=j8.extend({entityType:X.literal("action-item"),metadata:ca8});var ga8=X.record(X.string(),X.unknown());class V80 extends ox{metadataSchema;constructor(x){super({entityType:x.entityType,purpose:x.purpose,schema:x.schema,frontmatterSchema:x.metadataSchema});this.metadataSchema=x.parseMetadata}composeContent(x,B,A){return this.buildMarkdown([`# ${x}`,"",B.trim(),""].join(`
5369
5369
  `),ga8.parse(A))}toMarkdown(x){return x.content}fromMarkdown(x){return{entityType:this.entityType,content:x,metadata:this.parseFrontMatter(x,this.metadataSchema)}}}class aK extends V80{constructor(){super({entityType:k2,purpose:"A decision recorded from a conversation.",schema:xY,metadataSchema:PO,parseMetadata:PO})}}class sK extends V80{constructor(){super({entityType:IB,purpose:"An action item captured from a conversation.",schema:BY,metadataSchema:JO,parseMetadata:JO})}}var Ta8=X.record(X.string(),X.unknown()),pa8=_O.extend({visibility:Z2.optional()});class OB extends ox{constructor(){super({entityType:k6,purpose:"A read-only, system-maintained summary derived from stored conversation messages.",schema:eX,frontmatterSchema:_O})}createContentBody(x){let B=["# Conversation Summary",""];for(let A of x)B.push(`## ${A.title}`),B.push(""),B.push(`Time: ${A.timeRange.start} \u2192 ${A.timeRange.end} `),B.push(`Messages summarized: ${A.sourceMessageCount}`),B.push(""),B.push(A.summary.trim()),B.push(""),this.appendList(B,"Key Points",A.keyPoints);return B.join(`
5370
5370
  `).trimEnd()+`
5371
5371
  `}composeContent(x,B){return this.buildMarkdown(this.createContentBody(x),Ta8.parse(B))}parseBody(x){return{entries:(x.startsWith("---")?this.extractBody(x):x).split(/^##\s+/m).slice(1).map((f)=>this.parseEntry(f)).filter((f)=>f!==null)}}toMarkdown(x){let{entries:B}=this.parseBody(x.content);return this.buildMarkdown(this.createContentBody(B),{...x.metadata,visibility:x.visibility})}fromMarkdown(x){let{visibility:B,...A}=this.parseFrontMatter(x,pa8);return{entityType:k6,content:x,...B?{visibility:B}:{},metadata:A}}appendList(x,B,A){if(A.length===0)return;x.push(`### ${B}`),x.push("");for(let w of A)x.push(`- ${w}`);x.push("")}parseEntry(x){let[B="",...A]=x.split(`
@@ -5433,7 +5433,7 @@ facts, owners, or tasks. Return only the required structured JSON.`});var xs8=X.
5433
5433
  `);return this.truncateContent(w||B||wq(x))}truncateContent(x){if(x.length<=rFx)return x;let B=x.slice(0,rFx-1),A=B.search(/\s\S*$/);return`${(A>0?B.slice(0,A):B).trimEnd()}\u2026`}isSummaryEntity(x){return x.entityType===k6}isDecisionEntity(x){return x.entityType===k2}getEntitySpaceId(x){let B=x.metadata;if("spaceId"in B&&typeof B.spaceId==="string")return B.spaceId;return R3(B)}}var Ms8=5,vs8=3;function J80(x){x.messaging.subscribe(OO,async(B)=>{let A=hO.parse(B.payload);return{success:!0,data:await RO(x,A)}})}async function RO(x,B){let A=oX(B.userPermissionLevel);if(!B.channelId)return oFx(x,B,{visibilityScope:A,reason:"no-channel-context",items:[]}),{items:[]};let w=new fq(x),f=await w.retrieve({query:B.message,conversationId:B.conversationId,interfaceType:B.interfaceType,channelId:B.channelId,limit:Ms8,visibilityScope:A}),D=f.results.length===0?await w.retrieve({conversationId:B.conversationId,interfaceType:B.interfaceType,channelId:B.channelId,limit:vs8,visibilityScope:A}):void 0,$=f.results.length>0,Z=$?f.results:D?.results??[];return oFx(x,B,{visibilityScope:A,spaceId:f.spaceId??D?.spaceId,reason:Z.length>0?"memory-injected":"no-same-space-memory",items:Z.map((Q)=>Ns8(Q,$))}),{items:Z.map(Is8)}}function oFx(x,B,A){x.logger.info("Conversation memory agent context audit",{conversationId:B.conversationId,interfaceType:B.interfaceType,channelId:B.channelId,channelName:B.channelName,userPermissionLevel:B.userPermissionLevel,visibilityScope:A.visibilityScope,spaceId:A.spaceId,reason:A.reason,itemCount:A.items.length,items:A.items})}function Ns8(x,B){return{id:x.id,entityType:x.entityType,conversationId:x.conversationId,spaceId:x.spaceId,visibility:x.visibility,score:x.score,updated:x.updated,eligibilityReason:B?"same-space-query-match":"recent-same-space-memory"}}function Is8(x){let B=x.channelName??x.channelId;return{id:x.id,source:"conversation-memory",title:`${x.entityType} from ${B}`,content:x.content,provenance:{entityType:x.entityType,entityId:x.id,conversationId:x.conversationId,spaceId:x.spaceId,interfaceType:x.interfaceType,channelId:x.channelId,channelName:x.channelName,updated:x.updated,score:x.score,messageCount:x.messageCount,entryCount:x.entryCount,status:x.status}}}var xKx=X.enum(["user","assistant"]),Os8=X.object({actorId:X.string(),canonicalId:X.string().optional(),interfaceType:X.string(),role:xKx,displayName:X.string().optional(),username:X.string().optional(),isBot:X.boolean().optional()}),hs8=X.object({messageId:X.string().optional(),channelId:X.string().optional(),channelName:X.string().optional(),threadId:X.string().optional(),metadata:X.record(X.string(),X.unknown()).optional()}),k80=X.object({role:xKx,content:X.string(),timestamp:X.string().datetime().optional(),actor:Os8.optional(),source:hs8.optional()}),Rs8=X.object({conversationId:X.string().default("eval-conversation"),messages:X.array(k80)}),ys8=X.object({conversationId:X.string()}),ms8=X.object({conversationId:X.string().default("eval-conversation"),interfaceType:X.string().default("eval"),channelId:X.string().default("eval-channel"),channelName:X.string().optional(),projectionDecision:X.enum(["update","append"]).default("update"),existingSummary:X.string().optional(),existingMessageCount:X.number().int().min(0).default(0),messages:X.array(k80)}),yO=X.object({actorId:X.string(),canonicalId:X.string().optional(),displayName:X.string().optional()}),Cs8=yO.extend({roles:X.array(X.enum(["user","assistant","system"])).default(["user"]),sourceActorIds:X.array(X.string()).optional()}),cs8=X.object({actorId:X.string().optional(),canonicalId:X.string().optional(),displayName:X.string()}),BKx=X.object({id:X.string(),entityType:X.enum(["summary","decision","action-item"]),content:X.string(),excerpt:X.string().optional(),score:X.number().optional(),conversationId:X.string(),interfaceType:X.string(),channelId:X.string(),channelName:X.string().optional(),updated:X.string().datetime().optional(),visibility:Z2,status:X.string().optional(),participants:X.array(Cs8).optional(),decidedBy:X.array(yO).optional(),mentionedBy:X.array(yO).optional(),assignedTo:X.array(cs8).optional(),requestedBy:X.array(yO).optional()}),gs8=X.object({query:X.string().optional(),conversationId:X.string().optional(),interfaceType:X.string().optional(),channelId:X.string().optional(),limit:X.number().int().min(1).optional(),includeOtherSpaces:X.boolean().optional(),actorId:X.string().optional(),canonicalId:X.string().optional(),visibilityScope:Z2.optional(),memory:X.array(BKx).optional()}),Ts8=X.object({conversationId:X.string().default("eval-conversation"),message:X.string(),interfaceType:X.string().default("eval"),channelId:X.string().optional(),channelName:X.string().optional(),userPermissionLevel:X.enum(["admin","trusted","public"]).default("trusted"),memory:X.array(BKx).optional()}),ps8=X.object({conversationId:X.string().default("eval-conversation"),existingSummary:X.string().optional(),existingMessageCount:X.number().int().min(0).default(0),messages:X.array(k80)});function AKx(x){let{context:B,logger:A,config:w}=x;B.eval.registerHandler("summarizeMessages",async(f)=>{let D=Rs8.parse(f),$=L80(D.messages,D.conversationId),Q=await new oK(B,A,w).extract($);return Q.entries.map((Y)=>{let W=Q.decisions.filter((F)=>F.timeRange.start>=Y.timeRange.start).filter((F)=>F.timeRange.end<=Y.timeRange.end).map((F)=>F.text),H=Q.actionItems.filter((F)=>F.timeRange.start>=Y.timeRange.start).filter((F)=>F.timeRange.end<=Y.timeRange.end).map((F)=>F.text);return{...Y,decisions:W,actionItems:H,keyPointsText:Y.keyPoints.join(`
5434
5434
  `),decisionsText:W.join(`
5435
5435
  `),actionItemsText:H.join(`
5436
- `)}})}),B.eval.registerHandler("decideProjection",async(f)=>{let D=ps8.parse(f),$=L80(D.messages,D.conversationId),Z=D.existingSummary?tFx({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null;return new o$(B,A,w).decideProjection($,Z)}),B.eval.registerHandler("retrieveMemory",async(f)=>{let D=gs8.parse(f),$=D.memory?eFx(B,D.memory):B,Z=new fq($),{actorId:Q,canonicalId:Y,memory:W,...H}=D,F=Q??Y;return Z.retrieve({...H,...F?{identity:s$({actorId:F,interfaceType:as8(F),role:"user",...Y?{canonicalId:Y}:{}})}:{}})}),B.eval.registerHandler("buildAgentContext",async(f)=>{let D=Ts8.parse(f),$=D.memory?eFx(B,D.memory):B;return RO($,D)}),B.eval.registerHandler("projectMessages",async(f)=>{let D=ms8.parse(f),$=L80(D.messages,D.conversationId),Z=us8({conversationId:D.conversationId,interfaceType:D.interfaceType,channelId:D.channelId,channelName:D.channelName,messages:$}),Q=D.existingSummary?tFx({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null,Y=[],W=[],H=Ss8({context:B,conversation:Z,messages:$,existing:Q,upserted:Y,deleted:W,projectionDecision:D.projectionDecision});return{result:await new o$(H,A,w).projectConversation(D.conversationId),summaries:Y.filter((q)=>q.entityType==="summary"),decisions:Y.filter((q)=>q.entityType==="decision"),actionItems:Y.filter((q)=>q.entityType==="action-item"),deleted:W}}),B.eval.registerHandler("projectConversation",async(f)=>{let D=ys8.parse(f);return new o$(B,A,w).projectConversation(D.conversationId)})}function tFx(x){return{id:x.conversationId,entityType:"summary",content:x.content,contentHash:"eval-existing-summary",visibility:x.visibility,created:"2026-01-01T00:00:00.000Z",updated:"2026-01-01T00:00:00.000Z",metadata:{conversationId:x.conversationId,channelId:"eval-channel",interfaceType:"eval",messageCount:x.messageCount,entryCount:1,sourceHash:"eval-source-hash",projectionVersion:x.projectionVersion}}}function L80(x,B){return x.map((A,w)=>{let f=A.timestamp??new Date(Date.UTC(2026,0,1,0,w)).toISOString();return{id:`eval-message-${w+1}`,conversationId:B,role:A.role,content:A.content,timestamp:f,metadata:{...A.actor?{actor:A.actor}:{},...A.source?{source:A.source}:{}}}})}function us8(x){let B=x.messages[0],A=x.messages[x.messages.length-1],w=B?.timestamp??"2026-01-01T00:00:00.000Z",f=A?.timestamp??w;return{id:x.conversationId,sessionId:x.conversationId,interfaceType:x.interfaceType,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},startedAt:w,lastActiveAt:f,createdAt:w,updatedAt:f,metadata:{}}}function Ss8(x){let B=R3(x.conversation);return{...x.context,spaces:[B],conversations:{...x.context.conversations,get:async()=>x.conversation,getMessages:async()=>x.messages},ai:{...x.context.ai,generateObject:async()=>({object:{decision:x.projectionDecision,rationale:"Forced by eval input"}})},entityService:{...x.context.entityService,getEntity:async({entityType:A})=>A==="summary"?x.existing:null,listEntities:async()=>[],deleteEntity:async(A)=>{return x.deleted.push(A),!0},upsertEntity:async({entity:A})=>{return x.upserted.push(A),{entityId:A.id,jobId:"eval-upsert",created:!0,skipped:!1}}}}}function eFx(x,B){let A=B.map(is8),w=A.map((f,D)=>({entity:f,score:B[D]?.score??1,excerpt:B[D]?.excerpt??wq(f)}));return{...x,entityService:{...x.entityService,search:async()=>w,listEntities:async({entityType:f})=>A.filter((D)=>D.entityType===f)}}}function is8(x){if(x.entityType==="summary")return ls8(x);if(x.entityType==="decision")return ns8(x);return ds8(x)}function M80(x){let B=x.updated??"2026-01-01T00:00:00.000Z";return{id:x.id,content:x.content,contentHash:_8(x.content),visibility:x.visibility,created:B,updated:B}}function ls8(x){return eX.parse({...M80(x),entityType:"summary",metadata:{conversationId:x.conversationId,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},interfaceType:x.interfaceType,messageCount:3,entryCount:1,sourceHash:`source-${x.id}`,projectionVersion:1,...x.participants?{participants:x.participants}:{}}})}function ns8(x){return xY.parse({...M80(x),entityType:"decision",metadata:{conversationId:x.conversationId,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},interfaceType:x.interfaceType,spaceId:R3(x),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:x.conversationId,sourceMessageCount:2,projectionVersion:1,status:x.status==="superseded"?"superseded":"active",...x.decidedBy?{decidedBy:x.decidedBy}:{},...x.mentionedBy?{mentionedBy:x.mentionedBy}:{}}})}function ds8(x){let B=x.status==="done"||x.status==="dropped"?x.status:"open";return BY.parse({...M80(x),entityType:"action-item",metadata:{conversationId:x.conversationId,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},interfaceType:x.interfaceType,spaceId:R3(x),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:x.conversationId,sourceMessageCount:2,projectionVersion:1,status:B,...x.assignedTo?{assignedTo:x.assignedTo}:{},...x.requestedBy?{requestedBy:x.requestedBy}:{}}})}function as8(x){let B=x.indexOf(":");return B>0?x.slice(0,B):"legacy"}var wKx={name:"@brains/conversation-memory",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Plugin for deriving durable conversation memory",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/conversation-service":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/node":"^20.19.43",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},main:"./src/index.ts",private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var rs8=new OB,os8=new aK,ts8=new sK,es8=X.object({conversationId:X.string()});class N80 extends g8{entityType=k6;schema=eX;adapter=rs8;constructor(x={}){super(EO,wKx,x,G80,{[k6]:{create:"never",update:"never",delete:"never",extract:"never",publish:"never"}})}getConfig(){return this.config}getTemplates(){return{"summary-list":vFx,"summary-detail":NFx,"ai-response":IFx}}getDataSources(){return[new P80(this.logger.child("SummaryDataSource"))]}getDerivedEntityProjections(x){if(!this.config.enableProjection)return[];return[{id:"conversation-memory-projection",targetType:k6,job:{type:EFx,handler:new kO(x,this.logger,this.config)},initialSync:{shouldEnqueue:async()=>x.spaces.length>0&&!await xF(x,k6,{outputVisibility:this.config.memoryVisibility}),jobData:{mode:"rebuild-all",reason:"initial-sync"},jobOptions:{source:K80,deduplication:"coalesce",deduplicationKey:"conversation-memory:rebuild-all:initial-sync",metadata:{operationType:"data_processing",operationTarget:"conversation-memory:rebuild-all",pluginId:EO}}},sourceChange:{sourceKind:v80,sourceTypes:[v80],shouldEnqueue:(B)=>this.shouldEnqueueConversationProjection(x,B),events:[fKx],jobData:(B)=>{let{conversationId:A}=this.parseConversationMessagePayload(B);return{mode:"conversation",conversationId:A,reason:"message-added"}},jobOptions:(B)=>{let{conversationId:A}=this.parseConversationMessagePayload(B);return{priority:5,delayMs:this.config.projectionDelayMs,source:K80,deduplication:"skip",deduplicationKey:`conversation-memory:${A}`,metadata:{operationType:"data_processing",operationTarget:`conversation-memory:${A}`,pluginId:EO}}}}}]}parseConversationMessagePayload(x){return es8.parse(x)}async shouldEnqueueConversationProjection(x,B){let{conversationId:A}=this.parseConversationMessagePayload(B),w=await x.conversations.get(A);if(!w)return!1;return AY({conversation:w,spaces:x.spaces}).eligible}async onRegister(x){x.entities.register(k2,xY,os8),x.entities.register(IB,BY,ts8),RFx({context:x}),mFx({context:x}),lFx({context:x}),aFx({context:x,config:this.config}),J80(x),AKx({context:x,logger:this.logger,config:this.config})}}function I80(x={}){return new N80(x)}class O80{logger;handleImports;handleDelete;deleteOnFileRemoval;fileOperations;constructor(x,B,A,w,f=!0){if(this.logger=x,this.fileOperations=w,this.deleteOnFileRemoval=f,A)this.handleImports=async(D)=>{let $=await A({type:"directory-import",data:{paths:D}});this.logger.debug("Queued import job for file changes",{jobId:$,pathCount:D.length})},this.handleDelete=async(D)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:D});return}try{let{entityType:$,id:Z}=this.fileOperations.parseEntityFromPath(D),Q=await A({type:"directory-delete",data:{entityId:Z,entityType:$,filePath:D}});this.logger.info("Queued delete job for removed file",{jobId:Q,path:D,entityId:Z,entityType:$})}catch($){this.logger.warn("Could not extract entity info from deleted file",{path:D,error:$})}};else this.handleImports=async(D)=>{await B(D)},this.handleDelete=async(D)=>{this.logger.warn("File deleted but no job queue available",{path:D})}}async handleFileChanges(x){let B=[],A=async()=>{if(B.length===0)return;let w=B;B=[];try{await this.handleImports(w)}catch(f){this.logger.error("Failed to handle file change batch",{paths:w,error:f})}};for(let[w,f]of x){if(f==="add"||f==="change"){B.push(w);continue}await A(),await this.handleFileChange(f,w)}await A()}async handleFileChange(x,B){this.logger.debug("Processing file change",{event:x,path:B});try{switch(x){case"add":case"change":await this.handleImports([B]);break;case"delete":case"unlink":await this.handleDelete(B);break;default:this.logger.debug("Unhandled file event",{event:x,path:B})}}catch(A){this.logger.error("Failed to handle file change",{event:x,path:B,error:A})}}}import{EventEmitter as vr8}from"events";import{stat as Nr8,Stats as QC6}from"fs";import{readdir as Ir8,stat as Or8}from"fs/promises";import*as h8 from"path";import{lstat as DKx,readdir as xr8,realpath as Br8,stat as Ar8}from"fs/promises";import{join as wr8,relative as fr8,resolve as $Kx,sep as Dr8}from"path";import{Readable as $r8}from"stream";var M2={FILE_TYPE:"files",DIR_TYPE:"directories",FILE_DIR_TYPE:"files_directories",EVERYTHING_TYPE:"all"},h80={root:".",fileFilter:(x)=>!0,directoryFilter:(x)=>!0,type:M2.FILE_TYPE,lstat:!1,depth:2147483648,alwaysStat:!1,highWaterMark:4096};Object.freeze(h80);var YKx="READDIRP_RECURSIVE_ERROR",Zr8=new Set(["ENOENT","EPERM","EACCES","ELOOP",YKx]),ZKx=[M2.DIR_TYPE,M2.EVERYTHING_TYPE,M2.FILE_DIR_TYPE,M2.FILE_TYPE],Qr8=new Set([M2.DIR_TYPE,M2.EVERYTHING_TYPE,M2.FILE_DIR_TYPE]),Xr8=new Set([M2.EVERYTHING_TYPE,M2.FILE_DIR_TYPE,M2.FILE_TYPE]),Yr8=(x)=>Zr8.has(x.code),Wr8=process.platform==="win32",QKx=(x)=>!0,XKx=(x)=>{if(x===void 0)return QKx;if(typeof x==="function")return x;if(typeof x==="string"){let B=x.trim();return(A)=>A.basename===B}if(Array.isArray(x)){let B=x.map((A)=>A.trim());return(A)=>B.some((w)=>A.basename===w)}return QKx};class R80 extends $r8{parents;reading;parent;_stat;_maxDepth;_wantsDir;_wantsFile;_wantsEverything;_root;_isDirent;_statsProp;_rdOptions;_fileFilter;_directoryFilter;constructor(x={}){super({objectMode:!0,autoDestroy:!0,highWaterMark:x.highWaterMark});let B={...h80,...x},{root:A,type:w}=B;this._fileFilter=XKx(B.fileFilter),this._directoryFilter=XKx(B.directoryFilter);let f=B.lstat?DKx:Ar8;if(Wr8)this._stat=(D)=>f(D,{bigint:!0});else this._stat=f;this._maxDepth=B.depth!=null&&Number.isSafeInteger(B.depth)?B.depth:h80.depth,this._wantsDir=w?Qr8.has(w):!1,this._wantsFile=w?Xr8.has(w):!1,this._wantsEverything=w===M2.EVERYTHING_TYPE,this._root=$Kx(A),this._isDirent=!B.alwaysStat,this._statsProp=this._isDirent?"dirent":"stats",this._rdOptions={encoding:"utf8",withFileTypes:this._isDirent},this.parents=[this._exploreDir(A,1)],this.reading=!1,this.parent=void 0}async _read(x){if(this.reading)return;this.reading=!0;try{while(!this.destroyed&&x>0){let B=this.parent,A=B&&B.files;if(A&&A.length>0){let{path:w,depth:f}=B,D=A.splice(0,x).map((Z)=>this._formatEntry(Z,w)),$=await Promise.all(D);for(let Z of $){if(!Z)continue;if(this.destroyed)return;let Q=await this._getEntryType(Z);if(Q==="directory"&&this._directoryFilter(Z)){if(f<=this._maxDepth)this.parents.push(this._exploreDir(Z.fullPath,f+1));if(this._wantsDir)this.push(Z),x--}else if((Q==="file"||this._includeAsFile(Z))&&this._fileFilter(Z)){if(this._wantsFile)this.push(Z),x--}}}else{let w=this.parents.pop();if(!w){this.push(null);break}if(this.parent=await w,this.destroyed)return}}}catch(B){this.destroy(B)}finally{this.reading=!1}}async _exploreDir(x,B){let A;try{A=await xr8(x,this._rdOptions)}catch(w){this._onError(w)}return{files:A,depth:B,path:x}}async _formatEntry(x,B){let A,w=this._isDirent?x.name:x;try{let f=$Kx(wr8(B,w));A={path:fr8(this._root,f),fullPath:f,basename:w},A[this._statsProp]=this._isDirent?x:await this._stat(f)}catch(f){this._onError(f);return}return A}_onError(x){if(Yr8(x)&&!this.destroyed)this.emit("warn",x);else this.destroy(x)}async _getEntryType(x){if(!x&&this._statsProp in x)return"";let B=x[this._statsProp];if(B.isFile())return"file";if(B.isDirectory())return"directory";if(B&&B.isSymbolicLink()){let A=x.fullPath;try{let w=await Br8(A),f=await DKx(w);if(f.isFile())return"file";if(f.isDirectory()){let D=w.length;if(A.startsWith(w)&&A.substr(D,1)===Dr8){let $=Error(`Circular symlink detected: "${A}" points to "${w}"`);return $.code=YKx,this._onError($)}return"directory"}}catch(w){return this._onError(w),""}}}_includeAsFile(x){let B=x&&x[this._statsProp];return B&&this._wantsEverything&&!B.isDirectory()}}function WKx(x,B={}){let A=B.entryType||B.type;if(A==="both")A=M2.FILE_DIR_TYPE;if(A)B.type=A;if(!x)throw Error("readdirp: root argument is required. Usage: readdirp(root, options)");else if(typeof x!=="string")throw TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");else if(A&&!ZKx.includes(A))throw Error(`readdirp: Invalid type passed. Use one of ${ZKx.join(", ")}`);return B.root=x,new R80(B)}import{watch as Hr8,unwatchFile as HKx,watchFile as Fr8}from"fs";import{realpath as y80,lstat as Kr8,open as qr8,stat as KKx}from"fs/promises";import{type as zr8}from"os";import*as F6 from"path";var br8="data",c80="end",qKx="close",gO=()=>{};var TO=process.platform,g80=TO==="win32",Vr8=TO==="darwin",Ur8=TO==="linux",Gr8=TO==="freebsd",zKx=zr8()==="OS400",A6={ALL:"all",READY:"ready",ADD:"add",CHANGE:"change",ADD_DIR:"addDir",UNLINK:"unlink",UNLINK_DIR:"unlinkDir",RAW:"raw",ERROR:"error"},y3=A6,Er8="watch",jr8={lstat:Kr8,stat:KKx},wY="listeners",mO="errHandlers",Dq="rawEmitters",_r8=[wY,mO,Dq],Pr8=new Set(["3dm","3ds","3g2","3gp","7z","a","aac","adp","afdesign","afphoto","afpub","ai","aif","aiff","alz","ape","apk","appimage","ar","arj","asf","au","avi","bak","baml","bh","bin","bk","bmp","btif","bz2","bzip2","cab","caf","cgm","class","cmx","cpio","cr2","cur","dat","dcm","deb","dex","djvu","dll","dmg","dng","doc","docm","docx","dot","dotm","dra","DS_Store","dsk","dts","dtshd","dvb","dwg","dxf","ecelp4800","ecelp7470","ecelp9600","egg","eol","eot","epub","exe","f4v","fbs","fh","fla","flac","flatpak","fli","flv","fpx","fst","fvt","g3","gh","gif","graffle","gz","gzip","h261","h263","h264","icns","ico","ief","img","ipa","iso","jar","jpeg","jpg","jpgv","jpm","jxr","key","ktx","lha","lib","lvp","lz","lzh","lzma","lzo","m3u","m4a","m4v","mar","mdi","mht","mid","midi","mj2","mka","mkv","mmr","mng","mobi","mov","movie","mp3","mp4","mp4a","mpeg","mpg","mpga","mxu","nef","npx","numbers","nupkg","o","odp","ods","odt","oga","ogg","ogv","otf","ott","pages","pbm","pcx","pdb","pdf","pea","pgm","pic","png","pnm","pot","potm","potx","ppa","ppam","ppm","pps","ppsm","ppsx","ppt","pptm","pptx","psd","pya","pyc","pyo","pyv","qt","rar","ras","raw","resources","rgb","rip","rlc","rmf","rmvb","rpm","rtf","rz","s3m","s7z","scpt","sgi","shar","snap","sil","sketch","slk","smv","snk","so","stl","suo","sub","swf","tar","tbz","tbz2","tga","tgz","thmx","tif","tiff","tlz","ttc","ttf","txz","udf","uvh","uvi","uvm","uvp","uvs","uvu","viv","vob","war","wav","wax","wbmp","wdp","weba","webm","webp","whl","wim","wm","wma","wmv","wmx","woff","woff2","wrm","wvx","xbm","xif","xla","xlam","xls","xlsb","xlsm","xlsx","xlt","xltm","xltx","xm","xmind","xpi","xpm","xwd","xz","z","zip","zipx"]),Jr8=(x)=>Pr8.has(F6.extname(x).slice(1).toLowerCase()),C80=(x,B)=>{if(x instanceof Set)x.forEach(B);else B(x)},Aj=(x,B,A)=>{let w=x[B];if(!(w instanceof Set))x[B]=w=new Set([w]);w.add(A)},Lr8=(x)=>(B)=>{let A=x[B];if(A instanceof Set)A.clear();else delete x[B]},wj=(x,B,A)=>{let w=x[B];if(w instanceof Set)w.delete(A);else if(w===A)delete x[B]},bKx=(x)=>x instanceof Set?x.size===0:!x,CO=new Map;function FKx(x,B,A,w,f){let D=($,Z)=>{if(A(x),f($,Z,{watchedPath:x}),Z&&x!==Z)cO(F6.resolve(x,Z),wY,F6.join(x,Z))};try{return Hr8(x,{persistent:B.persistent},D)}catch($){w($);return}}var cO=(x,B,A,w,f)=>{let D=CO.get(x);if(!D)return;C80(D[B],($)=>{$(A,w,f)})},kr8=(x,B,A,w)=>{let{listener:f,errHandler:D,rawEmitter:$}=w,Z=CO.get(B),Q;if(!A.persistent){if(Q=FKx(x,A,f,D,$),!Q)return;return Q.close.bind(Q)}if(Z)Aj(Z,wY,f),Aj(Z,mO,D),Aj(Z,Dq,$);else{if(Q=FKx(x,A,cO.bind(null,B,wY),D,cO.bind(null,B,Dq)),!Q)return;Q.on(y3.ERROR,async(Y)=>{let W=cO.bind(null,B,mO);if(Z)Z.watcherUnusable=!0;if(g80&&Y.code==="EPERM")try{await(await qr8(x,"r")).close(),W(Y)}catch(H){}else W(Y)}),Z={listeners:f,errHandlers:D,rawEmitters:$,watcher:Q},CO.set(B,Z)}return()=>{if(wj(Z,wY,f),wj(Z,mO,D),wj(Z,Dq,$),bKx(Z.listeners))Z.watcher.close(),CO.delete(B),_r8.forEach(Lr8(Z)),Z.watcher=void 0,Object.freeze(Z)}},m80=new Map,Mr8=(x,B,A,w)=>{let{listener:f,rawEmitter:D}=w,$=m80.get(B),Z=$&&$.options;if(Z&&(Z.persistent<A.persistent||Z.interval>A.interval))HKx(B),$=void 0;if($)Aj($,wY,f),Aj($,Dq,D);else $={listeners:f,rawEmitters:D,options:A,watcher:Fr8(B,A,(Q,Y)=>{C80($.rawEmitters,(H)=>{H(y3.CHANGE,B,{curr:Q,prev:Y})});let W=Q.mtimeMs;if(Q.size!==Y.size||W>Y.mtimeMs||W===0)C80($.listeners,(H)=>H(x,Q))})},m80.set(B,$);return()=>{if(wj($,wY,f),wj($,Dq,D),bKx($.listeners))m80.delete(B),HKx(B),$.options=$.watcher=void 0,Object.freeze($)}};class T80{fsw;_boundHandleError;constructor(x){this.fsw=x,this._boundHandleError=(B)=>x._handleError(B)}_watchWithNodeFs(x,B){let A=this.fsw.options,w=F6.dirname(x),f=F6.basename(x);this.fsw._getWatchedDir(w).add(f);let $=F6.resolve(x),Z={persistent:A.persistent};if(!B)B=gO;let Q;if(A.usePolling){let Y=A.interval!==A.binaryInterval;Z.interval=Y&&Jr8(f)?A.binaryInterval:A.interval,Q=Mr8(x,$,Z,{listener:B,rawEmitter:this.fsw._emitRaw})}else Q=kr8(x,$,Z,{listener:B,errHandler:this._boundHandleError,rawEmitter:this.fsw._emitRaw});return Q}_handleFile(x,B,A){if(this.fsw.closed)return;let w=F6.dirname(x),f=F6.basename(x),D=this.fsw._getWatchedDir(w),$=B;if(D.has(f))return;let Z=async(Y,W)=>{if(!this.fsw._throttle(Er8,x,5))return;if(!W||W.mtimeMs===0)try{let H=await KKx(x);if(this.fsw.closed)return;let{atimeMs:F,mtimeMs:K}=H;if(!F||F<=K||K!==$.mtimeMs)this.fsw._emit(y3.CHANGE,x,H);if((Vr8||Ur8||Gr8)&&$.ino!==H.ino){this.fsw._closeFile(Y),$=H;let q=this._watchWithNodeFs(x,Z);if(q)this.fsw._addPathCloser(Y,q)}else $=H}catch(H){this.fsw._remove(w,f)}else if(D.has(f)){let{atimeMs:H,mtimeMs:F}=W;if(!H||H<=F||F!==$.mtimeMs)this.fsw._emit(y3.CHANGE,x,W);$=W}},Q=this._watchWithNodeFs(x,Z);if(!(A&&this.fsw.options.ignoreInitial)&&this.fsw._isntIgnored(x)){if(!this.fsw._throttle(y3.ADD,x,0))return;this.fsw._emit(y3.ADD,x,B)}return Q}async _handleSymlink(x,B,A,w){if(this.fsw.closed)return;let f=x.fullPath,D=this.fsw._getWatchedDir(B);if(!this.fsw.options.followSymlinks){this.fsw._incrReadyCount();let $;try{$=await y80(A)}catch(Z){return this.fsw._emitReady(),!0}if(this.fsw.closed)return;if(D.has(w)){if(this.fsw._symlinkPaths.get(f)!==$)this.fsw._symlinkPaths.set(f,$),this.fsw._emit(y3.CHANGE,A,x.stats)}else D.add(w),this.fsw._symlinkPaths.set(f,$),this.fsw._emit(y3.ADD,A,x.stats);return this.fsw._emitReady(),!0}if(this.fsw._symlinkPaths.has(f))return!0;this.fsw._symlinkPaths.set(f,!0)}_handleRead(x,B,A,w,f,D,$){x=F6.join(x,"");let Z=w?`${x}:${w}`:x;if($=this.fsw._throttle("readdir",Z,1000),!$)return;let Q=this.fsw._getWatchedDir(A.path),Y=new Set,W=this.fsw._readdirp(x,{fileFilter:(H)=>A.filterPath(H),directoryFilter:(H)=>A.filterDir(H)});if(!W)return;return W.on(br8,async(H)=>{if(this.fsw.closed){W=void 0;return}let F=H.path,K=F6.join(x,F);if(Y.add(F),H.stats.isSymbolicLink()&&await this._handleSymlink(H,x,K,F))return;if(this.fsw.closed){W=void 0;return}if(F===w||!w&&!Q.has(F))this.fsw._incrReadyCount(),K=F6.join(f,F6.relative(f,K)),this._addToNodeFs(K,B,A,D+1)}).on(y3.ERROR,this._boundHandleError),new Promise((H,F)=>{if(!W)return F();W.once(c80,()=>{if(this.fsw.closed){W=void 0;return}let K=$?$.clear():!1;if(H(void 0),Q.getChildren().filter((q)=>{return q!==x&&!Y.has(q)}).forEach((q)=>{this.fsw._remove(x,q)}),W=void 0,K)this._handleRead(x,!1,A,w,f,D,$)})})}async _handleDir(x,B,A,w,f,D,$){let Z=this.fsw._getWatchedDir(F6.dirname(x)),Q=Z.has(F6.basename(x));if(!(A&&this.fsw.options.ignoreInitial)&&!f&&!Q)this.fsw._emit(y3.ADD_DIR,x,B);Z.add(F6.basename(x)),this.fsw._getWatchedDir(x);let Y,W,H=this.fsw.options.depth;if((H==null||w<=H)&&!this.fsw._symlinkPaths.has($)){if(!f){if(await this._handleRead(x,A,D,f,x,w,Y),this.fsw.closed)return}W=this._watchWithNodeFs(x,(F,K)=>{if(K&&K.mtimeMs===0)return;this._handleRead(F,!1,D,f,x,w,Y)})}return W}async _addToNodeFs(x,B,A,w,f){let D=this.fsw._emitReady;if(this.fsw._isIgnored(x)||this.fsw.closed)return D(),!1;let $=this.fsw._getWatchHelpers(x);if(A)$.filterPath=(Z)=>A.filterPath(Z),$.filterDir=(Z)=>A.filterDir(Z);try{let Z=await jr8[$.statMethod]($.watchPath);if(this.fsw.closed)return;if(this.fsw._isIgnored($.watchPath,Z))return D(),!1;let Q=this.fsw.options.followSymlinks,Y;if(Z.isDirectory()){let W=F6.resolve(x),H=Q?await y80(x):x;if(this.fsw.closed)return;if(Y=await this._handleDir($.watchPath,Z,B,w,f,$,H),this.fsw.closed)return;if(W!==H&&H!==void 0)this.fsw._symlinkPaths.set(W,H)}else if(Z.isSymbolicLink()){let W=Q?await y80(x):x;if(this.fsw.closed)return;let H=F6.dirname($.watchPath);if(this.fsw._getWatchedDir(H).add($.watchPath),this.fsw._emit(y3.ADD,$.watchPath,Z),Y=await this._handleDir(H,Z,B,w,x,$,W),this.fsw.closed)return;if(W!==void 0)this.fsw._symlinkPaths.set(F6.resolve(x),W)}else Y=this._handleFile($.watchPath,Z,B);if(D(),Y)this.fsw._addPathCloser(x,Y);return!1}catch(Z){if(this.fsw._handleError(Z))return D(),x}}}/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */var p80="/",hr8="//",jKx=".",Rr8="..",yr8="string",mr8=/\\/g,_Kx=/\/\//g,Cr8=/\..*\.(sw[px])$|~$|\.subl.*\.tmp/,cr8=/^\.[/\\]/;function pO(x){return Array.isArray(x)?x:[x]}var u80=(x)=>typeof x==="object"&&x!==null&&!(x instanceof RegExp);function gr8(x){if(typeof x==="function")return x;if(typeof x==="string")return(B)=>x===B;if(x instanceof RegExp)return(B)=>x.test(B);if(typeof x==="object"&&x!==null)return(B)=>{if(x.path===B)return!0;if(x.recursive){let A=h8.relative(x.path,B);if(!A)return!1;return!A.startsWith("..")&&!h8.isAbsolute(A)}return!1};return()=>!1}function Tr8(x){if(typeof x!=="string")throw Error("string expected");x=h8.normalize(x),x=x.replace(/\\/g,"/");let B=!1;if(x.startsWith("//"))B=!0;if(x=x.replace(_Kx,"/"),B)x="/"+x;return x}function VKx(x,B,A){let w=Tr8(B);for(let f=0;f<x.length;f++){let D=x[f];if(D(w,A))return!0}return!1}function pr8(x,B){if(x==null)throw TypeError("anymatch: specify first argument");let w=pO(x).map((f)=>gr8(f));if(B==null)return(f,D)=>{return VKx(w,f,D)};return VKx(w,B)}var UKx=(x)=>{let B=pO(x).flat();if(!B.every((A)=>typeof A===yr8))throw TypeError(`Non-string provided as watch path: ${B}`);return B.map(PKx)},GKx=(x)=>{let B=x.replace(mr8,p80),A=!1;if(B.startsWith(hr8))A=!0;if(B=B.replace(_Kx,p80),A)B=p80+B;return B},PKx=(x)=>GKx(h8.normalize(GKx(x))),EKx=(x="")=>(B)=>{if(typeof B==="string")return PKx(h8.isAbsolute(B)?B:h8.join(x,B));else return B},ur8=(x,B)=>{if(h8.isAbsolute(x))return x;return h8.join(B,x)},Sr8=Object.freeze(new Set);class JKx{path;_removeWatcher;items;constructor(x,B){this.path=x,this._removeWatcher=B,this.items=new Set}add(x){let{items:B}=this;if(!B)return;if(x!==jKx&&x!==Rr8)B.add(x)}async remove(x){let{items:B}=this;if(!B)return;if(B.delete(x),B.size>0)return;let A=this.path;try{await Ir8(A)}catch(w){if(this._removeWatcher)this._removeWatcher(h8.dirname(A),h8.basename(A))}}has(x){let{items:B}=this;if(!B)return;return B.has(x)}getChildren(){let{items:x}=this;if(!x)return[];return[...x.values()]}dispose(){this.items.clear(),this.path="",this._removeWatcher=gO,this.items=Sr8,Object.freeze(this)}}var ir8="stat",lr8="lstat";class LKx{fsw;path;watchPath;fullWatchPath;dirParts;followSymlinks;statMethod;constructor(x,B,A){this.fsw=A;let w=x;this.path=x=x.replace(cr8,""),this.watchPath=w,this.fullWatchPath=h8.resolve(w),this.dirParts=[],this.dirParts.forEach((f)=>{if(f.length>1)f.pop()}),this.followSymlinks=B,this.statMethod=B?ir8:lr8}entryPath(x){return h8.join(this.watchPath,h8.relative(this.watchPath,x.fullPath))}filterPath(x){let{stats:B}=x;if(B&&B.isSymbolicLink())return this.filterDir(x);let A=this.entryPath(x);return this.fsw._isntIgnored(A,B)&&this.fsw._hasReadPermissions(B)}filterDir(x){return this.fsw._isntIgnored(this.entryPath(x),x.stats)}}class S80 extends vr8{closed;options;_closers;_ignoredPaths;_throttled;_streams;_symlinkPaths;_watched;_pendingWrites;_pendingUnlinks;_readyCount;_emitReady;_closePromise;_userIgnored;_readyEmitted;_emitRaw;_boundRemove;_nodeFsHandler;constructor(x={}){super();this.closed=!1,this._closers=new Map,this._ignoredPaths=new Set,this._throttled=new Map,this._streams=new Set,this._symlinkPaths=new Map,this._watched=new Map,this._pendingWrites=new Map,this._pendingUnlinks=new Map,this._readyCount=0,this._readyEmitted=!1;let B=x.awaitWriteFinish,A={stabilityThreshold:2000,pollInterval:100},w={persistent:!0,ignoreInitial:!1,ignorePermissionErrors:!1,interval:100,binaryInterval:300,followSymlinks:!0,usePolling:!1,atomic:!0,...x,ignored:x.ignored?pO(x.ignored):pO([]),awaitWriteFinish:B===!0?A:typeof B==="object"?{...A,...B}:!1};if(zKx)w.usePolling=!0;if(w.atomic===void 0)w.atomic=!w.usePolling;let f=process.env.CHOKIDAR_USEPOLLING;if(f!==void 0){let Z=f.toLowerCase();if(Z==="false"||Z==="0")w.usePolling=!1;else if(Z==="true"||Z==="1")w.usePolling=!0;else w.usePolling=!!Z}let D=process.env.CHOKIDAR_INTERVAL;if(D)w.interval=Number.parseInt(D,10);let $=0;this._emitReady=()=>{if($++,$>=this._readyCount)this._emitReady=gO,this._readyEmitted=!0,process.nextTick(()=>this.emit(A6.READY))},this._emitRaw=(...Z)=>this.emit(A6.RAW,...Z),this._boundRemove=this._remove.bind(this),this.options=w,this._nodeFsHandler=new T80(this),Object.freeze(w)}_addIgnoredPath(x){if(u80(x)){for(let B of this._ignoredPaths)if(u80(B)&&B.path===x.path&&B.recursive===x.recursive)return}this._ignoredPaths.add(x)}_removeIgnoredPath(x){if(this._ignoredPaths.delete(x),typeof x==="string"){for(let B of this._ignoredPaths)if(u80(B)&&B.path===x)this._ignoredPaths.delete(B)}}add(x,B,A){let{cwd:w}=this.options;this.closed=!1,this._closePromise=void 0;let f=UKx(x);if(w)f=f.map((D)=>{return ur8(D,w)});if(f.forEach((D)=>{this._removeIgnoredPath(D)}),this._userIgnored=void 0,!this._readyCount)this._readyCount=0;return this._readyCount+=f.length,Promise.all(f.map(async(D)=>{let $=await this._nodeFsHandler._addToNodeFs(D,!A,void 0,0,B);if($)this._emitReady();return $})).then((D)=>{if(this.closed)return;D.forEach(($)=>{if($)this.add(h8.dirname($),h8.basename(B||$))})}),this}unwatch(x){if(this.closed)return this;let B=UKx(x),{cwd:A}=this.options;return B.forEach((w)=>{if(!h8.isAbsolute(w)&&!this._closers.has(w)){if(A)w=h8.join(A,w);w=h8.resolve(w)}if(this._closePath(w),this._addIgnoredPath(w),this._watched.has(w))this._addIgnoredPath({path:w,recursive:!0});this._userIgnored=void 0}),this}close(){if(this._closePromise)return this._closePromise;this.closed=!0,this.removeAllListeners();let x=[];return this._closers.forEach((B)=>B.forEach((A)=>{let w=A();if(w instanceof Promise)x.push(w)})),this._streams.forEach((B)=>B.destroy()),this._userIgnored=void 0,this._readyCount=0,this._readyEmitted=!1,this._watched.forEach((B)=>B.dispose()),this._closers.clear(),this._watched.clear(),this._streams.clear(),this._symlinkPaths.clear(),this._throttled.clear(),this._closePromise=x.length?Promise.all(x).then(()=>{return}):Promise.resolve(),this._closePromise}getWatched(){let x={};return this._watched.forEach((B,A)=>{let f=(this.options.cwd?h8.relative(this.options.cwd,A):A)||jKx;x[f]=B.getChildren().sort()}),x}emitWithAll(x,B){if(this.emit(x,...B),x!==A6.ERROR)this.emit(A6.ALL,x,...B)}async _emit(x,B,A){if(this.closed)return;let w=this.options;if(g80)B=h8.normalize(B);if(w.cwd)B=h8.relative(w.cwd,B);let f=[B];if(A!=null)f.push(A);let D=w.awaitWriteFinish,$;if(D&&($=this._pendingWrites.get(B)))return $.lastChange=new Date,this;if(w.atomic){if(x===A6.UNLINK)return this._pendingUnlinks.set(B,[x,...f]),setTimeout(()=>{this._pendingUnlinks.forEach((Z,Q)=>{this.emit(...Z),this.emit(A6.ALL,...Z),this._pendingUnlinks.delete(Q)})},typeof w.atomic==="number"?w.atomic:100),this;if(x===A6.ADD&&this._pendingUnlinks.has(B))x=A6.CHANGE,this._pendingUnlinks.delete(B)}if(D&&(x===A6.ADD||x===A6.CHANGE)&&this._readyEmitted){let Z=(Q,Y)=>{if(Q)x=A6.ERROR,f[0]=Q,this.emitWithAll(x,f);else if(Y){if(f.length>1)f[1]=Y;else f.push(Y);this.emitWithAll(x,f)}};return this._awaitWriteFinish(B,D.stabilityThreshold,x,Z),this}if(x===A6.CHANGE){if(!this._throttle(A6.CHANGE,B,50))return this}if(w.alwaysStat&&A===void 0&&(x===A6.ADD||x===A6.ADD_DIR||x===A6.CHANGE)){let Z=w.cwd?h8.join(w.cwd,B):B,Q;try{Q=await Or8(Z)}catch(Y){}if(!Q||this.closed)return;f.push(Q)}return this.emitWithAll(x,f),this}_handleError(x){let B=x&&x.code;if(x&&B!=="ENOENT"&&B!=="ENOTDIR"&&(!this.options.ignorePermissionErrors||B!=="EPERM"&&B!=="EACCES"))this.emit(A6.ERROR,x);return x||this.closed}_throttle(x,B,A){if(!this._throttled.has(x))this._throttled.set(x,new Map);let w=this._throttled.get(x);if(!w)throw Error("invalid throttle");let f=w.get(B);if(f)return f.count++,!1;let D,$=()=>{let Q=w.get(B),Y=Q?Q.count:0;if(w.delete(B),clearTimeout(D),Q)clearTimeout(Q.timeoutObject);return Y};D=setTimeout($,A);let Z={timeoutObject:D,clear:$,count:0};return w.set(B,Z),Z}_incrReadyCount(){return this._readyCount++}_awaitWriteFinish(x,B,A,w){let f=this.options.awaitWriteFinish;if(typeof f!=="object")return;let D=f.pollInterval,$,Z=x;if(this.options.cwd&&!h8.isAbsolute(x))Z=h8.join(this.options.cwd,x);let Q=new Date,Y=this._pendingWrites;function W(H){Nr8(Z,(F,K)=>{if(F||!Y.has(x)){if(F&&F.code!=="ENOENT")w(F);return}let q=Number(new Date);if(H&&K.size!==H.size)Y.get(x).lastChange=q;let V=Y.get(x);if(q-V.lastChange>=B)Y.delete(x),w(void 0,K);else $=setTimeout(W,D,K)})}if(!Y.has(x))Y.set(x,{lastChange:Q,cancelWait:()=>{return Y.delete(x),clearTimeout($),A}}),$=setTimeout(W,D)}_isIgnored(x,B){if(this.options.atomic&&Cr8.test(x))return!0;if(!this._userIgnored){let{cwd:A}=this.options,f=(this.options.ignored||[]).map(EKx(A)),$=[...[...this._ignoredPaths].map(EKx(A)),...f];this._userIgnored=pr8($,void 0)}return this._userIgnored(x,B)}_isntIgnored(x,B){return!this._isIgnored(x,B)}_getWatchHelpers(x){return new LKx(x,this.options.followSymlinks,this)}_getWatchedDir(x){let B=h8.resolve(x);if(!this._watched.has(B))this._watched.set(B,new JKx(B,this._boundRemove));return this._watched.get(B)}_hasReadPermissions(x){if(this.options.ignorePermissionErrors)return!0;return Boolean(Number(x.mode)&256)}_remove(x,B,A){let w=h8.join(x,B),f=h8.resolve(w);if(A=A!=null?A:this._watched.has(w)||this._watched.has(f),!this._throttle("remove",w,100))return;if(!A&&this._watched.size===1)this.add(x,B,!0);this._getWatchedDir(w).getChildren().forEach((H)=>this._remove(w,H));let Z=this._getWatchedDir(x),Q=Z.has(B);if(Z.remove(B),this._symlinkPaths.has(f))this._symlinkPaths.delete(f);let Y=w;if(this.options.cwd)Y=h8.relative(this.options.cwd,w);if(this.options.awaitWriteFinish&&this._pendingWrites.has(Y)){if(this._pendingWrites.get(Y).cancelWait()===A6.ADD)return}this._watched.delete(w),this._watched.delete(f);let W=A?A6.UNLINK_DIR:A6.UNLINK;if(Q&&!this._isIgnored(w))this._emit(W,w);this._closePath(w)}_closePath(x){this._closeFile(x);let B=h8.dirname(x);this._getWatchedDir(B).remove(h8.basename(x))}_closeFile(x){let B=this._closers.get(x);if(!B)return;B.forEach((A)=>A()),this._closers.delete(x)}_addPathCloser(x,B){if(!B)return;let A=this._closers.get(x);if(!A)A=[],this._closers.set(x,A);A.push(B)}_readdirp(x,B){if(this.closed)return;let A={type:A6.ALL,alwaysStat:!0,lstat:!0,...B,depth:0},w=WKx(x,A);return this._streams.add(w),w.once(qKx,()=>{w=void 0}),w.once(c80,()=>{if(w)this._streams.delete(w),w=void 0}),w}}function nr8(x,B={}){let A=new S80(B);return A.add(x),A}var kKx={watch:nr8,FSWatcher:S80};import{extname as dr8}from"path";var uO=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function fY(x){let B=dr8(x).toLowerCase();return uO.includes(B)}function MKx(x){switch(x.toLowerCase().replace(".","")){case"jpg":case"jpeg":return"image/jpeg";case"png":return"image/png";case"gif":return"image/gif";case"webp":return"image/webp";case"svg":return"image/svg+xml";default:return"image/png"}}function i80(x){switch(x.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${x.toLowerCase()}`}}import{isAbsolute as ar8,relative as sr8,sep as vKx,join as rr8}from"path";function s4(x,B){return ar8(B)?B:rr8(x,B)}function lA(x,B){let A=s4(x,B),w=sr8(x,A);return vKx==="/"?w:w.split(vKx).join("/")}var or8=1e4;function tr8(x,B){if(!lA(B,x).startsWith("image/"))return!1;return fY(x)}function er8(x,B){if(lA(B,x).split("/")[0]?.startsWith("_"))return!1;if(x.endsWith(".md"))return!0;return tr8(x,B)}class l80{watcher;watchCallback;pendingChanges=new Map;suppressedPaths=new Map;delayScope;delayedBatches;clock;activeCallbacks=new Set;stopPromise=null;stopping=!1;syncPath;watchInterval;logger;onFileChange;onFileChanges;constructor(x){this.syncPath=x.syncPath,this.watchInterval=x.watchInterval,this.logger=x.logger,this.onFileChange=x.onFileChange,this.onFileChanges=x.onFileChanges,this.clock=x.clock,this.delayScope=H0.runSync(y9.make()),this.delayedBatches=H0.runSync(y9.extend(QB.make(),this.delayScope))}async start(){if(this.watcher){this.logger.debug("Already watching directory");return}if(this.stopping)throw Error("Cannot restart a stopped file watcher");this.logger.debug("Starting directory watch",{path:this.syncPath,interval:this.watchInterval});let x=kKx.watch(this.syncPath,{ignored:/(^|[/\\])\../,ignoreInitial:!0,persistent:!0,interval:this.watchInterval,awaitWriteFinish:{stabilityThreshold:2000,pollInterval:100}});if(this.watcher=x,x.on("add",(B)=>void this.handleFileChange("add",B)).on("change",(B)=>void this.handleFileChange("change",B)).on("unlink",(B)=>void this.handleFileChange("delete",B)).on("error",(B)=>this.logger.error("Watcher error",B)),this.watchCallback)x.on("all",this.watchCallback);try{await this.awaitReady(x)}catch(B){this.watcher=void 0;try{await x.close()}catch{}throw B}}stop(){return this.stopping=!0,this.stopPromise??=this.stopWatcher(),this.stopPromise}async stopWatcher(){let x=this.watcher;this.watcher=void 0;let B=this.closeDelayScope();this.pendingChanges.clear(),this.suppressedPaths.clear();let A=[B,...x?[x.close()]:[],...this.activeCallbacks],f=(await Promise.allSettled(A)).find((D)=>D.status==="rejected");if(x)this.logger.info("Stopped directory watch");if(f)throw f.reason}awaitReady(x){return new Promise((B,A)=>{let w=()=>{x.off("error",f),B()},f=(D)=>{x.off("ready",w),A(D)};x.once("ready",w),x.once("error",f)})}setCallback(x){if(this.watchCallback=x,this.watcher)this.watcher.on("all",x)}suppressPaths(x){let B=Date.now()+or8;for(let A of x){let w=lA(this.syncPath,A);this.pendingChanges.delete(w),this.suppressedPaths.set(w,B)}}async handleFileChange(x,B){if(this.stopping||!er8(B,this.syncPath))return;let A=lA(this.syncPath,B);if(this.isSuppressed(A)){this.logger.debug("Suppressed git-triggered file change",{event:x,path:B});return}this.logger.debug("File change detected",{event:x,path:B}),this.pendingChanges.set(A,x);let w=H0.sleep(500).pipe(H0.andThen(H0.sync(()=>this.startPendingProcessing()))),f=this.clock?H0.withClock(w,this.clock):w;QB.unsafeSet(this.delayedBatches,"file-change-batch",H0.runFork(f))}async processPendingChanges(){if(this.pendingChanges.size===0)return;let x=new Map(this.pendingChanges);if(this.pendingChanges.clear(),this.logger.debug("Processing batched file changes",{changeCount:x.size}),this.onFileChanges){let B=new Map([...x].map(([A,w])=>[s4(this.syncPath,A),w]));try{await this.onFileChanges(B)}catch(A){this.logger.error("Error processing file change batch",{error:A})}return}for(let[B,A]of x){let w=s4(this.syncPath,B);try{if(this.onFileChange)await this.onFileChange(A,w)}catch(f){this.logger.error("Error processing file change",{path:B,event:A,error:f})}}}isSuppressed(x){let B=this.suppressedPaths.get(x);if(B===void 0)return!1;return this.suppressedPaths.delete(x),B>Date.now()}startPendingProcessing(){if(this.stopping)return;let x=this.processPendingChanges();this.activeCallbacks.add(x),x.then(()=>this.activeCallbacks.delete(x),()=>this.activeCallbacks.delete(x))}async closeDelayScope(){let x=await H0.runPromiseExit(y9.close(this.delayScope,f5.void));if(f5.isFailure(x))throw _4.squash(x.cause)}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}async function NKx(x,B){if(x?.isWatching())return B.logger.debug("Already watching directory"),x;return xo8(B)}async function IKx(x){await x?.stop()}function OKx(x,B){if(x)x.setCallback(B)}async function xo8(x){let{logger:B,syncPath:A,watchInterval:w,importEntities:f,jobQueueCallback:D,fileOperations:$,deleteOnFileRemoval:Z}=x,Q=new O80(B,f,D,$,Z),Y=new l80({syncPath:A,watchInterval:w,logger:B,onFileChanges:async(W)=>{await Q.handleFileChanges(W)}});return await Y.start(),Y}async function hKx(x){let B=Date.now();x.logger.debug("Starting sync (import only)");let A=await x.importEntities(),w=await x.removeOrphanedEntities(),f=Date.now()-B;return x.markSynced(new Date),x.logger.debug("Sync completed",{duration:f,imported:A.imported,orphansDeleted:w.deleted}),{export:{exported:0,failed:0,errors:[]},import:A,duration:f}}class n80{logger;syncPath;deleteOnFileRemoval;constructor(x){this.logger=x.logger,this.syncPath=x.syncPath,this.deleteOnFileRemoval=x.deleteOnFileRemoval}prepareBatchOperations(x,B=!0){let A=[],w=this.createImportOperations(x);A.push(...w);let f=w.length;if(B&&this.deleteOnFileRemoval)A.push({type:"directory-cleanup",data:{}});let D=x.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:f,totalFiles:D}),{operations:A,exportOperationsCount:0,importOperationsCount:f,totalFiles:D}}async queueSyncBatch(x,B,A,w,f=!0){let D=this.prepareBatchOperations(A,f);if(D.operations.length===0)return this.logger.debug("No sync operations needed",{source:B}),null;return{batchId:await x.jobs.enqueueBatch(D.operations,{source:B,rootJobId:w?.rootJobId??DY(),metadata:{progressToken:w?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:w?.pluginId??"directory-sync",interfaceType:w?.interfaceType,channelId:w?.channelId}}),operationCount:D.operations.length,exportOperationsCount:D.exportOperationsCount,importOperationsCount:D.importOperationsCount,totalFiles:D.totalFiles}}createImportOperations(x){if(x.length===0)return[];let B=50,A=[];for(let w=0;w<x.length;w+=B){let f=x.slice(w,w+B);A.push({type:"directory-import",data:{batchIndex:Math.floor(w/B),paths:f,batchSize:f.length}})}return A}}import{extname as Bo8}from"path";var SO=[".pdf"],iO=".meta.json";function $Y(x){let B=Bo8(x).toLowerCase();return SO.includes(B)}function lO(x){return x.toLowerCase().endsWith(iO)}function d80(x){return`${x}${iO}`}function RKx(x){switch(x.toLowerCase().replace(".","")){case"pdf":default:return"application/pdf"}}class a80{syncInProgress=!1;logger;syncPath;fileOperations;batchOperationsManager;constructor(x){this.logger=x.logger,this.syncPath=x.syncPath,this.fileOperations=x.fileOperations,this.batchOperationsManager=new n80({logger:x.logger,syncPath:x.syncPath,deleteOnFileRemoval:x.deleteOnFileRemoval})}async queueSyncBatch(x,B,A,w){if(this.syncInProgress)return this.logger.debug("Sync already in progress, skipping",{source:B}),null;this.syncInProgress=!0;try{let f=await this.fileOperations.getAllSyncFiles(),D=w?await this.selectChangedFiles(f,w):{files:f,includeCleanup:!0};return await this.batchOperationsManager.queueSyncBatch(x,B,D.files,A,D.includeCleanup)}finally{this.syncInProgress=!1}}async selectChangedFiles(x,B){let A=new Set(B.map((D)=>this.normalizePath(D))),w=x.filter((D)=>A.has(lA(this.syncPath,D))),f=!1;for(let D of A)if(!await this.fileOperations.fileExists(s4(this.syncPath,D))){f=!0;break}return{files:w,includeCleanup:f}}normalizePath(x){let B=lA(this.syncPath,x);return lO(B)?B.slice(0,-iO.length):B}}class s80{options;constructor(x){this.options=x}createExportDeps(x,B){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:x,entityTypes:B}}createImportDeps(x){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,quarantine:this.options.quarantine,imageJobQueue:this.createImageJobQueueDeps(),entityTypes:x}}createCleanupDeps(x,B){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:x,entityTypes:B}}createImageJobQueueDeps(){return{logger:this.options.logger,syncPath:this.options.syncPath,jobQueueCallback:this.options.getJobQueueCallback(),coverImageConverter:this.options.coverImageConverter,inlineImageConverter:this.options.inlineImageConverter}}}import{basename as $o8,dirname as Zo8,extname as Qo8}from"path";import{extname as Ao8,join as nO}from"path";function dO(x,B){let w=lA(x,B).split("/"),f,D;if(w.length===1)f="note",D=w;else if(w.length>1&&w[0])f=w[0],D=w.slice(1);else f="note",D=w;let $;if(D.length>1){let Z=D[D.length-1];if(Z)D[D.length-1]=yKx(Z);$=D.join(":")}else $=yKx(D[0]??"");return{entityType:f,id:$}}function mKx(x,B,A,w=".md"){let f=B.split(":").filter((Y)=>Y.length>0),D=A==="note";if(f.length===1)return D?nO(x,`${f[0]}${w}`):nO(x,A,`${f[0]}${w}`);let $=f;if(f[0]===A)$=f.slice(1);let Z=$[$.length-1],Q=$.slice(0,-1);if(D)return nO(x,...Q,`${Z}${w}`);return nO(x,A,...Q,`${Z}${w}`)}function CKx(x){if(x.entityType==="document")return".pdf";if(x.entityType!=="image")return".md";let B=x.metadata.format;if(B)return i80(B);let A=x.content.match(/^data:image\/([a-z+]+);base64,/i);return A?.[1]?i80(A[1]):".md"}function yKx(x){let B=Ao8(x).toLowerCase();return B===".md"||uO.includes(B)||SO.includes(B)?x.slice(0,-B.length):x}import{mkdir as Xo8,readFile as $q,writeFile as o80,stat as Yo8,utimes as Wo8}from"fs/promises";import{join as aO}from"path";import{mkdir as cKx,readdir as fo8,stat as Do8}from"fs/promises";import{access as wo8}from"fs/promises";async function s6(x){try{return await wo8(x),!0}catch{return!1}}async function r80(x,B){return uKx(x,B,{includeDocuments:!1,includeImages:!1})}async function gKx(x,B){return uKx(x,B,{includeDocuments:!0,includeImages:!0})}async function TKx(x,B){if(!await s6(x))await cKx(x,{recursive:!0});for(let A of B)if(A!=="note")await cKx(aO(x,A),{recursive:!0})}async function pKx(x,B){let A=[],w={totalFiles:0,byEntityType:{}};if(!await s6(x))return{files:A,stats:w};let f=await r80(x,B);for(let D of f)try{let $=aO(x,D),Z=await Do8($),{entityType:Q}=dO(x,D);A.push({path:D,entityType:Q,modified:Z.mtime}),w.totalFiles++,w.byEntityType[Q]=(w.byEntityType[Q]??0)+1}catch{continue}return{files:A,stats:w}}async function uKx(x,B,A){let w=[];if(!await s6(x))return w;let f=async(D,$="",Z=!1,Q=!1)=>{let Y=await fo8(D,{withFileTypes:!0});for(let W of Y){let H=$?aO($,W.name):W.name;if(W.isFile()&&!W.name.endsWith(".invalid")&&!lO(W.name)){if(W.name.endsWith(".md"))w.push(H);else if(A.includeImages&&Z&&fY(W.name))w.push(H);else if(A.includeDocuments&&Q&&$Y(W.name))w.push(H)}else if(W.isDirectory()&&!W.name.startsWith(".")){if($===""&&!B.hasEntityType(W.name))continue;let F=aO(D,W.name),K=W.name==="image"&&$==="",q=W.name==="document"&&$==="";await f(F,H,Z||K,Q||q)}}};return await f(x),w}var Ho8=X.record(X.string(),X.unknown());class t80{syncPath;entityService;constructor(x,B){this.syncPath=x,this.entityService=B}parseEntityFromPath(x){return dO(this.syncPath,x)}async readEntity(x){let B=s4(this.syncPath,x),A=await Yo8(B),{entityType:w,id:f}=this.parseEntityFromPath(x),D=A.birthtime.getTime()>0?A.birthtime:A.mtime,$=A.mtime,Z,Q;if(fY(x)||$Y(x)){let H=(await $q(B)).toString("base64"),F=Qo8(x);if(Z=`data:${$Y(x)?RKx(F):MKx(F)};base64,${H}`,$Y(x))Q=await this.readDocumentSidecar(B,x)}else Z=await $q(B,"utf-8");let Y={entityType:w,id:f,content:Z,created:D,updated:$};if(Q)Y.metadata=Q;return Y}async readDocumentSidecar(x,B){let A={mimeType:"application/pdf",filename:$o8(B)},w=d80(x);if(!await s6(w))return A;try{let f=await $q(w,"utf-8"),D=Ho8.safeParse(JSON.parse(f));return{...A,...D.success?D.data:{}}}catch{return A}}async writeEntity(x){let B=this.getEntityFilePath(x),A=x.entityType==="image",w=x.entityType==="document";if(A||w){let D=A?/^data:image\/[a-z+]+;base64,(.+)$/i:/^data:application\/pdf;base64,(.+)$/i,$=x.content.match(D),Z=$?.[1]?Buffer.from($[1],"base64"):Buffer.from(x.content,"base64"),Q=!1;if(await s6(B)){let Y=await $q(B),W=_8(Y.toString("base64")),H=_8(Z.toString("base64"));if(W===H)Q=!0}if(!Q)await this.ensureEntityDirectory(x,B),await o80(B,Z);if(w)await this.writeDocumentSidecar(x,B);if(Q)return}else{let D=this.entityService.serializeEntity(x);if(await s6(B)){let $=await $q(B,"utf-8"),Z=_8($),Q=_8(D);if(Z===Q)return}await this.ensureEntityDirectory(x,B),await o80(B,D,"utf-8")}let f=new Date(x.updated);await Wo8(B,f,f)}async ensureEntityDirectory(x,B){if(x.entityType!=="note")await Xo8(Zo8(B),{recursive:!0})}async writeDocumentSidecar(x,B){let A=x.metadata,w={};for(let[$,Z]of Object.entries(A)){if($==="mimeType")continue;if(Z===void 0)continue;w[$]=Z}let f=d80(B),D=`${JSON.stringify(w,null,2)}
5436
+ `)}})}),B.eval.registerHandler("decideProjection",async(f)=>{let D=ps8.parse(f),$=L80(D.messages,D.conversationId),Z=D.existingSummary?tFx({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null;return new o$(B,A,w).decideProjection($,Z)}),B.eval.registerHandler("retrieveMemory",async(f)=>{let D=gs8.parse(f),$=D.memory?eFx(B,D.memory):B,Z=new fq($),{actorId:Q,canonicalId:Y,memory:W,...H}=D,F=Q??Y;return Z.retrieve({...H,...F?{identity:s$({actorId:F,interfaceType:as8(F),role:"user",...Y?{canonicalId:Y}:{}})}:{}})}),B.eval.registerHandler("buildAgentContext",async(f)=>{let D=Ts8.parse(f),$=D.memory?eFx(B,D.memory):B;return RO($,D)}),B.eval.registerHandler("projectMessages",async(f)=>{let D=ms8.parse(f),$=L80(D.messages,D.conversationId),Z=us8({conversationId:D.conversationId,interfaceType:D.interfaceType,channelId:D.channelId,channelName:D.channelName,messages:$}),Q=D.existingSummary?tFx({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null,Y=[],W=[],H=Ss8({context:B,conversation:Z,messages:$,existing:Q,upserted:Y,deleted:W,projectionDecision:D.projectionDecision});return{result:await new o$(H,A,w).projectConversation(D.conversationId),summaries:Y.filter((q)=>q.entityType==="summary"),decisions:Y.filter((q)=>q.entityType==="decision"),actionItems:Y.filter((q)=>q.entityType==="action-item"),deleted:W}}),B.eval.registerHandler("projectConversation",async(f)=>{let D=ys8.parse(f);return new o$(B,A,w).projectConversation(D.conversationId)})}function tFx(x){return{id:x.conversationId,entityType:"summary",content:x.content,contentHash:"eval-existing-summary",visibility:x.visibility,created:"2026-01-01T00:00:00.000Z",updated:"2026-01-01T00:00:00.000Z",metadata:{conversationId:x.conversationId,channelId:"eval-channel",interfaceType:"eval",messageCount:x.messageCount,entryCount:1,sourceHash:"eval-source-hash",projectionVersion:x.projectionVersion}}}function L80(x,B){return x.map((A,w)=>{let f=A.timestamp??new Date(Date.UTC(2026,0,1,0,w)).toISOString();return{id:`eval-message-${w+1}`,conversationId:B,role:A.role,content:A.content,timestamp:f,metadata:{...A.actor?{actor:A.actor}:{},...A.source?{source:A.source}:{}}}})}function us8(x){let B=x.messages[0],A=x.messages[x.messages.length-1],w=B?.timestamp??"2026-01-01T00:00:00.000Z",f=A?.timestamp??w;return{id:x.conversationId,sessionId:x.conversationId,interfaceType:x.interfaceType,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},startedAt:w,lastActiveAt:f,createdAt:w,updatedAt:f,metadata:{}}}function Ss8(x){let B=R3(x.conversation);return{...x.context,spaces:[B],conversations:{...x.context.conversations,get:async()=>x.conversation,getMessages:async()=>x.messages},ai:{...x.context.ai,generateObject:async()=>({object:{decision:x.projectionDecision,rationale:"Forced by eval input"}})},entityService:{...x.context.entityService,getEntity:async({entityType:A})=>A==="summary"?x.existing:null,listEntities:async()=>[],deleteEntity:async(A)=>{return x.deleted.push(A),!0},upsertEntity:async({entity:A})=>{return x.upserted.push(A),{entityId:A.id,jobId:"eval-upsert",created:!0,skipped:!1}}}}}function eFx(x,B){let A=B.map(is8),w=A.map((f,D)=>({entity:f,score:B[D]?.score??1,excerpt:B[D]?.excerpt??wq(f)}));return{...x,entityService:{...x.entityService,search:async()=>w,listEntities:async({entityType:f})=>A.filter((D)=>D.entityType===f)}}}function is8(x){if(x.entityType==="summary")return ls8(x);if(x.entityType==="decision")return ns8(x);return ds8(x)}function M80(x){let B=x.updated??"2026-01-01T00:00:00.000Z";return{id:x.id,content:x.content,contentHash:_8(x.content),visibility:x.visibility,created:B,updated:B}}function ls8(x){return eX.parse({...M80(x),entityType:"summary",metadata:{conversationId:x.conversationId,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},interfaceType:x.interfaceType,messageCount:3,entryCount:1,sourceHash:`source-${x.id}`,projectionVersion:1,...x.participants?{participants:x.participants}:{}}})}function ns8(x){return xY.parse({...M80(x),entityType:"decision",metadata:{conversationId:x.conversationId,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},interfaceType:x.interfaceType,spaceId:R3(x),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:x.conversationId,sourceMessageCount:2,projectionVersion:1,status:x.status==="superseded"?"superseded":"active",...x.decidedBy?{decidedBy:x.decidedBy}:{},...x.mentionedBy?{mentionedBy:x.mentionedBy}:{}}})}function ds8(x){let B=x.status==="done"||x.status==="dropped"?x.status:"open";return BY.parse({...M80(x),entityType:"action-item",metadata:{conversationId:x.conversationId,channelId:x.channelId,...x.channelName?{channelName:x.channelName}:{},interfaceType:x.interfaceType,spaceId:R3(x),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:x.conversationId,sourceMessageCount:2,projectionVersion:1,status:B,...x.assignedTo?{assignedTo:x.assignedTo}:{},...x.requestedBy?{requestedBy:x.requestedBy}:{}}})}function as8(x){let B=x.indexOf(":");return B>0?x.slice(0,B):"legacy"}var wKx={name:"@brains/conversation-memory",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Plugin for deriving durable conversation memory",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/conversation-service":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/node":"^20.19.43",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},main:"./src/index.ts",private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var rs8=new OB,os8=new aK,ts8=new sK,es8=X.object({conversationId:X.string()});class N80 extends g8{entityType=k6;schema=eX;adapter=rs8;constructor(x={}){super(EO,wKx,x,G80,{[k6]:{create:"never",update:"never",delete:"never",extract:"never",publish:"never"}})}getConfig(){return this.config}getTemplates(){return{"summary-list":vFx,"summary-detail":NFx,"ai-response":IFx}}getDataSources(){return[new P80(this.logger.child("SummaryDataSource"))]}getDerivedEntityProjections(x){if(!this.config.enableProjection)return[];return[{id:"conversation-memory-projection",targetType:k6,job:{type:EFx,handler:new kO(x,this.logger,this.config)},initialSync:{shouldEnqueue:async()=>x.spaces.length>0&&!await xF(x,k6,{outputVisibility:this.config.memoryVisibility}),jobData:{mode:"rebuild-all",reason:"initial-sync"},jobOptions:{source:K80,deduplication:"coalesce",deduplicationKey:"conversation-memory:rebuild-all:initial-sync",metadata:{operationType:"data_processing",operationTarget:"conversation-memory:rebuild-all",pluginId:EO}}},sourceChange:{sourceKind:v80,sourceTypes:[v80],shouldEnqueue:(B)=>this.shouldEnqueueConversationProjection(x,B),events:[fKx],jobData:(B)=>{let{conversationId:A}=this.parseConversationMessagePayload(B);return{mode:"conversation",conversationId:A,reason:"message-added"}},jobOptions:(B)=>{let{conversationId:A}=this.parseConversationMessagePayload(B);return{priority:5,delayMs:this.config.projectionDelayMs,source:K80,deduplication:"skip",deduplicationKey:`conversation-memory:${A}`,metadata:{operationType:"data_processing",operationTarget:`conversation-memory:${A}`,pluginId:EO}}}}}]}parseConversationMessagePayload(x){return es8.parse(x)}async shouldEnqueueConversationProjection(x,B){let{conversationId:A}=this.parseConversationMessagePayload(B),w=await x.conversations.get(A);if(!w)return!1;return AY({conversation:w,spaces:x.spaces}).eligible}async onRegister(x){x.entities.register(k2,xY,os8),x.entities.register(IB,BY,ts8),RFx({context:x}),mFx({context:x}),lFx({context:x}),aFx({context:x,config:this.config}),J80(x),AKx({context:x,logger:this.logger,config:this.config})}}function I80(x={}){return new N80(x)}class O80{logger;handleImports;handleDelete;deleteOnFileRemoval;fileOperations;constructor(x,B,A,w,f=!0){if(this.logger=x,this.fileOperations=w,this.deleteOnFileRemoval=f,A)this.handleImports=async(D)=>{let $=await A({type:"directory-import",data:{paths:D}});this.logger.debug("Queued import job for file changes",{jobId:$,pathCount:D.length})},this.handleDelete=async(D)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:D});return}try{let{entityType:$,id:Z}=this.fileOperations.parseEntityFromPath(D),Q=await A({type:"directory-delete",data:{entityId:Z,entityType:$,filePath:D}});this.logger.info("Queued delete job for removed file",{jobId:Q,path:D,entityId:Z,entityType:$})}catch($){this.logger.warn("Could not extract entity info from deleted file",{path:D,error:$})}};else this.handleImports=async(D)=>{await B(D)},this.handleDelete=async(D)=>{this.logger.warn("File deleted but no job queue available",{path:D})}}async handleFileChanges(x){let B=[],A=async()=>{if(B.length===0)return;let w=B;B=[];try{await this.handleImports(w)}catch(f){this.logger.error("Failed to handle file change batch",{paths:w,error:f})}};for(let[w,f]of x){if(f==="add"||f==="change"){B.push(w);continue}await A(),await this.handleFileChange(f,w)}await A()}async handleFileChange(x,B){this.logger.debug("Processing file change",{event:x,path:B});try{switch(x){case"add":case"change":await this.handleImports([B]);break;case"delete":case"unlink":await this.handleDelete(B);break;default:this.logger.debug("Unhandled file event",{event:x,path:B})}}catch(A){this.logger.error("Failed to handle file change",{event:x,path:B,error:A})}}}import{EventEmitter as vr8}from"events";import{stat as Nr8,Stats as QC6}from"fs";import{readdir as Ir8,stat as Or8}from"fs/promises";import*as h8 from"path";import{lstat as DKx,readdir as xr8,realpath as Br8,stat as Ar8}from"fs/promises";import{join as wr8,relative as fr8,resolve as $Kx,sep as Dr8}from"path";import{Readable as $r8}from"stream";var M2={FILE_TYPE:"files",DIR_TYPE:"directories",FILE_DIR_TYPE:"files_directories",EVERYTHING_TYPE:"all"},h80={root:".",fileFilter:(x)=>!0,directoryFilter:(x)=>!0,type:M2.FILE_TYPE,lstat:!1,depth:2147483648,alwaysStat:!1,highWaterMark:4096};Object.freeze(h80);var YKx="READDIRP_RECURSIVE_ERROR",Zr8=new Set(["ENOENT","EPERM","EACCES","ELOOP",YKx]),ZKx=[M2.DIR_TYPE,M2.EVERYTHING_TYPE,M2.FILE_DIR_TYPE,M2.FILE_TYPE],Qr8=new Set([M2.DIR_TYPE,M2.EVERYTHING_TYPE,M2.FILE_DIR_TYPE]),Xr8=new Set([M2.EVERYTHING_TYPE,M2.FILE_DIR_TYPE,M2.FILE_TYPE]),Yr8=(x)=>Zr8.has(x.code),Wr8=process.platform==="win32",QKx=(x)=>!0,XKx=(x)=>{if(x===void 0)return QKx;if(typeof x==="function")return x;if(typeof x==="string"){let B=x.trim();return(A)=>A.basename===B}if(Array.isArray(x)){let B=x.map((A)=>A.trim());return(A)=>B.some((w)=>A.basename===w)}return QKx};class R80 extends $r8{parents;reading;parent;_stat;_maxDepth;_wantsDir;_wantsFile;_wantsEverything;_root;_isDirent;_statsProp;_rdOptions;_fileFilter;_directoryFilter;constructor(x={}){super({objectMode:!0,autoDestroy:!0,highWaterMark:x.highWaterMark});let B={...h80,...x},{root:A,type:w}=B;this._fileFilter=XKx(B.fileFilter),this._directoryFilter=XKx(B.directoryFilter);let f=B.lstat?DKx:Ar8;if(Wr8)this._stat=(D)=>f(D,{bigint:!0});else this._stat=f;this._maxDepth=B.depth!=null&&Number.isSafeInteger(B.depth)?B.depth:h80.depth,this._wantsDir=w?Qr8.has(w):!1,this._wantsFile=w?Xr8.has(w):!1,this._wantsEverything=w===M2.EVERYTHING_TYPE,this._root=$Kx(A),this._isDirent=!B.alwaysStat,this._statsProp=this._isDirent?"dirent":"stats",this._rdOptions={encoding:"utf8",withFileTypes:this._isDirent},this.parents=[this._exploreDir(A,1)],this.reading=!1,this.parent=void 0}async _read(x){if(this.reading)return;this.reading=!0;try{while(!this.destroyed&&x>0){let B=this.parent,A=B&&B.files;if(A&&A.length>0){let{path:w,depth:f}=B,D=A.splice(0,x).map((Z)=>this._formatEntry(Z,w)),$=await Promise.all(D);for(let Z of $){if(!Z)continue;if(this.destroyed)return;let Q=await this._getEntryType(Z);if(Q==="directory"&&this._directoryFilter(Z)){if(f<=this._maxDepth)this.parents.push(this._exploreDir(Z.fullPath,f+1));if(this._wantsDir)this.push(Z),x--}else if((Q==="file"||this._includeAsFile(Z))&&this._fileFilter(Z)){if(this._wantsFile)this.push(Z),x--}}}else{let w=this.parents.pop();if(!w){this.push(null);break}if(this.parent=await w,this.destroyed)return}}}catch(B){this.destroy(B)}finally{this.reading=!1}}async _exploreDir(x,B){let A;try{A=await xr8(x,this._rdOptions)}catch(w){this._onError(w)}return{files:A,depth:B,path:x}}async _formatEntry(x,B){let A,w=this._isDirent?x.name:x;try{let f=$Kx(wr8(B,w));A={path:fr8(this._root,f),fullPath:f,basename:w},A[this._statsProp]=this._isDirent?x:await this._stat(f)}catch(f){this._onError(f);return}return A}_onError(x){if(Yr8(x)&&!this.destroyed)this.emit("warn",x);else this.destroy(x)}async _getEntryType(x){if(!x&&this._statsProp in x)return"";let B=x[this._statsProp];if(B.isFile())return"file";if(B.isDirectory())return"directory";if(B&&B.isSymbolicLink()){let A=x.fullPath;try{let w=await Br8(A),f=await DKx(w);if(f.isFile())return"file";if(f.isDirectory()){let D=w.length;if(A.startsWith(w)&&A.substr(D,1)===Dr8){let $=Error(`Circular symlink detected: "${A}" points to "${w}"`);return $.code=YKx,this._onError($)}return"directory"}}catch(w){return this._onError(w),""}}}_includeAsFile(x){let B=x&&x[this._statsProp];return B&&this._wantsEverything&&!B.isDirectory()}}function WKx(x,B={}){let A=B.entryType||B.type;if(A==="both")A=M2.FILE_DIR_TYPE;if(A)B.type=A;if(!x)throw Error("readdirp: root argument is required. Usage: readdirp(root, options)");else if(typeof x!=="string")throw TypeError("readdirp: root argument must be a string. Usage: readdirp(root, options)");else if(A&&!ZKx.includes(A))throw Error(`readdirp: Invalid type passed. Use one of ${ZKx.join(", ")}`);return B.root=x,new R80(B)}import{watch as Hr8,unwatchFile as HKx,watchFile as Fr8}from"fs";import{realpath as y80,lstat as Kr8,open as qr8,stat as KKx}from"fs/promises";import{type as zr8}from"os";import*as F6 from"path";var br8="data",c80="end",qKx="close",gO=()=>{};var TO=process.platform,g80=TO==="win32",Vr8=TO==="darwin",Ur8=TO==="linux",Gr8=TO==="freebsd",zKx=zr8()==="OS400",A6={ALL:"all",READY:"ready",ADD:"add",CHANGE:"change",ADD_DIR:"addDir",UNLINK:"unlink",UNLINK_DIR:"unlinkDir",RAW:"raw",ERROR:"error"},y3=A6,Er8="watch",jr8={lstat:Kr8,stat:KKx},wY="listeners",mO="errHandlers",Dq="rawEmitters",_r8=[wY,mO,Dq],Pr8=new Set(["3dm","3ds","3g2","3gp","7z","a","aac","adp","afdesign","afphoto","afpub","ai","aif","aiff","alz","ape","apk","appimage","ar","arj","asf","au","avi","bak","baml","bh","bin","bk","bmp","btif","bz2","bzip2","cab","caf","cgm","class","cmx","cpio","cr2","cur","dat","dcm","deb","dex","djvu","dll","dmg","dng","doc","docm","docx","dot","dotm","dra","DS_Store","dsk","dts","dtshd","dvb","dwg","dxf","ecelp4800","ecelp7470","ecelp9600","egg","eol","eot","epub","exe","f4v","fbs","fh","fla","flac","flatpak","fli","flv","fpx","fst","fvt","g3","gh","gif","graffle","gz","gzip","h261","h263","h264","icns","ico","ief","img","ipa","iso","jar","jpeg","jpg","jpgv","jpm","jxr","key","ktx","lha","lib","lvp","lz","lzh","lzma","lzo","m3u","m4a","m4v","mar","mdi","mht","mid","midi","mj2","mka","mkv","mmr","mng","mobi","mov","movie","mp3","mp4","mp4a","mpeg","mpg","mpga","mxu","nef","npx","numbers","nupkg","o","odp","ods","odt","oga","ogg","ogv","otf","ott","pages","pbm","pcx","pdb","pdf","pea","pgm","pic","png","pnm","pot","potm","potx","ppa","ppam","ppm","pps","ppsm","ppsx","ppt","pptm","pptx","psd","pya","pyc","pyo","pyv","qt","rar","ras","raw","resources","rgb","rip","rlc","rmf","rmvb","rpm","rtf","rz","s3m","s7z","scpt","sgi","shar","snap","sil","sketch","slk","smv","snk","so","stl","suo","sub","swf","tar","tbz","tbz2","tga","tgz","thmx","tif","tiff","tlz","ttc","ttf","txz","udf","uvh","uvi","uvm","uvp","uvs","uvu","viv","vob","war","wav","wax","wbmp","wdp","weba","webm","webp","whl","wim","wm","wma","wmv","wmx","woff","woff2","wrm","wvx","xbm","xif","xla","xlam","xls","xlsb","xlsm","xlsx","xlt","xltm","xltx","xm","xmind","xpi","xpm","xwd","xz","z","zip","zipx"]),Jr8=(x)=>Pr8.has(F6.extname(x).slice(1).toLowerCase()),C80=(x,B)=>{if(x instanceof Set)x.forEach(B);else B(x)},Aj=(x,B,A)=>{let w=x[B];if(!(w instanceof Set))x[B]=w=new Set([w]);w.add(A)},Lr8=(x)=>(B)=>{let A=x[B];if(A instanceof Set)A.clear();else delete x[B]},wj=(x,B,A)=>{let w=x[B];if(w instanceof Set)w.delete(A);else if(w===A)delete x[B]},bKx=(x)=>x instanceof Set?x.size===0:!x,CO=new Map;function FKx(x,B,A,w,f){let D=($,Z)=>{if(A(x),f($,Z,{watchedPath:x}),Z&&x!==Z)cO(F6.resolve(x,Z),wY,F6.join(x,Z))};try{return Hr8(x,{persistent:B.persistent},D)}catch($){w($);return}}var cO=(x,B,A,w,f)=>{let D=CO.get(x);if(!D)return;C80(D[B],($)=>{$(A,w,f)})},kr8=(x,B,A,w)=>{let{listener:f,errHandler:D,rawEmitter:$}=w,Z=CO.get(B),Q;if(!A.persistent){if(Q=FKx(x,A,f,D,$),!Q)return;return Q.close.bind(Q)}if(Z)Aj(Z,wY,f),Aj(Z,mO,D),Aj(Z,Dq,$);else{if(Q=FKx(x,A,cO.bind(null,B,wY),D,cO.bind(null,B,Dq)),!Q)return;Q.on(y3.ERROR,async(Y)=>{let W=cO.bind(null,B,mO);if(Z)Z.watcherUnusable=!0;if(g80&&Y.code==="EPERM")try{await(await qr8(x,"r")).close(),W(Y)}catch(H){}else W(Y)}),Z={listeners:f,errHandlers:D,rawEmitters:$,watcher:Q},CO.set(B,Z)}return()=>{if(wj(Z,wY,f),wj(Z,mO,D),wj(Z,Dq,$),bKx(Z.listeners))Z.watcher.close(),CO.delete(B),_r8.forEach(Lr8(Z)),Z.watcher=void 0,Object.freeze(Z)}},m80=new Map,Mr8=(x,B,A,w)=>{let{listener:f,rawEmitter:D}=w,$=m80.get(B),Z=$&&$.options;if(Z&&(Z.persistent<A.persistent||Z.interval>A.interval))HKx(B),$=void 0;if($)Aj($,wY,f),Aj($,Dq,D);else $={listeners:f,rawEmitters:D,options:A,watcher:Fr8(B,A,(Q,Y)=>{C80($.rawEmitters,(H)=>{H(y3.CHANGE,B,{curr:Q,prev:Y})});let W=Q.mtimeMs;if(Q.size!==Y.size||W>Y.mtimeMs||W===0)C80($.listeners,(H)=>H(x,Q))})},m80.set(B,$);return()=>{if(wj($,wY,f),wj($,Dq,D),bKx($.listeners))m80.delete(B),HKx(B),$.options=$.watcher=void 0,Object.freeze($)}};class T80{fsw;_boundHandleError;constructor(x){this.fsw=x,this._boundHandleError=(B)=>x._handleError(B)}_watchWithNodeFs(x,B){let A=this.fsw.options,w=F6.dirname(x),f=F6.basename(x);this.fsw._getWatchedDir(w).add(f);let $=F6.resolve(x),Z={persistent:A.persistent};if(!B)B=gO;let Q;if(A.usePolling){let Y=A.interval!==A.binaryInterval;Z.interval=Y&&Jr8(f)?A.binaryInterval:A.interval,Q=Mr8(x,$,Z,{listener:B,rawEmitter:this.fsw._emitRaw})}else Q=kr8(x,$,Z,{listener:B,errHandler:this._boundHandleError,rawEmitter:this.fsw._emitRaw});return Q}_handleFile(x,B,A){if(this.fsw.closed)return;let w=F6.dirname(x),f=F6.basename(x),D=this.fsw._getWatchedDir(w),$=B;if(D.has(f))return;let Z=async(Y,W)=>{if(!this.fsw._throttle(Er8,x,5))return;if(!W||W.mtimeMs===0)try{let H=await KKx(x);if(this.fsw.closed)return;let{atimeMs:F,mtimeMs:K}=H;if(!F||F<=K||K!==$.mtimeMs)this.fsw._emit(y3.CHANGE,x,H);if((Vr8||Ur8||Gr8)&&$.ino!==H.ino){this.fsw._closeFile(Y),$=H;let q=this._watchWithNodeFs(x,Z);if(q)this.fsw._addPathCloser(Y,q)}else $=H}catch(H){this.fsw._remove(w,f)}else if(D.has(f)){let{atimeMs:H,mtimeMs:F}=W;if(!H||H<=F||F!==$.mtimeMs)this.fsw._emit(y3.CHANGE,x,W);$=W}},Q=this._watchWithNodeFs(x,Z);if(!(A&&this.fsw.options.ignoreInitial)&&this.fsw._isntIgnored(x)){if(!this.fsw._throttle(y3.ADD,x,0))return;this.fsw._emit(y3.ADD,x,B)}return Q}async _handleSymlink(x,B,A,w){if(this.fsw.closed)return;let f=x.fullPath,D=this.fsw._getWatchedDir(B);if(!this.fsw.options.followSymlinks){this.fsw._incrReadyCount();let $;try{$=await y80(A)}catch(Z){return this.fsw._emitReady(),!0}if(this.fsw.closed)return;if(D.has(w)){if(this.fsw._symlinkPaths.get(f)!==$)this.fsw._symlinkPaths.set(f,$),this.fsw._emit(y3.CHANGE,A,x.stats)}else D.add(w),this.fsw._symlinkPaths.set(f,$),this.fsw._emit(y3.ADD,A,x.stats);return this.fsw._emitReady(),!0}if(this.fsw._symlinkPaths.has(f))return!0;this.fsw._symlinkPaths.set(f,!0)}_handleRead(x,B,A,w,f,D,$){x=F6.join(x,"");let Z=w?`${x}:${w}`:x;if($=this.fsw._throttle("readdir",Z,1000),!$)return;let Q=this.fsw._getWatchedDir(A.path),Y=new Set,W=this.fsw._readdirp(x,{fileFilter:(H)=>A.filterPath(H),directoryFilter:(H)=>A.filterDir(H)});if(!W)return;return W.on(br8,async(H)=>{if(this.fsw.closed){W=void 0;return}let F=H.path,K=F6.join(x,F);if(Y.add(F),H.stats.isSymbolicLink()&&await this._handleSymlink(H,x,K,F))return;if(this.fsw.closed){W=void 0;return}if(F===w||!w&&!Q.has(F))this.fsw._incrReadyCount(),K=F6.join(f,F6.relative(f,K)),this._addToNodeFs(K,B,A,D+1)}).on(y3.ERROR,this._boundHandleError),new Promise((H,F)=>{if(!W)return F();W.once(c80,()=>{if(this.fsw.closed){W=void 0;return}let K=$?$.clear():!1;if(H(void 0),Q.getChildren().filter((q)=>{return q!==x&&!Y.has(q)}).forEach((q)=>{this.fsw._remove(x,q)}),W=void 0,K)this._handleRead(x,!1,A,w,f,D,$)})})}async _handleDir(x,B,A,w,f,D,$){let Z=this.fsw._getWatchedDir(F6.dirname(x)),Q=Z.has(F6.basename(x));if(!(A&&this.fsw.options.ignoreInitial)&&!f&&!Q)this.fsw._emit(y3.ADD_DIR,x,B);Z.add(F6.basename(x)),this.fsw._getWatchedDir(x);let Y,W,H=this.fsw.options.depth;if((H==null||w<=H)&&!this.fsw._symlinkPaths.has($)){if(!f){if(await this._handleRead(x,A,D,f,x,w,Y),this.fsw.closed)return}W=this._watchWithNodeFs(x,(F,K)=>{if(K&&K.mtimeMs===0)return;this._handleRead(F,!1,D,f,x,w,Y)})}return W}async _addToNodeFs(x,B,A,w,f){let D=this.fsw._emitReady;if(this.fsw._isIgnored(x)||this.fsw.closed)return D(),!1;let $=this.fsw._getWatchHelpers(x);if(A)$.filterPath=(Z)=>A.filterPath(Z),$.filterDir=(Z)=>A.filterDir(Z);try{let Z=await jr8[$.statMethod]($.watchPath);if(this.fsw.closed)return;if(this.fsw._isIgnored($.watchPath,Z))return D(),!1;let Q=this.fsw.options.followSymlinks,Y;if(Z.isDirectory()){let W=F6.resolve(x),H=Q?await y80(x):x;if(this.fsw.closed)return;if(Y=await this._handleDir($.watchPath,Z,B,w,f,$,H),this.fsw.closed)return;if(W!==H&&H!==void 0)this.fsw._symlinkPaths.set(W,H)}else if(Z.isSymbolicLink()){let W=Q?await y80(x):x;if(this.fsw.closed)return;let H=F6.dirname($.watchPath);if(this.fsw._getWatchedDir(H).add($.watchPath),this.fsw._emit(y3.ADD,$.watchPath,Z),Y=await this._handleDir(H,Z,B,w,x,$,W),this.fsw.closed)return;if(W!==void 0)this.fsw._symlinkPaths.set(F6.resolve(x),W)}else Y=this._handleFile($.watchPath,Z,B);if(D(),Y)this.fsw._addPathCloser(x,Y);return!1}catch(Z){if(this.fsw._handleError(Z))return D(),x}}}/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */var p80="/",hr8="//",jKx=".",Rr8="..",yr8="string",mr8=/\\/g,_Kx=/\/\//g,Cr8=/\..*\.(sw[px])$|~$|\.subl.*\.tmp/,cr8=/^\.[/\\]/;function pO(x){return Array.isArray(x)?x:[x]}var u80=(x)=>typeof x==="object"&&x!==null&&!(x instanceof RegExp);function gr8(x){if(typeof x==="function")return x;if(typeof x==="string")return(B)=>x===B;if(x instanceof RegExp)return(B)=>x.test(B);if(typeof x==="object"&&x!==null)return(B)=>{if(x.path===B)return!0;if(x.recursive){let A=h8.relative(x.path,B);if(!A)return!1;return!A.startsWith("..")&&!h8.isAbsolute(A)}return!1};return()=>!1}function Tr8(x){if(typeof x!=="string")throw Error("string expected");x=h8.normalize(x),x=x.replace(/\\/g,"/");let B=!1;if(x.startsWith("//"))B=!0;if(x=x.replace(_Kx,"/"),B)x="/"+x;return x}function VKx(x,B,A){let w=Tr8(B);for(let f=0;f<x.length;f++){let D=x[f];if(D(w,A))return!0}return!1}function pr8(x,B){if(x==null)throw TypeError("anymatch: specify first argument");let w=pO(x).map((f)=>gr8(f));if(B==null)return(f,D)=>{return VKx(w,f,D)};return VKx(w,B)}var UKx=(x)=>{let B=pO(x).flat();if(!B.every((A)=>typeof A===yr8))throw TypeError(`Non-string provided as watch path: ${B}`);return B.map(PKx)},GKx=(x)=>{let B=x.replace(mr8,p80),A=!1;if(B.startsWith(hr8))A=!0;if(B=B.replace(_Kx,p80),A)B=p80+B;return B},PKx=(x)=>GKx(h8.normalize(GKx(x))),EKx=(x="")=>(B)=>{if(typeof B==="string")return PKx(h8.isAbsolute(B)?B:h8.join(x,B));else return B},ur8=(x,B)=>{if(h8.isAbsolute(x))return x;return h8.join(B,x)},Sr8=Object.freeze(new Set);class JKx{path;_removeWatcher;items;constructor(x,B){this.path=x,this._removeWatcher=B,this.items=new Set}add(x){let{items:B}=this;if(!B)return;if(x!==jKx&&x!==Rr8)B.add(x)}async remove(x){let{items:B}=this;if(!B)return;if(B.delete(x),B.size>0)return;let A=this.path;try{await Ir8(A)}catch(w){if(this._removeWatcher)this._removeWatcher(h8.dirname(A),h8.basename(A))}}has(x){let{items:B}=this;if(!B)return;return B.has(x)}getChildren(){let{items:x}=this;if(!x)return[];return[...x.values()]}dispose(){this.items.clear(),this.path="",this._removeWatcher=gO,this.items=Sr8,Object.freeze(this)}}var ir8="stat",lr8="lstat";class LKx{fsw;path;watchPath;fullWatchPath;dirParts;followSymlinks;statMethod;constructor(x,B,A){this.fsw=A;let w=x;this.path=x=x.replace(cr8,""),this.watchPath=w,this.fullWatchPath=h8.resolve(w),this.dirParts=[],this.dirParts.forEach((f)=>{if(f.length>1)f.pop()}),this.followSymlinks=B,this.statMethod=B?ir8:lr8}entryPath(x){return h8.join(this.watchPath,h8.relative(this.watchPath,x.fullPath))}filterPath(x){let{stats:B}=x;if(B&&B.isSymbolicLink())return this.filterDir(x);let A=this.entryPath(x);return this.fsw._isntIgnored(A,B)&&this.fsw._hasReadPermissions(B)}filterDir(x){return this.fsw._isntIgnored(this.entryPath(x),x.stats)}}class S80 extends vr8{closed;options;_closers;_ignoredPaths;_throttled;_streams;_symlinkPaths;_watched;_pendingWrites;_pendingUnlinks;_readyCount;_emitReady;_closePromise;_userIgnored;_readyEmitted;_emitRaw;_boundRemove;_nodeFsHandler;constructor(x={}){super();this.closed=!1,this._closers=new Map,this._ignoredPaths=new Set,this._throttled=new Map,this._streams=new Set,this._symlinkPaths=new Map,this._watched=new Map,this._pendingWrites=new Map,this._pendingUnlinks=new Map,this._readyCount=0,this._readyEmitted=!1;let B=x.awaitWriteFinish,A={stabilityThreshold:2000,pollInterval:100},w={persistent:!0,ignoreInitial:!1,ignorePermissionErrors:!1,interval:100,binaryInterval:300,followSymlinks:!0,usePolling:!1,atomic:!0,...x,ignored:x.ignored?pO(x.ignored):pO([]),awaitWriteFinish:B===!0?A:typeof B==="object"?{...A,...B}:!1};if(zKx)w.usePolling=!0;if(w.atomic===void 0)w.atomic=!w.usePolling;let f=process.env.CHOKIDAR_USEPOLLING;if(f!==void 0){let Z=f.toLowerCase();if(Z==="false"||Z==="0")w.usePolling=!1;else if(Z==="true"||Z==="1")w.usePolling=!0;else w.usePolling=!!Z}let D=process.env.CHOKIDAR_INTERVAL;if(D)w.interval=Number.parseInt(D,10);let $=0;this._emitReady=()=>{if($++,$>=this._readyCount)this._emitReady=gO,this._readyEmitted=!0,process.nextTick(()=>this.emit(A6.READY))},this._emitRaw=(...Z)=>this.emit(A6.RAW,...Z),this._boundRemove=this._remove.bind(this),this.options=w,this._nodeFsHandler=new T80(this),Object.freeze(w)}_addIgnoredPath(x){if(u80(x)){for(let B of this._ignoredPaths)if(u80(B)&&B.path===x.path&&B.recursive===x.recursive)return}this._ignoredPaths.add(x)}_removeIgnoredPath(x){if(this._ignoredPaths.delete(x),typeof x==="string"){for(let B of this._ignoredPaths)if(u80(B)&&B.path===x)this._ignoredPaths.delete(B)}}add(x,B,A){let{cwd:w}=this.options;this.closed=!1,this._closePromise=void 0;let f=UKx(x);if(w)f=f.map((D)=>{return ur8(D,w)});if(f.forEach((D)=>{this._removeIgnoredPath(D)}),this._userIgnored=void 0,!this._readyCount)this._readyCount=0;return this._readyCount+=f.length,Promise.all(f.map(async(D)=>{let $=await this._nodeFsHandler._addToNodeFs(D,!A,void 0,0,B);if($)this._emitReady();return $})).then((D)=>{if(this.closed)return;D.forEach(($)=>{if($)this.add(h8.dirname($),h8.basename(B||$))})}),this}unwatch(x){if(this.closed)return this;let B=UKx(x),{cwd:A}=this.options;return B.forEach((w)=>{if(!h8.isAbsolute(w)&&!this._closers.has(w)){if(A)w=h8.join(A,w);w=h8.resolve(w)}if(this._closePath(w),this._addIgnoredPath(w),this._watched.has(w))this._addIgnoredPath({path:w,recursive:!0});this._userIgnored=void 0}),this}close(){if(this._closePromise)return this._closePromise;this.closed=!0,this.removeAllListeners();let x=[];return this._closers.forEach((B)=>B.forEach((A)=>{let w=A();if(w instanceof Promise)x.push(w)})),this._streams.forEach((B)=>B.destroy()),this._userIgnored=void 0,this._readyCount=0,this._readyEmitted=!1,this._watched.forEach((B)=>B.dispose()),this._closers.clear(),this._watched.clear(),this._streams.clear(),this._symlinkPaths.clear(),this._throttled.clear(),this._closePromise=x.length?Promise.all(x).then(()=>{return}):Promise.resolve(),this._closePromise}getWatched(){let x={};return this._watched.forEach((B,A)=>{let f=(this.options.cwd?h8.relative(this.options.cwd,A):A)||jKx;x[f]=B.getChildren().sort()}),x}emitWithAll(x,B){if(this.emit(x,...B),x!==A6.ERROR)this.emit(A6.ALL,x,...B)}async _emit(x,B,A){if(this.closed)return;let w=this.options;if(g80)B=h8.normalize(B);if(w.cwd)B=h8.relative(w.cwd,B);let f=[B];if(A!=null)f.push(A);let D=w.awaitWriteFinish,$;if(D&&($=this._pendingWrites.get(B)))return $.lastChange=new Date,this;if(w.atomic){if(x===A6.UNLINK)return this._pendingUnlinks.set(B,[x,...f]),setTimeout(()=>{this._pendingUnlinks.forEach((Z,Q)=>{this.emit(...Z),this.emit(A6.ALL,...Z),this._pendingUnlinks.delete(Q)})},typeof w.atomic==="number"?w.atomic:100),this;if(x===A6.ADD&&this._pendingUnlinks.has(B))x=A6.CHANGE,this._pendingUnlinks.delete(B)}if(D&&(x===A6.ADD||x===A6.CHANGE)&&this._readyEmitted){let Z=(Q,Y)=>{if(Q)x=A6.ERROR,f[0]=Q,this.emitWithAll(x,f);else if(Y){if(f.length>1)f[1]=Y;else f.push(Y);this.emitWithAll(x,f)}};return this._awaitWriteFinish(B,D.stabilityThreshold,x,Z),this}if(x===A6.CHANGE){if(!this._throttle(A6.CHANGE,B,50))return this}if(w.alwaysStat&&A===void 0&&(x===A6.ADD||x===A6.ADD_DIR||x===A6.CHANGE)){let Z=w.cwd?h8.join(w.cwd,B):B,Q;try{Q=await Or8(Z)}catch(Y){}if(!Q||this.closed)return;f.push(Q)}return this.emitWithAll(x,f),this}_handleError(x){let B=x&&x.code;if(x&&B!=="ENOENT"&&B!=="ENOTDIR"&&(!this.options.ignorePermissionErrors||B!=="EPERM"&&B!=="EACCES"))this.emit(A6.ERROR,x);return x||this.closed}_throttle(x,B,A){if(!this._throttled.has(x))this._throttled.set(x,new Map);let w=this._throttled.get(x);if(!w)throw Error("invalid throttle");let f=w.get(B);if(f)return f.count++,!1;let D,$=()=>{let Q=w.get(B),Y=Q?Q.count:0;if(w.delete(B),clearTimeout(D),Q)clearTimeout(Q.timeoutObject);return Y};D=setTimeout($,A);let Z={timeoutObject:D,clear:$,count:0};return w.set(B,Z),Z}_incrReadyCount(){return this._readyCount++}_awaitWriteFinish(x,B,A,w){let f=this.options.awaitWriteFinish;if(typeof f!=="object")return;let D=f.pollInterval,$,Z=x;if(this.options.cwd&&!h8.isAbsolute(x))Z=h8.join(this.options.cwd,x);let Q=new Date,Y=this._pendingWrites;function W(H){Nr8(Z,(F,K)=>{if(F||!Y.has(x)){if(F&&F.code!=="ENOENT")w(F);return}let q=Number(new Date);if(H&&K.size!==H.size)Y.get(x).lastChange=q;let V=Y.get(x);if(q-V.lastChange>=B)Y.delete(x),w(void 0,K);else $=setTimeout(W,D,K)})}if(!Y.has(x))Y.set(x,{lastChange:Q,cancelWait:()=>{return Y.delete(x),clearTimeout($),A}}),$=setTimeout(W,D)}_isIgnored(x,B){if(this.options.atomic&&Cr8.test(x))return!0;if(!this._userIgnored){let{cwd:A}=this.options,f=(this.options.ignored||[]).map(EKx(A)),$=[...[...this._ignoredPaths].map(EKx(A)),...f];this._userIgnored=pr8($,void 0)}return this._userIgnored(x,B)}_isntIgnored(x,B){return!this._isIgnored(x,B)}_getWatchHelpers(x){return new LKx(x,this.options.followSymlinks,this)}_getWatchedDir(x){let B=h8.resolve(x);if(!this._watched.has(B))this._watched.set(B,new JKx(B,this._boundRemove));return this._watched.get(B)}_hasReadPermissions(x){if(this.options.ignorePermissionErrors)return!0;return Boolean(Number(x.mode)&256)}_remove(x,B,A){let w=h8.join(x,B),f=h8.resolve(w);if(A=A!=null?A:this._watched.has(w)||this._watched.has(f),!this._throttle("remove",w,100))return;if(!A&&this._watched.size===1)this.add(x,B,!0);this._getWatchedDir(w).getChildren().forEach((H)=>this._remove(w,H));let Z=this._getWatchedDir(x),Q=Z.has(B);if(Z.remove(B),this._symlinkPaths.has(f))this._symlinkPaths.delete(f);let Y=w;if(this.options.cwd)Y=h8.relative(this.options.cwd,w);if(this.options.awaitWriteFinish&&this._pendingWrites.has(Y)){if(this._pendingWrites.get(Y).cancelWait()===A6.ADD)return}this._watched.delete(w),this._watched.delete(f);let W=A?A6.UNLINK_DIR:A6.UNLINK;if(Q&&!this._isIgnored(w))this._emit(W,w);this._closePath(w)}_closePath(x){this._closeFile(x);let B=h8.dirname(x);this._getWatchedDir(B).remove(h8.basename(x))}_closeFile(x){let B=this._closers.get(x);if(!B)return;B.forEach((A)=>A()),this._closers.delete(x)}_addPathCloser(x,B){if(!B)return;let A=this._closers.get(x);if(!A)A=[],this._closers.set(x,A);A.push(B)}_readdirp(x,B){if(this.closed)return;let A={type:A6.ALL,alwaysStat:!0,lstat:!0,...B,depth:0},w=WKx(x,A);return this._streams.add(w),w.once(qKx,()=>{w=void 0}),w.once(c80,()=>{if(w)this._streams.delete(w),w=void 0}),w}}function nr8(x,B={}){let A=new S80(B);return A.add(x),A}var kKx={watch:nr8,FSWatcher:S80};import{extname as dr8}from"path";var uO=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function fY(x){let B=dr8(x).toLowerCase();return uO.includes(B)}function MKx(x){switch(x.toLowerCase().replace(".","")){case"jpg":case"jpeg":return"image/jpeg";case"png":return"image/png";case"gif":return"image/gif";case"webp":return"image/webp";case"svg":return"image/svg+xml";default:return"image/png"}}function i80(x){switch(x.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${x.toLowerCase()}`}}import{isAbsolute as ar8,relative as sr8,sep as vKx,join as rr8}from"path";function s4(x,B){return ar8(B)?B:rr8(x,B)}function lA(x,B){let A=s4(x,B),w=sr8(x,A);return vKx==="/"?w:w.split(vKx).join("/")}var or8=1e4;function tr8(x,B){if(!lA(B,x).startsWith("image/"))return!1;return fY(x)}function er8(x,B){if(lA(B,x).split("/")[0]?.startsWith("_"))return!1;if(x.endsWith(".md"))return!0;return tr8(x,B)}class l80{watcher;watchCallback;pendingChanges=new Map;suppressedPaths=new Map;delayScope;delayedBatches;clock;activeCallbacks=new Set;stopPromise=null;stopping=!1;syncPath;watchInterval;logger;onFileChange;onFileChanges;constructor(x){this.syncPath=x.syncPath,this.watchInterval=x.watchInterval,this.logger=x.logger,this.onFileChange=x.onFileChange,this.onFileChanges=x.onFileChanges,this.clock=x.clock,this.delayScope=H0.runSync(y9.make()),this.delayedBatches=H0.runSync(y9.extend(QB.make(),this.delayScope))}async start(){if(this.watcher){this.logger.debug("Already watching directory");return}if(this.stopping)throw Error("Cannot restart a stopped file watcher");this.logger.debug("Starting directory watch",{path:this.syncPath,interval:this.watchInterval});let x=kKx.watch(this.syncPath,{ignored:/(^|[/\\])\../,ignoreInitial:!0,persistent:!0,interval:this.watchInterval,awaitWriteFinish:{stabilityThreshold:2000,pollInterval:100}});if(this.watcher=x,x.on("add",(B)=>void this.handleFileChange("add",B)).on("change",(B)=>void this.handleFileChange("change",B)).on("unlink",(B)=>void this.handleFileChange("delete",B)).on("error",(B)=>this.logger.error("Watcher error",B)),this.watchCallback)x.on("all",this.watchCallback);try{await this.awaitReady(x)}catch(B){this.watcher=void 0;try{await x.close()}catch{}throw B}}stop(){return this.stopping=!0,this.stopPromise??=this.stopWatcher(),this.stopPromise}async stopWatcher(){let x=this.watcher;this.watcher=void 0;let B=this.closeDelayScope();this.pendingChanges.clear(),this.suppressedPaths.clear();let A=[B,...x?[x.close()]:[],...this.activeCallbacks],f=(await Promise.allSettled(A)).find((D)=>D.status==="rejected");if(x)this.logger.info("Stopped directory watch");if(f)throw f.reason}awaitReady(x){return new Promise((B,A)=>{let w=()=>{x.off("error",f),B()},f=(D)=>{x.off("ready",w),A(D)};x.once("ready",w),x.once("error",f)})}setCallback(x){if(this.watchCallback=x,this.watcher)this.watcher.on("all",x)}suppressPaths(x){let B=Date.now()+or8;for(let A of x){let w=lA(this.syncPath,A);this.pendingChanges.delete(w),this.suppressedPaths.set(w,B)}}async handleFileChange(x,B){if(this.stopping||!er8(B,this.syncPath))return;let A=lA(this.syncPath,B);if(this.isSuppressed(A)){this.logger.debug("Suppressed git-triggered file change",{event:x,path:B});return}this.logger.debug("File change detected",{event:x,path:B}),this.pendingChanges.set(A,x);let w=H0.sleep(500).pipe(H0.andThen(H0.sync(()=>this.startPendingProcessing()))),f=this.clock?H0.withClock(w,this.clock):w;QB.unsafeSet(this.delayedBatches,"file-change-batch",H0.runFork(f))}async processPendingChanges(){if(this.pendingChanges.size===0)return;let x=new Map(this.pendingChanges);if(this.pendingChanges.clear(),this.logger.debug("Processing batched file changes",{changeCount:x.size}),this.onFileChanges){let B=new Map([...x].map(([A,w])=>[s4(this.syncPath,A),w]));try{await this.onFileChanges(B)}catch(A){this.logger.error("Error processing file change batch",{error:A})}return}for(let[B,A]of x){let w=s4(this.syncPath,B);try{if(this.onFileChange)await this.onFileChange(A,w)}catch(f){this.logger.error("Error processing file change",{path:B,event:A,error:f})}}}isSuppressed(x){let B=this.suppressedPaths.get(x);if(B===void 0)return!1;return this.suppressedPaths.delete(x),B>Date.now()}startPendingProcessing(){if(this.stopping)return;let x=this.processPendingChanges();this.activeCallbacks.add(x),x.then(()=>this.activeCallbacks.delete(x),()=>this.activeCallbacks.delete(x))}async closeDelayScope(){let x=await H0.runPromiseExit(y9.close(this.delayScope,f5.void));if(f5.isFailure(x))throw _4.squash(x.cause)}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}async function NKx(x,B){if(x?.isWatching())return B.logger.debug("Already watching directory"),x;return xo8(B)}async function IKx(x){await x?.stop()}function OKx(x,B){if(x)x.setCallback(B)}async function xo8(x){let{logger:B,syncPath:A,watchInterval:w,importEntities:f,jobQueueCallback:D,fileOperations:$,deleteOnFileRemoval:Z}=x,Q=new O80(B,f,D,$,Z),Y=new l80({syncPath:A,watchInterval:w,logger:B,onFileChanges:async(W)=>{await Q.handleFileChanges(W)}});return await Y.start(),Y}async function hKx(x){let B=Date.now();x.logger.debug("Starting sync (import only)");let A=await x.importEntities(),w=await x.removeOrphanedEntities(),f=Date.now()-B;return x.markSynced(new Date),x.logger.debug("Sync completed",{duration:f,imported:A.imported,orphansDeleted:w.deleted}),{export:{exported:0,failed:0,errors:[]},import:A,duration:f}}class n80{logger;syncPath;deleteOnFileRemoval;constructor(x){this.logger=x.logger,this.syncPath=x.syncPath,this.deleteOnFileRemoval=x.deleteOnFileRemoval}prepareBatchOperations(x,B=!0){let A=[],w=this.createImportOperations(x);A.push(...w);let f=w.length;if(B&&this.deleteOnFileRemoval)A.push({type:"directory-cleanup",data:{}});let D=x.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:f,totalFiles:D}),{operations:A,exportOperationsCount:0,importOperationsCount:f,totalFiles:D}}async queueSyncBatch(x,B,A,w,f=!0){let D=this.prepareBatchOperations(A,f);if(D.operations.length===0)return this.logger.debug("No sync operations needed",{source:B}),null;return{batchId:await x.jobs.enqueueBatch(D.operations,{source:B,rootJobId:w?.rootJobId??DY(),metadata:{progressToken:w?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:w?.pluginId??"directory-sync",interfaceType:w?.interfaceType,channelId:w?.channelId}}),operationCount:D.operations.length,exportOperationsCount:D.exportOperationsCount,importOperationsCount:D.importOperationsCount,totalFiles:D.totalFiles}}createImportOperations(x){if(x.length===0)return[];let B=50,A=[];for(let w=0;w<x.length;w+=B){let f=x.slice(w,w+B);A.push({type:"directory-import",data:{batchIndex:Math.floor(w/B),paths:f,batchSize:f.length}})}return A}}import{extname as Bo8}from"path";var SO=[".pdf"],iO=".meta.json";function $Y(x){let B=Bo8(x).toLowerCase();return SO.includes(B)}function lO(x){return x.toLowerCase().endsWith(iO)}function d80(x){return`${x}${iO}`}function RKx(x){switch(x.toLowerCase().replace(".","")){case"pdf":default:return"application/pdf"}}class a80{syncInProgress=!1;logger;syncPath;fileOperations;batchOperationsManager;constructor(x){this.logger=x.logger,this.syncPath=x.syncPath,this.fileOperations=x.fileOperations,this.batchOperationsManager=new n80({logger:x.logger,syncPath:x.syncPath,deleteOnFileRemoval:x.deleteOnFileRemoval})}async queueSyncBatch(x,B,A,w){if(this.syncInProgress)return this.logger.debug("Sync already in progress, skipping",{source:B}),null;this.syncInProgress=!0;try{let f=await this.fileOperations.getAllSyncFiles(),D=w?await this.selectChangedFiles(f,w):{files:f,includeCleanup:!0};return await this.batchOperationsManager.queueSyncBatch(x,B,D.files,A,D.includeCleanup)}finally{this.syncInProgress=!1}}async selectChangedFiles(x,B){let A=new Set(B.map((D)=>this.normalizePath(D))),w=x.filter((D)=>A.has(lA(this.syncPath,D))),f=!1;for(let D of A)if(!await this.fileOperations.fileExists(s4(this.syncPath,D))){f=!0;break}return{files:w,includeCleanup:f}}normalizePath(x){let B=lA(this.syncPath,x);return lO(B)?B.slice(0,-iO.length):B}}class s80{options;constructor(x){this.options=x}createExportDeps(x,B){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:x,entityTypes:B}}createImportDeps(x){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,quarantine:this.options.quarantine,imageJobQueue:this.createImageJobQueueDeps(),entityTypes:x}}createCleanupDeps(x,B){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:x,entityTypes:B}}createImageJobQueueDeps(){return{logger:this.options.logger,syncPath:this.options.syncPath,jobQueueCallback:this.options.getJobQueueCallback(),coverImageConverter:this.options.coverImageConverter,inlineImageConverter:this.options.inlineImageConverter}}}import{basename as $o8,dirname as Zo8,extname as Qo8}from"path";import{extname as Ao8,join as nO}from"path";function dO(x,B){let w=lA(x,B).split("/"),f,D;if(w.length===1)f="note",D=w;else if(w.length>1&&w[0])f=w[0],D=w.slice(1);else f="note",D=w;let $;if(D.length>1){let Z=D[D.length-1];if(Z)D[D.length-1]=yKx(Z);$=D.join(":")}else $=yKx(D[0]??"");return{entityType:f,id:$}}function mKx(x,B,A,w=".md"){let f=B.split(":").filter((Y)=>Y.length>0),D=A==="note";if(f.length===1)return D?nO(x,`${f[0]}${w}`):nO(x,A,`${f[0]}${w}`);let $=f;if(f[0]===A)$=f.slice(1);let Z=$[$.length-1],Q=$.slice(0,-1);if(D)return nO(x,...Q,`${Z}${w}`);return nO(x,A,...Q,`${Z}${w}`)}function CKx(x){if(x.entityType==="document")return".pdf";if(x.entityType!=="image")return".md";let B=x.metadata.format;if(B)return i80(B);let A=x.content.match(/^data:image\/([a-z+]+);base64,/i);return A?.[1]?i80(A[1]):".md"}function yKx(x){let B=Ao8(x).toLowerCase();return B===".md"||uO.includes(B)||SO.includes(B)?x.slice(0,-B.length):x}import{mkdir as Xo8,readFile as $q,writeFile as o80,stat as Yo8,utimes as Wo8}from"fs/promises";import{join as aO}from"path";import{mkdir as cKx,readdir as fo8,stat as Do8}from"fs/promises";import{access as wo8}from"fs/promises";async function s6(x){try{return await wo8(x),!0}catch{return!1}}async function r80(x,B){return uKx(x,B,{includeDocuments:!1,includeImages:!1})}async function gKx(x,B){return uKx(x,B,{includeDocuments:!0,includeImages:!0})}async function TKx(x,B){if(!await s6(x))await cKx(x,{recursive:!0});for(let A of B)if(A!=="note")await cKx(aO(x,A),{recursive:!0})}async function pKx(x,B){let A=[],w={totalFiles:0,byEntityType:{}};if(!await s6(x))return{files:A,stats:w};let f=await r80(x,B);for(let D of f)try{let $=aO(x,D),Z=await Do8($),{entityType:Q}=dO(x,D);A.push({path:D,entityType:Q,modified:Z.mtime}),w.totalFiles++,w.byEntityType[Q]=(w.byEntityType[Q]??0)+1}catch{continue}return{files:A,stats:w}}async function uKx(x,B,A){let w=[];if(!await s6(x))return w;let f=async(D,$="",Z=!1,Q=!1)=>{let Y=await fo8(D,{withFileTypes:!0});for(let W of Y){let H=$?aO($,W.name):W.name;if(W.isFile()&&!W.name.endsWith(".invalid")&&!lO(W.name)){if(W.name.endsWith(".md"))w.push(H);else if(A.includeImages&&Z&&fY(W.name))w.push(H);else if(A.includeDocuments&&Q&&$Y(W.name))w.push(H)}else if(W.isDirectory()&&!W.name.startsWith(".")){if($===""&&!B.hasEntityType(W.name))continue;let F=aO(D,W.name),K=W.name==="image"&&$==="",q=W.name==="document"&&$==="";await f(F,H,Z||K,Q||q)}}};return await f(x),w}var Ho8=X.record(X.string(),X.unknown());class t80{syncPath;entityService;constructor(x,B){this.syncPath=x,this.entityService=B}parseEntityFromPath(x){return dO(this.syncPath,x)}async readEntity(x){let B=s4(this.syncPath,x),A=await Yo8(B),{entityType:w,id:f}=this.parseEntityFromPath(x),D=A.birthtime.getTime()>0?A.birthtime:A.mtime,$=A.mtime,Z,Q;if(fY(x)||$Y(x)){let H=(await $q(B)).toString("base64"),F=Qo8(x);if(Z=`data:${$Y(x)?RKx(F):MKx(F)};base64,${H}`,$Y(x))Q=await this.readDocumentSidecar(B,x)}else Z=await $q(B,"utf-8");let Y={entityType:w,id:f,content:Z,created:D,updated:$};if(Q)Y.metadata=Q;return Y}async readDocumentSidecar(x,B){let A={mimeType:"application/pdf",filename:$o8(B)},w=d80(x);if(!await s6(w))return A;try{let f=await $q(w,"utf-8"),D=Ho8.safeParse(JSON.parse(f));return{...A,...D.success?D.data:{}}}catch{return A}}async writeEntity(x){let B=this.getEntityFilePath(x),A=x.entityType==="image",w=x.entityType==="document";if(A||w){let D=A?/^data:image\/[a-z+]+;base64,(.+)$/i:/^data:application\/pdf;base64,(.+)$/i,$=x.content.match(D),Z=$?.[1]?Buffer.from($[1],"base64"):Buffer.from(x.content,"base64"),Q=!1;if(await s6(B)){let Y=await $q(B),W=_8(Y.toString("base64")),H=_8(Z.toString("base64"));if(W===H)Q=!0}if(!Q)await this.ensureEntityDirectory(x,B),await o80(B,Z);if(w)await this.writeDocumentSidecar(x,B);if(Q)return}else{let D=this.entityService.serializeEntity(x);if(await s6(B)){let $=await $q(B,"utf-8"),Z=_8($),Q=_8(D);if(Z===Q)return}await this.ensureEntityDirectory(x,B),await o80(B,D,"utf-8")}let f=new Date(x.updated);await Wo8(B,f,f)}async ensureEntityDirectory(x,B){if(x.entityType!=="note")await Xo8(Zo8(B),{recursive:!0})}async writeDocumentSidecar(x,B){let A=x.metadata,w={};for(let[$,Z]of Object.entries(A)){if($==="mimeType")continue;if(Z===void 0)continue;w[$]=Z}let f=d80(B),D=`${JSON.stringify(w,null,2)}
5437
5437
  `;if(await s6(f)){if(await $q(f,"utf-8")===D)return}await this.ensureEntityDirectory(x,f),await o80(f,D,"utf-8")}getFilePath(x,B,A=".md"){return mKx(this.syncPath,x,B,A)}getEntityFilePath(x){return this.getFilePath(x.id,x.entityType,CKx(x))}async getAllMarkdownFiles(){return r80(this.syncPath,this.entityService)}async getAllSyncFiles(){return gKx(this.syncPath,this.entityService)}async ensureDirectoryStructure(x){await TKx(this.syncPath,x)}shouldUpdateEntity(x,B){let A=_8(B.content);return x.contentHash!==A}async gatherFileStatus(){return pKx(this.syncPath,this.entityService)}async syncDirectoryExists(){return s6(this.syncPath)}async fileExists(x){return s6(x)}}async function tO(x,B,A,w){let{sourceUrl:f}=x,D=await B.listEntities({entityType:"image",options:{filter:{metadata:{sourceUrl:f}},limit:1}});if(D[0])return w.debug("Reusing existing image entity",{sourceUrl:f,imageId:D[0].id}),D[0].id;let $=await A(f),{base64:Z}=sO($),Q=rO(Z),Y=oO(Z);if(!Q||!Y)throw Error("Could not detect image format or dimensions");let W=await B.createEntity({entity:{id:x.id,entityType:"image",content:$,metadata:{title:x.title,alt:x.alt,format:Q,width:Y.width,height:Y.height,sourceUrl:f}}});return w.debug("Created image entity from URL",{sourceUrl:f,imageId:W.entityId}),W.entityId}var SKx=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class e80{entityService;fetcher;logger;constructor(x,B,A=m3){this.entityService=x,this.fetcher=A,this.logger=B.child("FrontmatterImageConverter")}detectCoverImageUrl(x){let B;try{B=I1(x)}catch{return null}let{frontmatter:A}=B,w=SKx.safeParse(A);if(!w.success)return null;if(w.data.coverImageId)return null;let{title:f,slug:D,coverImageUrl:$,coverImageAlt:Z}=w.data;if(!fj($))return null;return{sourceUrl:$,postTitle:f,postSlug:D??Gx(f),customAlt:Z}}async convert(x){let B;try{B=I1(x)}catch(Y){return this.logger.debug("Parse failed",{error:Y}),{content:x,converted:!1}}let{frontmatter:A}=B,w=SKx.safeParse(A);if(!w.success)return{content:x,converted:!1};if(w.data.coverImageId)return{content:x,converted:!1};let{title:f,slug:D,coverImageUrl:$,coverImageAlt:Z}=w.data;if(!fj($))return{content:x,converted:!1};let Q={postTitle:f,postSlug:D??Gx(f),sourceUrl:$,customAlt:Z};try{let Y=await this.createImageEntity(Q),W={...A};return delete W.coverImageUrl,delete W.coverImageAlt,W.coverImageId=Y,{content:eO(W,B.content),converted:!0,imageId:Y}}catch(Y){return this.logger.warn("Failed to convert coverImageUrl",{url:$,error:g(Y)}),{content:x,converted:!1}}}async createImageEntity(x){let{postTitle:B,postSlug:A,sourceUrl:w,customAlt:f}=x,D=`Cover image for ${B}`;return tO({id:`${A}-cover`,title:D,alt:f??D,sourceUrl:w},this.entityService,this.fetcher,this.logger)}}class Dj{entityService;fetcher;logger;constructor(x,B,A=m3){this.entityService=x,this.fetcher=A,this.logger=B.child("MarkdownImageConverter")}detectInlineImages(x,B){let A=[],w=iKx(x);for(let f of w){if(!fj(f.url))continue;if(f.url.startsWith("entity://"))continue;let D=this.reconstructMarkdown(f);A.push({sourceUrl:f.url,alt:f.alt,originalMarkdown:D,postSlug:B})}return A}reconstructMarkdown(x){if(x.title)return`![${x.alt}](${x.url} "${x.title}")`;return`![${x.alt}](${x.url})`}async convert(x,B){let A=this.detectInlineImages(x,B);if(A.length===0)return{content:x,converted:!1,convertedCount:0};let w=x,f=0,D=0;for(let $ of A)try{let Z=await this.createImageEntity($,D++),Q=`![${$.alt}](entity://image/${Z})`;w=w.replace($.originalMarkdown,Q),f++,this.logger.debug("Converted inline image",{sourceUrl:$.sourceUrl,imageId:Z})}catch(Z){this.logger.warn("Failed to convert inline image",{sourceUrl:$.sourceUrl,error:g(Z)})}return{content:w,converted:f>0,convertedCount:f}}async createImageEntity(x,B){let{sourceUrl:A,alt:w,postSlug:f}=x;return tO({id:`${f}-inline-${B}`,title:w||`Inline image ${B+1} for ${f}`,alt:w||"",sourceUrl:A},this.entityService,this.fetcher,this.logger)}}class x90{logger;entityService;fileOperations;constructor(x,B,A){this.logger=x,this.entityService=B,this.fileOperations=A}async importEntitiesWithProgress(x,B,A,w){this.logger.debug("Importing entities with progress reporting");let f={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},D=x??await this.fileOperations.getAllSyncFiles(),$=D.length;await B.report({progress:0,message:`Starting import of ${$} files`});for(let Z=0;Z<$;Z+=A){let Q=D.slice(Z,Z+A),Y=await w(Q);f.imported+=Y.imported,f.skipped+=Y.skipped,f.failed+=Y.failed,f.quarantined+=Y.quarantined,f.errors.push(...Y.errors),f.quarantinedFiles.push(...Y.quarantinedFiles),f.jobIds.push(...Y.jobIds);let W=Math.min(Z+A,$),H=Math.round(W/$*40);await B.report({progress:H,message:`Imported ${W}/${$} files`})}return f}async exportEntitiesWithProgress(x,B,A,w){this.logger.debug("Exporting entities with progress reporting");let f=x??this.entityService.getEntityTypes();await B.report({progress:50,message:`Starting export of ${f.length} entity types`});let D=await w(x);return await B.report({progress:100,message:`Exported ${D.exported} entities`}),this.logger.debug("Export completed",D),D}}import{rename as Fo8,appendFile as Ko8,readFile as qo8,writeFile as zo8,access as bo8}from"fs/promises";import{join as lKx}from"path";class B90{logger;syncPath;constructor(x,B){this.logger=x,this.syncPath=B}isValidationError(x){return nKx(x)}async quarantineInvalidFile(x,B,A,w){let f=w(x),D=`${f}.invalid`;try{await Fo8(f,D),A.quarantined++,A.quarantinedFiles.push(x);let $=lKx(this.syncPath,".import-errors.log"),Z=new Date().toISOString(),Q=g(B),Y=`${Z} - ${x}: ${Q}
5438
5438
  \u2192 ${x}.invalid
5439
5439
 
@@ -5461,7 +5461,7 @@ facts, owners, or tasks. Return only the required structured JSON.`});var xs8=X.
5461
5461
  *...and ${x.files.length-10} more files*`)}if(x.exists&&x.stats.totalFiles===0)B.push(`
5462
5462
  ## Getting Started
5463
5463
  `),B.push("Your sync directory is empty. Entities will be organized as follows:"),B.push("- Base entities: `/<entity-id>.md`"),B.push("- Other types: `/<entity-type>/<entity-id>.md`");return B.join(`
5464
- `)}}class Jh extends $9{directorySync;operationStatus;constructor(x,B,A,w){super(x,{schema:w60,jobTypeName:"directory-export"});this.directorySync=A,this.operationStatus=w}async process(x,B,A){this.logger.debug("Processing directory export job",{jobId:B,data:x});let w=Date.now();try{let f=await this.directorySync.exportEntitiesWithProgress(x.entityTypes,A,x.batchSize??100);return this.logger.debug("Directory export job completed",{jobId:B,exported:f.exported,failed:f.failed,duration:Date.now()-w}),await this.operationStatus?.addExportResult(f),f}catch(f){throw this.logger.error("Directory export job failed",{jobId:B,error:f}),await this.operationStatus?.recordIssue({kind:"export",message:g(f,"Directory export failed")}),f}}summarizeDataForLog(x){return{entityTypes:x.entityTypes??"all",batchSize:x.batchSize}}}class Lh extends $9{directorySync;operationStatus;constructor(x,B,A,w){super(x,{schema:A60,jobTypeName:"directory-import"});this.directorySync=A,this.operationStatus=w}async process(x,B,A){this.logger.debug("Processing directory import job",{jobId:B,data:x});let w=Date.now();try{let f=await this.directorySync.importEntitiesWithProgress(x.paths,A,x.batchSize??100);return this.logger.debug("Directory import job completed",{jobId:B,imported:f.imported,skipped:f.skipped,failed:f.failed,quarantined:f.quarantined,duration:Date.now()-w}),await this.operationStatus?.addImportResult(f),f}catch(f){throw this.logger.error("Directory import job failed",{jobId:B,error:f}),await this.operationStatus?.recordIssue({kind:"import",message:g(f,"Directory import failed")}),f}}summarizeDataForLog(x){return{pathCount:x.paths?.length??"all",batchSize:x.batchSize}}}var Cx9=300000,cx9=500;async function IVx(x){if(x.jobIds.length===0)return;let B=x.maxWaitMs??Cx9,A=x.pollIntervalMs??cx9;x.logger.debug(`Waiting for ${x.jobIds.length} import jobs to complete`);let w=H0.gen(function*(){let $=yield*FD.currentTimeMillis;yield*H0.gen(function*(){let Y=(yield*H0.tryPromise({try:()=>Promise.all(x.jobIds.map((F)=>x.entityService.getAsyncJobStatus(F))),catch:(F)=>F})).filter((F)=>F&&(F.status==="completed"||F.status==="failed")).length;if(Y===x.jobIds.length)return x.logger.debug("All import jobs completed"),!0;if((yield*FD.currentTimeMillis)-$>B)return x.logger.warn(`Timeout waiting for import jobs (${Y}/${x.jobIds.length} completed)`),!0;let H=Math.round(Y/x.jobIds.length*100);return yield*H0.tryPromise({try:()=>x.reporter.report({progress:50+Math.round(H*0.05),message:`Processing ${Y}/${x.jobIds.length} entities`}),catch:(F)=>F}),!1}).pipe(H0.repeat({schedule:hk.spaced(A),until:(Q)=>Q}))}),f=x.clock?H0.withClock(w,x.clock):w,D=await H0.runPromiseExit(f);if(f5.isFailure(D))throw _4.squash(D.cause)}class kh extends $9{getDirectorySync;context;constructor(x,B,A){super(x,{schema:x60,jobTypeName:"directory-sync"});this.context=B,this.getDirectorySync=A}async process(x,B,A){let w=Date.now(),f=x.syncDirection??"both",D=this.getDirectorySync();this.logger.info("Starting directory sync job",{jobId:B,operation:x.operation,syncDirection:f});let $={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},Z={exported:0,failed:0,errors:[]};if(f!=="export")if(await A.report({progress:10,message:"Scanning directory for changes"}),$=await this.importWithProgress(D,x.paths,A),f==="import")await this.waitForImportJobs($.jobIds,A),await A.report({progress:100,message:`Import complete: ${$.imported} imported`});else await A.report({progress:50,message:`Imported ${$.imported} entities`}),await this.waitForImportJobs($.jobIds,A),await A.report({progress:56,message:"Processing complete, starting export"});if(f!=="import"){let Y=f==="export"?10:60;await A.report({progress:Y,message:"Exporting entities to directory"}),Z=await this.exportWithProgress(D,x.entityTypes,A),await A.report({progress:100,message:f==="export"?`Export complete: ${Z.exported} exported`:`Sync complete: ${$.imported} imported, ${Z.exported} exported`})}let Q=Date.now()-w;return this.logger.info("Directory sync job completed",{jobId:B,duration:Q,imported:$.imported,exported:Z.exported}),{import:$,export:Z,duration:Q}}async importWithProgress(x,B,A){try{return await x.importEntitiesWithProgress(B,A,10)}catch(w){throw this.logger.error("Import phase failed",{error:w}),w}}async exportWithProgress(x,B,A){try{return await x.exportEntitiesWithProgress(B,A,10)}catch(w){throw this.logger.error("Export phase failed",{error:w}),w}}waitForImportJobs(x,B){return IVx({jobIds:x,entityService:this.context.entityService,reporter:B,logger:this.logger})}summarizeDataForLog(x){return{operation:x.operation,syncDirection:x.syncDirection}}}class Mh extends $9{context;getDirectorySync;getGitSync;constructor(x,B,A,w){super(x,{schema:B60,jobTypeName:"sync-request"});this.context=B,this.getDirectorySync=A,this.getGitSync=w}async process(x,B,A){await A.report({progress:5,message:"Pulling latest content from git"});let w=this.getDirectorySync(),f=this.getGitSync(),D=await f.withLock(async()=>{return await f.pull(),await A.report({progress:35,message:"Scanning pulled content for sync changes"}),w.queueSyncBatch(this.context,x.source,{rootJobId:B,interfaceType:x.interfaceType,channelId:x.channelId})});if(!D)return await A.report({progress:100,message:"Sync complete: no files to import"}),{gitPulled:!0,batchQueued:!1};return await A.report({progress:100,message:`Sync queued: ${D.importOperationsCount} import jobs for ${D.totalFiles} files`}),gx9(D)}summarizeDataForLog(x){return{source:x.source,interfaceType:x.interfaceType,channelId:x.channelId}}}function gx9(x){return{gitPulled:!0,batchQueued:!0,batchId:x.batchId,importOperations:x.importOperationsCount,totalFiles:x.totalFiles}}class vh extends $9{context;constructor(x,B,A){super(x,{schema:_h,jobTypeName:"directory-delete"});this.context=B}async process(x,B,A){let w=_h.parse(x);this.logger.info("Processing entity deletion for removed file",{entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}),await A.report({progress:0,total:1,message:`Deleting ${w.entityType}:${w.entityId}`});try{let f=await this.context.entityService.deleteEntity({entityType:w.entityType,id:w.entityId});if(f)this.logger.info("Successfully deleted entity for removed file",{entityId:w.entityId,entityType:w.entityType});else this.logger.warn("Entity not found in database",{entityId:w.entityId,entityType:w.entityType});return await A.report({progress:1,total:1,message:`Deleted ${w.entityType}:${w.entityId}`}),{deleted:f,entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}}catch(f){throw this.logger.error("Failed to delete entity",{entityId:w.entityId,entityType:w.entityType,error:f}),f}}summarizeDataForLog(x){return{entityId:x.entityId,entityType:x.entityType,filePath:x.filePath}}}var Tx9=X.object({});class Nh extends $9{directorySync;constructor(x,B){super(x,{schema:Tx9,jobTypeName:"directory-cleanup"});this.directorySync=B}async process(x,B,A){await A.report({progress:0,message:"Removing orphaned entities"});let w=await this.directorySync.removeOrphanedEntities();return await A.report({progress:100,message:`Cleanup complete: ${w.deleted} orphans removed`}),w}}import{readFile as px9,writeFile as ux9}from"fs/promises";var Sx9=f60,ix9=X.record(X.string(),X.unknown());class Ih extends $9{context;fetcher;constructor(x,B,A=m3){super(B,{schema:Sx9,jobTypeName:"cover-image-convert"});this.context=x,this.fetcher=A}async process(x,B,A){let{filePath:w,sourceUrl:f,postTitle:D,postSlug:$,customAlt:Z}=x;this.logger.debug("Starting image conversion job",{jobId:B,filePath:w,sourceUrl:f,postSlug:$});try{await this.reportProgress(A,{progress:b8.INIT,message:`Reading file: ${w}`});let Q;try{Q=await px9(w,"utf-8")}catch(b){return this.logger.error("Failed to read file",{filePath:w,error:g(b)}),p6.failure(b)}let Y;try{Y=I1(Q)}catch(b){return this.logger.warn("Failed to parse markdown",{filePath:w,error:g(b)}),p6.failure(b)}let W=ix9.safeParse(Y.frontmatter),H=W.success?W.data:{};if(H.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:w}),await this.reportProgress(A,{progress:b8.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(A,{progress:b8.FETCH,message:"Checking for existing image"});let F=await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{sourceUrl:f}},limit:1}}),K;if(F[0])K=F[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:f,imageId:K}),await this.reportProgress(A,{progress:b8.EXTRACT,message:`Reusing existing image: ${K}`});else{await this.reportProgress(A,{progress:b8.PROCESS,message:`Fetching image from ${f}`});let b;try{b=await this.fetcher(f)}catch(y){return this.logger.error("Failed to fetch image",{sourceUrl:f,error:g(y)}),p6.failure(y)}await this.reportProgress(A,{progress:b8.GENERATE,message:"Creating image entity"});let{base64:G}=sO(b),E=rO(G),_=oO(G);if(!E||!_)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:f}),p6.failure(Error("Could not detect image format or dimensions"));K=`${$}-cover`;let L=`Cover image for ${D}`,N=Z??L;await this.context.entityService.createEntity({entity:{id:K,entityType:"image",content:b,metadata:{title:L,alt:N,format:E,width:_.width,height:_.height,sourceUrl:f}}}),this.logger.debug("Created image entity",{imageId:K,sourceUrl:f}),await this.reportProgress(A,{progress:b8.EXTRACT,message:`Created image: ${K}`})}await this.reportProgress(A,{progress:b8.SAVE,message:"Updating file"});let q={...H};delete q.coverImageUrl,delete q.coverImageAlt,q.coverImageId=K;let V=eO(q,Y.content);try{await ux9(w,V,"utf-8")}catch(b){return this.logger.error("Failed to write file",{filePath:w,error:g(b)}),p6.failure(b)}return await this.reportProgress(A,{progress:b8.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:w,imageId:K,sourceUrl:f}),{success:!0,imageId:K}}catch(Q){return this.logger.error("Image conversion job failed",{jobId:B,filePath:w,error:g(Q)}),p6.failure(Q)}}summarizeDataForLog(x){return{filePath:x.filePath,sourceUrl:x.sourceUrl,postSlug:x.postSlug}}}import{readFile as lx9,writeFile as nx9}from"fs/promises";class Oh extends $9{converter;constructor(x,B,A=m3){super(B,{schema:D60,jobTypeName:"inline-image-convert"});this.converter=new Dj(x.entityService,B,A)}async process(x,B,A){let{filePath:w,postSlug:f}=x;this.logger.debug("Starting inline image conversion job",{jobId:B,filePath:w,postSlug:f});try{await this.reportProgress(A,{progress:b8.INIT,message:`Reading file: ${w}`});let D;try{D=await lx9(w,"utf-8")}catch(Q){let Y=g(Q);return this.logger.error("Failed to read file",{filePath:w,error:Y}),{success:!1,error:Y}}await this.reportProgress(A,{progress:b8.FETCH,message:"Detecting inline images"});let $=this.converter.detectInlineImages(D,f);if($.length===0)return this.logger.debug("No inline images to convert",{filePath:w}),await this.reportProgress(A,{progress:b8.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:w,count:$.length}),await this.reportProgress(A,{progress:b8.PROCESS,message:`Converting ${$.length} images`});let Z=await this.converter.convert(D,f);if(!Z.converted)return this.logger.debug("No images were converted",{filePath:w}),await this.reportProgress(A,{progress:b8.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(A,{progress:b8.SAVE,message:"Writing updated file"});try{await nx9(w,Z.content,"utf-8")}catch(Q){let Y=g(Q);return this.logger.error("Failed to write file",{filePath:w,error:Y}),{success:!1,error:Y}}return await this.reportProgress(A,{progress:b8.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:w,convertedCount:Z.convertedCount}),{success:!0,convertedCount:Z.convertedCount}}catch(D){let $=g(D);return this.logger.error("Inline image conversion job failed",{jobId:B,filePath:w,error:$}),{success:!1,error:$}}}summarizeDataForLog(x){return{filePath:x.filePath,postSlug:x.postSlug}}}function OVx(x,B,A,w=()=>B,f){let D=($)=>A.child($);x.jobs.registerHandler("directory-sync",new kh(D("DirectorySyncJobHandler"),x,w)),x.jobs.registerHandler("directory-export",new Jh(D("DirectoryExportJobHandler"),x,B,f)),x.jobs.registerHandler("directory-import",new Lh(D("DirectoryImportJobHandler"),x,B,f)),x.jobs.registerHandler("directory-delete",new vh(D("DirectoryDeleteJobHandler"),x,B)),x.jobs.registerHandler("directory-cleanup",new Nh(D("DirectoryCleanupJobHandler"),B)),x.jobs.registerHandler("cover-image-convert",new Ih(x,D("CoverImageConversionJobHandler"))),x.jobs.registerHandler("inline-image-convert",new Oh(x,D("InlineImageConversionJobHandler"))),A.debug("Registered async job handlers")}import{unlink as dx9,access as ax9}from"fs/promises";var sx9=X.record(X.string(),X.unknown());function hVx(x,B,A,w,f){let{subscribe:D}=x.messaging,{entityService:$}=x;D(l8.created,async(Z)=>{let{entity:Q}=Z.payload;try{await B().fileOps.writeEntity(Q),A.debug("Auto-exported created entity",{id:Q.id,entityType:Q.entityType}),await f?.clearIssues(["export"])}catch(Y){A.error("Auto-export FAILED for created entity",{id:Q.id,entityType:Q.entityType,error:g(Y),stack:Y instanceof Error?Y.stack:void 0}),await f?.recordIssue({kind:"export",path:`${Q.entityType}/${Q.id}.md`,message:g(Y,"Entity export failed")})}return{success:!0}}),D(l8.updated,async(Z)=>{let{entityType:Q,entityId:Y}=Z.payload;try{let W=await $.getEntity({entityType:Q,id:Y});if(!W)return A.debug("Entity not found in DB, skipping export",{entityType:Q,entityId:Y}),{success:!1};await B().fileOps.writeEntity(W),A.debug("Auto-exported updated entity",{id:W.id,entityType:W.entityType}),await f?.clearIssues(["export"])}catch(W){A.error("Auto-export FAILED for updated entity",{entityType:Q,entityId:Y,error:g(W),stack:W instanceof Error?W.stack:void 0}),await f?.recordIssue({kind:"export",path:`${Q}/${Y}.md`,message:g(W,"Entity export failed")})}return{success:!0}}),D(l8.deleted,async(Z)=>{let{entityId:Q,entityType:Y}=Z.payload,W=B().fileOps.getFilePath(Q,Y);if(await ax9(W).then(()=>!0,()=>!1))await dx9(W),A.debug("Auto-deleted entity file",{id:Q,entityType:Y,path:W});return{success:!0}}),A.debug("Setup auto-sync for entity events",{entityTypes:w})}function $60(x,B,A,w){B.setJobQueueCallback(async(f)=>{let D=await w?.startRun("watcher","importing"),$=[{type:f.type,data:sx9.parse(f.data)}];try{let Z=await x.jobs.enqueueBatch($,{priority:5,source:"directory-sync-watcher",rootJobId:DY(),metadata:{operationType:"file_operations",operationTarget:A,pluginId:"directory-sync"}});if(D)await w?.attachBatch(D,Z);return Z}catch(Z){if(D)await w?.failRun(D,g(Z,"Watcher import failed"),"import");throw Z}})}import{readdir as mVx,mkdir as ox9,copyFile as tx9}from"fs/promises";import{join as yVx,resolve as Z60}from"path";import{join as rx9}from"path";async function RVx(x){if(!await s6(rx9(x,".git")))return!1;try{return await C3(x).revparse(["--verify","HEAD"]),!0}catch{return!1}}async function ex9(x,B){if(!await s6(x))return!0;if((await mVx(x)).filter((f)=>!f.startsWith(".")&&!f.startsWith("_")).length>0)return!1;if(await RVx(x))return B.debug("Git repository with history detected - skipping seed content",{path:x}),!1;return!0}async function CVx(x,B){let A=await mVx(x,{withFileTypes:!0});for(let w of A){let f=yVx(x,w.name),D=yVx(B,w.name);if(w.isDirectory()){if(!await s6(D))await ox9(D,{recursive:!0});await CVx(f,D)}else await tx9(f,D)}}async function cVx(x,B,A){let w=Z60(process.cwd(),x);A=A?Z60(A):Z60(process.cwd(),"seed-content");let f=await ex9(w,B);if(f&&await s6(A))B.debug("Copying seed content to brain-data directory"),await CVx(A,w),B.debug("Seed content copied successfully");else if(f)B.debug("No seed content directory found, starting with empty brain-data");else B.debug("brain-data directory not empty, skipping seed content")}function gVx(x,B,A,w,f){let D=!1,$=async()=>{if(D)return;D=!0;let Z=B();if(A.seedContent){let Q=A.syncPath??x.dataDir;await cVx(Q,w,A.seedContentPath)}try{if(f){w.debug("Git enabled \u2014 pulling before import");let Y=await f.pull();if(Y.files.length>0)w.info("Pulled changes from remote",{filesChanged:Y.files.length})}w.debug("Starting initial sync");let Q=await Z.sync();w.debug("Initial sync completed",{imported:Q.import.imported,failed:Q.import.failed,duration:Q.duration}),await x.messaging.send({type:e8.initialSyncCompleted,payload:{success:!0},...{broadcast:!0}})}catch(Q){w.error("Initial sync failed",Q),await x.messaging.send({type:e8.initialSyncCompleted,payload:{success:!1,error:g(Q)},...{broadcast:!0}})}};x.messaging.subscribe(e8.pluginsRegistered,async()=>{return w.debug("Plugins registered, starting initial sync"),await $(),{success:!0}})}var x89="git-auto-commit";function TVx(x,B,A,w,f,D){let $=typeof B==="function"?B:()=>B,Z=async()=>{let Y=$();try{if(!await Y.withLock(async()=>{let H=await Y.getStatus();if(!H.isRepo)throw Error("Git repository is unavailable");if(!H.hasChanges&&H.ahead===0)return!1;if(H.hasChanges)await Y.commit();return await Y.push(),!0}))return;await D?.clearIssues(["git"]),await D?.recordTerminal("save","succeeded","Local content committed and pushed")}catch(W){w.error("Git auto-commit failed",{error:W});let H=g(W,"Git auto-commit failed");await D?.recordIssue({kind:"git",message:H}),await D?.recordTerminal("save","failed",H)}},Q=[l8.created,l8.updated,l8.deleted];for(let Y of Q)x.subscribe(Y,async()=>{return f.scheduleTrailing(x89,A,Z),{success:!0}})}function pVx(x,B,A,w,f,D,$){if(w<=0)return;let Z=w*60*1000,Q=async(Y)=>{let W=await $?.startRun("periodic","pulling");try{let{files:H,result:F}=await x.withLock(async()=>{let K=await x.pull(Y);if(Y.throwIfAborted(),K.files.length===0)return{files:[],result:null};let q=await B.queueSyncBatch(A,"periodic-sync",void 0,K.files);if(q)B.suppressWatchPaths(K.files);return{files:K.files,result:q}},Y);if(H.length>0)f.info("Periodic sync: pulled changes",{filesChanged:H.length});if(F){if(f.debug("Periodic sync: queued imports",{importOperations:F.importOperationsCount,totalFiles:F.totalFiles}),W)await $?.attachBatch(W,F.batchId)}else if(W)await $?.completeRun(W,H.length===0?"Remote checked; no changes found":"Remote changes required no imports")}catch(H){if(Y.aborted){if(W)await $?.clearRun(W)}else if(f.error("Periodic git sync failed",{error:H}),W)await $?.failRun(W,g(H,"Periodic Git sync failed"))}};D.schedulePeriodic(Z,Q),f.info("Started periodic git sync",{intervalMinutes:w})}import{spawnSync as SVx}from"child_process";import{cpSync as B89,existsSync as uVx,mkdirSync as A89,mkdtempSync as w89,rmSync as f89}from"fs";import{tmpdir as D89}from"os";import{fileURLToPath as $89}from"url";import{join as Z89,resolve as Q89}from"path";function BZ(x,B){let A=SVx("git",B,{cwd:x,stdio:"pipe"});if(A.status!==0){let w=A.stderr.toString().trim(),f=A.stdout.toString().trim();throw Error(w||f||`git ${B.join(" ")} failed`)}}function X89(x){return x.startsWith("file://")}function Y89(x){return $89(x)}function W89(x,B){return SVx("git",["--git-dir",x,"show-ref","--verify","--quiet",`refs/heads/${B}`]).status===0}async function iVx(x){if(!x.bootstrapFromSeed)return;if(!x.gitUrl||!X89(x.gitUrl))return;if(!x.seedContentPath)throw Error("directory-sync git.bootstrapFromSeed requires seedContentPath for local file:// remotes");let B=x.branch??"main",A=Y89(x.gitUrl),w=Q89(x.seedContentPath);if(!uVx(w))throw Error(`Seed content path not found: ${w}`);if(!uVx(A))x.logger.debug("Creating local bare content remote",{remotePath:A,branch:B}),A89(A,{recursive:!0}),BZ(process.cwd(),["init","--bare",`--initial-branch=${B}`,A]);if(W89(A,B)){x.logger.debug("Content remote already initialized",{remotePath:A,branch:B});return}x.logger.debug("Seeding local content remote",{remotePath:A,seedPath:w,branch:B});let f=w89(Z89(D89(),"directory-sync-seed-"));try{BZ(f,["init",`--initial-branch=${B}`]),BZ(f,["config","user.name",x.authorName??"Brain"]),BZ(f,["config","user.email",x.authorEmail??"brain@localhost"]),B89(w,f,{recursive:!0,filter:(D)=>!D.split("/").includes(".git")}),BZ(f,["add","."]),BZ(f,["commit","-m","seed content remote"]),BZ(f,["remote","add","origin",x.gitUrl]),BZ(f,["push","-u","origin",B])}finally{f89(f,{recursive:!0,force:!0})}}function lVx(x,B,A,w,f,D,$){let{subscribe:Z}=x.messaging;Z(HB.entityExportRequest,async(Q)=>{try{return{success:!0,data:await B().exportEntities(Q.payload.entityTypes)}}catch(Y){return{success:!1,error:g(Y,"Export failed")}}}),Z(HB.entityImportRequest,async(Q)=>{try{let Y=B(),W=Q.payload.paths,H=await Y.importEntities(W);if(W&&W.length>0)await Y.removeOrphanedEntities();return{success:!0,data:H}}catch(Y){return{success:!1,error:g(Y,"Import failed")}}}),Z(HB.statusRequest,async()=>{try{let Y=await B().getStatus(),W=$?.();return{success:!0,data:{syncPath:Y.syncPath,isInitialized:Y.exists,watchEnabled:Y.watching,lastSync:Y.lastSync?.toISOString()??null,totalFiles:Y.stats.totalFiles,byEntityType:Y.stats.byEntityType,git:await H89(D?.(),w),...W?{managementUrl:W}:{}}}}catch(Q){return{success:!1,error:g(Q,"Status check failed")}}}),Z(HB.configureRequest,async(Q)=>{try{return await A({syncPath:Q.payload.syncPath}),{success:!0,data:{syncPath:Q.payload.syncPath,configured:!0}}}catch(Y){return{success:!1,error:g(Y,"Configuration failed")}}}),Z(HB.getRepoInfo,async()=>{if(!f?.repo)return{success:!1,error:"Git not configured"};return{success:!0,data:{repo:f.repo,branch:f.branch??"main"}}}),w.debug("Registered message handlers")}async function H89(x,B){if(!x)return null;try{let A=await x.getStatus();return{branch:A.branch,hasChanges:A.hasChanges,ahead:A.ahead,behind:A.behind,lastCommit:A.lastCommit??null,remote:A.remote??null}}catch(A){return B.debug("Git status unavailable for sync:status:request",{error:A}),null}}async function hh(x){let B=await x.operationStatus?.startRun("manual",x.gitSync?"pulling":"scanning");try{if(x.gitSync){let w=await x.context.jobs.enqueue({type:"sync-request",data:{source:x.source,interfaceType:x.interfaceType,channelId:x.channelId},...x.toolContext?{toolContext:x.toolContext}:{}});if(B)await x.operationStatus?.attachJob(B,w);return{...B?{runId:B}:{},gitPulled:!0,jobId:w,status:"queued"}}let A=await x.directorySync.queueSyncBatch(x.context,x.source,{interfaceType:x.interfaceType,channelId:x.channelId});if(!A){if(B)await x.operationStatus?.completeRun(B,"No files to sync");return{...B?{runId:B}:{},gitPulled:!1,status:"settled"}}if(B)await x.operationStatus?.attachBatch(B,A.batchId);return{...B?{runId:B}:{},...A,gitPulled:!1,status:"queued"}}catch(A){if(B)await x.operationStatus?.failRun(B,g(A,"Sync request failed"),x.gitSync?"git":"source");throw A}}var XS6=X.object({entityType:X.string(),id:X.string(),sha:X.string().optional(),limit:X.number().int().positive().optional().default(10)});async function nVx(x,B){let A=`${x.entityType}/${x.id}.md`,w=x.limit??10;try{if(x.sha){let D=await B.show(x.sha,A);return G1({sha:x.sha,entityType:x.entityType,id:x.id,content:D},`Content at ${x.sha.slice(0,7)}`)}let f=await B.log(A,w);if(f.length===0)return G1({commits:[]},`No history found for ${x.entityType}/${x.id}`);return G1({commits:f,entityType:x.entityType,id:x.id},`${f.length} version${f.length===1?"":"s"} found`)}catch(f){return U1(g(f,"History lookup failed"))}}var F89=X.object({action:X.enum(["sync","status"]).default("sync").describe("Use sync for a refresh request and status for a status check")}),K89=X.object({action:X.enum(["sync","status","history"]).default("sync").describe("Use sync for git/filesystem sync, status for a status check, and history only for entity history"),entityType:X.string().optional().describe("History only; omit for sync and status"),id:X.string().optional().describe("History only; omit for sync and status"),sha:X.string().optional().describe("Optional history revision; omit for sync and status"),limit:X.number().int().positive().optional().default(10).describe("History only; omit for sync and status")}),q89=X.discriminatedUnion("action",[X.object({action:X.literal("sync")}),X.object({action:X.literal("status")})]),z89=X.discriminatedUnion("action",[X.object({action:X.literal("sync")}),X.object({action:X.literal("status")}),X.object({action:X.literal("history"),entityType:X.string().min(1),id:X.string().min(1),sha:X.string().optional(),limit:X.number().int().positive().optional().default(10)})]);function dVx(x,B,A,w,f){return[E1("directory","sync",w?"Manage directory and git sync with an action discriminator. For requests such as 'sync with git', immediately call action=sync with no entityType, id, or sha; never ask for those fields because they apply only to action=history. Action=sync queues a git pull plus filesystem scan when git is configured and also handles refresh, pull, backup-to-git, and filesystem import requests. For every sync or git status follow-up after action=sync, including a bare 'what is the status', immediately call action=status with no entity fields; a sync jobId is not a system_job_status batchId. Use action=history to read git version history for a specific entity.":"Manage directory sync with an action discriminator. Immediately call action=sync for refresh, filesystem import, or content sync requests. Immediately call action=status for directory sync status follow-ups, including a bare 'what is the status'.",w?K89:F89,async($,Z)=>{let Q=w?z89.parse($):q89.parse($);if(Q.action==="sync")return b89({directorySync:x,pluginContext:B,pluginId:A,gitSync:w,operationStatus:f,context:Z});if(Q.action==="status")return V89(x,w);if(!w)return U1("History is unavailable because git is not configured");return nVx(Q,w)},{visibility:"admin",sideEffects:"external",cli:{name:"sync"}})]}async function b89(x){try{let B=x.context.channelId?`${x.context.interfaceType}:${x.context.channelId}`:`plugin:${x.pluginId}`,A=await hh({context:x.pluginContext,directorySync:x.directorySync,source:B,interfaceType:x.context.interfaceType,channelId:x.context.channelId,toolContext:x.context,gitSync:x.gitSync,operationStatus:x.operationStatus});if(A.gitPulled)return G1({jobId:A.jobId,status:A.status,gitPulled:!0,...A.runId?{runId:A.runId}:{}},"Sync queued: git pull and filesystem scan will run in the background");if(A.status==="settled")return G1({gitPulled:!1,...A.runId?{runId:A.runId}:{}},"No files to sync");return G1({batchId:A.batchId,importOperations:A.importOperationsCount,totalFiles:A.totalFiles,gitPulled:!1,...A.runId?{runId:A.runId}:{}},`Sync started: ${A.importOperationsCount} import jobs queued for ${A.totalFiles} files`)}catch(B){return U1(g(B,"Sync failed"))}}async function V89(x,B){try{let A=await x.getStatus(),w={syncPath:A.syncPath,lastSync:A.lastSync?.toISOString(),watching:A.watching};if(B){let f=await B.getStatus();w.git={isRepo:f.isRepo,branch:f.branch,hasChanges:f.hasChanges,ahead:f.ahead,behind:f.behind,remote:f.remote}}return G1(w)}catch(A){return U1(g(A,"Status check failed"))}}import{isAbsolute as aVx,relative as U89}from"path";var oVx=X.enum(["manual","periodic","watcher","save"]),G89=X.enum(["pulling","scanning","importing","settling"]),tVx={imported:X.number().int().nonnegative(),skipped:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),quarantined:X.number().int().nonnegative(),exported:X.number().int().nonnegative()},E89=X.object({id:X.string().min(1),source:oVx,state:G89,startedAt:X.string().datetime(),jobId:X.string().min(1).optional(),batchId:X.string().min(1).optional(),...tVx}),j89=X.object({id:X.string().min(1),source:oVx,outcome:X.enum(["succeeded","attention","failed"]),startedAt:X.string().datetime(),completedAt:X.string().datetime(),summary:X.string().min(1).max(240),...tVx}),_89=X.object({id:X.string().min(1),kind:X.enum(["quarantined","import","export","git","source"]),path:X.string().min(1).max(300).optional(),message:X.string().min(1).max(400),occurredAt:X.string().datetime()}),P89=X.object({activeRun:E89.optional(),recentRuns:X.array(j89).max(5),issues:X.array(_89).max(8)}),J89=X.object({gitPulled:X.literal(!0),batchQueued:X.boolean(),batchId:X.string().optional(),importOperations:X.number().int().nonnegative().optional(),totalFiles:X.number().int().nonnegative().optional()}),sVx={imported:0,skipped:0,failed:0,quarantined:0,exported:0},L89={recentRuns:[],issues:[]},k89="directory-sync.operation-status",M89="current";class Q60{store;jobs;logger;syncPath;constructor(x,B,A,w){this.store=new yh({runtimeState:x,namespace:k89,key:M89,schema:P89,createEmpty:()=>structuredClone(L89)}),this.jobs=B,this.logger=A,this.syncPath=w}setSyncPath(x){this.syncPath=x}async initialize(){let x=await this.store.snapshot();if(x.activeRun&&!x.activeRun.jobId&&!x.activeRun.batchId){await this.clearRun(x.activeRun.id);return}await this.reconcile()}startRun(x,B){let A=DY();return this.mutate((w)=>{if(w.activeRun)return;return w.activeRun={id:A,source:x,state:B,startedAt:new Date().toISOString(),...sVx},A})}markPhase(x,B){return this.mutate((A)=>{if(A.activeRun?.id===x)A.activeRun.state=B})}attachJob(x,B){return this.mutate((A)=>{if(A.activeRun?.id!==x)return;A.activeRun.jobId=B,A.activeRun.state="pulling"})}attachBatch(x,B){return this.mutate((A)=>{if(A.activeRun?.id!==x)return;delete A.activeRun.jobId,A.activeRun.batchId=B,A.activeRun.state="importing"})}addImportResult(x){return this.mutate((B)=>{if(B.activeRun)B.activeRun.imported+=x.imported,B.activeRun.skipped+=x.skipped,B.activeRun.failed+=x.failed,B.activeRun.quarantined+=x.quarantined;let A=[...x.errors.map((w)=>({kind:"import",path:this.safePath(w.path),message:w.error})),...x.quarantinedFiles.map((w)=>({kind:"quarantined",path:this.safePath(w),message:"File was quarantined because it could not be imported"}))];if(A.length===0)B.issues=B.issues.filter((w)=>w.kind!=="import"&&w.kind!=="quarantined");else for(let w of A)this.prependIssue(B,w)})}addExportResult(x){return this.mutate((B)=>{if(B.activeRun)B.activeRun.exported+=x.exported,B.activeRun.failed+=x.failed;if(x.errors.length===0){B.issues=B.issues.filter((A)=>A.kind!=="export");return}for(let A of x.errors)this.prependIssue(B,{kind:"export",path:`${A.entityType}/${A.entityId}.md`,message:A.error})})}recordIssue(x){return this.mutate((B)=>this.prependIssue(B,x))}clearIssues(x){return this.mutate((B)=>{B.issues=B.issues.filter((A)=>!x.includes(A.kind))})}completeRun(x,B){return this.finishRun(x,"succeeded",B)}clearRun(x){return this.mutate((B)=>{if(B.activeRun?.id===x)delete B.activeRun})}failRun(x,B,A="git"){return this.mutate((w)=>{let f=w.activeRun;if(f?.id!==x)return;let D=Rh(B);this.prependRecent(w,f,"failed",D),this.prependIssue(w,{kind:A,message:D}),delete w.activeRun})}recordTerminal(x,B,A,w={}){return this.mutate((f)=>{let D=new Date().toISOString();this.prependRecent(f,{id:DY(),source:x,state:"settling",startedAt:D,...sVx,...w},B,A)})}async reconcile(){let B=(await this.store.snapshot()).activeRun;if(!B)return;try{if(B.jobId){let A=await this.jobs.getStatus(B.jobId);if(!A){await this.failRun(B.id,"The active sync job could not be found after restart","source");return}if(A.status==="pending"||A.status==="processing"){await this.markPhase(B.id,"pulling");return}if(A.status==="failed"){await this.failRun(B.id,A.lastError??"Git-backed sync failed");return}let w=J89.safeParse(v89(A.result));if(!w.success){await this.failRun(B.id,"Sync job completed without a readable result","source");return}if(w.data.batchQueued&&w.data.batchId)return await this.attachBatch(B.id,w.data.batchId),await this.reconcile();await this.completeRun(B.id,"Remote checked; no files to import");return}if(B.batchId){let A=await this.jobs.getBatchStatus(B.batchId);if(!A){await this.failRun(B.id,"The active sync batch could not be recovered after restart","source");return}if(A.status==="pending"||A.status==="processing"){await this.markPhase(B.id,"importing");return}if(A.status==="failed"){await this.failRun(B.id,A.errors.join("; ")||"Directory import batch failed","import");return}await this.completeRun(B.id,`${A.completedOperations} sync operations completed`)}}catch(A){this.logger.debug("Unable to reconcile directory sync operation",{error:A})}}async getSnapshot(){return await this.reconcile(),this.store.snapshot()}finishRun(x,B,A){return this.mutate((w)=>{let f=w.activeRun;if(f?.id!==x)return;let D=f.failed>0||f.quarantined>0?"attention":B;if(this.prependRecent(w,f,D,A),delete w.activeRun,D==="succeeded")w.issues=w.issues.filter(($)=>$.kind!=="git"&&$.kind!=="source")})}mutate(x){return this.store.mutate(x)}prependRecent(x,B,A,w){let f={id:B.id,source:B.source,outcome:A,startedAt:B.startedAt,completedAt:new Date().toISOString(),summary:Rh(w,240),imported:B.imported,skipped:B.skipped,failed:B.failed,quarantined:B.quarantined,exported:B.exported};x.recentRuns=[f,...x.recentRuns.filter((D)=>D.id!==f.id)].slice(0,5)}prependIssue(x,B){let A=B.path?this.safePath(B.path):void 0,w={id:`${B.kind}:${A??Rh(B.message,80)}`,kind:B.kind,...A?{path:A}:{},message:Rh(B.message),occurredAt:new Date().toISOString()};x.issues=[w,...x.issues.filter((f)=>f.id!==w.id)].slice(0,8)}safePath(x){if(!aVx(x))return rVx(x);let B=U89(this.syncPath,x);if(B.startsWith("..")||aVx(B))return"content file";return rVx(B)}}function v89(x){if(typeof x!=="string")return x;try{return JSON.parse(x)}catch{return x}}function rVx(x){return x.replaceAll("\\","/").replace(/^\.\//,"").slice(0,300)||"content file"}function Rh(x,B=400){return x.replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi,"$1[redacted]@").replace(/(token|password|authorization)=([^\s&]+)/gi,"$1=[redacted]").replace(/\s+/g," ").trim().slice(0,B)||"Directory sync operation failed"}import{basename as N89}from"path";var I89=X.object({type:X.literal("sync-now")}),eVx={imported:X.number().int().nonnegative(),skipped:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),quarantined:X.number().int().nonnegative(),exported:X.number().int().nonnegative()},O89=X.object({health:X.enum(["healthy","active","attention"]),directory:X.object({displayPath:X.string().min(1),exists:X.boolean(),watching:X.boolean(),totalFiles:X.number().int().nonnegative(),byEntityType:X.record(X.string(),X.number().int().nonnegative()),lastSettledAt:X.string().datetime().optional()}),git:X.object({branch:X.string().min(1),remoteLabel:X.string().min(1).optional(),hasChanges:X.boolean(),ahead:X.number().int().nonnegative(),behind:X.number().int().nonnegative(),lastCommit:X.string().min(1).optional(),changedFiles:X.array(X.object({path:X.string().min(1),status:X.string().min(1)})),changedFilesTruncated:X.boolean()}).nullable(),automation:X.object({autoSync:X.boolean(),watchIntervalMs:X.number().int().nonnegative(),remoteIntervalMinutes:X.number().nonnegative().optional(),commitDebounceMs:X.number().int().nonnegative().optional(),deleteOnFileRemoval:X.boolean()}),activeRun:X.object({id:X.string().min(1),source:X.enum(["manual","periodic","watcher","save"]),state:X.enum(["pulling","scanning","importing","settling"]),startedAt:X.string().datetime(),jobId:X.string().min(1).optional(),batchId:X.string().min(1).optional(),...eVx}).optional(),recentRuns:X.array(X.object({id:X.string().min(1),source:X.enum(["manual","periodic","watcher","save"]),outcome:X.enum(["succeeded","attention","failed"]),startedAt:X.string().datetime(),completedAt:X.string().datetime(),summary:X.string().min(1),...eVx})),issues:X.array(X.object({id:X.string().min(1),kind:X.enum(["quarantined","import","export","git","source"]),path:X.string().min(1).optional(),message:X.string().min(1),occurredAt:X.string().datetime()}))});class X60{options;constructor(x){this.options=x}async getSnapshot(){let x=await this.options.getDirectorySync().getStatus();this.options.operationStatus.setSyncPath(x.syncPath);let B,A=this.options.getGitSync();if(A)try{if(B=await A.getStatus(),!B.hasChanges&&B.ahead===0&&B.behind===0)await this.options.operationStatus.clearIssues(["git"])}catch($){await this.options.operationStatus.recordIssue({kind:"git",message:g($,"Git status unavailable")})}if(!x.exists)await this.options.operationStatus.recordIssue({kind:"source",message:"The configured sync directory is unavailable"});else await this.options.operationStatus.clearIssues(["source"]);let w=await this.options.operationStatus.getSnapshot(),f=w.recentRuns[0]?.completedAt??x.lastSync?.toISOString(),D=w.activeRun?"active":w.issues.length>0?"attention":"healthy";return O89.parse({health:D,directory:{displayPath:N89(x.syncPath)||"brain-data",exists:x.exists,watching:x.watching,totalFiles:x.stats.totalFiles,byEntityType:x.stats.byEntityType,...f?{lastSettledAt:f}:{}},git:B?this.toSafeGitStatus(B):null,automation:{autoSync:this.options.config.autoSync,watchIntervalMs:this.options.config.watchInterval,...A?{remoteIntervalMinutes:this.options.config.syncInterval,commitDebounceMs:this.options.config.commitDebounce}:{},deleteOnFileRemoval:this.options.config.deleteOnFileRemoval},...w.activeRun?{activeRun:w.activeRun}:{},recentRuns:w.recentRuns,issues:w.issues})}async registerCmsWorkspace(){let x={id:"sync",pluginId:this.options.pluginId,label:"Sync",rendererName:"DirectorySyncWorkspace",priority:60,accessHandler:(B)=>_7.hasPermission(B.userPermissionLevel,"admin"),dataProvider:async(B)=>{if(!_7.hasPermission(B.userPermissionLevel,"admin"))throw Error("Directory sync requires admin permission");return this.getSnapshot()},actionHandler:async(B,A)=>{if(!_7.hasPermission(A.userPermissionLevel,"admin"))throw Error("Directory sync requires admin permission");if(!I89.safeParse(B).success)throw Error("Invalid directory sync workspace action");let f={interfaceType:"cms",actor:A.actor,userPermissionLevel:A.userPermissionLevel},D=await hh({context:this.options.context,directorySync:this.options.getDirectorySync(),source:`cms:${A.userId}`,interfaceType:"cms",toolContext:f,gitSync:this.options.getGitSync(),operationStatus:this.options.operationStatus});return{accepted:D.status==="queued",status:D.status,...D.runId?{runId:D.runId}:{},...D.gitPulled?{jobId:D.jobId}:{},...!D.gitPulled&&D.status==="queued"?{batchId:D.batchId}:{}}}};return bq(this.options.context,x)}toSafeGitStatus(x){let B=x.files.slice(0,20).map((w)=>({path:h89(w.path),status:w.status.trim()||"changed"})),A=R89(this.options.config);return{branch:x.branch,...A?{remoteLabel:A}:{},hasChanges:x.hasChanges,ahead:x.ahead,behind:x.behind,...x.lastCommit?{lastCommit:x.lastCommit}:{},changedFiles:B,changedFilesTruncated:x.files.length>B.length}}}function h89(x){let B=x.replaceAll("\\","/").replace(/^\.\//,"");if(B.startsWith("../")||B.startsWith("/"))return"content file";return B.slice(0,300)||"content file"}function R89(x){if(x.git?.repo)return x.git.repo;let B=x.git?.gitUrl;if(!B)return;if(B.startsWith("file:"))return"local remote";try{let A=new URL(B),w=A.pathname.replace(/^\//,"").replace(/\.git$/,"");return w?`${A.hostname}/${w}`:A.hostname}catch{let A=/^(?:[^@]+@)?([^:]+):(.+?)(?:\.git)?$/.exec(B);if(!A?.[1]||!A[2])return"configured remote";return`${A[1]}/${A[2].replace(/\.git$/,"")}`}}class mh{resourceScope;scheduleScope;periodicScope;delayScope;scheduleFibers;periodicFibers;delayedFibers;clock;activeOperations=new Set;activeFailures=[];nextPeriodicId=0;closePromise=null;closed=!1;constructor(x={}){this.resourceScope=H0.runSync(y9.make()),this.scheduleScope=H0.runSync(y9.make()),this.periodicScope=H0.runSync(y9.make()),this.delayScope=H0.runSync(y9.make()),this.scheduleFibers=H0.runSync(y9.extend(_w.make(),this.scheduleScope)),this.periodicFibers=H0.runSync(y9.extend(QB.make(),this.periodicScope)),this.delayedFibers=H0.runSync(y9.extend(QB.make(),this.delayScope)),this.clock=x.clock}async acquire(x,B){if(this.closed)throw Error("Directory sync runtime is closed");let A=H0.acquireRelease(H0.promise(x),(f)=>H0.promise(()=>B(f))),w=await H0.runPromiseExit(y9.extend(A,this.resourceScope));if(f5.isFailure(w))throw _4.squash(w.cause);return w.value}schedulePeriodic(x,B){if(this.closed)return;if(!Number.isFinite(x)||x<=0)throw Error("Periodic interval must be a positive finite number");let A=this.nextPeriodicId++,w=()=>{if(this.closed||QB.unsafeHas(this.periodicFibers,A))return;let $=H0.tryPromise({try:B,catch:(Z)=>Z}).pipe(H0.catchAll((Z)=>H0.sync(()=>{this.activeFailures.push(Z)})));QB.unsafeSet(this.periodicFibers,A,H0.runFork($),{onlyIfMissing:!0})},f=H0.sleep(x).pipe(H0.andThen(H0.sync(w)),H0.forever),D=this.clock?H0.withClock(f,this.clock):f;_w.unsafeAdd(this.scheduleFibers,H0.runFork(D))}scheduleTrailing(x,B,A){if(this.closed)return;let w=H0.sleep(B).pipe(H0.andThen(H0.sync(()=>{this.trackActive(A)}))),f=this.clock?H0.withClock(w,this.clock):w,D=H0.runFork(f);QB.unsafeSet(this.delayedFibers,x,D)}close(){return this.closed=!0,this.closePromise??=this.closeRuntime(),this.closePromise}trackActive(x){if(this.closed)return;let B;try{B=x()}catch(w){B=Promise.reject(w)}let A=B.catch((w)=>{this.activeFailures.push(w)}).finally(()=>{this.activeOperations.delete(A)});this.activeOperations.add(A)}async closeRuntime(){let x=[],B=async(A)=>{try{await A()}catch(w){x.push(w)}};await B(()=>this.closeScope(this.scheduleScope)),await B(()=>this.closeScope(this.periodicScope)),await B(()=>this.closeScope(this.delayScope)),await B(()=>this.closeScope(this.resourceScope));while(this.activeOperations.size>0)await Promise.all([...this.activeOperations]);if(x.push(...this.activeFailures),x.length>0)throw x[0]}async closeScope(x){let B=await H0.runPromiseExit(y9.close(x,f5.void));if(f5.isFailure(B))throw _4.squash(B.cause)}}function xUx(x){return{initialize:()=>x().initialize(),initializeDirectory:()=>x().initializeDirectory(),setJobQueueCallback:(B)=>x().setJobQueueCallback(B),sync:()=>x().sync(),processEntityExport:(B)=>x().processEntityExport(B),exportEntities:(B)=>x().exportEntities(B),importEntitiesWithProgress:(B,A,w)=>x().importEntitiesWithProgress(B,A,w),exportEntitiesWithProgress:(B,A,w)=>x().exportEntitiesWithProgress(B,A,w),importEntities:(B)=>x().importEntities(B),removeOrphanedEntities:()=>x().removeOrphanedEntities(),get fileOps(){return x().fileOps},get shouldDeleteOnFileRemoval(){return x().shouldDeleteOnFileRemoval},getAllMarkdownFiles:()=>x().getAllMarkdownFiles(),ensureDirectoryStructure:()=>x().ensureDirectoryStructure(),getStatus:()=>x().getStatus(),queueSyncBatch:(B,A,w,f)=>x().queueSyncBatch(B,A,w,f),startWatching:()=>x().startWatching(),stopWatching:()=>x().stopWatching(),suppressWatchPaths:(B)=>x().suppressWatchPaths(B),setWatchCallback:(B)=>x().setWatchCallback(B)}}function BUx(x){return{withLock:(B,A)=>x().withLock(B,A),initialize:()=>x().initialize(),hasRemote:()=>x().hasRemote(),getStatus:()=>x().getStatus(),hasLocalChanges:()=>x().hasLocalChanges(),commit:(B)=>x().commit(B),push:(B)=>x().push(B),pull:(B)=>x().pull(B),cleanup:()=>x().cleanup(),log:(B,A)=>x().log(B,A),show:(B,A)=>x().show(B,A)}}var AUx={name:"@brains/directory-sync",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Directory-based entity synchronization plugin for Brains",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",chokidar:"^5.0.0","simple-git":"^3.36.0"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",typescript:"^7.0.2"},exports:{".":{types:"./src/index.ts",import:"./src/index.ts"},"./env-schema":"./src/env-schema.ts"},main:"./src/index.ts",peerDependencies:{},private:!0,scripts:{clean:"rm -rf .turbo",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};class Y60 extends D8{directorySync;gitSync;operationStatus;workspaceProvider;cmsWorkspaceUrl;runtime=new mh;directorySyncFacade=xUx(()=>this.requireDirectorySync());gitSyncFacade=BUx(()=>this.requireGitSync());runtimeScheduler={scheduleTrailing:(x,B,A)=>{this.runtime.scheduleTrailing(x,B,A)}};watcherOwned=!1;gitBackgroundStarted=!1;gitAutoCommitRegistered=!1;readyState=!1;shutdownStarted=!1;configurationQueue=Promise.resolve();constructor(x={}){super("directory-sync",AUx,x,bj)}requireDirectorySync(){if(!this.directorySync)throw Error("DirectorySync service not initialized");return this.directorySync}requireGitSync(){if(!this.gitSync)throw Error("GitSync service not initialized");return this.gitSync}requireOperationStatus(){if(!this.operationStatus)throw Error("Directory sync operation status not initialized");return this.operationStatus}hasGitSync(){return this.gitSync!==void 0}async onRegister(x){x.templates.register({status:{name:"status",description:"Directory synchronization status",schema:Vj,basePrompt:"",formatter:new Ph,requiredPermission:"admin"}});let B=this.config.syncPath??x.dataDir;this.directorySync=this.createDirectorySync(x,B);try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:B})}catch(A){throw this.logger.error("Failed to initialize directory",A),A}if(this.operationStatus=new Q60(x.runtimeState,x.jobs,this.logger.child("OperationStatus"),B),await this.operationStatus.initialize(),this.config.autoSync)$60(x,this.directorySync,B,this.operationStatus);if(await this.registerJobHandlers(x),hVx(x,()=>this.requireDirectorySync(),this.logger,this.config.entityTypes,this.operationStatus),this.config.git&&!this.isGitConfigured())this.logger.debug("Git block present but no repo/gitUrl configured \u2014 git sync disabled");if(this.isGitConfigured())await this.bootstrapContentRemote(),this.gitSync=await this.initializeGitSync(B),x.jobs.registerHandler("sync-request",new Mh(this.logger.child("DirectorySyncRequestJobHandler"),x,()=>this.requireDirectorySync(),()=>this.requireGitSync()));if(this.config.initialSync)gVx(x,()=>this.requireDirectorySync(),this.config,this.logger,this.gitSync?this.gitSyncFacade:void 0);this.workspaceProvider=new X60({context:x,pluginId:this.id,config:this.config,getDirectorySync:()=>this.requireDirectorySync(),getGitSync:()=>this.gitSync,operationStatus:this.operationStatus}),lVx(x,()=>this.requireDirectorySync(),(A)=>this.configure(A),this.logger,this.config.git,()=>this.gitSync,()=>this.cmsWorkspaceUrl)}async onReady(){await this.startBackgroundWork(),this.readyState=!0,this.cmsWorkspaceUrl=await this.workspaceProvider?.registerCmsWorkspace()}async getTools(){return dVx(this.directorySyncFacade,this.getContext(),this.id,this.gitSync?this.gitSyncFacade:void 0,this.operationStatus)}async onShutdown(){this.shutdownStarted=!0,await this.configurationQueue,await this.stopGeneration(this.runtime,this.directorySync,this.gitSync),this.readyState=!1,this.watcherOwned=!1,this.gitBackgroundStarted=!1}getDirectorySync(){return this.directorySync}configure(x){let B=this.configurationQueue.then(()=>this.replaceGeneration(x.syncPath));return this.configurationQueue=B.catch(()=>{}),B}async replaceGeneration(x){if(this.shutdownStarted)throw Error("Directory sync plugin is shutting down");let B=this.getContext(),A=new mh,w=this.createDirectorySync(B,x),f;try{if(await w.initializeDirectory(),this.config.autoSync)$60(B,w,x,this.operationStatus);if(this.isGitConfigured())f=await this.initializeGitSync(x)}catch(Q){throw await this.abandonCandidate(A,w,f),Q}let D=this.runtime,$=this.directorySync,Z=this.gitSync;try{await this.stopGeneration(D,$,Z)}catch(Q){throw await this.abandonCandidate(A,w,f),Q}if(this.runtime=A,this.directorySync=w,this.gitSync=f,this.operationStatus?.setSyncPath(x),this.watcherOwned=!1,this.gitBackgroundStarted=!1,this.readyState)await this.startBackgroundWork();this.logger.info("Directory sync reconfigured",{path:x})}createDirectorySync(x,B){return new Bh({syncPath:B,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:x.entityService,logger:x.logger})}isGitConfigured(){return this.config.git!==void 0&&(this.config.git.repo!==void 0||this.config.git.gitUrl!==void 0)}async bootstrapContentRemote(){let x=this.config.git;if(!x)return;await iVx({gitUrl:x.gitUrl,branch:x.branch,seedContentPath:this.config.seedContentPath,bootstrapFromSeed:x.bootstrapFromSeed,authorName:x.authorName,authorEmail:x.authorEmail,logger:this.logger.child("ContentRemoteBootstrap")})}async initializeGitSync(x){let B=this.config.git;if(!B)throw Error("Git configuration is unavailable");let A=new e90({logger:this.logger.child("GitSync"),dataDir:x,repo:B.repo,gitUrl:B.gitUrl,branch:B.branch,authToken:B.authToken,authorName:B.authorName,authorEmail:B.authorEmail});return await A.initialize(),this.logger.info("Git integration enabled",{repo:B.repo}),A}async startBackgroundWork(){let x=this.requireDirectorySync();if(this.config.autoSync&&!this.watcherOwned)await this.runtime.acquire(()=>x.startWatching(),()=>x.stopWatching()),this.watcherOwned=!0;let B=this.gitSync;if(!B||this.gitBackgroundStarted)return;let A=this.getContext();if(!this.gitAutoCommitRegistered)TVx(A.messaging,()=>this.requireGitSync(),this.config.commitDebounce,this.logger.child("GitAutoCommit"),this.runtimeScheduler,this.operationStatus),this.gitAutoCommitRegistered=!0;if(this.config.autoSync)pVx(B,x,A,this.config.syncInterval,this.logger.child("GitPeriodicSync"),this.runtime,this.operationStatus);this.gitBackgroundStarted=!0}async stopGeneration(x,B,A){let w=[];try{await x.close()}catch(f){w.push(f)}try{await B?.stopWatching()}catch(f){w.push(f)}try{A?.cleanup()}catch(f){w.push(f)}if(w.length>0)throw w[0]}async abandonCandidate(x,B,A){try{await x.close()}catch{}try{await B.stopWatching()}catch{}try{A?.cleanup()}catch{}}async registerJobHandlers(x){OVx(x,this.directorySyncFacade,this.logger,()=>this.requireDirectorySync(),this.requireOperationStatus())}}function W60(x={}){return new Y60(x)}var AZ=X.object({title:X.string(),section:X.string(),order:X.number().int(),sourcePath:X.string(),description:X.string().nullable().default(null),slug:X.string().nullable().default(null)}),wUx=X.object({title:X.string(),section:X.string(),order:X.number().int(),description:X.string().nullable().default(null),slug:X.string()}),Vq=j8.extend({entityType:X.literal("doc"),metadata:wUx}),H60=Vq.extend({frontmatter:AZ,body:X.string()});class F60 extends ox{constructor(){super({entityType:"doc",purpose:"A structured documentation page.",schema:Vq,frontmatterSchema:AZ})}toMarkdown(x){let B=this.extractBody(x.content),A=this.parseFrontMatter(x.content,AZ);return this.buildMarkdown(B,A)}fromMarkdown(x){let B=this.parseFrontMatter(x,AZ),A=B.slug??Gx(B.title);return{content:x,entityType:"doc",metadata:{title:B.title,section:B.section,order:B.order,slug:A,description:B.description}}}}var Ch=new F60;function fUx(x){return[...x].sort((B,A)=>{let w=B.metadata.order-A.metadata.order;if(w!==0)return w;return B.metadata.title.localeCompare(A.metadata.title)})}function DUx(x){let B=G9(x.content,AZ);return H60.parse({...x,frontmatter:B.metadata,body:B.content})}class ch extends j7{id="docs:entities";name="Docs Entity DataSource";description="Fetches and transforms doc entities for rendering";config={entityType:"doc",defaultSort:[{field:"order",direction:"asc"},{field:"section",direction:"asc"},{field:"title",direction:"asc"}],defaultLimit:100,enableNavigation:!0};constructor(x){super(x)}transformEntity(x){return DUx(x)}async fetch(x,B,A){let w=this.parseQuery(x);if(!w.query.id){let W=await this.fetchList({...w.query,limit:1000,page:void 0,pageSize:void 0},A.entityService);return B.parse(this.buildListResult(W.items,null,w.query))}let[f,D]=await Promise.all([this.fetchDetail(w.query.id,A.entityService),this.fetchList({limit:1000},A.entityService)]),$=fUx(D.items),Z=$.findIndex((W)=>W.id===f.item.id),Q=Z>0?$[Z-1]:null,Y=Z>=0&&Z<$.length-1?$[Z+1]:null;return B.parse({doc:f.item,docs:$,prevDoc:Q,nextDoc:Y})}buildDetailResult(x,B){return{doc:x,docs:[x],prevDoc:B?.prev??null,nextDoc:B?.next??null}}buildListResult(x,B,A){return{docs:fUx(x),pagination:B,baseUrl:A.baseUrl??null}}}import{jsxDEV as P5}from"preact/jsx-dev-runtime";var m89=["I","II","III","IV","V","VI","VII","VIII","IX","X"];function Uj(x){return[...x].sort((B,A)=>{let w=B.metadata.order-A.metadata.order;if(w!==0)return w;return B.metadata.title.localeCompare(A.metadata.title)})}function gh(x){let B=new Map;for(let A of Uj(x)){let w=A.metadata.section;B.set(w,[...B.get(w)??[],A])}return[...B.entries()].map(([A,w])=>({section:A,docs:w}))}function Uq(x){return`/docs/${x.metadata.slug}`}function Th(x){return`section-${x+1}`}function Gq(x){return m89[x]??String(x+1)}var QUx="text-[var(--docs-text)] font-bold",XUx="text-[var(--docs-accent)] font-bold",YUx="text-[var(--docs-text-muted)]",C89="docs-font-label text-xs uppercase tracking-[0.18em] text-[var(--docs-accent)]",c89="docs-font-display text-[var(--docs-heading)]",$Ux="inline-flex items-center justify-center rounded-lg border px-[18px] py-2.5 text-sm font-semibold transition-colors duration-150",ZUx="relative hidden py-1 text-[15px] text-[var(--docs-text-muted)] transition-colors duration-150 after:absolute after:bottom-0 after:left-0 after:h-px after:w-0 after:bg-[var(--docs-accent)] after:transition-[width] after:duration-300 hover:text-[var(--docs-text)] hover:after:w-full min-[861px]:inline-block",K60="docs-font-label text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:text-[var(--docs-text)]",dA={wrap:"mx-auto max-w-6xl px-6 pt-20 md:px-12 md:pt-24",label:C89,display:c89,button:`${$Ux} border-[var(--docs-text)] text-[var(--docs-text)] hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)]`,primaryButton:`${$Ux} border-[var(--docs-accent)] bg-[var(--docs-accent)] text-white hover:bg-transparent hover:text-[var(--docs-accent)]`},WUx=()=>P5("nav",{className:"docs-header fixed inset-x-0 top-0 z-[100] flex items-center justify-between px-6 py-4 md:px-10 md:py-5 xl:px-20",children:[P5("a",{href:"/docs",className:"docs-font-body text-xl font-bold","aria-label":"Brains docs",children:[P5("span",{className:QUx,children:"brains"},void 0,!1,void 0,this),P5("span",{className:XUx,children:"."},void 0,!1,void 0,this),P5("span",{className:YUx,children:"docs"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P5("div",{className:"docs-header__nav flex items-center gap-4 md:gap-8",children:[P5("a",{className:ZUx,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),P5("a",{className:ZUx,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),P5("a",{href:"https://rizom.ai",className:"inline-flex items-center justify-center rounded-lg border border-[var(--docs-text)] px-4 py-2 text-[13px] font-semibold text-[var(--docs-text)] transition-colors duration-150 hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)] md:px-6 md:py-2.5 md:text-[15px]",children:"Get Brains"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),HUx=()=>P5("footer",{className:"flex flex-col items-center justify-between gap-4 border-t border-[var(--docs-border-light)] py-8 text-center md:flex-row md:gap-6 md:py-6 md:text-left",children:[P5("a",{href:"https://rizom.ai",className:"docs-font-body text-[15px] font-bold",children:[P5("span",{className:QUx,children:"rizom"},void 0,!1,void 0,this),P5("span",{className:XUx,children:"."},void 0,!1,void 0,this),P5("span",{className:YUx,children:"ai"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P5("div",{className:"flex flex-wrap items-center justify-center gap-6 md:justify-end",children:[P5("a",{className:K60,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),P5("a",{className:K60,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),P5("a",{className:K60,href:"https://rizom.ai",children:"Rizom"},void 0,!1,void 0,this),P5("button",{id:"themeToggle",className:"docs-font-label cursor-pointer rounded-md border border-[var(--docs-text-light)] bg-transparent px-2.5 py-1.5 text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:border-[var(--docs-text)] hover:text-[var(--docs-text)]",type:"button",children:"\u2600 Light"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),g89=`
5464
+ `)}}class Jh extends $9{directorySync;operationStatus;constructor(x,B,A,w){super(x,{schema:w60,jobTypeName:"directory-export"});this.directorySync=A,this.operationStatus=w}async process(x,B,A){this.logger.debug("Processing directory export job",{jobId:B,data:x});let w=Date.now();try{let f=await this.directorySync.exportEntitiesWithProgress(x.entityTypes,A,x.batchSize??100);return this.logger.debug("Directory export job completed",{jobId:B,exported:f.exported,failed:f.failed,duration:Date.now()-w}),await this.operationStatus?.addExportResult(f),f}catch(f){throw this.logger.error("Directory export job failed",{jobId:B,error:f}),await this.operationStatus?.recordIssue({kind:"export",message:g(f,"Directory export failed")}),f}}summarizeDataForLog(x){return{entityTypes:x.entityTypes??"all",batchSize:x.batchSize}}}class Lh extends $9{directorySync;operationStatus;constructor(x,B,A,w){super(x,{schema:A60,jobTypeName:"directory-import"});this.directorySync=A,this.operationStatus=w}async process(x,B,A){this.logger.debug("Processing directory import job",{jobId:B,data:x});let w=Date.now();try{let f=await this.directorySync.importEntitiesWithProgress(x.paths,A,x.batchSize??100);return this.logger.debug("Directory import job completed",{jobId:B,imported:f.imported,skipped:f.skipped,failed:f.failed,quarantined:f.quarantined,duration:Date.now()-w}),await this.operationStatus?.addImportResult(f),f}catch(f){throw this.logger.error("Directory import job failed",{jobId:B,error:f}),await this.operationStatus?.recordIssue({kind:"import",message:g(f,"Directory import failed")}),f}}summarizeDataForLog(x){return{pathCount:x.paths?.length??"all",batchSize:x.batchSize}}}var Cx9=300000,cx9=500;async function IVx(x){if(x.jobIds.length===0)return;let B=x.maxWaitMs??Cx9,A=x.pollIntervalMs??cx9;x.logger.debug(`Waiting for ${x.jobIds.length} import jobs to complete`);let w=H0.gen(function*(){let $=yield*FD.currentTimeMillis;yield*H0.gen(function*(){let Y=(yield*H0.tryPromise({try:()=>Promise.all(x.jobIds.map((F)=>x.entityService.getAsyncJobStatus(F))),catch:(F)=>F})).filter((F)=>F&&(F.status==="completed"||F.status==="failed")).length;if(Y===x.jobIds.length)return x.logger.debug("All import jobs completed"),!0;if((yield*FD.currentTimeMillis)-$>B)return x.logger.warn(`Timeout waiting for import jobs (${Y}/${x.jobIds.length} completed)`),!0;let H=Math.round(Y/x.jobIds.length*100);return yield*H0.tryPromise({try:()=>x.reporter.report({progress:50+Math.round(H*0.05),message:`Processing ${Y}/${x.jobIds.length} entities`}),catch:(F)=>F}),!1}).pipe(H0.repeat({schedule:hk.spaced(A),until:(Q)=>Q}))}),f=x.clock?H0.withClock(w,x.clock):w,D=await H0.runPromiseExit(f);if(f5.isFailure(D))throw _4.squash(D.cause)}class kh extends $9{getDirectorySync;context;constructor(x,B,A){super(x,{schema:x60,jobTypeName:"directory-sync"});this.context=B,this.getDirectorySync=A}async process(x,B,A){let w=Date.now(),f=x.syncDirection??"both",D=this.getDirectorySync();this.logger.info("Starting directory sync job",{jobId:B,operation:x.operation,syncDirection:f});let $={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},Z={exported:0,failed:0,errors:[]};if(f!=="export")if(await A.report({progress:10,message:"Scanning directory for changes"}),$=await this.importWithProgress(D,x.paths,A),f==="import")await this.waitForImportJobs($.jobIds,A),await A.report({progress:100,message:`Import complete: ${$.imported} imported`});else await A.report({progress:50,message:`Imported ${$.imported} entities`}),await this.waitForImportJobs($.jobIds,A),await A.report({progress:56,message:"Processing complete, starting export"});if(f!=="import"){let Y=f==="export"?10:60;await A.report({progress:Y,message:"Exporting entities to directory"}),Z=await this.exportWithProgress(D,x.entityTypes,A),await A.report({progress:100,message:f==="export"?`Export complete: ${Z.exported} exported`:`Sync complete: ${$.imported} imported, ${Z.exported} exported`})}let Q=Date.now()-w;return this.logger.info("Directory sync job completed",{jobId:B,duration:Q,imported:$.imported,exported:Z.exported}),{import:$,export:Z,duration:Q}}async importWithProgress(x,B,A){try{return await x.importEntitiesWithProgress(B,A,10)}catch(w){throw this.logger.error("Import phase failed",{error:w}),w}}async exportWithProgress(x,B,A){try{return await x.exportEntitiesWithProgress(B,A,10)}catch(w){throw this.logger.error("Export phase failed",{error:w}),w}}waitForImportJobs(x,B){return IVx({jobIds:x,entityService:this.context.entityService,reporter:B,logger:this.logger})}summarizeDataForLog(x){return{operation:x.operation,syncDirection:x.syncDirection}}}class Mh extends $9{context;getDirectorySync;getGitSync;constructor(x,B,A,w){super(x,{schema:B60,jobTypeName:"sync-request"});this.context=B,this.getDirectorySync=A,this.getGitSync=w}async process(x,B,A){await A.report({progress:5,message:"Pulling latest content from git"});let w=this.getDirectorySync(),f=this.getGitSync(),D=await f.withLock(async()=>{return await f.pull(),await A.report({progress:35,message:"Scanning pulled content for sync changes"}),w.queueSyncBatch(this.context,x.source,{rootJobId:B,interfaceType:x.interfaceType,channelId:x.channelId})});if(!D)return await A.report({progress:100,message:"Sync complete: no files to import"}),{gitPulled:!0,batchQueued:!1};return await A.report({progress:100,message:`Sync queued: ${D.importOperationsCount} import jobs for ${D.totalFiles} files`}),gx9(D)}summarizeDataForLog(x){return{source:x.source,interfaceType:x.interfaceType,channelId:x.channelId}}}function gx9(x){return{gitPulled:!0,batchQueued:!0,batchId:x.batchId,importOperations:x.importOperationsCount,totalFiles:x.totalFiles}}class vh extends $9{context;constructor(x,B,A){super(x,{schema:_h,jobTypeName:"directory-delete"});this.context=B}async process(x,B,A){let w=_h.parse(x);this.logger.info("Processing entity deletion for removed file",{entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}),await A.report({progress:0,total:1,message:`Deleting ${w.entityType}:${w.entityId}`});try{let f=await this.context.entityService.deleteEntity({entityType:w.entityType,id:w.entityId});if(f)this.logger.info("Successfully deleted entity for removed file",{entityId:w.entityId,entityType:w.entityType});else this.logger.warn("Entity not found in database",{entityId:w.entityId,entityType:w.entityType});return await A.report({progress:1,total:1,message:`Deleted ${w.entityType}:${w.entityId}`}),{deleted:f,entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}}catch(f){throw this.logger.error("Failed to delete entity",{entityId:w.entityId,entityType:w.entityType,error:f}),f}}summarizeDataForLog(x){return{entityId:x.entityId,entityType:x.entityType,filePath:x.filePath}}}var Tx9=X.object({});class Nh extends $9{directorySync;constructor(x,B){super(x,{schema:Tx9,jobTypeName:"directory-cleanup"});this.directorySync=B}async process(x,B,A){await A.report({progress:0,message:"Removing orphaned entities"});let w=await this.directorySync.removeOrphanedEntities();return await A.report({progress:100,message:`Cleanup complete: ${w.deleted} orphans removed`}),w}}import{readFile as px9,writeFile as ux9}from"fs/promises";var Sx9=f60,ix9=X.record(X.string(),X.unknown());class Ih extends $9{context;fetcher;constructor(x,B,A=m3){super(B,{schema:Sx9,jobTypeName:"cover-image-convert"});this.context=x,this.fetcher=A}async process(x,B,A){let{filePath:w,sourceUrl:f,postTitle:D,postSlug:$,customAlt:Z}=x;this.logger.debug("Starting image conversion job",{jobId:B,filePath:w,sourceUrl:f,postSlug:$});try{await this.reportProgress(A,{progress:b8.INIT,message:`Reading file: ${w}`});let Q;try{Q=await px9(w,"utf-8")}catch(b){return this.logger.error("Failed to read file",{filePath:w,error:g(b)}),p6.failure(b)}let Y;try{Y=I1(Q)}catch(b){return this.logger.warn("Failed to parse markdown",{filePath:w,error:g(b)}),p6.failure(b)}let W=ix9.safeParse(Y.frontmatter),H=W.success?W.data:{};if(H.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:w}),await this.reportProgress(A,{progress:b8.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(A,{progress:b8.FETCH,message:"Checking for existing image"});let F=await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{sourceUrl:f}},limit:1}}),K;if(F[0])K=F[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:f,imageId:K}),await this.reportProgress(A,{progress:b8.EXTRACT,message:`Reusing existing image: ${K}`});else{await this.reportProgress(A,{progress:b8.PROCESS,message:`Fetching image from ${f}`});let b;try{b=await this.fetcher(f)}catch(y){return this.logger.error("Failed to fetch image",{sourceUrl:f,error:g(y)}),p6.failure(y)}await this.reportProgress(A,{progress:b8.GENERATE,message:"Creating image entity"});let{base64:G}=sO(b),E=rO(G),_=oO(G);if(!E||!_)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:f}),p6.failure(Error("Could not detect image format or dimensions"));K=`${$}-cover`;let L=`Cover image for ${D}`,N=Z??L;await this.context.entityService.createEntity({entity:{id:K,entityType:"image",content:b,metadata:{title:L,alt:N,format:E,width:_.width,height:_.height,sourceUrl:f}}}),this.logger.debug("Created image entity",{imageId:K,sourceUrl:f}),await this.reportProgress(A,{progress:b8.EXTRACT,message:`Created image: ${K}`})}await this.reportProgress(A,{progress:b8.SAVE,message:"Updating file"});let q={...H};delete q.coverImageUrl,delete q.coverImageAlt,q.coverImageId=K;let V=eO(q,Y.content);try{await ux9(w,V,"utf-8")}catch(b){return this.logger.error("Failed to write file",{filePath:w,error:g(b)}),p6.failure(b)}return await this.reportProgress(A,{progress:b8.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:w,imageId:K,sourceUrl:f}),{success:!0,imageId:K}}catch(Q){return this.logger.error("Image conversion job failed",{jobId:B,filePath:w,error:g(Q)}),p6.failure(Q)}}summarizeDataForLog(x){return{filePath:x.filePath,sourceUrl:x.sourceUrl,postSlug:x.postSlug}}}import{readFile as lx9,writeFile as nx9}from"fs/promises";class Oh extends $9{converter;constructor(x,B,A=m3){super(B,{schema:D60,jobTypeName:"inline-image-convert"});this.converter=new Dj(x.entityService,B,A)}async process(x,B,A){let{filePath:w,postSlug:f}=x;this.logger.debug("Starting inline image conversion job",{jobId:B,filePath:w,postSlug:f});try{await this.reportProgress(A,{progress:b8.INIT,message:`Reading file: ${w}`});let D;try{D=await lx9(w,"utf-8")}catch(Q){let Y=g(Q);return this.logger.error("Failed to read file",{filePath:w,error:Y}),{success:!1,error:Y}}await this.reportProgress(A,{progress:b8.FETCH,message:"Detecting inline images"});let $=this.converter.detectInlineImages(D,f);if($.length===0)return this.logger.debug("No inline images to convert",{filePath:w}),await this.reportProgress(A,{progress:b8.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:w,count:$.length}),await this.reportProgress(A,{progress:b8.PROCESS,message:`Converting ${$.length} images`});let Z=await this.converter.convert(D,f);if(!Z.converted)return this.logger.debug("No images were converted",{filePath:w}),await this.reportProgress(A,{progress:b8.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(A,{progress:b8.SAVE,message:"Writing updated file"});try{await nx9(w,Z.content,"utf-8")}catch(Q){let Y=g(Q);return this.logger.error("Failed to write file",{filePath:w,error:Y}),{success:!1,error:Y}}return await this.reportProgress(A,{progress:b8.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:w,convertedCount:Z.convertedCount}),{success:!0,convertedCount:Z.convertedCount}}catch(D){let $=g(D);return this.logger.error("Inline image conversion job failed",{jobId:B,filePath:w,error:$}),{success:!1,error:$}}}summarizeDataForLog(x){return{filePath:x.filePath,postSlug:x.postSlug}}}function OVx(x,B,A,w=()=>B,f){let D=($)=>A.child($);x.jobs.registerHandler("directory-sync",new kh(D("DirectorySyncJobHandler"),x,w)),x.jobs.registerHandler("directory-export",new Jh(D("DirectoryExportJobHandler"),x,B,f)),x.jobs.registerHandler("directory-import",new Lh(D("DirectoryImportJobHandler"),x,B,f)),x.jobs.registerHandler("directory-delete",new vh(D("DirectoryDeleteJobHandler"),x,B)),x.jobs.registerHandler("directory-cleanup",new Nh(D("DirectoryCleanupJobHandler"),B)),x.jobs.registerHandler("cover-image-convert",new Ih(x,D("CoverImageConversionJobHandler"))),x.jobs.registerHandler("inline-image-convert",new Oh(x,D("InlineImageConversionJobHandler"))),A.debug("Registered async job handlers")}import{unlink as dx9,access as ax9}from"fs/promises";var sx9=X.record(X.string(),X.unknown());function hVx(x,B,A,w,f){let{subscribe:D}=x.messaging,{entityService:$}=x;D(l8.created,async(Z)=>{let{entity:Q}=Z.payload;try{await B().fileOps.writeEntity(Q),A.debug("Auto-exported created entity",{id:Q.id,entityType:Q.entityType}),await f?.clearIssues(["export"])}catch(Y){A.error("Auto-export FAILED for created entity",{id:Q.id,entityType:Q.entityType,error:g(Y),stack:Y instanceof Error?Y.stack:void 0}),await f?.recordIssue({kind:"export",path:`${Q.entityType}/${Q.id}.md`,message:g(Y,"Entity export failed")})}return{success:!0}}),D(l8.updated,async(Z)=>{let{entityType:Q,entityId:Y}=Z.payload;try{let W=await $.getEntity({entityType:Q,id:Y});if(!W)return A.debug("Entity not found in DB, skipping export",{entityType:Q,entityId:Y}),{success:!1};await B().fileOps.writeEntity(W),A.debug("Auto-exported updated entity",{id:W.id,entityType:W.entityType}),await f?.clearIssues(["export"])}catch(W){A.error("Auto-export FAILED for updated entity",{entityType:Q,entityId:Y,error:g(W),stack:W instanceof Error?W.stack:void 0}),await f?.recordIssue({kind:"export",path:`${Q}/${Y}.md`,message:g(W,"Entity export failed")})}return{success:!0}}),D(l8.deleted,async(Z)=>{let{entityId:Q,entityType:Y}=Z.payload,W=B().fileOps.getFilePath(Q,Y);if(await ax9(W).then(()=>!0,()=>!1))await dx9(W),A.debug("Auto-deleted entity file",{id:Q,entityType:Y,path:W});return{success:!0}}),A.debug("Setup auto-sync for entity events",{entityTypes:w})}function $60(x,B,A,w){B.setJobQueueCallback(async(f)=>{let D=await w?.startRun("watcher","importing"),$=[{type:f.type,data:sx9.parse(f.data)}];try{let Z=await x.jobs.enqueueBatch($,{priority:5,source:"directory-sync-watcher",rootJobId:DY(),metadata:{operationType:"file_operations",operationTarget:A,pluginId:"directory-sync"}});if(D)await w?.attachBatch(D,Z);return Z}catch(Z){if(D)await w?.failRun(D,g(Z,"Watcher import failed"),"import");throw Z}})}import{readdir as mVx,mkdir as ox9,copyFile as tx9}from"fs/promises";import{join as yVx,resolve as Z60}from"path";import{join as rx9}from"path";async function RVx(x){if(!await s6(rx9(x,".git")))return!1;try{return await C3(x).revparse(["--verify","HEAD"]),!0}catch{return!1}}async function ex9(x,B){if(!await s6(x))return!0;if((await mVx(x)).filter((f)=>!f.startsWith(".")&&!f.startsWith("_")).length>0)return!1;if(await RVx(x))return B.debug("Git repository with history detected - skipping seed content",{path:x}),!1;return!0}async function CVx(x,B){let A=await mVx(x,{withFileTypes:!0});for(let w of A){let f=yVx(x,w.name),D=yVx(B,w.name);if(w.isDirectory()){if(!await s6(D))await ox9(D,{recursive:!0});await CVx(f,D)}else await tx9(f,D)}}async function cVx(x,B,A){let w=Z60(process.cwd(),x);A=A?Z60(A):Z60(process.cwd(),"seed-content");let f=await ex9(w,B);if(f&&await s6(A))B.debug("Copying seed content to brain-data directory"),await CVx(A,w),B.debug("Seed content copied successfully");else if(f)B.debug("No seed content directory found, starting with empty brain-data");else B.debug("brain-data directory not empty, skipping seed content")}function gVx(x,B,A,w,f){let D=!1,$=async()=>{if(D)return;D=!0;let Z=B();if(A.seedContent){let Q=A.syncPath??x.dataDir;await cVx(Q,w,A.seedContentPath)}try{if(f){w.debug("Git enabled \u2014 pulling before import");let Y=await f.pull();if(Y.files.length>0)w.info("Pulled changes from remote",{filesChanged:Y.files.length})}w.debug("Starting initial sync");let Q=await Z.sync();w.debug("Initial sync completed",{imported:Q.import.imported,failed:Q.import.failed,duration:Q.duration}),await x.messaging.send({type:e8.initialSyncCompleted,payload:{success:!0},...{broadcast:!0}})}catch(Q){w.error("Initial sync failed",Q),await x.messaging.send({type:e8.initialSyncCompleted,payload:{success:!1,error:g(Q)},...{broadcast:!0}})}};x.messaging.subscribe(e8.pluginsRegistered,async()=>{return w.debug("Plugins registered, starting initial sync"),await $(),{success:!0}})}var x89="git-auto-commit";function TVx(x,B,A,w,f,D){let $=typeof B==="function"?B:()=>B,Z=async()=>{let Y=$();try{if(!await Y.withLock(async()=>{let H=await Y.getStatus();if(!H.isRepo)throw Error("Git repository is unavailable");if(!H.hasChanges&&H.ahead===0)return!1;if(H.hasChanges)await Y.commit();return await Y.push(),!0}))return;await D?.clearIssues(["git"]),await D?.recordTerminal("save","succeeded","Local content committed and pushed")}catch(W){w.error("Git auto-commit failed",{error:W});let H=g(W,"Git auto-commit failed");await D?.recordIssue({kind:"git",message:H}),await D?.recordTerminal("save","failed",H)}},Q=[l8.created,l8.updated,l8.deleted];for(let Y of Q)x.subscribe(Y,async()=>{return f.scheduleTrailing(x89,A,Z),{success:!0}})}function pVx(x,B,A,w,f,D,$){if(w<=0)return;let Z=w*60*1000,Q=async(Y)=>{let W=await $?.startRun("periodic","pulling");try{let{files:H,result:F}=await x.withLock(async()=>{let K=await x.pull(Y);if(Y.throwIfAborted(),K.files.length===0)return{files:[],result:null};let q=await B.queueSyncBatch(A,"periodic-sync",void 0,K.files);if(q)B.suppressWatchPaths(K.files);return{files:K.files,result:q}},Y);if(H.length>0)f.info("Periodic sync: pulled changes",{filesChanged:H.length});if(F){if(f.debug("Periodic sync: queued imports",{importOperations:F.importOperationsCount,totalFiles:F.totalFiles}),W)await $?.attachBatch(W,F.batchId)}else if(W)await $?.completeRun(W,H.length===0?"Remote checked; no changes found":"Remote changes required no imports")}catch(H){if(Y.aborted){if(W)await $?.clearRun(W)}else if(f.error("Periodic git sync failed",{error:H}),W)await $?.failRun(W,g(H,"Periodic Git sync failed"))}};D.schedulePeriodic(Z,Q),f.info("Started periodic git sync",{intervalMinutes:w})}import{spawnSync as SVx}from"child_process";import{cpSync as B89,existsSync as uVx,mkdirSync as A89,mkdtempSync as w89,rmSync as f89}from"fs";import{tmpdir as D89}from"os";import{fileURLToPath as $89}from"url";import{join as Z89,resolve as Q89}from"path";function BZ(x,B){let A=SVx("git",B,{cwd:x,stdio:"pipe"});if(A.status!==0){let w=A.stderr.toString().trim(),f=A.stdout.toString().trim();throw Error(w||f||`git ${B.join(" ")} failed`)}}function X89(x){return x.startsWith("file://")}function Y89(x){return $89(x)}function W89(x,B){return SVx("git",["--git-dir",x,"show-ref","--verify","--quiet",`refs/heads/${B}`]).status===0}async function iVx(x){if(!x.bootstrapFromSeed)return;if(!x.gitUrl||!X89(x.gitUrl))return;if(!x.seedContentPath)throw Error("directory-sync git.bootstrapFromSeed requires seedContentPath for local file:// remotes");let B=x.branch??"main",A=Y89(x.gitUrl),w=Q89(x.seedContentPath);if(!uVx(w))throw Error(`Seed content path not found: ${w}`);if(!uVx(A))x.logger.debug("Creating local bare content remote",{remotePath:A,branch:B}),A89(A,{recursive:!0}),BZ(process.cwd(),["init","--bare",`--initial-branch=${B}`,A]);if(W89(A,B)){x.logger.debug("Content remote already initialized",{remotePath:A,branch:B});return}x.logger.debug("Seeding local content remote",{remotePath:A,seedPath:w,branch:B});let f=w89(Z89(D89(),"directory-sync-seed-"));try{BZ(f,["init",`--initial-branch=${B}`]),BZ(f,["config","user.name",x.authorName??"Brain"]),BZ(f,["config","user.email",x.authorEmail??"brain@localhost"]),B89(w,f,{recursive:!0,filter:(D)=>!D.split("/").includes(".git")}),BZ(f,["add","."]),BZ(f,["commit","-m","seed content remote"]),BZ(f,["remote","add","origin",x.gitUrl]),BZ(f,["push","-u","origin",B])}finally{f89(f,{recursive:!0,force:!0})}}function lVx(x,B,A,w,f,D,$){let{subscribe:Z}=x.messaging;Z(HB.entityExportRequest,async(Q)=>{try{return{success:!0,data:await B().exportEntities(Q.payload.entityTypes)}}catch(Y){return{success:!1,error:g(Y,"Export failed")}}}),Z(HB.entityImportRequest,async(Q)=>{try{let Y=B(),W=Q.payload.paths,H=await Y.importEntities(W);if(W&&W.length>0)await Y.removeOrphanedEntities();return{success:!0,data:H}}catch(Y){return{success:!1,error:g(Y,"Import failed")}}}),Z(HB.statusRequest,async()=>{try{let Y=await B().getStatus(),W=$?.();return{success:!0,data:{syncPath:Y.syncPath,isInitialized:Y.exists,watchEnabled:Y.watching,lastSync:Y.lastSync?.toISOString()??null,totalFiles:Y.stats.totalFiles,byEntityType:Y.stats.byEntityType,git:await H89(D?.(),w),...W?{managementUrl:W}:{}}}}catch(Q){return{success:!1,error:g(Q,"Status check failed")}}}),Z(HB.configureRequest,async(Q)=>{try{return await A({syncPath:Q.payload.syncPath}),{success:!0,data:{syncPath:Q.payload.syncPath,configured:!0}}}catch(Y){return{success:!1,error:g(Y,"Configuration failed")}}}),Z(HB.getRepoInfo,async()=>{if(!f?.repo)return{success:!1,error:"Git not configured"};return{success:!0,data:{repo:f.repo,branch:f.branch??"main"}}}),w.debug("Registered message handlers")}async function H89(x,B){if(!x)return null;try{let A=await x.getStatus();return{branch:A.branch,hasChanges:A.hasChanges,ahead:A.ahead,behind:A.behind,lastCommit:A.lastCommit??null,remote:A.remote??null}}catch(A){return B.debug("Git status unavailable for sync:status:request",{error:A}),null}}async function hh(x){let B=await x.operationStatus?.startRun("manual",x.gitSync?"pulling":"scanning");try{if(x.gitSync){let w=await x.context.jobs.enqueue({type:"sync-request",data:{source:x.source,interfaceType:x.interfaceType,channelId:x.channelId},...x.toolContext?{toolContext:x.toolContext}:{}});if(B)await x.operationStatus?.attachJob(B,w);return{...B?{runId:B}:{},gitPulled:!0,jobId:w,status:"queued"}}let A=await x.directorySync.queueSyncBatch(x.context,x.source,{interfaceType:x.interfaceType,channelId:x.channelId});if(!A){if(B)await x.operationStatus?.completeRun(B,"No files to sync");return{...B?{runId:B}:{},gitPulled:!1,status:"settled"}}if(B)await x.operationStatus?.attachBatch(B,A.batchId);return{...B?{runId:B}:{},...A,gitPulled:!1,status:"queued"}}catch(A){if(B)await x.operationStatus?.failRun(B,g(A,"Sync request failed"),x.gitSync?"git":"source");throw A}}var XS6=X.object({entityType:X.string(),id:X.string(),sha:X.string().optional(),limit:X.number().int().positive().optional().default(10)});async function nVx(x,B){let A=`${x.entityType}/${x.id}.md`,w=x.limit??10;try{if(x.sha){let D=await B.show(x.sha,A);return G1({sha:x.sha,entityType:x.entityType,id:x.id,content:D},`Content at ${x.sha.slice(0,7)}`)}let f=await B.log(A,w);if(f.length===0)return G1({commits:[]},`No history found for ${x.entityType}/${x.id}`);return G1({commits:f,entityType:x.entityType,id:x.id},`${f.length} version${f.length===1?"":"s"} found`)}catch(f){return U1(g(f,"History lookup failed"))}}var F89=X.object({action:X.enum(["sync","status"]).default("sync").describe("Use sync for a refresh request and status for a status check")}),K89=X.object({action:X.enum(["sync","status","history"]).default("sync").describe("Use sync for git/filesystem sync, status for a status check, and history only for entity history"),entityType:X.string().optional().describe("History only; omit for sync and status"),id:X.string().optional().describe("History only; omit for sync and status"),sha:X.string().optional().describe("Optional history revision; omit for sync and status"),limit:X.number().int().positive().optional().default(10).describe("History only; omit for sync and status")}),q89=X.discriminatedUnion("action",[X.object({action:X.literal("sync")}),X.object({action:X.literal("status")})]),z89=X.discriminatedUnion("action",[X.object({action:X.literal("sync")}),X.object({action:X.literal("status")}),X.object({action:X.literal("history"),entityType:X.string().min(1),id:X.string().min(1),sha:X.string().optional(),limit:X.number().int().positive().optional().default(10)})]);function dVx(x,B,A,w,f){return[E1("directory","sync",w?"Manage directory and git sync with an action discriminator. For requests such as 'sync with git', immediately call action=sync with no entityType, id, or sha; never ask for those fields because they apply only to action=history. Action=sync queues a git pull plus filesystem scan when git is configured and also handles refresh, pull, backup-to-git, and filesystem import requests. For every sync or git status follow-up after action=sync, including a bare 'what is the status', immediately call action=status with no entity fields; a sync jobId is not a system_job_status batchId. Use action=history to read git version history for a specific entity.":"Manage directory sync with an action discriminator. Immediately call action=sync for refresh, filesystem import, or content sync requests. Immediately call action=status for directory sync status follow-ups, including a bare 'what is the status'.",w?K89:F89,async($,Z)=>{let Q=w?z89.parse($):q89.parse($);if(Q.action==="sync")return b89({directorySync:x,pluginContext:B,pluginId:A,gitSync:w,operationStatus:f,context:Z});if(Q.action==="status")return V89(x,w);if(!w)return U1("History is unavailable because git is not configured");return nVx(Q,w)},{visibility:"admin",sideEffects:"external",cli:{name:"sync"}})]}async function b89(x){try{let B=x.context.channelId?`${x.context.interfaceType}:${x.context.channelId}`:`plugin:${x.pluginId}`,A=await hh({context:x.pluginContext,directorySync:x.directorySync,source:B,interfaceType:x.context.interfaceType,channelId:x.context.channelId,toolContext:x.context,gitSync:x.gitSync,operationStatus:x.operationStatus});if(A.gitPulled)return G1({jobId:A.jobId,status:A.status,gitPulled:!0,...A.runId?{runId:A.runId}:{}},"Sync queued: git pull and filesystem scan will run in the background");if(A.status==="settled")return G1({gitPulled:!1,...A.runId?{runId:A.runId}:{}},"No files to sync");return G1({batchId:A.batchId,importOperations:A.importOperationsCount,totalFiles:A.totalFiles,gitPulled:!1,...A.runId?{runId:A.runId}:{}},`Sync started: ${A.importOperationsCount} import jobs queued for ${A.totalFiles} files`)}catch(B){return U1(g(B,"Sync failed"))}}async function V89(x,B){try{let A=await x.getStatus(),w={syncPath:A.syncPath,lastSync:A.lastSync?.toISOString(),watching:A.watching};if(B){let f=await B.getStatus();w.git={isRepo:f.isRepo,branch:f.branch,hasChanges:f.hasChanges,ahead:f.ahead,behind:f.behind,remote:f.remote}}return G1(w)}catch(A){return U1(g(A,"Status check failed"))}}import{isAbsolute as aVx,relative as U89}from"path";var oVx=X.enum(["manual","periodic","watcher","save"]),G89=X.enum(["pulling","scanning","importing","settling"]),tVx={imported:X.number().int().nonnegative(),skipped:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),quarantined:X.number().int().nonnegative(),exported:X.number().int().nonnegative()},E89=X.object({id:X.string().min(1),source:oVx,state:G89,startedAt:X.string().datetime(),jobId:X.string().min(1).optional(),batchId:X.string().min(1).optional(),...tVx}),j89=X.object({id:X.string().min(1),source:oVx,outcome:X.enum(["succeeded","attention","failed"]),startedAt:X.string().datetime(),completedAt:X.string().datetime(),summary:X.string().min(1).max(240),...tVx}),_89=X.object({id:X.string().min(1),kind:X.enum(["quarantined","import","export","git","source"]),path:X.string().min(1).max(300).optional(),message:X.string().min(1).max(400),occurredAt:X.string().datetime()}),P89=X.object({activeRun:E89.optional(),recentRuns:X.array(j89).max(5),issues:X.array(_89).max(8)}),J89=X.object({gitPulled:X.literal(!0),batchQueued:X.boolean(),batchId:X.string().optional(),importOperations:X.number().int().nonnegative().optional(),totalFiles:X.number().int().nonnegative().optional()}),sVx={imported:0,skipped:0,failed:0,quarantined:0,exported:0},L89={recentRuns:[],issues:[]},k89="directory-sync.operation-status",M89="current";class Q60{store;jobs;logger;syncPath;constructor(x,B,A,w){this.store=new yh({runtimeState:x,namespace:k89,key:M89,schema:P89,createEmpty:()=>structuredClone(L89)}),this.jobs=B,this.logger=A,this.syncPath=w}setSyncPath(x){this.syncPath=x}async initialize(){let x=await this.store.snapshot();if(x.activeRun&&!x.activeRun.jobId&&!x.activeRun.batchId){await this.clearRun(x.activeRun.id);return}await this.reconcile()}startRun(x,B){let A=DY();return this.mutate((w)=>{if(w.activeRun)return;return w.activeRun={id:A,source:x,state:B,startedAt:new Date().toISOString(),...sVx},A})}markPhase(x,B){return this.mutate((A)=>{if(A.activeRun?.id===x)A.activeRun.state=B})}attachJob(x,B){return this.mutate((A)=>{if(A.activeRun?.id!==x)return;A.activeRun.jobId=B,A.activeRun.state="pulling"})}attachBatch(x,B){return this.mutate((A)=>{if(A.activeRun?.id!==x)return;delete A.activeRun.jobId,A.activeRun.batchId=B,A.activeRun.state="importing"})}addImportResult(x){return this.mutate((B)=>{if(B.activeRun)B.activeRun.imported+=x.imported,B.activeRun.skipped+=x.skipped,B.activeRun.failed+=x.failed,B.activeRun.quarantined+=x.quarantined;let A=[...x.errors.map((w)=>({kind:"import",path:this.safePath(w.path),message:w.error})),...x.quarantinedFiles.map((w)=>({kind:"quarantined",path:this.safePath(w),message:"File was quarantined because it could not be imported"}))];if(A.length===0)B.issues=B.issues.filter((w)=>w.kind!=="import"&&w.kind!=="quarantined");else for(let w of A)this.prependIssue(B,w)})}addExportResult(x){return this.mutate((B)=>{if(B.activeRun)B.activeRun.exported+=x.exported,B.activeRun.failed+=x.failed;if(x.errors.length===0){B.issues=B.issues.filter((A)=>A.kind!=="export");return}for(let A of x.errors)this.prependIssue(B,{kind:"export",path:`${A.entityType}/${A.entityId}.md`,message:A.error})})}recordIssue(x){return this.mutate((B)=>this.prependIssue(B,x))}clearIssues(x){return this.mutate((B)=>{B.issues=B.issues.filter((A)=>!x.includes(A.kind))})}completeRun(x,B){return this.finishRun(x,"succeeded",B)}clearRun(x){return this.mutate((B)=>{if(B.activeRun?.id===x)delete B.activeRun})}failRun(x,B,A="git"){return this.mutate((w)=>{let f=w.activeRun;if(f?.id!==x)return;let D=Rh(B);this.prependRecent(w,f,"failed",D),this.prependIssue(w,{kind:A,message:D}),delete w.activeRun})}recordTerminal(x,B,A,w={}){return this.mutate((f)=>{let D=new Date().toISOString();this.prependRecent(f,{id:DY(),source:x,state:"settling",startedAt:D,...sVx,...w},B,A)})}async reconcile(){let B=(await this.store.snapshot()).activeRun;if(!B)return;try{if(B.jobId){let A=await this.jobs.getStatus(B.jobId);if(!A){await this.failRun(B.id,"The active sync job could not be found after restart","source");return}if(A.status==="pending"||A.status==="processing"){await this.markPhase(B.id,"pulling");return}if(A.status==="failed"){await this.failRun(B.id,A.lastError??"Git-backed sync failed");return}let w=J89.safeParse(v89(A.result));if(!w.success){await this.failRun(B.id,"Sync job completed without a readable result","source");return}if(w.data.batchQueued&&w.data.batchId)return await this.attachBatch(B.id,w.data.batchId),await this.reconcile();await this.completeRun(B.id,"Remote checked; no files to import");return}if(B.batchId){let A=await this.jobs.getBatchStatus(B.batchId);if(!A){await this.failRun(B.id,"The active sync batch could not be recovered after restart","source");return}if(A.status==="pending"||A.status==="processing"){await this.markPhase(B.id,"importing");return}if(A.status==="failed"){await this.failRun(B.id,A.errors.join("; ")||"Directory import batch failed","import");return}await this.completeRun(B.id,`${A.completedOperations} sync operations completed`)}}catch(A){this.logger.debug("Unable to reconcile directory sync operation",{error:A})}}async getSnapshot(){return await this.reconcile(),this.store.snapshot()}finishRun(x,B,A){return this.mutate((w)=>{let f=w.activeRun;if(f?.id!==x)return;let D=f.failed>0||f.quarantined>0?"attention":B;if(this.prependRecent(w,f,D,A),delete w.activeRun,D==="succeeded")w.issues=w.issues.filter(($)=>$.kind!=="git"&&$.kind!=="source")})}mutate(x){return this.store.mutate(x)}prependRecent(x,B,A,w){let f={id:B.id,source:B.source,outcome:A,startedAt:B.startedAt,completedAt:new Date().toISOString(),summary:Rh(w,240),imported:B.imported,skipped:B.skipped,failed:B.failed,quarantined:B.quarantined,exported:B.exported};x.recentRuns=[f,...x.recentRuns.filter((D)=>D.id!==f.id)].slice(0,5)}prependIssue(x,B){let A=B.path?this.safePath(B.path):void 0,w={id:`${B.kind}:${A??Rh(B.message,80)}`,kind:B.kind,...A?{path:A}:{},message:Rh(B.message),occurredAt:new Date().toISOString()};x.issues=[w,...x.issues.filter((f)=>f.id!==w.id)].slice(0,8)}safePath(x){if(!aVx(x))return rVx(x);let B=U89(this.syncPath,x);if(B.startsWith("..")||aVx(B))return"content file";return rVx(B)}}function v89(x){if(typeof x!=="string")return x;try{return JSON.parse(x)}catch{return x}}function rVx(x){return x.replaceAll("\\","/").replace(/^\.\//,"").slice(0,300)||"content file"}function Rh(x,B=400){return x.replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi,"$1[redacted]@").replace(/(token|password|authorization)=([^\s&]+)/gi,"$1=[redacted]").replace(/\s+/g," ").trim().slice(0,B)||"Directory sync operation failed"}import{basename as N89}from"path";var I89=X.object({type:X.literal("sync-now")}),eVx={imported:X.number().int().nonnegative(),skipped:X.number().int().nonnegative(),failed:X.number().int().nonnegative(),quarantined:X.number().int().nonnegative(),exported:X.number().int().nonnegative()},O89=X.object({health:X.enum(["healthy","active","attention"]),directory:X.object({displayPath:X.string().min(1),exists:X.boolean(),watching:X.boolean(),totalFiles:X.number().int().nonnegative(),byEntityType:X.record(X.string(),X.number().int().nonnegative()),lastSettledAt:X.string().datetime().optional()}),git:X.object({branch:X.string().min(1),remoteLabel:X.string().min(1).optional(),hasChanges:X.boolean(),ahead:X.number().int().nonnegative(),behind:X.number().int().nonnegative(),lastCommit:X.string().min(1).optional(),changedFiles:X.array(X.object({path:X.string().min(1),status:X.string().min(1)})),changedFilesTruncated:X.boolean()}).nullable(),automation:X.object({autoSync:X.boolean(),watchIntervalMs:X.number().int().nonnegative(),remoteIntervalMinutes:X.number().nonnegative().optional(),commitDebounceMs:X.number().int().nonnegative().optional(),deleteOnFileRemoval:X.boolean()}),activeRun:X.object({id:X.string().min(1),source:X.enum(["manual","periodic","watcher","save"]),state:X.enum(["pulling","scanning","importing","settling"]),startedAt:X.string().datetime(),jobId:X.string().min(1).optional(),batchId:X.string().min(1).optional(),...eVx}).optional(),recentRuns:X.array(X.object({id:X.string().min(1),source:X.enum(["manual","periodic","watcher","save"]),outcome:X.enum(["succeeded","attention","failed"]),startedAt:X.string().datetime(),completedAt:X.string().datetime(),summary:X.string().min(1),...eVx})),issues:X.array(X.object({id:X.string().min(1),kind:X.enum(["quarantined","import","export","git","source"]),path:X.string().min(1).optional(),message:X.string().min(1),occurredAt:X.string().datetime()}))});class X60{options;constructor(x){this.options=x}async getSnapshot(){let x=await this.options.getDirectorySync().getStatus();this.options.operationStatus.setSyncPath(x.syncPath);let B,A=this.options.getGitSync();if(A)try{if(B=await A.getStatus(),!B.hasChanges&&B.ahead===0&&B.behind===0)await this.options.operationStatus.clearIssues(["git"])}catch($){await this.options.operationStatus.recordIssue({kind:"git",message:g($,"Git status unavailable")})}if(!x.exists)await this.options.operationStatus.recordIssue({kind:"source",message:"The configured sync directory is unavailable"});else await this.options.operationStatus.clearIssues(["source"]);let w=await this.options.operationStatus.getSnapshot(),f=w.recentRuns[0]?.completedAt??x.lastSync?.toISOString(),D=w.activeRun?"active":w.issues.length>0?"attention":"healthy";return O89.parse({health:D,directory:{displayPath:N89(x.syncPath)||"brain-data",exists:x.exists,watching:x.watching,totalFiles:x.stats.totalFiles,byEntityType:x.stats.byEntityType,...f?{lastSettledAt:f}:{}},git:B?this.toSafeGitStatus(B):null,automation:{autoSync:this.options.config.autoSync,watchIntervalMs:this.options.config.watchInterval,...A?{remoteIntervalMinutes:this.options.config.syncInterval,commitDebounceMs:this.options.config.commitDebounce}:{},deleteOnFileRemoval:this.options.config.deleteOnFileRemoval},...w.activeRun?{activeRun:w.activeRun}:{},recentRuns:w.recentRuns,issues:w.issues})}async registerCmsWorkspace(){let x={id:"sync",pluginId:this.options.pluginId,label:"Sync",rendererName:"DirectorySyncWorkspace",priority:60,accessHandler:(B)=>_7.hasPermission(B.userPermissionLevel,"admin"),dataProvider:async(B)=>{if(!_7.hasPermission(B.userPermissionLevel,"admin"))throw Error("Directory sync requires admin permission");return this.getSnapshot()},actionHandler:async(B,A)=>{if(!_7.hasPermission(A.userPermissionLevel,"admin"))throw Error("Directory sync requires admin permission");if(!I89.safeParse(B).success)throw Error("Invalid directory sync workspace action");let f={interfaceType:"cms",actor:A.actor,userPermissionLevel:A.userPermissionLevel},D=await hh({context:this.options.context,directorySync:this.options.getDirectorySync(),source:`cms:${A.userId}`,interfaceType:"cms",toolContext:f,gitSync:this.options.getGitSync(),operationStatus:this.options.operationStatus});return{accepted:D.status==="queued",status:D.status,...D.runId?{runId:D.runId}:{},...D.gitPulled?{jobId:D.jobId}:{},...!D.gitPulled&&D.status==="queued"?{batchId:D.batchId}:{}}}};return bq(this.options.context,x)}toSafeGitStatus(x){let B=x.files.slice(0,20).map((w)=>({path:h89(w.path),status:w.status.trim()||"changed"})),A=R89(this.options.config);return{branch:x.branch,...A?{remoteLabel:A}:{},hasChanges:x.hasChanges,ahead:x.ahead,behind:x.behind,...x.lastCommit?{lastCommit:x.lastCommit}:{},changedFiles:B,changedFilesTruncated:x.files.length>B.length}}}function h89(x){let B=x.replaceAll("\\","/").replace(/^\.\//,"");if(B.startsWith("../")||B.startsWith("/"))return"content file";return B.slice(0,300)||"content file"}function R89(x){if(x.git?.repo)return x.git.repo;let B=x.git?.gitUrl;if(!B)return;if(B.startsWith("file:"))return"local remote";try{let A=new URL(B),w=A.pathname.replace(/^\//,"").replace(/\.git$/,"");return w?`${A.hostname}/${w}`:A.hostname}catch{let A=/^(?:[^@]+@)?([^:]+):(.+?)(?:\.git)?$/.exec(B);if(!A?.[1]||!A[2])return"configured remote";return`${A[1]}/${A[2].replace(/\.git$/,"")}`}}class mh{resourceScope;scheduleScope;periodicScope;delayScope;scheduleFibers;periodicFibers;delayedFibers;clock;activeOperations=new Set;activeFailures=[];nextPeriodicId=0;closePromise=null;closed=!1;constructor(x={}){this.resourceScope=H0.runSync(y9.make()),this.scheduleScope=H0.runSync(y9.make()),this.periodicScope=H0.runSync(y9.make()),this.delayScope=H0.runSync(y9.make()),this.scheduleFibers=H0.runSync(y9.extend(_w.make(),this.scheduleScope)),this.periodicFibers=H0.runSync(y9.extend(QB.make(),this.periodicScope)),this.delayedFibers=H0.runSync(y9.extend(QB.make(),this.delayScope)),this.clock=x.clock}async acquire(x,B){if(this.closed)throw Error("Directory sync runtime is closed");let A=H0.acquireRelease(H0.promise(x),(f)=>H0.promise(()=>B(f))),w=await H0.runPromiseExit(y9.extend(A,this.resourceScope));if(f5.isFailure(w))throw _4.squash(w.cause);return w.value}schedulePeriodic(x,B){if(this.closed)return;if(!Number.isFinite(x)||x<=0)throw Error("Periodic interval must be a positive finite number");let A=this.nextPeriodicId++,w=()=>{if(this.closed||QB.unsafeHas(this.periodicFibers,A))return;let $=H0.tryPromise({try:B,catch:(Z)=>Z}).pipe(H0.catchAll((Z)=>H0.sync(()=>{this.activeFailures.push(Z)})));QB.unsafeSet(this.periodicFibers,A,H0.runFork($),{onlyIfMissing:!0})},f=H0.sleep(x).pipe(H0.andThen(H0.sync(w)),H0.forever),D=this.clock?H0.withClock(f,this.clock):f;_w.unsafeAdd(this.scheduleFibers,H0.runFork(D))}scheduleTrailing(x,B,A){if(this.closed)return;let w=H0.sleep(B).pipe(H0.andThen(H0.sync(()=>{this.trackActive(A)}))),f=this.clock?H0.withClock(w,this.clock):w,D=H0.runFork(f);QB.unsafeSet(this.delayedFibers,x,D)}close(){return this.closed=!0,this.closePromise??=this.closeRuntime(),this.closePromise}trackActive(x){if(this.closed)return;let B;try{B=x()}catch(w){B=Promise.reject(w)}let A=B.catch((w)=>{this.activeFailures.push(w)}).finally(()=>{this.activeOperations.delete(A)});this.activeOperations.add(A)}async closeRuntime(){let x=[],B=async(A)=>{try{await A()}catch(w){x.push(w)}};await B(()=>this.closeScope(this.scheduleScope)),await B(()=>this.closeScope(this.periodicScope)),await B(()=>this.closeScope(this.delayScope)),await B(()=>this.closeScope(this.resourceScope));while(this.activeOperations.size>0)await Promise.all([...this.activeOperations]);if(x.push(...this.activeFailures),x.length>0)throw x[0]}async closeScope(x){let B=await H0.runPromiseExit(y9.close(x,f5.void));if(f5.isFailure(B))throw _4.squash(B.cause)}}function xUx(x){return{initialize:()=>x().initialize(),initializeDirectory:()=>x().initializeDirectory(),setJobQueueCallback:(B)=>x().setJobQueueCallback(B),sync:()=>x().sync(),processEntityExport:(B)=>x().processEntityExport(B),exportEntities:(B)=>x().exportEntities(B),importEntitiesWithProgress:(B,A,w)=>x().importEntitiesWithProgress(B,A,w),exportEntitiesWithProgress:(B,A,w)=>x().exportEntitiesWithProgress(B,A,w),importEntities:(B)=>x().importEntities(B),removeOrphanedEntities:()=>x().removeOrphanedEntities(),get fileOps(){return x().fileOps},get shouldDeleteOnFileRemoval(){return x().shouldDeleteOnFileRemoval},getAllMarkdownFiles:()=>x().getAllMarkdownFiles(),ensureDirectoryStructure:()=>x().ensureDirectoryStructure(),getStatus:()=>x().getStatus(),queueSyncBatch:(B,A,w,f)=>x().queueSyncBatch(B,A,w,f),startWatching:()=>x().startWatching(),stopWatching:()=>x().stopWatching(),suppressWatchPaths:(B)=>x().suppressWatchPaths(B),setWatchCallback:(B)=>x().setWatchCallback(B)}}function BUx(x){return{withLock:(B,A)=>x().withLock(B,A),initialize:()=>x().initialize(),hasRemote:()=>x().hasRemote(),getStatus:()=>x().getStatus(),hasLocalChanges:()=>x().hasLocalChanges(),commit:(B)=>x().commit(B),push:(B)=>x().push(B),pull:(B)=>x().pull(B),cleanup:()=>x().cleanup(),log:(B,A)=>x().log(B,A),show:(B,A)=>x().show(B,A)}}var AUx={name:"@brains/directory-sync",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Directory-based entity synchronization plugin for Brains",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",chokidar:"^5.0.0","simple-git":"^3.36.0"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",typescript:"^7.0.2"},exports:{".":{types:"./src/index.ts",import:"./src/index.ts"},"./env-schema":"./src/env-schema.ts"},main:"./src/index.ts",peerDependencies:{},private:!0,scripts:{clean:"rm -rf .turbo",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};class Y60 extends D8{directorySync;gitSync;operationStatus;workspaceProvider;cmsWorkspaceUrl;runtime=new mh;directorySyncFacade=xUx(()=>this.requireDirectorySync());gitSyncFacade=BUx(()=>this.requireGitSync());runtimeScheduler={scheduleTrailing:(x,B,A)=>{this.runtime.scheduleTrailing(x,B,A)}};watcherOwned=!1;gitBackgroundStarted=!1;gitAutoCommitRegistered=!1;readyState=!1;shutdownStarted=!1;configurationQueue=Promise.resolve();constructor(x={}){super("directory-sync",AUx,x,bj)}requireDirectorySync(){if(!this.directorySync)throw Error("DirectorySync service not initialized");return this.directorySync}requireGitSync(){if(!this.gitSync)throw Error("GitSync service not initialized");return this.gitSync}requireOperationStatus(){if(!this.operationStatus)throw Error("Directory sync operation status not initialized");return this.operationStatus}hasGitSync(){return this.gitSync!==void 0}async onRegister(x){x.templates.register({status:{name:"status",description:"Directory synchronization status",schema:Vj,basePrompt:"",formatter:new Ph,requiredPermission:"admin"}});let B=this.config.syncPath??x.dataDir;this.directorySync=this.createDirectorySync(x,B);try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:B})}catch(A){throw this.logger.error("Failed to initialize directory",A),A}if(this.operationStatus=new Q60(x.runtimeState,x.jobs,this.logger.child("OperationStatus"),B),await this.operationStatus.initialize(),this.config.autoSync)$60(x,this.directorySync,B,this.operationStatus);if(await this.registerJobHandlers(x),hVx(x,()=>this.requireDirectorySync(),this.logger,this.config.entityTypes,this.operationStatus),this.config.git&&!this.isGitConfigured())this.logger.debug("Git block present but no repo/gitUrl configured \u2014 git sync disabled");if(this.isGitConfigured())await this.bootstrapContentRemote(),this.gitSync=await this.initializeGitSync(B),x.jobs.registerHandler("sync-request",new Mh(this.logger.child("DirectorySyncRequestJobHandler"),x,()=>this.requireDirectorySync(),()=>this.requireGitSync()));if(this.config.initialSync)gVx(x,()=>this.requireDirectorySync(),this.config,this.logger,this.gitSync?this.gitSyncFacade:void 0);this.workspaceProvider=new X60({context:x,pluginId:this.id,config:this.config,getDirectorySync:()=>this.requireDirectorySync(),getGitSync:()=>this.gitSync,operationStatus:this.operationStatus}),lVx(x,()=>this.requireDirectorySync(),(A)=>this.configure(A),this.logger,this.config.git,()=>this.gitSync,()=>this.cmsWorkspaceUrl)}async onReady(){await this.startBackgroundWork(),this.readyState=!0,this.cmsWorkspaceUrl=await this.workspaceProvider?.registerCmsWorkspace()}async getTools(){return dVx(this.directorySyncFacade,this.getContext(),this.id,this.gitSync?this.gitSyncFacade:void 0,this.operationStatus)}async onShutdown(){this.shutdownStarted=!0,await this.configurationQueue,await this.stopGeneration(this.runtime,this.directorySync,this.gitSync),this.readyState=!1,this.watcherOwned=!1,this.gitBackgroundStarted=!1}getDirectorySync(){return this.directorySync}configure(x){let B=this.configurationQueue.then(()=>this.replaceGeneration(x.syncPath));return this.configurationQueue=B.catch(()=>{}),B}async replaceGeneration(x){if(this.shutdownStarted)throw Error("Directory sync plugin is shutting down");let B=this.getContext(),A=new mh,w=this.createDirectorySync(B,x),f;try{if(await w.initializeDirectory(),this.config.autoSync)$60(B,w,x,this.operationStatus);if(this.isGitConfigured())f=await this.initializeGitSync(x)}catch(Q){throw await this.abandonCandidate(A,w,f),Q}let D=this.runtime,$=this.directorySync,Z=this.gitSync;try{await this.stopGeneration(D,$,Z)}catch(Q){throw await this.abandonCandidate(A,w,f),Q}if(this.runtime=A,this.directorySync=w,this.gitSync=f,this.operationStatus?.setSyncPath(x),this.watcherOwned=!1,this.gitBackgroundStarted=!1,this.readyState)await this.startBackgroundWork();this.logger.info("Directory sync reconfigured",{path:x})}createDirectorySync(x,B){return new Bh({syncPath:B,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:x.entityService,logger:x.logger})}isGitConfigured(){return this.config.git!==void 0&&(this.config.git.repo!==void 0||this.config.git.gitUrl!==void 0)}async bootstrapContentRemote(){let x=this.config.git;if(!x)return;await iVx({gitUrl:x.gitUrl,branch:x.branch,seedContentPath:this.config.seedContentPath,bootstrapFromSeed:x.bootstrapFromSeed,authorName:x.authorName,authorEmail:x.authorEmail,logger:this.logger.child("ContentRemoteBootstrap")})}async initializeGitSync(x){let B=this.config.git;if(!B)throw Error("Git configuration is unavailable");let A=new e90({logger:this.logger.child("GitSync"),dataDir:x,repo:B.repo,gitUrl:B.gitUrl,branch:B.branch,authToken:B.authToken,authorName:B.authorName,authorEmail:B.authorEmail});return await A.initialize(),this.logger.info("Git integration enabled",{repo:B.repo}),A}async startBackgroundWork(){let x=this.requireDirectorySync();if(this.config.autoSync&&!this.watcherOwned)await this.runtime.acquire(()=>x.startWatching(),()=>x.stopWatching()),this.watcherOwned=!0;let B=this.gitSync;if(!B||this.gitBackgroundStarted)return;let A=this.getContext();if(!this.gitAutoCommitRegistered)TVx(A.messaging,()=>this.requireGitSync(),this.config.commitDebounce,this.logger.child("GitAutoCommit"),this.runtimeScheduler,this.operationStatus),this.gitAutoCommitRegistered=!0;if(this.config.autoSync)pVx(B,x,A,this.config.syncInterval,this.logger.child("GitPeriodicSync"),this.runtime,this.operationStatus);this.gitBackgroundStarted=!0}async stopGeneration(x,B,A){let w=[];try{await x.close()}catch(f){w.push(f)}try{await B?.stopWatching()}catch(f){w.push(f)}try{A?.cleanup()}catch(f){w.push(f)}if(w.length>0)throw w[0]}async abandonCandidate(x,B,A){try{await x.close()}catch{}try{await B.stopWatching()}catch{}try{A?.cleanup()}catch{}}async registerJobHandlers(x){OVx(x,this.directorySyncFacade,this.logger,()=>this.requireDirectorySync(),this.requireOperationStatus())}}function W60(x={}){return new Y60(x)}var AZ=X.object({title:X.string(),section:X.string(),order:X.number().int(),sourcePath:X.string(),description:X.string().nullable().default(null),slug:X.string().nullable().default(null)}),wUx=X.object({title:X.string(),section:X.string(),order:X.number().int(),description:X.string().nullable().default(null),slug:X.string()}),Vq=j8.extend({entityType:X.literal("doc"),metadata:wUx}),H60=Vq.extend({frontmatter:AZ,body:X.string()});class F60 extends ox{constructor(){super({entityType:"doc",purpose:"A structured documentation page.",schema:Vq,frontmatterSchema:AZ})}toMarkdown(x){let B=this.extractBody(x.content),A=this.parseFrontMatter(x.content,AZ);return this.buildMarkdown(B,A)}fromMarkdown(x){let B=this.parseFrontMatter(x,AZ),A=B.slug??Gx(B.title);return{content:x,entityType:"doc",metadata:{title:B.title,section:B.section,order:B.order,slug:A,description:B.description}}}}var Ch=new F60;function fUx(x){return[...x].sort((B,A)=>{let w=B.metadata.order-A.metadata.order;if(w!==0)return w;return B.metadata.title.localeCompare(A.metadata.title)})}function DUx(x){let B=G9(x.content,AZ);return H60.parse({...x,frontmatter:B.metadata,body:B.content})}class ch extends j7{id="docs:entities";name="Docs Entity DataSource";description="Fetches and transforms doc entities for rendering";config={entityType:"doc",defaultSort:[{field:"order",direction:"asc"},{field:"section",direction:"asc"},{field:"title",direction:"asc"}],defaultLimit:100,enableNavigation:!0};constructor(x){super(x)}transformEntity(x){return DUx(x)}async fetch(x,B,A){let w=this.parseQuery(x);if(!w.query.id){let W=await this.fetchList({...w.query,limit:1000,page:void 0,pageSize:void 0},A.entityService);return B.parse(this.buildListResult(W.items,null,w.query))}let[f,D]=await Promise.all([this.fetchDetail(w.query.id,A.entityService),this.fetchList({limit:1000},A.entityService)]),$=fUx(D.items),Z=$.findIndex((W)=>W.id===f.item.id),Q=Z>0?$[Z-1]:null,Y=Z>=0&&Z<$.length-1?$[Z+1]:null;return B.parse({doc:f.item,docs:$,prevDoc:Q,nextDoc:Y})}buildDetailResult(x,B){return{doc:x,docs:[x],prevDoc:B?.prev??null,nextDoc:B?.next??null}}buildListResult(x,B,A){return{docs:fUx(x),pagination:B,baseUrl:A.baseUrl??null}}}import{jsxDEV as P5}from"preact/jsx-dev-runtime";var m89=["I","II","III","IV","V","VI","VII","VIII","IX","X"];function Uj(x){return[...x].sort((B,A)=>{let w=B.metadata.order-A.metadata.order;if(w!==0)return w;return B.metadata.title.localeCompare(A.metadata.title)})}function gh(x){let B=new Map;for(let A of Uj(x)){let w=A.metadata.section;B.set(w,[...B.get(w)??[],A])}return[...B.entries()].map(([A,w])=>({section:A,docs:w}))}function Uq(x){return`/docs/${x.metadata.slug}`}function Th(x){return`section-${x+1}`}function Gq(x){return m89[x]??String(x+1)}var QUx="text-[var(--docs-text)] font-bold",XUx="text-[var(--docs-accent)] font-bold",YUx="text-[var(--docs-text-muted)]",C89="docs-font-label text-xs uppercase tracking-[0.18em] text-[var(--docs-accent)]",c89="docs-font-display text-[var(--docs-heading)]",$Ux="inline-flex items-center justify-center rounded-lg border px-[18px] py-2.5 text-sm font-semibold transition-colors duration-150",ZUx="relative hidden py-1 text-[15px] text-[var(--docs-text-muted)] transition-colors duration-150 after:absolute after:bottom-0 after:left-0 after:h-px after:w-0 after:bg-[var(--docs-accent)] after:transition-[width] after:duration-300 hover:text-[var(--docs-text)] hover:after:w-full min-[861px]:inline-block",K60="docs-font-label text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:text-[var(--docs-text)]",dA={wrap:"mx-auto max-w-6xl px-6 pt-20 md:px-12 md:pt-24",label:C89,display:c89,button:`${$Ux} border-[var(--docs-text)] text-[var(--docs-text)] hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)]`,primaryButton:`${$Ux} border-[var(--docs-accent)] bg-[var(--docs-accent)] text-white hover:bg-transparent hover:text-[var(--docs-accent)]`},WUx=()=>P5("nav",{className:"docs-header fixed inset-x-0 top-0 z-[100] flex items-center justify-between px-6 py-4 md:px-10 md:py-5 xl:px-20",children:[P5("a",{href:"/docs",className:"docs-font-body text-xl font-bold","aria-label":"Brains docs",children:[P5("span",{className:QUx,children:"brains"},void 0,!1,void 0,this),P5("span",{className:XUx,children:"."},void 0,!1,void 0,this),P5("span",{className:YUx,children:"docs"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P5("div",{className:"docs-header__nav flex items-center gap-4 md:gap-8",children:[P5("a",{className:ZUx,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),P5("a",{className:ZUx,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),P5("a",{href:"https://rizom.ai",className:"inline-flex items-center justify-center rounded-lg border border-[var(--docs-text)] px-4 py-2 text-[13px] font-semibold text-[var(--docs-text)] transition-colors duration-150 hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)] md:px-6 md:py-2.5 md:text-[15px]",children:"Get Brains"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),HUx=()=>P5("footer",{className:"flex flex-col items-center justify-between gap-4 border-t border-[var(--docs-border-light)] py-8 text-center md:flex-row md:gap-6 md:py-6 md:text-left",children:[P5("a",{href:"https://rizom.ai",className:"docs-font-body text-[15px] font-bold",children:[P5("span",{className:QUx,children:"rizom"},void 0,!1,void 0,this),P5("span",{className:XUx,children:"."},void 0,!1,void 0,this),P5("span",{className:YUx,children:"ai"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P5("div",{className:"flex flex-wrap items-center justify-center gap-6 md:justify-end",children:[P5("a",{className:K60,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),P5("a",{className:K60,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),P5("a",{className:K60,href:"https://rizom.ai",children:"Rizom"},void 0,!1,void 0,this),P5("button",{id:"themeToggle",className:"docs-font-label cursor-pointer rounded-md border border-[var(--docs-text-light)] bg-transparent px-2.5 py-1.5 text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:border-[var(--docs-text)] hover:text-[var(--docs-text)]",type:"button",children:"\u2600 Light"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),g89=`
5465
5465
  .docs-handbook {
5466
5466
  --docs-bg: var(--color-bg, #0d0a1a);
5467
5467
  --docs-bg-card: var(--color-bg-card, #1a0a3e);
@@ -5613,14 +5613,14 @@ facts, owners, or tasks. Return only the required structured JSON.`});var xs8=X.
5613
5613
  background: transparent;
5614
5614
  }
5615
5615
 
5616
- `,FUx=()=>P5("style",{children:g89},void 0,!1,void 0,this);import{jsxDEV as _x,Fragment as T89}from"preact/jsx-dev-runtime";var ph=({title:x,description:B,children:A,detail:w=!1,footer:f=!1,contentClassName:D=""})=>_x(T89,{children:[_x(z9,{title:x,description:B},void 0,!1,void 0,this),_x(FUx,{},void 0,!1,void 0,this),_x("div",{className:`docs-handbook${w?" docs-handbook--detail":""}`,children:[_x(WUx,{},void 0,!1,void 0,this),_x("div",{className:`${dA.wrap} ${D}`.trim(),children:[A,f&&_x(HUx,{},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),KUx=({docsCount:x,sectionsCount:B,startDoc:A})=>_x("section",{className:"border-b border-[var(--docs-text)] py-14 md:py-24 md:pb-[72px]",children:[_x("p",{className:`${dA.label} mb-8`,children:"Handbook \xB7 Brains docs"},void 0,!1,void 0,this),_x("h1",{className:`${dA.display} m-0 max-w-[16ch] text-5xl leading-[1.05] tracking-[-0.02em] md:text-7xl`,children:["Build, run, and publish"," ",_x("em",{className:"text-[var(--docs-accent)]",children:"brains."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),_x("p",{className:"mt-8 max-w-[52ch] text-lg leading-[1.65] text-[var(--docs-text-muted)]",children:"Documentation for composing brain models, managing markdown entities, wiring interfaces, and shipping generated sites."},void 0,!1,void 0,this),_x("dl",{className:"mt-10 flex flex-wrap gap-7 docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] md:mt-14 md:gap-12",children:[_x("div",{children:[_x("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:x},void 0,!1,void 0,this),"Documents"]},void 0,!0,void 0,this),_x("div",{children:[_x("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:B},void 0,!1,void 0,this),"Sections"]},void 0,!0,void 0,this),_x("div",{children:[_x("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:"April 2026"},void 0,!1,void 0,this),"Updated"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),_x("div",{className:"mt-9 flex flex-wrap gap-3.5",children:[A&&_x("a",{className:dA.primaryButton,href:Uq(A),children:"Start reading"},void 0,!1,void 0,this),_x("a",{className:dA.button,href:"#sections",children:"Browse sections"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),qUx=({groups:x})=>_x("aside",{className:"docs-rail sticky top-8 hidden docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] min-[861px]:block","aria-label":"Documentation sections",children:[_x("p",{className:"m-0 mb-3.5 font-medium text-[var(--docs-text)]",children:"Sections"},void 0,!1,void 0,this),_x("ol",{className:"m-0 list-none p-0",children:x.map((B,A)=>_x("li",{className:"grid grid-cols-[32px_1fr] gap-2 py-1.5",children:[_x("span",{className:"docs-font-display text-[var(--docs-text-light)] italic",children:[Gq(A),"."]},void 0,!0,void 0,this),_x("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:`#${Th(A)}`,children:B.section},void 0,!1,void 0,this)]},B.section,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),zUx=({group:x,index:B})=>_x("article",{className:"mb-16 last:mb-0",id:Th(B),children:[_x("header",{className:"mb-2 grid grid-cols-[36px_auto_1fr] items-baseline gap-x-3 border-b border-[var(--docs-border)] pb-3.5 md:grid-cols-[48px_auto_1fr] md:gap-x-5",children:[_x("span",{className:"text-right docs-font-display text-3xl leading-[1.1] text-[var(--docs-accent)] italic md:text-4xl",children:[Gq(B),"."]},void 0,!0,void 0,this),_x("h2",{className:`${dA.display} m-0 text-3xl leading-[1.1] tracking-[-0.015em] md:text-4xl`,children:x.section},void 0,!1,void 0,this),_x("span",{className:"docs-chapter__leader"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),_x("ol",{className:"m-0 list-none p-0",children:x.docs.map((A)=>_x("li",{className:"border-b border-[var(--docs-border-light)] last:border-b-0",children:_x("a",{className:"group block py-[18px] pl-12 md:pl-[68px]",href:Uq(A),children:[_x("p",{className:"m-0 text-[22px] leading-[1.2] tracking-[-0.005em] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:A.metadata.title},void 0,!1,void 0,this),A.metadata.description&&_x("p",{className:"mt-1.5 mb-0 max-w-[70ch] text-sm leading-[1.55] text-[var(--docs-text-muted)]",children:A.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},A.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),bUx=({title:x})=>_x("nav",{className:"mb-8 flex flex-wrap items-baseline gap-2.5 docs-font-label text-[11px] uppercase tracking-[0.06em] text-[var(--docs-text-light)]","aria-label":"Breadcrumb",children:[_x("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/",children:"Home"},void 0,!1,void 0,this),_x("span",{children:"/"},void 0,!1,void 0,this),_x("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/docs",children:"Docs"},void 0,!1,void 0,this),_x("span",{children:"/"},void 0,!1,void 0,this),_x("span",{children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this),VUx=({groups:x,activeGroupIndex:B,activeSlug:A})=>_x("aside",{className:"docs-detail-rail sticky top-24 hidden max-h-[calc(100vh-120px)] overflow-auto pr-2 min-[861px]:block","aria-label":"Documentation navigation",children:_x("nav",{className:"docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)]",children:[_x("p",{className:"m-0 mb-4 border-b border-[var(--docs-text)] pb-3 text-[11px] uppercase tracking-[0.08em] text-[var(--docs-text-light)]",children:"Documentation"},void 0,!1,void 0,this),_x("ol",{className:"m-0 list-none p-0",children:x.map((w,f)=>{let D=f===B;return _x("li",{className:D?"mb-[22px]":"mb-3.5",children:[_x("a",{className:`mb-2 flex items-baseline gap-2.5 docs-font-label text-[11px] uppercase leading-[1.4] tracking-[0.06em] transition-colors duration-150 hover:text-[var(--docs-text)] ${D?"text-[var(--docs-text)]":"text-[var(--docs-text-muted)]"}`,href:`/docs#${Th(f)}`,children:[_x("span",{className:"docs-font-display text-sm text-[var(--docs-accent)] italic",children:[Gq(f),"."]},void 0,!0,void 0,this)," ",w.section]},void 0,!0,void 0,this),D&&_x("ol",{className:"mt-0.5 list-none p-0",children:w.docs.map(($)=>{let Z=$.metadata.slug===A;return _x("li",{children:_x("a",{className:`docs-rail__doc relative block py-1.5 docs-font-body text-sm leading-[1.4] tracking-normal transition-[color,padding-left] duration-150 hover:text-[var(--docs-text)] ${Z?"pl-3.5 font-medium text-[var(--docs-accent)]":"text-[var(--docs-text-muted)]"}`,href:Uq($),"aria-current":Z?"page":void 0,children:$.metadata.title},void 0,!1,void 0,this)},$.id,!1,void 0,this)})},void 0,!1,void 0,this)]},w.section,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),UUx=({prevDoc:x,nextDoc:B})=>{if(!x&&!B)return null;return _x("nav",{className:"mt-12 grid grid-cols-1 gap-5 border-t border-[var(--docs-border)] pt-7 md:grid-cols-2","aria-label":"Previous and next docs",children:[x?_x("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] transition-colors duration-150 hover:border-[var(--docs-accent)]",href:Uq(x),children:[_x("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Previous"},void 0,!1,void 0,this),_x("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:["\u2190 ",x.metadata.title]},void 0,!0,void 0,this)]},void 0,!0,void 0,this):_x("span",{},void 0,!1,void 0,this),B&&_x("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] text-left transition-colors duration-150 hover:border-[var(--docs-accent)] md:text-right",href:Uq(B),children:[_x("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Next"},void 0,!1,void 0,this),_x("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:[B.metadata.title," \u2192"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as Eq}from"preact/jsx-dev-runtime";var q60=({docs:x})=>{let B=Uj(x),A=gh(B),f=B.filter((D)=>D.metadata.slug!=="index")[0]??B[0];return Eq(ph,{title:"Documentation",description:"Brains documentation",children:[Eq(KUx,{docsCount:x.length,sectionsCount:A.length,startDoc:f},void 0,!1,void 0,this),Eq("section",{className:"grid items-start gap-10 py-12 md:grid-cols-[200px_minmax(0,1fr)] md:gap-20 md:py-20 md:pb-[120px]",id:"sections",children:[Eq(qUx,{groups:A},void 0,!1,void 0,this),Eq("div",{children:A.map((D,$)=>Eq(zUx,{group:D,index:$},D.section,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as I2}from"preact/jsx-dev-runtime";var z60=({doc:x,docs:B,prevDoc:A,nextDoc:w})=>{let f=gh(B.length>0?B:[x]),D=Uj(B.length>0?B:[x]),$=D.findIndex((Q)=>Q.metadata.slug===x.metadata.slug),Z=Math.max(f.findIndex((Q)=>Q.docs.some((Y)=>Y.metadata.slug===x.metadata.slug)),0);return I2(ph,{title:x.metadata.title,description:x.metadata.description??x.metadata.section,detail:!0,footer:!0,contentClassName:"pt-16",children:[I2(bUx,{title:x.metadata.title},void 0,!1,void 0,this),I2("div",{className:"grid items-start gap-10 py-8 pb-24 md:grid-cols-[240px_minmax(0,1fr)] md:gap-20",children:[I2(VUx,{groups:f,activeGroupIndex:Z,activeSlug:x.metadata.slug},void 0,!1,void 0,this),I2("article",{className:"min-w-0",children:[I2("header",{className:"mb-10 border-b border-[var(--docs-border)] pb-8",children:[I2("p",{className:`${dA.label} m-0 mb-6 flex items-baseline gap-3`,children:[I2("span",{className:"docs-font-display text-lg leading-none tracking-normal normal-case text-[var(--docs-accent)] italic",children:[Gq(Z),"."]},void 0,!0,void 0,this)," ",x.metadata.section,$>=0?` \xB7 ${$+1}/${D.length}`:""]},void 0,!0,void 0,this),I2("h1",{className:`${dA.display} m-0 max-w-[18ch] text-4xl leading-[1.05] tracking-[-0.02em] md:text-6xl`,children:x.metadata.title},void 0,!1,void 0,this),x.metadata.description&&I2("p",{className:"mt-6 max-w-[56ch] docs-font-display text-[22px] font-[350] leading-[1.5] text-[var(--docs-text-muted)]",children:x.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I2("div",{className:"docs-article__body",children:I2(cB,{markdown:x.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),I2(UUx,{prevDoc:A,nextDoc:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};var p89=X.object({title:X.string(),section:X.string(),order:X.number().int(),sourcePath:X.string(),description:X.string().nullable().default(null),slug:X.string().nullable().default(null)}),u89=X.object({title:X.string(),section:X.string(),order:X.number().int(),description:X.string().nullable().default(null),slug:X.string()}),Gj=X.object({id:X.string(),entityType:X.literal("doc"),content:X.string(),created:X.string(),updated:X.string(),visibility:Z2,metadata:u89,contentHash:X.string(),frontmatter:p89,body:X.string()}),S89=X.object({docs:X.array(Gj),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null)}),i89=X.object({doc:Gj,docs:X.array(Gj),prevDoc:Gj.nullable(),nextDoc:Gj.nullable()});function GUx(){return{"doc-list":mx({name:"doc-list",description:"Documentation index template",schema:S89,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:q60}}),"doc-detail":mx({name:"doc-detail",description:"Documentation page template",schema:i89,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:z60}})}}var EUx={name:"@brains/doc",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Documentation entity type \u2014 markdown docs as first-class brain content",dependencies:{"@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class b60 extends g8{entityType=Ch.entityType;schema=Vq;adapter=Ch;constructor(){super("docs",EUx,{},qB)}getEntityTypeConfig(){return{projectionSourceRole:"primary"}}getTemplates(){return GUx()}getDataSources(){return[new ch(this.logger.child("DocDataSource"))]}}function V60(){return new b60}var U60=X.literal("application/pdf"),jUx=X.enum(["pending","draft","failed"]),G60=X.object({title:X.string().optional(),mimeType:U60,filename:X.string().min(1),pageCount:X.number().int().min(0).optional(),status:jUx.optional(),processingJobId:X.string().optional(),processingError:X.string().optional(),sourceEntityType:X.string().min(1).optional(),sourceEntityId:X.string().min(1).optional(),sourceUploadId:X.string().optional(),sourceFilename:X.string().optional(),sourceMediaType:X.string().optional(),attachmentType:X.string().min(1).optional(),dedupKey:X.string().min(1).optional()}),jq=j8.extend({entityType:X.literal("document"),content:X.string().regex(/^data:application\/pdf;base64,.+$/),metadata:G60});function Ej(x){let B=x.match(/^data:(application\/pdf);base64,(.+)$/i);if(!B?.[1]||!B[2])throw Error("Invalid PDF document data URL");return{mimeType:"application/pdf",base64:B[2]}}function uh(x){return`data:application/pdf;base64,${Buffer.from(x).toString("base64")}`}function E60(x){let B=Buffer.from(x).toString("latin1"),A=0,w=/\/Type\s*\/Pages\b[^]*?\/Count\s+(\d+)|\/Count\s+(\d+)[^]*?\/Type\s*\/Pages\b/g;for(let D of B.matchAll(w)){let $=parseInt(D[1]??D[2]??"0",10);if($>A)A=$}if(A>0)return A;return B.match(/\/Type\s*\/Page(?!\w)/g)?.length??0}class Sh{entityType="document";purpose="A durable rendered file artifact such as a printable or carousel PDF.";schema=jq;toMarkdown(x){return x.content}fromMarkdown(x){return Ej(x),{entityType:"document",content:x}}extractMetadata(x){return x.metadata}parseFrontMatter(x,B){return B.parse({})}generateFrontMatter(x){return""}getBodyTemplate(){return""}createDocumentEntity(x){let{dataUrl:B,...A}=x,{mimeType:w}=Ej(B);return{entityType:"document",content:B,metadata:{mimeType:w,...A}}}}var vf=new Sh;async function j60(x,B={}){let A=B.maxBytes??5000000;if(x.byteLength>A)throw Error(`Uploaded PDF is too large for synchronous markdown extraction (${x.byteLength} bytes; max ${A} bytes)`);let f=(await import("./chunks/pdf-78qb824z.js")).getDocument({data:new Uint8Array(x),disableFontFace:!1,useSystemFonts:!0,useWorkerFetch:!1}),D=await f.promise;try{let $=B.maxPages??50;if(D.numPages>$)throw Error(`Uploaded PDF has ${D.numPages} pages; maximum supported for synchronous markdown extraction is ${$}`);let Z=[];for(let Y=1;Y<=D.numPages;Y+=1){let F=(await(await D.getPage(Y)).getTextContent()).items.flatMap((K)=>("str"in K)?[K.str]:[]).join(" ").replace(/\s+/g," ").trim();if(F.length>0)Z.push(F)}let Q=Z.join(`
5616
+ `,FUx=()=>P5("style",{children:g89},void 0,!1,void 0,this);import{jsxDEV as _x,Fragment as T89}from"preact/jsx-dev-runtime";var ph=({title:x,description:B,children:A,detail:w=!1,footer:f=!1,contentClassName:D=""})=>_x(T89,{children:[_x(z9,{title:x,description:B},void 0,!1,void 0,this),_x(FUx,{},void 0,!1,void 0,this),_x("div",{className:`docs-handbook${w?" docs-handbook--detail":""}`,children:[_x(WUx,{},void 0,!1,void 0,this),_x("div",{className:`${dA.wrap} ${D}`.trim(),children:[A,f&&_x(HUx,{},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),KUx=({docsCount:x,sectionsCount:B,startDoc:A})=>_x("section",{className:"border-b border-[var(--docs-text)] py-14 md:py-24 md:pb-[72px]",children:[_x("p",{className:`${dA.label} mb-8`,children:"Handbook \xB7 Brains docs"},void 0,!1,void 0,this),_x("h1",{className:`${dA.display} m-0 max-w-[16ch] text-5xl leading-[1.05] tracking-[-0.02em] md:text-7xl`,children:["Build, run, and publish"," ",_x("em",{className:"text-[var(--docs-accent)]",children:"brains."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),_x("p",{className:"mt-8 max-w-[52ch] text-lg leading-[1.65] text-[var(--docs-text-muted)]",children:"Documentation for composing brain models, managing markdown entities, wiring interfaces, and shipping generated sites."},void 0,!1,void 0,this),_x("dl",{className:"mt-10 flex flex-wrap gap-7 docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] md:mt-14 md:gap-12",children:[_x("div",{children:[_x("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:x},void 0,!1,void 0,this),"Documents"]},void 0,!0,void 0,this),_x("div",{children:[_x("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:B},void 0,!1,void 0,this),"Sections"]},void 0,!0,void 0,this),_x("div",{children:[_x("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:"April 2026"},void 0,!1,void 0,this),"Updated"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),_x("div",{className:"mt-9 flex flex-wrap gap-3.5",children:[A&&_x("a",{className:dA.primaryButton,href:Uq(A),children:"Start reading"},void 0,!1,void 0,this),_x("a",{className:dA.button,href:"#sections",children:"Browse sections"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),qUx=({groups:x})=>_x("aside",{className:"docs-rail sticky top-8 hidden docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] min-[861px]:block","aria-label":"Documentation sections",children:[_x("p",{className:"m-0 mb-3.5 font-medium text-[var(--docs-text)]",children:"Sections"},void 0,!1,void 0,this),_x("ol",{className:"m-0 list-none p-0",children:x.map((B,A)=>_x("li",{className:"grid grid-cols-[32px_1fr] gap-2 py-1.5",children:[_x("span",{className:"docs-font-display text-[var(--docs-text-light)] italic",children:[Gq(A),"."]},void 0,!0,void 0,this),_x("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:`#${Th(A)}`,children:B.section},void 0,!1,void 0,this)]},B.section,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),zUx=({group:x,index:B})=>_x("article",{className:"mb-16 last:mb-0",id:Th(B),children:[_x("header",{className:"mb-2 grid grid-cols-[36px_auto_1fr] items-baseline gap-x-3 border-b border-[var(--docs-border)] pb-3.5 md:grid-cols-[48px_auto_1fr] md:gap-x-5",children:[_x("span",{className:"text-right docs-font-display text-3xl leading-[1.1] text-[var(--docs-accent)] italic md:text-4xl",children:[Gq(B),"."]},void 0,!0,void 0,this),_x("h2",{className:`${dA.display} m-0 text-3xl leading-[1.1] tracking-[-0.015em] md:text-4xl`,children:x.section},void 0,!1,void 0,this),_x("span",{className:"docs-chapter__leader"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),_x("ol",{className:"m-0 list-none p-0",children:x.docs.map((A)=>_x("li",{className:"border-b border-[var(--docs-border-light)] last:border-b-0",children:_x("a",{className:"group block py-[18px] pl-12 md:pl-[68px]",href:Uq(A),children:[_x("p",{className:"m-0 text-[22px] leading-[1.2] tracking-[-0.005em] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:A.metadata.title},void 0,!1,void 0,this),A.metadata.description&&_x("p",{className:"mt-1.5 mb-0 max-w-[70ch] text-sm leading-[1.55] text-[var(--docs-text-muted)]",children:A.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},A.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),bUx=({title:x})=>_x("nav",{className:"mb-8 flex flex-wrap items-baseline gap-2.5 docs-font-label text-[11px] uppercase tracking-[0.06em] text-[var(--docs-text-light)]","aria-label":"Breadcrumb",children:[_x("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/",children:"Home"},void 0,!1,void 0,this),_x("span",{children:"/"},void 0,!1,void 0,this),_x("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/docs",children:"Docs"},void 0,!1,void 0,this),_x("span",{children:"/"},void 0,!1,void 0,this),_x("span",{children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this),VUx=({groups:x,activeGroupIndex:B,activeSlug:A})=>_x("aside",{className:"docs-detail-rail sticky top-24 hidden max-h-[calc(100vh-120px)] overflow-auto pr-2 min-[861px]:block","aria-label":"Documentation navigation",children:_x("nav",{className:"docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)]",children:[_x("p",{className:"m-0 mb-4 border-b border-[var(--docs-text)] pb-3 text-[11px] uppercase tracking-[0.08em] text-[var(--docs-text-light)]",children:"Documentation"},void 0,!1,void 0,this),_x("ol",{className:"m-0 list-none p-0",children:x.map((w,f)=>{let D=f===B;return _x("li",{className:D?"mb-[22px]":"mb-3.5",children:[_x("a",{className:`mb-2 flex items-baseline gap-2.5 docs-font-label text-[11px] uppercase leading-[1.4] tracking-[0.06em] transition-colors duration-150 hover:text-[var(--docs-text)] ${D?"text-[var(--docs-text)]":"text-[var(--docs-text-muted)]"}`,href:`/docs#${Th(f)}`,children:[_x("span",{className:"docs-font-display text-sm text-[var(--docs-accent)] italic",children:[Gq(f),"."]},void 0,!0,void 0,this)," ",w.section]},void 0,!0,void 0,this),D&&_x("ol",{className:"mt-0.5 list-none p-0",children:w.docs.map(($)=>{let Z=$.metadata.slug===A;return _x("li",{children:_x("a",{className:`docs-rail__doc relative block py-1.5 docs-font-body text-sm leading-[1.4] tracking-normal transition-[color,padding-left] duration-150 hover:text-[var(--docs-text)] ${Z?"pl-3.5 font-medium text-[var(--docs-accent)]":"text-[var(--docs-text-muted)]"}`,href:Uq($),"aria-current":Z?"page":void 0,children:$.metadata.title},void 0,!1,void 0,this)},$.id,!1,void 0,this)})},void 0,!1,void 0,this)]},w.section,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),UUx=({prevDoc:x,nextDoc:B})=>{if(!x&&!B)return null;return _x("nav",{className:"mt-12 grid grid-cols-1 gap-5 border-t border-[var(--docs-border)] pt-7 md:grid-cols-2","aria-label":"Previous and next docs",children:[x?_x("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] transition-colors duration-150 hover:border-[var(--docs-accent)]",href:Uq(x),children:[_x("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Previous"},void 0,!1,void 0,this),_x("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:["\u2190 ",x.metadata.title]},void 0,!0,void 0,this)]},void 0,!0,void 0,this):_x("span",{},void 0,!1,void 0,this),B&&_x("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] text-left transition-colors duration-150 hover:border-[var(--docs-accent)] md:text-right",href:Uq(B),children:[_x("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Next"},void 0,!1,void 0,this),_x("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:[B.metadata.title," \u2192"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as Eq}from"preact/jsx-dev-runtime";var q60=({docs:x})=>{let B=Uj(x),A=gh(B),f=B.filter((D)=>D.metadata.slug!=="index")[0]??B[0];return Eq(ph,{title:"Documentation",description:"Brains documentation",children:[Eq(KUx,{docsCount:x.length,sectionsCount:A.length,startDoc:f},void 0,!1,void 0,this),Eq("section",{className:"grid items-start gap-10 py-12 md:grid-cols-[200px_minmax(0,1fr)] md:gap-20 md:py-20 md:pb-[120px]",id:"sections",children:[Eq(qUx,{groups:A},void 0,!1,void 0,this),Eq("div",{children:A.map((D,$)=>Eq(zUx,{group:D,index:$},D.section,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as I2}from"preact/jsx-dev-runtime";var z60=({doc:x,docs:B,prevDoc:A,nextDoc:w})=>{let f=gh(B.length>0?B:[x]),D=Uj(B.length>0?B:[x]),$=D.findIndex((Q)=>Q.metadata.slug===x.metadata.slug),Z=Math.max(f.findIndex((Q)=>Q.docs.some((Y)=>Y.metadata.slug===x.metadata.slug)),0);return I2(ph,{title:x.metadata.title,description:x.metadata.description??x.metadata.section,detail:!0,footer:!0,contentClassName:"pt-16",children:[I2(bUx,{title:x.metadata.title},void 0,!1,void 0,this),I2("div",{className:"grid items-start gap-10 py-8 pb-24 md:grid-cols-[240px_minmax(0,1fr)] md:gap-20",children:[I2(VUx,{groups:f,activeGroupIndex:Z,activeSlug:x.metadata.slug},void 0,!1,void 0,this),I2("article",{className:"min-w-0",children:[I2("header",{className:"mb-10 border-b border-[var(--docs-border)] pb-8",children:[I2("p",{className:`${dA.label} m-0 mb-6 flex items-baseline gap-3`,children:[I2("span",{className:"docs-font-display text-lg leading-none tracking-normal normal-case text-[var(--docs-accent)] italic",children:[Gq(Z),"."]},void 0,!0,void 0,this)," ",x.metadata.section,$>=0?` \xB7 ${$+1}/${D.length}`:""]},void 0,!0,void 0,this),I2("h1",{className:`${dA.display} m-0 max-w-[18ch] text-4xl leading-[1.05] tracking-[-0.02em] md:text-6xl`,children:x.metadata.title},void 0,!1,void 0,this),x.metadata.description&&I2("p",{className:"mt-6 max-w-[56ch] docs-font-display text-[22px] font-[350] leading-[1.5] text-[var(--docs-text-muted)]",children:x.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I2("div",{className:"docs-article__body",children:I2(cB,{markdown:x.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),I2(UUx,{prevDoc:A,nextDoc:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};var p89=X.object({title:X.string(),section:X.string(),order:X.number().int(),sourcePath:X.string(),description:X.string().nullable().default(null),slug:X.string().nullable().default(null)}),u89=X.object({title:X.string(),section:X.string(),order:X.number().int(),description:X.string().nullable().default(null),slug:X.string()}),Gj=X.object({id:X.string(),entityType:X.literal("doc"),content:X.string(),created:X.string(),updated:X.string(),visibility:Z2,metadata:u89,contentHash:X.string(),frontmatter:p89,body:X.string()}),S89=X.object({docs:X.array(Gj),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null)}),i89=X.object({doc:Gj,docs:X.array(Gj),prevDoc:Gj.nullable(),nextDoc:Gj.nullable()});function GUx(){return{"doc-list":mx({name:"doc-list",description:"Documentation index template",schema:S89,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:q60}}),"doc-detail":mx({name:"doc-detail",description:"Documentation page template",schema:i89,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:z60}})}}var EUx={name:"@brains/doc",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Documentation entity type \u2014 markdown docs as first-class brain content",dependencies:{"@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class b60 extends g8{entityType=Ch.entityType;schema=Vq;adapter=Ch;constructor(){super("docs",EUx,{},qB)}getEntityTypeConfig(){return{projectionSourceRole:"primary"}}getTemplates(){return GUx()}getDataSources(){return[new ch(this.logger.child("DocDataSource"))]}}function V60(){return new b60}var U60=X.literal("application/pdf"),jUx=X.enum(["pending","draft","failed"]),G60=X.object({title:X.string().optional(),mimeType:U60,filename:X.string().min(1),pageCount:X.number().int().min(0).optional(),status:jUx.optional(),processingJobId:X.string().optional(),processingError:X.string().optional(),sourceEntityType:X.string().min(1).optional(),sourceEntityId:X.string().min(1).optional(),sourceUploadId:X.string().optional(),sourceFilename:X.string().optional(),sourceMediaType:X.string().optional(),attachmentType:X.string().min(1).optional(),dedupKey:X.string().min(1).optional()}),jq=j8.extend({entityType:X.literal("document"),content:X.string().regex(/^data:application\/pdf;base64,.+$/),metadata:G60});function Ej(x){let B=x.match(/^data:(application\/pdf);base64,(.+)$/i);if(!B?.[1]||!B[2])throw Error("Invalid PDF document data URL");return{mimeType:"application/pdf",base64:B[2]}}function uh(x){return`data:application/pdf;base64,${Buffer.from(x).toString("base64")}`}function E60(x){let B=Buffer.from(x).toString("latin1"),A=0,w=/\/Type\s*\/Pages\b[^]*?\/Count\s+(\d+)|\/Count\s+(\d+)[^]*?\/Type\s*\/Pages\b/g;for(let D of B.matchAll(w)){let $=parseInt(D[1]??D[2]??"0",10);if($>A)A=$}if(A>0)return A;return B.match(/\/Type\s*\/Page(?!\w)/g)?.length??0}class Sh{entityType="document";purpose="A durable rendered file artifact such as a printable or carousel PDF.";schema=jq;toMarkdown(x){return x.content}fromMarkdown(x){return Ej(x),{entityType:"document",content:x}}extractMetadata(x){return x.metadata}parseFrontMatter(x,B){return B.parse({})}generateFrontMatter(x){return""}getBodyTemplate(){return""}createDocumentEntity(x){let{dataUrl:B,...A}=x,{mimeType:w}=Ej(B);return{entityType:"document",content:B,metadata:{mimeType:w,...A}}}}var vf=new Sh;async function j60(x,B={}){let A=B.maxBytes??5000000;if(x.byteLength>A)throw Error(`Uploaded PDF is too large for synchronous markdown extraction (${x.byteLength} bytes; max ${A} bytes)`);let f=(await import("./chunks/pdf-78qb824z.js")).getDocument({data:new Uint8Array(x),disableFontFace:!1,useSystemFonts:!0,useWorkerFetch:!1}),D=await f.promise;try{let $=B.maxPages??50;if(D.numPages>$)throw Error(`Uploaded PDF has ${D.numPages} pages; maximum supported for synchronous markdown extraction is ${$}`);let Z=[];for(let Y=1;Y<=D.numPages;Y+=1){let F=(await(await D.getPage(Y)).getTextContent()).items.flatMap((K)=>("str"in K)?[K.str]:[]).join(" ").replace(/\s+/g," ").trim();if(F.length>0)Z.push(F)}let Q=Z.join(`
5617
5617
 
5618
- `).trim();if(!Q)throw Error("Could not extract text from the uploaded PDF");return Q}finally{await f.destroy()}}import{createHash as d89}from"crypto";var a89=26214400,s89=20,r89=60000,_Ux=80,o89=10,t89={renderUrl:X.url().optional(),sourceEntityType:X.string().min(1),sourceEntityId:X.string().min(1),attachmentType:X.string().min(1),documentId:X.string().min(1).optional(),title:X.string().min(1).optional(),filename:X.string().min(1).optional(),dedupKey:X.string().min(1).optional(),replace:X.boolean().optional(),pageCount:X.number().int().min(0).optional(),maxPageCount:X.number().int().positive().optional(),maxBytes:X.number().int().positive().optional(),timeoutMs:X.number().int().positive().optional(),width:X.union([X.string(),X.number()]).optional(),height:X.union([X.string(),X.number()]).optional(),format:X.string().optional(),targetEntityType:X.string().min(1).optional(),targetEntityId:X.string().min(1).optional()},LUx=X.object(t89),ih=LUx.refine((x)=>x.targetEntityType===void 0&&x.targetEntityId===void 0||x.targetEntityType!==void 0&&x.targetEntityId!==void 0,{message:"targetEntityType and targetEntityId must be provided together",path:["targetEntityId"]});class lh extends $9{context;renderPdf;constructor(x,B,A={}){super(x,{schema:ih,jobTypeName:"document-generate"});this.context=B,this.renderPdf=A.renderPdf??JUx}async getDedupKey(x){if(x.dedupKey!==void 0)return x.dedupKey;if(x.renderUrl!==void 0)return`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:${x.renderUrl}`;let B=`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:resolved-attachment`,A=await this.context.entityService.getEntity({entityType:x.sourceEntityType,id:x.sourceEntityId});return A?`${B}:${A.contentHash}`:B}async process(x,B,A){this.logger.debug("Starting document generation job",{jobId:B,sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType});let w=x.maxPageCount??s89,f=x.maxBytes??a89,D=x.timeoutMs??r89;if(x.pageCount!==void 0&&x.pageCount>w)throw Error(`Refusing to render ${x.pageCount} page PDF; maxPageCount=${w}`);let $=await this.getDedupKey(x),Z=_60(x,$),Q=x.documentId!==void 0||x.filename!==void 0;if(x.replace!==!0){let Y=await this.findDocumentByDedupKey($,Q?Z:void 0);if(Y&&(!Q||Y.id===Z)){if(x.targetEntityType&&x.targetEntityId)await this.attachDocumentToTarget(x.targetEntityType,x.targetEntityId,Y.id,x);return await this.reportProgress(A,{progress:100,message:"Reusing existing generated document"}),{success:!0,documentId:Y.id,reused:!0}}}await this.reportProgress(A,{progress:20,message:"Rendering PDF document"});try{let Y=await this.resolveDocumentAttachment(x,Z,{timeoutMs:D,maxBytes:f}),W=Y.data;if(W.byteLength>f)throw Error(`Rendered PDF exceeds maxBytes=${f}: ${W.byteLength} bytes`);let H=E60(W);if(H>w)throw Error(`Rendered PDF has ${H} pages, exceeding maxPageCount=${w}`);let F=H>0?H:x.pageCount;await this.reportProgress(A,{progress:70,message:"Storing PDF document"});let K=x.filename??(x.renderUrl===void 0?Y.filename:`${Z}.pdf`),q=vf.createDocumentEntity({dataUrl:uh(W),filename:K,...x.title&&{title:x.title},...F!==void 0&&{pageCount:F},status:"draft",sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType,dedupKey:$});if(await l7({entityService:this.context.entityService,entity:{...q,id:Z}}),x.targetEntityType&&x.targetEntityId)await this.attachDocumentToTarget(x.targetEntityType,x.targetEntityId,Z,x);return await this.reportProgress(A,{progress:100,message:"PDF document generation complete"}),{success:!0,documentId:Z,reused:!1}}catch(Y){let W=g(Y);throw this.logger.error("Document generation failed",{jobId:B,error:W}),await Nf({entityService:this.context.entityService,entityType:"document",id:Z,error:W}),Y}}async resolveDocumentAttachment(x,B,A){if(x.renderUrl!==void 0)return{type:"document",data:await this.renderPdf(x.renderUrl,{timeoutMs:A.timeoutMs,maxBytes:A.maxBytes,printBackground:!0,preferCSSPageSize:!0,...x.width!==void 0&&{width:x.width},...x.height!==void 0&&{height:x.height},...x.format!==void 0&&{format:x.format}}),mimeType:"application/pdf",filename:x.filename??`${B}.pdf`};let w=await this.context.attachments.resolve({sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType});if(!w)throw Error(`No attachment provider found for ${x.sourceEntityType}/${x.attachmentType}`);if(w.type!=="document")throw Error(`Attachment provider returned ${w.type}; expected document`);return w}async findDocumentByDedupKey(x,B){let A=await this.context.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:x}}}});if(A.length>1)this.logger.warn("Multiple documents share dedupKey; using first",{dedupKey:x,count:A.length,ids:A.map((f)=>f.id),preferredDocumentId:B});let w=A.filter((f)=>f.metadata.status!=="pending"&&f.metadata.status!=="failed");return w.find((f)=>f.id===B)??w[0]}async attachDocumentToTarget(x,B,A,w){let f=await this.context.entityService.getEntity({entityType:x,id:B});if(!f)throw Error(`Target entity not found: ${x}/${B}`);let{frontmatter:D}=I1(f.content),$=Array.isArray(D.documents)?D.documents.filter(x99):[],Z=w.replace?await this.removeReferencesForSameSourceAttachment($,A,w):$,Q=Z.some((Y)=>Y.id===A)?Z:[...Z,{id:A}];await this.context.entityService.updateEntity({entity:{...f,content:h3(f.content,"documents",Q)}})}async removeReferencesForSameSourceAttachment(x,B,A){let w=[];for(let f of x){if(f.id===B){w.push(f);continue}let D=await this.context.entityService.getEntity({entityType:"document",id:f.id});if(!D||!B99(D,A))w.push(f)}return w}}function _60(x,B){let A=`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:${x.renderUrl??"resolved-attachment"}`,w=x.documentId??x.filename?.replace(/\.pdf$/i,"")??B??A,f=x.replace===!0&&x.documentId===void 0?`${w}-${Date.now()}`:w;return e89(f)}function e89(x){let B=Gx(x.replace(/[/:]+/g," "))||`document-${PUx(x)}`;if(B.length<=_Ux)return B;let A=`-${PUx(x)}`;return`${B.slice(0,_Ux-A.length).replace(/-+$/g,"")}${A}`}function PUx(x){return d89("sha256").update(x).digest("hex").slice(0,o89)}function x99(x){return typeof x==="object"&&x!==null&&"id"in x&&typeof x.id==="string"&&x.id.length>0}function B99(x,B){return x.metadata.sourceEntityType===B.sourceEntityType&&x.metadata.sourceEntityId===B.sourceEntityId&&x.metadata.attachmentType===B.attachmentType}var kUx={name:"@brains/document-plugin",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Document entity type for generated PDFs and publishable document attachments",dependencies:{"@brains/contracts":"workspace:*","@brains/document":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/typescript-config":"workspace:*","bun-types":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var w99=`data:application/pdf;base64,${Buffer.from(`%PDF-1.4
5618
+ `).trim();if(!Q)throw Error("Could not extract text from the uploaded PDF");return Q}finally{await f.destroy()}}import{createHash as d89}from"crypto";var a89=26214400,s89=20,r89=60000,_Ux=80,o89=10,t89={renderUrl:X.url().optional(),sourceEntityType:X.string().min(1),sourceEntityId:X.string().min(1),attachmentType:X.string().min(1),documentId:X.string().min(1).optional(),title:X.string().min(1).optional(),filename:X.string().min(1).optional(),dedupKey:X.string().min(1).optional(),replace:X.boolean().optional(),pageCount:X.number().int().min(0).optional(),maxPageCount:X.number().int().positive().optional(),maxBytes:X.number().int().positive().optional(),timeoutMs:X.number().int().positive().optional(),width:X.union([X.string(),X.number()]).optional(),height:X.union([X.string(),X.number()]).optional(),format:X.string().optional(),targetEntityType:X.string().min(1).optional(),targetEntityId:X.string().min(1).optional()},LUx=X.object(t89),ih=LUx.refine((x)=>x.targetEntityType===void 0&&x.targetEntityId===void 0||x.targetEntityType!==void 0&&x.targetEntityId!==void 0,{message:"targetEntityType and targetEntityId must be provided together",path:["targetEntityId"]});class lh extends $9{context;renderPdf;constructor(x,B,A={}){super(x,{schema:ih,jobTypeName:"document-generate"});this.context=B,this.renderPdf=A.renderPdf??JUx}async getDedupKey(x){if(x.dedupKey!==void 0)return x.dedupKey;if(x.renderUrl!==void 0)return`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:${x.renderUrl}`;let B=`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:resolved-attachment`,A=await this.context.entityService.getEntity({entityType:x.sourceEntityType,id:x.sourceEntityId});return A?`${B}:${A.contentHash}`:B}async process(x,B,A){this.logger.debug("Starting document generation job",{jobId:B,sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType});let w=x.maxPageCount??s89,f=x.maxBytes??a89,D=x.timeoutMs??r89;if(x.pageCount!==void 0&&x.pageCount>w)throw Error(`Refusing to render ${x.pageCount} page PDF; maxPageCount=${w}`);let $=await this.getDedupKey(x),Z=_60(x,$),Q=x.documentId!==void 0||x.filename!==void 0;if(x.replace!==!0){let Y=await this.findDocumentByDedupKey($,Q?Z:void 0);if(Y&&(!Q||Y.id===Z)){if(x.targetEntityType&&x.targetEntityId)await this.attachDocumentToTarget(x.targetEntityType,x.targetEntityId,Y.id,x);return await this.reportProgress(A,{progress:100,message:"Reusing existing generated document"}),{success:!0,documentId:Y.id,reused:!0}}}await this.reportProgress(A,{progress:20,message:"Rendering PDF document"});try{let Y=await this.resolveDocumentAttachment(x,Z,{timeoutMs:D,maxBytes:f}),W=Y.data;if(W.byteLength>f)throw Error(`Rendered PDF exceeds maxBytes=${f}: ${W.byteLength} bytes`);let H=E60(W);if(H>w)throw Error(`Rendered PDF has ${H} pages, exceeding maxPageCount=${w}`);let F=H>0?H:x.pageCount;await this.reportProgress(A,{progress:70,message:"Storing PDF document"});let K=x.filename??(x.renderUrl===void 0?Y.filename:`${Z}.pdf`),q=vf.createDocumentEntity({dataUrl:uh(W),filename:K,...x.title&&{title:x.title},...F!==void 0&&{pageCount:F},status:"draft",sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType,dedupKey:$});if(await l7({entityService:this.context.entityService,entity:{...q,id:Z}}),x.targetEntityType&&x.targetEntityId)await this.attachDocumentToTarget(x.targetEntityType,x.targetEntityId,Z,x);return await this.reportProgress(A,{progress:100,message:"PDF document generation complete"}),{success:!0,documentId:Z,reused:!1}}catch(Y){let W=g(Y);throw this.logger.error("Document generation failed",{jobId:B,error:W}),await Nf({entityService:this.context.entityService,entityType:"document",id:Z,error:W}),Y}}async resolveDocumentAttachment(x,B,A){if(x.renderUrl!==void 0)return{type:"document",data:await this.renderPdf(x.renderUrl,{timeoutMs:A.timeoutMs,maxBytes:A.maxBytes,printBackground:!0,preferCSSPageSize:!0,...x.width!==void 0&&{width:x.width},...x.height!==void 0&&{height:x.height},...x.format!==void 0&&{format:x.format}}),mimeType:"application/pdf",filename:x.filename??`${B}.pdf`};let w=await this.context.attachments.resolve({sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType});if(!w)throw Error(`No attachment provider found for ${x.sourceEntityType}/${x.attachmentType}`);if(w.type!=="document")throw Error(`Attachment provider returned ${w.type}; expected document`);return w}async findDocumentByDedupKey(x,B){let A=await this.context.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:x}}}});if(A.length>1)this.logger.warn("Multiple documents share dedupKey; using first",{dedupKey:x,count:A.length,ids:A.map((f)=>f.id),preferredDocumentId:B});let w=A.filter((f)=>f.metadata.status!=="pending"&&f.metadata.status!=="failed");return w.find((f)=>f.id===B)??w[0]}async attachDocumentToTarget(x,B,A,w){let f=await this.context.entityService.getEntity({entityType:x,id:B});if(!f)throw Error(`Target entity not found: ${x}/${B}`);let{frontmatter:D}=I1(f.content),$=Array.isArray(D.documents)?D.documents.filter(x99):[],Z=w.replace?await this.removeReferencesForSameSourceAttachment($,A,w):$,Q=Z.some((Y)=>Y.id===A)?Z:[...Z,{id:A}];await this.context.entityService.updateEntity({entity:{...f,content:h3(f.content,"documents",Q)}})}async removeReferencesForSameSourceAttachment(x,B,A){let w=[];for(let f of x){if(f.id===B){w.push(f);continue}let D=await this.context.entityService.getEntity({entityType:"document",id:f.id});if(!D||!B99(D,A))w.push(f)}return w}}function _60(x,B){let A=`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:${x.renderUrl??"resolved-attachment"}`,w=x.documentId??x.filename?.replace(/\.pdf$/i,"")??B??A,f=x.replace===!0&&x.documentId===void 0?`${w}-${Date.now()}`:w;return e89(f)}function e89(x){let B=Gx(x.replace(/[/:]+/g," "))||`document-${PUx(x)}`;if(B.length<=_Ux)return B;let A=`-${PUx(x)}`;return`${B.slice(0,_Ux-A.length).replace(/-+$/g,"")}${A}`}function PUx(x){return d89("sha256").update(x).digest("hex").slice(0,o89)}function x99(x){return typeof x==="object"&&x!==null&&"id"in x&&typeof x.id==="string"&&x.id.length>0}function B99(x,B){return x.metadata.sourceEntityType===B.sourceEntityType&&x.metadata.sourceEntityId===B.sourceEntityId&&x.metadata.attachmentType===B.attachmentType}var kUx={name:"@brains/document-plugin",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Document entity type for generated PDFs and publishable document attachments",dependencies:{"@brains/contracts":"workspace:*","@brains/document":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/typescript-config":"workspace:*","bun-types":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var w99=`data:application/pdf;base64,${Buffer.from(`%PDF-1.4
5619
5619
  % Pending document placeholder
5620
5620
  %%EOF
5621
- `).toString("base64")}`;function f99(x){return{source:"document",metadata:{operationType:"content_operations",interfaceType:x.interfaceType,requestedByActor:x.actor,...x.actor.kind==="user"?{requestedByUserId:x.actor.userId}:{},requestedByInterface:x.interfaceType}}}var D99=X.object({}).catchall(X.unknown()).transform(()=>({})),P60={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function $99(x,B){let A=x.title?.trim();if(A)return A;return B.replace(/\.[^.]+$/,"").trim()||B}function Z99(x,B){return`data:${x};base64,${B.toString("base64")}`}function Q99(x){let B=encodeURIComponent(x.entityId);return{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${B}`,downloadUrl:`/api/chat/attachments/document?id=${B}&download=1`,filename:x.filename,source:{entityType:"document",entityId:x.entityId,attachmentType:"uploaded"}}}class J60 extends D8{entityType=vf.entityType;schema=jq;adapter=vf;pluginContext;constructor(){super("document",kUx,{},D99)}async onRegister(x){this.pluginContext=x,x.entities.register(this.entityType,this.schema,this.adapter,{embeddable:!1,projectionSource:!1,projectionSourceRole:"excluded"}),x.entities.registerCreateInterceptor(this.entityType,(B,A)=>this.interceptCreate(B,A)),x.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["application/pdf"],handler:async(B,A)=>{let w=await this.promoteUpload({entityType:this.entityType,...B.title!==void 0?{title:B.title}:{},from:B.upload},x,A);return w.kind==="handled"?w.result:{success:!1,error:"Document upload save was not handled"}}}),x.jobs.registerHandler("generate",new lh(this.logger.child("DocumentGenerationJobHandler"),x))}async interceptCreate(x,B){let A=this.pluginContext;if(x.from?.kind===P60.refKind){if(!A)return{kind:"handled",result:{success:!1,error:"Plugin context not initialized"}};return this.promoteUpload(x,A,B)}if(x.from?.kind!=="entity-attachment")return{kind:"continue",input:x};if(!A)return{kind:"handled",result:{success:!1,error:"Plugin context not initialized"}};let w=ih.parse({sourceEntityType:x.from.sourceEntityType,sourceEntityId:x.from.sourceEntityId,attachmentType:x.from.attachmentType,...x.title&&{title:x.title},...x.replace===!0&&{replace:!0},...x.targetEntityType&&{targetEntityType:x.targetEntityType},...x.targetEntityId&&{targetEntityId:x.targetEntityId}}),f=await this.getDedupKey(w,A),D=w.replace===!0?void 0:await this.findExistingDocument(f,A),$=D?.id??_60(w,f);if(!D)await this.createPendingDocument(A,{id:$,title:w.title??$,filename:`${$}.pdf`,sourceEntityType:w.sourceEntityType,sourceEntityId:w.sourceEntityId,attachmentType:w.attachmentType,dedupKey:f},B);let Z=await A.jobs.enqueue({type:"generate",data:{...w,dedupKey:f,documentId:$},options:f99(B)}),Q=`${$}.pdf`;return{kind:"handled",result:{success:!0,data:{entityId:$,jobId:Z,status:"generating",attachment:{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${encodeURIComponent($)}`,downloadUrl:`/api/chat/attachments/document?id=${encodeURIComponent($)}&download=1`,filename:Q,source:{entityType:"document",entityId:$,attachmentType:w.attachmentType}}}}}}async promoteUpload(x,B,A){let w=x.from;if(w?.kind!==P60.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let f;try{f=await B.uploads.scoped(P60).read(w.id)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(f.record.mediaType!=="application/pdf")return{kind:"handled",result:{success:!1,error:"Only PDF uploads can be promoted to document entities"}};let D=$99(x,f.record.filename),$=Gx(D);if(!$)return{kind:"handled",result:{success:!1,error:"Could not derive a document id from the uploaded filename. Provide a title."}};let Z=new Date().toISOString(),Q=vf.createDocumentEntity({dataUrl:Z99(f.record.mediaType,f.content),filename:f.record.filename,title:D,status:"draft",sourceUploadId:w.id,sourceFilename:f.record.filename,sourceMediaType:f.record.mediaType,attachmentType:"uploaded",dedupKey:`upload:${w.kind}:${w.id}`}),Y=await B.entityService.createEntity({entity:{id:$,...Q,created:Z,updated:Z},options:{deduplicateId:!0,eventContext:{actor:A.actor,interfaceType:A.interfaceType}}});return{kind:"handled",result:{success:!0,data:{entityId:Y.entityId,status:"created",attachment:Q99({entityId:Y.entityId,filename:f.record.filename})}}}}async createPendingDocument(x,B,A){let w=new Date().toISOString(),f=vf.createDocumentEntity({dataUrl:w99,filename:B.filename,title:B.title,status:"pending",sourceEntityType:B.sourceEntityType,sourceEntityId:B.sourceEntityId,attachmentType:B.attachmentType,dedupKey:B.dedupKey});await _q({entityService:x.entityService,entity:{id:B.id,...f,created:w,updated:w},options:{eventContext:{actor:A.actor,interfaceType:A.interfaceType}}})}async getDedupKey(x,B){if(x.dedupKey!==void 0)return x.dedupKey;if(x.renderUrl!==void 0)return`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:${x.renderUrl}`;let A=`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:resolved-attachment`,w=await B.entityService.getEntity({entityType:x.sourceEntityType,id:x.sourceEntityId});return w?`${A}:${w.contentHash}`:A}async findExistingDocument(x,B){return(await B.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:x}}}}))[0]}async getInstructions(){return"Document entities store durable file artifacts such as PDFs. Uploaded PDFs are raw document files, not decks. Source-derived document artifacts are durable documents backed by registered attachment providers such as carousel or printable. Generate saved PDF artifacts through system_generate with source.kind attachment; preserve raw uploaded PDFs with system_create source.kind upload and transform preserve."}async getTools(){return[]}}function L60(){return new J60}var MUx={name:"@brains/email",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Email message interface with Resend delivery and IMAP intake",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",imapflow:"^1.6.5",mailparser:"^3.9.14"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/mailparser":"^3.4.6","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Ckx=S("tls"),ckx=S("net"),iZ9=S("crypto"),{EventEmitter:lZ9}=S("events"),nZ9=U50(),Bw=bY(),wy=S("zlib"),{Headers:gkx}=U10(),{LimitedPassthrough:dZ9}=s_x(),{ImapStream:aZ9}=BPx(),{parser:sZ9,compiler:fy}=P10(),N40=zPx(),Tkx=hR(),pkx=OR(),rZ9=Tj(),{PassThrough:ukx}=S("stream"),{proxyConnection:oZ9,detachEarlyErrorHandler:tZ9}=jJx(),{ConnectionDeadline:eZ9}=m10(),{comparePaths:xQ9,updateCapabilities:BQ9,getFolderTree:AQ9,formatMessageResponse:wQ9,getDecoder:fQ9,packMessageRange:Skx,normalizePath:DQ9,expandRange:$Q9,AuthenticationFailure:uq,getColorFlags:ZQ9,hasCapability:QQ9,unrefTimer:I40}=n9(),XQ9=mkx(),x_=()=>{};var YQ9={NOT_AUTHENTICATED:1,AUTHENTICATED:2,SELECTED:3,LOGOUT:4};class ikx extends lZ9{static version=N40.version;constructor(x){super({captureRejections:!0});this.options=x||{},this.id=this.options.id||this.getRandomId(),this.clientInfo=Object.assign({name:N40.name,version:N40.version,vendor:"Postal Systems","support-url":"https://github.com/postalsys/imapflow/issues"},this.options.clientInfo||{});for(let B of Object.keys(this.clientInfo))if(typeof this.clientInfo[B]==="string")this.clientInfo[B]=this.clientInfo[B].normalize("NFD").replace(/\p{Diacritic}/gu,"");if(this.serverInfo=null,this.log=this.getLogger(),this.secureConnection=!!this.options.secure,this.port=Number(this.options.port)||(this.secureConnection?993:143),this.host=this.options.host||"localhost",this.servername=this.options.servername?this.options.servername:!ckx.isIP(this.host)?this.host:!1,typeof this.options.secure>"u"&&this.port===993)this.secureConnection=!0;this.socketTimeout=Number(this.options.socketTimeout)||300000,this.logRaw=this.options.logRaw,this.streamer=new aZ9({logger:this.log,cid:this.id,logRaw:this.logRaw,secureConnection:this.secureConnection,maxLineLength:this.options.maxLineLength,maxLiteralSize:this.options.maxLiteralSize}),this.reading=!1,this.socket=!1,this.writeSocket=!1,this._throttleTimer=null,this._throttleAbort=null,this._upgradeReject=null,this.isClosed=!1,this.states=YQ9,this.state=this.states.NOT_AUTHENTICATED,this.lockCounter=0,this.tagCounter=0,this.requestTagMap=new Map,this.requestQueue=[],this.currentRequest=!1,this._unknownTagCount=0,this._nextUnknownTagWarn=1,this.writeBytesCounter=0,this.commandParts=[],this.capabilities=new Map,this.authCapabilities=new Map,this.rawCapabilities=null,this.expectCapabilityUpdate=!1,this._starttlsHadTrailingData=!1,this.enabled=new Set,this.usable=!1,this.authenticated=!1,this.mailbox=!1,this.currentSelectCommand=!1,this.idling=!1,this.emitLogs=!!this.options.emitLogs,this.lo=0,this.untaggedHandlers={},this.sectionHandlers={},this.commands=XQ9,this.folders=new Map,this.currentLock=!1,this.locks=[],this.idRequested=!1,this.maxIdleTime=this.options.maxIdleTime||!1,this.missingIdleCommand=(this.options.missingIdleCommand||"").toString().toUpperCase().trim()||"NOOP",this.disableBinary=!!this.options.disableBinary,this.skipListSubscribedArg=!1,this.skipListStatusArgs=!1,this.skipListAuxArgs=!1,this.skipLsub=!1,this._streamerErrorHandler=(B)=>{if(["Z_BUF_ERROR","ECONNRESET","EPIPE","ETIMEDOUT","EHOSTUNREACH"].includes(B.code)){this.closeAfter();return}this.log.error({err:B,cid:this.id}),this.emitError(B)},this.streamer.on("error",this._streamerErrorHandler),this._connectCalled=!1}emitError(x){if(!x)return;if(x._connId=x._connId||this.id,this.upgrading){let B=this._upgradeReject;if(this._upgradeReject=null,typeof B==="function"){B(x);return}this.upgrading=!1,this.closeAfter();return}if(typeof this.initialReject==="function"){let B=this.initialReject;this.initialResolve=!1,this.initialReject=!1,this.closeAfter(),B(x);return}this.closeAfter(),this.emit("error",x)}getRandomId(){let x=BigInt("0x"+iZ9.randomBytes(13).toString("hex")).toString(36);if(x.length<20)x="0".repeat(20-x.length)+x;if(x.length>20)x=x.substr(0,20);return x}write(x){if(!this.socket||this.socket.destroyed){let A=Error("Socket is already closed");throw A.code="NoConnection",A}if(this.state===this.states.LOGOUT){let A=Error("Can not send data after logged out");throw A.code="StateLogout",A}if(this.writeSocket.destroyed){this.log.error({msg:"Write socket destroyed",cid:this.id}),this.close();return}let B=!this.commandParts.length;if(typeof x==="string"){if(B)x+=`\r
5621
+ `).toString("base64")}`;function f99(x){return{source:"document",metadata:{operationType:"content_operations",interfaceType:x.interfaceType,requestedByActor:x.actor,...x.actor.kind==="user"?{requestedByUserId:x.actor.userId}:{},requestedByInterface:x.interfaceType}}}var D99=X.object({}).catchall(X.unknown()).transform(()=>({})),P60={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function $99(x,B){let A=x.title?.trim();if(A)return A;return B.replace(/\.[^.]+$/,"").trim()||B}function Z99(x,B){return`data:${x};base64,${B.toString("base64")}`}function Q99(x){let B=encodeURIComponent(x.entityId);return{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${B}`,downloadUrl:`/api/chat/attachments/document?id=${B}&download=1`,filename:x.filename,source:{entityType:"document",entityId:x.entityId,attachmentType:"uploaded"}}}class J60 extends D8{entityType=vf.entityType;schema=jq;adapter=vf;pluginContext;constructor(){super("document",kUx,{},D99)}async onRegister(x){this.pluginContext=x,x.entities.register(this.entityType,this.schema,this.adapter,{embeddable:!1,projectionSource:!1,projectionSourceRole:"excluded"}),x.entities.registerCreateInterceptor(this.entityType,(B,A)=>this.interceptCreate(B,A)),x.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["application/pdf"],handler:async(B,A)=>{let w=await this.promoteUpload({entityType:this.entityType,...B.title!==void 0?{title:B.title}:{},from:B.upload},x,A);return w.kind==="handled"?w.result:{success:!1,error:"Document upload save was not handled"}}}),x.jobs.registerHandler("generate",new lh(this.logger.child("DocumentGenerationJobHandler"),x))}async interceptCreate(x,B){let A=this.pluginContext;if(x.from?.kind===P60.refKind){if(!A)return{kind:"handled",result:{success:!1,error:"Plugin context not initialized"}};return this.promoteUpload(x,A,B)}if(x.from?.kind!=="entity-attachment")return{kind:"continue",input:x};if(!A)return{kind:"handled",result:{success:!1,error:"Plugin context not initialized"}};let w=ih.parse({sourceEntityType:x.from.sourceEntityType,sourceEntityId:x.from.sourceEntityId,attachmentType:x.from.attachmentType,...x.title&&{title:x.title},...x.replace===!0&&{replace:!0},...x.targetEntityType&&{targetEntityType:x.targetEntityType},...x.targetEntityId&&{targetEntityId:x.targetEntityId}}),f=await this.getDedupKey(w,A),D=w.replace===!0?void 0:await this.findExistingDocument(f,A),$=D?.id??_60(w,f);if(!D)await this.createPendingDocument(A,{id:$,title:w.title??$,filename:`${$}.pdf`,sourceEntityType:w.sourceEntityType,sourceEntityId:w.sourceEntityId,attachmentType:w.attachmentType,dedupKey:f},B);let Z=await A.jobs.enqueue({type:"generate",data:{...w,dedupKey:f,documentId:$},options:f99(B)}),Q=`${$}.pdf`;return{kind:"handled",result:{success:!0,data:{entityId:$,jobId:Z,status:"generating",attachment:{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${encodeURIComponent($)}`,downloadUrl:`/api/chat/attachments/document?id=${encodeURIComponent($)}&download=1`,filename:Q,source:{entityType:"document",entityId:$,attachmentType:w.attachmentType}}}}}}async promoteUpload(x,B,A){let w=x.from;if(w?.kind!==P60.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let f;try{f=await B.uploads.scoped(P60).read(w.id)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(f.record.mediaType!=="application/pdf")return{kind:"handled",result:{success:!1,error:"Only PDF uploads can be promoted to document entities"}};let D=$99(x,f.record.filename),$=Gx(D);if(!$)return{kind:"handled",result:{success:!1,error:"Could not derive a document id from the uploaded filename. Provide a title."}};let Z=new Date().toISOString(),Q=vf.createDocumentEntity({dataUrl:Z99(f.record.mediaType,f.content),filename:f.record.filename,title:D,status:"draft",sourceUploadId:w.id,sourceFilename:f.record.filename,sourceMediaType:f.record.mediaType,attachmentType:"uploaded",dedupKey:`upload:${w.kind}:${w.id}`}),Y=await B.entityService.createEntity({entity:{id:$,...Q,created:Z,updated:Z},options:{deduplicateId:!0,eventContext:{actor:A.actor,interfaceType:A.interfaceType}}});return{kind:"handled",result:{success:!0,data:{entityId:Y.entityId,status:"created",attachment:Q99({entityId:Y.entityId,filename:f.record.filename})}}}}async createPendingDocument(x,B,A){let w=new Date().toISOString(),f=vf.createDocumentEntity({dataUrl:w99,filename:B.filename,title:B.title,status:"pending",sourceEntityType:B.sourceEntityType,sourceEntityId:B.sourceEntityId,attachmentType:B.attachmentType,dedupKey:B.dedupKey});await _q({entityService:x.entityService,entity:{id:B.id,...f,created:w,updated:w},options:{eventContext:{actor:A.actor,interfaceType:A.interfaceType}}})}async getDedupKey(x,B){if(x.dedupKey!==void 0)return x.dedupKey;if(x.renderUrl!==void 0)return`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:${x.renderUrl}`;let A=`${x.attachmentType}:${x.sourceEntityType}:${x.sourceEntityId}:resolved-attachment`,w=await B.entityService.getEntity({entityType:x.sourceEntityType,id:x.sourceEntityId});return w?`${A}:${w.contentHash}`:A}async findExistingDocument(x,B){return(await B.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:x}}}}))[0]}async getInstructions(){return"Document entities store durable file artifacts such as PDFs. Uploaded PDFs are raw document files, not decks. Source-derived document artifacts are durable documents backed by registered attachment providers such as carousel or printable. Generate saved PDF artifacts through system_generate with source.kind attachment; preserve raw uploaded PDFs with system_create source.kind upload and transform preserve."}async getTools(){return[]}}function L60(){return new J60}var MUx={name:"@brains/email",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Email message interface with Resend delivery and IMAP intake",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",imapflow:"^1.6.5",mailparser:"^3.9.14"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/mailparser":"^3.4.6","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Ckx=S("tls"),ckx=S("net"),iZ9=S("crypto"),{EventEmitter:lZ9}=S("events"),nZ9=U50(),Bw=bY(),wy=S("zlib"),{Headers:gkx}=U10(),{LimitedPassthrough:dZ9}=s_x(),{ImapStream:aZ9}=BPx(),{parser:sZ9,compiler:fy}=P10(),N40=zPx(),Tkx=hR(),pkx=OR(),rZ9=Tj(),{PassThrough:ukx}=S("stream"),{proxyConnection:oZ9,detachEarlyErrorHandler:tZ9}=jJx(),{ConnectionDeadline:eZ9}=m10(),{comparePaths:xQ9,updateCapabilities:BQ9,getFolderTree:AQ9,formatMessageResponse:wQ9,getDecoder:fQ9,packMessageRange:Skx,normalizePath:DQ9,expandRange:$Q9,AuthenticationFailure:uq,getColorFlags:ZQ9,hasCapability:QQ9,unrefTimer:I40}=n9(),XQ9=mkx(),x_=()=>{};var YQ9={NOT_AUTHENTICATED:1,AUTHENTICATED:2,SELECTED:3,LOGOUT:4};class ikx extends lZ9{static version=N40.version;constructor(x){super({captureRejections:!0});this.options=x||{},this.id=this.options.id||this.getRandomId(),this.clientInfo=Object.assign({name:N40.name,version:N40.version,vendor:"Postal Systems","support-url":"https://github.com/postalsys/imapflow/issues"},this.options.clientInfo||{});for(let B of Object.keys(this.clientInfo))if(typeof this.clientInfo[B]==="string")this.clientInfo[B]=this.clientInfo[B].normalize("NFD").replace(/\p{Diacritic}/gu,"");if(this.serverInfo=null,this.log=this.getLogger(),this.secureConnection=!!this.options.secure,this.port=Number(this.options.port)||(this.secureConnection?993:143),this.host=this.options.host||"localhost",this.servername=this.options.servername?this.options.servername:!ckx.isIP(this.host)?this.host:!1,typeof this.options.secure>"u"&&this.port===993)this.secureConnection=!0;this.socketTimeout=Number(this.options.socketTimeout)||300000,this.logRaw=this.options.logRaw,this.streamer=new aZ9({logger:this.log,cid:this.id,logRaw:this.logRaw,secureConnection:this.secureConnection,maxLineLength:this.options.maxLineLength,maxLiteralSize:this.options.maxLiteralSize}),this.reading=!1,this.socket=!1,this.writeSocket=!1,this._throttleTimer=null,this._throttleAbort=null,this._upgradeReject=null,this.isClosed=!1,this.states=YQ9,this.state=this.states.NOT_AUTHENTICATED,this.lockCounter=0,this.tagCounter=0,this.requestTagMap=new Map,this.requestQueue=[],this.currentRequest=!1,this._unknownTagCount=0,this._nextUnknownTagWarn=1,this.writeBytesCounter=0,this.commandParts=[],this.capabilities=new Map,this.authCapabilities=new Map,this.rawCapabilities=null,this.expectCapabilityUpdate=!1,this._starttlsHadTrailingData=!1,this.enabled=new Set,this.usable=!1,this.authenticated=!1,this.mailbox=!1,this.currentSelectCommand=!1,this.idling=!1,this.emitLogs=!!this.options.emitLogs,this.lo=0,this.untaggedHandlers={},this.sectionHandlers={},this.commands=XQ9,this.folders=new Map,this.currentLock=!1,this.locks=[],this.idRequested=!1,this.maxIdleTime=this.options.maxIdleTime||!1,this.missingIdleCommand=(this.options.missingIdleCommand||"").toString().toUpperCase().trim()||"NOOP",this.disableBinary=!!this.options.disableBinary,this.skipListSubscribedArg=!1,this.skipListStatusArgs=!1,this.skipListAuxArgs=!1,this.skipLsub=!1,this._streamerErrorHandler=(B)=>{if(["Z_BUF_ERROR","ECONNRESET","EPIPE","ETIMEDOUT","EHOSTUNREACH"].includes(B.code)){this.closeAfter();return}this.log.error({err:B,cid:this.id}),this.emitError(B)},this.streamer.on("error",this._streamerErrorHandler),this._connectCalled=!1}emitError(x){if(!x)return;if(x._connId=x._connId||this.id,this.upgrading){let B=this._upgradeReject;if(this._upgradeReject=null,typeof B==="function"){B(x);return}this.upgrading=!1,this.closeAfter();return}if(typeof this.initialReject==="function"){let B=this.initialReject;this.initialResolve=!1,this.initialReject=!1,this.closeAfter(),B(x);return}this.closeAfter(),this.emit("error",x)}getRandomId(){let x=BigInt("0x"+iZ9.randomBytes(13).toString("hex")).toString(36);if(x.length<20)x="0".repeat(20-x.length)+x;if(x.length>20)x=x.substr(0,20);return x}write(x){if(!this.socket||this.socket.destroyed){let A=Error("Socket is already closed");throw A.code="NoConnection",A}if(this.state===this.states.LOGOUT){let A=Error("Can not send data after logged out");throw A.code="StateLogout",A}if(this.writeSocket.destroyed){this.log.error({msg:"Write socket destroyed",cid:this.id}),this.close();return}let B=!this.commandParts.length;if(typeof x==="string"){if(B)x+=`\r
5622
5622
  `;x=Buffer.from(x,"binary")}else if(Buffer.isBuffer(x)){if(B)x=Buffer.concat([x,Buffer.from(`\r
5623
- `)])}else return!1;if(this.logRaw)this.log.trace({src:"c",msg:"write to socket",data:x.toString("base64"),compress:!!this._deflate,secure:!!this.secureConnection,cid:this.id});this.writeBytesCounter+=x.length,this.writeSocket.write(x)}stats(x){let B={sent:this.writeBytesCounter||0,received:this.streamer&&this.streamer.readBytesCounter||0};if(x){if(this.writeBytesCounter=0,this.streamer)this.streamer.readBytesCounter=0}return B}async send(x){if(this.state===this.states.LOGOUT){if(x.tag){let f=this.requestTagMap.get(x.tag);if(f){this.requestTagMap.delete(f.tag);let D=Error("Connection not available");D.code="NoConnection",f.reject(D)}}return}let B=await fy(x,{asArray:!0,literalMinus:QQ9(this,"LITERAL-")||this.capabilities.has("LITERAL+")});this.commandParts=B;let A=await fy(x,{isLogging:!0}),w=x.options||{};if(this.log.debug({src:"c",msg:A.toString(),cid:this.id,comment:w.comment}),this.write(this.commandParts.shift()),this.currentRequest&&this.currentRequest.tag===x.tag)this.currentRequest.sent=!0;if(typeof w.onSend==="function")try{w.onSend()}catch(f){this.log.warn({err:f,cid:this.id})}}async trySend(){while(!this.currentRequest&&this.requestQueue.length){this.currentRequest=this.requestQueue.shift();try{await this.send({tag:this.currentRequest.tag,command:this.currentRequest.command,attributes:this.currentRequest.attributes,options:this.currentRequest.options});return}catch(x){this.commandParts=[],this.rejectCurrentRequest(x)}}}exec(x,B,A){if(this.state===this.states.LOGOUT||this.isClosed){let D=Error("Connection not available");D.code="NoConnection";let $=Promise.reject(D);return $.catch(x_),$}if(!this.socket||this.socket.destroyed){let D=Error("Connection closed");D.code="EConnectionClosed";let $=Promise.reject(D);return $.catch(x_),$}let w=(++this.tagCounter).toString(16).toUpperCase();A=A||{};let f=new Promise((D,$)=>{this.requestTagMap.set(w,{command:x,attributes:B,options:A,resolve:D,reject:$}),this.requestQueue.push({tag:w,command:x,attributes:B,options:A}),this.trySend().catch((Z)=>this.log.warn({err:Z,cid:this.id}))});return f.catch(x_),f}getUntaggedHandler(x,B){if(/^[0-9]+$/.test(x)){let A=B&&B.length&&typeof B[0].value==="string"?B[0].value.toUpperCase():!1;if(A)x=A}if(x=x.toUpperCase().trim(),this.currentRequest&&this.currentRequest.options&&this.currentRequest.options.untagged&&this.currentRequest.options.untagged[x])return this.currentRequest.options.untagged[x];if(this.untaggedHandlers[x])return this.untaggedHandlers[x]}getSectionHandler(x){if(this.sectionHandlers[x])return this.sectionHandlers[x]}releaseStreamData(x){if(!x||x.released)return;if(x.released=!0,typeof x.next==="function")x.next()}countUnknownTag(x){if(this.isClosed)return;if(this._unknownTagCount++,this._unknownTagCount===this._nextUnknownTagWarn)this._nextUnknownTagWarn*=2,this.log.warn({msg:"Tagged response for an unknown tag",tag:x,unknownTagCount:this._unknownTagCount,cid:this.id})}failProtocol(x){if(this.streamer&&!this.streamer.destroyed)this.streamer.destroy();this.emitError(x)}rejectCurrentRequest(x){if(!this.currentRequest)return;let B=this.currentRequest.tag;this.currentRequest=!1;let A=this.requestTagMap.get(B);if(A)this.requestTagMap.delete(B),A.reject(x)}async reader(){let x,B=0;while((x=this.streamer.read())!==null){let A;try{A=await this.handleResponse(x)}catch(w){A=!1;let f=Error("Failed to process server response");f.code="ResponseProcessingFailed",f._err=w,this.log.error({msg:"Failed to process server response",err:w,cid:this.id}),this.rejectCurrentRequest(f),this.failProtocol(f)}finally{this.releaseStreamData(x)}if(!A)return;if(B++,B%10===0)await new Promise((w)=>setImmediate(w))}}rejectUnparsedCompletion(x,B){if(!this.currentRequest||!this.currentRequest.sent)return;let A=B&&B.parsedTag;if(!A){let f=x.toString("latin1",0,64).match(/^\0*([^\s\x00-\x1f\x7f]+)/);A=f&&f[1]}if(!A||A!==this.currentRequest.tag)return;let w=Error("Failed to parse the server response for this command");w.code=B.code||"ParserError",w.parserError=B,this.rejectCurrentRequest(w),this.trySend().catch((f)=>this.log.warn({err:f,cid:this.id}))}async handleResponse(x){let B;try{B=await sZ9(x.payload,{literals:x.literals})}catch(f){return this.log.error({src:"s",msg:x.payload.toString(),err:f,cid:this.id}),this.rejectUnparsedCompletion(x.payload,f),!0}if(B.tag&&!["*","+"].includes(B.tag)&&B.command){let f={response:B.command};if(B.attributes&&B.attributes[0]&&B.attributes[0].section&&B.attributes[0].section[0]&&B.attributes[0].section[0].type==="ATOM")f.code=B.attributes[0].section[0].value;try{this.emit("response",f)}catch(D){this.log.warn({err:D,cid:this.id})}}let A=await fy(B,{isLogging:!0});if(/^\d+$/.test(B.command)&&B.attributes&&B.attributes[0]&&B.attributes[0].value==="FETCH")this.log.trace({src:"s",msg:A.toString(),cid:this.id,nullBytesRemoved:B.nullBytesRemoved});else this.log.debug({src:"s",msg:A.toString(),cid:this.id,nullBytesRemoved:B.nullBytesRemoved});if(B.tag==="+"&&this.currentRequest&&this.currentRequest.options&&typeof this.currentRequest.options.onPlusTag==="function"){try{await this.currentRequest.options.onPlusTag(B)}catch(f){this.log.warn({err:f,cid:this.id})}return!0}if(B.tag==="+"&&this.commandParts.length){let f=this.commandParts.shift();try{this.write(f),this.log.debug({src:"c",msg:`(* ${f.length}B continuation *)`,cid:this.id})}catch(D){this.log.warn({err:D,cid:this.id})}return!0}let w=B.attributes&&B.attributes.length&&B.attributes[0]&&!B.attributes[0].value&&B.attributes[0].section;if(w&&w.length&&w[0].type==="ATOM"&&typeof w[0].value==="string"){let f=this.getSectionHandler(w[0].value.toUpperCase().trim());if(f)try{await f(w.slice(1))}catch(D){this.log.warn({err:D,cid:this.id})}}if(B.tag==="*"&&B.command){let f=this.getUntaggedHandler(B.command,B.attributes);if(f)try{await f(B)}catch(D){return this.log.warn({err:D,cid:this.id}),!0}}if(B.tag&&!["*","+"].includes(B.tag))if(this.currentRequest&&this.currentRequest.tag===B.tag&&this.currentRequest.sent){let f=this.requestTagMap.get(B.tag);if(this.requestTagMap.delete(B.tag),this.currentRequest=!1,f)await this.settleRequest(f,B,!!x.trailingAfterLine);try{await this.trySend()}catch(D){this.log.warn({err:D,cid:this.id})}}else if(this.requestTagMap.has(B.tag)){let f=this.requestTagMap.get(B.tag);this.requestTagMap.delete(B.tag);let D=Error("Server sent a tagged response for a command that was not in flight");return D.code="UnexpectedTag",D.details={received:B.tag,expected:this.currentRequest?this.currentRequest.tag:null},this.log.error({msg:"Protocol desynchronization",err:D,cid:this.id}),f.reject(D),this.failProtocol(D),!1}else this.countUnknownTag(B.tag);return!0}async settleRequest(x,B,A){switch((B.command||"").toUpperCase()){case"OK":case"BYE":await new Promise((w)=>x.resolve({response:B,next:w,hasTrailingData:A}));break;case"NO":case"BAD":{let w=B.attributes&&B.attributes.filter((D)=>D.type==="TEXT").map((D)=>D.value.trim()).join(" "),f=Error("Command failed");f.response=B,f.responseStatus=B.command.toUpperCase();try{f.executedCommand=B.tag+(await fy(x,{isLogging:!0})).toString()}catch{}if(w){if(f.responseText=w,f.responseStatus==="NO"&&w.includes("Some of the requested messages no longer exist")){this.log.warn({msg:"Partial FETCH response",cid:this.id,err:f}),await new Promise(($)=>x.resolve({response:B,next:$}));break}let D=!1;if(/Request is throttled/i.test(w)&&/Backoff Time/i.test(w)){let $=w.match(/Backoff Time[:=\s]+(\d+)/i);if($&&$[1]&&!isNaN($[1]))D=Number($[1])}if(D){f.code="ETHROTTLE",f.throttleReset=D;let $=D;if($>300000)$=300000;this.log.warn({msg:"Throttling detected",cid:this.id,throttleDelay:D,delayResponse:$,err:f});let Z=await new Promise((Q)=>{this._throttleAbort=Q,this._throttleTimer=setTimeout(()=>Q(!1),$),I40(this._throttleTimer)});if(this._throttleTimer=null,this._throttleAbort=null,Z){x.reject(this.createNoConnectionError(this.byeReason));break}}}x.reject(f);break}default:{let w=Error("Invalid server response");w.code="InvalidResponse",w.response=B,x.reject(w);break}}}setEventHandlers(){this.socketReadable=()=>{if(!this.reading)this.reading=!0,this.reader().catch((x)=>this.log.error({err:x,cid:this.id})).finally(()=>{this.reading=!1})},this.streamer.on("readable",this.socketReadable)}configureSocket(x){if(!x)return;if(typeof x.setKeepAlive==="function")x.setKeepAlive(!0,5000);if(typeof x.setTimeout==="function")x.setTimeout(this.socketTimeout)}setSocketHandlers(){if(this.clearSocketHandlers(),this._socketError=this._socketError||((x)=>{this.log.error({err:x,cid:this.id}),this.emitError(x)}),this._socketClose=this._socketClose||(()=>this.close()),this._socketEnd=this._socketEnd||(()=>this.close()),this._socketTimeout=this._socketTimeout||(()=>{let x=Error("Socket timeout");if(x.code="ETIMEOUT",this.idling){if(!this.usable||!this.socket||this.socket.destroyed){this.emitError(x);return}this.run("NOOP").then(()=>this.idle()).catch((B)=>{if(this.log.warn({msg:"IDLE recovery failed after timeout",err:B,cid:this.id}),!this.isClosed)this.close()})}else this.log.debug({msg:"Socket timeout",cid:this.id}),this.emitError(x)}),this.socket.once("error",this._socketError),this.socket.once("close",this._socketClose),this.socket.once("end",this._socketEnd),this.socket.on("tlsClientError",this._socketError),this.socket.on("timeout",this._socketTimeout),this.writeSocket&&this.writeSocket!==this.socket)this.writeSocket.on("error",this._socketError)}clearSocketHandlers(){if(!this.socket)return;if(this._connectErrorHandler)this.socket.removeListener("error",this._connectErrorHandler),this._connectErrorHandler=null;if(this._socketError){if(this.socket.removeListener("error",this._socketError),this.socket.removeListener("tlsClientError",this._socketError),this.writeSocket&&this.writeSocket!==this.socket)this.writeSocket.removeListener("error",this._socketError)}if(this._socketTimeout)this.socket.removeListener("timeout",this._socketTimeout);if(this._socketClose)this.socket.removeListener("close",this._socketClose);if(this._socketEnd)this.socket.removeListener("end",this._socketEnd)}async startSession(){if(await this.run("CAPABILITY"),this.capabilities.has("ID"))this.idRequested=await this.run("ID",this.clientInfo);if(await this.upgradeToSTARTTLS(),await this.authenticate(),(!this.idRequested||Object.keys(this.idRequested).length<2)&&this.capabilities.has("ID"))this.idRequested=await this.run("ID",this.clientInfo);let x=await this.run("NAMESPACE");if(x&&x.error&&x.status==="BAD"&&/User is authenticated but not connected/i.test(x.text)){this.authenticated=!1;let B=new uq("Authentication failed");throw B.response=x.text,B}if(this.options.verifyOnly){if(this.options.includeMailboxes)this._mailboxList=await this.list();return await this.logout()}if(!this.options.disableCompression)await this.compress();if(!this.options.disableAutoEnable)await this.autoEnable();this.usable=!0}async autoEnable(){let x=["CONDSTORE","UTF8=ACCEPT"].concat(this.options.qresync?"QRESYNC":[]).concat(this.options.disableIMAP4rev2?[]:"IMAP4rev2");if(await this.run("ENABLE",x)===!1&&x.includes("IMAP4rev2"))await this.run("ENABLE",x.filter((A)=>A!=="IMAP4rev2"))}async compress(){if(!await this.run("COMPRESS"))return;this._deflate=wy.createDeflateRaw({windowBits:15,level:wy.constants.Z_DEFAULT_COMPRESSION,memLevel:8,strategy:wy.constants.Z_DEFAULT_STRATEGY,chunkSize:16384}),this._inflate=wy.createInflateRaw({chunkSize:16384}),this.socket.unpipe(this.streamer),this.streamer.compress=!0,this.socket.pipe(this._inflate).pipe(this.streamer),this._inflate.on("error",(w)=>{if(!this.streamer.destroyed&&this.streamer.listenerCount("error"))this.streamer.emit("error",w)}),this.writeSocket=new ukx({highWaterMark:65536}),this.writeSocket.destroySoon=()=>{try{if(this.socket)this.socket.destroy();this.writeSocket.end()}catch(w){throw this.log.error({err:w,info:"Failed to destroy PassThrough socket",cid:this.id}),w}};let x=!1,B=0,A=async()=>{try{x=!0,B=0;let w;while(this.writeSocket&&(w=this.writeSocket.read())!==null){if(this._deflate&&this._deflate.write(w)===!1)return this._deflate.once("drain",A);if(B++,B%100===0){if(await new Promise((f)=>setImmediate(f)),!this.writeSocket)break}}if(this._deflate)this._deflate.flush();x=!1}catch(w){this.emitError(w)}};this.writeSocket.on("readable",()=>{if(!x&&this.writeSocket)A()}),this.writeSocket.on("error",(w)=>{if(this.socket)this.socket.emit("error",w)}),this._deflate.pipe(this.socket),this._deflate.on("error",(w)=>{if(this.socket)this.socket.emit("error",w)})}_failSTARTTLS(){if(this.options.doSTARTTLS===!0){let x=Error("Server does not support STARTTLS");throw x.tlsFailed=!0,x}return!1}async upgradeToSTARTTLS(){if(this.options.doSTARTTLS===!0&&this.options.secure===!0)throw Error("Misconfiguration: Cannot set both secure=true for TLS and doSTARTTLS=true for STARTTLS.");if(this.secureConnection)return!0;if(this.options.doSTARTTLS===!1)return!1;if(!this.capabilities.has("STARTTLS"))return this._failSTARTTLS();if(this.expectCapabilityUpdate=!0,!await this.run("STARTTLS"))return this._failSTARTTLS();let B=()=>{let f=Error("Server sent data after the STARTTLS response and before the TLS handshake; possible plaintext-injection attack");return f.code="STARTTLS_INJECTION",f.tlsFailed=!0,this.closeAfter(),f};if(this._starttlsHadTrailingData)throw B();this.socket.unpipe(this.streamer);let A=typeof this.socket.read==="function"?this.socket.read():null;if(A&&A.length)throw B();let w=await new Promise((f,D)=>{let $=this.socket,Z=Object.assign({socket:this.socket,servername:this.servername,port:this.port},this.options.tls||{});this.clearSocketHandlers();let Q=!1,Y=(W,H)=>{if(Q)return;if(Q=!0,clearTimeout(this.upgradeTimeout),this.upgradeTimeout=null,this.upgrading=!1,this._upgradeReject=null,$.removeListener("error",Y),this.socket&&this.socket!==$)this.socket.removeListener("error",Y);if(W)return clearTimeout(this.connectTimeout),W.tlsFailed=!0,this.closeAfter(),D(W);f(H)};this._upgradeReject=Y,$.once("error",Y),this.upgradeTimeout=setTimeout(()=>{let W=Error("Failed to upgrade connection in required time");W.code="UPGRADE_TIMEOUT",Y(W)},1e4),this.upgrading=!0,this.socket=Ckx.connect(Z,()=>{try{if(this.isClosed){let W=Error("Connection closed during TLS upgrade");return W.code="NoConnection",Y(W)}if(this.secureConnection=!0,this.streamer.secureConnection=!0,this.socket.pipe(this.streamer),this.tls=typeof this.socket.getCipher==="function"?this.socket.getCipher():!1,this.tls)this.tls.authorized=this.socket.authorized,this.log.info({src:"tls",msg:"Established TLS session",cid:this.id,authorized:this.tls.authorized,algo:this.tls.standardName||this.tls.name,version:this.tls.version});if(typeof $.setTimeout==="function")$.setTimeout(0);this.setSocketHandlers(),this.configureSocket(this.socket),Y(null,!0)}catch(W){this.emitError(W)}}),this.socket.once("error",Y),this.writeSocket=this.socket});if(w)this.clearCapabilities(),await this.run("CAPABILITY");return w}async setAuthenticationState(){if(this.state=this.states.AUTHENTICATED,this.authenticated=!0,this.expectCapabilityUpdate)await this.run("CAPABILITY")}async authenticate(){if(this.state===this.states.LOGOUT)throw new uq("Already logged out");if(this.state!==this.states.NOT_AUTHENTICATED)return!0;if(!this.options.auth)throw new uq("Please configure the login");this.expectCapabilityUpdate=!0;let x=(this.options.auth.loginMethod||"").toString().trim().toUpperCase();if(!x&&/\\|\//.test(this.options.auth.user))x="LOGIN";if(this.options.auth.accessToken)this.authenticated=await this.run("AUTHENTICATE",this.options.auth.user,{accessToken:this.options.auth.accessToken});else if(this.options.auth.pass)if((this.capabilities.has("AUTH=LOGIN")||this.capabilities.has("AUTH=PLAIN"))&&x!=="LOGIN")this.authenticated=await this.run("AUTHENTICATE",this.options.auth.user,{password:this.options.auth.pass,loginMethod:x,authzid:this.options.auth.authzid});else{if(this.capabilities.has("LOGINDISABLED"))throw new uq("Login is disabled");this.authenticated=await this.run("LOGIN",this.options.auth.user,this.options.auth.pass)}else throw new uq("No password configured");if(this.authenticated)return this.log.info({src:"auth",msg:"User authenticated",cid:this.id,user:this.options.auth.user}),await this.setAuthenticationState(),!0;throw new uq("No matching authentication method")}beginSession(x){if(clearTimeout(this.greetingTimeout),this.untaggedHandlers.OK=null,this.untaggedHandlers.PREAUTH=null,this.isClosed)return;this.startSession().then(()=>{if(typeof this.initialResolve==="function"){let B=this.initialResolve;return this.initialResolve=!1,this.initialReject=!1,B()}}).catch((B)=>{if(this.log.error({err:B,cid:this.id}),typeof this.initialReject==="function"){clearTimeout(this.greetingTimeout);let A=this.initialReject;return this.initialResolve=!1,this.initialReject=!1,A(B)}x(B)})}async initialOK(x){this.greeting=(x.attributes||[]).filter((B)=>B.type==="TEXT").map((B)=>B.value).filter((B)=>B).join(""),this.beginSession((B)=>this.emitError(B))}async initialPREAUTH(){if(this.isClosed)return;this.state=this.states.AUTHENTICATED,this.authenticated=!0,this.beginSession((x)=>{this.log.error({err:x,cid:this.id}),this.closeAfter()})}async serverBye(x){let B=x&&x.attributes&&x.attributes.filter((A)=>A.type==="TEXT").map((A)=>A.value.trim()).join(" ");this.byeReason=B||"Server closed connection",this.untaggedHandlers.BYE=null,this.state=this.states.LOGOUT}clearCapabilities(){this.capabilities.clear(),this.authCapabilities.clear(),this.rawCapabilities=null}updateCapabilitiesFromRaw(x){if(this.rawCapabilities=x,this.capabilities=BQ9(x),this.capabilities){for(let[B]of this.capabilities)if(/^AUTH=/i.test(B)&&!this.authCapabilities.has(B.toUpperCase()))this.authCapabilities.set(B.toUpperCase(),!1)}if(this.expectCapabilityUpdate)this.expectCapabilityUpdate=!1}async sectionCapability(x){this.updateCapabilitiesFromRaw(x)}async untaggedCapability(x){this.updateCapabilitiesFromRaw(x.attributes)}async untaggedExists(x){if(!this.mailbox)return;if(!x||!x.command||isNaN(x.command))return;let B=Number(x.command);if(B===this.mailbox.exists)return;let A=this.mailbox.exists;this.mailbox.exists=B,this.emit("exists",{path:this.mailbox.path,count:B,prevCount:A})}async untaggedExpunge(x){if(!this.mailbox)return;if(!x||!x.command||isNaN(x.command))return;let B=Number(x.command);if(B&&B<=this.mailbox.exists){this.mailbox.exists--;let A={path:this.mailbox.path,seq:B,vanished:!1};if(typeof this.options.expungeHandler==="function")try{await this.options.expungeHandler(A)}catch(w){this.log.error({msg:"Failed to notify expunge event",payload:A,error:w,cid:this.id})}else this.emit("expunge",A)}}async untaggedVanished(x,B){if(B=B||this.mailbox,!B)return;let A=[],w=!1;if(x.attributes.length>1&&Array.isArray(x.attributes[0]))A=x.attributes[0].map((D)=>typeof D.value==="string"?D.value.toUpperCase():!1).filter((D)=>D),x.attributes.shift();if(x.attributes[0]&&typeof x.attributes[0].value==="string")w=x.attributes[0].value;let f=$Q9(w);for(let D of f){let $={path:B.path,uid:D,vanished:!0,earlier:A.includes("EARLIER")};if(typeof this.options.expungeHandler==="function")try{await this.options.expungeHandler($)}catch(Z){this.log.error({msg:"Failed to notify expunge event",payload:$,error:Z,cid:this.id})}else this.emit("expunge",$)}}async untaggedFetch(x,B){if(B=B||this.mailbox,!B)return;let A=await wQ9(x,B);if(A.flags){let w={path:B.path,seq:A.seq};if(A.uid)w.uid=A.uid;if(A.modseq)w.modseq=A.modseq;if(w.flags=A.flags,A.flagColor)w.flagColor=A.flagColor;this.emit("flags",w)}}async ensureSelectedMailbox(x){if(!x)return!1;if(!this.mailbox||!xQ9(this,this.mailbox.path,x))return await this.mailboxOpen(x);return!0}async resolveRange(x,B){if(typeof x==="number"||typeof x==="bigint")x=x.toString();if(x==="*"){if(!this.mailbox.exists)return!1;x=this.mailbox.exists.toString(),B.uid=!1}if(x&&typeof x==="object"&&!Array.isArray(x)){if(x.all&&Object.keys(x).length===1)x="1:*";else if(x.uid&&Object.keys(x).length===1)x=x.uid,B.uid=!0;else if(B.uid=!0,x=await this.run("SEARCH",x,B),x&&x.length)x=Skx(x)}if(Array.isArray(x))x=x.join(",");if(!x)return!1;return x}autoidle(){if(clearTimeout(this.idleStartTimer),this.options.disableAutoIdle||this.state!==this.states.SELECTED)return;this.idleStartTimer=setTimeout(()=>{this.idle().catch((x)=>this.log.warn({err:x,cid:this.id}))},15000),I40(this.idleStartTimer)}async connect(){if(this._connectCalled)throw Error("Can not re-use ImapFlow instance");this._connectCalled=!0;let x=new eZ9(this.options.connectionTimeout),B=this.secureConnection?Ckx:ckx,A=Object.assign({host:this.host,servername:this.servername,port:this.port},this.options.tls||{});this.untaggedHandlers.OK=(...D)=>this.initialOK(...D),this.untaggedHandlers.BYE=(...D)=>this.serverBye(...D),this.untaggedHandlers.PREAUTH=(...D)=>this.initialPREAUTH(...D),this.untaggedHandlers.CAPABILITY=(...D)=>this.untaggedCapability(...D),this.sectionHandlers.CAPABILITY=(...D)=>this.sectionCapability(...D),this.untaggedHandlers.EXISTS=(...D)=>this.untaggedExists(...D),this.untaggedHandlers.EXPUNGE=(...D)=>this.untaggedExpunge(...D),this.untaggedHandlers.FETCH=(D)=>this.untaggedFetch(D),this.untaggedHandlers.VANISHED=(D)=>this.untaggedVanished(D);let w=!1;if(this.options.proxy)try{if(w=await oZ9(this.log,this.options.proxy,this.host,this.port,{deadline:x}),!w)throw Error("Failed to setup proxy connection")}catch(D){if(D.code==="CONNECT_TIMEOUT")throw this.log.error({err:D,cid:this.id}),D;let $=Error("Failed to setup proxy connection");throw $.code=D.code||"ProxyError",$._err=D,this.log.error({error:$,cid:this.id}),$}let f=new Promise((D,$)=>{this.connectTimeout=setTimeout(()=>{let Q=x.error();this.log.error({err:Q,cid:this.id}),this.closeAfter(),$(Q)},x.remaining());let Z=()=>{try{clearTimeout(this.connectTimeout),tZ9(w),this.configureSocket(this.socket),this.greetingTimeout=setTimeout(()=>{let Y=Error(`Failed to receive greeting from server in required time${!this.secureConnection?". Maybe should use TLS?":""}`);Y.code="GREETING_TIMEOUT",Y.details={greetingTimeout:this.options.greetingTimeout||16000},this.log.error({err:Y,cid:this.id}),this.closeAfter(),$(Y)},this.options.greetingTimeout||16000),this.tls=typeof this.socket.getCipher==="function"?this.socket.getCipher():!1;let Q={src:"connection",msg:`Established ${this.tls?"secure ":""}TCP connection`,cid:this.id,secure:!!this.tls,host:this.host,servername:this.servername,port:this.socket.remotePort,address:this.socket.remoteAddress,localAddress:this.socket.localAddress,localPort:this.socket.localPort};if(this.tls)Q.authorized=this.tls.authorized=this.socket.authorized,Q.algo=this.tls.standardName||this.tls.name,Q.version=this.tls.version;this.log.info(Q),this.setSocketHandlers(),this.setEventHandlers(),this.socket.pipe(this.streamer),this.initialResolve=D,this.initialReject=$}catch(Q){$(Q)}};if(w)if(this.secureConnection)A.socket=w,this.socket=B.connect(A,Z);else this.socket=w,setImmediate(Z);else this.socket=B.connect(A,Z);this.writeSocket=this.socket,this._connectErrorHandler=(Q)=>{clearTimeout(this.connectTimeout),clearTimeout(this.greetingTimeout),this.closeAfter(),this.log.error({err:Q,cid:this.id}),$(Q)},this.socket.on("error",this._connectErrorHandler)});f.catch(x_),await f}async logout(){return await this.run("LOGOUT")}closeAfter(){setImmediate(()=>this.close())}createNoConnectionError(x){let B=Error("Connection not available");if(B.code="NoConnection",x)B.reason=x;return B}close(){try{if(clearTimeout(this.idleStartTimer),clearTimeout(this.upgradeTimeout),clearTimeout(this.connectTimeout),clearTimeout(this.greetingTimeout),clearTimeout(this._throttleTimer),this._throttleTimer=null,typeof this._throttleAbort==="function")this._throttleAbort(!0),this._throttleAbort=null;if(this.usable=!1,this._idleSession=null,this.idling=!1,typeof this._upgradeReject==="function"){let f=this._upgradeReject;this._upgradeReject=null;let D=Error("Connection closed during TLS upgrade");D.code="NoConnection",f(D)}if(typeof this.initialReject==="function"&&!this.options.verifyOnly){clearTimeout(this.greetingTimeout);let f=this.initialReject;this.initialResolve=!1,this.initialReject=!1;let D=Error("Unexpected close");if(D.code=`ClosedAfterConnect${this.secureConnection?"TLS":"Text"}`,this.byeReason)D.reason=this.byeReason;f(D)}if(typeof this.preCheck==="function")this.preCheck().catch((f)=>this.log.warn({err:f,cid:this.id}));let x=!1;if(!this.isClosed){if(x=this.mailbox,this.mailbox=!1,this.currentSelectCommand=!1,!this.options.verifyOnly)this.authenticated=!1;this.preCheck=!1}let B=[];if(this.currentRequest&&this.requestTagMap.has(this.currentRequest.tag)){let f=this.currentRequest.tag,D=this.requestTagMap.get(f);if(D)this.requestTagMap.delete(f),B.push(D);this.currentRequest=!1}while(this.requestQueue.length){let f=this.requestQueue.shift();if(f&&this.requestTagMap.has(f.tag)){let D=this.requestTagMap.get(f.tag);if(D)this.requestTagMap.delete(f.tag),B.push(D)}}let A=(f)=>this.createNoConnectionError(f),w=this.byeReason;for(let f of B)f.reject(A(w));if(this.currentLock&&this.currentLock.heldWarnTimer)clearTimeout(this.currentLock.heldWarnTimer),this.currentLock.heldWarnTimer=null;if(this.currentLock=!1,this.locks&&this.locks.length){let f=this.locks.splice(0);for(let D of f){if(D.acquireTimer)clearTimeout(D.acquireTimer),D.acquireTimer=null;if(typeof D.reject==="function")D.reject(A(w))}}if(this._inflate)try{this._inflate.unpipe(),this._inflate.destroy(),this._inflate=null}catch(f){this.log.error({err:f,info:"Failed to destroy inflate stream",cid:this.id})}if(this._deflate)try{this._deflate.unpipe(),this._deflate.destroy(),this._deflate=null}catch(f){this.log.error({err:f,info:"Failed to destroy deflate stream",cid:this.id})}if(this.streamer)try{if(this.socketReadable)this.streamer.removeListener("readable",this.socketReadable);if(this._streamerErrorHandler)this.streamer.removeListener("error",this._streamerErrorHandler);if(!this.streamer.destroyed)this.streamer.destroy()}catch(f){this.log.error({err:f,info:"Failed to cleanup streamer",cid:this.id})}if(this.clearSocketHandlers(),this.folders.clear(),this.requestTagMap.clear(),this.state=this.states.LOGOUT,this.isClosed)return;if(this.isClosed=!0,this.writeSocket&&this.writeSocket!==this.socket&&!this.writeSocket.destroyed)try{this.writeSocket.destroy()}catch(f){this.log.error({err:f,cid:this.id})}if(this.socket&&!this.socket.destroyed)try{this.socket.destroy()}catch(f){this.log.error({err:f,cid:this.id})}if(this.socket=null,this.writeSocket=null,this._inflate=null,this._deflate=null,this._streamerErrorHandler=null,this._connectErrorHandler=null,this._socketError=null,this._socketClose=null,this._socketEnd=null,this._socketTimeout=null,this.log.trace({msg:"Connection closed",cid:this.id,...this._unknownTagCount?{unknownTagCount:this._unknownTagCount}:{}}),x)this.emit("mailboxClose",x);this.emit("close")}catch(x){this.log.error(x)}}async getQuota(x){return x=x||"INBOX",await this.run("QUOTA",x)}async list(x){x=x||{};let B=await this.run("LIST","","*",x);return this.folders=new Map(B.map((A)=>[A.path,A])),B}async listTree(x){x=x||{};let B=await this.run("LIST","","*",x);return this.folders=new Map(B.map((A)=>[A.path,A])),AQ9(B)}async noop(){await this.run("NOOP")}async mailboxCreate(x){return await this.run("CREATE",x)}async mailboxRename(x,B){return await this.run("RENAME",x,B)}async mailboxDelete(x){return await this.run("DELETE",x)}async mailboxSubscribe(x){return await this.run("SUBSCRIBE",x)}async mailboxUnsubscribe(x){return await this.run("UNSUBSCRIBE",x)}async mailboxOpen(x,B){return await this.run("SELECT",x,B)}async mailboxClose(){return await this.run("CLOSE")}async status(x,B){return await this.run("STATUS",x,B)}async idle(){if(!this.idling)return await this.run("IDLE",this.maxIdleTime)}async messageFlagsSet(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=Object.assign({operation:"set"},A);return await this.run("STORE",x,B,w)}async messageFlagsAdd(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=Object.assign({operation:"add"},A);return await this.run("STORE",x,B,w)}async messageFlagsRemove(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=Object.assign({operation:"remove"},A);return await this.run("STORE",x,B,w)}async setFlagColor(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=ZQ9(B);if(!w)return!1;let f,D;if(w.add&&w.add.length){let $=Object.assign({operation:"add"},A,{useLabels:!1,silent:w.remove&&w.remove.length});f=await this.run("STORE",x,w.add,$)}if(w.remove&&w.remove.length){let $=Object.assign({operation:"remove"},A,{useLabels:!1});D=await this.run("STORE",x,w.remove,$)}return f||D||!1}async messageDelete(x,B){if(B=B||{},x=await this.resolveRange(x,B),!x)return!1;return await this.run("EXPUNGE",x,B)}async append(x,B,A,w){return await this.run("APPEND",x,B,A,w)||!1}async messageCopy(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;return await this.run("COPY",x,B,A)}async messageMove(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;return await this.run("MOVE",x,B,A)}async search(x,B){if(!this.mailbox)return;let A=await this.run("SEARCH",x,B)||!1;if(B&&B.returnOptions&&Array.isArray(A)){let w=A,f=B.returnOptions.map(($)=>typeof $==="string"?$.toUpperCase():$),D={};if(f.includes("COUNT"))D.count=w.length;if(f.includes("MIN")&&w.length)D.min=w[0];if(f.includes("MAX")&&w.length)D.max=w[w.length-1];if(f.includes("ALL")&&w.length)D.all=Skx(w);if(Object.keys(D).length===0)return A;return D}return A}async*fetch(x,B,A){if(A=A||{},!this.mailbox)return;if(x=await this.resolveRange(x,A),!x)return!1;let w=!1,f=!1,D=!1,$=[],Z=()=>new Promise((Y,W)=>{let H=()=>{if($.length){let F=$.shift();if(F.err)return W(F.err);return Y(F.value)}if(w)return Y(null);D=()=>{D=!1,H()}};H()});this.run("FETCH",x,B,{uid:!!A.uid,binary:A.binary,changedSince:A.changedSince,onUntaggedFetch:(Y,W)=>{if(f){W();return}if($.push({value:{response:Y,next:W}}),typeof D==="function")D()}}).then(()=>{if(w=!0,typeof D==="function")D()}).catch((Y)=>{if($.push({err:Y}),typeof D==="function")D()});let Q=null;try{let Y;while(Y=await Z()){if(Q=Y,this.isClosed||!this.socket||this.socket.destroyed){let W=Error("Connection closed");throw W.code="EConnectionClosed",W}yield Y.response,Y.next(),Q=null}}finally{if(f=!0,Q&&typeof Q.next==="function")Q.next();while($.length){let Y=$.shift();if(Y.value&&typeof Y.value.next==="function")Y.value.next()}}}async fetchAll(x,B,A){let w=[],f=this.fetch(x,B,A);for await(let D of f)w.push(D);return w}async fetchOne(x,B,A){if(!this.mailbox)return;if(x==="*"){if(!this.mailbox.exists)return!1;x=this.mailbox.exists.toString(),A=Object.assign({},A||{},{uid:!1})}let w=await this.run("FETCH",(x||"").toString(),B,A);if(!w||!w.list||!w.list.length)return!1;return w.list[0]}async download(x,B,A){if(!this.mailbox)return{};A=Object.assign({chunkSize:65536,maxBytes:1/0},A||{});let w=!0,f=0,D=Number(A.chunkSize)||65536,$=Number(A.maxBytes)||1/0,Z=!1;if(B==="1"){let c=await this.fetchOne(x,{uid:!0,bodyStructure:!0},A);if(!c)return{response:!1,chunk:!1};if(!Z&&c.uid)Z=c.uid,x=Z,A.uid=!0;if(!c.bodyStructure.childNodes)B="TEXT"}let Q=async(c)=>{c=c||{};let n;if(!B)c.source={start:f,maxLength:D};else{if(B=B.toString().toLowerCase().trim(),!c.bodyParts)c.bodyParts=[];if(c.size){if(/^[\d.]+$/.test(B))n=B+".mime",c.bodyParts.push(n);else if(B==="text")n="header",c.bodyParts.push(n)}c.bodyParts.push({key:B,start:f,maxLength:D})}let R=await this.fetchOne(x,c,A);if(!R)return{response:!1,chunk:!1};if(!Z&&R.uid)Z=R.uid,x=Z,A.uid=!0;let M=!B?R.source:R.bodyParts&&R.bodyParts.get(B);if(!M)return{};f+=M.length,w=M.length>=D;let B0={chunk:M};if(c.size)B0.response=R;if(c.bodyParts)if(n==="header")B0.mime=R.headers;else B0.mime=R.bodyParts.get(n);return B0},{response:Y,chunk:W,mime:H}=await Q({size:!0,uid:!0});if(!Y||!W)return{};let F={expectedSize:Y.size};if(!B)F.contentType="message/rfc822";else if(H){let c=new gkx(H),n=Bw.parseHeaderValue(c.getFirst("Content-Type")),R=Bw.parseHeaderValue(c.getFirst("Content-Transfer-Encoding")),M=Bw.parseHeaderValue(c.getFirst("Content-Disposition"));if(n.value.toLowerCase().trim())F.contentType=n.value.toLowerCase().trim();if(n.params.charset)F.charset=n.params.charset.toLowerCase().trim();if(R.value)F.encoding=R.value.replace(/\(.*\)/g,"").toLowerCase().trim();if(M.value){F.disposition=M.value.toLowerCase().trim()||!1;try{F.disposition=Bw.decodeWords(F.disposition)}catch{}}if(n.params.format&&n.params.format.toLowerCase().trim()==="flowed"){if(F.flowed=!0,n.params.delsp&&n.params.delsp.toLowerCase().trim()==="yes")F.delSp=!0}let B0=M.params.filename||n.params.name||!1;if(B0){try{B0=Bw.decodeWords(B0)}catch{}F.filename=B0}}let K,q,V=!1;switch(Y.binaryParts&&Y.binaryParts.has(B)?!1:F.encoding){case"base64":q=K=new pkx.Decoder;break;case"quoted-printable":q=K=new Tkx.Decoder;break;default:q=K=new ukx}let G=["text/html","text/plain","text/x-amp-html"].includes(F.contentType)||B==="1"&&!F.contentType;if((!F.disposition||F.disposition==="inline")&&G){if(F.flowed){let c=new rZ9({delSp:F.delSp});q.on("error",(n)=>{c.emit("error",n)}),q=q.pipe(c)}if(F.charset&&!["ascii","usascii","utf8"].includes(F.charset.toLowerCase().replace(/[^a-z0-9]+/g,"")))try{let c=fQ9(F.charset);c.on("error",(n)=>{this.log.warn({err:n,charset:F.charset,cid:this.id})}),q.on("error",(n)=>{c.emit("error",n)}),q=q.pipe(c),F.charset="utf-8"}catch{}}let E=new dZ9({maxBytes:$});q.on("error",(c)=>{E.emit("error",c)}),q=q.pipe(E);let _=()=>{if(V=!0,K&&!K.destroyed)K.destroy()};q.once("error",_),q.once("close",_);let L=(c)=>{if(E.limited||V||K.destroyed)return!0;return K.write(c)},N=async()=>{while(w&&!E.limited&&!V){let{chunk:c}=await Q();if(!c||V)break;if(L(c)===!1){try{await new Promise((n,R)=>{let M=!1,B0=(G0)=>{if(M)return;if(M=!0,K.removeAllListeners("drain"),K.removeAllListeners("error"),K.removeAllListeners("close"),G0)R(G0);else n()};K.once("drain",()=>B0()),K.once("error",(G0)=>B0(G0)),K.once("close",()=>B0())})}catch(n){if(!V)throw n}if(V)break}}},y=()=>{N().catch((c)=>{if(!V&&K&&!K.destroyed)K.emit("error",c);else this.log.warn({msg:"Download error after stream closed",err:c,fetchAborted:V,streamDestroyed:K?.destroyed,cid:this.id})}).finally(()=>{if(!V&&K&&!K.destroyed)K.end()})};return setImmediate(()=>{let c;try{c=L(W)}catch(n){if(K.emit("error",n),!V&&K&&!K.destroyed)K.end();return}if(!c)K.once("drain",()=>{if(!V)y()});else y()}),{meta:F,content:q}}async downloadMany(x,B,A){if(!this.mailbox)return{};A=Object.assign({chunkSize:65536,maxBytes:1/0},A||{});let w={bodyParts:[]};for(let $ of B)w.bodyParts.push($+".mime"),w.bodyParts.push($);let f=await this.fetchOne(x,w,A);if(!f||!f.bodyParts)return{response:!1};let D={};for(let[$,Z]of f.bodyParts){let Q=$.split(".mime");if(Q.length===1){let Y=Q[0];if(!D[Y])D[Y]={content:Z};else D[Y].content=Z}else if(Q.length===2){let Y=Q[0];if(!D[Y])D[Y]={};if(!D[Y].meta)D[Y].meta={};let W=new gkx(Z),H=Bw.parseHeaderValue(W.getFirst("Content-Type")),F=Bw.parseHeaderValue(W.getFirst("Content-Transfer-Encoding")),K=Bw.parseHeaderValue(W.getFirst("Content-Disposition"));if(H.value.toLowerCase().trim())D[Y].meta.contentType=H.value.toLowerCase().trim();if(H.params.charset)D[Y].meta.charset=H.params.charset.toLowerCase().trim();if(F.value)D[Y].meta.encoding=F.value.replace(/\(.*\)/g,"").toLowerCase().trim();if(K.value){D[Y].meta.disposition=K.value.toLowerCase().trim()||!1;try{D[Y].meta.disposition=Bw.decodeWords(D[Y].meta.disposition)}catch{}}if(H.params.format&&H.params.format.toLowerCase().trim()==="flowed"){if(D[Y].meta.flowed=!0,H.params.delsp&&H.params.delsp.toLowerCase().trim()==="yes")D[Y].meta.delSp=!0}let q=K.params.filename||H.params.name||!1;if(q){try{q=Bw.decodeWords(q)}catch{}D[Y].meta.filename=q}}}for(let $ of Object.keys(D)){let Z=D[$].meta;switch(f.binaryParts&&f.binaryParts.has($)?!1:Z.encoding){case"base64":D[$].content=D[$].content?pkx.decode(D[$].content.toString()):null;break;case"quoted-printable":D[$].content=D[$].content?Tkx.decode(D[$].content.toString()):null;break;default:}}return D}async run(x,...B){if(x=x.toUpperCase(),!this.commands.has(x))return!1;if(!this.socket||this.socket.destroyed)throw this.createNoConnectionError();if(clearTimeout(this.idleStartTimer),typeof this.preCheck==="function")await this.preCheck();let A=await this.runInternal(x,...B);if(x!=="IDLE")this.autoidle();return A}async runInternal(x,...B){if(x=x.toUpperCase(),!this.commands.has(x))return!1;if(!this.socket||this.socket.destroyed)throw this.createNoConnectionError();return await this.commands.get(x)(this,...B)}async processLocks(){if(this.processingLock){this.log.trace({msg:"Mailbox locking queued",path:this.mailbox&&this.mailbox.path,pending:this.locks.length,idling:this.idling,activeLock:this.currentLock?{lockId:this.currentLock.lockId,...this.currentLock.options?.description&&{description:this.currentLock.options?.description}}:null});return}this.processingLock=!0;try{let B=0;while(this.locks.length>0){if(this.currentLock)break;if(B++,B%5===0)await new Promise((W)=>setImmediate(W));let A=this.locks.shift(),{resolve:w,reject:f,path:D,options:$,lockId:Z}=A;if(A.acquireTimer)clearTimeout(A.acquireTimer),A.acquireTimer=null;let Q=()=>{let W=Number($.maxLockHoldTime??this.options.maxLockHoldTime??1800000);if(!W||W<=0)return;A.heldAt=Date.now(),A.heldWarnTimer=setTimeout(()=>{A.heldWarnTimer=null,this.log.warn({msg:"Mailbox lock held for a long time",lockId:A.lockId,path:D,heldFor:Date.now()-A.heldAt,...$.description&&{description:$.description},cid:this.id})},W),I40(A.heldWarnTimer)},Y=()=>{if(this.currentLock===A){if(A.heldWarnTimer)clearTimeout(A.heldWarnTimer),A.heldWarnTimer=null;this.log.trace({msg:"Mailbox lock released",lockId:A.lockId,path:this.mailbox&&this.mailbox.path,pending:this.locks.length,idling:this.idling}),this.currentLock=!1,setImmediate(()=>{this.processLocks().catch((W)=>this.log.error({err:W,cid:this.id}))})}else this.log.trace({msg:"Ignoring stale lock release",lockId:A.lockId,cid:this.id})};if(!this.usable||!this.socket||this.socket.destroyed){this.log.trace({msg:"Failed to acquire mailbox lock",path:D,lockId:Z,idling:this.idling});let W=Error("Connection not available");W.code="NoConnection",f(W);continue}if(this.mailbox&&this.mailbox.path===D&&!!this.mailbox.readOnly===!!$.readOnly){this.log.trace({msg:"Mailbox lock acquired [existing]",path:D,lockId:Z,idling:this.idling,...$.description&&{description:$.description}}),this.currentLock=A,Q(),w({path:D,release:Y});break}try{await this.mailboxOpen(D,$),this.log.trace({msg:"Mailbox lock acquired [selected]",path:D,lockId:Z,idling:this.idling,...$.description&&{description:$.description}}),this.currentLock=A,Q(),w({path:D,release:Y});break}catch(W){if(W.responseStatus==="NO")try{let H=await this.run("LIST","",D,{listOnly:!0});if(!H||!H.length)W.mailboxMissing=!0}catch(H){this.log.trace({msg:"Failed to verify failed mailbox",path:D,err:H})}this.log.trace({msg:"Failed to acquire mailbox lock",path:D,lockId:Z,idling:this.idling,...$.description&&{description:$.description},err:W}),f(W)}}}finally{if(this.processingLock=!1,this.locks.length&&!this.currentLock)setImmediate(()=>{this.processLocks().catch((B)=>this.log.error({err:B,cid:this.id}))})}}getMailboxLock(x,B){B=B||{},x=DQ9(this,x);let A=++this.lockCounter;this.log.trace({msg:"Requesting lock",path:x,lockId:A,...B.description&&{description:B.description},activeLock:this.currentLock?{lockId:this.currentLock.lockId,...this.currentLock.options?.description&&{description:this.currentLock.options?.description}}:null});let w=new Promise((f,D)=>{let $={resolve:f,reject:D,path:x,options:B,lockId:A};if(this.locks.push($),Number(B.acquireTimeout)>0)$.acquireTimer=setTimeout(()=>{$.acquireTimer=null;let Z=this.locks.indexOf($);if(Z!==-1){this.locks.splice(Z,1);let Q=Error("Timed out waiting for mailbox lock");Q.code="LockTimeout",Q.lockId=$.lockId,D(Q)}},Number(B.acquireTimeout));this.processLocks().catch((Z)=>D(Z))});return w.catch(x_),w}getLogger(){let x=this.options.logger&&typeof this.options.logger==="object"?this.options.logger:nZ9.child({component:"imap-connection",cid:this.id}),B={},A=["trace","debug","info","warn","error","fatal"];for(let w of A)B[w]=(...f)=>{if(this.options.logger!==!1)if(typeof x[w]!=="function"){if(w==="fatal"||w==="error")console.log(JSON.stringify(...f))}else x[w](...f);if(this.emitLogs&&f&&f[0]&&typeof f[0]==="object"){let D=Object.assign({level:w,t:Date.now(),cid:this.id,lo:++this.lo},f[0]);if(D.err&&typeof D.err==="object"){let $=D.err;D.err={stack:$.stack},Object.keys($).forEach((Z)=>{D.err[Z]=$[Z]})}this.emit("log",D)}};return B}unbind(){if(this.socket.unpipe(this.streamer),this._inflate)this._inflate.unpipe(this.streamer);this.clearSocketHandlers();let x=this._inflate||this.socket,B=this.writeSocket||this.socket;if(this.socket!==x&&this.socket!==B)this.socket.on("error",(A)=>{this.log.debug({msg:"Suppressed error on unbound socket",err:A,cid:this.id})});return{readSocket:x,writeSocket:B,socket:this.socket}}}var O40=ikx;var INx=b7(vNx(),1);function ONx(x){let B=new O40({host:x.host,port:x.port,secure:!0,auth:{user:x.user,pass:x.password},disableAutoIdle:!0,maxIdleTime:x.pollIntervalMs,logger:!1});return{connect:async()=>{await B.connect()},selectMailbox:async(A)=>{return(await B.mailboxOpen(A,{readOnly:!0})).uidValidity.toString()},fetchMessages:async function*(A){let w=B.fetch(`${A}:*`,{uid:!0,source:!0,internalDate:!0,threadId:!0},{uid:!0});for await(let f of w){if(f.uid<A)continue;if(!f.source||!f.internalDate)throw Error("Inbound email source was incomplete");yield{uid:f.uid,source:f.source,receivedAt:new Date(f.internalDate),...f.threadId?{threadId:f.threadId}:{}}}},waitForChanges:(A)=>{if(A.aborted)return Promise.reject(A.reason);return new Promise((w,f)=>{let D=!1,$=()=>{B.off("exists",Z),B.off("close",Q),B.off("error",Q),A.removeEventListener("abort",Y)},Z=()=>{if(D)return;D=!0,$(),w()},Q=()=>{if(D)return;D=!0,$(),f(Error("Inbound email IDLE failed"))},Y=()=>{B.close(),Q()};B.on("exists",Z),B.on("close",Q),B.on("error",Q),A.addEventListener("abort",Y,{once:!0}),B.idle().then(Z,Q)})},disconnect:async()=>{if(B.usable)await B.logout();else B.close()}}}function hNx(x,B){let A=JSON.stringify({mailbox:x.mailbox,uidValidity:x.uidValidity,uid:B});return`imap:${S6(A)}`}async function RNx(x,B,A){let{cursor:w,publish:f,resolveSender:D,logger:$}=A,Z=await w.get("cursor"),Q=Z!==null&&Z.mailbox===B.mailbox&&Z.uidValidity===B.uidValidity,Y=Q?Z.lastUid:0;if(!Q)await w.set("cursor",{...B,lastUid:0});let W=Y,H=0;for await(let F of x.fetchMessages(Y+1)){if(F.uid<=W)continue;let K;try{K=await Rq9(F,hNx(B,F.uid))}catch{$.warn("Inbound email message could not be parsed",{uid:F.uid}),await w.set("cursor",{...B,lastUid:F.uid}),W=F.uid;continue}if(D)try{let V=await D(K.from.address);if(V)K={...K,sender:V}}catch{$.warn("Inbound email sender resolution failed",{messageKey:S6(K.messageId)})}let q=!1;try{let V=await f({type:H_,payload:K});q="success"in V&&V.success}catch{}if(!q){$.warn("Inbound email event was not acknowledged",{messageKey:S6(K.messageId)});break}await w.set("cursor",{...B,lastUid:F.uid}),W=F.uid,H+=1,$.debug("Inbound email event published",{messageKey:S6(K.messageId)})}return H}async function Rq9(x,B){let A=await INx.simpleParser(Buffer.from(x.source),{skipImageLinks:!0}),w=mq9(A.from);if(!w)throw Error("Inbound email sender was missing");let f=yq9(A.messageId,x.source),D=typeof A.html==="string"?A.html:void 0,$={messageId:f,sourceRef:B,...x.threadId?{threadId:x.threadId}:{},from:w,to:yNx(A.to),subject:A.subject??"",receivedAt:x.receivedAt.toISOString(),text:A.text??"",...D?{html:D}:{},headers:{...x20(A.headerLines,"list-unsubscribe","listUnsubscribe"),...x20(A.headerLines,"auto-submitted","autoSubmitted"),...x20(A.headerLines,"precedence","precedence")}};return FZ.parse($)}function yq9(x,B){let A=x?.trim();if(A)return A;let w=Buffer.from(B).toString("base64");return`<synthetic-${S6(w)}@brains.local>`}function yNx(x){return(x?Array.isArray(x)?x:[x]:[]).flatMap((A)=>A.value.flatMap((w)=>{if(w.group)return w.group.flatMap((f)=>NNx(f));return NNx(w)}))}function mq9(x){return yNx(x)[0]}function NNx(x){let B=x.address?.trim().toLowerCase();if(!B)return[];let A=x.name.trim();return[{address:B,...A?{name:A}:{}}]}function x20(x,B,A){let w=x.find(($)=>$.key===B)?.line,f=w?.indexOf(":")??-1,D=f>=0?w?.slice(f+1).trim():void 0;if(!D)return{};switch(A){case"listUnsubscribe":return{listUnsubscribe:D};case"autoSubmitted":return{autoSubmitted:D};case"precedence":return{precedence:D}}}class B20{options;sleep;client;controller;loop;constructor(x){this.options=x,this.sleep=x.sleep??cq9}isRunning(){return this.controller!==void 0}isConnected(){return this.client!==void 0}async start(){if(this.controller)return;let x=new AbortController;this.controller=x;let B;try{B=this.options.createClient(this.options.config);let A=await this.connectAndIntake(B);if(p3(x.signal)){await F_(B);return}this.client=B,this.loop=this.observeLoop(this.run({client:B,selection:A},x.signal),x.signal)}catch{if(B)await F_(B);if(p3(x.signal))return;this.options.logger.warn("Inbound email initial connection failed; reconnecting"),this.loop=this.observeLoop(this.recover(0,x.signal),x.signal)}}async stop(){let x=this.controller,B=this.client,A=this.loop;if(this.controller=void 0,this.loop=void 0,!x&&!B&&!A)return;x?.abort(Error("Inbound email listener stopped"));let w;if(B)try{await B.disconnect()}catch(D){w=D}await A;let f=this.client;if(f&&f!==B)try{await f.disconnect()}catch(D){w??=D}if(this.client=void 0,w)throw w}async recover(x,B){let A=await this.reconnect(void 0,x,B);await this.run(A,B)}async run(x,B){let A=x,w=this.options.config.pollMode,f=0;while(!p3(B)){if(w==="idle")try{await A.client.waitForChanges(B)}catch{if(p3(B))return;w="interval",this.options.logger.warn("Inbound email IDLE failed; falling back to interval polling");continue}else try{await this.sleep(this.options.config.pollIntervalMs,B)}catch{if(p3(B))return;this.options.logger.warn("Inbound email polling wait failed; reconnecting"),A=await this.reconnect(A.client,f,B),f+=1,w=this.options.config.pollMode;continue}if(p3(B))return;try{await this.options.intake(A.client,A.selection),f=0}catch{if(p3(B))return;this.options.logger.warn("Inbound email polling failed; reconnecting"),A=await this.reconnect(A.client,f,B),f+=1,w=this.options.config.pollMode}}}async reconnect(x,B,A){if(x){if(await F_(x),this.client===x)this.client=void 0}let w=B;while(!p3(A)){let f=Cq9(w);if(this.options.logger.debug("Inbound email reconnect scheduled",{retryInMs:f}),await this.sleep(f,A),p3(A))break;let D;try{D=this.options.createClient(this.options.config);let $=await this.connectAndIntake(D);if(p3(A)){await F_(D);break}return this.client=D,{client:D,selection:$}}catch{if(D)await F_(D);w+=1,this.options.logger.warn("Inbound email reconnect failed")}}throw Error("Inbound email reconnect aborted")}async connectAndIntake(x){await x.connect();let B=this.options.config.mailbox,A=await x.selectMailbox(B),w={mailbox:B,uidValidity:A};return await this.options.intake(x,w),w}observeLoop(x,B){return x.catch(()=>{if(p3(B))return;this.options.logger.error("Inbound email supervision stopped")})}}function p3(x){return x.aborted}function Cq9(x){let B=Math.min(Math.max(0,Math.floor(x)),6);return Math.min(60000,1000*2**B)}async function F_(x){try{await x.disconnect()}catch{}}function cq9(x,B){if(B.aborted)return Promise.reject(B.reason);return new Promise((A,w)=>{let f=()=>{clearTimeout(D),w(B.reason)},D=setTimeout(()=>{B.removeEventListener("abort",f),A()},x);D.unref(),B.addEventListener("abort",f,{once:!0})})}var gq9=X.object({host:X.string().min(1),port:X.coerce.number().int().min(1).max(65535),user:X.string().min(1),password:X.string().min(1),mailbox:X.string().min(1).default("INBOX"),pollMode:X.enum(["idle","interval"]).default("idle"),pollIntervalMs:X.coerce.number().int().positive().default(60000)}),Tq9=X.object({transport:X.literal("resend").default("resend"),apiKey:X.string().min(1).optional(),from:X.string().min(1).optional(),imap:gq9.optional()}),pq9=X.looseObject({id:X.string().optional()});function uq9(x){return x!=="normal"}class A20 extends SK{fetchImpl;imapClientFactory;inboundSleep;inboundCursor;constructor(x={},B={}){super("email",MUx,x,Tq9);this.fetchImpl=B.fetchImpl??fetch,this.imapClientFactory=B.imapClientFactory??ONx,this.inboundSleep=B.inboundSleep}createDaemon(){let x=this.config.imap;if(!x)return;let B=new B20({config:x,createClient:this.imapClientFactory,intake:async(A,w)=>RNx(A,w,{cursor:this.getInboundCursor(),publish:this.getContext().messaging.send,resolveSender:async(f)=>this.resolveInboundSender(f),logger:this.logger}),logger:this.logger,...this.inboundSleep?{sleep:this.inboundSleep}:{}});return{start:async()=>{try{await B.start(),this.logger.info(B.isConnected()?"Inbound email listener connected":"Inbound email listener started; awaiting connection")}catch{throw Error("Inbound email listener failed to start")}},stop:async()=>{try{await B.stop(),this.logger.info("Inbound email listener disconnected")}catch{throw Error("Inbound email listener failed to disconnect")}},healthCheck:async()=>({status:B.isConnected()?"healthy":"error",message:B.isConnected()?"Inbound email listener connected":B.isRunning()?"Inbound email listener awaiting connection":"Inbound email listener disconnected",lastCheck:new Date})}}async onRegister(x){if(await super.onRegister(x),this.config.imap)this.inboundCursor=x.runtimeState.scoped({namespace:"email.inbound.uid-cursor",schema:X.strictObject({mailbox:X.string().min(1),uidValidity:X.string().regex(/^[1-9]\d*$/),lastUid:X.number().int().nonnegative()})});if(x.channels.registerDescriptor({type:"email",displayName:"Email",subjectLabel:"Email address",subjectPattern:{source:"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$",flags:"i"},manualDelivery:!0}),!this.config.apiKey||!this.config.from){this.logger.warn("Email interface transport is disabled because apiKey or from is missing");return}x.channels.registerDeliveryProvider({channelType:"email",isAvailable:async()=>!0,send:async(B)=>this.deliver(B)})}async resolveInboundSender(x){let B=await this.getContext().messaging.send({type:KL,payload:{actor:{kind:"external",externalActorId:pA("email",x)}}});if("noop"in B||!B.success)return;let A=mNx.safeParse(B.data),w=A.success?A.data.principal:void 0;return w?{personId:w.personId,permissionLevel:w.permissionLevel}:void 0}getInboundCursor(){if(!this.inboundCursor)throw Error("Inbound email cursor is unavailable");return this.inboundCursor}async deliver(x){let B=uq9(x.sensitivity);try{let A=await this.sendWithResend({to:x.recipient,subject:x.subject,text:x.text,...x.html?{html:x.html}:{},idempotencyKey:x.idempotencyKey});return A.status==="sent"?{status:"sent",...A.id?{providerDeliveryId:A.id}:{}}:{status:"failed",failureCode:"email_delivery_failed"}}catch(A){if(B)this.logger.warn("Email delivery failed for a secret message");else this.logger.warn("Email delivery failed",{to:x.recipient,subject:x.subject,error:g(A)});return{status:"failed",failureCode:"email_delivery_failed"}}}async sendWithResend(x){let B=this.config.apiKey,A=this.config.from;if(!B||!A)return{status:"failed"};let w=await this.fetchImpl("https://api.resend.com/emails",{method:"POST",headers:{Authorization:`Bearer ${B}`,"Content-Type":"application/json",...x.idempotencyKey?{"Idempotency-Key":x.idempotencyKey}:{}},body:JSON.stringify({from:A,to:x.to,subject:x.subject,text:x.text,...x.html?{html:x.html}:{}})});if(!w.ok)throw Error("Resend email request failed");let f=pq9.parse(await w.json());return f.id?{status:"sent",id:f.id}:{status:"sent"}}}var Oy={name:"@brains/email-triage",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Safe derived triage for inbound email",dependencies:{"@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var iq9=["opportunity","recruiting","work","administrative","personal"],IY=X.enum(iq9),lq9=["high","normal","low"],OY=X.enum(lq9),nq9=["new","reviewed","handled","archived"],dq=X.enum(nq9),CNx=X.strictObject({ref:X.string().min(1).max(1024),senderKey:X.string().regex(/^[a-f0-9]{64}$/),threadKey:X.string().regex(/^[a-f0-9]{64}$/).optional(),personId:X.string().min(1).max(200).optional(),domain:X.string().min(1).max(253).optional()}),aq=X.strictObject({title:X.string().min(1).max(160),category:IY.nullable().default(null),priority:OY,status:dq,needsReply:X.boolean(),receivedAt:X.iso.datetime(),source:CNx,organization:X.string().min(1).max(200).optional(),requestedActions:X.array(X.string().min(1).max(240)).max(10)}),cNx=aq.pick({title:!0,category:!0,priority:!0,status:!0,needsReply:!0,receivedAt:!0}),KZ=j8.extend({entityType:X.literal("mail-item"),metadata:cNx});var gNx=X.string().min(1).max(1000);class w20 extends ox{constructor(){super({entityType:"mail-item",purpose:"A restricted, derived routing summary for an inbound email whose original remains in the mailbox.",schema:KZ,frontmatterSchema:aq})}createMailItemContent(x,B){return this.buildMarkdown(gNx.parse(B),aq.parse(x))}parseMailItemContent(x){return{frontmatter:this.parseFrontMatter(x,aq),summary:gNx.parse(this.extractBody(x).trim())}}fromMarkdown(x){let{frontmatter:B}=this.parseMailItemContent(x);return{content:x,entityType:"mail-item",metadata:{title:B.title,category:B.category,priority:B.priority,status:B.status,needsReply:B.needsReply,receivedAt:B.receivedAt}}}}var u3=new w20;var dq9=X.object({});class hy extends g8{entityType="mail-item";schema=KZ;adapter=u3;constructor(){super("mail-item",Oy,{},dq9)}getEntityTypeConfig(){return{projectionSource:!1,projectionSourceRole:"excluded"}}async onRegister(x){await super.onRegister(x),x.entities.registerPersistValidator("mail-item",async(B)=>{if(B.visibility!=="restricted")throw Error("Mail items must have restricted visibility");let{frontmatter:A}=u3.parseMailItemContent(B.content);if(A.category===null&&(A.title!=="Unclassified email"||A.priority!=="high"))throw Error("Only the system fallback may have an unclassified category")})}}var f20={category:IY.nullable().optional(),priority:OY.optional(),status:dq.optional(),needsReply:X.boolean().optional(),limit:X.number().int().min(1).max(100).default(50)},K_=X.strictObject(f20),q_=X.strictObject({id:X.string().min(1),title:X.string().min(1).max(160),category:IY.nullable(),priority:OY,status:dq,needsReply:X.boolean(),receivedAt:X.iso.datetime(),summary:X.string().min(1).max(1000),organization:X.string().min(1).max(200).optional(),requestedActions:X.array(X.string().min(1).max(240)).max(10)}),Ry=X.strictObject({items:X.array(q_),total:X.number().int().nonnegative()}),aq9=X.strictObject({success:X.literal(!0),data:Ry}),sq9=X.strictObject({success:X.literal(!1),error:X.string().min(1)}),D20=X.discriminatedUnion("success",[aq9,sq9]),z_=X.strictObject({total:X.number().int().nonnegative(),new:X.number().int().nonnegative(),high:X.number().int().nonnegative(),needsReply:X.number().int().nonnegative(),unclassified:X.number().int().nonnegative()}),$20=X.strictObject({summary:z_,items:X.array(q_)}),rq9=X.strictObject({type:X.literal("mark-reviewed"),id:X.string().min(1)}),oq9=X.strictObject({type:X.literal("mark-handled"),id:X.string().min(1)}),tq9=X.strictObject({type:X.literal("archive"),id:X.string().min(1)}),hY=X.discriminatedUnion("type",[rq9,oq9,tq9]),yy=X.strictObject({id:X.string().min(1),status:dq}),b_=X.strictObject({summary:z_,managementUrl:X.string().min(1).optional()});var eq9=100;class my{sourceId="mail-items";displayName="Email Triage";operator;constructor(x){this.operator=x}async list(){let x=await this.operator.list({status:"new",limit:eq9});return TNx.parse(x.items.map(xz9))}async act(x,B,A){let w=hY.safeParse({type:B,id:x});if(!w.success)throw Error("Invalid email triage inbox action");await this.operator.act(w.data,{userPermissionLevel:A.permissionLevel})}}function xz9(x){return{id:x.id,title:x.title,summary:x.summary,receivedAt:x.receivedAt,urgency:x.priority==="high"?"high":"normal",entityRef:{entityType:"mail-item",entityId:x.id},actions:Bz9()}}function Bz9(){return[{id:"mark-reviewed",label:"Mark reviewed"},{id:"mark-handled",label:"Mark handled"},{id:"archive",label:"Archive",confirm:!0}]}var pNx=X.strictObject({decision:X.literal("retain"),title:X.string().min(1).max(160),category:IY,priority:OY,needsReply:X.boolean(),organization:X.string().min(1).max(200).optional(),requestedActions:X.array(X.string().min(1).max(240)).max(10),summary:X.string().min(1).max(1000)}),Z20=pNx,Az9=X.strictObject({decision:X.literal("discard"),reason:X.literal("spam")});var sq=X.discriminatedUnion("decision",[pNx,Az9]);var Q20="email-triage:classification",Cy=`Classify the message by purpose using this routing rubric:
5623
+ `)])}else return!1;if(this.logRaw)this.log.trace({src:"c",msg:"write to socket",data:x.toString("base64"),compress:!!this._deflate,secure:!!this.secureConnection,cid:this.id});this.writeBytesCounter+=x.length,this.writeSocket.write(x)}stats(x){let B={sent:this.writeBytesCounter||0,received:this.streamer&&this.streamer.readBytesCounter||0};if(x){if(this.writeBytesCounter=0,this.streamer)this.streamer.readBytesCounter=0}return B}async send(x){if(this.state===this.states.LOGOUT){if(x.tag){let f=this.requestTagMap.get(x.tag);if(f){this.requestTagMap.delete(f.tag);let D=Error("Connection not available");D.code="NoConnection",f.reject(D)}}return}let B=await fy(x,{asArray:!0,literalMinus:QQ9(this,"LITERAL-")||this.capabilities.has("LITERAL+")});this.commandParts=B;let A=await fy(x,{isLogging:!0}),w=x.options||{};if(this.log.debug({src:"c",msg:A.toString(),cid:this.id,comment:w.comment}),this.write(this.commandParts.shift()),this.currentRequest&&this.currentRequest.tag===x.tag)this.currentRequest.sent=!0;if(typeof w.onSend==="function")try{w.onSend()}catch(f){this.log.warn({err:f,cid:this.id})}}async trySend(){while(!this.currentRequest&&this.requestQueue.length){this.currentRequest=this.requestQueue.shift();try{await this.send({tag:this.currentRequest.tag,command:this.currentRequest.command,attributes:this.currentRequest.attributes,options:this.currentRequest.options});return}catch(x){this.commandParts=[],this.rejectCurrentRequest(x)}}}exec(x,B,A){if(this.state===this.states.LOGOUT||this.isClosed){let D=Error("Connection not available");D.code="NoConnection";let $=Promise.reject(D);return $.catch(x_),$}if(!this.socket||this.socket.destroyed){let D=Error("Connection closed");D.code="EConnectionClosed";let $=Promise.reject(D);return $.catch(x_),$}let w=(++this.tagCounter).toString(16).toUpperCase();A=A||{};let f=new Promise((D,$)=>{this.requestTagMap.set(w,{command:x,attributes:B,options:A,resolve:D,reject:$}),this.requestQueue.push({tag:w,command:x,attributes:B,options:A}),this.trySend().catch((Z)=>this.log.warn({err:Z,cid:this.id}))});return f.catch(x_),f}getUntaggedHandler(x,B){if(/^[0-9]+$/.test(x)){let A=B&&B.length&&typeof B[0].value==="string"?B[0].value.toUpperCase():!1;if(A)x=A}if(x=x.toUpperCase().trim(),this.currentRequest&&this.currentRequest.options&&this.currentRequest.options.untagged&&this.currentRequest.options.untagged[x])return this.currentRequest.options.untagged[x];if(this.untaggedHandlers[x])return this.untaggedHandlers[x]}getSectionHandler(x){if(this.sectionHandlers[x])return this.sectionHandlers[x]}releaseStreamData(x){if(!x||x.released)return;if(x.released=!0,typeof x.next==="function")x.next()}countUnknownTag(x){if(this.isClosed)return;if(this._unknownTagCount++,this._unknownTagCount===this._nextUnknownTagWarn)this._nextUnknownTagWarn*=2,this.log.warn({msg:"Tagged response for an unknown tag",tag:x,unknownTagCount:this._unknownTagCount,cid:this.id})}failProtocol(x){if(this.streamer&&!this.streamer.destroyed)this.streamer.destroy();this.emitError(x)}rejectCurrentRequest(x){if(!this.currentRequest)return;let B=this.currentRequest.tag;this.currentRequest=!1;let A=this.requestTagMap.get(B);if(A)this.requestTagMap.delete(B),A.reject(x)}async reader(){let x,B=0;while((x=this.streamer.read())!==null){let A;try{A=await this.handleResponse(x)}catch(w){A=!1;let f=Error("Failed to process server response");f.code="ResponseProcessingFailed",f._err=w,this.log.error({msg:"Failed to process server response",err:w,cid:this.id}),this.rejectCurrentRequest(f),this.failProtocol(f)}finally{this.releaseStreamData(x)}if(!A)return;if(B++,B%10===0)await new Promise((w)=>setImmediate(w))}}rejectUnparsedCompletion(x,B){if(!this.currentRequest||!this.currentRequest.sent)return;let A=B&&B.parsedTag;if(!A){let f=x.toString("latin1",0,64).match(/^\0*([^\s\x00-\x1f\x7f]+)/);A=f&&f[1]}if(!A||A!==this.currentRequest.tag)return;let w=Error("Failed to parse the server response for this command");w.code=B.code||"ParserError",w.parserError=B,this.rejectCurrentRequest(w),this.trySend().catch((f)=>this.log.warn({err:f,cid:this.id}))}async handleResponse(x){let B;try{B=await sZ9(x.payload,{literals:x.literals})}catch(f){return this.log.error({src:"s",msg:x.payload.toString(),err:f,cid:this.id}),this.rejectUnparsedCompletion(x.payload,f),!0}if(B.tag&&!["*","+"].includes(B.tag)&&B.command){let f={response:B.command};if(B.attributes&&B.attributes[0]&&B.attributes[0].section&&B.attributes[0].section[0]&&B.attributes[0].section[0].type==="ATOM")f.code=B.attributes[0].section[0].value;try{this.emit("response",f)}catch(D){this.log.warn({err:D,cid:this.id})}}let A=await fy(B,{isLogging:!0});if(/^\d+$/.test(B.command)&&B.attributes&&B.attributes[0]&&B.attributes[0].value==="FETCH")this.log.trace({src:"s",msg:A.toString(),cid:this.id,nullBytesRemoved:B.nullBytesRemoved});else this.log.debug({src:"s",msg:A.toString(),cid:this.id,nullBytesRemoved:B.nullBytesRemoved});if(B.tag==="+"&&this.currentRequest&&this.currentRequest.options&&typeof this.currentRequest.options.onPlusTag==="function"){try{await this.currentRequest.options.onPlusTag(B)}catch(f){this.log.warn({err:f,cid:this.id})}return!0}if(B.tag==="+"&&this.commandParts.length){let f=this.commandParts.shift();try{this.write(f),this.log.debug({src:"c",msg:`(* ${f.length}B continuation *)`,cid:this.id})}catch(D){this.log.warn({err:D,cid:this.id})}return!0}let w=B.attributes&&B.attributes.length&&B.attributes[0]&&!B.attributes[0].value&&B.attributes[0].section;if(w&&w.length&&w[0].type==="ATOM"&&typeof w[0].value==="string"){let f=this.getSectionHandler(w[0].value.toUpperCase().trim());if(f)try{await f(w.slice(1))}catch(D){this.log.warn({err:D,cid:this.id})}}if(B.tag==="*"&&B.command){let f=this.getUntaggedHandler(B.command,B.attributes);if(f)try{await f(B)}catch(D){return this.log.warn({err:D,cid:this.id}),!0}}if(B.tag&&!["*","+"].includes(B.tag))if(this.currentRequest&&this.currentRequest.tag===B.tag&&this.currentRequest.sent){let f=this.requestTagMap.get(B.tag);if(this.requestTagMap.delete(B.tag),this.currentRequest=!1,f)await this.settleRequest(f,B,!!x.trailingAfterLine);try{await this.trySend()}catch(D){this.log.warn({err:D,cid:this.id})}}else if(this.requestTagMap.has(B.tag)){let f=this.requestTagMap.get(B.tag);this.requestTagMap.delete(B.tag);let D=Error("Server sent a tagged response for a command that was not in flight");return D.code="UnexpectedTag",D.details={received:B.tag,expected:this.currentRequest?this.currentRequest.tag:null},this.log.error({msg:"Protocol desynchronization",err:D,cid:this.id}),f.reject(D),this.failProtocol(D),!1}else this.countUnknownTag(B.tag);return!0}async settleRequest(x,B,A){switch((B.command||"").toUpperCase()){case"OK":case"BYE":await new Promise((w)=>x.resolve({response:B,next:w,hasTrailingData:A}));break;case"NO":case"BAD":{let w=B.attributes&&B.attributes.filter((D)=>D.type==="TEXT").map((D)=>D.value.trim()).join(" "),f=Error("Command failed");f.response=B,f.responseStatus=B.command.toUpperCase();try{f.executedCommand=B.tag+(await fy(x,{isLogging:!0})).toString()}catch{}if(w){if(f.responseText=w,f.responseStatus==="NO"&&w.includes("Some of the requested messages no longer exist")){this.log.warn({msg:"Partial FETCH response",cid:this.id,err:f}),await new Promise(($)=>x.resolve({response:B,next:$}));break}let D=!1;if(/Request is throttled/i.test(w)&&/Backoff Time/i.test(w)){let $=w.match(/Backoff Time[:=\s]+(\d+)/i);if($&&$[1]&&!isNaN($[1]))D=Number($[1])}if(D){f.code="ETHROTTLE",f.throttleReset=D;let $=D;if($>300000)$=300000;this.log.warn({msg:"Throttling detected",cid:this.id,throttleDelay:D,delayResponse:$,err:f});let Z=await new Promise((Q)=>{this._throttleAbort=Q,this._throttleTimer=setTimeout(()=>Q(!1),$),I40(this._throttleTimer)});if(this._throttleTimer=null,this._throttleAbort=null,Z){x.reject(this.createNoConnectionError(this.byeReason));break}}}x.reject(f);break}default:{let w=Error("Invalid server response");w.code="InvalidResponse",w.response=B,x.reject(w);break}}}setEventHandlers(){this.socketReadable=()=>{if(!this.reading)this.reading=!0,this.reader().catch((x)=>this.log.error({err:x,cid:this.id})).finally(()=>{this.reading=!1})},this.streamer.on("readable",this.socketReadable)}configureSocket(x){if(!x)return;if(typeof x.setKeepAlive==="function")x.setKeepAlive(!0,5000);if(typeof x.setTimeout==="function")x.setTimeout(this.socketTimeout)}setSocketHandlers(){if(this.clearSocketHandlers(),this._socketError=this._socketError||((x)=>{this.log.error({err:x,cid:this.id}),this.emitError(x)}),this._socketClose=this._socketClose||(()=>this.close()),this._socketEnd=this._socketEnd||(()=>this.close()),this._socketTimeout=this._socketTimeout||(()=>{let x=Error("Socket timeout");if(x.code="ETIMEOUT",this.idling){if(!this.usable||!this.socket||this.socket.destroyed){this.emitError(x);return}this.run("NOOP").then(()=>this.idle()).catch((B)=>{if(this.log.warn({msg:"IDLE recovery failed after timeout",err:B,cid:this.id}),!this.isClosed)this.close()})}else this.log.debug({msg:"Socket timeout",cid:this.id}),this.emitError(x)}),this.socket.once("error",this._socketError),this.socket.once("close",this._socketClose),this.socket.once("end",this._socketEnd),this.socket.on("tlsClientError",this._socketError),this.socket.on("timeout",this._socketTimeout),this.writeSocket&&this.writeSocket!==this.socket)this.writeSocket.on("error",this._socketError)}clearSocketHandlers(){if(!this.socket)return;if(this._connectErrorHandler)this.socket.removeListener("error",this._connectErrorHandler),this._connectErrorHandler=null;if(this._socketError){if(this.socket.removeListener("error",this._socketError),this.socket.removeListener("tlsClientError",this._socketError),this.writeSocket&&this.writeSocket!==this.socket)this.writeSocket.removeListener("error",this._socketError)}if(this._socketTimeout)this.socket.removeListener("timeout",this._socketTimeout);if(this._socketClose)this.socket.removeListener("close",this._socketClose);if(this._socketEnd)this.socket.removeListener("end",this._socketEnd)}async startSession(){if(await this.run("CAPABILITY"),this.capabilities.has("ID"))this.idRequested=await this.run("ID",this.clientInfo);if(await this.upgradeToSTARTTLS(),await this.authenticate(),(!this.idRequested||Object.keys(this.idRequested).length<2)&&this.capabilities.has("ID"))this.idRequested=await this.run("ID",this.clientInfo);let x=await this.run("NAMESPACE");if(x&&x.error&&x.status==="BAD"&&/User is authenticated but not connected/i.test(x.text)){this.authenticated=!1;let B=new uq("Authentication failed");throw B.response=x.text,B}if(this.options.verifyOnly){if(this.options.includeMailboxes)this._mailboxList=await this.list();return await this.logout()}if(!this.options.disableCompression)await this.compress();if(!this.options.disableAutoEnable)await this.autoEnable();this.usable=!0}async autoEnable(){let x=["CONDSTORE","UTF8=ACCEPT"].concat(this.options.qresync?"QRESYNC":[]).concat(this.options.disableIMAP4rev2?[]:"IMAP4rev2");if(await this.run("ENABLE",x)===!1&&x.includes("IMAP4rev2"))await this.run("ENABLE",x.filter((A)=>A!=="IMAP4rev2"))}async compress(){if(!await this.run("COMPRESS"))return;this._deflate=wy.createDeflateRaw({windowBits:15,level:wy.constants.Z_DEFAULT_COMPRESSION,memLevel:8,strategy:wy.constants.Z_DEFAULT_STRATEGY,chunkSize:16384}),this._inflate=wy.createInflateRaw({chunkSize:16384}),this.socket.unpipe(this.streamer),this.streamer.compress=!0,this.socket.pipe(this._inflate).pipe(this.streamer),this._inflate.on("error",(w)=>{if(!this.streamer.destroyed&&this.streamer.listenerCount("error"))this.streamer.emit("error",w)}),this.writeSocket=new ukx({highWaterMark:65536}),this.writeSocket.destroySoon=()=>{try{if(this.socket)this.socket.destroy();this.writeSocket.end()}catch(w){throw this.log.error({err:w,info:"Failed to destroy PassThrough socket",cid:this.id}),w}};let x=!1,B=0,A=async()=>{try{x=!0,B=0;let w;while(this.writeSocket&&(w=this.writeSocket.read())!==null){if(this._deflate&&this._deflate.write(w)===!1)return this._deflate.once("drain",A);if(B++,B%100===0){if(await new Promise((f)=>setImmediate(f)),!this.writeSocket)break}}if(this._deflate)this._deflate.flush();x=!1}catch(w){this.emitError(w)}};this.writeSocket.on("readable",()=>{if(!x&&this.writeSocket)A()}),this.writeSocket.on("error",(w)=>{if(this.socket)this.socket.emit("error",w)}),this._deflate.pipe(this.socket),this._deflate.on("error",(w)=>{if(this.socket)this.socket.emit("error",w)})}_failSTARTTLS(){if(this.options.doSTARTTLS===!0){let x=Error("Server does not support STARTTLS");throw x.tlsFailed=!0,x}return!1}async upgradeToSTARTTLS(){if(this.options.doSTARTTLS===!0&&this.options.secure===!0)throw Error("Misconfiguration: Cannot set both secure=true for TLS and doSTARTTLS=true for STARTTLS.");if(this.secureConnection)return!0;if(this.options.doSTARTTLS===!1)return!1;if(!this.capabilities.has("STARTTLS"))return this._failSTARTTLS();if(this.expectCapabilityUpdate=!0,!await this.run("STARTTLS"))return this._failSTARTTLS();let B=()=>{let f=Error("Server sent data after the STARTTLS response and before the TLS handshake; possible plaintext-injection attack");return f.code="STARTTLS_INJECTION",f.tlsFailed=!0,this.closeAfter(),f};if(this._starttlsHadTrailingData)throw B();this.socket.unpipe(this.streamer);let A=typeof this.socket.read==="function"?this.socket.read():null;if(A&&A.length)throw B();let w=await new Promise((f,D)=>{let $=this.socket,Z=Object.assign({socket:this.socket,servername:this.servername,port:this.port},this.options.tls||{});this.clearSocketHandlers();let Q=!1,Y=(W,H)=>{if(Q)return;if(Q=!0,clearTimeout(this.upgradeTimeout),this.upgradeTimeout=null,this.upgrading=!1,this._upgradeReject=null,$.removeListener("error",Y),this.socket&&this.socket!==$)this.socket.removeListener("error",Y);if(W)return clearTimeout(this.connectTimeout),W.tlsFailed=!0,this.closeAfter(),D(W);f(H)};this._upgradeReject=Y,$.once("error",Y),this.upgradeTimeout=setTimeout(()=>{let W=Error("Failed to upgrade connection in required time");W.code="UPGRADE_TIMEOUT",Y(W)},1e4),this.upgrading=!0,this.socket=Ckx.connect(Z,()=>{try{if(this.isClosed){let W=Error("Connection closed during TLS upgrade");return W.code="NoConnection",Y(W)}if(this.secureConnection=!0,this.streamer.secureConnection=!0,this.socket.pipe(this.streamer),this.tls=typeof this.socket.getCipher==="function"?this.socket.getCipher():!1,this.tls)this.tls.authorized=this.socket.authorized,this.log.info({src:"tls",msg:"Established TLS session",cid:this.id,authorized:this.tls.authorized,algo:this.tls.standardName||this.tls.name,version:this.tls.version});if(typeof $.setTimeout==="function")$.setTimeout(0);this.setSocketHandlers(),this.configureSocket(this.socket),Y(null,!0)}catch(W){this.emitError(W)}}),this.socket.once("error",Y),this.writeSocket=this.socket});if(w)this.clearCapabilities(),await this.run("CAPABILITY");return w}async setAuthenticationState(){if(this.state=this.states.AUTHENTICATED,this.authenticated=!0,this.expectCapabilityUpdate)await this.run("CAPABILITY")}async authenticate(){if(this.state===this.states.LOGOUT)throw new uq("Already logged out");if(this.state!==this.states.NOT_AUTHENTICATED)return!0;if(!this.options.auth)throw new uq("Please configure the login");this.expectCapabilityUpdate=!0;let x=(this.options.auth.loginMethod||"").toString().trim().toUpperCase();if(!x&&/\\|\//.test(this.options.auth.user))x="LOGIN";if(this.options.auth.accessToken)this.authenticated=await this.run("AUTHENTICATE",this.options.auth.user,{accessToken:this.options.auth.accessToken});else if(this.options.auth.pass)if((this.capabilities.has("AUTH=LOGIN")||this.capabilities.has("AUTH=PLAIN"))&&x!=="LOGIN")this.authenticated=await this.run("AUTHENTICATE",this.options.auth.user,{password:this.options.auth.pass,loginMethod:x,authzid:this.options.auth.authzid});else{if(this.capabilities.has("LOGINDISABLED"))throw new uq("Login is disabled");this.authenticated=await this.run("LOGIN",this.options.auth.user,this.options.auth.pass)}else throw new uq("No password configured");if(this.authenticated)return this.log.info({src:"auth",msg:"User authenticated",cid:this.id,user:this.options.auth.user}),await this.setAuthenticationState(),!0;throw new uq("No matching authentication method")}beginSession(x){if(clearTimeout(this.greetingTimeout),this.untaggedHandlers.OK=null,this.untaggedHandlers.PREAUTH=null,this.isClosed)return;this.startSession().then(()=>{if(typeof this.initialResolve==="function"){let B=this.initialResolve;return this.initialResolve=!1,this.initialReject=!1,B()}}).catch((B)=>{if(this.log.error({err:B,cid:this.id}),typeof this.initialReject==="function"){clearTimeout(this.greetingTimeout);let A=this.initialReject;return this.initialResolve=!1,this.initialReject=!1,A(B)}x(B)})}async initialOK(x){this.greeting=(x.attributes||[]).filter((B)=>B.type==="TEXT").map((B)=>B.value).filter((B)=>B).join(""),this.beginSession((B)=>this.emitError(B))}async initialPREAUTH(){if(this.isClosed)return;this.state=this.states.AUTHENTICATED,this.authenticated=!0,this.beginSession((x)=>{this.log.error({err:x,cid:this.id}),this.closeAfter()})}async serverBye(x){let B=x&&x.attributes&&x.attributes.filter((A)=>A.type==="TEXT").map((A)=>A.value.trim()).join(" ");this.byeReason=B||"Server closed connection",this.untaggedHandlers.BYE=null,this.state=this.states.LOGOUT}clearCapabilities(){this.capabilities.clear(),this.authCapabilities.clear(),this.rawCapabilities=null}updateCapabilitiesFromRaw(x){if(this.rawCapabilities=x,this.capabilities=BQ9(x),this.capabilities){for(let[B]of this.capabilities)if(/^AUTH=/i.test(B)&&!this.authCapabilities.has(B.toUpperCase()))this.authCapabilities.set(B.toUpperCase(),!1)}if(this.expectCapabilityUpdate)this.expectCapabilityUpdate=!1}async sectionCapability(x){this.updateCapabilitiesFromRaw(x)}async untaggedCapability(x){this.updateCapabilitiesFromRaw(x.attributes)}async untaggedExists(x){if(!this.mailbox)return;if(!x||!x.command||isNaN(x.command))return;let B=Number(x.command);if(B===this.mailbox.exists)return;let A=this.mailbox.exists;this.mailbox.exists=B,this.emit("exists",{path:this.mailbox.path,count:B,prevCount:A})}async untaggedExpunge(x){if(!this.mailbox)return;if(!x||!x.command||isNaN(x.command))return;let B=Number(x.command);if(B&&B<=this.mailbox.exists){this.mailbox.exists--;let A={path:this.mailbox.path,seq:B,vanished:!1};if(typeof this.options.expungeHandler==="function")try{await this.options.expungeHandler(A)}catch(w){this.log.error({msg:"Failed to notify expunge event",payload:A,error:w,cid:this.id})}else this.emit("expunge",A)}}async untaggedVanished(x,B){if(B=B||this.mailbox,!B)return;let A=[],w=!1;if(x.attributes.length>1&&Array.isArray(x.attributes[0]))A=x.attributes[0].map((D)=>typeof D.value==="string"?D.value.toUpperCase():!1).filter((D)=>D),x.attributes.shift();if(x.attributes[0]&&typeof x.attributes[0].value==="string")w=x.attributes[0].value;let f=$Q9(w);for(let D of f){let $={path:B.path,uid:D,vanished:!0,earlier:A.includes("EARLIER")};if(typeof this.options.expungeHandler==="function")try{await this.options.expungeHandler($)}catch(Z){this.log.error({msg:"Failed to notify expunge event",payload:$,error:Z,cid:this.id})}else this.emit("expunge",$)}}async untaggedFetch(x,B){if(B=B||this.mailbox,!B)return;let A=await wQ9(x,B);if(A.flags){let w={path:B.path,seq:A.seq};if(A.uid)w.uid=A.uid;if(A.modseq)w.modseq=A.modseq;if(w.flags=A.flags,A.flagColor)w.flagColor=A.flagColor;this.emit("flags",w)}}async ensureSelectedMailbox(x){if(!x)return!1;if(!this.mailbox||!xQ9(this,this.mailbox.path,x))return await this.mailboxOpen(x);return!0}async resolveRange(x,B){if(typeof x==="number"||typeof x==="bigint")x=x.toString();if(x==="*"){if(!this.mailbox.exists)return!1;x=this.mailbox.exists.toString(),B.uid=!1}if(x&&typeof x==="object"&&!Array.isArray(x)){if(x.all&&Object.keys(x).length===1)x="1:*";else if(x.uid&&Object.keys(x).length===1)x=x.uid,B.uid=!0;else if(B.uid=!0,x=await this.run("SEARCH",x,B),x&&x.length)x=Skx(x)}if(Array.isArray(x))x=x.join(",");if(!x)return!1;return x}autoidle(){if(clearTimeout(this.idleStartTimer),this.options.disableAutoIdle||this.state!==this.states.SELECTED)return;this.idleStartTimer=setTimeout(()=>{this.idle().catch((x)=>this.log.warn({err:x,cid:this.id}))},15000),I40(this.idleStartTimer)}async connect(){if(this._connectCalled)throw Error("Can not re-use ImapFlow instance");this._connectCalled=!0;let x=new eZ9(this.options.connectionTimeout),B=this.secureConnection?Ckx:ckx,A=Object.assign({host:this.host,servername:this.servername,port:this.port},this.options.tls||{});this.untaggedHandlers.OK=(...D)=>this.initialOK(...D),this.untaggedHandlers.BYE=(...D)=>this.serverBye(...D),this.untaggedHandlers.PREAUTH=(...D)=>this.initialPREAUTH(...D),this.untaggedHandlers.CAPABILITY=(...D)=>this.untaggedCapability(...D),this.sectionHandlers.CAPABILITY=(...D)=>this.sectionCapability(...D),this.untaggedHandlers.EXISTS=(...D)=>this.untaggedExists(...D),this.untaggedHandlers.EXPUNGE=(...D)=>this.untaggedExpunge(...D),this.untaggedHandlers.FETCH=(D)=>this.untaggedFetch(D),this.untaggedHandlers.VANISHED=(D)=>this.untaggedVanished(D);let w=!1;if(this.options.proxy)try{if(w=await oZ9(this.log,this.options.proxy,this.host,this.port,{deadline:x}),!w)throw Error("Failed to setup proxy connection")}catch(D){if(D.code==="CONNECT_TIMEOUT")throw this.log.error({err:D,cid:this.id}),D;let $=Error("Failed to setup proxy connection");throw $.code=D.code||"ProxyError",$._err=D,this.log.error({error:$,cid:this.id}),$}let f=new Promise((D,$)=>{this.connectTimeout=setTimeout(()=>{let Q=x.error();this.log.error({err:Q,cid:this.id}),this.closeAfter(),$(Q)},x.remaining());let Z=()=>{try{clearTimeout(this.connectTimeout),tZ9(w),this.configureSocket(this.socket),this.greetingTimeout=setTimeout(()=>{let Y=Error(`Failed to receive greeting from server in required time${!this.secureConnection?". Maybe should use TLS?":""}`);Y.code="GREETING_TIMEOUT",Y.details={greetingTimeout:this.options.greetingTimeout||16000},this.log.error({err:Y,cid:this.id}),this.closeAfter(),$(Y)},this.options.greetingTimeout||16000),this.tls=typeof this.socket.getCipher==="function"?this.socket.getCipher():!1;let Q={src:"connection",msg:`Established ${this.tls?"secure ":""}TCP connection`,cid:this.id,secure:!!this.tls,host:this.host,servername:this.servername,port:this.socket.remotePort,address:this.socket.remoteAddress,localAddress:this.socket.localAddress,localPort:this.socket.localPort};if(this.tls)Q.authorized=this.tls.authorized=this.socket.authorized,Q.algo=this.tls.standardName||this.tls.name,Q.version=this.tls.version;this.log.info(Q),this.setSocketHandlers(),this.setEventHandlers(),this.socket.pipe(this.streamer),this.initialResolve=D,this.initialReject=$}catch(Q){$(Q)}};if(w)if(this.secureConnection)A.socket=w,this.socket=B.connect(A,Z);else this.socket=w,setImmediate(Z);else this.socket=B.connect(A,Z);this.writeSocket=this.socket,this._connectErrorHandler=(Q)=>{clearTimeout(this.connectTimeout),clearTimeout(this.greetingTimeout),this.closeAfter(),this.log.error({err:Q,cid:this.id}),$(Q)},this.socket.on("error",this._connectErrorHandler)});f.catch(x_),await f}async logout(){return await this.run("LOGOUT")}closeAfter(){setImmediate(()=>this.close())}createNoConnectionError(x){let B=Error("Connection not available");if(B.code="NoConnection",x)B.reason=x;return B}close(){try{if(clearTimeout(this.idleStartTimer),clearTimeout(this.upgradeTimeout),clearTimeout(this.connectTimeout),clearTimeout(this.greetingTimeout),clearTimeout(this._throttleTimer),this._throttleTimer=null,typeof this._throttleAbort==="function")this._throttleAbort(!0),this._throttleAbort=null;if(this.usable=!1,this._idleSession=null,this.idling=!1,typeof this._upgradeReject==="function"){let f=this._upgradeReject;this._upgradeReject=null;let D=Error("Connection closed during TLS upgrade");D.code="NoConnection",f(D)}if(typeof this.initialReject==="function"&&!this.options.verifyOnly){clearTimeout(this.greetingTimeout);let f=this.initialReject;this.initialResolve=!1,this.initialReject=!1;let D=Error("Unexpected close");if(D.code=`ClosedAfterConnect${this.secureConnection?"TLS":"Text"}`,this.byeReason)D.reason=this.byeReason;f(D)}if(typeof this.preCheck==="function")this.preCheck().catch((f)=>this.log.warn({err:f,cid:this.id}));let x=!1;if(!this.isClosed){if(x=this.mailbox,this.mailbox=!1,this.currentSelectCommand=!1,!this.options.verifyOnly)this.authenticated=!1;this.preCheck=!1}let B=[];if(this.currentRequest&&this.requestTagMap.has(this.currentRequest.tag)){let f=this.currentRequest.tag,D=this.requestTagMap.get(f);if(D)this.requestTagMap.delete(f),B.push(D);this.currentRequest=!1}while(this.requestQueue.length){let f=this.requestQueue.shift();if(f&&this.requestTagMap.has(f.tag)){let D=this.requestTagMap.get(f.tag);if(D)this.requestTagMap.delete(f.tag),B.push(D)}}let A=(f)=>this.createNoConnectionError(f),w=this.byeReason;for(let f of B)f.reject(A(w));if(this.currentLock&&this.currentLock.heldWarnTimer)clearTimeout(this.currentLock.heldWarnTimer),this.currentLock.heldWarnTimer=null;if(this.currentLock=!1,this.locks&&this.locks.length){let f=this.locks.splice(0);for(let D of f){if(D.acquireTimer)clearTimeout(D.acquireTimer),D.acquireTimer=null;if(typeof D.reject==="function")D.reject(A(w))}}if(this._inflate)try{this._inflate.unpipe(),this._inflate.destroy(),this._inflate=null}catch(f){this.log.error({err:f,info:"Failed to destroy inflate stream",cid:this.id})}if(this._deflate)try{this._deflate.unpipe(),this._deflate.destroy(),this._deflate=null}catch(f){this.log.error({err:f,info:"Failed to destroy deflate stream",cid:this.id})}if(this.streamer)try{if(this.socketReadable)this.streamer.removeListener("readable",this.socketReadable);if(this._streamerErrorHandler)this.streamer.removeListener("error",this._streamerErrorHandler);if(!this.streamer.destroyed)this.streamer.destroy()}catch(f){this.log.error({err:f,info:"Failed to cleanup streamer",cid:this.id})}if(this.clearSocketHandlers(),this.folders.clear(),this.requestTagMap.clear(),this.state=this.states.LOGOUT,this.isClosed)return;if(this.isClosed=!0,this.writeSocket&&this.writeSocket!==this.socket&&!this.writeSocket.destroyed)try{this.writeSocket.destroy()}catch(f){this.log.error({err:f,cid:this.id})}if(this.socket&&!this.socket.destroyed)try{this.socket.destroy()}catch(f){this.log.error({err:f,cid:this.id})}if(this.socket=null,this.writeSocket=null,this._inflate=null,this._deflate=null,this._streamerErrorHandler=null,this._connectErrorHandler=null,this._socketError=null,this._socketClose=null,this._socketEnd=null,this._socketTimeout=null,this.log.trace({msg:"Connection closed",cid:this.id,...this._unknownTagCount?{unknownTagCount:this._unknownTagCount}:{}}),x)this.emit("mailboxClose",x);this.emit("close")}catch(x){this.log.error(x)}}async getQuota(x){return x=x||"INBOX",await this.run("QUOTA",x)}async list(x){x=x||{};let B=await this.run("LIST","","*",x);return this.folders=new Map(B.map((A)=>[A.path,A])),B}async listTree(x){x=x||{};let B=await this.run("LIST","","*",x);return this.folders=new Map(B.map((A)=>[A.path,A])),AQ9(B)}async noop(){await this.run("NOOP")}async mailboxCreate(x){return await this.run("CREATE",x)}async mailboxRename(x,B){return await this.run("RENAME",x,B)}async mailboxDelete(x){return await this.run("DELETE",x)}async mailboxSubscribe(x){return await this.run("SUBSCRIBE",x)}async mailboxUnsubscribe(x){return await this.run("UNSUBSCRIBE",x)}async mailboxOpen(x,B){return await this.run("SELECT",x,B)}async mailboxClose(){return await this.run("CLOSE")}async status(x,B){return await this.run("STATUS",x,B)}async idle(){if(!this.idling)return await this.run("IDLE",this.maxIdleTime)}async messageFlagsSet(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=Object.assign({operation:"set"},A);return await this.run("STORE",x,B,w)}async messageFlagsAdd(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=Object.assign({operation:"add"},A);return await this.run("STORE",x,B,w)}async messageFlagsRemove(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=Object.assign({operation:"remove"},A);return await this.run("STORE",x,B,w)}async setFlagColor(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;let w=ZQ9(B);if(!w)return!1;let f,D;if(w.add&&w.add.length){let $=Object.assign({operation:"add"},A,{useLabels:!1,silent:w.remove&&w.remove.length});f=await this.run("STORE",x,w.add,$)}if(w.remove&&w.remove.length){let $=Object.assign({operation:"remove"},A,{useLabels:!1});D=await this.run("STORE",x,w.remove,$)}return f||D||!1}async messageDelete(x,B){if(B=B||{},x=await this.resolveRange(x,B),!x)return!1;return await this.run("EXPUNGE",x,B)}async append(x,B,A,w){return await this.run("APPEND",x,B,A,w)||!1}async messageCopy(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;return await this.run("COPY",x,B,A)}async messageMove(x,B,A){if(A=A||{},x=await this.resolveRange(x,A),!x)return!1;return await this.run("MOVE",x,B,A)}async search(x,B){if(!this.mailbox)return;let A=await this.run("SEARCH",x,B)||!1;if(B&&B.returnOptions&&Array.isArray(A)){let w=A,f=B.returnOptions.map(($)=>typeof $==="string"?$.toUpperCase():$),D={};if(f.includes("COUNT"))D.count=w.length;if(f.includes("MIN")&&w.length)D.min=w[0];if(f.includes("MAX")&&w.length)D.max=w[w.length-1];if(f.includes("ALL")&&w.length)D.all=Skx(w);if(Object.keys(D).length===0)return A;return D}return A}async*fetch(x,B,A){if(A=A||{},!this.mailbox)return;if(x=await this.resolveRange(x,A),!x)return!1;let w=!1,f=!1,D=!1,$=[],Z=()=>new Promise((Y,W)=>{let H=()=>{if($.length){let F=$.shift();if(F.err)return W(F.err);return Y(F.value)}if(w)return Y(null);D=()=>{D=!1,H()}};H()});this.run("FETCH",x,B,{uid:!!A.uid,binary:A.binary,changedSince:A.changedSince,onUntaggedFetch:(Y,W)=>{if(f){W();return}if($.push({value:{response:Y,next:W}}),typeof D==="function")D()}}).then(()=>{if(w=!0,typeof D==="function")D()}).catch((Y)=>{if($.push({err:Y}),typeof D==="function")D()});let Q=null;try{let Y;while(Y=await Z()){if(Q=Y,this.isClosed||!this.socket||this.socket.destroyed){let W=Error("Connection closed");throw W.code="EConnectionClosed",W}yield Y.response,Y.next(),Q=null}}finally{if(f=!0,Q&&typeof Q.next==="function")Q.next();while($.length){let Y=$.shift();if(Y.value&&typeof Y.value.next==="function")Y.value.next()}}}async fetchAll(x,B,A){let w=[],f=this.fetch(x,B,A);for await(let D of f)w.push(D);return w}async fetchOne(x,B,A){if(!this.mailbox)return;if(x==="*"){if(!this.mailbox.exists)return!1;x=this.mailbox.exists.toString(),A=Object.assign({},A||{},{uid:!1})}let w=await this.run("FETCH",(x||"").toString(),B,A);if(!w||!w.list||!w.list.length)return!1;return w.list[0]}async download(x,B,A){if(!this.mailbox)return{};A=Object.assign({chunkSize:65536,maxBytes:1/0},A||{});let w=!0,f=0,D=Number(A.chunkSize)||65536,$=Number(A.maxBytes)||1/0,Z=!1;if(B==="1"){let c=await this.fetchOne(x,{uid:!0,bodyStructure:!0},A);if(!c)return{response:!1,chunk:!1};if(!Z&&c.uid)Z=c.uid,x=Z,A.uid=!0;if(!c.bodyStructure.childNodes)B="TEXT"}let Q=async(c)=>{c=c||{};let n;if(!B)c.source={start:f,maxLength:D};else{if(B=B.toString().toLowerCase().trim(),!c.bodyParts)c.bodyParts=[];if(c.size){if(/^[\d.]+$/.test(B))n=B+".mime",c.bodyParts.push(n);else if(B==="text")n="header",c.bodyParts.push(n)}c.bodyParts.push({key:B,start:f,maxLength:D})}let R=await this.fetchOne(x,c,A);if(!R)return{response:!1,chunk:!1};if(!Z&&R.uid)Z=R.uid,x=Z,A.uid=!0;let M=!B?R.source:R.bodyParts&&R.bodyParts.get(B);if(!M)return{};f+=M.length,w=M.length>=D;let B0={chunk:M};if(c.size)B0.response=R;if(c.bodyParts)if(n==="header")B0.mime=R.headers;else B0.mime=R.bodyParts.get(n);return B0},{response:Y,chunk:W,mime:H}=await Q({size:!0,uid:!0});if(!Y||!W)return{};let F={expectedSize:Y.size};if(!B)F.contentType="message/rfc822";else if(H){let c=new gkx(H),n=Bw.parseHeaderValue(c.getFirst("Content-Type")),R=Bw.parseHeaderValue(c.getFirst("Content-Transfer-Encoding")),M=Bw.parseHeaderValue(c.getFirst("Content-Disposition"));if(n.value.toLowerCase().trim())F.contentType=n.value.toLowerCase().trim();if(n.params.charset)F.charset=n.params.charset.toLowerCase().trim();if(R.value)F.encoding=R.value.replace(/\(.*\)/g,"").toLowerCase().trim();if(M.value){F.disposition=M.value.toLowerCase().trim()||!1;try{F.disposition=Bw.decodeWords(F.disposition)}catch{}}if(n.params.format&&n.params.format.toLowerCase().trim()==="flowed"){if(F.flowed=!0,n.params.delsp&&n.params.delsp.toLowerCase().trim()==="yes")F.delSp=!0}let B0=M.params.filename||n.params.name||!1;if(B0){try{B0=Bw.decodeWords(B0)}catch{}F.filename=B0}}let K,q,V=!1;switch(Y.binaryParts&&Y.binaryParts.has(B)?!1:F.encoding){case"base64":q=K=new pkx.Decoder;break;case"quoted-printable":q=K=new Tkx.Decoder;break;default:q=K=new ukx}let G=["text/html","text/plain","text/x-amp-html"].includes(F.contentType)||B==="1"&&!F.contentType;if((!F.disposition||F.disposition==="inline")&&G){if(F.flowed){let c=new rZ9({delSp:F.delSp});q.on("error",(n)=>{c.emit("error",n)}),q=q.pipe(c)}if(F.charset&&!["ascii","usascii","utf8"].includes(F.charset.toLowerCase().replace(/[^a-z0-9]+/g,"")))try{let c=fQ9(F.charset);c.on("error",(n)=>{this.log.warn({err:n,charset:F.charset,cid:this.id})}),q.on("error",(n)=>{c.emit("error",n)}),q=q.pipe(c),F.charset="utf-8"}catch{}}let E=new dZ9({maxBytes:$});q.on("error",(c)=>{E.emit("error",c)}),q=q.pipe(E);let _=()=>{if(V=!0,K&&!K.destroyed)K.destroy()};q.once("error",_),q.once("close",_);let L=(c)=>{if(E.limited||V||K.destroyed)return!0;return K.write(c)},N=async()=>{while(w&&!E.limited&&!V){let{chunk:c}=await Q();if(!c||V)break;if(L(c)===!1){try{await new Promise((n,R)=>{let M=!1,B0=(G0)=>{if(M)return;if(M=!0,K.removeAllListeners("drain"),K.removeAllListeners("error"),K.removeAllListeners("close"),G0)R(G0);else n()};K.once("drain",()=>B0()),K.once("error",(G0)=>B0(G0)),K.once("close",()=>B0())})}catch(n){if(!V)throw n}if(V)break}}},y=()=>{N().catch((c)=>{if(!V&&K&&!K.destroyed)K.emit("error",c);else this.log.warn({msg:"Download error after stream closed",err:c,fetchAborted:V,streamDestroyed:K?.destroyed,cid:this.id})}).finally(()=>{if(!V&&K&&!K.destroyed)K.end()})};return setImmediate(()=>{let c;try{c=L(W)}catch(n){if(K.emit("error",n),!V&&K&&!K.destroyed)K.end();return}if(!c)K.once("drain",()=>{if(!V)y()});else y()}),{meta:F,content:q}}async downloadMany(x,B,A){if(!this.mailbox)return{};A=Object.assign({chunkSize:65536,maxBytes:1/0},A||{});let w={bodyParts:[]};for(let $ of B)w.bodyParts.push($+".mime"),w.bodyParts.push($);let f=await this.fetchOne(x,w,A);if(!f||!f.bodyParts)return{response:!1};let D={};for(let[$,Z]of f.bodyParts){let Q=$.split(".mime");if(Q.length===1){let Y=Q[0];if(!D[Y])D[Y]={content:Z};else D[Y].content=Z}else if(Q.length===2){let Y=Q[0];if(!D[Y])D[Y]={};if(!D[Y].meta)D[Y].meta={};let W=new gkx(Z),H=Bw.parseHeaderValue(W.getFirst("Content-Type")),F=Bw.parseHeaderValue(W.getFirst("Content-Transfer-Encoding")),K=Bw.parseHeaderValue(W.getFirst("Content-Disposition"));if(H.value.toLowerCase().trim())D[Y].meta.contentType=H.value.toLowerCase().trim();if(H.params.charset)D[Y].meta.charset=H.params.charset.toLowerCase().trim();if(F.value)D[Y].meta.encoding=F.value.replace(/\(.*\)/g,"").toLowerCase().trim();if(K.value){D[Y].meta.disposition=K.value.toLowerCase().trim()||!1;try{D[Y].meta.disposition=Bw.decodeWords(D[Y].meta.disposition)}catch{}}if(H.params.format&&H.params.format.toLowerCase().trim()==="flowed"){if(D[Y].meta.flowed=!0,H.params.delsp&&H.params.delsp.toLowerCase().trim()==="yes")D[Y].meta.delSp=!0}let q=K.params.filename||H.params.name||!1;if(q){try{q=Bw.decodeWords(q)}catch{}D[Y].meta.filename=q}}}for(let $ of Object.keys(D)){let Z=D[$].meta;switch(f.binaryParts&&f.binaryParts.has($)?!1:Z.encoding){case"base64":D[$].content=D[$].content?pkx.decode(D[$].content.toString()):null;break;case"quoted-printable":D[$].content=D[$].content?Tkx.decode(D[$].content.toString()):null;break;default:}}return D}async run(x,...B){if(x=x.toUpperCase(),!this.commands.has(x))return!1;if(!this.socket||this.socket.destroyed)throw this.createNoConnectionError();if(clearTimeout(this.idleStartTimer),typeof this.preCheck==="function")await this.preCheck();let A=await this.runInternal(x,...B);if(x!=="IDLE")this.autoidle();return A}async runInternal(x,...B){if(x=x.toUpperCase(),!this.commands.has(x))return!1;if(!this.socket||this.socket.destroyed)throw this.createNoConnectionError();return await this.commands.get(x)(this,...B)}async processLocks(){if(this.processingLock){this.log.trace({msg:"Mailbox locking queued",path:this.mailbox&&this.mailbox.path,pending:this.locks.length,idling:this.idling,activeLock:this.currentLock?{lockId:this.currentLock.lockId,...this.currentLock.options?.description&&{description:this.currentLock.options?.description}}:null});return}this.processingLock=!0;try{let B=0;while(this.locks.length>0){if(this.currentLock)break;if(B++,B%5===0)await new Promise((W)=>setImmediate(W));let A=this.locks.shift(),{resolve:w,reject:f,path:D,options:$,lockId:Z}=A;if(A.acquireTimer)clearTimeout(A.acquireTimer),A.acquireTimer=null;let Q=()=>{let W=Number($.maxLockHoldTime??this.options.maxLockHoldTime??1800000);if(!W||W<=0)return;A.heldAt=Date.now(),A.heldWarnTimer=setTimeout(()=>{A.heldWarnTimer=null,this.log.warn({msg:"Mailbox lock held for a long time",lockId:A.lockId,path:D,heldFor:Date.now()-A.heldAt,...$.description&&{description:$.description},cid:this.id})},W),I40(A.heldWarnTimer)},Y=()=>{if(this.currentLock===A){if(A.heldWarnTimer)clearTimeout(A.heldWarnTimer),A.heldWarnTimer=null;this.log.trace({msg:"Mailbox lock released",lockId:A.lockId,path:this.mailbox&&this.mailbox.path,pending:this.locks.length,idling:this.idling}),this.currentLock=!1,setImmediate(()=>{this.processLocks().catch((W)=>this.log.error({err:W,cid:this.id}))})}else this.log.trace({msg:"Ignoring stale lock release",lockId:A.lockId,cid:this.id})};if(!this.usable||!this.socket||this.socket.destroyed){this.log.trace({msg:"Failed to acquire mailbox lock",path:D,lockId:Z,idling:this.idling});let W=Error("Connection not available");W.code="NoConnection",f(W);continue}if(this.mailbox&&this.mailbox.path===D&&!!this.mailbox.readOnly===!!$.readOnly){this.log.trace({msg:"Mailbox lock acquired [existing]",path:D,lockId:Z,idling:this.idling,...$.description&&{description:$.description}}),this.currentLock=A,Q(),w({path:D,release:Y});break}try{await this.mailboxOpen(D,$),this.log.trace({msg:"Mailbox lock acquired [selected]",path:D,lockId:Z,idling:this.idling,...$.description&&{description:$.description}}),this.currentLock=A,Q(),w({path:D,release:Y});break}catch(W){if(W.responseStatus==="NO")try{let H=await this.run("LIST","",D,{listOnly:!0});if(!H||!H.length)W.mailboxMissing=!0}catch(H){this.log.trace({msg:"Failed to verify failed mailbox",path:D,err:H})}this.log.trace({msg:"Failed to acquire mailbox lock",path:D,lockId:Z,idling:this.idling,...$.description&&{description:$.description},err:W}),f(W)}}}finally{if(this.processingLock=!1,this.locks.length&&!this.currentLock)setImmediate(()=>{this.processLocks().catch((B)=>this.log.error({err:B,cid:this.id}))})}}getMailboxLock(x,B){B=B||{},x=DQ9(this,x);let A=++this.lockCounter;this.log.trace({msg:"Requesting lock",path:x,lockId:A,...B.description&&{description:B.description},activeLock:this.currentLock?{lockId:this.currentLock.lockId,...this.currentLock.options?.description&&{description:this.currentLock.options?.description}}:null});let w=new Promise((f,D)=>{let $={resolve:f,reject:D,path:x,options:B,lockId:A};if(this.locks.push($),Number(B.acquireTimeout)>0)$.acquireTimer=setTimeout(()=>{$.acquireTimer=null;let Z=this.locks.indexOf($);if(Z!==-1){this.locks.splice(Z,1);let Q=Error("Timed out waiting for mailbox lock");Q.code="LockTimeout",Q.lockId=$.lockId,D(Q)}},Number(B.acquireTimeout));this.processLocks().catch((Z)=>D(Z))});return w.catch(x_),w}getLogger(){let x=this.options.logger&&typeof this.options.logger==="object"?this.options.logger:nZ9.child({component:"imap-connection",cid:this.id}),B={},A=["trace","debug","info","warn","error","fatal"];for(let w of A)B[w]=(...f)=>{if(this.options.logger!==!1)if(typeof x[w]!=="function"){if(w==="fatal"||w==="error")console.log(JSON.stringify(...f))}else x[w](...f);if(this.emitLogs&&f&&f[0]&&typeof f[0]==="object"){let D=Object.assign({level:w,t:Date.now(),cid:this.id,lo:++this.lo},f[0]);if(D.err&&typeof D.err==="object"){let $=D.err;D.err={stack:$.stack},Object.keys($).forEach((Z)=>{D.err[Z]=$[Z]})}this.emit("log",D)}};return B}unbind(){if(this.socket.unpipe(this.streamer),this._inflate)this._inflate.unpipe(this.streamer);this.clearSocketHandlers();let x=this._inflate||this.socket,B=this.writeSocket||this.socket;if(this.socket!==x&&this.socket!==B)this.socket.on("error",(A)=>{this.log.debug({msg:"Suppressed error on unbound socket",err:A,cid:this.id})});return{readSocket:x,writeSocket:B,socket:this.socket}}}var O40=ikx;var INx=b7(vNx(),1);function ONx(x){let B=new O40({host:x.host,port:x.port,secure:!0,auth:{user:x.user,pass:x.password},disableAutoIdle:!0,maxIdleTime:x.pollIntervalMs,logger:!1});return{connect:async()=>{await B.connect()},selectMailbox:async(A)=>{return(await B.mailboxOpen(A,{readOnly:!0})).uidValidity.toString()},fetchMessages:async function*(A){let w=B.fetch(`${A}:*`,{uid:!0,source:!0,internalDate:!0,threadId:!0},{uid:!0});for await(let f of w){if(f.uid<A)continue;if(!f.source||!f.internalDate)throw Error("Inbound email source was incomplete");yield{uid:f.uid,source:f.source,receivedAt:new Date(f.internalDate),...f.threadId?{threadId:f.threadId}:{}}}},waitForChanges:(A)=>{if(A.aborted)return Promise.reject(A.reason);return new Promise((w,f)=>{let D=!1,$=()=>{B.off("exists",Z),B.off("close",Q),B.off("error",Q),A.removeEventListener("abort",Y)},Z=()=>{if(D)return;D=!0,$(),w()},Q=()=>{if(D)return;D=!0,$(),f(Error("Inbound email IDLE failed"))},Y=()=>{B.close(),Q()};B.on("exists",Z),B.on("close",Q),B.on("error",Q),A.addEventListener("abort",Y,{once:!0}),B.idle().then(Z,Q)})},disconnect:async()=>{if(B.usable)await B.logout();else B.close()}}}function hNx(x,B){let A=JSON.stringify({mailbox:x.mailbox,uidValidity:x.uidValidity,uid:B});return`imap:${S6(A)}`}async function RNx(x,B,A){let{cursor:w,publish:f,resolveSender:D,logger:$}=A,Z=await w.get("cursor"),Q=Z!==null&&Z.mailbox===B.mailbox&&Z.uidValidity===B.uidValidity,Y=Q?Z.lastUid:0;if(!Q)await w.set("cursor",{...B,lastUid:0});let W=Y,H=0;for await(let F of x.fetchMessages(Y+1)){if(F.uid<=W)continue;let K;try{K=await Rq9(F,hNx(B,F.uid))}catch{$.warn("Inbound email message could not be parsed",{uid:F.uid}),await w.set("cursor",{...B,lastUid:F.uid}),W=F.uid;continue}if(D)try{let V=await D(K.from.address);if(V)K={...K,sender:V}}catch{$.warn("Inbound email sender resolution failed",{messageKey:S6(K.messageId)})}let q=!1;try{let V=await f({type:H_,payload:K});q="success"in V&&V.success}catch{}if(!q){$.warn("Inbound email event was not acknowledged",{messageKey:S6(K.messageId)});break}await w.set("cursor",{...B,lastUid:F.uid}),W=F.uid,H+=1,$.debug("Inbound email event published",{messageKey:S6(K.messageId)})}return H}async function Rq9(x,B){let A=await INx.simpleParser(Buffer.from(x.source),{skipImageLinks:!0}),w=mq9(A.from);if(!w)throw Error("Inbound email sender was missing");let f=yq9(A.messageId,x.source),D=typeof A.html==="string"?A.html:void 0,$={messageId:f,sourceRef:B,...x.threadId?{threadId:x.threadId}:{},from:w,to:yNx(A.to),subject:A.subject??"",receivedAt:x.receivedAt.toISOString(),text:A.text??"",...D?{html:D}:{},headers:{...x20(A.headerLines,"list-unsubscribe","listUnsubscribe"),...x20(A.headerLines,"auto-submitted","autoSubmitted"),...x20(A.headerLines,"precedence","precedence")}};return FZ.parse($)}function yq9(x,B){let A=x?.trim();if(A)return A;let w=Buffer.from(B).toString("base64");return`<synthetic-${S6(w)}@brains.local>`}function yNx(x){return(x?Array.isArray(x)?x:[x]:[]).flatMap((A)=>A.value.flatMap((w)=>{if(w.group)return w.group.flatMap((f)=>NNx(f));return NNx(w)}))}function mq9(x){return yNx(x)[0]}function NNx(x){let B=x.address?.trim().toLowerCase();if(!B)return[];let A=x.name.trim();return[{address:B,...A?{name:A}:{}}]}function x20(x,B,A){let w=x.find(($)=>$.key===B)?.line,f=w?.indexOf(":")??-1,D=f>=0?w?.slice(f+1).trim():void 0;if(!D)return{};switch(A){case"listUnsubscribe":return{listUnsubscribe:D};case"autoSubmitted":return{autoSubmitted:D};case"precedence":return{precedence:D}}}class B20{options;sleep;client;controller;loop;constructor(x){this.options=x,this.sleep=x.sleep??cq9}isRunning(){return this.controller!==void 0}isConnected(){return this.client!==void 0}async start(){if(this.controller)return;let x=new AbortController;this.controller=x;let B;try{B=this.options.createClient(this.options.config);let A=await this.connectAndIntake(B);if(p3(x.signal)){await F_(B);return}this.client=B,this.loop=this.observeLoop(this.run({client:B,selection:A},x.signal),x.signal)}catch{if(B)await F_(B);if(p3(x.signal))return;this.options.logger.warn("Inbound email initial connection failed; reconnecting"),this.loop=this.observeLoop(this.recover(0,x.signal),x.signal)}}async stop(){let x=this.controller,B=this.client,A=this.loop;if(this.controller=void 0,this.loop=void 0,!x&&!B&&!A)return;x?.abort(Error("Inbound email listener stopped"));let w;if(B)try{await B.disconnect()}catch(D){w=D}await A;let f=this.client;if(f&&f!==B)try{await f.disconnect()}catch(D){w??=D}if(this.client=void 0,w)throw w}async recover(x,B){let A=await this.reconnect(void 0,x,B);await this.run(A,B)}async run(x,B){let A=x,w=this.options.config.pollMode,f=0;while(!p3(B)){if(w==="idle")try{await A.client.waitForChanges(B)}catch{if(p3(B))return;w="interval",this.options.logger.warn("Inbound email IDLE failed; falling back to interval polling");continue}else try{await this.sleep(this.options.config.pollIntervalMs,B)}catch{if(p3(B))return;this.options.logger.warn("Inbound email polling wait failed; reconnecting"),A=await this.reconnect(A.client,f,B),f+=1,w=this.options.config.pollMode;continue}if(p3(B))return;try{await this.options.intake(A.client,A.selection),f=0}catch{if(p3(B))return;this.options.logger.warn("Inbound email polling failed; reconnecting"),A=await this.reconnect(A.client,f,B),f+=1,w=this.options.config.pollMode}}}async reconnect(x,B,A){if(x){if(await F_(x),this.client===x)this.client=void 0}let w=B;while(!p3(A)){let f=Cq9(w);if(this.options.logger.debug("Inbound email reconnect scheduled",{retryInMs:f}),await this.sleep(f,A),p3(A))break;let D;try{D=this.options.createClient(this.options.config);let $=await this.connectAndIntake(D);if(p3(A)){await F_(D);break}return this.client=D,{client:D,selection:$}}catch{if(D)await F_(D);w+=1,this.options.logger.warn("Inbound email reconnect failed")}}throw Error("Inbound email reconnect aborted")}async connectAndIntake(x){await x.connect();let B=this.options.config.mailbox,A=await x.selectMailbox(B),w={mailbox:B,uidValidity:A};return await this.options.intake(x,w),w}observeLoop(x,B){return x.catch(()=>{if(p3(B))return;this.options.logger.error("Inbound email supervision stopped")})}}function p3(x){return x.aborted}function Cq9(x){let B=Math.min(Math.max(0,Math.floor(x)),6);return Math.min(60000,1000*2**B)}async function F_(x){try{await x.disconnect()}catch{}}function cq9(x,B){if(B.aborted)return Promise.reject(B.reason);return new Promise((A,w)=>{let f=()=>{clearTimeout(D),w(B.reason)},D=setTimeout(()=>{B.removeEventListener("abort",f),A()},x);D.unref(),B.addEventListener("abort",f,{once:!0})})}var gq9=X.object({host:X.string().min(1),port:X.coerce.number().int().min(1).max(65535),user:X.string().min(1),password:X.string().min(1),mailbox:X.string().min(1).default("INBOX"),pollMode:X.enum(["idle","interval"]).default("idle"),pollIntervalMs:X.coerce.number().int().positive().default(60000)}),Tq9=X.object({transport:X.literal("resend").default("resend"),apiKey:X.string().min(1).optional(),from:X.string().min(1).optional(),imap:gq9.optional()}),pq9=X.looseObject({id:X.string().optional()});function uq9(x){return x!=="normal"}class A20 extends SK{fetchImpl;imapClientFactory;inboundSleep;inboundCursor;constructor(x={},B={}){super("email",MUx,x,Tq9);this.fetchImpl=B.fetchImpl??fetch,this.imapClientFactory=B.imapClientFactory??ONx,this.inboundSleep=B.inboundSleep}createDaemon(){let x=this.config.imap;if(!x)return;let B=new B20({config:x,createClient:this.imapClientFactory,intake:async(A,w)=>RNx(A,w,{cursor:this.getInboundCursor(),publish:this.getContext().messaging.send,resolveSender:async(f)=>this.resolveInboundSender(f),logger:this.logger}),logger:this.logger,...this.inboundSleep?{sleep:this.inboundSleep}:{}});return{start:async()=>{try{await B.start(),this.logger.info(B.isConnected()?"Inbound email listener connected":"Inbound email listener started; awaiting connection")}catch{throw Error("Inbound email listener failed to start")}},stop:async()=>{try{await B.stop(),this.logger.info("Inbound email listener disconnected")}catch{throw Error("Inbound email listener failed to disconnect")}},healthCheck:async()=>({status:B.isConnected()?"healthy":"error",message:B.isConnected()?"Inbound email listener connected":B.isRunning()?"Inbound email listener awaiting connection":"Inbound email listener disconnected",lastCheck:new Date})}}async onRegister(x){if(await super.onRegister(x),this.config.imap)this.inboundCursor=x.runtimeState.scoped({namespace:"email.inbound.uid-cursor",schema:X.strictObject({mailbox:X.string().min(1),uidValidity:X.string().regex(/^[1-9]\d*$/),lastUid:X.number().int().nonnegative()})});if(x.channels.registerDescriptor({type:"email",displayName:"Email",subjectLabel:"Email address",subjectPattern:{source:"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$",flags:"i"},manualDelivery:!0}),!this.config.apiKey||!this.config.from){this.logger.warn("Email interface transport is disabled because apiKey or from is missing");return}x.channels.registerDeliveryProvider({channelType:"email",isAvailable:async()=>!0,send:async(B)=>this.deliver(B)})}async resolveInboundSender(x){let B=await this.getContext().messaging.send({type:KL,payload:{actor:{kind:"external",externalActorId:pA("email",x)}}});if("noop"in B||!B.success)return;let A=mNx.safeParse(B.data),w=A.success?A.data.principal:void 0;return w?{personId:w.personId,permissionLevel:w.permissionLevel}:void 0}getInboundCursor(){if(!this.inboundCursor)throw Error("Inbound email cursor is unavailable");return this.inboundCursor}async deliver(x){let B=uq9(x.sensitivity);try{let A=await this.sendWithResend({to:x.recipient,subject:x.subject,text:x.text,...x.html?{html:x.html}:{},idempotencyKey:x.idempotencyKey});return A.status==="sent"?{status:"sent",...A.id?{providerDeliveryId:A.id}:{}}:{status:"failed",failureCode:"email_delivery_failed"}}catch(A){if(B)this.logger.warn("Email delivery failed for a secret message");else this.logger.warn("Email delivery failed",{to:x.recipient,subject:x.subject,error:g(A)});return{status:"failed",failureCode:"email_delivery_failed"}}}async sendWithResend(x){let B=this.config.apiKey,A=this.config.from;if(!B||!A)return{status:"failed"};let w=await this.fetchImpl("https://api.resend.com/emails",{method:"POST",headers:{Authorization:`Bearer ${B}`,"Content-Type":"application/json",...x.idempotencyKey?{"Idempotency-Key":x.idempotencyKey}:{}},body:JSON.stringify({from:A,to:x.to,subject:x.subject,text:x.text,...x.html?{html:x.html}:{}})});if(!w.ok)throw Error("Resend email request failed");let f=pq9.parse(await w.json());return f.id?{status:"sent",id:f.id}:{status:"sent"}}}var Oy={name:"@brains/email-triage",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Safe derived triage for inbound email",dependencies:{"@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var iq9=["opportunity","recruiting","work","administrative","personal"],IY=X.enum(iq9),lq9=["high","normal","low"],OY=X.enum(lq9),nq9=["new","reviewed","handled","archived"],dq=X.enum(nq9),CNx=X.strictObject({ref:X.string().min(1).max(1024),senderKey:X.string().regex(/^[a-f0-9]{64}$/),threadKey:X.string().regex(/^[a-f0-9]{64}$/).optional(),personId:X.string().min(1).max(200).optional(),domain:X.string().min(1).max(253).optional()}),aq=X.strictObject({title:X.string().min(1).max(160),category:IY.nullable().default(null),priority:OY,status:dq,needsReply:X.boolean(),receivedAt:X.iso.datetime(),source:CNx,organization:X.string().min(1).max(200).optional(),requestedActions:X.array(X.string().min(1).max(240)).max(10)}),cNx=aq.pick({title:!0,category:!0,priority:!0,status:!0,needsReply:!0,receivedAt:!0}),KZ=j8.extend({entityType:X.literal("mail-item"),metadata:cNx});var gNx=X.string().min(1).max(1000);class w20 extends ox{constructor(){super({entityType:"mail-item",purpose:"A restricted, derived routing summary for an inbound email whose original remains in the mailbox.",schema:KZ,frontmatterSchema:aq})}createMailItemContent(x,B){return this.buildMarkdown(gNx.parse(B),aq.parse(x))}parseMailItemContent(x){return{frontmatter:this.parseFrontMatter(x,aq),summary:gNx.parse(this.extractBody(x).trim())}}fromMarkdown(x){let{frontmatter:B}=this.parseMailItemContent(x);return{content:x,entityType:"mail-item",metadata:{title:B.title,category:B.category,priority:B.priority,status:B.status,needsReply:B.needsReply,receivedAt:B.receivedAt}}}}var u3=new w20;var dq9=X.object({});class hy extends g8{entityType="mail-item";schema=KZ;adapter=u3;constructor(){super("mail-item",Oy,{},dq9)}getEntityTypeConfig(){return{projectionSource:!1,projectionSourceRole:"excluded"}}async onRegister(x){await super.onRegister(x),x.entities.registerPersistValidator("mail-item",async(B)=>{if(B.visibility!=="restricted")throw Error("Mail items must have restricted visibility");let{frontmatter:A}=u3.parseMailItemContent(B.content);if(A.category===null&&(A.title!=="Unclassified email"||A.priority!=="high"))throw Error("Only the system fallback may have an unclassified category")})}}var f20={category:IY.nullable().optional(),priority:OY.optional(),status:dq.optional(),needsReply:X.boolean().optional(),limit:X.number().int().min(1).max(100).default(50)},K_=X.strictObject(f20),q_=X.strictObject({id:X.string().min(1),title:X.string().min(1).max(160),category:IY.nullable(),priority:OY,status:dq,needsReply:X.boolean(),receivedAt:X.iso.datetime(),summary:X.string().min(1).max(1000),organization:X.string().min(1).max(200).optional(),requestedActions:X.array(X.string().min(1).max(240)).max(10)}),Ry=X.strictObject({items:X.array(q_),total:X.number().int().nonnegative()}),aq9=X.strictObject({success:X.literal(!0),data:Ry}),sq9=X.strictObject({success:X.literal(!1),error:X.string().min(1)}),D20=X.discriminatedUnion("success",[aq9,sq9]),z_=X.strictObject({total:X.number().int().nonnegative(),new:X.number().int().nonnegative(),high:X.number().int().nonnegative(),needsReply:X.number().int().nonnegative(),unclassified:X.number().int().nonnegative()}),$20=X.strictObject({summary:z_,items:X.array(q_)}),rq9=X.strictObject({type:X.literal("mark-reviewed"),id:X.string().min(1)}),oq9=X.strictObject({type:X.literal("mark-handled"),id:X.string().min(1)}),tq9=X.strictObject({type:X.literal("archive"),id:X.string().min(1)}),hY=X.discriminatedUnion("type",[rq9,oq9,tq9]),yy=X.strictObject({id:X.string().min(1),status:dq}),b_=X.strictObject({summary:z_,managementUrl:X.string().min(1).optional()});var eq9=100;class my{sourceId="mail-items";displayName="Email Triage";operator;constructor(x){this.operator=x}async list(){let x=await this.operator.list({status:"new",limit:eq9});return TNx.parse(x.items.map(xz9))}async act(x,B,A){let w=hY.safeParse({type:B,id:x});if(!w.success)throw Error("Invalid email triage inbox action");await this.operator.act(w.data,{userPermissionLevel:A.permissionLevel})}}function xz9(x){return{id:x.id,title:x.title,summary:x.summary,receivedAt:x.receivedAt,urgency:x.priority==="high"?"high":"normal",entityRef:{entityType:"mail-item",entityId:x.id},actions:Bz9()}}function Bz9(){return[{id:"mark-reviewed",label:"Mark reviewed"},{id:"mark-handled",label:"Mark handled"},{id:"archive",label:"Archive",confirm:!0}]}var pNx=X.strictObject({decision:X.literal("retain"),title:X.string().min(1).max(160),category:IY,priority:OY,needsReply:X.boolean(),organization:X.string().min(1).max(200).optional(),requestedActions:X.array(X.string().min(1).max(240)).max(10),summary:X.string().min(1).max(1000)}),Z20=pNx,Az9=X.strictObject({decision:X.literal("discard"),reason:X.literal("spam")});var sq=X.discriminatedUnion("decision",[pNx,Az9]);var Q20="email-triage:classification",Cy=`Classify the message by purpose using this routing rubric:
5624
5624
  - opportunity: prospective commercial, partnership, or collaboration work
5625
5625
  - recruiting: employment, hiring, candidate, or talent correspondence
5626
5626
  - work: existing professional, project, client, colleague, or support correspondence
@@ -5655,7 +5655,7 @@ ${W}
5655
5655
  Title: "${x.entityTitle??Z}"
5656
5656
 
5657
5657
  Content:
5658
- ${F}`,Wz9);H=`${w.trim()} ${G.imagePrompt}`}catch(G){this.logger.warn("AI prompt distillation failed, using fallback",{error:g(G)})}}await this.reportProgress(A,{progress:b8.PROCESS,message:"Generating image"});let q=oNx(Y)+H,V;try{V=await this.context.ai.generateImage(q,{...f&&{aspectRatio:f}})}catch(G){return this.logger.error("Image generation failed",{jobId:B,error:g(G)}),p6.failure(G)}await this.reportProgress(A,{progress:b8.GENERATE,message:"Creating image entity"});let b=dB.createImageEntity({dataUrl:V.dataUrl,title:Z,status:"draft",attachmentType:"generated",...D&&{sourceEntityType:D},...$&&{sourceEntityId:$}});if(await l7({entityService:this.context.entityService,entity:{...b,id:Q}}),this.logger.debug("Created image entity",{imageId:Q}),D&&$){await this.reportProgress(A,{progress:b8.SAVE,message:`Updating ${D} with cover image`});let G=await ny(this.context.entityService,D,$,this.logger);if(!G)return p6.failure(Error(`Target entity not found: ${D}/${$}`));let E=dy(G,Q);await this.context.entities.update(E),this.logger.debug("Updated target entity with cover image",{targetEntityType:D,targetEntityId:$,imageId:Q})}return await this.reportProgress(A,{progress:b8.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:B,imageId:Q,targetEntityType:D,targetEntityId:$}),{success:!0,imageId:Q}}catch(Y){let W=g(Y);return this.logger.error("Image generation job failed",{jobId:B,error:W}),await Nf({entityService:this.context.entityService,entityType:"image",id:Q,error:W}),p6.failure(Y)}}summarizeDataForLog(x){return{title:x.title,promptLength:x.prompt.length,aspectRatio:x.aspectRatio,targetEntityType:x.targetEntityType,targetEntityId:x.targetEntityId}}}var Fz9=X.object({sourceEntityType:X.string().min(1),sourceEntityId:X.string().min(1),attachmentType:X.string().min(1),imageId:X.string().min(1),dedupKey:X.string().min(1).optional(),replace:X.boolean().optional(),targetEntityType:X.string().min(1).optional(),targetEntityId:X.string().min(1).optional(),targetImageField:X.enum(["coverImageId","ogImageId"]).optional()});class G20 extends $9{context;constructor(x,B){super(B,{schema:Fz9,jobTypeName:"image-render-source"});this.context=x}async process(x,B,A){this.logger.debug("Starting source image render job",{jobId:B,sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType,imageId:x.imageId});try{if(x.replace!==!0&&x.dedupKey){let $=await this.findImageByDedupKey(x.dedupKey);if($)return await this.updateTarget(x,$.id),await this.reportProgress(A,{progress:b8.COMPLETE,message:"Reusing existing generated image"}),{success:!0,imageId:$.id,reused:!0}}await this.reportProgress(A,{progress:b8.PROCESS,message:"Rendering source image"});let w=await this.context.attachments.resolve({sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType});if(!w)return p6.failure(Error(`No attachment provider found for ${x.sourceEntityType}/${x.attachmentType}`));if(w.type!=="image")return p6.failure(Error(`Attachment provider returned ${w.type}; expected image`));await this.reportProgress(A,{progress:b8.GENERATE,message:"Creating image entity"});let f=w.mimeType.split("/")[1]??"png",D=dB.createImageEntity({dataUrl:tNx(w.data.toString("base64"),f),title:x.imageId,status:"draft",sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType,...x.dedupKey&&{dedupKey:x.dedupKey}});return await l7({entityService:this.context.entityService,entity:{...D,id:x.imageId}}),await this.updateTarget(x,x.imageId),await this.reportProgress(A,{progress:b8.COMPLETE,message:"Image render complete"}),{success:!0,imageId:x.imageId,reused:!1}}catch(w){let f=g(w);return this.logger.error("Source image render job failed",{jobId:B,error:f}),await Nf({entityService:this.context.entityService,entityType:"image",id:x.imageId,error:f}),p6.failure(w)}}async findImageByDedupKey(x){return(await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{dedupKey:x}}}})).find((A)=>A.metadata.status!=="pending"&&A.metadata.status!=="failed")}async updateTarget(x,B){if(!x.targetEntityType||!x.targetEntityId)return;let A=await ny(this.context.entityService,x.targetEntityType,x.targetEntityId,this.logger);if(!A)throw Error(`Target entity not found: ${x.targetEntityType}/${x.targetEntityId}`);let f=(x.targetImageField??"coverImageId")==="ogImageId"?eNx(A,B):dy(A,B);await this.context.entities.update(f)}}var rq={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function sy(x){return["image/png","image/jpeg","image/webp","image/gif"].includes(x.toLowerCase())}function ry(x){let B=Kz9(x.title,x.filename),A=Gx(B);if(!A)throw Error("Could not derive an image id from the uploaded filename. Provide a title.");return{id:A,title:B}}function xIx(x,B){return`data:${x};base64,${B.toString("base64")}`}function Kz9(x,B){let A=x?.trim();if(A)return A;return B.replace(/\.[^.]+$/,"").trim()||B}var qz9=X.object({uploadId:X.string().min(1),imageId:X.string().min(1).optional(),title:X.string().optional()});class E20 extends $9{context;constructor(x,B){super(x,{schema:qz9,jobTypeName:"upload-promote"});this.context=B}async process(x,B,A){try{await this.reportProgress(A,{progress:10,message:"Reading uploaded image"});let w=await this.context.uploads.scoped(rq).read(x.uploadId);if(!sy(w.record.mediaType))throw Error("Only image uploads can be promoted to image entities");let f=ry({filename:w.record.filename,...x.title!==void 0?{title:x.title}:{}}),D=x.imageId??f.id;await this.reportProgress(A,{progress:60,message:"Saving uploaded image"});let $=new Date().toISOString(),Z=dB.createImageEntity({dataUrl:xIx(w.record.mediaType,w.content),title:f.title,status:"draft",sourceUploadId:x.uploadId,sourceFilename:w.record.filename,sourceMediaType:w.record.mediaType,attachmentType:"uploaded"}),Q=await l7({entityService:this.context.entityService,entity:{id:D,...Z,created:$,updated:$}});return await this.reportProgress(A,{progress:100,message:"Uploaded image promoted"}),{entityId:Q.entityId,status:"created"}}catch(w){if(x.imageId)await Nf({entityService:this.context.entityService,entityType:"image",id:x.imageId,error:g(w)});return p6.failure(w)}}summarizeDataForLog(x){return{uploadId:x.uploadId,imageId:x.imageId,hasTitle:x.title!==void 0}}}var BIx={name:"@brains/image-plugin",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Plugin for AI-powered image generation and management",dependencies:{"@brains/contracts":"workspace:*","@brains/entity-service":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},main:"./src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var bz9="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";function Vz9(x){return{source:"image",metadata:{operationType:"content_operations",interfaceType:x.interfaceType,requestedByActor:x.actor,...x.actor.kind==="user"?{requestedByUserId:x.actor.userId}:{},requestedByInterface:x.interfaceType}}}var Uz9=X.object({defaultAspectRatio:X.enum(["1:1","16:9","9:16","4:3","3:4"]).default("16:9").describe("Default aspect ratio for generated images")});function S3(x){let B=x?.trim();if(!B)return;return B}function Gz9(x){let B=S3(x.prompt);if(B)return B;let A=S3(x.content);if(A&&!U20(A))return A;return}function Ez9(x){let B=x.attachmentType==="og-image"?"og":x.attachmentType;return Gx(`${B}-${x.sourceEntityType}-${x.sourceEntityId}`)}function AIx(x){let B=S3(x.title)??(x.targetEntityId?`cover-${x.targetEntityId}`:x.prompt.slice(0,60).trim());return Gx(B)}async function jz9(x,B){let A=`${B.attachmentType}:${B.sourceEntityType}:${B.sourceEntityId}:resolved-attachment`,w=await x.entityService.getEntity({entityType:B.sourceEntityType,id:B.sourceEntityId});return w?`${A}:${w.contentHash}`:A}function j20(x,B="generated"){let A=encodeURIComponent(x);return{mediaType:"image/png",url:`/api/chat/attachments/image?id=${A}`,downloadUrl:`/api/chat/attachments/image?id=${A}&download=1`,filename:`${x}.png`,source:{entityType:"image",entityId:x,attachmentType:B}}}function _z9(x){let B=encodeURIComponent(x.entityId);return{mediaType:x.mediaType,url:`/api/chat/attachments/image?id=${B}`,downloadUrl:`/api/chat/attachments/image?id=${B}&download=1`,filename:x.filename,source:{entityType:"image",entityId:x.entityId,attachmentType:"uploaded"}}}class _20 extends g8{entityType=dB.entityType;schema=wIx;adapter=dB;constructor(x={}){super("image",BIx,x,Uz9)}getEntityTypeConfig(){return{embeddable:!1,projectionSource:!1,projectionSourceRole:"excluded"}}async interceptCreate(x,B,A){if(x.from?.kind===rq.refKind)return this.promoteUpload(x,A,B);let w=Gz9(x),f=S3(x.targetEntityType),D=S3(x.targetEntityId),$=f===this.entityType?D:void 0,Z=x.from;if(Z?.kind==="entity-attachment")return this.enqueueSourceImageRender({...x,from:Z},A);if(!f||!D||$){if(!w)return{kind:"continue",input:x};let F=S3(x.title)??$,K=AIx({prompt:w,...F&&{title:F}});await this.createPendingImage(A,{id:K,title:F??w.slice(0,60).trim(),alt:F??w.slice(0,60).trim(),attachmentType:"generated"});let q=await A.jobs.enqueue({type:"image-generate",data:{prompt:w,...F&&{title:F}}});return{kind:"handled",result:{success:!0,data:{entityId:K,status:"generating",jobId:q,attachment:j20(K)}}}}let Q=await oy(A.entityService,f,D,this.logger,"Target entity");if(!Q.ok)return{kind:"handled",result:{success:!1,error:Q.error}};if(!w)return{kind:"continue",input:{...x,targetEntityId:Q.entity.id}};let Y=ly(Q.entity.content),W=AIx({prompt:w,...x.title&&{title:x.title},targetEntityId:Q.entity.id});await this.createPendingImage(A,{id:W,title:x.title??`cover-${Q.entity.id}`,alt:x.title??`cover-${Q.entity.id}`,attachmentType:"generated",sourceEntityType:f,sourceEntityId:Q.entity.id});let H=await A.jobs.enqueue({type:"image-generate",data:{prompt:w,...x.title&&{title:x.title},targetEntityType:f,targetEntityId:Q.entity.id,entityTitle:typeof Q.entity.metadata.title==="string"?Q.entity.metadata.title:Q.entity.id,...Y&&{entityContent:Y}}});return{kind:"handled",result:{success:!0,data:{entityId:W,status:"generating",jobId:H,attachment:j20(W)}}}}async promoteUpload(x,B,A){let w=x.from;if(w?.kind!==rq.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let f=w.id,D;try{D=await B.uploads.scoped(rq).readRecord(f)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(!sy(D.mediaType))return{kind:"handled",result:{success:!1,error:"Only image uploads can be promoted to image entities"}};let $;try{$=ry({filename:D.filename,...x.title!==void 0?{title:x.title}:{}})}catch(Q){return{kind:"handled",result:{success:!1,error:g(Q)}}}await this.createPendingImage(B,{id:$.id,title:$.title,alt:$.title,sourceUploadId:f,sourceFilename:D.filename,sourceMediaType:D.mediaType,attachmentType:"uploaded"},A);let Z=await B.jobs.enqueue({type:"upload-promote",data:{uploadId:f,imageId:$.id,title:$.title},options:Vz9(A)});return{kind:"handled",result:{success:!0,data:{entityId:$.id,status:"generating",jobId:Z,attachment:_z9({mediaType:D.mediaType,entityId:$.id,filename:D.filename})}}}}async enqueueSourceImageRender(x,B){let A=S3(x.from.sourceEntityType),w=S3(x.from.sourceEntityId),f=S3(x.from.attachmentType);if(!A||!w||!f)return{kind:"handled",result:{success:!1,error:"Image source requires sourceEntityType, sourceEntityId, and attachmentType"}};let D=await oy(B.entityService,A,w,this.logger,"Source entity");if(!D.ok)return{kind:"handled",result:{success:!1,error:D.error}};let $=S3(x.targetEntityType),Z=S3(x.targetEntityId),Q;if($&&Z){let K=await oy(B.entityService,$,Z,this.logger,"Target entity");if(!K.ok)return{kind:"handled",result:{success:!1,error:K.error}};Q=K.entity.id}let Y={sourceEntityType:A,sourceEntityId:D.entity.id,attachmentType:f},W=await jz9(B,Y),H=Ez9(Y);await this.createPendingImage(B,{id:H,title:H,alt:H,sourceEntityType:Y.sourceEntityType,sourceEntityId:Y.sourceEntityId,attachmentType:f,dedupKey:W});let F=await B.jobs.enqueue({type:"image-render-source",data:{...Y,imageId:H,dedupKey:W,...x.replace===!0&&{replace:!0},...$&&{targetEntityType:$},...Q&&{targetEntityId:Q},...f==="og-image"&&{targetImageField:"ogImageId"}}});return{kind:"handled",result:{success:!0,data:{entityId:H,status:"generating",jobId:F,attachment:j20(H,f)}}}}async createPendingImage(x,B,A){let w=new Date().toISOString(),f=dB.createImageEntity({dataUrl:bz9,title:B.title,alt:B.alt,status:"pending",attachmentType:B.attachmentType,...B.sourceEntityType&&{sourceEntityType:B.sourceEntityType},...B.sourceEntityId&&{sourceEntityId:B.sourceEntityId},...B.sourceUploadId&&{sourceUploadId:B.sourceUploadId},...B.sourceFilename&&{sourceFilename:B.sourceFilename},...B.sourceMediaType&&{sourceMediaType:B.sourceMediaType},...B.dedupKey&&{dedupKey:B.dedupKey}});await _q({entityService:x.entityService,entity:{id:B.id,...f,created:w,updated:w},...A?{options:{eventContext:{actor:A.actor,interfaceType:A.interfaceType}}}:{}})}async getInstructions(){return"Image entities store durable images. Standalone generated images are valid system_generate image calls with a prompt source and no target fields. A prompt source creates a new image; never use it to describe, analyze, or discuss an existing uploaded image. For uploaded-image discussion, answer directly from the attachment/context; if the user later asks to save that discussion as a note, create entityType note from prior-response or exact text. targetEntityType and targetEntityId are only for attaching the result to an existing entity as coverImageId. Cover images and OG/social preview images are distinct domain concepts: cover-image fields use coverImageId, while OG/Open Graph/social preview fields use ogImageId. Rendered OG/social preview images are deterministic attachment-source images with attachmentType og-image."}createGenerationHandler(x){return new ay(x,this.logger)}async onRegister(x){x.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["image/*"],handler:async(A,w)=>{let f=await this.promoteUpload({entityType:this.entityType,...A.title!==void 0?{title:A.title}:{},from:A.upload},x,w);return f.kind==="handled"?f.result:{success:!1,error:"Image upload save was not handled"}}});let B=new ay(x,this.logger);x.jobs.registerHandler("image-generate",B),x.jobs.registerHandler("image-render-source",new G20(x,this.logger)),x.jobs.registerHandler("upload-promote",new E20(this.logger.child("UploadPromotionJobHandler"),x))}}function P20(x={}){return new _20(x)}var fIx=X.object({ref:X.string(),label:X.string()}),DIx=X.enum(["pending","draft","published"]),U_=X.object({status:DIx,title:X.string(),url:X.string().url(),description:X.string().optional(),domain:X.string(),capturedAt:X.string().datetime(),source:fIx}),$Ix=U_.pick({title:!0,status:!0}),RY=j8.extend({entityType:X.literal("link"),metadata:$Ix});var J20=X.object({enableSummarization:X.boolean().default(!0).describe("Generate AI summaries for captured links"),jinaApiKey:X.string().optional().describe("Jina Reader API key for higher rate limits (500 RPM vs 20 RPM without key)")});class qZ extends ox{constructor(){super({entityType:"link",purpose:"A saved external URL or web resource captured for later reference.",schema:RY,frontmatterSchema:U_})}createLinkContent(x){let B={status:x.status,title:x.title,url:x.url,description:x.description,domain:x.domain,capturedAt:x.capturedAt,source:x.source},A=x.summary??"";return this.buildMarkdown(A,B)}parseLinkContent(x){return{frontmatter:this.parseFrontMatter(x,U_),summary:this.extractBody(x).trim()}}fromMarkdown(x){let{frontmatter:B}=this.parseLinkContent(x);return{content:x,entityType:"link",metadata:{title:B.title,status:B.status}}}}var oq=new qZ;var Pz9=X.object({success:X.boolean().describe("Set to true if you can extract meaningful content. Set to false only if the provided content is empty, just an error message, or otherwise unusable."),error:X.string().describe("If success is false, explain why content could not be extracted. Use an empty string when success is true."),title:X.string().max(80).describe("The page title - extract from the content or create a descriptive one. Leave empty string if success is false."),description:X.string().describe("A one-sentence description of what the page is about. Leave empty string if success is false."),summary:X.string().describe("A 1-2 paragraph summary of the main content. Leave empty string if success is false.")}),ZIx=mx({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:Pz9,basePrompt:`You are an expert at extracting key information from webpage content.
5658
+ ${F}`,Wz9);H=`${w.trim()} ${G.imagePrompt}`}catch(G){this.logger.warn("AI prompt distillation failed, using fallback",{error:g(G)})}}await this.reportProgress(A,{progress:b8.PROCESS,message:"Generating image"});let q=oNx(Y)+H,V;try{V=await this.context.ai.generateImage(q,{...f&&{aspectRatio:f}})}catch(G){return this.logger.error("Image generation failed",{jobId:B,error:g(G)}),p6.failure(G)}await this.reportProgress(A,{progress:b8.GENERATE,message:"Creating image entity"});let b=dB.createImageEntity({dataUrl:V.dataUrl,title:Z,status:"draft",attachmentType:"generated",...D&&{sourceEntityType:D},...$&&{sourceEntityId:$}});if(await l7({entityService:this.context.entityService,entity:{...b,id:Q}}),this.logger.debug("Created image entity",{imageId:Q}),D&&$){await this.reportProgress(A,{progress:b8.SAVE,message:`Updating ${D} with cover image`});let G=await ny(this.context.entityService,D,$,this.logger);if(!G)return p6.failure(Error(`Target entity not found: ${D}/${$}`));let E=dy(G,Q);await this.context.entities.update(E),this.logger.debug("Updated target entity with cover image",{targetEntityType:D,targetEntityId:$,imageId:Q})}return await this.reportProgress(A,{progress:b8.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:B,imageId:Q,targetEntityType:D,targetEntityId:$}),{success:!0,imageId:Q}}catch(Y){let W=g(Y);return this.logger.error("Image generation job failed",{jobId:B,error:W}),await Nf({entityService:this.context.entityService,entityType:"image",id:Q,error:W}),p6.failure(Y)}}summarizeDataForLog(x){return{title:x.title,promptLength:x.prompt.length,aspectRatio:x.aspectRatio,targetEntityType:x.targetEntityType,targetEntityId:x.targetEntityId}}}var Fz9=X.object({sourceEntityType:X.string().min(1),sourceEntityId:X.string().min(1),attachmentType:X.string().min(1),imageId:X.string().min(1),dedupKey:X.string().min(1).optional(),replace:X.boolean().optional(),targetEntityType:X.string().min(1).optional(),targetEntityId:X.string().min(1).optional(),targetImageField:X.enum(["coverImageId","ogImageId"]).optional()});class G20 extends $9{context;constructor(x,B){super(B,{schema:Fz9,jobTypeName:"image-render-source"});this.context=x}async process(x,B,A){this.logger.debug("Starting source image render job",{jobId:B,sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType,imageId:x.imageId});try{if(x.replace!==!0&&x.dedupKey){let $=await this.findImageByDedupKey(x.dedupKey);if($)return await this.updateTarget(x,$.id),await this.reportProgress(A,{progress:b8.COMPLETE,message:"Reusing existing generated image"}),{success:!0,imageId:$.id,reused:!0}}await this.reportProgress(A,{progress:b8.PROCESS,message:"Rendering source image"});let w=await this.context.attachments.resolve({sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType});if(!w)return p6.failure(Error(`No attachment provider found for ${x.sourceEntityType}/${x.attachmentType}`));if(w.type!=="image")return p6.failure(Error(`Attachment provider returned ${w.type}; expected image`));await this.reportProgress(A,{progress:b8.GENERATE,message:"Creating image entity"});let f=w.mimeType.split("/")[1]??"png",D=dB.createImageEntity({dataUrl:tNx(w.data.toString("base64"),f),title:x.imageId,status:"draft",sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:x.attachmentType,...x.dedupKey&&{dedupKey:x.dedupKey}});return await l7({entityService:this.context.entityService,entity:{...D,id:x.imageId}}),await this.updateTarget(x,x.imageId),await this.reportProgress(A,{progress:b8.COMPLETE,message:"Image render complete"}),{success:!0,imageId:x.imageId,reused:!1}}catch(w){let f=g(w);return this.logger.error("Source image render job failed",{jobId:B,error:f}),await Nf({entityService:this.context.entityService,entityType:"image",id:x.imageId,error:f}),p6.failure(w)}}async findImageByDedupKey(x){return(await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{dedupKey:x}}}})).find((A)=>A.metadata.status!=="pending"&&A.metadata.status!=="failed")}async updateTarget(x,B){if(!x.targetEntityType||!x.targetEntityId)return;let A=await ny(this.context.entityService,x.targetEntityType,x.targetEntityId,this.logger);if(!A)throw Error(`Target entity not found: ${x.targetEntityType}/${x.targetEntityId}`);let f=(x.targetImageField??"coverImageId")==="ogImageId"?eNx(A,B):dy(A,B);await this.context.entities.update(f)}}var rq={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function sy(x){return["image/png","image/jpeg","image/webp","image/gif"].includes(x.toLowerCase())}function ry(x){let B=Kz9(x.title,x.filename),A=Gx(B);if(!A)throw Error("Could not derive an image id from the uploaded filename. Provide a title.");return{id:A,title:B}}function xIx(x,B){return`data:${x};base64,${B.toString("base64")}`}function Kz9(x,B){let A=x?.trim();if(A)return A;return B.replace(/\.[^.]+$/,"").trim()||B}var qz9=X.object({uploadId:X.string().min(1),imageId:X.string().min(1).optional(),title:X.string().optional()});class E20 extends $9{context;constructor(x,B){super(x,{schema:qz9,jobTypeName:"upload-promote"});this.context=B}async process(x,B,A){try{await this.reportProgress(A,{progress:10,message:"Reading uploaded image"});let w=await this.context.uploads.scoped(rq).read(x.uploadId);if(!sy(w.record.mediaType))throw Error("Only image uploads can be promoted to image entities");let f=ry({filename:w.record.filename,...x.title!==void 0?{title:x.title}:{}}),D=x.imageId??f.id;await this.reportProgress(A,{progress:60,message:"Saving uploaded image"});let $=new Date().toISOString(),Z=dB.createImageEntity({dataUrl:xIx(w.record.mediaType,w.content),title:f.title,status:"draft",sourceUploadId:x.uploadId,sourceFilename:w.record.filename,sourceMediaType:w.record.mediaType,attachmentType:"uploaded"}),Q=await l7({entityService:this.context.entityService,entity:{id:D,...Z,created:$,updated:$}});return await this.reportProgress(A,{progress:100,message:"Uploaded image promoted"}),{entityId:Q.entityId,status:"created"}}catch(w){if(x.imageId)await Nf({entityService:this.context.entityService,entityType:"image",id:x.imageId,error:g(w)});return p6.failure(w)}}summarizeDataForLog(x){return{uploadId:x.uploadId,imageId:x.imageId,hasTitle:x.title!==void 0}}}var BIx={name:"@brains/image-plugin",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Plugin for AI-powered image generation and management",dependencies:{"@brains/contracts":"workspace:*","@brains/entity-service":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},main:"./src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var bz9="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";function Vz9(x){return{source:"image",metadata:{operationType:"content_operations",interfaceType:x.interfaceType,requestedByActor:x.actor,...x.actor.kind==="user"?{requestedByUserId:x.actor.userId}:{},requestedByInterface:x.interfaceType}}}var Uz9=X.object({defaultAspectRatio:X.enum(["1:1","16:9","9:16","4:3","3:4"]).default("16:9").describe("Default aspect ratio for generated images")});function S3(x){let B=x?.trim();if(!B)return;return B}function Gz9(x){let B=S3(x.prompt);if(B)return B;let A=S3(x.content);if(A&&!U20(A))return A;return}function Ez9(x){let B=x.attachmentType==="og-image"?"og":x.attachmentType;return Gx(`${B}-${x.sourceEntityType}-${x.sourceEntityId}`)}function AIx(x){let B=S3(x.title)??(x.targetEntityId?`cover-${x.targetEntityId}`:x.prompt.slice(0,60).trim());return Gx(B)}async function jz9(x,B){let A=`${B.attachmentType}:${B.sourceEntityType}:${B.sourceEntityId}:resolved-attachment`,w=await x.entityService.getEntity({entityType:B.sourceEntityType,id:B.sourceEntityId});return w?`${A}:${w.contentHash}`:A}function j20(x,B="generated"){let A=encodeURIComponent(x);return{mediaType:"image/png",url:`/api/chat/attachments/image?id=${A}`,downloadUrl:`/api/chat/attachments/image?id=${A}&download=1`,filename:`${x}.png`,source:{entityType:"image",entityId:x,attachmentType:B}}}function _z9(x){let B=encodeURIComponent(x.entityId);return{mediaType:x.mediaType,url:`/api/chat/attachments/image?id=${B}`,downloadUrl:`/api/chat/attachments/image?id=${B}&download=1`,filename:x.filename,source:{entityType:"image",entityId:x.entityId,attachmentType:"uploaded"}}}class _20 extends g8{entityType=dB.entityType;schema=wIx;adapter=dB;constructor(x={}){super("image",BIx,x,Uz9)}getEntityTypeConfig(){return{embeddable:!1,projectionSource:!1,projectionSourceRole:"excluded"}}async interceptCreate(x,B,A){if(x.from?.kind===rq.refKind)return this.promoteUpload(x,A,B);let w=Gz9(x),f=S3(x.targetEntityType),D=S3(x.targetEntityId),$=f===this.entityType?D:void 0,Z=x.from;if(Z?.kind==="entity-attachment")return this.enqueueSourceImageRender({...x,from:Z},A);if(!f||!D||$){if(!w)return{kind:"continue",input:x};let F=S3(x.title)??$,K=AIx({prompt:w,...F&&{title:F}});await this.createPendingImage(A,{id:K,title:F??w.slice(0,60).trim(),alt:F??w.slice(0,60).trim(),attachmentType:"generated"});let q=await A.jobs.enqueue({type:"image-generate",data:{prompt:w,...F&&{title:F}}});return{kind:"handled",result:{success:!0,data:{entityId:K,status:"generating",jobId:q,attachment:j20(K)}}}}let Q=await oy(A.entityService,f,D,this.logger,"Target entity");if(!Q.ok)return{kind:"handled",result:{success:!1,error:Q.error}};if(!w)return{kind:"continue",input:{...x,targetEntityId:Q.entity.id}};let Y=ly(Q.entity.content),W=AIx({prompt:w,...x.title&&{title:x.title},targetEntityId:Q.entity.id});await this.createPendingImage(A,{id:W,title:x.title??`cover-${Q.entity.id}`,alt:x.title??`cover-${Q.entity.id}`,attachmentType:"generated",sourceEntityType:f,sourceEntityId:Q.entity.id});let H=await A.jobs.enqueue({type:"image-generate",data:{prompt:w,...x.title&&{title:x.title},targetEntityType:f,targetEntityId:Q.entity.id,entityTitle:typeof Q.entity.metadata.title==="string"?Q.entity.metadata.title:Q.entity.id,...Y&&{entityContent:Y}}});return{kind:"handled",result:{success:!0,data:{entityId:W,status:"generating",jobId:H,attachment:j20(W)}}}}async promoteUpload(x,B,A){let w=x.from;if(w?.kind!==rq.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let f=w.id,D;try{D=await B.uploads.scoped(rq).readRecord(f)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(!sy(D.mediaType))return{kind:"handled",result:{success:!1,error:"Only image uploads can be promoted to image entities"}};let $;try{$=ry({filename:D.filename,...x.title!==void 0?{title:x.title}:{}})}catch(Q){return{kind:"handled",result:{success:!1,error:g(Q)}}}await this.createPendingImage(B,{id:$.id,title:$.title,alt:$.title,sourceUploadId:f,sourceFilename:D.filename,sourceMediaType:D.mediaType,attachmentType:"uploaded"},A);let Z=await B.jobs.enqueue({type:"upload-promote",data:{uploadId:f,imageId:$.id,title:$.title},options:Vz9(A)});return{kind:"handled",result:{success:!0,data:{entityId:$.id,status:"generating",jobId:Z,attachment:_z9({mediaType:D.mediaType,entityId:$.id,filename:D.filename})}}}}async enqueueSourceImageRender(x,B){let A=S3(x.from.sourceEntityType),w=S3(x.from.sourceEntityId),f=S3(x.from.attachmentType);if(!A||!w||!f)return{kind:"handled",result:{success:!1,error:"Image source requires sourceEntityType, sourceEntityId, and attachmentType"}};let D=await oy(B.entityService,A,w,this.logger,"Source entity");if(!D.ok)return{kind:"handled",result:{success:!1,error:D.error}};let $=S3(x.targetEntityType),Z=S3(x.targetEntityId),Q;if($&&Z){let K=await oy(B.entityService,$,Z,this.logger,"Target entity");if(!K.ok)return{kind:"handled",result:{success:!1,error:K.error}};Q=K.entity.id}let Y={sourceEntityType:A,sourceEntityId:D.entity.id,attachmentType:f},W=await jz9(B,Y),H=Ez9(Y);await this.createPendingImage(B,{id:H,title:H,alt:H,sourceEntityType:Y.sourceEntityType,sourceEntityId:Y.sourceEntityId,attachmentType:f,dedupKey:W});let F=await B.jobs.enqueue({type:"image-render-source",data:{...Y,imageId:H,dedupKey:W,...x.replace===!0&&{replace:!0},...$&&{targetEntityType:$},...Q&&{targetEntityId:Q},...f==="og-image"&&{targetImageField:"ogImageId"}}});return{kind:"handled",result:{success:!0,data:{entityId:H,status:"generating",jobId:F,attachment:j20(H,f)}}}}async createPendingImage(x,B,A){let w=new Date().toISOString(),f=dB.createImageEntity({dataUrl:bz9,title:B.title,alt:B.alt,status:"pending",attachmentType:B.attachmentType,...B.sourceEntityType&&{sourceEntityType:B.sourceEntityType},...B.sourceEntityId&&{sourceEntityId:B.sourceEntityId},...B.sourceUploadId&&{sourceUploadId:B.sourceUploadId},...B.sourceFilename&&{sourceFilename:B.sourceFilename},...B.sourceMediaType&&{sourceMediaType:B.sourceMediaType},...B.dedupKey&&{dedupKey:B.dedupKey}});await _q({entityService:x.entityService,entity:{id:B.id,...f,created:w,updated:w},...A?{options:{eventContext:{actor:A.actor,interfaceType:A.interfaceType}}}:{}})}async getInstructions(){return"Image entities store durable images. Standalone generated images are valid system_generate image calls with a prompt source and no target fields. A prompt source creates a new image; never use it to describe, analyze, or discuss an existing uploaded image. For uploaded-image discussion, answer directly from the attachment/context; if the user later asks to save that discussion as a note, create entityType note from prior-response or exact text. targetEntityType and targetEntityId are only for attaching the result to an existing entity as coverImageId. Cover images and OG/social preview images are distinct domain concepts: cover-image fields use coverImageId, while OG/Open Graph/social preview fields use ogImageId. Rendered OG/social preview images are deterministic attachment-source images with attachmentType og-image."}createGenerationHandler(x){return new ay(x,this.logger)}async onRegister(x){x.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["image/*"],handler:async(A,w)=>{let f=await this.promoteUpload({entityType:this.entityType,...A.title!==void 0?{title:A.title}:{},from:A.upload},x,w);return f.kind==="handled"?f.result:{success:!1,error:"Image upload save was not handled"}}});let B=new ay(x,this.logger);x.jobs.registerHandler("image-generate",B),x.jobs.registerHandler("image-render-source",new G20(x,this.logger)),x.jobs.registerHandler("upload-promote",new E20(this.logger.child("UploadPromotionJobHandler"),x))}}function P20(x={}){return new _20(x)}var fIx=X.object({ref:X.string(),label:X.string()}),DIx=X.enum(["pending","draft","published"]),U_=X.object({status:DIx,title:X.string(),url:X.string().url(),description:X.string().optional(),domain:X.string(),capturedAt:X.string().datetime(),source:fIx}),$Ix=U_.pick({title:!0,status:!0}),RY=j8.extend({entityType:X.literal("link"),metadata:$Ix});var J20=X.object({enableSummarization:X.boolean().default(!0).describe("Generate AI summaries for captured links"),jinaApiKey:X.string().optional().describe("Jina Reader API key for higher rate limits (500 RPM vs 20 RPM without key)")});class qZ extends ox{constructor(){super({entityType:"link",purpose:"A saved external URL or web resource captured for later reference.",schema:RY,frontmatterSchema:U_})}createLinkContent(x){let B={status:x.status,title:x.title,url:x.url,description:x.description,domain:x.domain,capturedAt:x.capturedAt,source:x.source},A=x.summary??"";return this.buildMarkdown(A,B)}parseLinkContent(x){return{frontmatter:this.parseFrontMatter(x,U_),summary:this.extractBody(x).trim()}}fromMarkdown(x){let{frontmatter:B}=this.parseLinkContent(x);return{content:x,entityType:"link",metadata:{title:B.title,status:B.status}}}}var oq=new qZ;var Pz9=X.object({success:X.boolean().describe("Set to true if you can extract meaningful content. Set to false only if the provided content is empty, just an error message, or otherwise unusable."),error:X.string().describe("If success is false, explain why content could not be extracted. Use an empty string when success is true."),title:X.string().max(80).describe("The page title - extract from the content or create a descriptive one. Leave empty string if success is false."),description:X.string().describe("A one-sentence description of what the page is about. Leave empty string if success is false."),summary:X.string().describe("A 1-2 paragraph summary of the main content. Leave empty string if success is false.")}),ZIx=mx({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:Pz9,basePrompt:`You are an expert at extracting key information from webpage content.
5659
5659
 
5660
5660
  You will receive webpage content in markdown format. Your job is to extract structured information from it.
5661
5661
 
@@ -5677,9 +5677,9 @@ Accuracy rules:
5677
5677
 
5678
5678
  `))return{success:!1,error:$.trim(),errorType:"fetch_failed"};return{success:!0,content:$}}catch(A){return this.handleFetchError(A,x)}}handleHttpError(x,B){if(x===400)return{success:!1,error:`Invalid or non-existent URL: ${B}`,errorType:"url_not_found"};if(x===404)return{success:!1,error:`Page not found: ${B}`,errorType:"url_not_found"};if(x>=500)return{success:!1,error:`Server error while fetching ${B}`,errorType:"url_unreachable"};return{success:!1,error:`HTTP ${x} error while fetching ${B}`,errorType:"fetch_failed"}}handleFetchError(x,B){if(x instanceof Error){if(x.name==="AbortError")return{success:!1,error:`Request timeout while fetching ${B}`,errorType:"url_unreachable"};if(x.message.includes("ENOTFOUND")||x.message.includes("getaddrinfo"))return{success:!1,error:`Domain not found: ${new URL(B).hostname}`,errorType:"url_not_found"};if(x.message.includes("ECONNREFUSED")||x.message.includes("ETIMEDOUT"))return{success:!1,error:`Could not connect to ${B}`,errorType:"url_unreachable"};return{success:!1,error:`Failed to fetch ${B}: ${x.message}`,errorType:"fetch_failed"}}return{success:!1,error:`Unknown error fetching ${B}`,errorType:"fetch_failed"}}}import{createHash as Nz9}from"crypto";class bZ{static URL_PATTERN=/https?:\/\/[^\s<>"{}|\\^`[\]]+?(?=[,;:\s]|$)/gi;static extractUrls(x){let B=x.match(bZ.URL_PATTERN)??[];return[...new Set(B)]}static normalizeUrl(x){try{let B=new URL(x),A=B.pathname.replace(/\/$/,"")||"/";return`${B.protocol}//${B.host}${A}`}catch{return x}}static generateEntityId(x){let B=this.normalizeUrl(x),A=Nz9("sha256").update(B).digest("hex");try{return`${new URL(B).hostname.replace(/\./g,"-")}-${A.substring(0,6)}`}catch{return A.substring(0,12)}}static isValidUrl(x){try{let B=new URL(x);return["http:","https:"].includes(B.protocol)}catch{return!1}}}var Iz9=X.object({interfaceId:X.string().optional(),userId:X.string().optional(),channelId:X.string().optional(),channelName:X.string().optional(),timestamp:X.string().optional()}),Oz9=X.object({url:X.url(),metadata:Iz9.optional()}),et6=X.object({success:X.boolean(),entityId:X.string().optional(),title:X.string().optional(),url:X.string().optional(),status:X.enum(["pending","draft","published"]).optional(),error:X.string().optional()});class ey extends $9{context;linkAdapter;urlFetcher;constructor(x,B,A){super(x,{schema:Oz9,jobTypeName:"link-capture"});this.context=B,this.linkAdapter=new qZ,this.urlFetcher=new tq(A?.jinaApiKey?{jinaApiKey:A.jinaApiKey}:void 0)}async process(x,B,A){let{url:w,metadata:f}=x;try{await A.report({progress:b8.START,total:100,message:"Starting link capture"});let D=bZ.generateEntityId(w);await A.report({progress:b8.INIT,total:100,message:"Checking for existing link"});let $=await this.context.entityService.getEntity({entityType:"link",id:D});if($){let{frontmatter:K}=this.linkAdapter.parseLinkContent($.content),q=$.metadata.status;if(q!=="pending")return this.logger.info("Link already captured, returning existing",{url:w,entityId:D}),{success:!0,entityId:$.id,title:K.title,url:w,status:q};this.logger.info("Pending link exists, completing extraction",{url:w,entityId:D})}let Z=this.resolveSource(f),Q=new Date().toISOString();await A.report({progress:b8.FETCH,total:100,message:"Fetching webpage content"});let Y=await this.urlFetcher.fetch(w);if(!Y.success){if(Y.errorType==="url_not_found"||Y.errorType==="url_unreachable"){this.logger.warn("Link URL not accessible",{url:w,errorType:Y.errorType,error:Y.error});let K=new URL(w).hostname,q=`Could not capture link: ${Y.error}`,V=this.linkAdapter.createLinkContent({status:"pending",title:K,url:w,description:q,summary:q,domain:K,capturedAt:Q,source:Z});return await l7({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:V,metadata:{status:"pending",title:K}}}),{success:!1,entityId:D,title:K,url:w,status:"pending",error:q}}}await A.report({progress:b8.PROCESS,total:100,message:"Extracting content with AI"});let W=await this.context.ai.generate({templateName:"link:extraction",prompt:Y.success?`Extract structured information from this webpage content:
5679
5679
 
5680
- ${Y.content}`:`The URL ${w} could not be fetched. Return success: false with error: "${Y.error}"`,data:{url:w,hasContent:Y.success},representedIdentity:"none",interfacePermissionGrant:"public"});if(this.logger.debug("AI extraction result",{result:W}),await A.report({progress:b8.EXTRACT,total:100,message:"Processing extraction results"}),W.success===!1||!W.title||!W.description||!W.summary){let K=W.title||new URL(w).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:w}),await A.report({progress:b8.SAVE,total:100,message:"Saving link as pending"});let q=this.linkAdapter.createLinkContent({status:"pending",title:K,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:Q,source:Z}),V=await l7({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:q,metadata:{status:"pending",title:K}}});return await A.report({progress:b8.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:V.entityId,title:K,url:w,status:"pending"}}await A.report({progress:b8.SAVE,total:100,message:`Saving link: "${W.title}"`});let H=this.linkAdapter.createLinkContent({status:"draft",title:W.title,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:Q,source:Z}),F=await l7({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:H,metadata:{status:"draft",title:W.title}}});return await A.report({progress:b8.COMPLETE,total:100,message:`Link captured: "${W.title}"`}),{success:!0,entityId:F.entityId,title:W.title,url:w,status:"draft"}}catch(D){return this.logger.error("Link capture job failed",{error:D,jobId:B,data:x}),p6.failure(D)}}resolveSource(x){let B=x?.channelId,A=x?.channelName;if(B)return{ref:`matrix:${B}`,label:A??B};let w=x?.interfaceId??"cli";return{ref:`${w}:local`,label:w.toUpperCase()}}summarizeDataForLog(x){return{url:x.url,interfaceId:x.metadata?.interfaceId}}}async function WIx({entity:x,config:B}){let A=RY.parse(x),{frontmatter:w,summary:f}=oq.parseLinkContent(A.content);return{$type:"ai.rizom.brain.link",title:w.title,url:w.url,...w.description&&{description:w.description},...f&&{summary:f},domain:w.domain,capturedAt:w.capturedAt,source:w.source,...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"link",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function I20(){return{entityType:"link",collection:"ai.rizom.brain.link",lexicon:h4["ai.rizom.brain.link"],validate:!1,buildRecord:WIx}}var HIx={name:"@brains/link",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Web content capture plugin with AI-powered extraction and structured storage",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Rz9=X.object({url:X.url()});class O20 extends g8{entityType=oq.entityType;schema=RY;adapter=oq;shell;unregisterAtprotoProjection;constructor(x={}){super("link",HIx,x,J20)}getEntityTypeConfig(){return{projectionSourceRole:"supporting"}}async register(x){this.shell=x;let B=await super.register(x);if(!this.context)throw Error("LinkPlugin context was not initialized during register()");return x.getJobQueueService().registerHandler("link-capture",new ey(this.logger.child("LinkCaptureJobHandler"),this.context,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0),this.id),B}async interceptCreate(x,B,A){if(x.content)try{let D=this.adapter.fromMarkdown(x.content).metadata,$=typeof D?.title==="string"?D.title:void 0,Z=typeof D?.status==="string"?D.status:void 0,Q=this.extractFirstUrl(x.content);if($&&Z&&Q){let Y=Gx(Q)||Gx($)||`${x.entityType}-${Date.now()}`,W=new Date().toISOString();return{kind:"handled",result:{success:!0,data:{entityId:(await A.entityService.createEntity({entity:{id:Y,entityType:x.entityType,content:x.content,metadata:{title:$,status:Z},created:W,updated:W}})).entityId,status:"created"}}}}}catch{}let w=x.url??this.extractFirstUrl(x.content,x.prompt,x.title);if(w){if(!this.shell)throw Error("LinkPlugin shell was not initialized during register()");try{let f=tH(B),D=await this.createPendingLink(w,x.title,B,A),$=await this.shell.getJobQueueService().enqueue({type:"link-capture",data:{url:w,metadata:{interfaceId:B.interfaceType,...f?{userId:f}:{},...B.channelId?{channelId:B.channelId}:{},...B.channelName?{channelName:B.channelName}:{},timestamp:new Date().toISOString()}},options:{source:this.id,metadata:{operationType:"data_processing",pluginId:this.id,interfaceType:B.interfaceType,requestedByActor:B.actor,...f?{requestedByUserId:f}:{},...B.channelId?{channelId:B.channelId}:{}}}});return{kind:"handled",result:{success:!0,data:{entityId:D,status:"generating",jobId:$}}}}catch(f){return{kind:"handled",result:{success:!1,error:g(f,"Failed to queue link capture job")}}}}if(x.content)return{kind:"handled",result:{success:!1,error:"Direct link creation requires full link markdown/frontmatter, or provide a URL to capture."}};if(x.prompt)return{kind:"handled",result:{success:!1,error:"Link creation requires a URL in the prompt, content, or title, or full link markdown content for direct creation."}};return{kind:"continue",input:x}}createGenerationHandler(x){return new ey(this.logger.child("LinkCaptureJobHandler"),x,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:ZIx,"link-list":QIx,"link-detail":YIx}}getDataSources(){return[new N20(this.logger.child("LinksDataSource"))]}async onRegister(x){this.unregisterAtprotoProjection=R4.getInstance().register(I20()),x.eval.registerHandler("extractContent",async(B)=>{let{url:A}=Rz9.parse(B),f=await new tq(this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0).fetch(A);if(!f.success)return{success:!1,error:f.error,errorType:f.errorType};return x.ai.generate({templateName:"link:extraction",prompt:`Extract structured information from this webpage content:
5680
+ ${Y.content}`:`The URL ${w} could not be fetched. Return success: false with error: "${Y.error}"`,data:{url:w,hasContent:Y.success},representedIdentity:"none",interfacePermissionGrant:"public"});if(this.logger.debug("AI extraction result",{result:W}),await A.report({progress:b8.EXTRACT,total:100,message:"Processing extraction results"}),W.success===!1||!W.title||!W.description||!W.summary){let K=W.title||new URL(w).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:w}),await A.report({progress:b8.SAVE,total:100,message:"Saving link as pending"});let q=this.linkAdapter.createLinkContent({status:"pending",title:K,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:Q,source:Z}),V=await l7({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:q,metadata:{status:"pending",title:K}}});return await A.report({progress:b8.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:V.entityId,title:K,url:w,status:"pending"}}await A.report({progress:b8.SAVE,total:100,message:`Saving link: "${W.title}"`});let H=this.linkAdapter.createLinkContent({status:"draft",title:W.title,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:Q,source:Z}),F=await l7({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:H,metadata:{status:"draft",title:W.title}}});return await A.report({progress:b8.COMPLETE,total:100,message:`Link captured: "${W.title}"`}),{success:!0,entityId:F.entityId,title:W.title,url:w,status:"draft"}}catch(D){return this.logger.error("Link capture job failed",{error:D,jobId:B,data:x}),p6.failure(D)}}resolveSource(x){let B=x?.channelId,A=x?.channelName;if(B)return{ref:`matrix:${B}`,label:A??B};let w=x?.interfaceId??"cli";return{ref:`${w}:local`,label:w.toUpperCase()}}summarizeDataForLog(x){return{url:x.url,interfaceId:x.metadata?.interfaceId}}}async function WIx({entity:x,config:B}){let A=RY.parse(x),{frontmatter:w,summary:f}=oq.parseLinkContent(A.content);return{$type:"ai.rizom.brain.link",title:w.title,url:w.url,...w.description&&{description:w.description},...f&&{summary:f},domain:w.domain,capturedAt:w.capturedAt,source:w.source,...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"link",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function I20(){return{entityType:"link",collection:"ai.rizom.brain.link",lexicon:h4["ai.rizom.brain.link"],validate:!1,buildRecord:WIx}}var HIx={name:"@brains/link",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Web content capture plugin with AI-powered extraction and structured storage",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Rz9=X.object({url:X.url()});class O20 extends g8{entityType=oq.entityType;schema=RY;adapter=oq;shell;unregisterAtprotoProjection;constructor(x={}){super("link",HIx,x,J20)}getEntityTypeConfig(){return{projectionSourceRole:"supporting"}}async register(x){this.shell=x;let B=await super.register(x);if(!this.context)throw Error("LinkPlugin context was not initialized during register()");return x.getJobQueueService().registerHandler("link-capture",new ey(this.logger.child("LinkCaptureJobHandler"),this.context,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0),this.id),B}async interceptCreate(x,B,A){if(x.content)try{let D=this.adapter.fromMarkdown(x.content).metadata,$=typeof D?.title==="string"?D.title:void 0,Z=typeof D?.status==="string"?D.status:void 0,Q=this.extractFirstUrl(x.content);if($&&Z&&Q){let Y=Gx(Q)||Gx($)||`${x.entityType}-${Date.now()}`,W=new Date().toISOString();return{kind:"handled",result:{success:!0,data:{entityId:(await A.entityService.createEntity({entity:{id:Y,entityType:x.entityType,content:x.content,metadata:{title:$,status:Z},created:W,updated:W}})).entityId,status:"created"}}}}}catch{}let w=x.url??this.extractFirstUrl(x.content,x.prompt,x.title);if(w){if(!this.shell)throw Error("LinkPlugin shell was not initialized during register()");try{let f=tH(B),D=await this.createPendingLink(w,x.title,B,A),$=await this.shell.getJobQueueService().enqueue({type:"link-capture",data:{url:w,metadata:{interfaceId:B.interfaceType,...f?{userId:f}:{},...B.channelId?{channelId:B.channelId}:{},...B.channelName?{channelName:B.channelName}:{},timestamp:new Date().toISOString()}},options:{source:this.id,metadata:{operationType:"data_processing",pluginId:this.id,interfaceType:B.interfaceType,requestedByActor:B.actor,...f?{requestedByUserId:f}:{},...B.channelId?{channelId:B.channelId}:{}}}});return{kind:"handled",result:{success:!0,data:{entityId:D,status:"generating",jobId:$}}}}catch(f){return{kind:"handled",result:{success:!1,error:g(f,"Failed to queue link capture job")}}}}if(x.content)return{kind:"handled",result:{success:!1,error:"Direct link creation requires full link markdown/frontmatter, or provide a URL to capture."}};if(x.prompt)return{kind:"handled",result:{success:!1,error:"Link creation requires a URL in the prompt, content, or title, or full link markdown content for direct creation."}};return{kind:"continue",input:x}}createGenerationHandler(x){return new ey(this.logger.child("LinkCaptureJobHandler"),x,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:ZIx,"link-list":QIx,"link-detail":YIx}}getDataSources(){return[new N20(this.logger.child("LinksDataSource"))]}async onRegister(x){this.unregisterAtprotoProjection=R4.getInstance().register(I20()),x.eval.registerHandler("extractContent",async(B)=>{let{url:A}=Rz9.parse(B),f=await new tq(this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0).fetch(A);if(!f.success)return{success:!1,error:f.error,errorType:f.errorType};return x.ai.generate({templateName:"link:extraction",prompt:`Extract structured information from this webpage content:
5681
5681
 
5682
- ${f.content}`,data:{url:A,hasContent:!0},representedIdentity:"none",interfacePermissionGrant:"public"})})}async createPendingLink(x,B,A,w){let f=bZ.generateEntityId(x),D=new URL(x),$=new Date().toISOString(),Z=B?.trim()?B.trim():D.hostname,Q=this.adapter.createLinkContent({status:"pending",title:Z,url:x,description:"Link capture is in progress.",summary:`Pending link capture for ${x}.`,domain:D.hostname,capturedAt:$,source:this.resolveSource(A)});return(await _q({entityService:w.entityService,entity:{id:f,entityType:"link",content:Q,metadata:{status:"pending",title:Z},created:$,updated:$}})).entityId}resolveSource(x){if(x.channelId)return{ref:`matrix:${x.channelId}`,label:x.channelName??x.channelId};return{ref:`${x.interfaceType}:local`,label:x.interfaceType.toUpperCase()}}extractFirstUrl(...x){for(let B of x){if(!B)continue;let[A]=bZ.extractUrls(B);if(A)return A}return}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function FIx(x={}){return new O20(x)}var h20=FIx;var yz9=X.object({conversationId:X.string().optional(),interfaceId:X.string().optional(),userId:X.string().optional(),messageId:X.string().optional(),timestamp:X.string().optional()}),ve6=X.object({id:X.string().optional(),metadata:yz9.optional()});import{StdioServerTransport as Cz9}from"@modelcontextprotocol/sdk/server/stdio.js";var mz9=X.custom((x)=>typeof x==="object"&&x!==null&&("info"in x)&&typeof x.info==="function"&&("debug"in x)&&typeof x.debug==="function"&&("error"in x)&&typeof x.error==="function"&&("warn"in x)&&typeof x.warn==="function");function KIx(){return{info:(x,...B)=>console.error(`[STDIO MCP] ${x}`,...B),debug:(x,...B)=>console.error(`[STDIO MCP DEBUG] ${x}`,...B),error:(x,...B)=>console.error(`[STDIO MCP ERROR] ${x}`,...B),warn:(x,...B)=>console.error(`[STDIO MCP WARN] ${x}`,...B)}}function R20(){return{info:(x,...B)=>console.log(`[HTTP MCP] ${x}`,...B),debug:(x,...B)=>console.debug(`[HTTP MCP DEBUG] ${x}`,...B),error:(x,...B)=>console.error(`[HTTP MCP ERROR] ${x}`,...B),warn:(x,...B)=>console.warn(`[HTTP MCP WARN] ${x}`,...B)}}function xm(x){let B=mz9.safeParse(x);if(B.success)return{info:(A,...w)=>B.data.info(A,...w),debug:(A,...w)=>B.data.debug(A,...w),error:(A,...w)=>B.data.error(A,...w),warn:(A,...w)=>B.data.warn(A,...w)};return R20()}class Bm{mcpServer=null;transport=null;config;logger;static createFresh(x){return new Bm(x)}constructor(x={}){this.config=x,this.logger=this.config.logger?xm(this.config.logger):KIx()}connectMCPServer(x){this.mcpServer=x,this.logger.debug("MCP server connected to stdio transport")}async start(){if(!this.mcpServer)throw Error("MCP server not connected. Call connectMCPServer() first.");if(this.transport)throw Error("Server is already running");this.logger.info("Starting stdio transport"),this.transport=new Cz9,await this.mcpServer.connect(this.transport),this.logger.info("Stdio transport started successfully")}stop(){if(this.logger.info("Stopping stdio transport"),this.transport)this.transport=null;this.logger.info("Stdio transport stopped")}isRunning(){return this.transport!==null}}import{randomUUID as gz9,timingSafeEqual as Tz9}from"crypto";import{WebStandardStreamableHTTPServerTransport as pz9}from"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";import{isInitializeRequest as uz9}from"@modelcontextprotocol/sdk/types.js";function cz9(x){return H0.async((B)=>{let A=setTimeout(()=>B(H0.void),x);return A.unref(),H0.sync(()=>clearTimeout(A))})}class y20{scope;fibers;activeSweeps=new Set;closePromise=null;closed=!1;constructor(x,B,A={}){this.scope=H0.runSync(y9.make()),this.fibers=H0.runSync(y9.extend(_w.make(),this.scope));let w=H0.flatMap(FD.currentTimeMillis,(Z)=>H0.tryPromise({try:()=>this.trackSweep(()=>B(Z)),catch:(Q)=>Q}).pipe(H0.catchAll((Q)=>H0.sync(()=>{A.onError?.(Q)})))),f=Math.max(1,x),D=(A.clock?H0.sleep(f):cz9(f)).pipe(H0.andThen(w),H0.forever),$=A.clock?H0.withClock(D,A.clock):D;_w.unsafeAdd(this.fibers,H0.runFork($))}close(){return this.closed=!0,this.closePromise??=this.closeSupervisor(),this.closePromise}trackSweep(x){if(this.closed)return Promise.resolve();let B=x();return this.activeSweeps.add(B),B.finally(()=>{this.activeSweeps.delete(B)})}async closeSupervisor(){let x=await H0.runPromiseExit(y9.close(this.scope,f5.void));if(await Promise.allSettled([...this.activeSweeps]),f5.isFailure(x))throw _4.squash(x.cause)}}var Sz9=1800000,iz9=60000,lz9={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, DELETE, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization, MCP-Session-Id, MCP-Protocol-Version, Last-Event-ID","Access-Control-Allow-Private-Network":"true","X-Content-Type-Options":"nosniff"},nz9=X.looseObject({code:X.string().optional()});function dz9(x){let B=new URL(x.url),w=x.headers.get("x-forwarded-proto")?.split(",")[0]?.trim(),f=x.headers.get("x-forwarded-host")??x.headers.get("host");if(!f)return B.origin;return`${w??B.protocol.replace(":","")}://${f}`}class Am{transports={};sessionLastActivity=new Map;sessionAuthorizations=new Map;mcpServer=null;mcpTransport=null;server=null;boundPort=null;sessionEviction;config;logger;authConfig;sessionIdleTtlMs;constructor(x={}){if(this.config=x,this.logger=this.config.logger?xm(this.config.logger):R20(),this.authConfig=x.auth??{},this.sessionIdleTtlMs=x.sessionIdleTtlMs??Sz9,!this.authConfig.disabled&&!this.authConfig.token&&!this.authConfig.verifyBearerToken)throw Error("MCP HTTP transport requires an auth token or bearer token verifier. Set MCP_AUTH_TOKEN, configure OAuth verification, or pass auth: { disabled: true } for local dev.");this.sessionEviction=new y20(Math.min(this.sessionIdleTtlMs,iz9),(B)=>this.evictIdleSessions(B),{onError:(B)=>{this.logger.error("Error sweeping idle MCP sessions:",B)}})}static createFresh(x){return new Am(x)}withCors(x){let B=new Headers(x.headers);for(let[A,w]of Object.entries(lz9))B.set(A,w);return new Response(x.body,{status:x.status,statusText:x.statusText,headers:B})}createJsonResponse(x,B=200){return this.withCors(new Response(JSON.stringify(x),{status:B,headers:{"Content-Type":"application/json"}}))}createTextResponse(x,B=200){return this.withCors(new Response(x,{status:B,headers:{"Content-Type":"text/plain; charset=utf-8"}}))}getAuthErrorResponse(x,B=401,A){let w=this.createJsonResponse({jsonrpc:"2.0",error:{code:-32001,message:x},id:null},B);if(!A)return w;let f=new Headers(w.headers);return f.set("WWW-Authenticate",A),new Response(w.body,{status:w.status,statusText:w.statusText,headers:f})}getBearerChallenge(x,B={}){let A={...this.authConfig.token?{}:{resource_metadata:`${dz9(x)}/.well-known/oauth-protected-resource`},...B};return`Bearer ${Object.entries(A).map(([f,D])=>`${f}="${az9(D)}"`).join(", ")}`}async authenticate(x){let B=new URL(x.url).pathname;if(B==="/health"||B==="/status"||B==="/mcp"&&x.method==="OPTIONS")return null;if(this.authConfig.disabled)return null;let A=x.headers.get("authorization");if(!A?.startsWith("Bearer "))return this.logger.warn("Authentication failed: Missing Bearer token"),this.getAuthErrorResponse("Unauthorized: Bearer token required",401,this.getBearerChallenge(x,{realm:"mcp"}));if(this.authConfig.token){let w=A.substring(7);if(!sz9(w,this.authConfig.token))return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(x,{error:"invalid_token"}));return this.logger.debug("Authentication successful"),{token:w,clientId:"static-token-client",scopes:this.authConfig.requiredScopes??[],extra:{subject:"static-token-operator",permissionLevel:"admin",isAnchor:!1,actor:{kind:"service",serviceId:"mcp-static-token"}}}}try{let w=await this.authConfig.verifyBearerToken?.(x);if(!w)return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(x,{error:"invalid_token"}));let f=this.authConfig.requiredScopes??[],D=f.filter(($)=>!w.scope?.includes($));if(D.length>0)return this.logger.warn(`Authentication failed: Missing required scope(s): ${D.join(", ")}`),this.getAuthErrorResponse("Forbidden: Missing required scope",403,this.getBearerChallenge(x,{error:"insufficient_scope",scope:f.join(" ")}));return this.logger.debug("Authentication successful"),{token:A.substring(7),clientId:w.subject,scopes:w.scope??[],extra:{subject:w.subject,permissionLevel:w.permissionLevel,isAnchor:w.isAnchor,actor:w.actor,displayName:w.displayName}}}catch(w){return this.logger.warn("Authentication failed: Invalid token",w),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(x,{error:"invalid_token"}))}}touchSession(x){this.sessionLastActivity.set(x,Date.now())}async evictIdleSessions(x){let B=[];for(let[A,w]of this.sessionLastActivity){if(x-w<this.sessionIdleTtlMs)continue;this.logger.info(`Evicting idle session ${A}`),this.sessionLastActivity.delete(A),this.sessionAuthorizations.delete(A);let f=this.transports[A];if(f)delete this.transports[A],B.push(f.close().catch((D)=>{this.logger.error(`Error closing idle transport for session ${A}:`,D)}))}await Promise.all(B)}async handleMcpRequest(x,B){let A=x.headers.get("mcp-session-id")??void 0;if(A&&this.transports[A]){let f=await this.validateSessionAuthorization(A,B);if(f)return f}if(x.method==="GET"){if(!A||!this.transports[A])return this.createTextResponse("Invalid or missing session ID",400);return this.touchSession(A),this.logger.debug(`GET /mcp - SSE stream for session ${A}`),this.withCors(await this.transports[A].handleRequest(x,{authInfo:B}))}if(x.method==="DELETE"){if(!A||!this.transports[A])return this.createTextResponse("Invalid or missing session ID",400);return this.logger.info(`DELETE /mcp - Terminating session ${A}`),this.withCors(await this.transports[A].handleRequest(x,{authInfo:B}))}if(x.method==="OPTIONS")return this.withCors(new Response(null,{status:204}));if(x.method!=="POST")return this.createTextResponse("Method Not Allowed",405);if(!this.mcpServer)return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Service Unavailable: MCP server not connected"},id:null},503);let w;try{w=await x.json()}catch{return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32700,message:"Parse error: Invalid JSON body"},id:null},400)}this.logger.debug(`POST /mcp - Session: ${A??"new"}`);try{let f;if(A&&this.transports[A])f=this.transports[A],this.touchSession(A);else if(!A&&uz9(w)){f=new pz9({sessionIdGenerator:()=>gz9(),onsessioninitialized:(Z)=>{this.logger.info(`Session initialized: ${Z}`),this.transports[Z]=f;let Q=qIx(B);if(Q)this.sessionAuthorizations.set(Z,Q);this.touchSession(Z)},onsessionclosed:(Z)=>{this.logger.info(`Session closed: ${Z}`),delete this.transports[Z],this.sessionLastActivity.delete(Z),this.sessionAuthorizations.delete(Z)}});let D=B?.extra?.permissionLevel;await(this.mcpTransport?this.mcpTransport.createMcpServer(D):this.mcpServer).connect(f)}else return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32000,message:"Bad Request: Server not initialized"},id:null},400);return this.withCors(await f.handleRequest(x,{parsedBody:w,authInfo:B}))}catch(f){return this.logger.error("MCP transport error:",f),this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}},500)}}async validateSessionAuthorization(x,B){let A=this.sessionAuthorizations.get(x);if(!A)return;let w=qIx(B);if(w?.subject!==A.subject)return this.logger.warn("Authentication failed: MCP session principal changed"),this.getAuthErrorResponse("Forbidden: Session belongs to another principal",403);if(w.permissionLevel!==A.permissionLevel){this.logger.warn("Authentication failed: MCP session permission changed");let f=this.transports[x];return delete this.transports[x],this.sessionLastActivity.delete(x),this.sessionAuthorizations.delete(x),await f?.close(),this.getAuthErrorResponse("Forbidden: Session permission changed; initialize a new session",403)}return}async handleRequest(x){let B=new URL(x.url);this.logger.debug(`${x.method} ${B.pathname}`);let A=await this.authenticate(x);if(A instanceof Response)return A;let w=A??void 0;if(B.pathname==="/health")return this.createJsonResponse({status:"ok",transport:"streamable-http",timestamp:new Date().toISOString()});if(B.pathname==="/status")return this.createJsonResponse({status:"ok",sessions:Object.keys(this.transports).length});if(B.pathname==="/mcp")return this.handleMcpRequest(x,w);return this.createTextResponse("Not Found",404)}connectMCPServer(x,B){this.mcpServer=x,this.mcpTransport=B??null,this.logger.debug("MCP server connected to StreamableHTTP transport")}async start(){if(this.server)throw Error("Server is already running");let x=Number(this.config.port??3333),B=this.config.host??"0.0.0.0";try{this.server=Bun.serve({port:x,hostname:B,fetch:(A)=>this.handleRequest(A)}),this.boundPort=this.server.port??x,this.logger.info(`StreamableHTTP server listening on http://${B}:${this.boundPort}/mcp`)}catch(A){let w=nz9.safeParse(A);if(w.success&&w.data.code==="EADDRINUSE")this.logger.error(`Port ${x} is already in use`);throw A}}async stop(){await this.sessionEviction.close(),this.sessionLastActivity.clear(),this.sessionAuthorizations.clear();for(let x in this.transports)try{let B=this.transports[x];if(B)this.logger.debug(`Closing transport for session ${x}`),await B.close(),delete this.transports[x]}catch(B){this.logger.error(`Error closing transport for session ${x}:`,B)}if(this.server)await this.server.stop(),this.logger.info("StreamableHTTP server stopped"),this.server=null,this.boundPort=null}getPort(){if(this.boundPort===null)throw Error("Server is not running");return this.boundPort}getApp(){return{fetch:(x)=>this.handleRequest(x)}}isRunning(){return this.server!==null}getSessionCount(){return Object.keys(this.transports).length}}function qIx(x){let B=x?.extra?.subject;if(typeof B!=="string")return;let A=x?.extra?.permissionLevel;return{subject:B,permissionLevel:A}}function az9(x){return x.replace(/["\\]/g,(B)=>`\\${B}`)}function sz9(x,B){let A=Buffer.from(x),w=Buffer.from(B);if(A.length!==w.length)return!1;return Tz9(A,w)}var m20=X.object({transport:X.enum(["stdio","http"]).default("http"),mode:X.enum(["basic","debug"]).default("basic"),httpPort:X.number().describe("Port for HTTP transport (only used when transport is 'http')").default(3333),authToken:X.string().describe("Bearer token for HTTP transport authentication").optional(),sessionIdleTtlMs:X.number().describe("Idle time in ms after which an HTTP session is closed and evicted").default(1800000)});import{createHash as ez9,randomUUID as xb9}from"crypto";function rz9(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}function E_(x,B){let A=x?.[B];return typeof A==="string"&&A.length>0?A:void 0}function oz9(x){let B=rz9(x.data)?x.data:void 0,A=x.args,w=E_(B,"entityId")??E_(B,"id"),f=x.jobId??E_(B,"jobId"),D=E_(A,"entityType")??E_(A,"type");if(!w&&!f)return;return{toolName:x.toolName,...D?{entityType:D}:{},...w?{entityId:w}:{},...f?{jobId:f}:{}}}function tz9(x){return x?.map(oz9).filter((B)=>B!==void 0)??[]}function C20(x,B={}){let A=x.pendingConfirmations?.[0];if(A)return{needsConfirmation:!0,toolName:A.toolName,summary:A.summary,...A.completionSummary?{completionSummary:A.completionSummary}:{},...A.preview?{preview:A.preview}:{},args:{approvalId:A.id,...B.conversationId?{conversationId:B.conversationId}:{},...A.toolCallId?{toolCallId:A.toolCallId}:{},originalArgs:A.args}};let w=tz9(x.toolResults);return{success:!0,data:{text:x.text,...B.conversationId?{conversationId:B.conversationId}:{},...x.toolResults?{toolResults:x.toolResults}:{},...w.length>0?{readYourWrites:w}:{}}}}var zIx=X.object({message:X.string().min(1),conversationId:X.string().min(1).optional().describe("Opaque conversation handle returned by a previous chat call. Omit it to start a new isolated conversation.")}),bIx=X.object({approvalId:X.string().min(1),confirmed:X.boolean(),conversationId:X.string().min(1).describe("Exact conversation handle returned by the chat confirmation.")});function VIx(x,B,A,w){let f=x.conversationId??A??w??`conversation-${xb9()}`,D=ez9("sha256").update(B).digest("hex").slice(0,16);return{handle:f,internalId:`mcp:${D}:${f}`}}function UIx(x){return{userPermissionLevel:x.userPermissionLevel??"public",isAnchor:x.isAnchor??!1,interfaceType:"mcp",...x.channelId?{channelId:x.channelId}:{},...x.channelName?{channelName:x.channelName}:{},actor:{identity:x.actor,interfaceType:"mcp",role:"user",...x.displayName?{displayName:x.displayName}:{}}}}function GIx(x,B){return[{name:"chat",description:"Talk to the brain to make changes or get reasoned answers. Use this for any create/update/delete request or questions requiring reasoning across content. For simple lookups, use search/get/list directly.",inputSchema:zIx.shape,visibility:"public",sideEffects:"writes",agentTool:!1,directMcpExposure:"basic",handler:async(A,w)=>{let f=zIx.parse(A),D=B();if(!D)return{success:!1,error:"MCP chat tool is not initialized."};let $=VIx(f,O1(w.actor),w.conversationId,w.channelId),Z=UIx(w),Q=w.signal?await D.agent.chat(f.message,$.internalId,Z,w.signal):await D.agent.chat(f.message,$.internalId,Z);return C20(Q,{conversationId:$.handle})}},{name:"confirm",description:"Resolve a pending confirmation returned by chat. Use this only after chat returns needsConfirmation with an approvalId.",inputSchema:bIx.shape,visibility:"public",sideEffects:"writes",agentTool:!1,directMcpExposure:"basic",handler:async(A,w)=>{let f=bIx.parse(A),D=B();if(!D)return{success:!1,error:"MCP confirm tool is not initialized."};let $=VIx(f,O1(w.actor),w.conversationId,w.channelId),Z=UIx(w),Q=w.signal?await D.agent.confirmPendingAction($.internalId,f.confirmed,f.approvalId,Z,w.signal):await D.agent.confirmPendingAction($.internalId,f.confirmed,f.approvalId,Z);return C20(Q,{conversationId:$.handle})}}]}function c20(x,B){x.messaging.subscribe(rL.progress,async(A)=>{let w=EIx.safeParse(A.payload);if(!w.success)return B.warn("Received invalid job-progress message",{error:w.error.message}),{success:!1};let f=w.data,D=f.type,$=f.status,Z=f.id;if(B.debug(`${D} ${Z} - ${$}:`,{id:f.id,message:f.message,progress:f.progress,metadata:f.metadata}),f.batchDetails)B.debug(`Batch details for ${Z}:`,{totalOperations:f.batchDetails.totalOperations,completedOperations:f.batchDetails.completedOperations,failedOperations:f.batchDetails.failedOperations,currentOperation:f.batchDetails.currentOperation,errors:f.batchDetails.errors});if(f.jobDetails)B.debug(`Job details for ${Z}:`,{jobType:f.jobDetails.jobType,priority:f.jobDetails.priority,retryCount:f.jobDetails.retryCount});return{success:!0}}),B.debug("Subscribed to job progress events")}var jIx={name:"@brains/mcp",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",dependencies:{"@brains/auth-service":"workspace:*","@brains/contracts":"workspace:*","@brains/mcp-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@modelcontextprotocol/sdk":"^1.29.0",cors:"^2.8.5",express:"^4.18.0","express-async-handler":"^1.2.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/cors":"^2.8.17",typescript:"^7.0.2"},files:["src"],main:"./src/index.ts",module:"./src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};class wm extends cH{mcpTransport;stdioServer;httpServer;domain;constructor(x={}){let B={...x,authToken:x.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",jIx,B,m20)}async getTools(){return GIx(this.id,()=>this.context)}async getResources(){return[]}async onRegister(x){if(this.domain=x.domain,this.config.transport==="http"&&!x.plugins.has("webserver"))throw Error("MCP HTTP transport requires the webserver interface. Standalone HTTP listeners have been removed.");if(this.logger.debug(`MCP interface initialized with ${this.config.transport} transport`),this.config.transport==="http")x.endpoints.register({label:"MCP",url:"/mcp",priority:30,visibility:"trusted"}),x.interactions.register({id:"mcp",label:"MCP",description:"Connect a trusted client through the Model Context Protocol.",href:"/mcp",kind:"protocol",priority:30,visibility:"trusted"});c20(x,this.logger)}getOrCreateHttpServer(){if(this.httpServer)return this.httpServer;let x=X6();return this.httpServer=Am.createFresh({port:this.config.httpPort,logger:this.logger,sessionIdleTtlMs:this.config.sessionIdleTtlMs,auth:this.config.authToken?{token:this.config.authToken}:x?{requiredScopes:["mcp"],verifyBearerToken:async(B)=>{let A=await x.resolveBearerGrant(B);if(!A)return;return{subject:A.token.subject,scope:A.token.scope,permissionLevel:A.principal.permissionLevel,isAnchor:A.principal.isAnchor,actor:{kind:"user",userId:A.principal.userId,...A.principal.canonicalId?{canonicalId:A.principal.canonicalId}:{}},displayName:A.principal.displayName}}}:{disabled:!0}}),this.httpServer}getWebRoutes(){if(this.config.transport!=="http")return[];let x=(B)=>this.getOrCreateHttpServer().handleRequest(B);return[{path:"/status",method:"GET",public:!0,handler:x},{path:"/mcp",method:"GET",public:!0,handler:x},{path:"/mcp",method:"POST",public:!0,handler:x},{path:"/mcp",method:"DELETE",public:!0,handler:x},{path:"/mcp",method:"OPTIONS",public:!0,handler:x}]}createDaemon(){return{start:async()=>{await this.startServer()},stop:async()=>{await this.stopServer()},healthCheck:async()=>{let x=this.isServerRunning(),B="MCP server not running";if(x)if(this.config.transport==="http")B=`MCP HTTP: ${this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/mcp"}`;else B="MCP stdio server running";return{status:x?"healthy":"error",message:B,lastCheck:new Date,details:{transport:this.config.transport,mode:this.config.mode,url:this.config.transport==="http"?this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/mcp":void 0,running:x}}}}}isServerRunning(){if(this.config.transport==="stdio")return this.stdioServer!==void 0&&this.mcpTransport!==void 0;else return this.httpServer!==void 0&&this.mcpTransport!==void 0}async startServer(){if(!this.context)throw Error("Context not initialized");let x=this.context;this.mcpTransport=x.mcpTransport;let B=this.config.transport==="stdio"?"stdio":"http",A=this.context.permissions.getUserLevel("mcp",B),w=X6(),f=this.config.transport==="http"&&(this.config.authToken?!0:w!==void 0);if(f)A="admin",this.logger.debug("HTTP authentication configured; session permissions resolve during initialization");if(this.config.mode==="debug"){if(this.config.transport==="http"&&!f)throw Error("MCP debug mode requires authenticated HTTP transport; configure authToken or OAuth auth service.");if(A!=="admin")throw Error("MCP debug mode requires admin permissions.")}if(this.mcpTransport.setProtocolMode(this.config.mode),this.mcpTransport.setPermissionLevel(A),this.mcpTransport.setAnchorStatus?.(this.context.permissions.isAnchor("mcp",B)),this.logger.debug(`Starting MCP ${this.config.transport} transport in ${this.config.mode} mode with ${A} permissions`),this.config.transport==="stdio"){this.stdioServer=Bm.createFresh();let D=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(D),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=this.getOrCreateHttpServer();let D=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(D,this.mcpTransport),this.logger.debug("MCP HTTP transport mounted on shared webserver host")}}async stopServer(){if(this.logger.debug(`Stopping MCP ${this.config.transport} transport`),this.stdioServer)this.stdioServer.stop(),this.stdioServer=void 0;if(this.httpServer)await this.httpServer.stop(),this.httpServer=void 0;this.mcpTransport=void 0}async handleProgressEvent(x,B){}}var eq={isConfigured:"buttondown:is-configured",send:"buttondown:send"};import{h as Ub9}from"preact";var fm=X.enum(["generating","draft","queued","published","failed"]),Ab9=X.enum(["generating","draft","queued","published","failed"]),Dm=X.object({subject:X.string(),status:fm,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional()}),_Ix=X.object({subject:X.string(),status:fm,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional(),error:X.string().optional()}),wb9=X.object({subject:X.string(),status:Ab9,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional(),error:X.string().optional()}),xz=j8.extend({entityType:X.literal("newsletter"),metadata:wb9});class PIx extends ox{constructor(){super({entityType:"newsletter",purpose:"An email newsletter issue composed for subscribers.",schema:xz,frontmatterSchema:Dm})}toMarkdown(x){let B=this.extractBody(x.content);return this.buildMarkdown(B,x.metadata)}fromMarkdown(x){let B=this.parseFrontmatter(x);return{entityType:"newsletter",content:x,metadata:B}}buildStub(x){let B={subject:x.title,status:"generating"};return{content:this.buildMarkdown("",B),metadata:B}}}var JIx=new PIx;var fb9=X.looseObject({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional(),baseUrl:X.string().optional(),status:X.enum(["generating","draft","queued","published","failed"]).optional()}),Db9=X.looseObject({entityType:X.string().optional(),query:fb9.optional()});function LIx(x){try{let{content:B}=G9(x.content,Dm);return B}catch{return x.content}}class g20 extends j7{id="newsletter:entities";name="Newsletter Entity DataSource";description="Fetches and transforms newsletter entities for rendering";config={entityType:"newsletter",defaultSort:[{field:"created",direction:"desc"}],defaultLimit:10,lookupField:"id",enableNavigation:!0};constructor(x){super(x);this.logger.debug("NewsletterDataSource initialized")}parseQuery(x){let B=Db9.parse(x);return{entityType:B.entityType??this.config.entityType,query:B.query??{}}}transformEntity(x){let B=LIx(x);return{id:x.id,subject:x.metadata.subject,status:x.metadata.status,excerpt:r$(B,150),created:x.created,sentAt:x.metadata.sentAt??null,url:`/newsletters/${x.id}`}}buildListResult(x,B,A){return{newsletters:x,totalCount:B?.totalItems??x.length,pagination:B}}async fetch(x,B,A){let{query:w}=this.parseQuery(x),f=A.entityService;if(w.id)return this.fetchSingleNewsletter(w.id,B,f);let D=w.status,$=D?{filter:{metadata:{status:D}}}:void 0,{items:Z,pagination:Q}=await this.fetchList(w,f,$);return B.parse(this.buildListResult(Z,Q,w))}async fetchSingleNewsletter(x,B,A){let w=await A.getEntity({entityType:this.config.entityType,id:x});if(!w)throw Error(`Newsletter not found: ${x}`);let f=await this.resolveNavigation(w,A),D=[];if(w.metadata.entityIds?.length){let Q=w.metadata.sourceEntityType??"post";D=(await Promise.all(w.metadata.entityIds.map(async(W)=>{let H=await A.getEntity({entityType:Q,id:W});if(H){let F=H.metadata;return{id:W,title:F.title??W,url:`/${Q}s/${F.slug??W}`}}return null}))).filter((W)=>W!==null)}let $=LIx(w),Z={id:w.id,subject:w.metadata.subject,status:w.metadata.status,content:$,created:w.created,updated:w.updated,sentAt:w.metadata.sentAt,scheduledFor:w.metadata.scheduledFor,newsletter:w,prevNewsletter:f.prev?{id:f.prev.id,subject:f.prev.subject,url:f.prev.url}:null,nextNewsletter:f.next?{id:f.next.id,subject:f.next.subject,url:f.next.url}:null,sourceEntities:D.length>0?D:void 0};return B.parse(Z)}}var $b9=X.object({prompt:X.string().optional().describe("AI generation prompt"),sourceEntityIds:X.array(X.string()).optional().describe("Entity IDs to include in newsletter (e.g., blog posts)"),sourceEntityType:X.enum(["post"]).optional().describe("Type of source entities"),content:X.string().optional().describe("Direct content (skip AI)"),subject:X.string().optional().describe("Newsletter subject (AI-generated if not provided)"),addToQueue:X.boolean().optional().describe("Create as queued (true) or draft (false)")});class T20 extends UA{constructor(x,B){super(x,B,{schema:$b9,jobTypeName:lf.generation,entityType:"newsletter"})}async generate(x,B){let A=x.addToQueue??!1,{prompt:w,sourceEntityIds:f,sourceEntityType:D}=x,{content:$,subject:Z}=x;if($){if(!Z)this.failEarly("Subject is required when providing content directly");await this.reportProgress(B,{progress:50,message:"Using provided content"})}else if(f&&f.length>0){let F=D??"post";await this.reportProgress(B,{progress:10,message:`Fetching ${f.length} source entities`});let q=(await Promise.all(f.map((L)=>this.context.entityService.getEntity({entityType:F,id:L})))).filter((L)=>L!=null);if(q.length===0)this.failEarly(`No source entities found for IDs: ${f.join(", ")}`);await this.reportProgress(B,{progress:30,message:`Generating newsletter from ${q.length} posts`});let b=`Create an engaging newsletter that highlights these blog posts:
5682
+ ${f.content}`,data:{url:A,hasContent:!0},representedIdentity:"none",interfacePermissionGrant:"public"})})}async createPendingLink(x,B,A,w){let f=bZ.generateEntityId(x),D=new URL(x),$=new Date().toISOString(),Z=B?.trim()?B.trim():D.hostname,Q=this.adapter.createLinkContent({status:"pending",title:Z,url:x,description:"Link capture is in progress.",summary:`Pending link capture for ${x}.`,domain:D.hostname,capturedAt:$,source:this.resolveSource(A)});return(await _q({entityService:w.entityService,entity:{id:f,entityType:"link",content:Q,metadata:{status:"pending",title:Z},created:$,updated:$}})).entityId}resolveSource(x){if(x.channelId)return{ref:`matrix:${x.channelId}`,label:x.channelName??x.channelId};return{ref:`${x.interfaceType}:local`,label:x.interfaceType.toUpperCase()}}extractFirstUrl(...x){for(let B of x){if(!B)continue;let[A]=bZ.extractUrls(B);if(A)return A}return}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function FIx(x={}){return new O20(x)}var h20=FIx;var yz9=X.object({conversationId:X.string().optional(),interfaceId:X.string().optional(),userId:X.string().optional(),messageId:X.string().optional(),timestamp:X.string().optional()}),ve6=X.object({id:X.string().optional(),metadata:yz9.optional()});import{StdioServerTransport as Cz9}from"@modelcontextprotocol/sdk/server/stdio.js";var mz9=X.custom((x)=>typeof x==="object"&&x!==null&&("info"in x)&&typeof x.info==="function"&&("debug"in x)&&typeof x.debug==="function"&&("error"in x)&&typeof x.error==="function"&&("warn"in x)&&typeof x.warn==="function");function KIx(){return{info:(x,...B)=>console.error(`[STDIO MCP] ${x}`,...B),debug:(x,...B)=>console.error(`[STDIO MCP DEBUG] ${x}`,...B),error:(x,...B)=>console.error(`[STDIO MCP ERROR] ${x}`,...B),warn:(x,...B)=>console.error(`[STDIO MCP WARN] ${x}`,...B)}}function R20(){return{info:(x,...B)=>console.log(`[HTTP MCP] ${x}`,...B),debug:(x,...B)=>console.debug(`[HTTP MCP DEBUG] ${x}`,...B),error:(x,...B)=>console.error(`[HTTP MCP ERROR] ${x}`,...B),warn:(x,...B)=>console.warn(`[HTTP MCP WARN] ${x}`,...B)}}function xm(x){let B=mz9.safeParse(x);if(B.success)return{info:(A,...w)=>B.data.info(A,...w),debug:(A,...w)=>B.data.debug(A,...w),error:(A,...w)=>B.data.error(A,...w),warn:(A,...w)=>B.data.warn(A,...w)};return R20()}class Bm{mcpServer=null;transport=null;config;logger;static createFresh(x){return new Bm(x)}constructor(x={}){this.config=x,this.logger=this.config.logger?xm(this.config.logger):KIx()}connectMCPServer(x){this.mcpServer=x,this.logger.debug("MCP server connected to stdio transport")}async start(){if(!this.mcpServer)throw Error("MCP server not connected. Call connectMCPServer() first.");if(this.transport)throw Error("Server is already running");this.logger.info("Starting stdio transport"),this.transport=new Cz9,await this.mcpServer.connect(this.transport),this.logger.info("Stdio transport started successfully")}stop(){if(this.logger.info("Stopping stdio transport"),this.transport)this.transport=null;this.logger.info("Stdio transport stopped")}isRunning(){return this.transport!==null}}import{randomUUID as gz9,timingSafeEqual as Tz9}from"crypto";import{WebStandardStreamableHTTPServerTransport as pz9}from"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";import{isInitializeRequest as uz9}from"@modelcontextprotocol/sdk/types.js";function cz9(x){return H0.async((B)=>{let A=setTimeout(()=>B(H0.void),x);return A.unref(),H0.sync(()=>clearTimeout(A))})}class y20{scope;fibers;activeSweeps=new Set;closePromise=null;closed=!1;constructor(x,B,A={}){this.scope=H0.runSync(y9.make()),this.fibers=H0.runSync(y9.extend(_w.make(),this.scope));let w=H0.flatMap(FD.currentTimeMillis,(Z)=>H0.tryPromise({try:()=>this.trackSweep(()=>B(Z)),catch:(Q)=>Q}).pipe(H0.catchAll((Q)=>H0.sync(()=>{A.onError?.(Q)})))),f=Math.max(1,x),D=(A.clock?H0.sleep(f):cz9(f)).pipe(H0.andThen(w),H0.forever),$=A.clock?H0.withClock(D,A.clock):D;_w.unsafeAdd(this.fibers,H0.runFork($))}close(){return this.closed=!0,this.closePromise??=this.closeSupervisor(),this.closePromise}trackSweep(x){if(this.closed)return Promise.resolve();let B=x();return this.activeSweeps.add(B),B.finally(()=>{this.activeSweeps.delete(B)})}async closeSupervisor(){let x=await H0.runPromiseExit(y9.close(this.scope,f5.void));if(await Promise.allSettled([...this.activeSweeps]),f5.isFailure(x))throw _4.squash(x.cause)}}var Sz9=1800000,iz9=60000,lz9={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, DELETE, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization, MCP-Session-Id, MCP-Protocol-Version, Last-Event-ID","Access-Control-Allow-Private-Network":"true","X-Content-Type-Options":"nosniff"},nz9=X.looseObject({code:X.string().optional()});function dz9(x){let B=new URL(x.url),w=x.headers.get("x-forwarded-proto")?.split(",")[0]?.trim(),f=x.headers.get("x-forwarded-host")??x.headers.get("host");if(!f)return B.origin;return`${w??B.protocol.replace(":","")}://${f}`}class Am{transports={};sessionLastActivity=new Map;sessionAuthorizations=new Map;mcpServer=null;mcpTransport=null;server=null;boundPort=null;sessionEviction;config;logger;authConfig;sessionIdleTtlMs;constructor(x={}){if(this.config=x,this.logger=this.config.logger?xm(this.config.logger):R20(),this.authConfig=x.auth??{},this.sessionIdleTtlMs=x.sessionIdleTtlMs??Sz9,!this.authConfig.disabled&&!this.authConfig.token&&!this.authConfig.verifyBearerToken)throw Error("MCP HTTP transport requires an auth token or bearer token verifier. Set MCP_AUTH_TOKEN, configure OAuth verification, or pass auth: { disabled: true } for local dev.");this.sessionEviction=new y20(Math.min(this.sessionIdleTtlMs,iz9),(B)=>this.evictIdleSessions(B),{onError:(B)=>{this.logger.error("Error sweeping idle MCP sessions:",B)}})}static createFresh(x){return new Am(x)}withCors(x){let B=new Headers(x.headers);for(let[A,w]of Object.entries(lz9))B.set(A,w);return new Response(x.body,{status:x.status,statusText:x.statusText,headers:B})}createJsonResponse(x,B=200){return this.withCors(new Response(JSON.stringify(x),{status:B,headers:{"Content-Type":"application/json"}}))}createTextResponse(x,B=200){return this.withCors(new Response(x,{status:B,headers:{"Content-Type":"text/plain; charset=utf-8"}}))}getAuthErrorResponse(x,B=401,A){let w=this.createJsonResponse({jsonrpc:"2.0",error:{code:-32001,message:x},id:null},B);if(!A)return w;let f=new Headers(w.headers);return f.set("WWW-Authenticate",A),new Response(w.body,{status:w.status,statusText:w.statusText,headers:f})}getBearerChallenge(x,B={}){let A={...this.authConfig.token?{}:{resource_metadata:`${dz9(x)}/.well-known/oauth-protected-resource`},...B};return`Bearer ${Object.entries(A).map(([f,D])=>`${f}="${az9(D)}"`).join(", ")}`}async authenticate(x){let B=new URL(x.url).pathname;if(B==="/health"||B==="/status"||B==="/mcp"&&x.method==="OPTIONS")return null;if(this.authConfig.disabled)return null;let A=x.headers.get("authorization");if(!A?.startsWith("Bearer "))return this.logger.warn("Authentication failed: Missing Bearer token"),this.getAuthErrorResponse("Unauthorized: Bearer token required",401,this.getBearerChallenge(x,{realm:"mcp"}));if(this.authConfig.token){let w=A.substring(7);if(!sz9(w,this.authConfig.token))return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(x,{error:"invalid_token"}));return this.logger.debug("Authentication successful"),{token:w,clientId:"static-token-client",scopes:this.authConfig.requiredScopes??[],extra:{subject:"static-token-operator",permissionLevel:"admin",isAnchor:!1,actor:{kind:"service",serviceId:"mcp-static-token"}}}}try{let w=await this.authConfig.verifyBearerToken?.(x);if(!w)return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(x,{error:"invalid_token"}));let f=this.authConfig.requiredScopes??[],D=f.filter(($)=>!w.scope?.includes($));if(D.length>0)return this.logger.warn(`Authentication failed: Missing required scope(s): ${D.join(", ")}`),this.getAuthErrorResponse("Forbidden: Missing required scope",403,this.getBearerChallenge(x,{error:"insufficient_scope",scope:f.join(" ")}));return this.logger.debug("Authentication successful"),{token:A.substring(7),clientId:w.subject,scopes:w.scope??[],extra:{subject:w.subject,permissionLevel:w.permissionLevel,isAnchor:w.isAnchor,actor:w.actor,displayName:w.displayName}}}catch(w){return this.logger.warn("Authentication failed: Invalid token",w),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(x,{error:"invalid_token"}))}}touchSession(x){this.sessionLastActivity.set(x,Date.now())}async evictIdleSessions(x){let B=[];for(let[A,w]of this.sessionLastActivity){if(x-w<this.sessionIdleTtlMs)continue;this.logger.info(`Evicting idle session ${A}`),this.sessionLastActivity.delete(A),this.sessionAuthorizations.delete(A);let f=this.transports[A];if(f)delete this.transports[A],B.push(f.close().catch((D)=>{this.logger.error(`Error closing idle transport for session ${A}:`,D)}))}await Promise.all(B)}async handleMcpRequest(x,B){let A=x.headers.get("mcp-session-id")??void 0;if(A&&this.transports[A]){let f=await this.validateSessionAuthorization(A,B);if(f)return f}if(x.method==="GET"){if(!A||!this.transports[A])return this.createTextResponse("Invalid or missing session ID",400);return this.touchSession(A),this.logger.debug(`GET /mcp - SSE stream for session ${A}`),this.withCors(await this.transports[A].handleRequest(x,{authInfo:B}))}if(x.method==="DELETE"){if(!A||!this.transports[A])return this.createTextResponse("Invalid or missing session ID",400);return this.logger.info(`DELETE /mcp - Terminating session ${A}`),this.withCors(await this.transports[A].handleRequest(x,{authInfo:B}))}if(x.method==="OPTIONS")return this.withCors(new Response(null,{status:204}));if(x.method!=="POST")return this.createTextResponse("Method Not Allowed",405);if(!this.mcpServer)return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Service Unavailable: MCP server not connected"},id:null},503);let w;try{w=await x.json()}catch{return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32700,message:"Parse error: Invalid JSON body"},id:null},400)}this.logger.debug(`POST /mcp - Session: ${A??"new"}`);try{let f;if(A&&this.transports[A])f=this.transports[A],this.touchSession(A);else if(!A&&uz9(w)){f=new pz9({sessionIdGenerator:()=>gz9(),onsessioninitialized:(Z)=>{this.logger.info(`Session initialized: ${Z}`),this.transports[Z]=f;let Q=qIx(B);if(Q)this.sessionAuthorizations.set(Z,Q);this.touchSession(Z)},onsessionclosed:(Z)=>{this.logger.info(`Session closed: ${Z}`),delete this.transports[Z],this.sessionLastActivity.delete(Z),this.sessionAuthorizations.delete(Z)}});let D=B?.extra?.permissionLevel;await(this.mcpTransport?this.mcpTransport.createMcpServer(D):this.mcpServer).connect(f)}else return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32000,message:"Bad Request: Server not initialized"},id:null},400);return this.withCors(await f.handleRequest(x,{parsedBody:w,authInfo:B}))}catch(f){return this.logger.error("MCP transport error:",f),this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}},500)}}async validateSessionAuthorization(x,B){let A=this.sessionAuthorizations.get(x);if(!A)return;let w=qIx(B);if(w?.subject!==A.subject)return this.logger.warn("Authentication failed: MCP session principal changed"),this.getAuthErrorResponse("Forbidden: Session belongs to another principal",403);if(w.permissionLevel!==A.permissionLevel){this.logger.warn("Authentication failed: MCP session permission changed");let f=this.transports[x];return delete this.transports[x],this.sessionLastActivity.delete(x),this.sessionAuthorizations.delete(x),await f?.close(),this.getAuthErrorResponse("Forbidden: Session permission changed; initialize a new session",403)}return}async handleRequest(x){let B=new URL(x.url);this.logger.debug(`${x.method} ${B.pathname}`);let A=await this.authenticate(x);if(A instanceof Response)return A;let w=A??void 0;if(B.pathname==="/health")return this.createJsonResponse({status:"ok",transport:"streamable-http",timestamp:new Date().toISOString()});if(B.pathname==="/status")return this.createJsonResponse({status:"ok",sessions:Object.keys(this.transports).length});if(B.pathname==="/mcp")return this.handleMcpRequest(x,w);return this.createTextResponse("Not Found",404)}connectMCPServer(x,B){this.mcpServer=x,this.mcpTransport=B??null,this.logger.debug("MCP server connected to StreamableHTTP transport")}async start(){if(this.server)throw Error("Server is already running");let x=Number(this.config.port??3333),B=this.config.host??"0.0.0.0";try{this.server=Bun.serve({port:x,hostname:B,fetch:(A)=>this.handleRequest(A)}),this.boundPort=this.server.port??x,this.logger.info(`StreamableHTTP server listening on http://${B}:${this.boundPort}/mcp`)}catch(A){let w=nz9.safeParse(A);if(w.success&&w.data.code==="EADDRINUSE")this.logger.error(`Port ${x} is already in use`);throw A}}async stop(){await this.sessionEviction.close(),this.sessionLastActivity.clear(),this.sessionAuthorizations.clear();for(let x in this.transports)try{let B=this.transports[x];if(B)this.logger.debug(`Closing transport for session ${x}`),await B.close(),delete this.transports[x]}catch(B){this.logger.error(`Error closing transport for session ${x}:`,B)}if(this.server)await this.server.stop(),this.logger.info("StreamableHTTP server stopped"),this.server=null,this.boundPort=null}getPort(){if(this.boundPort===null)throw Error("Server is not running");return this.boundPort}getApp(){return{fetch:(x)=>this.handleRequest(x)}}isRunning(){return this.server!==null}getSessionCount(){return Object.keys(this.transports).length}}function qIx(x){let B=x?.extra?.subject;if(typeof B!=="string")return;let A=x?.extra?.permissionLevel;return{subject:B,permissionLevel:A}}function az9(x){return x.replace(/["\\]/g,(B)=>`\\${B}`)}function sz9(x,B){let A=Buffer.from(x),w=Buffer.from(B);if(A.length!==w.length)return!1;return Tz9(A,w)}var m20=X.object({transport:X.enum(["stdio","http"]).default("http"),mode:X.enum(["basic","debug"]).default("basic"),httpPort:X.number().describe("Port for HTTP transport (only used when transport is 'http')").default(3333),authToken:X.string().describe("Bearer token for HTTP transport authentication").optional(),sessionIdleTtlMs:X.number().describe("Idle time in ms after which an HTTP session is closed and evicted").default(1800000)});import{createHash as ez9,randomUUID as xb9}from"crypto";function rz9(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}function E_(x,B){let A=x?.[B];return typeof A==="string"&&A.length>0?A:void 0}function oz9(x){let B=rz9(x.data)?x.data:void 0,A=x.args,w=E_(B,"entityId")??E_(B,"id"),f=x.jobId??E_(B,"jobId"),D=E_(A,"entityType")??E_(A,"type");if(!w&&!f)return;return{toolName:x.toolName,...D?{entityType:D}:{},...w?{entityId:w}:{},...f?{jobId:f}:{}}}function tz9(x){return x?.map(oz9).filter((B)=>B!==void 0)??[]}function C20(x,B={}){let A=x.pendingConfirmations?.[0];if(A)return{needsConfirmation:!0,toolName:A.toolName,summary:A.summary,...A.completionSummary?{completionSummary:A.completionSummary}:{},...A.preview?{preview:A.preview}:{},args:{approvalId:A.id,...B.conversationId?{conversationId:B.conversationId}:{},...A.toolCallId?{toolCallId:A.toolCallId}:{},originalArgs:A.args}};let w=tz9(x.toolResults);return{success:!0,data:{text:x.text,...B.conversationId?{conversationId:B.conversationId}:{},...x.toolResults?{toolResults:x.toolResults}:{},...w.length>0?{readYourWrites:w}:{}}}}var zIx=X.object({message:X.string().min(1),conversationId:X.string().min(1).optional().describe("Opaque conversation handle returned by a previous chat call. Omit it to start a new isolated conversation.")}),bIx=X.object({approvalId:X.string().min(1),confirmed:X.boolean(),conversationId:X.string().min(1).describe("Exact conversation handle returned by the chat confirmation.")});function VIx(x,B,A,w){let f=x.conversationId??A??w??`conversation-${xb9()}`,D=ez9("sha256").update(B).digest("hex").slice(0,16);return{handle:f,internalId:`mcp:${D}:${f}`}}function UIx(x){return{userPermissionLevel:x.userPermissionLevel??"public",isAnchor:x.isAnchor??!1,interfaceType:"mcp",...x.channelId?{channelId:x.channelId}:{},...x.channelName?{channelName:x.channelName}:{},actor:{identity:x.actor,interfaceType:"mcp",role:"user",...x.displayName?{displayName:x.displayName}:{}}}}function GIx(x,B){return[{name:"chat",description:"Talk to the brain to make changes or get reasoned answers. Use this for any create/update/delete request or questions requiring reasoning across content. For simple lookups, use search/get/list directly.",inputSchema:zIx.shape,visibility:"public",sideEffects:"writes",agentTool:!1,directMcpExposure:"basic",handler:async(A,w)=>{let f=zIx.parse(A),D=B();if(!D)return{success:!1,error:"MCP chat tool is not initialized."};let $=VIx(f,O1(w.actor),w.conversationId,w.channelId),Z=UIx(w),Q=w.signal?await D.agent.chat(f.message,$.internalId,Z,w.signal):await D.agent.chat(f.message,$.internalId,Z);return C20(Q,{conversationId:$.handle})}},{name:"confirm",description:"Resolve a pending confirmation returned by chat. Use this only after chat returns needsConfirmation with an approvalId.",inputSchema:bIx.shape,visibility:"public",sideEffects:"writes",agentTool:!1,directMcpExposure:"basic",handler:async(A,w)=>{let f=bIx.parse(A),D=B();if(!D)return{success:!1,error:"MCP confirm tool is not initialized."};let $=VIx(f,O1(w.actor),w.conversationId,w.channelId),Z=UIx(w),Q=w.signal?await D.agent.confirmPendingAction($.internalId,f.confirmed,f.approvalId,Z,w.signal):await D.agent.confirmPendingAction($.internalId,f.confirmed,f.approvalId,Z);return C20(Q,{conversationId:$.handle})}}]}function c20(x,B){x.messaging.subscribe(rL.progress,async(A)=>{let w=EIx.safeParse(A.payload);if(!w.success)return B.warn("Received invalid job-progress message",{error:w.error.message}),{success:!1};let f=w.data,D=f.type,$=f.status,Z=f.id;if(B.debug(`${D} ${Z} - ${$}:`,{id:f.id,message:f.message,progress:f.progress,metadata:f.metadata}),f.batchDetails)B.debug(`Batch details for ${Z}:`,{totalOperations:f.batchDetails.totalOperations,completedOperations:f.batchDetails.completedOperations,failedOperations:f.batchDetails.failedOperations,currentOperation:f.batchDetails.currentOperation,errors:f.batchDetails.errors});if(f.jobDetails)B.debug(`Job details for ${Z}:`,{jobType:f.jobDetails.jobType,priority:f.jobDetails.priority,retryCount:f.jobDetails.retryCount});return{success:!0}}),B.debug("Subscribed to job progress events")}var jIx={name:"@brains/mcp",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",dependencies:{"@brains/auth-service":"workspace:*","@brains/contracts":"workspace:*","@brains/mcp-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@modelcontextprotocol/sdk":"^1.29.0",cors:"^2.8.5",express:"^4.18.0","express-async-handler":"^1.2.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/cors":"^2.8.17",typescript:"^7.0.2"},files:["src"],main:"./src/index.ts",module:"./src/index.ts",private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};class wm extends cH{mcpTransport;stdioServer;httpServer;domain;constructor(x={}){let B={...x,authToken:x.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",jIx,B,m20)}async getTools(){return GIx(this.id,()=>this.context)}async getResources(){return[]}async onRegister(x){if(this.domain=x.domain,this.config.transport==="http"&&!x.plugins.has("webserver"))throw Error("MCP HTTP transport requires the webserver interface. Standalone HTTP listeners have been removed.");if(this.logger.debug(`MCP interface initialized with ${this.config.transport} transport`),this.config.transport==="http")x.endpoints.register({label:"MCP",url:"/mcp",priority:30,visibility:"trusted"}),x.interactions.register({id:"mcp",label:"MCP",description:"Connect a trusted client through the Model Context Protocol.",href:"/mcp",kind:"protocol",priority:30,visibility:"trusted"});c20(x,this.logger)}getOrCreateHttpServer(){if(this.httpServer)return this.httpServer;let x=X6();return this.httpServer=Am.createFresh({port:this.config.httpPort,logger:this.logger,sessionIdleTtlMs:this.config.sessionIdleTtlMs,auth:this.config.authToken?{token:this.config.authToken}:x?{requiredScopes:["mcp"],verifyBearerToken:async(B)=>{let A=await x.resolveBearerGrant(B);if(!A)return;return{subject:A.token.subject,scope:A.token.scope,permissionLevel:A.principal.permissionLevel,isAnchor:A.principal.isAnchor,actor:{kind:"user",userId:A.principal.userId,...A.principal.canonicalId?{canonicalId:A.principal.canonicalId}:{}},displayName:A.principal.displayName}}}:{disabled:!0}}),this.httpServer}getWebRoutes(){if(this.config.transport!=="http")return[];let x=(B)=>this.getOrCreateHttpServer().handleRequest(B);return[{path:"/status",method:"GET",public:!0,handler:x},{path:"/mcp",method:"GET",public:!0,handler:x},{path:"/mcp",method:"POST",public:!0,handler:x},{path:"/mcp",method:"DELETE",public:!0,handler:x},{path:"/mcp",method:"OPTIONS",public:!0,handler:x}]}createDaemon(){return{start:async()=>{await this.startServer()},stop:async()=>{await this.stopServer()},healthCheck:async()=>{let x=this.isServerRunning(),B="MCP server not running";if(x)if(this.config.transport==="http")B=`MCP HTTP: ${this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/mcp"}`;else B="MCP stdio server running";return{status:x?"healthy":"error",message:B,lastCheck:new Date,details:{transport:this.config.transport,mode:this.config.mode,url:this.config.transport==="http"?this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/mcp":void 0,running:x}}}}}isServerRunning(){if(this.config.transport==="stdio")return this.stdioServer!==void 0&&this.mcpTransport!==void 0;else return this.httpServer!==void 0&&this.mcpTransport!==void 0}async startServer(){if(!this.context)throw Error("Context not initialized");let x=this.context;this.mcpTransport=x.mcpTransport;let B=this.config.transport==="stdio"?"stdio":"http",A=this.context.permissions.getUserLevel("mcp",B),w=X6(),f=this.config.transport==="http"&&(this.config.authToken?!0:w!==void 0);if(f)A="admin",this.logger.debug("HTTP authentication configured; session permissions resolve during initialization");if(this.config.mode==="debug"){if(this.config.transport==="http"&&!f)throw Error("MCP debug mode requires authenticated HTTP transport; configure authToken or OAuth auth service.");if(A!=="admin")throw Error("MCP debug mode requires admin permissions.")}if(this.mcpTransport.setProtocolMode(this.config.mode),this.mcpTransport.setPermissionLevel(A),this.mcpTransport.setAnchorStatus?.(this.context.permissions.isAnchor("mcp",B)),this.logger.debug(`Starting MCP ${this.config.transport} transport in ${this.config.mode} mode with ${A} permissions`),this.config.transport==="stdio"){this.stdioServer=Bm.createFresh();let D=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(D),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=this.getOrCreateHttpServer();let D=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(D,this.mcpTransport),this.logger.debug("MCP HTTP transport mounted on shared webserver host")}}async stopServer(){if(this.logger.debug(`Stopping MCP ${this.config.transport} transport`),this.stdioServer)this.stdioServer.stop(),this.stdioServer=void 0;if(this.httpServer)await this.httpServer.stop(),this.httpServer=void 0;this.mcpTransport=void 0}async handleProgressEvent(x,B){}}var eq={isConfigured:"buttondown:is-configured",send:"buttondown:send"};import{h as Ub9}from"preact";var fm=X.enum(["generating","draft","queued","published","failed"]),Ab9=X.enum(["generating","draft","queued","published","failed"]),Dm=X.object({subject:X.string(),status:fm,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional()}),_Ix=X.object({subject:X.string(),status:fm,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional(),error:X.string().optional()}),wb9=X.object({subject:X.string(),status:Ab9,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional(),error:X.string().optional()}),xz=j8.extend({entityType:X.literal("newsletter"),metadata:wb9});class PIx extends ox{constructor(){super({entityType:"newsletter",purpose:"An email newsletter issue composed for subscribers.",schema:xz,frontmatterSchema:Dm})}toMarkdown(x){let B=this.extractBody(x.content);return this.buildMarkdown(B,x.metadata)}fromMarkdown(x){let B=this.parseFrontmatter(x);return{entityType:"newsletter",content:x,metadata:B}}buildStub(x){let B={subject:x.title,status:"generating"};return{content:this.buildMarkdown("",B),metadata:B}}}var JIx=new PIx;var fb9=X.looseObject({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional(),baseUrl:X.string().optional(),status:X.enum(["generating","draft","queued","published","failed"]).optional()}),Db9=X.looseObject({entityType:X.string().optional(),query:fb9.optional()});function LIx(x){try{let{content:B}=G9(x.content,Dm);return B}catch{return x.content}}class g20 extends j7{id="newsletter:entities";name="Newsletter Entity DataSource";description="Fetches and transforms newsletter entities for rendering";config={entityType:"newsletter",defaultSort:[{field:"created",direction:"desc"}],defaultLimit:10,lookupField:"id",enableNavigation:!0};constructor(x){super(x);this.logger.debug("NewsletterDataSource initialized")}parseQuery(x){let B=Db9.parse(x);return{entityType:B.entityType??this.config.entityType,query:B.query??{}}}transformEntity(x){let B=LIx(x);return{id:x.id,subject:x.metadata.subject,status:x.metadata.status,excerpt:r$(B,150),created:x.created,sentAt:x.metadata.sentAt??null,url:`/newsletters/${x.id}`}}buildListResult(x,B,A){return{newsletters:x,totalCount:B?.totalItems??x.length,pagination:B}}async fetch(x,B,A){let{query:w}=this.parseQuery(x),f=A.entityService;if(w.id)return this.fetchSingleNewsletter(w.id,B,f);let D=w.status,$=D?{filter:{metadata:{status:D}}}:void 0,{items:Z,pagination:Q}=await this.fetchList(w,f,$);return B.parse(this.buildListResult(Z,Q,w))}async fetchSingleNewsletter(x,B,A){let w=await A.getEntity({entityType:this.config.entityType,id:x});if(!w)throw Error(`Newsletter not found: ${x}`);let f=await this.resolveNavigation(w,A),D=[];if(w.metadata.entityIds?.length){let Q=w.metadata.sourceEntityType??"post";D=(await Promise.all(w.metadata.entityIds.map(async(W)=>{let H=await A.getEntity({entityType:Q,id:W});if(H){let F=H.metadata;return{id:W,title:F.title??W,url:`/${Q}s/${F.slug??W}`}}return null}))).filter((W)=>W!==null)}let $=LIx(w),Z={id:w.id,subject:w.metadata.subject,status:w.metadata.status,content:$,created:w.created,updated:w.updated,sentAt:w.metadata.sentAt,scheduledFor:w.metadata.scheduledFor,newsletter:w,prevNewsletter:f.prev?{id:f.prev.id,subject:f.prev.subject,url:f.prev.url}:null,nextNewsletter:f.next?{id:f.next.id,subject:f.next.subject,url:f.next.url}:null,sourceEntities:D.length>0?D:void 0};return B.parse(Z)}}var $b9=X.object({prompt:X.string().optional().describe("AI generation prompt"),sourceEntityIds:X.array(X.string()).optional().describe("Entity IDs to include in newsletter (e.g., blog posts)"),sourceEntityType:X.enum(["post"]).optional().describe("Type of source entities"),content:X.string().optional().describe("Direct content (skip AI)"),subject:X.string().optional().describe("Newsletter subject (AI-generated if not provided)"),addToQueue:X.boolean().optional().describe("Create as queued (true) or draft (false)")});class T20 extends UA{constructor(x,B){super(x,B,{schema:$b9,jobTypeName:lf.generation,entityType:"newsletter"})}async generate(x,B){let A=x.addToQueue??!1,{prompt:w,sourceEntityIds:f,sourceEntityType:D}=x,{content:$,subject:Z}=x;if($){if(!Z)this.failEarly("Subject is required when providing content directly");await this.reportProgress(B,{progress:50,message:"Using provided content"})}else if(f&&f.length>0){let F=D??"post";await this.reportProgress(B,{progress:10,message:`Fetching ${f.length} source entities`});let q=(await Promise.all(f.map((L)=>this.context.entityService.getEntity({entityType:F,id:L})))).filter((L)=>L!=null);if(q.length===0)this.failEarly(`No source entities found for IDs: ${f.join(", ")}`);await this.reportProgress(B,{progress:30,message:`Generating newsletter from ${q.length} posts`});let b=`Create an engaging newsletter that highlights these blog posts:
5683
5683
 
5684
5684
  ${q.map((L)=>`## ${L.metadata.title}
5685
5685
 
@@ -5748,7 +5748,7 @@ Newsletter-specific guidelines:
5748
5748
  - "Reply and let me know..."
5749
5749
  - "Until next time..."
5750
5750
 
5751
- The goal is to build a relationship with readers through valuable, authentic content.`});import{jsxDEV as f7,Fragment as Hb9}from"preact/jsx-dev-runtime";var Qb9=X.enum(["generating","draft","queued","published","failed"]),Xb9=X.object({id:X.string(),subject:X.string(),status:Qb9,excerpt:X.string(),created:X.string(),sentAt:X.string().nullable().default(null),url:X.string()}),Yb9=X.object({newsletters:X.array(Xb9),totalCount:X.number(),pagination:KB.nullable()}),Wb9=({newsletters:x,totalCount:B,pageTitle:A,pagination:w,baseUrl:f="/newsletters"})=>{let D=A??"Newsletters",$=`Browse all ${B} ${B===1?"newsletter":"newsletters"}`;return f7(Hb9,{children:[f7(z9,{title:D,description:$},void 0,!1,void 0,this),f7("div",{className:"newsletter-list bg-theme",children:f7("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[f7("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:D},void 0,!1,void 0,this),x.length===0?f7("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):f7("div",{className:"space-y-4",children:x.map((Z)=>f7(r8,{href:Z.url,children:[f7(h1,{className:"text-lg",children:Z.subject},void 0,!1,void 0,this),f7(K4,{children:f7("div",{className:"flex items-center gap-3",children:[f7(m2,{status:Z.status},void 0,!1,void 0,this),f7("span",{className:"text-sm text-theme-muted",children:G6(Z.sentAt??Z.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Z.excerpt&&f7("p",{className:"text-theme-muted line-clamp-2",children:Z.excerpt},void 0,!1,void 0,this)]},Z.id,!0,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&f7(oD,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},MIx=mx({name:"newsletter-list",description:"Newsletter list page template",schema:Yb9,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:Wb9}});import{jsxDEV as d9,Fragment as bb9}from"preact/jsx-dev-runtime";var Fb9=X.enum(["generating","draft","queued","published","failed"]),Kb9=X.object({id:X.string(),title:X.string(),url:X.string()}),vIx=X.object({id:X.string(),subject:X.string(),url:X.string()}),qb9=X.object({id:X.string(),subject:X.string(),status:Fb9,content:X.string(),created:X.string(),updated:X.string(),sentAt:X.string().nullable().default(null),scheduledFor:X.string().nullable().default(null),sourceEntities:X.array(Kb9).nullable().default(null),prevNewsletter:vIx.nullable().default(null),nextNewsletter:vIx.nullable().default(null)}),zb9=({subject:x,status:B,content:A,created:w,sentAt:f,scheduledFor:D,sourceEntities:$,prevNewsletter:Z,nextNewsletter:Q})=>{let Y=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:x}],W=f??w,H=f?"Sent":"Created";return d9(bb9,{children:[d9(z9,{title:x,description:`Newsletter: ${x}`},void 0,!1,void 0,this),d9("section",{className:"newsletter-detail-section",children:d9("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:d9("div",{className:"max-w-3xl mx-auto",children:[d9(nf,{items:Y},void 0,!1,void 0,this),d9("h1",{className:"text-3xl md:text-4xl font-bold text-heading leading-tight tracking-tight mb-4",children:x},void 0,!1,void 0,this),d9("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[d9(m2,{status:B},void 0,!1,void 0,this),d9("span",{children:[H,": ",G6(W,{style:"long"})]},void 0,!0,void 0,this),D&&B==="queued"&&d9("span",{children:["Scheduled for: ",G6(D,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),$&&$.length>0&&d9(r8,{variant:"compact",className:"mb-8",children:[d9("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),d9("ul",{className:"space-y-1",children:$.map((F)=>d9("li",{children:d9("a",{href:F.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:F.title},void 0,!1,void 0,this)},F.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),d9(cB,{markdown:A},void 0,!1,void 0,this),(Z??Q)&&d9("nav",{className:"mt-12 pt-8 border-t border-theme",children:d9("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[Z?d9(r8,{href:Z.url,variant:"compact",children:[d9("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),d9("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Z.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this):d9("div",{},void 0,!1,void 0,this),Q&&d9(r8,{href:Q.url,variant:"compact",className:"md:text-right",children:[d9("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),d9("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Q.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},NIx=mx({name:"newsletter-detail",description:"Individual newsletter detail template",schema:qb9,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:zb9}});var $m={name:"@brains/newsletter",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Newsletter composite \u2014 bundles the newsletter entity with the buttondown service plugin",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Gb9=X.looseObject({}),Eb9=X.object({prompt:X.string().optional(),content:X.string().optional()});class Zm extends g8{entityType="newsletter";schema=xz;adapter=JIx;constructor(x={}){super("newsletter",$m,x,Gb9)}getEntityTypeConfig(){return{projectionSourceRole:"secondary",publish:{publishStatuses:["queued","published","failed"]}}}createGenerationHandler(x){return new T20(this.logger,x)}getTemplates(){return{generation:kIx,"newsletter-list":MIx,"newsletter-detail":NIx}}getDataSources(){return[new g20(this.logger.child("NewsletterDataSource"))]}async onRegister(x){this.deferPublishRegistration(x),this.subscribeToGenerateExecute(x),this.registerEvalHandlers(x),x.messaging.subscribe(e8.pluginsRegistered,async()=>{let B=await x.messaging.send({type:eq.isConfigured,payload:{}});if(!("noop"in B)&&B.success)await x.messaging.send({type:O4.slotRegister,payload:{pluginId:this.id,slotName:"footer-top",render:()=>Ub9(IIx,{variant:"inline"})}});return{success:!0}}),this.logger.debug("Newsletter plugin registered")}deferPublishRegistration(x){let B={name:"internal",publish:async(A,w)=>{let f=typeof w.subject==="string"?w.subject:"",D=await x.messaging.send({type:eq.send,payload:{entityId:"",subject:f,content:A}});return{id:!("noop"in D)&&D.data?.emailId?D.data.emailId:"internal"}}};x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.messaging.send({type:d5.register,payload:{entityType:"newsletter",provider:B,config:{publishResultIdField:"buttondownId",publishTimestampField:"sentAt"}}}),{success:!0}})}subscribeToGenerateExecute(x){x.messaging.subscribe(w7.execute,async(B)=>{if(B.payload.entityType!=="newsletter")return{success:!0};try{let A=await x.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:10}});if(A.length===0)return await x.messaging.send({type:w7.reportFailure,payload:{entityType:"newsletter",error:"No published posts available for newsletter"}}),{success:!0};return await x.jobs.enqueue({type:lf.generation,data:{sourceEntityIds:A.map((w)=>w.id),sourceEntityType:"post",addToQueue:!1},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"newsletter-generation"}}}),{success:!0}}catch(A){return await x.messaging.send({type:w7.reportFailure,payload:{entityType:"newsletter",error:g(A)}}),{success:!0}}})}registerEvalHandlers(x){x.eval.registerHandler("generation",async(B)=>{let A=Eb9.parse(B),w=A.content?`Create an engaging newsletter based on this content:
5751
+ The goal is to build a relationship with readers through valuable, authentic content.`});import{jsxDEV as f7,Fragment as Hb9}from"preact/jsx-dev-runtime";var Qb9=X.enum(["generating","draft","queued","published","failed"]),Xb9=X.object({id:X.string(),subject:X.string(),status:Qb9,excerpt:X.string(),created:X.string(),sentAt:X.string().nullable().default(null),url:X.string()}),Yb9=X.object({newsletters:X.array(Xb9),totalCount:X.number(),pagination:KB.nullable()}),Wb9=({newsletters:x,totalCount:B,pageTitle:A,pagination:w,baseUrl:f="/newsletters"})=>{let D=A??"Newsletters",$=`Browse all ${B} ${B===1?"newsletter":"newsletters"}`;return f7(Hb9,{children:[f7(z9,{title:D,description:$},void 0,!1,void 0,this),f7("div",{className:"newsletter-list bg-theme",children:f7("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[f7("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:D},void 0,!1,void 0,this),x.length===0?f7("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):f7("div",{className:"space-y-4",children:x.map((Z)=>f7(r8,{href:Z.url,children:[f7(h1,{className:"text-lg",children:Z.subject},void 0,!1,void 0,this),f7(K4,{children:f7("div",{className:"flex items-center gap-3",children:[f7(m2,{status:Z.status},void 0,!1,void 0,this),f7("span",{className:"text-sm text-theme-muted",children:G6(Z.sentAt??Z.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Z.excerpt&&f7("p",{className:"text-theme-muted line-clamp-2",children:Z.excerpt},void 0,!1,void 0,this)]},Z.id,!0,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&f7(oD,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},MIx=mx({name:"newsletter-list",description:"Newsletter list page template",schema:Yb9,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:Wb9}});import{jsxDEV as d9,Fragment as bb9}from"preact/jsx-dev-runtime";var Fb9=X.enum(["generating","draft","queued","published","failed"]),Kb9=X.object({id:X.string(),title:X.string(),url:X.string()}),vIx=X.object({id:X.string(),subject:X.string(),url:X.string()}),qb9=X.object({id:X.string(),subject:X.string(),status:Fb9,content:X.string(),created:X.string(),updated:X.string(),sentAt:X.string().nullable().default(null),scheduledFor:X.string().nullable().default(null),sourceEntities:X.array(Kb9).nullable().default(null),prevNewsletter:vIx.nullable().default(null),nextNewsletter:vIx.nullable().default(null)}),zb9=({subject:x,status:B,content:A,created:w,sentAt:f,scheduledFor:D,sourceEntities:$,prevNewsletter:Z,nextNewsletter:Q})=>{let Y=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:x}],W=f??w,H=f?"Sent":"Created";return d9(bb9,{children:[d9(z9,{title:x,description:`Newsletter: ${x}`},void 0,!1,void 0,this),d9("section",{className:"newsletter-detail-section",children:d9("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:d9("div",{className:"max-w-3xl mx-auto",children:[d9(nf,{items:Y},void 0,!1,void 0,this),d9("h1",{className:"text-3xl md:text-4xl font-bold text-heading leading-tight tracking-tight mb-4",children:x},void 0,!1,void 0,this),d9("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[d9(m2,{status:B},void 0,!1,void 0,this),d9("span",{children:[H,": ",G6(W,{style:"long"})]},void 0,!0,void 0,this),D&&B==="queued"&&d9("span",{children:["Scheduled for: ",G6(D,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),$&&$.length>0&&d9(r8,{variant:"compact",className:"mb-8",children:[d9("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),d9("ul",{className:"space-y-1",children:$.map((F)=>d9("li",{children:d9("a",{href:F.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:F.title},void 0,!1,void 0,this)},F.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),d9(cB,{markdown:A},void 0,!1,void 0,this),(Z??Q)&&d9("nav",{className:"mt-12 pt-8 border-t border-theme",children:d9("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[Z?d9(r8,{href:Z.url,variant:"compact",children:[d9("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),d9("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Z.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this):d9("div",{},void 0,!1,void 0,this),Q&&d9(r8,{href:Q.url,variant:"compact",className:"md:text-right",children:[d9("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),d9("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Q.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},NIx=mx({name:"newsletter-detail",description:"Individual newsletter detail template",schema:qb9,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:zb9}});var $m={name:"@brains/newsletter",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Newsletter composite \u2014 bundles the newsletter entity with the buttondown service plugin",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Gb9=X.looseObject({}),Eb9=X.object({prompt:X.string().optional(),content:X.string().optional()});class Zm extends g8{entityType="newsletter";schema=xz;adapter=JIx;constructor(x={}){super("newsletter",$m,x,Gb9)}getEntityTypeConfig(){return{projectionSourceRole:"secondary",publish:{publishStatuses:["queued","published","failed"]}}}createGenerationHandler(x){return new T20(this.logger,x)}getTemplates(){return{generation:kIx,"newsletter-list":MIx,"newsletter-detail":NIx}}getDataSources(){return[new g20(this.logger.child("NewsletterDataSource"))]}async onRegister(x){this.deferPublishRegistration(x),this.subscribeToGenerateExecute(x),this.registerEvalHandlers(x),x.messaging.subscribe(e8.pluginsRegistered,async()=>{let B=await x.messaging.send({type:eq.isConfigured,payload:{}});if(!("noop"in B)&&B.success)await x.messaging.send({type:O4.slotRegister,payload:{pluginId:this.id,slotName:"footer-top",render:()=>Ub9(IIx,{variant:"inline"})}});return{success:!0}}),this.logger.debug("Newsletter plugin registered")}deferPublishRegistration(x){let B={name:"internal",publish:async(A,w)=>{let f=typeof w.subject==="string"?w.subject:"",D=await x.messaging.send({type:eq.send,payload:{entityId:"",subject:f,content:A}});return{id:!("noop"in D)&&D.data?.emailId?D.data.emailId:"internal"}}};x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.messaging.send({type:d5.register,payload:{entityType:"newsletter",provider:B,config:{publishResultIdField:"buttondownId",publishTimestampField:"sentAt"}}}),{success:!0}})}subscribeToGenerateExecute(x){x.messaging.subscribe(w7.execute,async(B)=>{if(B.payload.entityType!=="newsletter")return{success:!0};try{let A=await x.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:10}});if(A.length===0)return await x.messaging.send({type:w7.reportFailure,payload:{entityType:"newsletter",error:"No published posts available for newsletter"}}),{success:!0};return await x.jobs.enqueue({type:lf.generation,data:{sourceEntityIds:A.map((w)=>w.id),sourceEntityType:"post",addToQueue:!1},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"newsletter-generation"}}}),{success:!0}}catch(A){return await x.messaging.send({type:w7.reportFailure,payload:{entityType:"newsletter",error:g(A)}}),{success:!0}}})}registerEvalHandlers(x){x.eval.registerHandler("generation",async(B)=>{let A=Eb9.parse(B),w=A.content?`Create an engaging newsletter based on this content:
5752
5752
 
5753
5753
  ${A.content}`:A.prompt??"Write an engaging newsletter",f=i3(await y2(x.entityService));return x.ai.generate({prompt:w,templateName:lf.generation,representedIdentity:"anchor",...f&&{styleGuide:{voice:f}}})})}}function Qm(x={}){return new Zm(x)}var _b9="https://api.buttondown.email/v1",Pb9=X.enum(["unactivated","regular","unsubscribed","already_subscribed"]),Jb9=X.enum(["draft","about_to_send","scheduled","sent"]),p20=X.looseObject({id:X.string(),email:X.string(),subscriber_type:Pb9,metadata:X.record(X.string(),X.string()).optional()}),OIx=X.looseObject({id:X.string(),subject:X.string(),body:X.string().optional(),status:Jb9,publish_date:X.string().optional()}),Lb9=X.looseObject({results:X.array(p20),count:X.number()}),kb9=X.looseObject({detail:X.string().optional(),message:X.string().optional(),code:X.string().optional()});class u20 extends Error{status;code;constructor(x,B,A){super(x);this.name="ButtondownApiError",this.status=B,this.code=A}}class yY{config;logger;constructor(x,B){this.config=x,this.logger=B}async request(x,B={}){let A=`${_b9}${x}`;this.logger.debug("Buttondown API request",{endpoint:x,method:B.method??"GET"});let w=await fetch(A,{...B,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...B.headers}});if(!w.ok){let f=await w.json().catch(()=>({})),D=kb9.safeParse(f),$=D.success?D.data.detail??D.data.message??`HTTP ${w.status}`:`HTTP ${w.status}`,Z=D.success?D.data.code:void 0;throw this.logger.error("Buttondown API error",{endpoint:x,status:w.status,code:Z,error:$}),new u20(`Buttondown API error: ${$}`,w.status,Z)}return w.json()}async createSubscriber(x){let B={email_address:x.email,type:this.config.doubleOptIn?"unactivated":"regular"};if(x.name)B.metadata={name:x.name};if(x.tags&&x.tags.length>0)B.tags=x.tags;this.logger.info("Creating subscriber",{email:x.email});try{return p20.parse(await this.request("/subscribers",{method:"POST",body:JSON.stringify(B)}))}catch(A){if(A instanceof u20&&A.code==="email_already_exists")return this.logger.info("Subscriber already exists",{email:x.email}),{...await this.getSubscriberByEmail(x.email),subscriber_type:"already_subscribed"};throw A}}async getSubscriberByEmail(x){return p20.parse(await this.request(`/subscribers/${encodeURIComponent(x)}`))}async unsubscribe(x){this.logger.info("Unsubscribing",{email:x}),await this.request(`/subscribers/${encodeURIComponent(x)}`,{method:"DELETE"})}async listSubscribers(x){let B=new URLSearchParams;if(x?.type)B.set("type",x.type);if(x?.limit)B.set("page_size",String(x.limit));let A=B.toString(),w=A?`/subscribers?${A}`:"/subscribers";return Lb9.parse(await this.request(w))}async createEmail(x){let B={subject:x.subject,body:x.body,status:x.status??"draft"};if(x.publish_date)B.publish_date=x.publish_date;return this.logger.info("Creating email",{subject:x.subject,status:x.status??"draft"}),OIx.parse(await this.request("/emails",{method:"POST",body:JSON.stringify(B)}))}async getEmail(x){return OIx.parse(await this.request(`/emails/${x}`))}async validateCredentials(){try{return await this.request("/subscribers?page_size=1"),!0}catch{return!1}}}var Mb9=X.string().email({pattern:X.regexes.html5Email}),vb9=X.object({action:X.enum(["subscribe","unsubscribe","list"]).default("subscribe").describe("Subscriber action to perform"),email:Mb9.optional().describe("Email address for subscribe or unsubscribe"),name:X.string().optional().describe("Subscriber name for subscribe"),tags:X.array(X.string()).optional().describe("Tags to apply for subscribe"),type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Subscriber status filter for list"),limit:X.number().optional().describe("Maximum list results")});function hIx(x,B,A){let w=new yY(B,A);return[E1("newsletter","subscribers","Manage newsletter subscribers with an action discriminator. Use action=subscribe to add an email, action=unsubscribe to remove an email, and action=list to list subscribers with optional status filtering.",vb9,async(f)=>Nb9(w,f),{sideEffects:"external"})]}async function Nb9(x,B){switch(B.action){case"subscribe":return Ib9(x,B);case"unsubscribe":return Ob9(x,B);case"list":return hb9(x,B)}}async function Ib9(x,B){if(!B.email)return U1("email is required for subscribe action");try{let A=await x.createSubscriber({email:B.email,...B.name&&{name:B.name},...B.tags&&{tags:B.tags}}),w=A.subscriber_type==="already_subscribed";return G1({subscriberId:A.id,email:A.email,status:A.subscriber_type,message:w?"already_subscribed":"subscribed"},w?`${B.email} is already subscribed`:`Subscribed ${B.email} successfully`)}catch(A){return U1(g(A))}}async function Ob9(x,B){if(!B.email)return U1("email is required for unsubscribe action");try{return await x.unsubscribe(B.email),G1({email:B.email},`Unsubscribed ${B.email} successfully`)}catch(A){return U1(g(A))}}async function hb9(x,B){try{let A=await x.listSubscribers({...B.type&&{type:B.type},...B.limit&&{limit:B.limit}});return G1({subscribers:A.results.map((w)=>({id:w.id,email:w.email,status:w.subscriber_type})),count:A.count},`Found ${A.count} subscribers`)}catch(A){return U1(g(A))}}async function RIx(x,B,A,w){if(x.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let f=await A.getEntity({entityType:"post",id:x.entityId});if(!f)return{success:!1,error:`Post ${x.entityId} not found`};w.info("Auto-sending newsletter for published post",{postId:f.id,title:f.metadata.title});try{let D=await B.createEmail({subject:f.metadata.title,body:f.content,status:"about_to_send"});return w.info("Newsletter sent for post",{postId:f.id,emailId:D.id}),{success:!0,emailId:D.id}}catch(D){let $=g(D);return w.error("Failed to send newsletter for post",{postId:f.id,error:$}),{success:!1,error:$}}}var Rb9=X.object({apiKey:X.string().optional().describe("Buttondown API key"),doubleOptIn:X.boolean().default(!0).describe("Require email confirmation for new subscribers"),autoSendOnPublish:X.boolean().default(!1).describe("Automatically send newsletter when a blog post is published")});class Xm extends D8{constructor(x={}){super("buttondown",$m,x,Rb9)}async onRegister(x){if(x.messaging.subscribe(eq.isConfigured,async()=>{return{success:!!this.config.apiKey}}),this.config.apiKey){let B=new yY({apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger);if(x.messaging.subscribe(eq.send,async(A)=>{try{return{success:!0,data:{emailId:(await B.createEmail({subject:A.payload.subject,body:A.payload.content,status:"about_to_send"})).id}}}catch(w){return this.logger.error("Buttondown send failed",{error:g(w)}),{success:!1}}}),this.config.autoSendOnPublish)x.messaging.subscribe(d5.completed,async(A)=>{let w=await RIx(A.payload,B,x.entityService,this.logger);if(!w.success)return this.logger.error("Buttondown auto-send failed",{entityId:A.payload.entityId,error:w.error}),{success:!1,error:w.error};return{success:!0}}),this.logger.info("Buttondown auto-send on publish enabled")}}async getTools(){if(!this.config.apiKey)return[];return hIx(this.id,{apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger)}getApiRoutes(){if(!this.config.apiKey)return[];return[{path:"/subscribe",method:"POST",tool:"newsletter_subscribers",public:!0,successRedirect:"/subscribe/thanks",errorRedirect:"/subscribe/error"}]}}function Ym(x={}){return new Xm(x)}var yb9=X.object({apiKey:X.string().optional().describe("Buttondown API key"),doubleOptIn:X.boolean().optional().describe("Require email confirmation for new subscribers"),autoSendOnPublish:X.boolean().optional().describe("Automatically send newsletter when a blog post is published")});function yIx(x={}){let B=yb9.safeParse(x);if(!B.success)throw new Sy("newsletter",B.error.issues.map((w)=>({path:w.path.map(String).join("."),code:w.code,message:w.message})));let A=B.data;return[Qm({}),Ym({...A.apiKey!==void 0&&{apiKey:A.apiKey},...A.doubleOptIn!==void 0&&{doubleOptIn:A.doubleOptIn},...A.autoSendOnPublish!==void 0&&{autoSendOnPublish:A.autoSendOnPublish}})]}var mIx=X.enum(["generating","failed"]),VZ=X.object({title:X.string().optional(),status:mIx.optional(),error:X.string().optional()}),CIx=X.object({title:X.string(),status:mIx.optional(),error:X.string().optional()}),UZ=j8.extend({entityType:X.literal("note"),metadata:CIx}),mb9=UZ.extend({frontmatter:VZ,body:X.string()});var Cb9=X.record(X.string(),X.unknown());class S20 extends ox{constructor(){super({entityType:"note",purpose:"A short, free-form captured thought, reference, or snippet the user wants to keep.",schema:UZ,frontmatterSchema:VZ})}toMarkdown(x){let B=this.extractBody(x.content);try{let A=this.parseFrontMatter(x.content,VZ);if(Object.values(A).some((w)=>w!==void 0))return this.buildMarkdown(B,A)}catch{}return B}fromMarkdown(x){let B=this.parseMarkdownFrontmatter(x),A=B.title??this.extractH1(x)??"Untitled";return{content:x,entityType:"note",metadata:{title:A,...B.status&&{status:B.status},...B.error&&{error:B.error}}}}parseNoteFrontmatter(x){return this.parseMarkdownFrontmatter(x.content)}parseMarkdownFrontmatter(x){try{return this.parseFrontMatter(x,VZ)}catch{return{}}}buildStub(x){let B={title:x.title,status:"generating"};return{content:this.buildMarkdown("",B),metadata:{title:x.title,status:"generating"}}}createNoteContent(x,B){try{let A=this.parseFrontMatter(B,Cb9);if(Object.keys(A).length===0)return B;let w={...A,title:A.title??x},f=this.extractBody(B);return this.buildMarkdown(f,w)}catch{return B}}extractH1(x){return x.match(/^#\s+(.+)$/m)?.[1]?.trim()??null}}var df=new S20;var i20=X.object({defaultPrompt:X.string().default("Create a note summarizing key concepts from my knowledge base")});var cIx=X.object({title:X.string().max(80).describe("A clear, descriptive title for the note (3-8 words)"),body:X.string().describe("Note content in markdown format with clear organization and structure")}),l20=mx({name:"note:generation",description:"Template for AI to generate notes from prompts",schema:cIx,dataSourceId:"shell:ai-content",requiredPermission:"public",useKnowledgeContext:!0,basePrompt:`You are helping to create personal knowledge notes for research and reference.
5754
5754
 
@@ -5765,15 +5765,15 @@ title: ${JSON.stringify(x)}
5765
5765
  ---
5766
5766
 
5767
5767
  ${B.trim()}
5768
- `}var ub9={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"},Sb9=X.object({uploadId:X.string().min(1),entityId:X.string().min(1),stubContentHash:X.string().min(1).optional(),title:X.string().optional()});class d20 extends $9{context;constructor(x,B){super(x,{schema:Sb9,jobTypeName:"upload-import"});this.context=B}async process(x,B,A){try{await this.reportProgress(A,{progress:10,message:"Reading uploaded file"});let w=await this.context.uploads.scoped(ub9).read(x.uploadId);await this.reportProgress(A,{progress:35,message:"Extracting markdown from upload"});let f=await uIx({upload:w,...x.title!==void 0?{title:x.title}:{}});await this.reportProgress(A,{progress:80,message:"Saving imported note"});let D=new Date().toISOString(),$=df.fromMarkdown(f.content),Z=await l7({entityService:this.context.entityService,entity:{id:x.entityId,entityType:"note",content:f.content,metadata:{title:f.title,...$.metadata},created:D,updated:D},...x.stubContentHash!==void 0?{expectedContentHash:x.stubContentHash}:{}});if(Z.mutation.skipReason==="content-conflict")return await this.reportProgress(A,{progress:100,message:"Upload import superseded by newer note content"}),{entityId:Z.entityId,status:"superseded"};return await this.reportProgress(A,{progress:100,message:"Upload imported as markdown note"}),{entityId:Z.entityId,status:"created"}}catch(w){return await this.markStubFailed(x.entityId,g(w),x.stubContentHash),p6.failure(w)}}async markStubFailed(x,B,A){try{let w=await this.context.entityService.getEntity({entityType:"note",id:x});if(!w)return;await this.context.entityService.updateEntity({entity:{...w,content:h3(h3(w.content,"status","failed"),"error",B),metadata:{...w.metadata,status:"failed",error:B}},...A!==void 0?{options:{expectedContentHash:A}}:{}})}catch(w){this.logger.warn("Failed to mark import stub as failed",{error:w,entityId:x})}}summarizeDataForLog(x){return{uploadId:x.uploadId,entityId:x.entityId,hasTitle:x.title!==void 0,hasStubContentHash:x.stubContentHash!==void 0}}}async function SIx({entity:x,config:B}){let A=UZ.parse(x),w=G9(A.content,VZ);return{$type:"ai.rizom.brain.note",title:A.metadata.title,body:w.content,format:"text/markdown",...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"note",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function a20(){return{entityType:"note",collection:"ai.rizom.brain.note",lexicon:h4["ai.rizom.brain.note"],validate:!1,buildRecord:SIx}}var iIx={name:"@brains/note",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Personal knowledge capture with markdown-first workflow",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/document":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var lIx={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"},lb9=X.object({prompt:X.string()});class s20 extends g8{entityType=df.entityType;schema=UZ;adapter=df;unregisterAtprotoProjection;constructor(x={}){super("note",iIx,x,i20)}getEntityTypeConfig(){return{projectionSourceRole:"primary"}}async interceptCreate(x,B,A){if(x.from?.kind!==lIx.refKind)return{kind:"continue",input:x};if(x.transform!=="extract-markdown")return{kind:"handled",result:{success:!1,error:'Importing an upload as a note requires transform: "extract-markdown"'}};let w=x.from.id,f;try{f=await A.uploads.scoped(lIx).readRecord(w)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}try{if(!pIx(f.mediaType))return{kind:"handled",result:{success:!1,error:"Only text, JSON, and PDF uploads can be imported as markdown notes"}};let D=n20({filename:f.filename,...x.title!==void 0?{title:x.title}:{}}),$=df.buildStub({id:D.id,title:D.title}),Z=new Date().toISOString(),Q=await A.entityService.createEntity({entity:{id:D.id,entityType:"note",content:$.content,metadata:$.metadata,created:Z,updated:Z},options:{deduplicateId:!0}}),Y=await A.entityService.getEntity({entityType:"note",id:Q.entityId});if(!Y)throw Error("Created note import stub could not be read");let W=await A.jobs.enqueue({type:"upload-import",data:{uploadId:w,entityId:Q.entityId,stubContentHash:Y.contentHash,...x.title!==void 0?{title:x.title}:{}}});return{kind:"handled",result:{success:!0,data:{entityId:Q.entityId,status:"generating",jobId:W}}}}catch(D){return{kind:"handled",result:{success:!1,error:g(D,"Failed to import upload as markdown")}}}}createGenerationHandler(x){return new Wm(this.logger.child("NoteGenerationJobHandler"),x)}getTemplates(){return{generation:l20}}async onRegister(x){x.jobs.registerHandler("upload-import",new d20(this.logger.child("UploadMarkdownImportJobHandler"),x)),x.eval.registerHandler("generateNote",async(B)=>{let A=lb9.parse(B);return x.ai.generate({prompt:A.prompt,templateName:"note:generation",representedIdentity:"none"})}),this.unregisterAtprotoProjection=R4.getInstance().register(a20())}async getInstructions(){return"Note entities are editable markdown notes. Use them for durable text captures, summaries, and imported markdown; raw files remain document or image entities instead of notes."}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function r20(x={}){return new s20(x)}var nIx={name:"@brains/notifications",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Generic notification routing for transactional and administrative messages",dependencies:{"@brains/notification-contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var db9=X.looseObject({defaultRecipient:o20.optional()});class dIx extends D8{constructor(x={}){super("notifications",nIx,x,db9)}async onRegister(x){x.messaging.subscribe(PV,async(B)=>{let A=t20.parse(B.payload),w=A.recipient??this.config.defaultRecipient;if(!w)return x.logger.warn("Notification has no recipient"),{success:!1,error:"Notification recipient missing"};let f=x.channels.getDeliveryProvider(w.type);if(!f||!await f.isAvailable())return x.logger.warn("Notification has no available transport",{channelType:w.type}),{success:!1,error:"Notification transport missing"};let D=await f.send({recipient:w.address,subject:A.title,text:A.body,...A.html?{html:A.html}:{},sensitivity:A.sensitivity,idempotencyKey:A.idempotencyKey??crypto.randomUUID()});if(D.status!=="sent")return{success:!1,error:"Notification delivery failed"};return{success:!0,data:D.providerDeliveryId?{status:"sent",deliveryId:D.providerDeliveryId}:{status:"sent"}}})}}function aIx(x={}){return new dIx(x)}import{existsSync as fV9,mkdirSync as DV9,writeFileSync as $V9}from"fs";import{join as af}from"path";var e20=X.object({baseFolder:X.string().default("_obsidian")});function ab9(x){let B=wO(x);if(B==="enum"){let A=DO(x);return A?{type:"enum",enumValues:A}:{type:"enum"}}if(B==="literal")return{type:"string",defaultValue:$O(x)};if(B==="string")return{type:"string"};if(B==="number")return{type:"number"};if(B==="boolean")return{type:"boolean"};if(B==="array")return{type:"array"};if(B==="date")return{type:"date"};return{type:"unknown"}}function sIx(x){let B=[];for(let[A,w]of Object.entries(x.shape)){let{inner:f,required:D,defaultValue:$}=fO(w),Z=ab9(f),Q={name:A,type:Z.type,required:D},Y=$!==void 0?$:Z.defaultValue;if(Y!==void 0)Q.defaultValue=Y;if(Z.enumValues)Q.enumValues=Z.enumValues;B.push(Q)}return B}function sb9(x,B){if(x.name==="entityType")return String(x.defaultValue??B);if(x.name==="title")return'"{{title}}"';if(x.type==="date"&&(x.name==="created"||x.name==="updated"))return'"{{date}}"';if(x.defaultValue!==void 0){if(Array.isArray(x.defaultValue))return"[]";if(typeof x.defaultValue==="boolean")return String(x.defaultValue);if(typeof x.defaultValue==="number")return String(x.defaultValue);return String(x.defaultValue)}if(x.type==="enum"&&x.enumValues&&x.enumValues.length>0)return x.enumValues[0]??"";switch(x.type){case"string":return'""';case"number":return"";case"boolean":return"false";case"array":return"[]";case"date":return'""';default:return'""'}}function rIx(x,B,A=""){let w=["---"];for(let f of B){let D=sb9(f,x);if(D==="")w.push(`${f.name}:`);else w.push(`${f.name}: ${D}`)}if(w.push("---"),w.push(""),A)w.push(A);else w.push("<!-- Write your content here -->"),w.push("");return w.join(`
5768
+ `}var ub9={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"},Sb9=X.object({uploadId:X.string().min(1),entityId:X.string().min(1),stubContentHash:X.string().min(1).optional(),title:X.string().optional()});class d20 extends $9{context;constructor(x,B){super(x,{schema:Sb9,jobTypeName:"upload-import"});this.context=B}async process(x,B,A){try{await this.reportProgress(A,{progress:10,message:"Reading uploaded file"});let w=await this.context.uploads.scoped(ub9).read(x.uploadId);await this.reportProgress(A,{progress:35,message:"Extracting markdown from upload"});let f=await uIx({upload:w,...x.title!==void 0?{title:x.title}:{}});await this.reportProgress(A,{progress:80,message:"Saving imported note"});let D=new Date().toISOString(),$=df.fromMarkdown(f.content),Z=await l7({entityService:this.context.entityService,entity:{id:x.entityId,entityType:"note",content:f.content,metadata:{title:f.title,...$.metadata},created:D,updated:D},...x.stubContentHash!==void 0?{expectedContentHash:x.stubContentHash}:{}});if(Z.mutation.skipReason==="content-conflict")return await this.reportProgress(A,{progress:100,message:"Upload import superseded by newer note content"}),{entityId:Z.entityId,status:"superseded"};return await this.reportProgress(A,{progress:100,message:"Upload imported as markdown note"}),{entityId:Z.entityId,status:"created"}}catch(w){return await this.markStubFailed(x.entityId,g(w),x.stubContentHash),p6.failure(w)}}async markStubFailed(x,B,A){try{let w=await this.context.entityService.getEntity({entityType:"note",id:x});if(!w)return;await this.context.entityService.updateEntity({entity:{...w,content:h3(h3(w.content,"status","failed"),"error",B),metadata:{...w.metadata,status:"failed",error:B}},...A!==void 0?{options:{expectedContentHash:A}}:{}})}catch(w){this.logger.warn("Failed to mark import stub as failed",{error:w,entityId:x})}}summarizeDataForLog(x){return{uploadId:x.uploadId,entityId:x.entityId,hasTitle:x.title!==void 0,hasStubContentHash:x.stubContentHash!==void 0}}}async function SIx({entity:x,config:B}){let A=UZ.parse(x),w=G9(A.content,VZ);return{$type:"ai.rizom.brain.note",title:A.metadata.title,body:w.content,format:"text/markdown",...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"note",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function a20(){return{entityType:"note",collection:"ai.rizom.brain.note",lexicon:h4["ai.rizom.brain.note"],validate:!1,buildRecord:SIx}}var iIx={name:"@brains/note",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Personal knowledge capture with markdown-first workflow",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/document":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var lIx={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"},lb9=X.object({prompt:X.string()});class s20 extends g8{entityType=df.entityType;schema=UZ;adapter=df;unregisterAtprotoProjection;constructor(x={}){super("note",iIx,x,i20)}getEntityTypeConfig(){return{projectionSourceRole:"primary"}}async interceptCreate(x,B,A){if(x.from?.kind!==lIx.refKind)return{kind:"continue",input:x};if(x.transform!=="extract-markdown")return{kind:"handled",result:{success:!1,error:'Importing an upload as a note requires transform: "extract-markdown"'}};let w=x.from.id,f;try{f=await A.uploads.scoped(lIx).readRecord(w)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}try{if(!pIx(f.mediaType))return{kind:"handled",result:{success:!1,error:"Only text, JSON, and PDF uploads can be imported as markdown notes"}};let D=n20({filename:f.filename,...x.title!==void 0?{title:x.title}:{}}),$=df.buildStub({id:D.id,title:D.title}),Z=new Date().toISOString(),Q=await A.entityService.createEntity({entity:{id:D.id,entityType:"note",content:$.content,metadata:$.metadata,created:Z,updated:Z},options:{deduplicateId:!0}}),Y=await A.entityService.getEntity({entityType:"note",id:Q.entityId});if(!Y)throw Error("Created note import stub could not be read");let W=await A.jobs.enqueue({type:"upload-import",data:{uploadId:w,entityId:Q.entityId,stubContentHash:Y.contentHash,...x.title!==void 0?{title:x.title}:{}}});return{kind:"handled",result:{success:!0,data:{entityId:Q.entityId,status:"generating",jobId:W}}}}catch(D){return{kind:"handled",result:{success:!1,error:g(D,"Failed to import upload as markdown")}}}}createGenerationHandler(x){return new Wm(this.logger.child("NoteGenerationJobHandler"),x)}getTemplates(){return{generation:l20}}async onRegister(x){x.jobs.registerHandler("upload-import",new d20(this.logger.child("UploadMarkdownImportJobHandler"),x)),x.eval.registerHandler("generateNote",async(B)=>{let A=lb9.parse(B);return x.ai.generate({prompt:A.prompt,templateName:"note:generation",representedIdentity:"none"})}),this.unregisterAtprotoProjection=R4.getInstance().register(a20())}async getInstructions(){return"Note entities are editable markdown notes. Use them for durable text captures, summaries, and imported markdown; raw files remain document or image entities instead of notes."}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function r20(x={}){return new s20(x)}var nIx={name:"@brains/notifications",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Generic notification routing for transactional and administrative messages",dependencies:{"@brains/notification-contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var db9=X.looseObject({defaultRecipient:o20.optional()});class dIx extends D8{constructor(x={}){super("notifications",nIx,x,db9)}async onRegister(x){x.messaging.subscribe(PV,async(B)=>{let A=t20.parse(B.payload),w=A.recipient??this.config.defaultRecipient;if(!w)return x.logger.warn("Notification has no recipient"),{success:!1,error:"Notification recipient missing"};let f=x.channels.getDeliveryProvider(w.type);if(!f||!await f.isAvailable())return x.logger.warn("Notification has no available transport",{channelType:w.type}),{success:!1,error:"Notification transport missing"};let D=await f.send({recipient:w.address,subject:A.title,text:A.body,...A.html?{html:A.html}:{},sensitivity:A.sensitivity,idempotencyKey:A.idempotencyKey??crypto.randomUUID()});if(D.status!=="sent")return{success:!1,error:"Notification delivery failed"};return{success:!0,data:D.providerDeliveryId?{status:"sent",deliveryId:D.providerDeliveryId}:{status:"sent"}}})}}function aIx(x={}){return new dIx(x)}import{existsSync as fV9,mkdirSync as DV9,writeFileSync as $V9}from"fs";import{join as af}from"path";var e20=X.object({baseFolder:X.string().default("_obsidian")});function ab9(x){let B=wO(x);if(B==="enum"){let A=DO(x);return A?{type:"enum",enumValues:A}:{type:"enum"}}if(B==="literal")return{type:"string",defaultValue:$O(x)};if(B==="string")return{type:"string"};if(B==="number")return{type:"number"};if(B==="boolean")return{type:"boolean"};if(B==="array")return{type:"array"};if(B==="date")return{type:"date"};return{type:"unknown"}}function sIx(x){let B=[];for(let[A,w]of Object.entries(x.shape)){let{inner:f,required:D,defaultValue:$}=fO(w),Z=ab9(f),Q={name:A,type:Z.type,required:D},Y=$!==void 0?$:Z.defaultValue;if(Y!==void 0)Q.defaultValue=Y;if(Z.enumValues)Q.enumValues=Z.enumValues;B.push(Q)}return B}function sb9(x,B){if(x.name==="entityType")return String(x.defaultValue??B);if(x.name==="title")return'"{{title}}"';if(x.type==="date"&&(x.name==="created"||x.name==="updated"))return'"{{date}}"';if(x.defaultValue!==void 0){if(Array.isArray(x.defaultValue))return"[]";if(typeof x.defaultValue==="boolean")return String(x.defaultValue);if(typeof x.defaultValue==="number")return String(x.defaultValue);return String(x.defaultValue)}if(x.type==="enum"&&x.enumValues&&x.enumValues.length>0)return x.enumValues[0]??"";switch(x.type){case"string":return'""';case"number":return"";case"boolean":return"false";case"array":return"[]";case"date":return'""';default:return'""'}}function rIx(x,B,A=""){let w=["---"];for(let f of B){let D=sb9(f,x);if(D==="")w.push(`${f.name}:`);else w.push(`${f.name}: ${D}`)}if(w.push("---"),w.push(""),A)w.push(A);else w.push("<!-- Write your content here -->"),w.push("");return w.join(`
5769
5769
  `)}var rb9={string:"Input",number:"Number",boolean:"Boolean",date:"Date",enum:"Select",array:"Multi",unknown:"Input"};function ob9(x){let B={name:x.name,id:x.name,type:rb9[x.type]};if(x.type==="enum"&&x.enumValues){let A={};x.enumValues.forEach((w,f)=>{A[String(f)]=w}),B.options=A}return B}function oIx(x,B){let A={filesPaths:x,fields:B.map(ob9)};return`---
5770
5770
  ${Az(A)}---
5771
- `}var tb9=new Set(["entityType"]),eb9={base:"Notes"},xV9=new Set(["note"]);function BV9(x){let B=["file.name"];for(let A of x)if(!tb9.has(A.name))B.push(A.name);return B}function AV9(x){return x.some((B)=>B.name==="status"&&B.type==="enum")}function eIx(x,B){let A=eb9[x]??tIx(x),w=AV9(B),f=BV9(B),D=[{type:"table",name:`All ${A}`,order:f}];if(w)D.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:f});let Z={filters:{and:[xV9.has(x)?'file.folder == "/"':`file.inFolder("${x}")`]},views:D};return{filename:`${A}.base`,content:Az(Z),hasStatus:w}}function xOx(x){if(x.length===0)return null;let B=x.map((w)=>`file.inFolder("${w}")`),A={filters:{and:[B.length===1?B[0]:{or:B}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return Az(A)}function BOx(x){if(x.length===0)return null;let B=x.map((w)=>`file.inFolder("${w.entityType}")`),A={filters:{and:[B.length===1?B[0]:{or:B},'status != "published"']},views:[{type:"table",name:"Pipeline",groupBy:{property:"status",direction:"ASC"},order:["file.name","file.folder","status"]}]};return Az(A)}var AOx={name:"@brains/obsidian-vault",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Obsidian vault integration \u2014 generates templates from entity schemas",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var ZV9={mkdir:DV9,writeFile:$V9,existsFile:fV9};class xB0 extends D8{deps;constructor(x={},B={}){super("obsidian-vault",AOx,x,e20);this.deps={...ZV9,...B}}async onReady(x){this.logger.info("Auto-syncing Obsidian templates, fileClasses, and bases"),await this.sync(x)}async syncTemplates(x){return this.sync(this.getContext(),x)}async sync(x,B){try{let A=x.entityService.getEntityTypes(),w=B?A.filter((b)=>B.includes(b)):A,f=af(x.dataDir,this.config.baseFolder),D=af(f,"templates"),$=af(f,"fileClasses"),Z=af(f,"bases");this.deps.mkdir(D,{recursive:!0}),this.deps.mkdir($,{recursive:!0}),this.deps.mkdir(Z,{recursive:!0});let Q=[],Y=[],W=[],H=[],F=[],K=[];for(let b of w){let G=x.entities.getEffectiveFrontmatterSchema(b);if(!G){this.logger.debug(`Skipping ${b}: no frontmatter schema`),Y.push(b);continue}let E=sIx(G),_=x.entities.getAdapter(b),L=_?.isSingleton===!0,N=oIx(b,E);if(this.deps.writeFile(af($,`${b}.md`),N),W.push(b),L){F.push(b),this.logger.debug(`Generated fileClass (singleton): ${b}`);continue}let y=_?.getBodyTemplate()??"",c=rIx(b,E,y);this.deps.writeFile(af(D,`${b}.md`),c),Q.push(b);let n=eIx(b,E),R=af(Z,n.filename);if(!this.deps.existsFile(R))this.deps.writeFile(R,n.content),H.push(b),this.logger.debug(`Generated base: ${n.filename}`);if(n.hasStatus)K.push({entityType:b,fields:E});this.logger.debug(`Generated template + fileClass: ${b}`)}let q=xOx(F);if(q){let b=af(Z,"Settings.base");if(!this.deps.existsFile(b))this.deps.writeFile(b,q),H.push("Settings"),this.logger.debug("Generated Settings.base")}let V=BOx(K);if(V){let b=af(Z,"Pipeline.base");if(!this.deps.existsFile(b))this.deps.writeFile(b,V),H.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${Q.length} templates, ${W.length} fileClasses, ${H.length} bases (${Y.length} skipped)`),G1({generated:Q,skipped:Y,fileClasses:W,bases:H})}catch(A){return this.logger.error("Failed to sync",{error:A}),U1(g(A,"Unknown error"))}}}function BB0(x={},B){return new xB0(x,B)}var Hm=X.enum(["draft","active","archived"]),Fm=X.enum(["admin","trusted","public"]),Km=X.enum(["agent-confirmed","manual"]),QV9=X.enum(["draft","active","archived"]),XV9=X.enum(["admin","trusted","public"]),YV9=X.enum(["agent-confirmed","manual"]),Dw=X.preprocess((x)=>typeof x==="string"&&x.trim().length===0?void 0:x,X.string().min(1).optional()),sf=X.preprocess((x)=>typeof x==="string"&&x.trim().length===0?void 0:x,X.string().min(1).optional()),AB0=X.object({event:X.string().min(1),target:X.string().min(1),operatorAction:X.boolean().optional(),label:sf,description:sf,operatorDescription:sf}),wB0=X.object({id:X.string().min(1),title:X.string().min(1),prompt:sf,requiredDetails:X.array(X.string().min(1)).default([]),instructions:X.array(X.string().min(1)).default([]),doneWhen:X.array(X.string().min(1)).default([]),transitions:X.array(AB0).default([])}),qm=X.object({purpose:X.string().min(1),operatingRules:X.array(X.string().min(1)).default([]),initialState:X.string().min(1),states:X.array(wB0).min(1),finalStates:X.array(X.string().min(1)).min(1),nextPrompts:X.array(X.string().min(1)).default([])}),wz=X.object({title:X.string(),status:Hm.default("active"),audience:Fm.default("admin"),trigger:Dw.optional(),lifecycle:Dw.optional(),once:X.boolean().optional(),starterText:Dw.optional(),description:Dw.optional(),starterPrompt:Dw.optional(),completionMode:Km.default("agent-confirmed")}),wOx=X.object({title:X.string(),status:Hm,audience:Fm,trigger:Dw.optional(),lifecycle:Dw.optional(),once:X.boolean().optional(),starterText:Dw.optional(),description:Dw.optional(),starterPrompt:Dw.optional(),completionMode:Km}),WV9=X.object({title:X.string(),status:QV9,audience:XV9,trigger:sf.optional(),lifecycle:sf.optional(),once:X.boolean().optional(),starterText:sf.optional(),description:sf.optional(),starterPrompt:sf.optional(),completionMode:YV9}),fz=j8.extend({entityType:X.literal("playbook"),metadata:WV9});class zm extends q9{constructor(){super(qm,{title:"Playbook",mappings:[{key:"purpose",label:"Purpose",type:"string"},{key:"operatingRules",label:"Operating Rules",type:"array",itemType:"string"},{key:"initialState",label:"Initial State",type:"string"},{key:"states",label:"States",type:"array",itemType:"object",itemMappings:[{key:"id",label:"ID",type:"string"},{key:"title",label:"Title",type:"string"},{key:"prompt",label:"Prompt",type:"custom",formatter:fB0,parser:DB0},{key:"requiredDetails",label:"Required Details",type:"array",itemType:"string"},{key:"instructions",label:"Instructions",type:"array",itemType:"string"},{key:"doneWhen",label:"Done When",type:"array",itemType:"string"},{key:"transitions",label:"Transitions",type:"array",itemType:"object",itemMappings:[{key:"event",label:"Event",type:"string"},{key:"target",label:"Target",type:"string"},{key:"operatorAction",label:"User Choice",type:"custom",formatter:HV9,parser:FV9},{key:"label",label:"Label",type:"custom",formatter:fB0,parser:DB0},{key:"description",label:"Description",type:"string"},{key:"operatorDescription",label:"Operator Description",type:"custom",formatter:fB0,parser:DB0}]}]},{key:"finalStates",label:"Final States",type:"array",itemType:"string"},{key:"nextPrompts",label:"Next Prompts",type:"array",itemType:"string"}]})}}var j_=new zm;function fB0(x){return typeof x==="string"?x:""}function DB0(x){let B=x.trim();return B.length>0?B:void 0}function HV9(x){return typeof x==="boolean"?String(x):""}function FV9(x){let B=x.trim().toLowerCase();if(B==="true")return!0;if(B==="false")return!1;return}function $B0(x){let B=[],A=new Set,w=new Set;for(let f of x.states){if(A.has(f.id))w.add(f.id);A.add(f.id)}if(!A.has(x.initialState))B.push(`Playbook initial state '${x.initialState}' is not defined.`);for(let f of w)B.push(`Duplicate playbook state id '${f}'.`);for(let f of x.finalStates)if(!A.has(f))B.push(`Playbook final state '${f}' is not defined.`);for(let f of x.states)for(let D of f.transitions)if(!A.has(D.target))B.push(`Playbook transition '${f.id}' -> '${D.target}' targets an undefined state.`);for(let f of KV9(x,A))B.push(`Playbook state '${f}' is unreachable.`);return{valid:B.length===0,errors:B}}function Dz(x){let B=$B0(x);if(!B.valid)throw Error(B.errors.join(`
5771
+ `}var tb9=new Set(["entityType"]),eb9={base:"Notes"},xV9=new Set(["note"]);function BV9(x){let B=["file.name"];for(let A of x)if(!tb9.has(A.name))B.push(A.name);return B}function AV9(x){return x.some((B)=>B.name==="status"&&B.type==="enum")}function eIx(x,B){let A=eb9[x]??tIx(x),w=AV9(B),f=BV9(B),D=[{type:"table",name:`All ${A}`,order:f}];if(w)D.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:f});let Z={filters:{and:[xV9.has(x)?'file.folder == "/"':`file.inFolder("${x}")`]},views:D};return{filename:`${A}.base`,content:Az(Z),hasStatus:w}}function xOx(x){if(x.length===0)return null;let B=x.map((w)=>`file.inFolder("${w}")`),A={filters:{and:[B.length===1?B[0]:{or:B}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return Az(A)}function BOx(x){if(x.length===0)return null;let B=x.map((w)=>`file.inFolder("${w.entityType}")`),A={filters:{and:[B.length===1?B[0]:{or:B},'status != "published"']},views:[{type:"table",name:"Pipeline",groupBy:{property:"status",direction:"ASC"},order:["file.name","file.folder","status"]}]};return Az(A)}var AOx={name:"@brains/obsidian-vault",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Obsidian vault integration \u2014 generates templates from entity schemas",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var ZV9={mkdir:DV9,writeFile:$V9,existsFile:fV9};class xB0 extends D8{deps;constructor(x={},B={}){super("obsidian-vault",AOx,x,e20);this.deps={...ZV9,...B}}async onReady(x){this.logger.info("Auto-syncing Obsidian templates, fileClasses, and bases"),await this.sync(x)}async syncTemplates(x){return this.sync(this.getContext(),x)}async sync(x,B){try{let A=x.entityService.getEntityTypes(),w=B?A.filter((b)=>B.includes(b)):A,f=af(x.dataDir,this.config.baseFolder),D=af(f,"templates"),$=af(f,"fileClasses"),Z=af(f,"bases");this.deps.mkdir(D,{recursive:!0}),this.deps.mkdir($,{recursive:!0}),this.deps.mkdir(Z,{recursive:!0});let Q=[],Y=[],W=[],H=[],F=[],K=[];for(let b of w){let G=x.entities.getEffectiveFrontmatterSchema(b);if(!G){this.logger.debug(`Skipping ${b}: no frontmatter schema`),Y.push(b);continue}let E=sIx(G),_=x.entities.getAdapter(b),L=_?.isSingleton===!0,N=oIx(b,E);if(this.deps.writeFile(af($,`${b}.md`),N),W.push(b),L){F.push(b),this.logger.debug(`Generated fileClass (singleton): ${b}`);continue}let y=_?.getBodyTemplate()??"",c=rIx(b,E,y);this.deps.writeFile(af(D,`${b}.md`),c),Q.push(b);let n=eIx(b,E),R=af(Z,n.filename);if(!this.deps.existsFile(R))this.deps.writeFile(R,n.content),H.push(b),this.logger.debug(`Generated base: ${n.filename}`);if(n.hasStatus)K.push({entityType:b,fields:E});this.logger.debug(`Generated template + fileClass: ${b}`)}let q=xOx(F);if(q){let b=af(Z,"Settings.base");if(!this.deps.existsFile(b))this.deps.writeFile(b,q),H.push("Settings"),this.logger.debug("Generated Settings.base")}let V=BOx(K);if(V){let b=af(Z,"Pipeline.base");if(!this.deps.existsFile(b))this.deps.writeFile(b,V),H.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${Q.length} templates, ${W.length} fileClasses, ${H.length} bases (${Y.length} skipped)`),G1({generated:Q,skipped:Y,fileClasses:W,bases:H})}catch(A){return this.logger.error("Failed to sync",{error:A}),U1(g(A,"Unknown error"))}}}function BB0(x={},B){return new xB0(x,B)}var Hm=X.enum(["draft","active","archived"]),Fm=X.enum(["admin","trusted","public"]),Km=X.enum(["agent-confirmed","manual"]),QV9=X.enum(["draft","active","archived"]),XV9=X.enum(["admin","trusted","public"]),YV9=X.enum(["agent-confirmed","manual"]),Dw=X.preprocess((x)=>typeof x==="string"&&x.trim().length===0?void 0:x,X.string().min(1).optional()),sf=X.preprocess((x)=>typeof x==="string"&&x.trim().length===0?void 0:x,X.string().min(1).optional()),AB0=X.object({event:X.string().min(1),target:X.string().min(1),operatorAction:X.boolean().optional(),label:sf,description:sf,operatorDescription:sf}),wB0=X.object({id:X.string().min(1),title:X.string().min(1),prompt:sf,requiredDetails:X.array(X.string().min(1)).default([]),instructions:X.array(X.string().min(1)).default([]),doneWhen:X.array(X.string().min(1)).default([]),transitions:X.array(AB0).default([])}),qm=X.object({purpose:X.string().min(1),operatingRules:X.array(X.string().min(1)).default([]),initialState:X.string().min(1),states:X.array(wB0).min(1),finalStates:X.array(X.string().min(1)).min(1),nextPrompts:X.array(X.string().min(1)).default([])}),wz=X.object({title:X.string(),status:Hm.default("active"),audience:Fm.default("admin"),trigger:Dw.optional(),lifecycle:Dw.optional(),once:X.boolean().optional(),starterText:Dw.optional(),description:Dw.optional(),starterPrompt:Dw.optional(),completionMode:Km.default("agent-confirmed")}),wOx=X.object({title:X.string(),status:Hm,audience:Fm,trigger:Dw.optional(),lifecycle:Dw.optional(),once:X.boolean().optional(),starterText:Dw.optional(),description:Dw.optional(),starterPrompt:Dw.optional(),completionMode:Km}),WV9=X.object({title:X.string(),status:QV9,audience:XV9,trigger:sf.optional(),lifecycle:sf.optional(),once:X.boolean().optional(),starterText:sf.optional(),description:sf.optional(),starterPrompt:sf.optional(),completionMode:YV9}),fz=j8.extend({entityType:X.literal("playbook"),metadata:WV9});class zm extends q9{constructor(){super(qm,{title:"Playbook",mappings:[{key:"purpose",label:"Purpose",type:"string"},{key:"operatingRules",label:"Operating Rules",type:"array",itemType:"string"},{key:"initialState",label:"Initial State",type:"string"},{key:"states",label:"States",type:"array",itemType:"object",itemMappings:[{key:"id",label:"ID",type:"string"},{key:"title",label:"Title",type:"string"},{key:"prompt",label:"Prompt",type:"custom",formatter:fB0,parser:DB0},{key:"requiredDetails",label:"Required Details",type:"array",itemType:"string"},{key:"instructions",label:"Instructions",type:"array",itemType:"string"},{key:"doneWhen",label:"Done When",type:"array",itemType:"string"},{key:"transitions",label:"Transitions",type:"array",itemType:"object",itemMappings:[{key:"event",label:"Event",type:"string"},{key:"target",label:"Target",type:"string"},{key:"operatorAction",label:"User Choice",type:"custom",formatter:HV9,parser:FV9},{key:"label",label:"Label",type:"custom",formatter:fB0,parser:DB0},{key:"description",label:"Description",type:"string"},{key:"operatorDescription",label:"Operator Description",type:"custom",formatter:fB0,parser:DB0}]}]},{key:"finalStates",label:"Final States",type:"array",itemType:"string"},{key:"nextPrompts",label:"Next Prompts",type:"array",itemType:"string"}]})}}var j_=new zm;function fB0(x){return typeof x==="string"?x:""}function DB0(x){let B=x.trim();return B.length>0?B:void 0}function HV9(x){return typeof x==="boolean"?String(x):""}function FV9(x){let B=x.trim().toLowerCase();if(B==="true")return!0;if(B==="false")return!1;return}function $B0(x){let B=[],A=new Set,w=new Set;for(let f of x.states){if(A.has(f.id))w.add(f.id);A.add(f.id)}if(!A.has(x.initialState))B.push(`Playbook initial state '${x.initialState}' is not defined.`);for(let f of w)B.push(`Duplicate playbook state id '${f}'.`);for(let f of x.finalStates)if(!A.has(f))B.push(`Playbook final state '${f}' is not defined.`);for(let f of x.states)for(let D of f.transitions)if(!A.has(D.target))B.push(`Playbook transition '${f.id}' -> '${D.target}' targets an undefined state.`);for(let f of KV9(x,A))B.push(`Playbook state '${f}' is unreachable.`);return{valid:B.length===0,errors:B}}function Dz(x){let B=$B0(x);if(!B.valid)throw Error(B.errors.join(`
5772
5772
  `))}function KV9(x,B){if(!B.has(x.initialState))return[];let A=new Set,w=[x.initialState];while(w.length>0){let f=w.shift();if(!f||A.has(f))continue;A.add(f);let D=x.states.find(($)=>$.id===f);if(!D)continue;for(let $ of D.transitions)if(B.has($.target)&&!A.has($.target))w.push($.target)}return x.states.map((f)=>f.id).filter((f)=>!A.has(f))}class Vm extends ox{constructor(){super({entityType:"playbook",purpose:"A guided multi-step workflow the assistant runs together with the user.",schema:fz,frontmatterSchema:wz})}createPlaybookContent(x,B){return this.buildMarkdown(j_.format(B),x)}parsePlaybookContent(x){let B=this.parseFrontMatter(x,wz),A=this.extractBody(x).trim(),w=qV9(A)?zV9(A):j_.parse(A);return Dz(w),{frontmatter:wz.parse(B),body:w,bodyMarkdown:A}}fromMarkdown(x){let{frontmatter:B}=this.parsePlaybookContent(x);return{content:x,entityType:"playbook",metadata:{title:B.title,status:B.status,audience:B.audience,...B.trigger?{trigger:B.trigger}:{},...B.lifecycle?{lifecycle:B.lifecycle}:{},...B.once!==void 0?{once:B.once}:{},...B.starterText?{starterText:B.starterText}:{},...B.description?{description:B.description}:{},...B.starterPrompt?{starterPrompt:B.starterPrompt}:{},completionMode:B.completionMode}}}}var mY=new Vm;function qV9(x){return/^##\s+Steps\s*$/im.test(x)}function zV9(x){let B=bV9(ZB0(x,"Steps"));if(B.length===0)throw Error("Playbook must declare at least one step.");let A=B.map((w,f)=>{let D=f===B.length-1;if(!D&&w.doneWhen.length===0&&w.choices.length===0&&!w.skip)throw Error(`Playbook step '${w.title}' must declare Done when, Choices, or Skip.`);return{id:w.id,title:w.title,...w.prompt?{prompt:w.prompt}:{},requiredDetails:w.requiredDetails,instructions:w.instructions,doneWhen:w.doneWhen,transitions:[...w.doneWhen.length>0&&!D?[{event:"NEXT",target:B[f+1]?.id??w.id}]:[],...w.choices.map(($,Z)=>({event:`CHOICE_${Z+1}`,target:Gx($.target),operatorAction:!0,label:$.label})),...w.skip?[{event:"SKIP",target:Gx(w.skip.target),operatorAction:!0,label:w.skip.label}]:[]]}});return{purpose:VV9(x,"Purpose"),operatingRules:fOx(x,"Operating Rules"),initialState:B[0]?.id??"",states:A,finalStates:[B.at(-1)?.id??""],nextPrompts:fOx(x,"Next Prompts")}}function bV9(x){let B=[],A;for(let w of x.split(/\r?\n/)){let f=/^###\s+(.+?)\s*$/.exec(w);if(f){A={title:f[1]??"",content:[]},B.push(A);continue}A?.content.push(w)}return B.map((w)=>{let f=w.content.join(`
5773
5773
  `);return{title:w.title,id:Gx(w.title),...DOx(f,"Say")?{prompt:DOx(f,"Say")}:{},requiredDetails:bm(f,"Required details"),instructions:bm(f,"To do"),doneWhen:bm(f,"Done when"),choices:UV9(f,"Choices"),...$Ox(f)?{skip:$Ox(f)}:{}}})}function ZB0(x,B){let A=x.split(/\r?\n/),w=A.findIndex((D)=>D.trim().toLowerCase()===`## ${B.toLowerCase()}`);if(w===-1)return"";let f=[];for(let D of A.slice(w+1)){if(/^##\s+/.test(D))break;f.push(D)}return f.join(`
5774
5774
  `).trim()}function VV9(x,B){return ZB0(x,B).split(/\r?\n/).map((A)=>A.trim()).filter((A)=>A.length>0&&!A.startsWith("#")).join(`
5775
5775
  `).trim()}function fOx(x,B){return ZOx(ZB0(x,B))}function DOx(x,B){return new RegExp(`^${EV9(B)}:\\s*(.+?)\\s*$`,"im").exec(x)?.[1]?.trim()}function bm(x,B){let A=x.split(/\r?\n/),w=A.findIndex((D)=>D.trim().toLowerCase()===`${B.toLowerCase()}:`);if(w===-1)return[];let f=[];for(let D of A.slice(w+1)){let $=D.trim();if($.length===0)continue;if(/^[A-Za-z][A-Za-z ]+:/.test($)||/^#{1,6}\s+/.test($))break;f.push(D)}return ZOx(f.join(`
5776
- `))}function UV9(x,B){return bm(x,B).map(GV9)}function GV9(x){let B=/^(.+?)\s*(?:\u2192|->)\s*(.+)$/.exec(x);if(!B)throw Error(`Invalid playbook choice '${x}'. Expected "Label \u2192 Step".`);return{label:B[1]?.trim()??"",target:B[2]?.trim()??""}}function $Ox(x){let B=/^Skip:\s*(.+?)\s*(?:\u2192|->)\s*(.+?)\s*$/im.exec(x);if(!B)return;return{label:B[1]?.trim()??"",target:B[2]?.trim()??""}}function ZOx(x){return x.split(/\r?\n/).map((B)=>/^-\s+(.+?)\s*$/.exec(B)?.[1]?.trim()).filter((B)=>Boolean(B))}function EV9(x){return x.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Um=X.object({}).catchall(X.unknown()).transform(()=>({}));var Gm={name:"@brains/playbooks",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Runtime orchestration for chat-native playbook runs",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/runtime-state":"workspace:*","@brains/utils":"workspace:*",xstate:"^5.32.1"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var _V9="playbook";class QB0 extends g8{entityType=_V9;schema=fz;adapter=mY;constructor(x={}){super("playbook",Gm,x,Um)}getEntityTypeConfig(){return{projectionSource:!1,projectionSourceRole:"excluded"}}async getInstructions(){return"Playbook entities describe durable, editable guided workflows for the agent. Use them as operating guidance when a playbook run is active; do not treat them as content to publish unless the user explicitly asks. To inspect a playbook's lifecycle, run status, current state, or valid events, call playbook_status directly; do not use system_search as a substitute."}}function XB0(x={}){return new QB0(x)}function jm(x,B){return x.length===B.length&&x.every((A,w)=>A===B[w])}function YB0(x,B){return B==="NEXT"&&x.doneWhen.length>0}function _m(x,B){return B.gateVerdicts.some((A)=>A.stateId===x.id&&jm(A.goal,x.doneWhen)&&A.met)}function PV9(x,B,A){return Em.createMachine({id:x,initial:B.initialState,states:Object.fromEntries(B.states.map((w)=>{let f=B.finalStates.includes(w.id);return[w.id,{...f?{type:"final"}:{},...f?{}:{on:Object.fromEntries(w.transitions.map((D)=>[D.event,{target:D.target,...YB0(w,D.event)?{guard:()=>_m(w,A)}:{}}]))}}]}))})}function WB0(x,B){let A=PV9(B.playbookId,x,B);return Em.createActor(A,{snapshot:A.resolveState({value:B.currentState})})}function JV9(x,B,A){let w=WB0(B,x);w.start();let f=w.getSnapshot().can({type:A});return w.stop(),f}function $z(x,B,A){return A.transitions.filter((w)=>JV9(x,B,w.event))}function __(x,B,A){let w=new Set($z(x,B,A).map((f)=>`${f.event}\x00${f.target}`));return A.transitions.filter((f)=>!w.has(`${f.event}\x00${f.target}`))}function QOx(x,B){return x.evidence.filter((A)=>!A.stateId||A.stateId===B)}function CY(x,B){return x.states.find((A)=>A.id===B)}function cY(x){let B=x.operatorDescription??x.description??x.label;return B?`- ${x.event} -> ${x.target}: ${B}`:`- ${x.event} -> ${x.target}`}function XOx(x,B){if(B.doneWhen.length===0)return"- no gated Done When conditions";let A=x.gateVerdicts.find((w)=>w.stateId===B.id&&jm(w.goal,B.doneWhen));if(!A)return`- Not yet met: ${B.doneWhen.join("; ")}`;return A.met?`- Met: ${A.reason}`:`- Not yet met: ${A.reason}`}function YOx(x,B,A){let w=$z(x,B,A),f=w.filter((Q)=>Q.operatorAction!==!0),D=w.filter((Q)=>Q.operatorAction===!0),$=__(x,B,A),Z=x.gateVerdicts.find((Q)=>Q.stateId===A.id&&jm(Q.goal,A.doneWhen));return[`Current state: ${A.id} (${A.title})`,"Instructions:",...A.instructions.map((Q)=>`- ${Q}`),"Done When:",...A.doneWhen.length>0?A.doneWhen.map((Q)=>`- ${Q}`):["- none"],"Goal status:",Z?`- ${Z.met?"Met":"Not yet met"}: ${Z.reason}`:"- Not checked yet.","Current-state information rules:","- If this state asks the operator for information, ask the operator for the missing current-run information.","- If the current operator message partially answers the state's prompt, do not repeat the original prompt; ask only for the next missing detail required by the state instructions.","- Do not answer the state's operator-facing prompt from memory, existing durable records, profile data, search, or retrieval tools.","- Setup facts must come from current-run evidence or current operator input, not ambient records.","Event selection rules:","- Blocked events are not valid events; do not call playbook_manage action=send-event with a blocked event.","- For gated durable states, operator-provided details are not enough to send NEXT; first complete the required system_create/system_update/system_delete action or use existing current-run evidence that the Done When condition has already been met.","- If the operator explicitly says they have not chosen, selected, asked for, or used one of the available actions, do not send any event.",'- Operator actions and choices are not generic continuation events; even if only one operator action is available, generic continuation like "yes", "next", or "continue" is not a valid selection.',"- If multiple events are available, ask the operator to pick one labeled action.","- A Skip-style operator action is never a default continuation; send it only when the operator positively selects or asks to skip.","Valid continuation events:",...f.length>0?f.map((Q)=>cY(Q)):["- none"],"Available operator actions:",...D.length>0?D.map((Q)=>cY(Q)):["- none"],"Blocked events:",...$.length>0?$.map((Q)=>cY(Q)):["- none"]].join(`
5776
+ `))}function UV9(x,B){return bm(x,B).map(GV9)}function GV9(x){let B=/^(.+?)\s*(?:\u2192|->)\s*(.+)$/.exec(x);if(!B)throw Error(`Invalid playbook choice '${x}'. Expected "Label \u2192 Step".`);return{label:B[1]?.trim()??"",target:B[2]?.trim()??""}}function $Ox(x){let B=/^Skip:\s*(.+?)\s*(?:\u2192|->)\s*(.+?)\s*$/im.exec(x);if(!B)return;return{label:B[1]?.trim()??"",target:B[2]?.trim()??""}}function ZOx(x){return x.split(/\r?\n/).map((B)=>/^-\s+(.+?)\s*$/.exec(B)?.[1]?.trim()).filter((B)=>Boolean(B))}function EV9(x){return x.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Um=X.object({}).catchall(X.unknown()).transform(()=>({}));var Gm={name:"@brains/playbooks",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Runtime orchestration for chat-native playbook runs",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/runtime-state":"workspace:*","@brains/utils":"workspace:*",xstate:"^5.32.1"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var _V9="playbook";class QB0 extends g8{entityType=_V9;schema=fz;adapter=mY;constructor(x={}){super("playbook",Gm,x,Um)}getEntityTypeConfig(){return{projectionSource:!1,projectionSourceRole:"excluded"}}async getInstructions(){return"Playbook entities describe durable, editable guided workflows for the agent. Use them as operating guidance when a playbook run is active; do not treat them as content to publish unless the user explicitly asks. To inspect a playbook's lifecycle, run status, current state, or valid events, call playbook_status directly; do not use system_search as a substitute."}}function XB0(x={}){return new QB0(x)}function jm(x,B){return x.length===B.length&&x.every((A,w)=>A===B[w])}function YB0(x,B){return B==="NEXT"&&x.doneWhen.length>0}function _m(x,B){return B.gateVerdicts.some((A)=>A.stateId===x.id&&jm(A.goal,x.doneWhen)&&A.met)}function PV9(x,B,A){return Em.createMachine({id:x,initial:B.initialState,states:Object.fromEntries(B.states.map((w)=>{let f=B.finalStates.includes(w.id);return[w.id,{...f?{type:"final"}:{},...f?{}:{on:Object.fromEntries(w.transitions.map((D)=>[D.event,{target:D.target,...YB0(w,D.event)?{guard:()=>_m(w,A)}:{}}]))}}]}))})}function WB0(x,B){let A=PV9(B.playbookId,x,B);return Em.createActor(A,{snapshot:A.resolveState({value:B.currentState})})}function JV9(x,B,A){let w=WB0(B,x);w.start();let f=w.getSnapshot().can({type:A});return w.stop(),f}function $z(x,B,A){return A.transitions.filter((w)=>JV9(x,B,w.event))}function __(x,B,A){let w=new Set($z(x,B,A).map((f)=>`${f.event}\x00${f.target}`));return A.transitions.filter((f)=>!w.has(`${f.event}\x00${f.target}`))}function QOx(x,B){return x.evidence.filter((A)=>!A.stateId||A.stateId===B)}function CY(x,B){return x.states.find((A)=>A.id===B)}function cY(x){let B=x.operatorDescription??x.description??x.label;return B?`- ${x.event} -> ${x.target}: ${B}`:`- ${x.event} -> ${x.target}`}function XOx(x,B){if(B.doneWhen.length===0)return"- no gated Done When conditions";let A=x.gateVerdicts.find((w)=>w.stateId===B.id&&jm(w.goal,B.doneWhen));if(!A)return`- Not yet met: ${B.doneWhen.join("; ")}`;return A.met?`- Met: ${A.reason}`:`- Not yet met: ${A.reason}`}function YOx(x,B,A){let w=$z(x,B,A),f=w.filter((Q)=>Q.operatorAction!==!0),D=w.filter((Q)=>Q.operatorAction===!0),$=__(x,B,A),Z=x.gateVerdicts.find((Q)=>Q.stateId===A.id&&jm(Q.goal,A.doneWhen));return[`Current state: ${A.id} (${A.title})`,"Instructions:",...A.instructions.map((Q)=>`- ${Q}`),"Done When:",...A.doneWhen.length>0?A.doneWhen.map((Q)=>`- ${Q}`):["- none"],"Goal status:",Z?`- ${Z.met?"Met":"Not yet met"}: ${Z.reason}`:"- Not checked yet.","Current-state information rules:","- If this state asks the operator for information, ask the operator for the missing current-run information.","- If the current operator message partially answers the state's prompt, do not repeat the original prompt; ask only for the next missing detail required by the state instructions.","- Do not answer the state's operator-facing prompt from memory, existing durable records, profile data, search, or retrieval tools.","- Setup facts must come from current-run evidence or current operator input, not ambient records.","Event selection rules:","- Blocked events are not valid events; do not call playbook_manage action=send-event with a blocked event.","- For gated durable states, operator-provided details are not enough to send NEXT; first complete the required system_create/system_update/system_delete action or use existing current-run evidence that the Done When condition has already been met.","- If the operator explicitly says they have not chosen, selected, asked for, or used one of the available actions, do not send any event.",'- Operator actions and choices are not generic continuation events; even if only one operator action is available, generic continuation like "yes", "next", or "continue" is not a valid selection.',"- If multiple events are available, ask the operator to pick one labeled action.","- A Skip-style operator action is never a default continuation; send it only when the operator positively selects or asks to skip.","Valid continuation events:",...f.length>0?f.map((Q)=>cY(Q)):["- none"],"Available operator actions:",...D.length>0?D.map((Q)=>cY(Q)):["- none"],"Blocked events:",...$.length>0?$.map((Q)=>cY(Q)):["- none"]].join(`
5777
5777
  `)}function WOx(x){let{run:B,body:A,state:w,playbookTitle:f}=x,D=$z(B,A,w),$=D.filter((b)=>b.operatorAction!==!0),Z=D.filter((b)=>b.operatorAction===!0),Q=__(B,A,w),Y=$.map((b)=>cY(b)).join(`
5778
5778
  `),W=Z.map((b)=>cY(b)).join(`
5779
5779
  `),H=Q.map((b)=>cY(b)).join(`
@@ -6021,7 +6021,7 @@ Use the project request as the primary source of truth. If retrieved knowledge c
6021
6021
  font: 10px/1.45 var(--font-mono, "JetBrains Mono", ui-monospace, monospace);
6022
6022
  }
6023
6023
  .printable-footer a { color: inherit; text-decoration: none; overflow-wrap: anywhere; }
6024
- `}},void 0,!1,void 0,this),T5("section",{className:"project-shell",children:[T5("header",{className:"project-hero",children:[T5("div",{className:"project-index",children:[B.brandLabel&&T5("p",{className:"printable-kicker",children:B.brandLabel},void 0,!1,void 0,this),B.year&&T5("span",{className:"project-year",children:B.year},void 0,!1,void 0,this)]},void 0,!0,void 0,this),T5("div",{className:"project-title-panel",children:[T5("span",{className:"printable-kind",children:"Case study dossier"},void 0,!1,void 0,this),T5("h1",{className:"printable-title",children:B.title},void 0,!1,void 0,this),B.description&&T5("p",{className:"printable-description",children:B.description},void 0,!1,void 0,this),T5("div",{className:"printable-meta",children:[B.year&&T5("span",{children:B.year},void 0,!1,void 0,this),B.url&&T5("span",{children:B.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),B.coverImageUrl&&T5("img",{className:"printable-cover",src:B.coverImageUrl,alt:""},void 0,!1,void 0,this),T5(cB,{markdown:B.body,className:"printable-body"},void 0,!1,void 0,this),(Boolean(B.canonicalUrl)||Boolean(B.url)||Boolean(B.brandLabel))&&T5("footer",{className:"printable-footer",children:[T5("span",{children:B.brandLabel??"Project printable"},void 0,!1,void 0,this),B.canonicalUrl||B.url?T5("a",{href:B.canonicalUrl??B.url,children:B.canonicalUrl??B.url},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var mOx=Rm({sourceEntityType:"project",attachmentType:hm,template:yOx,themeMode:"light",buildContent:async(x,B)=>{let{frontmatter:A,content:w}=I1(x.content),f=Q1.parse(A),D=await B.resolveImageDataUrl(f.coverImageId);return{title:f.title,body:w,...f.description?{description:f.description}:{},year:f.year,...f.publishedAt?{publishedAt:f.publishedAt}:{},...f.url?{url:f.url,canonicalUrl:f.url}:{},...D?{coverImageUrl:D}:{},...B.brandLabel?{brandLabel:B.brandLabel}:{}}},pageTitle:(x)=>x.title,slug:(x)=>EZ(x.metadata.slug,x.metadata.title)});import{jsxDEV as HU9}from"preact/jsx-dev-runtime";var mm="og-image",YU9="portfolio:og-image",COx=X.object({title:X.string().min(1),description:X.string().optional(),year:X.number().optional(),brandLabel:X.string().optional(),coverImageUrl:X.string().optional()}),cOx={name:YU9,pluginId:"portfolio",schema:COx,renderers:{image:WU9}};function WU9(x){let B=COx.parse(x);return HU9(ym,{brandLabel:B.brandLabel??B.title,eyebrow:"Project",title:B.title,subtitle:B.description,tag:B.year},void 0,!1,void 0,this)}var gOx=Cm({sourceEntityType:"project",attachmentType:mm,template:cOx,themeMode:"light",buildContent:async(x,B)=>{let{frontmatter:A}=I1(x.content),w=Q1.parse(A),f=await B.resolveImageDataUrl(w.coverImageId);return{title:w.title,...w.description?{description:w.description}:{},year:w.year,...f?{coverImageUrl:f}:{},...B.brandLabel?{brandLabel:B.brandLabel}:{}}},pageTitle:(x)=>x.title,slug:(x)=>EZ(x.metadata.slug,x.metadata.title)});var TOx={name:"@brains/portfolio",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Portfolio showcase for projects and case studies",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var cm=Nm,KU9=X.object({projects:X.array(cm),pageTitle:X.string().nullable().default(null),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null)}),qU9=X.object({prompt:X.string(),year:X.number()});function zU9(x,B){for(let A of[x,B]){let w=A?.match(/\b(19\d{2}|20\d{2})\b/);if(w?.[1])return Number(w[1])}return null}class NB0 extends g8{entityType="project";schema=GZ;adapter=TY;unregisterAtprotoProjection;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(x={}){super("portfolio",TOx,x,PB0)}getEntityTypeConfig(){return{projectionSourceRole:"secondary"}}async interceptCreate(x,B,A){if(!x.prompt||x.content)return{kind:"continue",input:x};let w=zU9(x.title,x.prompt);if(!w)return{kind:"continue",input:x};return{kind:"handled",result:{success:!0,data:{status:"generating",jobId:await A.jobs.enqueue({type:kOx.generation,data:{prompt:x.prompt,...x.title?{title:x.title}:{},year:w},toolContext:B,options:{source:this.id,metadata:{operationType:"content_operations"}}})}}}}createGenerationHandler(x){return new Im(this.logger.child("ProjectGenerationJobHandler"),x)}getTemplates(){return{"project-list":mx({name:"project-list",description:"Portfolio project list page template",schema:KU9,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:JB0}}),"project-detail":mx({name:"project-detail",description:"Individual project case study template",schema:X.object({project:cm,prevProject:cm.nullable(),nextProject:cm.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:LB0}}),generation:kB0}}getDataSources(){return[new Om(this.logger.child("ProjectDataSource"))]}async onRegister(x){this.registerEvalHandlers(x),this.unregisterPrintableAttachmentProvider=x.attachments.register("project",hm,mOx(x)),this.unregisterOgImageAttachmentProvider=x.attachments.register("project",mm,gOx(x)),this.deferPublishRegistration(x),this.subscribeToPublishExecute(x),this.unregisterAtprotoProjection=R4.getInstance().register(vB0())}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}registerEvalHandlers(x){x.eval.registerHandler("generateProject",async(B)=>{let A=qU9.parse(B),w=i3(await y2(x.entityService));return x.ai.generate({prompt:MB0(A),templateName:"portfolio:generation",representedIdentity:"anchor",...w&&{styleGuide:{voice:w}}})})}deferPublishRegistration(x){let B={name:"internal",publish:async()=>({id:"internal"})};x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.messaging.send({type:d5.register,payload:{entityType:"project",provider:B,config:{executionMode:"provider"}}}),{success:!0}})}subscribeToPublishExecute(x){x.messaging.subscribe(d5.execute,async(B)=>{let{entityType:A,entityId:w}=B.payload;if(A!=="project")return{success:!0};try{let f=await x.entityService.getEntity({entityType:"project",id:w});if(!f)return await x.messaging.send({type:d5.reportFailure,payload:{entityType:A,entityId:w,error:`Project not found: ${w}`}}),{success:!0};if(f.metadata.status==="published")return{success:!0};let D=G9(f.content,Q1),$=new Date().toISOString(),Z=O3(D.content,{...D.metadata,status:"published",publishedAt:$});await x.entityService.updateEntity({entity:{...f,content:Z,metadata:{...f.metadata,status:"published",publishedAt:$}}}),await x.messaging.send({type:d5.reportSuccess,payload:{entityType:A,entityId:w,publishedAt:$}})}catch(f){await x.messaging.send({type:d5.reportFailure,payload:{entityType:A,entityId:w,error:g(f)}})}return{success:!0}})}}function IB0(x={}){return new NB0(x)}var pOx=X.enum(["available","early access","coming soon","planned"]),uOx=X.object({title:X.string(),description:X.string()}),c2=X.object({name:X.string(),availability:pOx,order:X.number(),ogImageId:X.string().optional()}),gm=X.object({tagline:X.string(),promise:X.string(),role:X.string(),purpose:X.string(),audience:X.string(),values:X.array(X.string()).min(1),features:X.array(uOx).min(1).max(6),story:X.string()}),bU9=c2.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),Xz=j8.extend({entityType:X.literal("product"),metadata:bU9}),Tm=Xz.extend({frontmatter:c2,body:gm,labels:X.record(X.string(),X.string()),ogImageUrl:X.string().optional()}),VU9=Tm.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional(),ogImageUrl:X.string().optional()});class Yz extends q9{constructor(){super(gm,{title:"Product",mappings:[{key:"tagline",label:"Tagline",type:"string"},{key:"promise",label:"Promise",type:"string"},{key:"role",label:"Role",type:"string"},{key:"purpose",label:"Purpose",type:"string"},{key:"audience",label:"Audience",type:"string"},{key:"values",label:"Values",type:"array",itemType:"string"},{key:"features",label:"Capabilities",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"story",label:"Story",type:"string"}]})}}class OB0 extends ox{constructor(){super({entityType:"product",purpose:"A product entry in the portfolio.",schema:Xz,frontmatterSchema:c2,bodyFormatter:new Yz})}toMarkdown(x){let B=this.extractBody(x.content);try{let A=this.parseFrontMatter(x.content,c2);return this.buildMarkdown(B,A)}catch{return B}}fromMarkdown(x){let B=this.parseFrontMatter(x,c2),A=Gx(B.name);return{content:x,entityType:"product",metadata:{name:B.name,slug:A,availability:B.availability,order:B.order}}}}var pm=new OB0;var SOx=X.object({title:X.string(),description:X.string()}),iOx=X.object({title:X.string(),description:X.string()}),UU9=X.object({title:X.string(),description:X.string()}),lOx=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),rf=X.object({headline:X.string(),tagline:X.string()}),GU9=X.object({title:X.string(),description:X.string()}),um=X.object({vision:X.string(),pillars:X.array(SOx).min(1).max(6),approach:X.array(GU9).min(1).max(6),productsIntro:X.string(),technologies:X.array(UU9).min(1).max(6),benefits:X.array(iOx).min(1).max(6),cta:lOx}),nOx=rf.pick({headline:!0}).extend({slug:X.string()}),Wz=j8.extend({entityType:X.literal("products-overview"),metadata:nOx}),hB0=Wz.extend({frontmatter:rf,body:um,labels:X.record(X.string(),X.string())});class Hz extends q9{constructor(){super(um,{title:"Products Overview",mappings:[{key:"vision",label:"Vision",type:"string"},{key:"pillars",label:"Core Principles",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"approach",label:"How It Works",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"productsIntro",label:"Products",type:"string"},{key:"technologies",label:"Built With",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"benefits",label:"Why Brains",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"cta",label:"Ready to Build",type:"object",children:[{key:"heading",label:"Heading",type:"string"},{key:"buttonText",label:"Button Text",type:"string"},{key:"link",label:"Link",type:"string"}]}]})}}class RB0 extends ox{constructor(){super({entityType:"products-overview",purpose:"A high-level overview of the product portfolio.",schema:Wz,frontmatterSchema:rf,bodyFormatter:new Hz})}toMarkdown(x){let B=this.extractBody(x.content);try{let A=this.parseFrontMatter(x.content,rf);return this.buildMarkdown(B,A)}catch{return B}}fromMarkdown(x){let B=this.parseFrontMatter(x,rf),A=Gx(B.headline);return{content:x,entityType:"products-overview",metadata:{headline:B.headline,slug:A}}}}var yB0=new RB0;var EU9=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function dOx(x,B){let A=G9(x.content,c2),w=B.parse(A.content),f=B.getLabels();return Tm.parse({...x,frontmatter:A.metadata,body:w,labels:f})}function aOx(x,B){let A=G9(x.content,rf),w=B.parse(A.content),f=B.getLabels();return hB0.parse({...x,frontmatter:A.metadata,body:w,labels:f})}class Sm{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new Hz;productFormatter=new Yz;constructor(x){this.logger=x,this.logger.debug("ProductsDataSource initialized")}async fetch(x,B,A){let w=EU9.parse(x),f=A.entityService;if(w.entityType==="products-overview"){let Y=(await f.listEntities({entityType:"products-overview",options:{limit:1}}))[0];if(!Y)throw Error("Products overview entity not found");let W=aOx(Y,this.overviewFormatter);return B.parse(W)}if(w.query?.id){let Y=(await f.listEntities({entityType:"product",options:{filter:{metadata:{slug:w.query.id}},limit:1}}))[0];if(!Y)throw Error(`Product not found: ${w.query.id}`);return B.parse({product:dOx(Y,this.productFormatter)})}let[D,$]=await Promise.all([f.listEntities({entityType:"products-overview",options:{limit:1}}),f.listEntities({entityType:"product",options:{sortFields:[{field:"order",direction:"asc"}]}})]),Z=D[0];if(!Z)throw Error("Products overview entity not found");return B.parse({overview:aOx(Z,this.overviewFormatter),products:$.map((Q)=>dOx(Q,this.productFormatter))})}}import{jsxDEV as P0,Fragment as PU9}from"preact/jsx-dev-runtime";var sOx=({overview:x,products:B})=>{let{frontmatter:A,body:w,labels:f}=x;return P0(PU9,{children:[P0(z9,{title:A.headline,description:A.tagline},void 0,!1,void 0,this),P0("header",{className:"relative w-full min-h-[80vh] flex items-end px-6 md:px-12 bg-brand-dark overflow-hidden",children:[P0("style",{children:`
6024
+ `}},void 0,!1,void 0,this),T5("section",{className:"project-shell",children:[T5("header",{className:"project-hero",children:[T5("div",{className:"project-index",children:[B.brandLabel&&T5("p",{className:"printable-kicker",children:B.brandLabel},void 0,!1,void 0,this),B.year&&T5("span",{className:"project-year",children:B.year},void 0,!1,void 0,this)]},void 0,!0,void 0,this),T5("div",{className:"project-title-panel",children:[T5("span",{className:"printable-kind",children:"Case study dossier"},void 0,!1,void 0,this),T5("h1",{className:"printable-title",children:B.title},void 0,!1,void 0,this),B.description&&T5("p",{className:"printable-description",children:B.description},void 0,!1,void 0,this),T5("div",{className:"printable-meta",children:[B.year&&T5("span",{children:B.year},void 0,!1,void 0,this),B.url&&T5("span",{children:B.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),B.coverImageUrl&&T5("img",{className:"printable-cover",src:B.coverImageUrl,alt:""},void 0,!1,void 0,this),T5(cB,{markdown:B.body,className:"printable-body"},void 0,!1,void 0,this),(Boolean(B.canonicalUrl)||Boolean(B.url)||Boolean(B.brandLabel))&&T5("footer",{className:"printable-footer",children:[T5("span",{children:B.brandLabel??"Project printable"},void 0,!1,void 0,this),B.canonicalUrl||B.url?T5("a",{href:B.canonicalUrl??B.url,children:B.canonicalUrl??B.url},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var mOx=Rm({sourceEntityType:"project",attachmentType:hm,template:yOx,themeMode:"light",buildContent:async(x,B)=>{let{frontmatter:A,content:w}=I1(x.content),f=Q1.parse(A),D=await B.resolveImageDataUrl(f.coverImageId);return{title:f.title,body:w,...f.description?{description:f.description}:{},year:f.year,...f.publishedAt?{publishedAt:f.publishedAt}:{},...f.url?{url:f.url,canonicalUrl:f.url}:{},...D?{coverImageUrl:D}:{},...B.brandLabel?{brandLabel:B.brandLabel}:{}}},pageTitle:(x)=>x.title,slug:(x)=>EZ(x.metadata.slug,x.metadata.title)});import{jsxDEV as HU9}from"preact/jsx-dev-runtime";var mm="og-image",YU9="portfolio:og-image",COx=X.object({title:X.string().min(1),description:X.string().optional(),year:X.number().optional(),brandLabel:X.string().optional(),coverImageUrl:X.string().optional()}),cOx={name:YU9,pluginId:"portfolio",schema:COx,renderers:{image:WU9}};function WU9(x){let B=COx.parse(x);return HU9(ym,{brandLabel:B.brandLabel??B.title,eyebrow:"Project",title:B.title,subtitle:B.description,tag:B.year},void 0,!1,void 0,this)}var gOx=Cm({sourceEntityType:"project",attachmentType:mm,template:cOx,themeMode:"light",buildContent:async(x,B)=>{let{frontmatter:A}=I1(x.content),w=Q1.parse(A),f=await B.resolveImageDataUrl(w.coverImageId);return{title:w.title,...w.description?{description:w.description}:{},year:w.year,...f?{coverImageUrl:f}:{},...B.brandLabel?{brandLabel:B.brandLabel}:{}}},pageTitle:(x)=>x.title,slug:(x)=>EZ(x.metadata.slug,x.metadata.title)});var TOx={name:"@brains/portfolio",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Portfolio showcase for projects and case studies",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var cm=Nm,KU9=X.object({projects:X.array(cm),pageTitle:X.string().nullable().default(null),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null)}),qU9=X.object({prompt:X.string(),year:X.number()});function zU9(x,B){for(let A of[x,B]){let w=A?.match(/\b(19\d{2}|20\d{2})\b/);if(w?.[1])return Number(w[1])}return null}class NB0 extends g8{entityType="project";schema=GZ;adapter=TY;unregisterAtprotoProjection;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(x={}){super("portfolio",TOx,x,PB0)}getEntityTypeConfig(){return{projectionSourceRole:"secondary"}}async interceptCreate(x,B,A){if(!x.prompt||x.content)return{kind:"continue",input:x};let w=zU9(x.title,x.prompt);if(!w)return{kind:"continue",input:x};return{kind:"handled",result:{success:!0,data:{status:"generating",jobId:await A.jobs.enqueue({type:kOx.generation,data:{prompt:x.prompt,...x.title?{title:x.title}:{},year:w},toolContext:B,options:{source:this.id,metadata:{operationType:"content_operations"}}})}}}}createGenerationHandler(x){return new Im(this.logger.child("ProjectGenerationJobHandler"),x)}getTemplates(){return{"project-list":mx({name:"project-list",description:"Portfolio project list page template",schema:KU9,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:JB0}}),"project-detail":mx({name:"project-detail",description:"Individual project case study template",schema:X.object({project:cm,prevProject:cm.nullable(),nextProject:cm.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:LB0}}),generation:kB0}}getDataSources(){return[new Om(this.logger.child("ProjectDataSource"))]}async onRegister(x){this.registerEvalHandlers(x),this.unregisterPrintableAttachmentProvider=x.attachments.register("project",hm,mOx(x)),this.unregisterOgImageAttachmentProvider=x.attachments.register("project",mm,gOx(x)),this.deferPublishRegistration(x),this.subscribeToPublishExecute(x),this.unregisterAtprotoProjection=R4.getInstance().register(vB0())}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}registerEvalHandlers(x){x.eval.registerHandler("generateProject",async(B)=>{let A=qU9.parse(B),w=i3(await y2(x.entityService));return x.ai.generate({prompt:MB0(A),templateName:"portfolio:generation",representedIdentity:"anchor",...w&&{styleGuide:{voice:w}}})})}deferPublishRegistration(x){let B={name:"internal",publish:async()=>({id:"internal"})};x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.messaging.send({type:d5.register,payload:{entityType:"project",provider:B,config:{executionMode:"provider"}}}),{success:!0}})}subscribeToPublishExecute(x){x.messaging.subscribe(d5.execute,async(B)=>{let{entityType:A,entityId:w}=B.payload;if(A!=="project")return{success:!0};try{let f=await x.entityService.getEntity({entityType:"project",id:w});if(!f)return await x.messaging.send({type:d5.reportFailure,payload:{entityType:A,entityId:w,error:`Project not found: ${w}`}}),{success:!0};if(f.metadata.status==="published")return{success:!0};let D=G9(f.content,Q1),$=new Date().toISOString(),Z=O3(D.content,{...D.metadata,status:"published",publishedAt:$});await x.entityService.updateEntity({entity:{...f,content:Z,metadata:{...f.metadata,status:"published",publishedAt:$}}}),await x.messaging.send({type:d5.reportSuccess,payload:{entityType:A,entityId:w,publishedAt:$}})}catch(f){await x.messaging.send({type:d5.reportFailure,payload:{entityType:A,entityId:w,error:g(f)}})}return{success:!0}})}}function IB0(x={}){return new NB0(x)}var pOx=X.enum(["available","early access","coming soon","planned"]),uOx=X.object({title:X.string(),description:X.string()}),c2=X.object({name:X.string(),availability:pOx,order:X.number(),ogImageId:X.string().optional()}),gm=X.object({tagline:X.string(),promise:X.string(),role:X.string(),purpose:X.string(),audience:X.string(),values:X.array(X.string()).min(1),features:X.array(uOx).min(1).max(6),story:X.string()}),bU9=c2.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),Xz=j8.extend({entityType:X.literal("product"),metadata:bU9}),Tm=Xz.extend({frontmatter:c2,body:gm,labels:X.record(X.string(),X.string()),ogImageUrl:X.string().optional()}),VU9=Tm.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional(),ogImageUrl:X.string().optional()});class Yz extends q9{constructor(){super(gm,{title:"Product",mappings:[{key:"tagline",label:"Tagline",type:"string"},{key:"promise",label:"Promise",type:"string"},{key:"role",label:"Role",type:"string"},{key:"purpose",label:"Purpose",type:"string"},{key:"audience",label:"Audience",type:"string"},{key:"values",label:"Values",type:"array",itemType:"string"},{key:"features",label:"Capabilities",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"story",label:"Story",type:"string"}]})}}class OB0 extends ox{constructor(){super({entityType:"product",purpose:"A product entry in the portfolio.",schema:Xz,frontmatterSchema:c2,bodyFormatter:new Yz})}toMarkdown(x){let B=this.extractBody(x.content);try{let A=this.parseFrontMatter(x.content,c2);return this.buildMarkdown(B,A)}catch{return B}}fromMarkdown(x){let B=this.parseFrontMatter(x,c2),A=Gx(B.name);return{content:x,entityType:"product",metadata:{name:B.name,slug:A,availability:B.availability,order:B.order}}}}var pm=new OB0;var SOx=X.object({title:X.string(),description:X.string()}),iOx=X.object({title:X.string(),description:X.string()}),UU9=X.object({title:X.string(),description:X.string()}),lOx=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),rf=X.object({headline:X.string(),tagline:X.string()}),GU9=X.object({title:X.string(),description:X.string()}),um=X.object({vision:X.string(),pillars:X.array(SOx).min(1).max(6),approach:X.array(GU9).min(1).max(6),productsIntro:X.string(),technologies:X.array(UU9).min(1).max(6),benefits:X.array(iOx).min(1).max(6),cta:lOx}),nOx=rf.pick({headline:!0}).extend({slug:X.string()}),Wz=j8.extend({entityType:X.literal("products-overview"),metadata:nOx}),hB0=Wz.extend({frontmatter:rf,body:um,labels:X.record(X.string(),X.string())});class Hz extends q9{constructor(){super(um,{title:"Products Overview",mappings:[{key:"vision",label:"Vision",type:"string"},{key:"pillars",label:"Core Principles",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"approach",label:"How It Works",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"productsIntro",label:"Products",type:"string"},{key:"technologies",label:"Built With",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"benefits",label:"Why Brains",type:"array",itemType:"object",itemMappings:[{key:"title",label:"Title",type:"string"},{key:"description",label:"Description",type:"string"}]},{key:"cta",label:"Ready to Build",type:"object",children:[{key:"heading",label:"Heading",type:"string"},{key:"buttonText",label:"Button Text",type:"string"},{key:"link",label:"Link",type:"string"}]}]})}}class RB0 extends ox{constructor(){super({entityType:"products-overview",purpose:"A high-level overview of the product portfolio.",schema:Wz,frontmatterSchema:rf,bodyFormatter:new Hz})}toMarkdown(x){let B=this.extractBody(x.content);try{let A=this.parseFrontMatter(x.content,rf);return this.buildMarkdown(B,A)}catch{return B}}fromMarkdown(x){let B=this.parseFrontMatter(x,rf),A=Gx(B.headline);return{content:x,entityType:"products-overview",metadata:{headline:B.headline,slug:A}}}}var yB0=new RB0;var EU9=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function dOx(x,B){let A=G9(x.content,c2),w=B.parse(A.content),f=B.getLabels();return Tm.parse({...x,frontmatter:A.metadata,body:w,labels:f})}function aOx(x,B){let A=G9(x.content,rf),w=B.parse(A.content),f=B.getLabels();return hB0.parse({...x,frontmatter:A.metadata,body:w,labels:f})}class Sm{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new Hz;productFormatter=new Yz;constructor(x){this.logger=x,this.logger.debug("ProductsDataSource initialized")}async fetch(x,B,A){let w=EU9.parse(x),f=A.entityService;if(w.entityType==="products-overview"){let Y=(await f.listEntities({entityType:"products-overview",options:{limit:1}}))[0];if(!Y)throw Error("Products overview entity not found");let W=aOx(Y,this.overviewFormatter);return B.parse(W)}if(w.query?.id){let Y=(await f.listEntities({entityType:"product",options:{filter:{metadata:{slug:w.query.id}},limit:1}}))[0];if(!Y)throw Error(`Product not found: ${w.query.id}`);return B.parse({product:dOx(Y,this.productFormatter)})}let[D,$]=await Promise.all([f.listEntities({entityType:"products-overview",options:{limit:1}}),f.listEntities({entityType:"product",options:{sortFields:[{field:"order",direction:"asc"}]}})]),Z=D[0];if(!Z)throw Error("Products overview entity not found");return B.parse({overview:aOx(Z,this.overviewFormatter),products:$.map((Q)=>dOx(Q,this.productFormatter))})}}import{jsxDEV as P0,Fragment as PU9}from"preact/jsx-dev-runtime";var sOx=({overview:x,products:B})=>{let{frontmatter:A,body:w,labels:f}=x;return P0(PU9,{children:[P0(z9,{title:A.headline,description:A.tagline},void 0,!1,void 0,this),P0("header",{className:"relative w-full min-h-[80vh] flex items-end px-6 md:px-12 bg-brand-dark overflow-hidden",children:[P0("style",{children:`
6025
6025
  @keyframes wave-drift {
6026
6026
  from { transform: translateX(0); }
6027
6027
  to { transform: translateX(-50%); }
@@ -6216,7 +6216,7 @@ Use the project request as the primary source of truth. If retrieved knowledge c
6216
6216
  font: 10px/1.45 var(--font-mono, "JetBrains Mono", ui-monospace, monospace);
6217
6217
  }
6218
6218
  `}},void 0,!1,void 0,this),g2("section",{className:"product-shell",children:[g2("header",{className:"product-hero",children:[B.brandLabel&&g2("p",{className:"printable-kicker",children:B.brandLabel},void 0,!1,void 0,this),g2("h1",{className:"printable-title",children:B.name},void 0,!1,void 0,this),B.availability&&g2("div",{className:"printable-meta",children:g2("span",{children:B.availability},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),g2("div",{className:"product-body-wrap",children:[g2("aside",{className:"product-rail","aria-hidden":"true",children:g2("p",{className:"product-rail-label",children:"Product brief / capabilities"},void 0,!1,void 0,this)},void 0,!1,void 0,this),g2(cB,{markdown:B.body,className:"printable-body"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B.brandLabel&&g2("footer",{className:"printable-footer",children:B.brandLabel},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var eOx=Rm({sourceEntityType:"product",attachmentType:im,template:tOx,themeMode:"light",buildContent:(x,B)=>{let{frontmatter:A,content:w}=I1(x.content),f=c2.parse(A);return{name:f.name,body:w,availability:f.availability,...B.brandLabel?{brandLabel:B.brandLabel}:{}}},pageTitle:(x)=>x.name,slug:(x)=>EZ(x.metadata.slug,x.metadata.name)});import{jsxDEV as NU9}from"preact/jsx-dev-runtime";var lm="og-image",MU9="products:og-image",xhx=X.object({name:X.string().min(1),tagline:X.string().optional(),availability:X.string().optional(),brandLabel:X.string().optional()}),Bhx={name:MU9,pluginId:"products",schema:xhx,renderers:{image:vU9}};function vU9(x){let B=xhx.parse(x);return NU9(ym,{cover:!0,brandLabel:B.brandLabel??B.name,eyebrow:"Product",title:B.name,subtitle:B.tagline,tag:B.availability},void 0,!1,void 0,this)}var Ahx=Cm({sourceEntityType:"product",attachmentType:lm,template:Bhx,themeMode:"light",buildContent:(x,B)=>{let{frontmatter:A,content:w}=I1(x.content),f=c2.parse(A),D=IU9(w,"Tagline");return{name:f.name,availability:f.availability,...D?{tagline:D}:{},...B.brandLabel?{brandLabel:B.brandLabel}:{}}},pageTitle:(x)=>x.name,slug:(x)=>EZ(x.metadata.slug,x.metadata.name)});function IU9(x,B){let A=x.split(/\r?\n/),w=A.findIndex(($)=>$.trim().toLowerCase()===`## ${B.toLowerCase()}`);if(w===-1)return;let f=[];for(let $ of A.slice(w+1)){if($.trim().startsWith("## "))break;f.push($)}let D=f.join(`
6219
- `).trim();return D.length>0?D:void 0}var whx={name:"@brains/products",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Product entity management and overview page for marketing showcase",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var hU9=X.union([X.enum(["public","shared","restricted"]),X.literal("private")]).optional().transform((x)=>{if(x===void 0)return"public";if(x==="private")return"restricted";return x}),fhx=X.object({id:X.string(),entityType:X.string(),content:X.string(),created:X.string(),updated:X.string(),visibility:hU9,metadata:X.record(X.string(),X.unknown()),contentHash:X.string()}),Dhx=X.enum(["available","early access","coming soon","planned"]),RU9=X.object({title:X.string(),description:X.string()}),yU9=X.object({name:X.string(),availability:Dhx,order:X.number(),ogImageId:X.string().nullable().default(null)}),mU9=X.object({tagline:X.string(),promise:X.string(),role:X.string(),purpose:X.string(),audience:X.string(),values:X.array(X.string()).min(1),features:X.array(RU9).min(1).max(6),story:X.string()}),CU9=X.object({name:X.string(),availability:Dhx,order:X.number(),slug:X.string()}),$hx=fhx.extend({entityType:X.literal("product"),metadata:CU9,frontmatter:yU9,body:mU9,labels:X.record(X.string(),X.string()),url:X.string().nullable().default(null),typeLabel:X.string().nullable().default(null),listUrl:X.string().nullable().default(null),listLabel:X.string().nullable().default(null),ogImageUrl:X.string().nullable().default(null)}),nm=X.object({title:X.string(),description:X.string()}),cU9=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),gU9=X.object({headline:X.string(),tagline:X.string()}),TU9=X.object({vision:X.string(),pillars:X.array(nm).min(1).max(6),approach:X.array(nm).min(1).max(6),productsIntro:X.string(),technologies:X.array(nm).min(1).max(6),benefits:X.array(nm).min(1).max(6),cta:cU9}),pU9=X.object({headline:X.string(),slug:X.string()}),uU9=fhx.extend({entityType:X.literal("products-overview"),metadata:pU9,frontmatter:gU9,body:TU9,labels:X.record(X.string(),X.string())}),SU9=X.object({overview:uU9,products:X.array($hx)}),iU9=X.object({product:$hx});class CB0 extends g8{entityType=pm.entityType;schema=Xz;adapter=pm;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(x={}){super("products",whx,x,mB0)}getTemplates(){return{"product-list":mx({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:SU9,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:sOx}}),"product-detail":mx({name:"product-detail",description:"Individual product detail page",schema:iU9,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:rOx}})}}getDataSources(){return[new Sm(this.logger.child("ProductsDataSource"))]}async onRegister(x){this.unregisterPrintableAttachmentProvider=x.attachments.register("product",im,eOx(x)),this.unregisterOgImageAttachmentProvider=x.attachments.register("product",lm,Ahx(x)),x.entities.register("products-overview",Wz,yB0)}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0}}function cB0(x={}){return new CB0(x)}var k_=X.object({title:X.string(),target:X.string()}),Zhx=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),M_=j8.extend({entityType:X.literal("prompt"),metadata:Zhx});class gB0 extends ox{constructor(){super({entityType:"prompt",purpose:"A reusable prompt or instruction template.",schema:M_,frontmatterSchema:k_})}toMarkdown(x){let B=this.extractBody(x.content),A=this.parseFrontMatter(x.content,k_);return this.buildMarkdown(B,A)}fromMarkdown(x){let B=this.parseFrontMatter(x,k_),A=Gx(B.target.replace(/:/g,"-"));return{content:x,entityType:"prompt",metadata:{title:B.title,target:B.target,slug:A}}}}var TB0=new gB0;var Qhx={name:"@brains/prompt",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Prompt entity type \u2014 AI prompts as editable markdown entities",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var nU9="prompt";class pB0 extends g8{entityType=nU9;schema=M_;adapter=TB0;constructor(){super("prompt",Qhx,{},qB)}getEntityTypeConfig(){return{embeddable:!1,projectionSource:!1,projectionSourceRole:"excluded"}}}function uB0(){return new pB0}import{readFile as Yhx}from"fs/promises";import{join as Whx}from"path";var Xhx={name:"@brains/onboarding",version:"0.2.0-alpha.254",description:"Canonical onboarding playbook bundle and activation plugin",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/playbooks":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",license:"AGPL-3.0-only"};var aU9=X.object({enabled:X.boolean().default(!1)}).strict(),Hhx=[{id:"onboarding",fileName:"onboarding.md",starter:{id:"onboarding",trigger:"first-admin-web-chat",playbookId:"onboarding",once:!0,starterText:"Set up your brain",description:"Tune the brain identity and anchor profile before using the knowledge loop.",starterPrompt:"Start playbook onboarding."}},{id:"first-knowledge-loop",fileName:"first-knowledge-loop.md"}];class Fhx extends D8{dependencies=["playbook","playbooks"];constructor(x={}){super("onboarding",Xhx,x,aU9)}async onReady(x){if(!this.config.enabled)return;for(let B of Hhx)await this.seedPlaybookIfMissing(x,B);for(let B of Hhx){if(!B.starter)continue;await x.messaging.send({type:P_,payload:B.starter})}}async seedPlaybookIfMissing(x,B){if(await x.entityService.getEntity({entityType:"playbook",id:B.id,visibilityScope:"restricted"}))return;let w=await sU9(B.fileName);await x.entityService.createEntityFromMarkdown({input:{entityType:"playbook",id:B.id,markdown:w}})}}async function sU9(x){try{return await Yhx(Whx(import.meta.dir,"..","content","playbook",x),"utf8")}catch(B){if(!(B instanceof Error)||!("code"in B)||B.code!=="ENOENT")throw B}return Yhx(Whx(import.meta.dir,"onboarding",x),"utf8")}function Khx(x={}){return new Fhx(x)}var qhx={project:"series:project"};var l3=X.object({title:X.string(),slug:X.string(),coverImageId:X.string().nullable().default(null)}),zhx=X.object({title:X.string(),slug:X.string()}),jZ=j8.extend({entityType:X.literal("series"),metadata:zhx}),dm=jZ.extend({frontmatter:l3}),rU9=dm.extend({description:X.string().nullable().default(null),postCount:X.number(),coverImageUrl:X.string().nullable().default(null),coverImageWidth:X.number().nullable().default(null),coverImageHeight:X.number().nullable().default(null)}),bhx=X.object({description:X.string().optional()});function pY(x){return new q9(bhx,{title:x,mappings:[{key:"description",label:"Description",type:"string"}]})}class SB0 extends ox{constructor(){super({entityType:"series",purpose:"A series grouping related posts or content under one theme.",schema:jZ,frontmatterSchema:l3,supportsCoverImage:!0,bodyFormatter:pY("")})}toMarkdown(x){let B=null,A={};try{B=this.parseFrontMatter(x.content,l3).coverImageId,A=pY(x.metadata.title).parse(this.extractBody(x.content))}catch{}let w={title:x.metadata.title,slug:x.metadata.slug,coverImageId:B},D=pY(x.metadata.title).format(A);return this.buildMarkdown(D,w)}fromMarkdown(x){let B=this.parseFrontMatter(x,l3);return{content:x,entityType:"series",metadata:{title:B.title,slug:B.slug}}}parseBody(x){try{let B=this.parseFrontMatter(x,l3);return pY(B.title).parse(this.extractBody(x))}catch{return{}}}generateFrontMatter(){return""}}var _Z=new SB0;var oU9=X.object({seriesName:X.string().optional(),seriesIndex:X.number().optional()});function am(x){let B=oU9.safeParse(x);return B.success?B.data:{}}function uY(x){return am(x.metadata).seriesName}function Vhx(x){return am(x.metadata).seriesIndex}function Uhx(x,B){let A=Vhx(x)??Number.MAX_SAFE_INTEGER,w=Vhx(B)??Number.MAX_SAFE_INTEGER;return A-w}class iB0{entityService;logger;constructor(x,B){this.entityService=x,this.logger=B}async syncAllSeries(){this.logger.debug("Syncing series from all entity types");let x=await this.collectSeriesNames();this.logger.debug(`Found ${x.size} unique series`);let B=await this.entityService.listEntities({entityType:"series"}),A=new Map(B.map((f)=>[f.id,f])),w=new Set;for(let f of x){let D=Gx(f);w.add(D);let $=A.get(D),Z=$?.content??this.createSeriesContent(f),Q=_8(Z);if($?.contentHash===Q)continue;let Y={id:D,entityType:"series",content:Z,contentHash:Q,created:$?.created??new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:f,slug:Gx(f)}};await this.entityService.upsertEntity({entity:Y}),this.logger.debug(`Upserted series: ${f}`)}for(let f of B)if(!w.has(f.id))await this.entityService.deleteEntity({entityType:"series",id:f.id}),this.logger.debug(`Deleted orphaned series: ${f.id}`)}async handleEntityChange(x,B){let A=uY(x);if(A)await this.ensureSeriesExists(A);if(B&&B!==A)await this.cleanupOrphanedSeries(B)}async handleEntityDeleted(){await this.syncAllSeries()}async ensureSeriesExists(x){let B=Gx(x);if(await this.entityService.getEntity({entityType:"series",id:B}))return;let w=this.createSeriesContent(x),f={id:B,entityType:"series",content:w,contentHash:_8(w),created:new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:x,slug:Gx(x)}};await this.entityService.upsertEntity({entity:f}),this.logger.debug(`Created series: ${x}`)}async cleanupOrphanedSeries(x){let B=Gx(x);if(!await this.entityService.getEntity({entityType:"series",id:B}))return;if(!await this.hasSeriesReferences(x))await this.entityService.deleteEntity({entityType:"series",id:B}),this.logger.debug(`Deleted orphaned series: ${x}`)}async hasSeriesReferences(x){let B=this.entityService.getEntityTypes();for(let A of B){if(A==="series")continue;if((await this.entityService.listEntities({entityType:A,options:{filter:{metadata:{seriesName:x}},limit:1}})).length>0)return!0}return!1}async collectSeriesNames(){let x=new Set,B=this.entityService.getEntityTypes();for(let A of B){if(A==="series")continue;let w=await this.entityService.listEntities({entityType:A});for(let f of w){let D=uY(f);if(D)x.add(D)}}return x}createSeriesContent(x){let B={title:x,slug:Gx(x),coverImageId:null};return O3("",B)}}var tU9=X.object({entityType:X.literal("series"),query:X.looseObject({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional()})}),eU9=X.object({type:X.enum(["list","detail"]),seriesName:X.string().optional()});function xG9(x){let B=eU9.safeParse(x);if(B.success)return{type:B.data.type,seriesName:B.data.seriesName};let A=tU9.safeParse(x);if(A.success){let{query:w}=A.data;if(w.id)return{type:"detail",seriesSlug:w.id};return{type:"list"}}throw Error('Invalid series query format. Expected { type: "list"|"detail" } or { entityType: "series", query: { id?: string } }')}function Ghx(x){let B=G9(x.content,l3);return dm.parse({...x,frontmatter:B.metadata})}class lB0{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(x){this.logger=x}async fetch(x,B,A){let w=xG9(x),f=A.entityService;if(w.type==="list")return this.fetchSeriesList(B,f);if(w.seriesName)return this.fetchSeriesDetail(w.seriesName,B,f);if(w.seriesSlug)return this.fetchSeriesDetailBySlug(w.seriesSlug,B,f);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(x,B){let A=await B.listEntities({entityType:"series"}),w=await this.countEntitiesPerSeries(B),f=A.map((D)=>{let $=Ghx(D),Z=_Z.parseBody(D.content);return{...$,description:Z.description,postCount:w.get(D.metadata.title)??0}});return this.logger.debug(`Found ${f.length} series entities`),x.parse({series:f})}async fetchSeriesDetail(x,B,A,w){if(!w)w=(await A.listEntities({entityType:"series",options:{filter:{metadata:{title:x}}}}))[0];if(!w)throw Error(`Series not found: ${x}`);let f=Ghx(w),D=_Z.parseBody(w.content),$=await this.getSeriesMembers(x,A);return this.logger.debug(`Found ${$.length} entities in series "${x}"`),B.parse({seriesName:x,posts:$,series:{...f,description:D.description,postCount:$.length},description:D.description})}async fetchSeriesDetailBySlug(x,B,A){let f=(await A.listEntities({entityType:"series",options:{filter:{metadata:{slug:x}}}}))[0];if(!f)throw Error(`Series not found with slug: ${x}`);return this.fetchSeriesDetail(f.metadata.title,B,A,f)}async countEntitiesPerSeries(x){let B=new Map,A=x.getEntityTypes();for(let w of A){if(w==="series")continue;let f=await x.listEntities({entityType:w});for(let D of f){let $=uY(D);if($)B.set($,(B.get($)??0)+1)}}return B}async getSeriesMembers(x,B){let A=[],w=B.getEntityTypes();for(let f of w){if(f==="series")continue;let D=await B.listEntities({entityType:f,options:{filter:{metadata:{seriesName:x}}}});A.push(...D)}return A.sort(Uhx),A}}var BG9=X.object({prompt:X.string().optional(),title:X.string().optional(),seriesId:X.string().optional()}),AG9=X.object({title:X.string().optional(),excerpt:X.string().optional()});class sm{logger;context;constructor(x,B){this.logger=x,this.context=B}async process(x){let B=x.seriesId??x.title;if(!B)return{success:!1,error:"seriesId or title required"};let A=await this.context.entityService.getEntity({entityType:"series",id:B});if(!A)return{success:!1,error:`Series not found: ${B}`};let w=await this.gatherMemberSummaries(A.metadata.title);if(w.length===0)return{success:!1,error:`No members found in series: ${A.metadata.title}`};let f=x.prompt??`Series name: ${A.metadata.title}
6219
+ `).trim();return D.length>0?D:void 0}var whx={name:"@brains/products",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Product entity management and overview page for marketing showcase",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var hU9=X.union([X.enum(["public","shared","restricted"]),X.literal("private")]).optional().transform((x)=>{if(x===void 0)return"public";if(x==="private")return"restricted";return x}),fhx=X.object({id:X.string(),entityType:X.string(),content:X.string(),created:X.string(),updated:X.string(),visibility:hU9,metadata:X.record(X.string(),X.unknown()),contentHash:X.string()}),Dhx=X.enum(["available","early access","coming soon","planned"]),RU9=X.object({title:X.string(),description:X.string()}),yU9=X.object({name:X.string(),availability:Dhx,order:X.number(),ogImageId:X.string().nullable().default(null)}),mU9=X.object({tagline:X.string(),promise:X.string(),role:X.string(),purpose:X.string(),audience:X.string(),values:X.array(X.string()).min(1),features:X.array(RU9).min(1).max(6),story:X.string()}),CU9=X.object({name:X.string(),availability:Dhx,order:X.number(),slug:X.string()}),$hx=fhx.extend({entityType:X.literal("product"),metadata:CU9,frontmatter:yU9,body:mU9,labels:X.record(X.string(),X.string()),url:X.string().nullable().default(null),typeLabel:X.string().nullable().default(null),listUrl:X.string().nullable().default(null),listLabel:X.string().nullable().default(null),ogImageUrl:X.string().nullable().default(null)}),nm=X.object({title:X.string(),description:X.string()}),cU9=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),gU9=X.object({headline:X.string(),tagline:X.string()}),TU9=X.object({vision:X.string(),pillars:X.array(nm).min(1).max(6),approach:X.array(nm).min(1).max(6),productsIntro:X.string(),technologies:X.array(nm).min(1).max(6),benefits:X.array(nm).min(1).max(6),cta:cU9}),pU9=X.object({headline:X.string(),slug:X.string()}),uU9=fhx.extend({entityType:X.literal("products-overview"),metadata:pU9,frontmatter:gU9,body:TU9,labels:X.record(X.string(),X.string())}),SU9=X.object({overview:uU9,products:X.array($hx)}),iU9=X.object({product:$hx});class CB0 extends g8{entityType=pm.entityType;schema=Xz;adapter=pm;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(x={}){super("products",whx,x,mB0)}getTemplates(){return{"product-list":mx({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:SU9,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:sOx}}),"product-detail":mx({name:"product-detail",description:"Individual product detail page",schema:iU9,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:rOx}})}}getDataSources(){return[new Sm(this.logger.child("ProductsDataSource"))]}async onRegister(x){this.unregisterPrintableAttachmentProvider=x.attachments.register("product",im,eOx(x)),this.unregisterOgImageAttachmentProvider=x.attachments.register("product",lm,Ahx(x)),x.entities.register("products-overview",Wz,yB0)}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0}}function cB0(x={}){return new CB0(x)}var k_=X.object({title:X.string(),target:X.string()}),Zhx=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),M_=j8.extend({entityType:X.literal("prompt"),metadata:Zhx});class gB0 extends ox{constructor(){super({entityType:"prompt",purpose:"A reusable prompt or instruction template.",schema:M_,frontmatterSchema:k_})}toMarkdown(x){let B=this.extractBody(x.content),A=this.parseFrontMatter(x.content,k_);return this.buildMarkdown(B,A)}fromMarkdown(x){let B=this.parseFrontMatter(x,k_),A=Gx(B.target.replace(/:/g,"-"));return{content:x,entityType:"prompt",metadata:{title:B.title,target:B.target,slug:A}}}}var TB0=new gB0;var Qhx={name:"@brains/prompt",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Prompt entity type \u2014 AI prompts as editable markdown entities",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"^1.3.14",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var nU9="prompt";class pB0 extends g8{entityType=nU9;schema=M_;adapter=TB0;constructor(){super("prompt",Qhx,{},qB)}getEntityTypeConfig(){return{embeddable:!1,projectionSource:!1,projectionSourceRole:"excluded"}}}function uB0(){return new pB0}import{readFile as Yhx}from"fs/promises";import{join as Whx}from"path";var Xhx={name:"@brains/onboarding",version:"0.2.0-alpha.255",description:"Canonical onboarding playbook bundle and activation plugin",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/playbooks":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",license:"AGPL-3.0-only"};var aU9=X.object({enabled:X.boolean().default(!1)}).strict(),Hhx=[{id:"onboarding",fileName:"onboarding.md",starter:{id:"onboarding",trigger:"first-admin-web-chat",playbookId:"onboarding",once:!0,starterText:"Set up your brain",description:"Tune the brain identity and anchor profile before using the knowledge loop.",starterPrompt:"Start playbook onboarding."}},{id:"first-knowledge-loop",fileName:"first-knowledge-loop.md"}];class Fhx extends D8{dependencies=["playbook","playbooks"];constructor(x={}){super("onboarding",Xhx,x,aU9)}async onReady(x){if(!this.config.enabled)return;for(let B of Hhx)await this.seedPlaybookIfMissing(x,B);for(let B of Hhx){if(!B.starter)continue;await x.messaging.send({type:P_,payload:B.starter})}}async seedPlaybookIfMissing(x,B){if(await x.entityService.getEntity({entityType:"playbook",id:B.id,visibilityScope:"restricted"}))return;let w=await sU9(B.fileName);await x.entityService.createEntityFromMarkdown({input:{entityType:"playbook",id:B.id,markdown:w}})}}async function sU9(x){try{return await Yhx(Whx(import.meta.dir,"..","content","playbook",x),"utf8")}catch(B){if(!(B instanceof Error)||!("code"in B)||B.code!=="ENOENT")throw B}return Yhx(Whx(import.meta.dir,"onboarding",x),"utf8")}function Khx(x={}){return new Fhx(x)}var qhx={project:"series:project"};var l3=X.object({title:X.string(),slug:X.string(),coverImageId:X.string().nullable().default(null)}),zhx=X.object({title:X.string(),slug:X.string()}),jZ=j8.extend({entityType:X.literal("series"),metadata:zhx}),dm=jZ.extend({frontmatter:l3}),rU9=dm.extend({description:X.string().nullable().default(null),postCount:X.number(),coverImageUrl:X.string().nullable().default(null),coverImageWidth:X.number().nullable().default(null),coverImageHeight:X.number().nullable().default(null)}),bhx=X.object({description:X.string().optional()});function pY(x){return new q9(bhx,{title:x,mappings:[{key:"description",label:"Description",type:"string"}]})}class SB0 extends ox{constructor(){super({entityType:"series",purpose:"A series grouping related posts or content under one theme.",schema:jZ,frontmatterSchema:l3,supportsCoverImage:!0,bodyFormatter:pY("")})}toMarkdown(x){let B=null,A={};try{B=this.parseFrontMatter(x.content,l3).coverImageId,A=pY(x.metadata.title).parse(this.extractBody(x.content))}catch{}let w={title:x.metadata.title,slug:x.metadata.slug,coverImageId:B},D=pY(x.metadata.title).format(A);return this.buildMarkdown(D,w)}fromMarkdown(x){let B=this.parseFrontMatter(x,l3);return{content:x,entityType:"series",metadata:{title:B.title,slug:B.slug}}}parseBody(x){try{let B=this.parseFrontMatter(x,l3);return pY(B.title).parse(this.extractBody(x))}catch{return{}}}generateFrontMatter(){return""}}var _Z=new SB0;var oU9=X.object({seriesName:X.string().optional(),seriesIndex:X.number().optional()});function am(x){let B=oU9.safeParse(x);return B.success?B.data:{}}function uY(x){return am(x.metadata).seriesName}function Vhx(x){return am(x.metadata).seriesIndex}function Uhx(x,B){let A=Vhx(x)??Number.MAX_SAFE_INTEGER,w=Vhx(B)??Number.MAX_SAFE_INTEGER;return A-w}class iB0{entityService;logger;constructor(x,B){this.entityService=x,this.logger=B}async syncAllSeries(){this.logger.debug("Syncing series from all entity types");let x=await this.collectSeriesNames();this.logger.debug(`Found ${x.size} unique series`);let B=await this.entityService.listEntities({entityType:"series"}),A=new Map(B.map((f)=>[f.id,f])),w=new Set;for(let f of x){let D=Gx(f);w.add(D);let $=A.get(D),Z=$?.content??this.createSeriesContent(f),Q=_8(Z);if($?.contentHash===Q)continue;let Y={id:D,entityType:"series",content:Z,contentHash:Q,created:$?.created??new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:f,slug:Gx(f)}};await this.entityService.upsertEntity({entity:Y}),this.logger.debug(`Upserted series: ${f}`)}for(let f of B)if(!w.has(f.id))await this.entityService.deleteEntity({entityType:"series",id:f.id}),this.logger.debug(`Deleted orphaned series: ${f.id}`)}async handleEntityChange(x,B){let A=uY(x);if(A)await this.ensureSeriesExists(A);if(B&&B!==A)await this.cleanupOrphanedSeries(B)}async handleEntityDeleted(){await this.syncAllSeries()}async ensureSeriesExists(x){let B=Gx(x);if(await this.entityService.getEntity({entityType:"series",id:B}))return;let w=this.createSeriesContent(x),f={id:B,entityType:"series",content:w,contentHash:_8(w),created:new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:x,slug:Gx(x)}};await this.entityService.upsertEntity({entity:f}),this.logger.debug(`Created series: ${x}`)}async cleanupOrphanedSeries(x){let B=Gx(x);if(!await this.entityService.getEntity({entityType:"series",id:B}))return;if(!await this.hasSeriesReferences(x))await this.entityService.deleteEntity({entityType:"series",id:B}),this.logger.debug(`Deleted orphaned series: ${x}`)}async hasSeriesReferences(x){let B=this.entityService.getEntityTypes();for(let A of B){if(A==="series")continue;if((await this.entityService.listEntities({entityType:A,options:{filter:{metadata:{seriesName:x}},limit:1}})).length>0)return!0}return!1}async collectSeriesNames(){let x=new Set,B=this.entityService.getEntityTypes();for(let A of B){if(A==="series")continue;let w=await this.entityService.listEntities({entityType:A});for(let f of w){let D=uY(f);if(D)x.add(D)}}return x}createSeriesContent(x){let B={title:x,slug:Gx(x),coverImageId:null};return O3("",B)}}var tU9=X.object({entityType:X.literal("series"),query:X.looseObject({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional()})}),eU9=X.object({type:X.enum(["list","detail"]),seriesName:X.string().optional()});function xG9(x){let B=eU9.safeParse(x);if(B.success)return{type:B.data.type,seriesName:B.data.seriesName};let A=tU9.safeParse(x);if(A.success){let{query:w}=A.data;if(w.id)return{type:"detail",seriesSlug:w.id};return{type:"list"}}throw Error('Invalid series query format. Expected { type: "list"|"detail" } or { entityType: "series", query: { id?: string } }')}function Ghx(x){let B=G9(x.content,l3);return dm.parse({...x,frontmatter:B.metadata})}class lB0{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(x){this.logger=x}async fetch(x,B,A){let w=xG9(x),f=A.entityService;if(w.type==="list")return this.fetchSeriesList(B,f);if(w.seriesName)return this.fetchSeriesDetail(w.seriesName,B,f);if(w.seriesSlug)return this.fetchSeriesDetailBySlug(w.seriesSlug,B,f);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(x,B){let A=await B.listEntities({entityType:"series"}),w=await this.countEntitiesPerSeries(B),f=A.map((D)=>{let $=Ghx(D),Z=_Z.parseBody(D.content);return{...$,description:Z.description,postCount:w.get(D.metadata.title)??0}});return this.logger.debug(`Found ${f.length} series entities`),x.parse({series:f})}async fetchSeriesDetail(x,B,A,w){if(!w)w=(await A.listEntities({entityType:"series",options:{filter:{metadata:{title:x}}}}))[0];if(!w)throw Error(`Series not found: ${x}`);let f=Ghx(w),D=_Z.parseBody(w.content),$=await this.getSeriesMembers(x,A);return this.logger.debug(`Found ${$.length} entities in series "${x}"`),B.parse({seriesName:x,posts:$,series:{...f,description:D.description,postCount:$.length},description:D.description})}async fetchSeriesDetailBySlug(x,B,A){let f=(await A.listEntities({entityType:"series",options:{filter:{metadata:{slug:x}}}}))[0];if(!f)throw Error(`Series not found with slug: ${x}`);return this.fetchSeriesDetail(f.metadata.title,B,A,f)}async countEntitiesPerSeries(x){let B=new Map,A=x.getEntityTypes();for(let w of A){if(w==="series")continue;let f=await x.listEntities({entityType:w});for(let D of f){let $=uY(D);if($)B.set($,(B.get($)??0)+1)}}return B}async getSeriesMembers(x,B){let A=[],w=B.getEntityTypes();for(let f of w){if(f==="series")continue;let D=await B.listEntities({entityType:f,options:{filter:{metadata:{seriesName:x}}}});A.push(...D)}return A.sort(Uhx),A}}var BG9=X.object({prompt:X.string().optional(),title:X.string().optional(),seriesId:X.string().optional()}),AG9=X.object({title:X.string().optional(),excerpt:X.string().optional()});class sm{logger;context;constructor(x,B){this.logger=x,this.context=B}async process(x){let B=x.seriesId??x.title;if(!B)return{success:!1,error:"seriesId or title required"};let A=await this.context.entityService.getEntity({entityType:"series",id:B});if(!A)return{success:!1,error:`Series not found: ${B}`};let w=await this.gatherMemberSummaries(A.metadata.title);if(w.length===0)return{success:!1,error:`No members found in series: ${A.metadata.title}`};let f=x.prompt??`Series name: ${A.metadata.title}
6220
6220
 
6221
6221
  Content in this series:
6222
6222
  ${w.join(`
@@ -6228,7 +6228,7 @@ Your task is to write a series description (2-3 sentences) that:
6228
6228
  3. Is engaging and makes readers want to explore the content
6229
6229
  4. Works well as a series overview on a website
6230
6230
 
6231
- Be concise and focus on what makes this series unique and valuable.`});async function vhx({entity:x,config:B}){let A=jZ.parse(x),w=_Z.parseBody(A.content);return{$type:"ai.rizom.brain.series",title:A.metadata.title,slug:A.metadata.slug,...w.description&&{description:w.description},...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"series",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function nB0(){return{entityType:"series",collection:"ai.rizom.brain.series",lexicon:h4["ai.rizom.brain.series"],validate:!1,buildRecord:vhx}}var Nhx={name:"@brains/series",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Cross-content series \u2014 auto-derived from entities with seriesName metadata",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/entity-service":"workspace:*","@brains/job-queue":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Ihx=X.discriminatedUnion("mode",[X.object({mode:X.literal("derive"),reason:X.string().optional()}),X.object({mode:X.literal("source"),entityId:X.string(),entityType:X.string(),seriesName:X.string().optional(),previousSeriesName:X.string().optional()})]);class dB0 extends g8{entityType="series";schema=jZ;adapter=_Z;manager;unregisterAtprotoProjection;constructor(){super("series",Nhx,{},qB)}getEntityTypeConfig(){return{weight:0.5,projectionSourceRole:"supporting"}}createGenerationHandler(x){return new sm(this.logger.child("SeriesGenerationHandler"),x)}getTemplates(){return{...khx(),description:Mhx}}getDataSources(){return[new lB0(this.logger.child("SeriesDataSource"))]}getDerivedEntityProjections(x){return[{id:"series-projection",targetType:"series",job:{type:qhx.project,handler:this.createSeriesProjectionHandler(x)},initialSync:{jobData:{mode:"derive",reason:"initial-sync"},jobOptions:this.getSyncProjectionJobOptions("initial-sync")},sourceChange:{sourceTypes:["*"],events:[l8.created,l8.updated,l8.deleted],requireInitialSync:!0,jobData:(B)=>{if(B.entityType==="series")return null;if(!B.entity)return null;let A=uY(B.entity),w=am(B.previousMetadata).seriesName;if(!A&&!w)return null;return{mode:"source",entityId:B.entity.id,entityType:B.entity.entityType,...A?{seriesName:A}:{},...w&&w!==A?{previousSeriesName:w}:{}}},jobOptions:(B)=>{if(!B.entity)return;return this.getSourceProjectionJobOptions(B.entity)}}}]}async onRegister(x){this.manager=new iB0(x.entityService,this.logger.child("SeriesManager")),this.unregisterAtprotoProjection=R4.getInstance().register(nB0())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}createSeriesProjectionHandler(x){return{process:async(B)=>{let A=Ihx.parse(B);if(A.mode==="derive")return await this.projectAll(x),{success:!0};let w=await x.entityService.getEntity({entityType:A.entityType,id:A.entityId});if(w)await this.projectSource(w,A.previousSeriesName);else{let f=this.requireManager();for(let D of[A.seriesName,A.previousSeriesName])if(D)await f.cleanupOrphanedSeries(D)}return{success:!0}},validateAndParse:(B)=>{let A=Ihx.safeParse(B??{});return A.success?A.data:null}}}requireManager(){if(!this.manager)throw Error("SeriesPlugin not registered");return this.manager}getSyncProjectionJobOptions(x){return{source:this.id,deduplication:"coalesce",deduplicationKey:`series-sync:${x}`,metadata:{operationType:"data_processing",operationTarget:"series"}}}getSourceProjectionJobOptions(x){return{source:this.id,deduplication:"coalesce",deduplicationKey:`series-source:${x.entityType}:${x.id}`,metadata:{operationType:"data_processing",operationTarget:`series:${x.entityType}:${x.id}`}}}async projectSource(x,B){await this.requireManager().handleEntityChange(x,B)}async projectAll(x){await this.requireManager().syncAllSeries();let B=new sm(this.logger.child("SeriesGenerationHandler"),x),A=await x.entityService.listEntities({entityType:"series"});for(let w of A)try{if(!this.adapter.parseBody(w.content).description)this.logger.info(`Generating description for series: ${w.metadata.title}`),await B.process({seriesId:w.id})}catch(f){this.logger.error(`Failed to generate description for series: ${w.id}`,{error:f})}}}function aB0(){return new dB0}import{render as Rhx}from"preact-render-to-string";import{h as SY}from"preact";import{dirname as yhx,join as sB0}from"path";import{promises as T2}from"fs";var Ohx=`@import "tailwindcss";
6231
+ Be concise and focus on what makes this series unique and valuable.`});async function vhx({entity:x,config:B}){let A=jZ.parse(x),w=_Z.parseBody(A.content);return{$type:"ai.rizom.brain.series",title:A.metadata.title,slug:A.metadata.slug,...w.description&&{description:w.description},...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"series",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function nB0(){return{entityType:"series",collection:"ai.rizom.brain.series",lexicon:h4["ai.rizom.brain.series"],validate:!1,buildRecord:vhx}}var Nhx={name:"@brains/series",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Cross-content series \u2014 auto-derived from entities with seriesName metadata",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/entity-service":"workspace:*","@brains/job-queue":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Ihx=X.discriminatedUnion("mode",[X.object({mode:X.literal("derive"),reason:X.string().optional()}),X.object({mode:X.literal("source"),entityId:X.string(),entityType:X.string(),seriesName:X.string().optional(),previousSeriesName:X.string().optional()})]);class dB0 extends g8{entityType="series";schema=jZ;adapter=_Z;manager;unregisterAtprotoProjection;constructor(){super("series",Nhx,{},qB)}getEntityTypeConfig(){return{weight:0.5,projectionSourceRole:"supporting"}}createGenerationHandler(x){return new sm(this.logger.child("SeriesGenerationHandler"),x)}getTemplates(){return{...khx(),description:Mhx}}getDataSources(){return[new lB0(this.logger.child("SeriesDataSource"))]}getDerivedEntityProjections(x){return[{id:"series-projection",targetType:"series",job:{type:qhx.project,handler:this.createSeriesProjectionHandler(x)},initialSync:{jobData:{mode:"derive",reason:"initial-sync"},jobOptions:this.getSyncProjectionJobOptions("initial-sync")},sourceChange:{sourceTypes:["*"],events:[l8.created,l8.updated,l8.deleted],requireInitialSync:!0,jobData:(B)=>{if(B.entityType==="series")return null;if(!B.entity)return null;let A=uY(B.entity),w=am(B.previousMetadata).seriesName;if(!A&&!w)return null;return{mode:"source",entityId:B.entity.id,entityType:B.entity.entityType,...A?{seriesName:A}:{},...w&&w!==A?{previousSeriesName:w}:{}}},jobOptions:(B)=>{if(!B.entity)return;return this.getSourceProjectionJobOptions(B.entity)}}}]}async onRegister(x){this.manager=new iB0(x.entityService,this.logger.child("SeriesManager")),this.unregisterAtprotoProjection=R4.getInstance().register(nB0())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}createSeriesProjectionHandler(x){return{process:async(B)=>{let A=Ihx.parse(B);if(A.mode==="derive")return await this.projectAll(x),{success:!0};let w=await x.entityService.getEntity({entityType:A.entityType,id:A.entityId});if(w)await this.projectSource(w,A.previousSeriesName);else{let f=this.requireManager();for(let D of[A.seriesName,A.previousSeriesName])if(D)await f.cleanupOrphanedSeries(D)}return{success:!0}},validateAndParse:(B)=>{let A=Ihx.safeParse(B??{});return A.success?A.data:null}}}requireManager(){if(!this.manager)throw Error("SeriesPlugin not registered");return this.manager}getSyncProjectionJobOptions(x){return{source:this.id,deduplication:"coalesce",deduplicationKey:`series-sync:${x}`,metadata:{operationType:"data_processing",operationTarget:"series"}}}getSourceProjectionJobOptions(x){return{source:this.id,deduplication:"coalesce",deduplicationKey:`series-source:${x.entityType}:${x.id}`,metadata:{operationType:"data_processing",operationTarget:`series:${x.entityType}:${x.id}`}}}async projectSource(x,B){await this.requireManager().handleEntityChange(x,B)}async projectAll(x){await this.requireManager().syncAllSeries();let B=new sm(this.logger.child("SeriesGenerationHandler"),x),A=await x.entityService.listEntities({entityType:"series"});for(let w of A)try{if(!this.adapter.parseBody(w.content).description)this.logger.info(`Generating description for series: ${w.metadata.title}`),await B.process({seriesId:w.id})}catch(f){this.logger.error(`Failed to generate description for series: ${w.id}`,{error:f})}}}function aB0(){return new dB0}import{render as Rhx}from"preact-render-to-string";import{h as SY}from"preact";import{dirname as yhx,join as sB0}from"path";import{promises as T2}from"fs";var Ohx=`@import "tailwindcss";
6232
6232
  @plugin "@tailwindcss/typography";
6233
6233
  @source "./**/*.html";
6234
6234
 
@@ -6324,19 +6324,19 @@ Be concise and focus on what makes this series unique and valuable.`});async fun
6324
6324
  font-size: 9.5px;
6325
6325
  line-height: 1.45;
6326
6326
  }
6327
- `;var HE9=X.object({environment:X.enum(["preview","production"]),active:X.object({state:X.enum(["debouncing","queued","building"])}).optional(),lastSuccess:X.object({completedAt:X.string(),routesBuilt:X.number(),warnings:X.array(X.string())}).optional(),lastFailure:X.object({completedAt:X.string(),message:X.string()}).optional(),lastCancellation:X.object({completedAt:X.string(),message:X.string()}).optional()}),ORx=X.object({site:X.object({title:X.string(),previewUrl:X.string().optional(),liveUrl:X.string().optional()}),environments:X.array(HE9),managementUrl:X.string().optional()});function Y30(x){if(x.active)return x.active.state;if(x.lastCancellation)return"cancelled";if(x.lastFailure)return"failed";if(x.lastSuccess)return"current";return"not built"}function FE9(x){if(x.lastCancellation)return x.lastCancellation.message;if(x.lastFailure)return x.lastFailure.message;if(x.lastSuccess){let B=x.lastSuccess.warnings.length>0?` \xB7 ${x.lastSuccess.warnings.length} warning`:"";return`${x.lastSuccess.routesBuilt} routes${B}`}return"No completed build in this runtime"}function IRx(x){let B=x.environment?Y30(x.environment):"unavailable";return p5("div",{class:`pipeline-metric site-health-metric site-health-metric--${B}`},[p5("dt",{},[p5("span",{class:"site-health-dot","aria-hidden":"true"}),x.label]),p5("dd",{},B),x.environment?p5("small",{class:"muted"},FE9(x.environment)):null])}function X30(x,B,A="external"){return p5("a",{class:`widget-action widget-action--${A==="manage"?"primary":"secondary"}`,href:x,...A==="external"?{target:"_blank",rel:"noreferrer"}:{}},[p5("span",{},B),p5("span",{class:"widget-action-arrow","aria-hidden":"true"},A==="external"?"\u2197":"\u2192")])}function KE9(x){let B=ORx.safeParse(x.data);if(!B.success)return p5("p",{class:"muted"},"Site health is unavailable.");let A=B.data,w=A.environments.find((Z)=>Z.environment==="preview"),f=A.environments.find((Z)=>Z.environment==="production"),D=A.environments.filter((Z)=>Z.lastFailure!==void 0),$=[];if(A.site.previewUrl)$.push(X30(A.site.previewUrl,"Open preview"));if(A.site.liveUrl)$.push(X30(A.site.liveUrl,"Open live"));if(A.managementUrl)$.push(X30(A.managementUrl,"Open in CMS","manage"));return p5("div",{class:"pipeline-digest site-health-widget"},[p5("dl",{class:"pipeline-metrics"},[p5(IRx,{label:"Preview",environment:w}),p5(IRx,{label:"Live",environment:f})]),D.length>0?p5("section",{class:"pipeline-failures"},[p5("h4",{},"Needs attention"),...D.map((Z)=>p5("div",{class:"pipeline-failure",key:Z.environment},[p5("strong",{},Z.environment),p5("span",{},Z.lastFailure?.message)]))]):null,$.length>0?p5("nav",{class:"widget-actions","aria-label":"Site actions"},$):null])}function qE9(x){let B=ORx.parse(x),A=B.environments.find((D)=>D.environment==="preview"),w=B.environments.find((D)=>D.environment==="production"),f=B.environments.filter((D)=>D.lastFailure!==void 0).length;return{digest:[{label:"Preview",value:A?Y30(A):"unavailable",...A?.lastFailure?{tone:"warn"}:{tone:"good"}},{label:"Live",value:w?Y30(w):"unavailable",...w?.lastFailure?{tone:"warn"}:{tone:"good"}}],needsOperator:f}}async function hRx(x,B,A){await x.dashboard.registerWidget({id:"site-health",title:"Site health",description:"Preview and live build status",group:"publishing",section:"sidebar",priority:50,rendererName:"SiteHealthWidget",visibility:"admin",component:KE9,clientStyles:NRx,dataProvider:async()=>({...await B.getSnapshot(),...A?{managementUrl:A}:{}}),digestProvider:qE9})}var zE9=X.object({id:X.string(),template:X.string(),content:X.unknown().optional(),dataQuery:X.looseObject({entityType:X.string().optional(),template:X.string().optional(),query:X.looseObject({id:X.string().optional(),limit:X.number().optional(),offset:X.number().optional()}).optional()}).optional(),order:X.number().optional()}),bE9=X.object({show:X.boolean().default(!1),label:X.string().optional(),slot:X.enum(N_).default("primary"),priority:X.number().min(0).max(100).default(50)}).optional(),VE9=X.object({id:X.string(),path:X.string(),title:X.string().default(""),pageLabel:X.string().optional(),description:X.string().default(""),sections:X.array(zE9).default([]),layout:X.string().default("default"),fullscreen:X.boolean().optional(),pluginId:X.string().optional(),sourceEntityType:X.string().optional(),external:X.boolean().optional(),navigation:bE9}),RRx=X.object({previewOutputDir:X.string().describe("Output directory for preview builds").default("./dist/site-preview"),productionOutputDir:X.string().describe("Output directory for production builds").default("./dist/site-production"),sharedImagesDir:X.string().describe("Shared directory for optimized images (used by both preview and production)").default("./dist/images"),workingDir:X.string().optional().describe("Working directory for builds").default("./.preact-work"),siteInfo:Fz.default({title:"Brain",description:"A knowledge management system"}),themeCSS:X.string().describe("Custom CSS theme overrides to inject into builds").optional(),analyticsScript:X.string().describe("Analytics tracking script to inject into page head (e.g., Cloudflare Web Analytics)").optional(),templates:X.any().optional().describe("Template definitions to register"),routes:X.array(VE9).optional().describe("Routes to register"),layouts:X.record(X.string(),X.any()).optional().describe("Layout components (at least 'default' required)"),autoRebuild:X.boolean().default(!0).describe("Automatically rebuild site when content changes"),rebuildDebounce:X.number().min(100).describe("Debounce time in ms before triggering site rebuild after content changes").default(5000),entityDisplay:X.record(X.string(),X.object({label:X.string().describe("Display label for entity type (e.g., 'Essay')"),pluralName:X.string().optional().describe("URL path segment (defaults to label.toLowerCase() + 's')"),layout:X.string().optional().describe("Layout name for this entity type's generated routes (defaults to 'default')"),paginate:X.boolean().optional().describe("Enable pagination for list pages"),pageSize:X.number().optional().describe("Items per page (default: 10)"),navigation:X.object({show:X.boolean().optional().describe("Show in navigation"),slot:X.enum(N_).optional().describe("Navigation slot (primary or secondary)"),priority:X.number().min(0).max(100).optional().describe("Navigation priority (0-100)")}).optional().describe("Navigation settings for this entity type")})).optional().describe("Display metadata per entity type \u2014 label, plural name, layout, pagination, navigation slot. Consulted when auto-generating routes for active entity plugins."),staticAssets:X.record(X.string(),X.string()).optional().describe("Static files to write to the output directory at build time. Keys are output paths (e.g. '/canvases/tree.js'), values are file contents as strings. Typically supplied by a SitePackage via text imports.")});var yRx={name:"@brains/site-builder-plugin",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Static site generation plugin for Brain system",dependencies:{"@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-engine":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*","@tailwindcss/typography":"^0.5.20",preact:"^10.27.2","preact-render-to-string":"^6.7.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{clean:"rm -rf dist",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class W30 extends D8{siteBuilder;pluginContext;_routeRegistry;_slotRegistry;profileService;layouts;rebuildManager;buildStatusService;siteWorkspaceProvider;headScripts=new Map;get routeRegistry(){if(!this._routeRegistry)throw Error("RouteRegistry not initialized - plugin not registered");return this._routeRegistry}constructor(x={}){let B=x.layouts??{};super("site-builder",yRx,{...x,layouts:B},RRx);this.layouts=B}async onRegister(x){if(this.pluginContext=x,this._routeRegistry=new cRx(x.logger),this._slotRegistry=new CRx,x.messaging.subscribe(O4.slotRegister,async(A)=>{let{slotName:w,pluginId:f,render:D,priority:$}=A.payload;return this._slotRegistry?.register(w,{pluginId:f,render:D,...$!==void 0&&{priority:$}}),{success:!0}}),x.messaging.subscribe(O4.headScriptRegister,async(A)=>{let{pluginId:w,script:f}=A.payload;return this.headScripts.set(w,f),{success:!0}}),x.entities.registerDataSource(new $30(this._routeRegistry,x.logger.child("NavigationDataSource"))),this.profileService={getProfile:()=>x.identity.getProfile()},this.buildStatusService=new Z30(x.runtimeState,x.jobs),await this.buildStatusService.initialize(),PRx(x,this._routeRegistry,this.logger),this.config.templates)x.templates.register(this.config.templates);if(this.config.routes)AC(this.config.routes,this.id,this.routeRegistry);let B={entityService:x.entityService,sendMessage:x.messaging.send,resolveTemplateContent:(A,w)=>x.templates.resolve(A,w),getViewTemplate:(A)=>x.views.get(A),listViewTemplateNames:()=>x.views.list().map((A)=>A.name)};if(this.siteBuilder=nY.createFresh(x.logger.child("SiteBuilder"),B,this.routeRegistry,this.profileService,void 0,this.config.entityDisplay),x.jobs.registerHandler("site-build",new D30(this.logger.child("SiteBuildJobHandler"),x.messaging.send,{siteBuilder:this.siteBuilder,layouts:this.layouts,defaultSiteConfig:this.config.siteInfo,sharedImagesDir:this.config.sharedImagesDir,siteUrl:x.siteUrl,previewUrl:x.previewUrl,localSiteUrl:x.localSiteUrl,preferLocalUrls:x.preferLocalUrls,themeCSS:this.config.themeCSS,slots:this._slotRegistry,getHeadScripts:()=>this.getRegisteredHeadScripts(),...this.config.staticAssets&&{staticAssets:this.config.staticAssets},statusService:this.buildStatusService})),this.rebuildManager=new f30(this.config,x,this.id,this.logger,this.buildStatusService),this.siteWorkspaceProvider=new Q30({context:x,config:this.config,routeRegistry:this.routeRegistry,statusService:this.buildStatusService,requestBuild:(A)=>{this.rebuildManager?.requestBuild(A)}}),this.config.autoRebuild)this.logger.debug("Auto-rebuild enabled"),this.rebuildManager.setupAutoRebuild();x.messaging.subscribe(mRx,async()=>{let A=await this.getInstructions();if(A)x.registerInstructions(A);return{success:!0}})}async onReady(x){if(!this.siteWorkspaceProvider)return;let B=await this.siteWorkspaceProvider.registerCmsWorkspace();await hRx(x,this.siteWorkspaceProvider,B)}getRegisteredHeadScripts(){return Array.from(this.headScripts.values())}async getTools(){if(!this.pluginContext||!this.rebuildManager)throw Error("Plugin context not initialized");let x=this.rebuildManager;return MRx(this.id,(B)=>x.requestBuild(B))}async getResources(){let x=this.getContext();return[{uri:"brain://site",name:"Site Metadata",description:"Site metadata \u2014 title, description, domain, URLs",mimeType:"application/json",handler:async()=>{let B=await dY(x.messaging.send,this.config.siteInfo);return{contents:[{uri:"brain://site",mimeType:"application/json",text:JSON.stringify({...B,domain:x.domain,siteUrl:x.siteUrl,previewUrl:x.previewUrl},null,2)}]}}},{uri:"site://routes",name:"Site Routes",description:"All registered routes with sections and templates",mimeType:"application/json",handler:async()=>{let B=this.routeRegistry.list();return{contents:[{uri:"site://routes",mimeType:"application/json",text:JSON.stringify(B.map((A)=>({id:A.id,path:A.path,title:A.title,description:A.description,sections:A.sections.map((w)=>({id:w.id,template:w.template}))})),null,2)}]}}},{uri:"site://templates",name:"View Templates",description:"All registered view templates",mimeType:"application/json",handler:async()=>{let B=x.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(B.map((A)=>({name:A.name,description:A.description,hasWebRenderer:!!A.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let x=this.getContext(),B="## Site Builder Actions\n- When the user asks to build, rebuild, publish, or build the website/site again, call `site-builder_build-site` immediately.\n- Every repeated build request requires a fresh `site-builder_build-site` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.",A=await dY(x.messaging.send,this.config.siteInfo);return`## Your Site
6327
+ `;var HE9=X.object({environment:X.enum(["preview","production"]),active:X.object({state:X.enum(["debouncing","queued","building"])}).optional(),lastSuccess:X.object({completedAt:X.string(),routesBuilt:X.number(),warnings:X.array(X.string())}).optional(),lastFailure:X.object({completedAt:X.string(),message:X.string()}).optional(),lastCancellation:X.object({completedAt:X.string(),message:X.string()}).optional()}),ORx=X.object({site:X.object({title:X.string(),previewUrl:X.string().optional(),liveUrl:X.string().optional()}),environments:X.array(HE9),managementUrl:X.string().optional()});function Y30(x){if(x.active)return x.active.state;if(x.lastCancellation)return"cancelled";if(x.lastFailure)return"failed";if(x.lastSuccess)return"current";return"not built"}function FE9(x){if(x.lastCancellation)return x.lastCancellation.message;if(x.lastFailure)return x.lastFailure.message;if(x.lastSuccess){let B=x.lastSuccess.warnings.length>0?` \xB7 ${x.lastSuccess.warnings.length} warning`:"";return`${x.lastSuccess.routesBuilt} routes${B}`}return"No completed build in this runtime"}function IRx(x){let B=x.environment?Y30(x.environment):"unavailable";return p5("div",{class:`pipeline-metric site-health-metric site-health-metric--${B}`},[p5("dt",{},[p5("span",{class:"site-health-dot","aria-hidden":"true"}),x.label]),p5("dd",{},B),x.environment?p5("small",{class:"muted"},FE9(x.environment)):null])}function X30(x,B,A="external"){return p5("a",{class:`widget-action widget-action--${A==="manage"?"primary":"secondary"}`,href:x,...A==="external"?{target:"_blank",rel:"noreferrer"}:{}},[p5("span",{},B),p5("span",{class:"widget-action-arrow","aria-hidden":"true"},A==="external"?"\u2197":"\u2192")])}function KE9(x){let B=ORx.safeParse(x.data);if(!B.success)return p5("p",{class:"muted"},"Site health is unavailable.");let A=B.data,w=A.environments.find((Z)=>Z.environment==="preview"),f=A.environments.find((Z)=>Z.environment==="production"),D=A.environments.filter((Z)=>Z.lastFailure!==void 0),$=[];if(A.site.previewUrl)$.push(X30(A.site.previewUrl,"Open preview"));if(A.site.liveUrl)$.push(X30(A.site.liveUrl,"Open live"));if(A.managementUrl)$.push(X30(A.managementUrl,"Open in CMS","manage"));return p5("div",{class:"pipeline-digest site-health-widget"},[p5("dl",{class:"pipeline-metrics"},[p5(IRx,{label:"Preview",environment:w}),p5(IRx,{label:"Live",environment:f})]),D.length>0?p5("section",{class:"pipeline-failures"},[p5("h4",{},"Needs attention"),...D.map((Z)=>p5("div",{class:"pipeline-failure",key:Z.environment},[p5("strong",{},Z.environment),p5("span",{},Z.lastFailure?.message)]))]):null,$.length>0?p5("nav",{class:"widget-actions","aria-label":"Site actions"},$):null])}function qE9(x){let B=ORx.parse(x),A=B.environments.find((D)=>D.environment==="preview"),w=B.environments.find((D)=>D.environment==="production"),f=B.environments.filter((D)=>D.lastFailure!==void 0).length;return{digest:[{label:"Preview",value:A?Y30(A):"unavailable",...A?.lastFailure?{tone:"warn"}:{tone:"good"}},{label:"Live",value:w?Y30(w):"unavailable",...w?.lastFailure?{tone:"warn"}:{tone:"good"}}],needsOperator:f}}async function hRx(x,B,A){await x.dashboard.registerWidget({id:"site-health",title:"Site health",description:"Preview and live build status",group:"publishing",section:"sidebar",priority:50,rendererName:"SiteHealthWidget",visibility:"admin",component:KE9,clientStyles:NRx,dataProvider:async()=>({...await B.getSnapshot(),...A?{managementUrl:A}:{}}),digestProvider:qE9})}var zE9=X.object({id:X.string(),template:X.string(),content:X.unknown().optional(),dataQuery:X.looseObject({entityType:X.string().optional(),template:X.string().optional(),query:X.looseObject({id:X.string().optional(),limit:X.number().optional(),offset:X.number().optional()}).optional()}).optional(),order:X.number().optional()}),bE9=X.object({show:X.boolean().default(!1),label:X.string().optional(),slot:X.enum(N_).default("primary"),priority:X.number().min(0).max(100).default(50)}).optional(),VE9=X.object({id:X.string(),path:X.string(),title:X.string().default(""),pageLabel:X.string().optional(),description:X.string().default(""),sections:X.array(zE9).default([]),layout:X.string().default("default"),fullscreen:X.boolean().optional(),pluginId:X.string().optional(),sourceEntityType:X.string().optional(),external:X.boolean().optional(),navigation:bE9}),RRx=X.object({previewOutputDir:X.string().describe("Output directory for preview builds").default("./dist/site-preview"),productionOutputDir:X.string().describe("Output directory for production builds").default("./dist/site-production"),sharedImagesDir:X.string().describe("Shared directory for optimized images (used by both preview and production)").default("./dist/images"),workingDir:X.string().optional().describe("Working directory for builds").default("./.preact-work"),siteInfo:Fz.default({title:"Brain",description:"A knowledge management system"}),themeCSS:X.string().describe("Custom CSS theme overrides to inject into builds").optional(),analyticsScript:X.string().describe("Analytics tracking script to inject into page head (e.g., Cloudflare Web Analytics)").optional(),templates:X.any().optional().describe("Template definitions to register"),routes:X.array(VE9).optional().describe("Routes to register"),layouts:X.record(X.string(),X.any()).optional().describe("Layout components (at least 'default' required)"),autoRebuild:X.boolean().default(!0).describe("Automatically rebuild site when content changes"),rebuildDebounce:X.number().min(100).describe("Debounce time in ms before triggering site rebuild after content changes").default(5000),entityDisplay:X.record(X.string(),X.object({label:X.string().describe("Display label for entity type (e.g., 'Essay')"),pluralName:X.string().optional().describe("URL path segment (defaults to label.toLowerCase() + 's')"),layout:X.string().optional().describe("Layout name for this entity type's generated routes (defaults to 'default')"),paginate:X.boolean().optional().describe("Enable pagination for list pages"),pageSize:X.number().optional().describe("Items per page (default: 10)"),navigation:X.object({show:X.boolean().optional().describe("Show in navigation"),slot:X.enum(N_).optional().describe("Navigation slot (primary or secondary)"),priority:X.number().min(0).max(100).optional().describe("Navigation priority (0-100)")}).optional().describe("Navigation settings for this entity type")})).optional().describe("Display metadata per entity type \u2014 label, plural name, layout, pagination, navigation slot. Consulted when auto-generating routes for active entity plugins."),staticAssets:X.record(X.string(),X.string()).optional().describe("Static files to write to the output directory at build time. Keys are output paths (e.g. '/canvases/tree.js'), values are file contents as strings. Typically supplied by a SitePackage via text imports.")});var yRx={name:"@brains/site-builder-plugin",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Static site generation plugin for Brain system",dependencies:{"@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-engine":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*","@tailwindcss/typography":"^0.5.20",preact:"^10.27.2","preact-render-to-string":"^6.7.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{clean:"rm -rf dist",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class W30 extends D8{siteBuilder;pluginContext;_routeRegistry;_slotRegistry;profileService;layouts;rebuildManager;buildStatusService;siteWorkspaceProvider;headScripts=new Map;get routeRegistry(){if(!this._routeRegistry)throw Error("RouteRegistry not initialized - plugin not registered");return this._routeRegistry}constructor(x={}){let B=x.layouts??{};super("site-builder",yRx,{...x,layouts:B},RRx);this.layouts=B}async onRegister(x){if(this.pluginContext=x,this._routeRegistry=new cRx(x.logger),this._slotRegistry=new CRx,x.messaging.subscribe(O4.slotRegister,async(A)=>{let{slotName:w,pluginId:f,render:D,priority:$}=A.payload;return this._slotRegistry?.register(w,{pluginId:f,render:D,...$!==void 0&&{priority:$}}),{success:!0}}),x.messaging.subscribe(O4.headScriptRegister,async(A)=>{let{pluginId:w,script:f}=A.payload;return this.headScripts.set(w,f),{success:!0}}),x.entities.registerDataSource(new $30(this._routeRegistry,x.logger.child("NavigationDataSource"))),this.profileService={getProfile:()=>x.identity.getProfile()},this.buildStatusService=new Z30(x.runtimeState,x.jobs),await this.buildStatusService.initialize(),PRx(x,this._routeRegistry,this.logger),this.config.templates)x.templates.register(this.config.templates);if(this.config.routes)AC(this.config.routes,this.id,this.routeRegistry);let B={entityService:x.entityService,sendMessage:x.messaging.send,resolveTemplateContent:(A,w)=>x.templates.resolve(A,w),getViewTemplate:(A)=>x.views.get(A),listViewTemplateNames:()=>x.views.list().map((A)=>A.name)};if(this.siteBuilder=nY.createFresh(x.logger.child("SiteBuilder"),B,this.routeRegistry,this.profileService,void 0,this.config.entityDisplay),x.jobs.registerHandler("site-build",new D30(this.logger.child("SiteBuildJobHandler"),x.messaging.send,{siteBuilder:this.siteBuilder,layouts:this.layouts,defaultSiteConfig:this.config.siteInfo,sharedImagesDir:this.config.sharedImagesDir,siteUrl:x.siteUrl,previewUrl:x.previewUrl,localSiteUrl:x.localSiteUrl,preferLocalUrls:x.preferLocalUrls,themeCSS:this.config.themeCSS,slots:this._slotRegistry,getHeadScripts:()=>this.getRegisteredHeadScripts(),...this.config.staticAssets&&{staticAssets:this.config.staticAssets},statusService:this.buildStatusService})),this.rebuildManager=new f30(this.config,x,this.id,this.logger,this.buildStatusService),this.siteWorkspaceProvider=new Q30({context:x,config:this.config,routeRegistry:this.routeRegistry,statusService:this.buildStatusService,requestBuild:(A)=>{this.rebuildManager?.requestBuild(A)}}),this.config.autoRebuild)this.logger.debug("Auto-rebuild enabled"),this.rebuildManager.setupAutoRebuild();x.messaging.subscribe(mRx,async()=>{let A=await this.getInstructions();if(A)x.registerInstructions(A);return{success:!0}})}async onReady(x){if(!this.siteWorkspaceProvider)return;let B=await this.siteWorkspaceProvider.registerCmsWorkspace();await hRx(x,this.siteWorkspaceProvider,B)}getRegisteredHeadScripts(){return Array.from(this.headScripts.values())}async getTools(){if(!this.pluginContext||!this.rebuildManager)throw Error("Plugin context not initialized");let x=this.rebuildManager;return MRx(this.id,(B)=>x.requestBuild(B))}async getResources(){let x=this.getContext();return[{uri:"brain://site",name:"Site Metadata",description:"Site metadata \u2014 title, description, domain, URLs",mimeType:"application/json",handler:async()=>{let B=await dY(x.messaging.send,this.config.siteInfo);return{contents:[{uri:"brain://site",mimeType:"application/json",text:JSON.stringify({...B,domain:x.domain,siteUrl:x.siteUrl,previewUrl:x.previewUrl},null,2)}]}}},{uri:"site://routes",name:"Site Routes",description:"All registered routes with sections and templates",mimeType:"application/json",handler:async()=>{let B=this.routeRegistry.list();return{contents:[{uri:"site://routes",mimeType:"application/json",text:JSON.stringify(B.map((A)=>({id:A.id,path:A.path,title:A.title,description:A.description,sections:A.sections.map((w)=>({id:w.id,template:w.template}))})),null,2)}]}}},{uri:"site://templates",name:"View Templates",description:"All registered view templates",mimeType:"application/json",handler:async()=>{let B=x.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(B.map((A)=>({name:A.name,description:A.description,hasWebRenderer:!!A.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let x=this.getContext(),B="## Site Builder Actions\n- When the user asks to build, rebuild, publish, or build the website/site again, call `site-builder_build-site` immediately.\n- Every repeated build request requires a fresh `site-builder_build-site` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.",A=await dY(x.messaging.send,this.config.siteInfo);return`## Your Site
6328
6328
  ${[`**Title:** ${A.title}`,`**Description:** ${A.description}`,x.domain&&`**Domain:** ${x.domain}`,x.siteUrl&&`**URL:** ${x.siteUrl}`].filter(Boolean).join(`
6329
6329
  `)}
6330
6330
 
6331
6331
  ## Site Builder Actions
6332
6332
  - When the user asks to build, rebuild, publish, or build the website/site again, call \`site-builder_build-site\` immediately.
6333
- - Every repeated build request requires a fresh \`site-builder_build-site\` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.`}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),await this.rebuildManager?.dispose(),await this.siteBuilder?.cancelActiveBuilds(),delete this.rebuildManager,delete this.siteBuilder,this.logger.debug("Cleaned up all event subscriptions")}}function H30(x={}){return new W30(x)}var F30=X.object({routeId:X.string(),sectionId:X.string()}),GE9=X.object({routeId:X.string(),sectionId:X.string()}),I_=j8.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:GE9});class gRx extends ox{constructor(){super({entityType:"site-content",purpose:"A content section bound to a route on the published site.",schema:I_,frontmatterSchema:F30})}toMarkdown(x){let B=this.extractBody(x.content);return this.buildMarkdown(B,x.metadata)}fromMarkdown(x){return{content:x,entityType:"site-content",metadata:this.parseFrontmatter(x)}}}var K30=new gRx;var wC=X.object({routeId:X.string().optional().describe("Optional: specific route filter"),sectionId:X.string().optional().describe("Optional: specific section filter"),dryRun:X.boolean().optional().default(!1).describe("Optional: preview changes without executing"),force:X.boolean().optional().default(!1).describe("Force regeneration even if content exists")}),nA5=X.object({jobs:X.array(X.object({jobId:X.string(),routeId:X.string(),sectionId:X.string()})),totalSections:X.number(),queuedSections:X.number(),skippedSections:X.number().optional(),batchId:X.string().optional()});var EE9=X.looseObject({id:X.string(),template:X.string().optional(),content:X.unknown().optional()}),jE9=X.looseObject({id:X.string(),title:X.string().optional(),description:X.string().optional(),sections:X.array(EE9)}),_E9=X.array(jE9);class q30{context;constructor(x){this.context=x}createJobOptions(x,B){if(!x)return;return{source:x.operationType??B,rootJobId:x.rootJobId??`${B}-${Date.now()}`,metadata:{operationType:x.operationType??"content_operations",progressToken:x.progressToken,pluginId:x.pluginId??"site-content",interfaceType:x.interfaceType,conversationId:x.conversationId,channelId:x.channelId,requestedByActor:x.requestedByActor,requestedByUserId:x.requestedByUserId,requestedByInterface:x.requestedByInterface}}}async fetchRoutes(){let x=await this.context.messaging.send({type:O4.routesList,payload:{}});if("noop"in x)throw Error("No handler for site-builder:routes:list \u2014 is site-builder plugin loaded?");if(!x.success||!x.data)throw Error("Failed to fetch routes from site-builder");let B=_E9.safeParse(x.data);if(!B.success)throw Error("Failed to parse routes from site-builder");return B.data}async generate(x,B,A){let w=this.context.logger.child("SiteContentOperations"),f=await this.fetchRoutes(),D=f;if(x.routeId){if(D=f.filter((W)=>W.id===x.routeId),D.length===0)throw Error(`Route not found: ${x.routeId}`)}let $=[];for(let W of D)for(let H of W.sections){if(x.sectionId&&H.id!==x.sectionId)continue;if(H.content){w.debug("Section has static content, skipping",{routeId:W.id,sectionId:H.id});continue}if(H.template){let F=this.context.templates.getCapabilities(H.template);if(!F){w.warn("Template not found, skipping section",{routeId:W.id,sectionId:H.id,templateName:H.template});continue}if(!F.canGenerate){w.debug("Template doesn't support generation, skipping",{routeId:W.id,sectionId:H.id,templateName:H.template,capabilities:F});continue}}else{w.debug("Section has no template, skipping",{routeId:W.id,sectionId:H.id});continue}if(!x.force&&!x.dryRun){let F=`${W.id}:${H.id}`;if(await this.context.entityService.getEntity({entityType:"site-content",id:F})){w.debug("Content already exists, skipping",{routeId:W.id,sectionId:H.id});continue}}$.push({route:W,section:H})}let Z=$.length;if(x.dryRun)return{jobs:[],totalSections:Z,queuedSections:Z,batchId:`dry-run-${Date.now()}`};let Q=[],Y=[];for(let{route:W,section:H}of $){let F=`${W.id}:${H.id}`,K=H.template,q={routeId:W.id,sectionId:H.id,entityId:F,entityType:"site-content",templateName:K,context:{prompt:typeof H.content==="string"?H.content:void 0,data:{routeId:W.id,sectionId:H.id,routeTitle:W.title,routeDescription:W.description,sectionContent:H.content},conversationId:"system"},siteConfig:B};Y.push({type:O_.contentGeneration,data:q})}if(Y.length>0){let W=this.createJobOptions(A,"site:content-generation"),H=await this.context.jobs.enqueueBatch(Y,W);for(let F=0;F<$.length;F++){let K=$[F];if(K)Q.push({jobId:`${H}-${F}`,routeId:K.route.id,sectionId:K.section.id})}return{jobs:Q,totalSections:Z,queuedSections:Q.length,batchId:H}}return{jobs:[],totalSections:Z,queuedSections:0,batchId:`empty-${Date.now()}`}}}class z30{siteConfig;operations;constructor(x,B){this.siteConfig=B,this.operations=new q30(x)}async generateContent(x,B){let A=wC.parse(x);return this.operations.generate(A,this.siteConfig,B)}}var PE9=X.object({namespace:X.string(),sections:X.record(X.string(),X.any())}),TRx=X.custom((x)=>PE9.safeParse(x).success),b30=X.object({definitions:X.union([TRx,X.array(TRx)]).optional()});function pRx(x,B){return[E1(B,"generate","Generate content for all routes, a specific route, or a specific section",wC,async(A,w)=>{let f=x();if(!f)return{success:!1,error:"Site content service not initialized"};if(A.sectionId&&!A.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let D=tH(w),$={rootJobId:`generate-${Date.now()}`,progressToken:w.progressToken,pluginId:B,operationType:"content_operations",interfaceType:w.interfaceType,channelId:w.channelId,requestedByActor:w.actor,...D?{requestedByUserId:D}:{},requestedByInterface:w.interfaceType},Z=await f.generateContent(A,$);return{success:!0,message:`Generated ${Z.queuedSections} of ${Z.totalSections} sections. ${Z.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:Z.batchId,jobsQueued:Z.queuedSections,totalSections:Z.totalSections,jobs:Z.jobs}}})]}var uRx={name:"@brains/site-content",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Site content entity and generation orchestration",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/site-composition":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class V30 extends D8{siteContentService;constructor(x={}){super("site-content",uRx,x,b30)}async onRegister(x){x.entities.register("site-content",I_,K30);for(let B of SRx(this.config.definitions))x.templates.register(fC(B),B.namespace);this.siteContentService=new z30(x)}async getTools(){return pRx(()=>this.siteContentService,this.id)}}function U30(x={}){return new V30(x)}var G30=X.enum(["linkedin"]),E30=X.enum(["generating","draft","queued","published","failed"]),iRx=X.enum(["post","deck"]),lRx=X.object({id:X.string().min(1).describe("Document entity ID")}),aB=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:G30.describe("Target platform"),status:E30,coverImageId:X.string().optional().describe("Image entity ID for post image"),documents:X.array(lRx).optional().describe("Document attachments for publishing"),publishedAt:X.string().datetime().optional(),platformPostId:X.string().optional().describe("ID from platform after publishing"),sourceEntityId:X.string().optional().describe("Source entity ID if auto-generated"),sourceEntityType:iRx.optional().describe("Source entity type (post, deck)")}),nRx=aB.extend({platform:G30.optional(),status:E30.optional()}),dRx=aB.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}"),error:X.string().optional()}),PZ=j8.extend({entityType:X.literal("social-post"),metadata:dRx}),DC=PZ.extend({frontmatter:aB,body:X.string()}),LE9=DC.extend({url:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional(),typeLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});class j30 extends ox{constructor(){super({entityType:"social-post",purpose:"A short post drafted for social media such as LinkedIn or X.",schema:PZ,frontmatterSchema:aB,supportsCoverImage:!0})}toMarkdown(x){let B,A={};try{A=this.parseFrontMatter(x.content,aB),B=this.extractBody(x.content)}catch{B=x.content}let w={...A,title:x.metadata.title,platform:x.metadata.platform,status:x.metadata.status,...x.metadata.publishedAt!==void 0&&{publishedAt:x.metadata.publishedAt},...x.metadata.platformPostId!==void 0&&{platformPostId:x.metadata.platformPostId}};return this.buildMarkdown(B,w)}fromMarkdown(x){let B=this.parseFrontMatter(x,nRx),A=B.platform??"linkedin",w=B.status??"draft",f=`${A}-${Gx(B.title)}`;return{content:x,entityType:"social-post",metadata:{title:B.title,slug:f,platform:A,status:w,publishedAt:B.publishedAt,platformPostId:B.platformPostId}}}parsePostFrontmatter(x){return this.parseFrontMatter(x.content,aB)}getPostContent(x){return this.extractBody(x.content)}createPostContent(x,B){return this.buildMarkdown(B,x)}buildStub(x){let A={title:x.title,platform:"linkedin",status:"generating"};return{content:this.buildMarkdown("",A),metadata:{title:x.title,slug:`linkedin-${Gx(x.title)}`,platform:"linkedin",status:"generating"}}}}var c1=new j30;var sRx=X.enum(["linkedin"]),rRx=X.enum(["generating","draft","queued","published","failed"]),kE9=X.enum(["post","deck"]),sB=X.string().nullable().default(null),aRx=X.number().nullable().default(null),ME9=X.union([X.enum(["public","shared","restricted"]),X.literal("private")]).optional().transform((x)=>{if(x===void 0)return"public";if(x==="private")return"restricted";return x}),vE9=X.object({id:X.string().min(1)}),NE9=X.object({title:X.string(),platform:sRx,status:rRx,coverImageId:sB,documents:X.array(vE9).nullable().default(null),publishedAt:sB,platformPostId:sB,sourceEntityId:sB,sourceEntityType:kE9.nullable().default(null)}),IE9=X.object({title:X.string(),platform:sRx,status:rRx,publishedAt:sB,platformPostId:sB,slug:X.string(),error:sB}),$C=X.object({id:X.string(),entityType:X.literal("social-post"),content:X.string(),created:X.string(),updated:X.string(),visibility:ME9,metadata:IE9,contentHash:X.string(),frontmatter:NE9,body:X.string(),url:sB,listUrl:sB,listLabel:sB,typeLabel:sB,coverImageUrl:sB,coverImageWidth:aRx,coverImageHeight:aRx});var OE9=X.looseObject({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional(),baseUrl:X.string().optional(),platform:X.enum(["linkedin"]).optional(),status:X.enum(["generating","draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),hE9=X.looseObject({entityType:X.string().optional(),query:OE9.optional()});function oRx(x){let B=G9(x.content,aB);return DC.parse({...x,frontmatter:B.metadata,body:B.content})}class ZC extends j7{id="social-media:posts";name="Social Post DataSource";description="Fetches and transforms social post entities for queue management and publishing";config={entityType:"social-post",defaultSort:[{field:"publishedAt",direction:"desc",nullsFirst:!0},{field:"created",direction:"desc"}],defaultLimit:100};constructor(x){super(x);this.logger.debug("SocialPostDataSource initialized")}parseQuery(x){let B=hE9.parse(x);return{entityType:B.entityType??this.config.entityType,query:B.query??{}}}transformEntity(x){return oRx(x)}buildDetailResult(x,B){return{post:x}}buildListResult(x,B,A){return{posts:x.map((w)=>$C.parse(w)),totalCount:B?.totalItems??x.length,pagination:B,baseUrl:A.baseUrl??null}}async fetch(x,B,A){let{query:w}=this.parseQuery(x),f=A.entityService;if(w.nextInQueue)return this.fetchNextInQueue(B,f);if(w.id){let{item:W}=await this.fetchDetail(w.id,f);return B.parse(this.buildDetailResult(W,null))}let D={};if(w.platform)D.platform=w.platform;if(w.status)D.status=w.status;let $=Object.keys(D).length>0,Z=w.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:Q,pagination:Y}=await this.fetchList(w,f,{...$&&{filter:{metadata:D}},sortFields:Z});return B.parse(this.buildListResult(Q,Y,w))}async fetchNextInQueue(x,B){let w=(await B.listEntities({entityType:this.config.entityType,options:{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}}))[0],f=w?oRx(w):null;return x.parse({post:f})}}var tRx=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional(),apiVersion:X.string().regex(/^\d{6}$/).optional()}),_30=X.object({linkedin:tRx.optional(),publishInterval:X.number().default(3600000),enabled:X.boolean().default(!0),defaultPrompt:X.string().default("Create an engaging social media post that drives engagement"),maxRetries:X.number().default(3),autoGenerateOnBlogPublish:X.boolean().default(!1)});import{jsxDEV as x5,Fragment as RE9}from"preact/jsx-dev-runtime";var QC=({posts:x,pageTitle:B,pagination:A,baseUrl:w})=>{let f=B??"Social Posts",D=A?.totalItems??x.length,$=`Browse all ${D} social ${D===1?"post":"posts"}`;return x5(RE9,{children:[x5(z9,{title:f,description:$},void 0,!1,void 0,this),x5("div",{className:"social-post-list bg-theme",children:x5("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[x5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:f},void 0,!1,void 0,this),x.length===0?x5("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):x5("ul",{className:"space-y-6",children:x.map((Z)=>x5("li",{children:x5(r8,{href:Z.url,variant:"horizontal",children:x5("div",{className:"flex flex-col sm:flex-row gap-4",children:[Z.coverImageUrl&&x5("img",{src:Z.coverImageUrl,alt:Z.frontmatter.title,className:"w-full sm:w-24 h-48 sm:h-24 object-cover rounded-lg shrink-0"},void 0,!1,void 0,this),x5("div",{className:"flex-1 min-w-0",children:[x5("div",{className:"flex items-start justify-between gap-4 mb-2",children:[x5("h2",{className:"text-lg font-semibold text-heading",children:Z.frontmatter.title},void 0,!1,void 0,this),x5("time",{className:"text-sm text-theme-muted shrink-0",children:G6(Z.frontmatter.publishedAt??Z.created,{style:"medium"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x5("div",{className:"flex items-center gap-2 mb-3",children:[x5(m2,{status:Z.frontmatter.status},void 0,!1,void 0,this),x5("span",{className:"text-xs text-theme-muted uppercase",children:Z.frontmatter.platform},void 0,!1,void 0,this),x5("span",{className:"text-xs text-theme-muted font-mono",children:Z.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x5("p",{className:"text-theme leading-relaxed",children:r$(Z.body,200)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},Z.id,!1,void 0,this))},void 0,!1,void 0,this),A&&A.totalPages>1&&x5(oD,{currentPage:A.currentPage,totalPages:A.totalPages,baseUrl:w??"/social-posts"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as B5,Fragment as yE9}from"preact/jsx-dev-runtime";var XC=({post:x})=>{let B=`Social Post - ${x.frontmatter.platform}`,A=x.body.slice(0,160),w=[{label:"Home",href:"/"},{label:x.listLabel,href:x.listUrl},{label:x.frontmatter.platform}];return B5(yE9,{children:[B5(z9,{title:B,description:A},void 0,!1,void 0,this),B5("section",{className:"social-post-detail",children:B5("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:B5("div",{className:"max-w-3xl mx-auto",children:[B5(nf,{items:w},void 0,!1,void 0,this),B5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:x.frontmatter.title},void 0,!1,void 0,this),B5("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[B5(m2,{status:x.frontmatter.status},void 0,!1,void 0,this),B5("span",{className:"text-sm text-theme-muted uppercase",children:x.frontmatter.platform},void 0,!1,void 0,this),B5("span",{className:"text-sm text-theme-muted font-mono",children:x.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x.coverImageUrl&&x.coverImageWidth&&x.coverImageHeight&&B5(Qz,{src:x.coverImageUrl,alt:x.frontmatter.title,width:x.coverImageWidth,height:x.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),B5(r8,{className:"p-8 mb-8",children:B5("p",{className:"text-lg text-theme leading-relaxed whitespace-pre-wrap",children:x.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),B5("div",{className:"space-y-4 text-sm text-theme-muted",children:[B5("div",{children:[B5("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",G6(x.created,{style:"long",includeTime:!0})]},void 0,!0,void 0,this),x.frontmatter.publishedAt&&B5("div",{children:[B5("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",G6(x.frontmatter.publishedAt,{style:"long",includeTime:!0})]},void 0,!0,void 0,this),x.frontmatter.platformPostId&&B5("div",{children:B5("a",{href:`https://www.linkedin.com/feed/update/${x.frontmatter.platformPostId}`,target:"_blank",rel:"noopener noreferrer",className:"text-brand hover:underline",children:"View on LinkedIn \u2192"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};function h_(x){return`social-media:${x}`}var CE9=X.union([X.boolean(),X.object({generate:X.boolean().optional(),prompt:X.string().optional()})]),P30=X.object({prompt:X.string().optional(),platform:X.enum(["linkedin"]).optional(),sourceEntityType:X.enum(["post","deck"]).optional(),sourceEntityId:X.string().optional(),title:X.string().optional().describe("Required when content is provided directly"),content:X.string().optional(),addToQueue:X.boolean().optional(),generateImage:X.boolean().optional().describe("Auto-generate cover image for post"),coverImage:CE9.optional().describe("Generic cover image generation request")}),cE9=iD.extend({slug:X.string().optional()});class aY extends UA{constructor(x,B){super(x,B,{schema:P30,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(x,B){let A=x.platform??"linkedin",w=x.addToQueue??!1,{prompt:f,sourceEntityType:D,sourceEntityId:$}=x,{content:Z,title:Q}=x,Y=Z&&Q?"":i3(await y2(this.context.entityService)),W={representedIdentity:"anchor",...Y&&{styleGuide:{voice:Y}}};if(Z&&Q)await this.reportProgress(B,{progress:50,message:"Using provided content"});else if(Z&&!Q){await this.reportProgress(B,{progress:10,message:"Shaping content with AI"});let E=await this.context.ai.generate({prompt:Z,templateName:h_(A),...W});Q=E.title,Z=E.content,await this.reportProgress(B,{progress:50,message:"Social post shaped from content"})}else if($&&D){await this.reportProgress(B,{progress:10,message:`Fetching source ${D}`});let E=await this.context.entityService.getEntity({entityType:D,id:$});if(!E)this.failEarly(`Source entity not found: ${D}/${$}`);await this.reportProgress(B,{progress:30,message:"Generating social post from source content"});let L=X.looseObject({slug:X.string()}).safeParse(E.metadata),N=L.success?L.data.slug:$,y=await this.context.ai.generate({prompt:`Create an engaging ${A} post to promote this ${D}:
6333
+ - Every repeated build request requires a fresh \`site-builder_build-site\` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.`}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),await this.rebuildManager?.dispose(),await this.siteBuilder?.cancelActiveBuilds(),delete this.rebuildManager,delete this.siteBuilder,this.logger.debug("Cleaned up all event subscriptions")}}function H30(x={}){return new W30(x)}var F30=X.object({routeId:X.string(),sectionId:X.string()}),GE9=X.object({routeId:X.string(),sectionId:X.string()}),I_=j8.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:GE9});class gRx extends ox{constructor(){super({entityType:"site-content",purpose:"A content section bound to a route on the published site.",schema:I_,frontmatterSchema:F30})}toMarkdown(x){let B=this.extractBody(x.content);return this.buildMarkdown(B,x.metadata)}fromMarkdown(x){return{content:x,entityType:"site-content",metadata:this.parseFrontmatter(x)}}}var K30=new gRx;var wC=X.object({routeId:X.string().optional().describe("Optional: specific route filter"),sectionId:X.string().optional().describe("Optional: specific section filter"),dryRun:X.boolean().optional().default(!1).describe("Optional: preview changes without executing"),force:X.boolean().optional().default(!1).describe("Force regeneration even if content exists")}),nA5=X.object({jobs:X.array(X.object({jobId:X.string(),routeId:X.string(),sectionId:X.string()})),totalSections:X.number(),queuedSections:X.number(),skippedSections:X.number().optional(),batchId:X.string().optional()});var EE9=X.looseObject({id:X.string(),template:X.string().optional(),content:X.unknown().optional()}),jE9=X.looseObject({id:X.string(),title:X.string().optional(),description:X.string().optional(),sections:X.array(EE9)}),_E9=X.array(jE9);class q30{context;constructor(x){this.context=x}createJobOptions(x,B){if(!x)return;return{source:x.operationType??B,rootJobId:x.rootJobId??`${B}-${Date.now()}`,metadata:{operationType:x.operationType??"content_operations",progressToken:x.progressToken,pluginId:x.pluginId??"site-content",interfaceType:x.interfaceType,conversationId:x.conversationId,channelId:x.channelId,requestedByActor:x.requestedByActor,requestedByUserId:x.requestedByUserId,requestedByInterface:x.requestedByInterface}}}async fetchRoutes(){let x=await this.context.messaging.send({type:O4.routesList,payload:{}});if("noop"in x)throw Error("No handler for site-builder:routes:list \u2014 is site-builder plugin loaded?");if(!x.success||!x.data)throw Error("Failed to fetch routes from site-builder");let B=_E9.safeParse(x.data);if(!B.success)throw Error("Failed to parse routes from site-builder");return B.data}async generate(x,B,A){let w=this.context.logger.child("SiteContentOperations"),f=await this.fetchRoutes(),D=f;if(x.routeId){if(D=f.filter((W)=>W.id===x.routeId),D.length===0)throw Error(`Route not found: ${x.routeId}`)}let $=[];for(let W of D)for(let H of W.sections){if(x.sectionId&&H.id!==x.sectionId)continue;if(H.content){w.debug("Section has static content, skipping",{routeId:W.id,sectionId:H.id});continue}if(H.template){let F=this.context.templates.getCapabilities(H.template);if(!F){w.warn("Template not found, skipping section",{routeId:W.id,sectionId:H.id,templateName:H.template});continue}if(!F.canGenerate){w.debug("Template doesn't support generation, skipping",{routeId:W.id,sectionId:H.id,templateName:H.template,capabilities:F});continue}}else{w.debug("Section has no template, skipping",{routeId:W.id,sectionId:H.id});continue}if(!x.force&&!x.dryRun){let F=`${W.id}:${H.id}`;if(await this.context.entityService.getEntity({entityType:"site-content",id:F})){w.debug("Content already exists, skipping",{routeId:W.id,sectionId:H.id});continue}}$.push({route:W,section:H})}let Z=$.length;if(x.dryRun)return{jobs:[],totalSections:Z,queuedSections:Z,batchId:`dry-run-${Date.now()}`};let Q=[],Y=[];for(let{route:W,section:H}of $){let F=`${W.id}:${H.id}`,K=H.template,q={routeId:W.id,sectionId:H.id,entityId:F,entityType:"site-content",templateName:K,context:{prompt:typeof H.content==="string"?H.content:void 0,data:{routeId:W.id,sectionId:H.id,routeTitle:W.title,routeDescription:W.description,sectionContent:H.content},conversationId:"system"},siteConfig:B};Y.push({type:O_.contentGeneration,data:q})}if(Y.length>0){let W=this.createJobOptions(A,"site:content-generation"),H=await this.context.jobs.enqueueBatch(Y,W);for(let F=0;F<$.length;F++){let K=$[F];if(K)Q.push({jobId:`${H}-${F}`,routeId:K.route.id,sectionId:K.section.id})}return{jobs:Q,totalSections:Z,queuedSections:Q.length,batchId:H}}return{jobs:[],totalSections:Z,queuedSections:0,batchId:`empty-${Date.now()}`}}}class z30{siteConfig;operations;constructor(x,B){this.siteConfig=B,this.operations=new q30(x)}async generateContent(x,B){let A=wC.parse(x);return this.operations.generate(A,this.siteConfig,B)}}var PE9=X.object({namespace:X.string(),sections:X.record(X.string(),X.any())}),TRx=X.custom((x)=>PE9.safeParse(x).success),b30=X.object({definitions:X.union([TRx,X.array(TRx)]).optional()});function pRx(x,B){return[E1(B,"generate","Generate content for all routes, a specific route, or a specific section",wC,async(A,w)=>{let f=x();if(!f)return{success:!1,error:"Site content service not initialized"};if(A.sectionId&&!A.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let D=tH(w),$={rootJobId:`generate-${Date.now()}`,progressToken:w.progressToken,pluginId:B,operationType:"content_operations",interfaceType:w.interfaceType,channelId:w.channelId,requestedByActor:w.actor,...D?{requestedByUserId:D}:{},requestedByInterface:w.interfaceType},Z=await f.generateContent(A,$);return{success:!0,message:`Generated ${Z.queuedSections} of ${Z.totalSections} sections. ${Z.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:Z.batchId,jobsQueued:Z.queuedSections,totalSections:Z.totalSections,jobs:Z.jobs}}})]}var uRx={name:"@brains/site-content",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Site content entity and generation orchestration",dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/site-composition":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class V30 extends D8{siteContentService;constructor(x={}){super("site-content",uRx,x,b30)}async onRegister(x){x.entities.register("site-content",I_,K30);for(let B of SRx(this.config.definitions))x.templates.register(fC(B),B.namespace);this.siteContentService=new z30(x)}async getTools(){return pRx(()=>this.siteContentService,this.id)}}function U30(x={}){return new V30(x)}var G30=X.enum(["linkedin"]),E30=X.enum(["generating","draft","queued","published","failed"]),iRx=X.enum(["post","deck"]),lRx=X.object({id:X.string().min(1).describe("Document entity ID")}),aB=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:G30.describe("Target platform"),status:E30,coverImageId:X.string().optional().describe("Image entity ID for post image"),documents:X.array(lRx).optional().describe("Document attachments for publishing"),publishedAt:X.string().datetime().optional(),platformPostId:X.string().optional().describe("ID from platform after publishing"),sourceEntityId:X.string().optional().describe("Source entity ID if auto-generated"),sourceEntityType:iRx.optional().describe("Source entity type (post, deck)")}),nRx=aB.extend({platform:G30.optional(),status:E30.optional()}),dRx=aB.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}"),error:X.string().optional()}),PZ=j8.extend({entityType:X.literal("social-post"),metadata:dRx}),DC=PZ.extend({frontmatter:aB,body:X.string()}),LE9=DC.extend({url:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional(),typeLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});class j30 extends ox{constructor(){super({entityType:"social-post",purpose:"A short post drafted for social media such as LinkedIn or X.",schema:PZ,frontmatterSchema:aB,supportsCoverImage:!0})}toMarkdown(x){let B,A={};try{A=this.parseFrontMatter(x.content,aB),B=this.extractBody(x.content)}catch{B=x.content}let w={...A,title:x.metadata.title,platform:x.metadata.platform,status:x.metadata.status,...x.metadata.publishedAt!==void 0&&{publishedAt:x.metadata.publishedAt},...x.metadata.platformPostId!==void 0&&{platformPostId:x.metadata.platformPostId}};return this.buildMarkdown(B,w)}fromMarkdown(x){let B=this.parseFrontMatter(x,nRx),A=B.platform??"linkedin",w=B.status??"draft",f=`${A}-${Gx(B.title)}`;return{content:x,entityType:"social-post",metadata:{title:B.title,slug:f,platform:A,status:w,publishedAt:B.publishedAt,platformPostId:B.platformPostId}}}parsePostFrontmatter(x){return this.parseFrontMatter(x.content,aB)}getPostContent(x){return this.extractBody(x.content)}createPostContent(x,B){return this.buildMarkdown(B,x)}buildStub(x){let A={title:x.title,platform:"linkedin",status:"generating"};return{content:this.buildMarkdown("",A),metadata:{title:x.title,slug:`linkedin-${Gx(x.title)}`,platform:"linkedin",status:"generating"}}}}var c1=new j30;var sRx=X.enum(["linkedin"]),rRx=X.enum(["generating","draft","queued","published","failed"]),kE9=X.enum(["post","deck"]),sB=X.string().nullable().default(null),aRx=X.number().nullable().default(null),ME9=X.union([X.enum(["public","shared","restricted"]),X.literal("private")]).optional().transform((x)=>{if(x===void 0)return"public";if(x==="private")return"restricted";return x}),vE9=X.object({id:X.string().min(1)}),NE9=X.object({title:X.string(),platform:sRx,status:rRx,coverImageId:sB,documents:X.array(vE9).nullable().default(null),publishedAt:sB,platformPostId:sB,sourceEntityId:sB,sourceEntityType:kE9.nullable().default(null)}),IE9=X.object({title:X.string(),platform:sRx,status:rRx,publishedAt:sB,platformPostId:sB,slug:X.string(),error:sB}),$C=X.object({id:X.string(),entityType:X.literal("social-post"),content:X.string(),created:X.string(),updated:X.string(),visibility:ME9,metadata:IE9,contentHash:X.string(),frontmatter:NE9,body:X.string(),url:sB,listUrl:sB,listLabel:sB,typeLabel:sB,coverImageUrl:sB,coverImageWidth:aRx,coverImageHeight:aRx});var OE9=X.looseObject({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional(),baseUrl:X.string().optional(),platform:X.enum(["linkedin"]).optional(),status:X.enum(["generating","draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),hE9=X.looseObject({entityType:X.string().optional(),query:OE9.optional()});function oRx(x){let B=G9(x.content,aB);return DC.parse({...x,frontmatter:B.metadata,body:B.content})}class ZC extends j7{id="social-media:posts";name="Social Post DataSource";description="Fetches and transforms social post entities for queue management and publishing";config={entityType:"social-post",defaultSort:[{field:"publishedAt",direction:"desc",nullsFirst:!0},{field:"created",direction:"desc"}],defaultLimit:100};constructor(x){super(x);this.logger.debug("SocialPostDataSource initialized")}parseQuery(x){let B=hE9.parse(x);return{entityType:B.entityType??this.config.entityType,query:B.query??{}}}transformEntity(x){return oRx(x)}buildDetailResult(x,B){return{post:x}}buildListResult(x,B,A){return{posts:x.map((w)=>$C.parse(w)),totalCount:B?.totalItems??x.length,pagination:B,baseUrl:A.baseUrl??null}}async fetch(x,B,A){let{query:w}=this.parseQuery(x),f=A.entityService;if(w.nextInQueue)return this.fetchNextInQueue(B,f);if(w.id){let{item:W}=await this.fetchDetail(w.id,f);return B.parse(this.buildDetailResult(W,null))}let D={};if(w.platform)D.platform=w.platform;if(w.status)D.status=w.status;let $=Object.keys(D).length>0,Z=w.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:Q,pagination:Y}=await this.fetchList(w,f,{...$&&{filter:{metadata:D}},sortFields:Z});return B.parse(this.buildListResult(Q,Y,w))}async fetchNextInQueue(x,B){let w=(await B.listEntities({entityType:this.config.entityType,options:{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}}))[0],f=w?oRx(w):null;return x.parse({post:f})}}var tRx=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional(),apiVersion:X.string().regex(/^\d{6}$/).optional()}),_30=X.object({linkedin:tRx.optional(),publishInterval:X.number().default(3600000),enabled:X.boolean().default(!0),defaultPrompt:X.string().default("Create an engaging social media post that drives engagement"),maxRetries:X.number().default(3),autoGenerateOnBlogPublish:X.boolean().default(!1)});import{jsxDEV as x5,Fragment as RE9}from"preact/jsx-dev-runtime";var QC=({posts:x,pageTitle:B,pagination:A,baseUrl:w})=>{let f=B??"Social Posts",D=A?.totalItems??x.length,$=`Browse all ${D} social ${D===1?"post":"posts"}`;return x5(RE9,{children:[x5(z9,{title:f,description:$},void 0,!1,void 0,this),x5("div",{className:"social-post-list bg-theme",children:x5("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[x5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:f},void 0,!1,void 0,this),x.length===0?x5("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):x5("ul",{className:"space-y-6",children:x.map((Z)=>x5("li",{children:x5(r8,{href:Z.url,variant:"horizontal",children:x5("div",{className:"flex flex-col sm:flex-row gap-4",children:[Z.coverImageUrl&&x5("img",{src:Z.coverImageUrl,alt:Z.frontmatter.title,className:"w-full sm:w-24 h-48 sm:h-24 object-cover rounded-lg shrink-0"},void 0,!1,void 0,this),x5("div",{className:"flex-1 min-w-0",children:[x5("div",{className:"flex items-start justify-between gap-4 mb-2",children:[x5("h2",{className:"text-lg font-semibold text-heading",children:Z.frontmatter.title},void 0,!1,void 0,this),x5("time",{className:"text-sm text-theme-muted shrink-0",children:G6(Z.frontmatter.publishedAt??Z.created,{style:"medium"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x5("div",{className:"flex items-center gap-2 mb-3",children:[x5(m2,{status:Z.frontmatter.status},void 0,!1,void 0,this),x5("span",{className:"text-xs text-theme-muted uppercase",children:Z.frontmatter.platform},void 0,!1,void 0,this),x5("span",{className:"text-xs text-theme-muted font-mono",children:Z.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x5("p",{className:"text-theme leading-relaxed",children:r$(Z.body,200)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},Z.id,!1,void 0,this))},void 0,!1,void 0,this),A&&A.totalPages>1&&x5(oD,{currentPage:A.currentPage,totalPages:A.totalPages,baseUrl:w??"/social-posts"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as B5,Fragment as yE9}from"preact/jsx-dev-runtime";var XC=({post:x})=>{let B=`Social Post - ${x.frontmatter.platform}`,A=x.body.slice(0,160),w=[{label:"Home",href:"/"},{label:x.listLabel,href:x.listUrl},{label:x.frontmatter.platform}];return B5(yE9,{children:[B5(z9,{title:B,description:A},void 0,!1,void 0,this),B5("section",{className:"social-post-detail",children:B5("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:B5("div",{className:"max-w-3xl mx-auto",children:[B5(nf,{items:w},void 0,!1,void 0,this),B5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:x.frontmatter.title},void 0,!1,void 0,this),B5("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[B5(m2,{status:x.frontmatter.status},void 0,!1,void 0,this),B5("span",{className:"text-sm text-theme-muted uppercase",children:x.frontmatter.platform},void 0,!1,void 0,this),B5("span",{className:"text-sm text-theme-muted font-mono",children:x.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x.coverImageUrl&&x.coverImageWidth&&x.coverImageHeight&&B5(Qz,{src:x.coverImageUrl,alt:x.frontmatter.title,width:x.coverImageWidth,height:x.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),B5(r8,{className:"p-8 mb-8",children:B5("p",{className:"text-lg text-theme leading-relaxed whitespace-pre-wrap",children:x.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),B5("div",{className:"space-y-4 text-sm text-theme-muted",children:[B5("div",{children:[B5("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",G6(x.created,{style:"long",includeTime:!0})]},void 0,!0,void 0,this),x.frontmatter.publishedAt&&B5("div",{children:[B5("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",G6(x.frontmatter.publishedAt,{style:"long",includeTime:!0})]},void 0,!0,void 0,this),x.frontmatter.platformPostId&&B5("div",{children:B5("a",{href:`https://www.linkedin.com/feed/update/${x.frontmatter.platformPostId}`,target:"_blank",rel:"noopener noreferrer",className:"text-brand hover:underline",children:"View on LinkedIn \u2192"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};function h_(x){return`social-media:${x}`}var CE9=X.union([X.boolean(),X.object({generate:X.boolean().optional(),prompt:X.string().optional()})]),P30=X.object({prompt:X.string().optional(),platform:X.enum(["linkedin"]).optional(),sourceEntityType:X.enum(["post","deck"]).optional(),sourceEntityId:X.string().optional(),title:X.string().optional().describe("Required when content is provided directly"),content:X.string().optional(),addToQueue:X.boolean().optional(),generateImage:X.boolean().optional().describe("Auto-generate cover image for post"),coverImage:CE9.optional().describe("Generic cover image generation request")}),cE9=iD.extend({slug:X.string().optional()});class aY extends UA{constructor(x,B){super(x,B,{schema:P30,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(x,B){let A=x.platform??"linkedin",w=x.addToQueue??!1,{prompt:f,sourceEntityType:D,sourceEntityId:$}=x,{content:Z,title:Q}=x,Y=Z&&Q?"":i3(await y2(this.context.entityService)),W={representedIdentity:"anchor",...Y&&{styleGuide:{voice:Y}}};if(Z&&Q)await this.reportProgress(B,{progress:50,message:"Using provided content"});else if(Z&&!Q){await this.reportProgress(B,{progress:10,message:"Shaping content with AI"});let E=await this.context.ai.generate({prompt:Z,templateName:h_(A),...W});Q=E.title,Z=E.content,await this.reportProgress(B,{progress:50,message:"Social post shaped from content"})}else if($&&D){await this.reportProgress(B,{progress:10,message:`Fetching source ${D}`});let E=await this.context.entityService.getEntity({entityType:D,id:$});if(!E)this.failEarly(`Source entity not found: ${D}/${$}`);await this.reportProgress(B,{progress:30,message:"Generating social post from source content"});let L=X.looseObject({slug:X.string()}).safeParse(E.metadata),N=L.success?L.data.slug:$,y=await this.context.ai.generate({prompt:`Create an engaging ${A} post to promote this ${D}:
6334
6334
 
6335
6335
  Source: ${D}/${N}
6336
6336
 
6337
6337
  ${E.content}`,templateName:h_(A),...W});Q=y.title,Z=y.content,await this.reportProgress(B,{progress:50,message:"Social post generated from source"})}else if(f){await this.reportProgress(B,{progress:10,message:"Generating social post with AI"});let E=await this.context.ai.generate({prompt:f,templateName:h_(A),...W});Q=E.title,Z=E.content,await this.reportProgress(B,{progress:50,message:"Social post generated"})}else this.failEarly("No content source provided (prompt, sourceEntityId, or content)");if(!Z||!Q)this.failEarly("Content or title was not generated");let F={title:Q,platform:A,status:w?"queued":"draft",...$&&{sourceEntityId:$},...D&&{sourceEntityType:D}},K=c1.createPostContent(F,Z),V=c1.fromMarkdown(K).metadata;if(!V)this.failEarly("Failed to parse social post metadata");let b=await Bz({entityType:"social-post",title:Q,deriveId:(E)=>`${A}-${Gx(E)}`,regeneratePrompt:"Generate a different social media post title on the same topic.",context:this.context}),G=K;if(b!==Q){V.title=b,V.slug=`${A}-${Gx(b)}`;let E={...F,title:b};G=c1.createPostContent(E,Z)}return{id:V.slug,content:G,metadata:V,title:b,resultExtras:{slug:V.slug},createOptions:{deduplicateId:!0}}}async onGenerationFailure(x,B){await this.context.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:B}})}async afterCreate(x,B,A,w){if(x.generateImage){await this.reportProgress(A,{progress:90,message:"Queueing image generation"});let f=w.title??"Social Post";await this.context.jobs.enqueue({type:eRx.generate,data:{prompt:`Social media graphic for: ${f}`,title:`${f} Image`,aspectRatio:"16:9",targetEntityType:"social-post",targetEntityId:B},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"social-media-generation"}}})}await this.context.messaging.send({type:w7.reportSuccess,payload:{entityType:"social-post",entityId:B}})}summarizeDataForLog(x){return{platform:x.platform??"linkedin",hasPrompt:!!x.prompt,sourceEntityType:x.sourceEntityType,addToQueue:x.addToQueue??!1,generateImage:x.generateImage??!1,coverImage:!!x.coverImage}}}var xyx=200,Byx="com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest";function R_(x){if(x.length<=xyx)return x;return`${x.slice(0,xyx)}\u2026 (truncated, ${x.length} bytes)`}var gE9=X.looseObject({sub:X.string()}),TE9=X.looseObject({id:X.string()}),pE9=X.looseObject({value:X.looseObject({asset:X.string(),uploadMechanism:X.looseObject({[Byx]:X.looseObject({uploadUrl:X.url()})})})}).transform((x)=>({uploadUrl:x.value.uploadMechanism[Byx].uploadUrl,assetUrn:x.value.asset})),uE9=X.looseObject({value:X.looseObject({uploadUrl:X.url(),document:X.string()})}).transform((x)=>({uploadUrl:x.value.uploadUrl,documentUrn:x.value.document}));function SE9(x){let B={status:"READY",media:x.urn};if(x.title)B.title={text:x.title};return B}function iE9(x){let B=pE9.safeParse(x);return B.success?B.data:null}function lE9(x){let B=uE9.safeParse(x);return B.success?B.data:null}var nE9="202604";class J30{config;logger;name="linkedin";apiBaseUrl="https://api.linkedin.com/v2";restApiBaseUrl="https://api.linkedin.com/rest";fetch;cachedUserId=null;constructor(x,B,A={}){this.config=x,this.logger=B,this.fetch=A.fetch??globalThis.fetch.bind(globalThis)}async publish(x,B,A,w){if(!this.config.accessToken)throw Error("LinkedIn access token not configured");let f=await this.getAuthor(),D=w?.[0];if(w&&w.length>1)this.logger.warn("LinkedIn document publishing supports one PDF",{count:w.length});let $=null;if(D){let H=await this.uploadDocument(f,D);return this.publishDocumentPost(f,x,H,D.filename)}else if(A){let H=await this.uploadImage(f,A);if(H)$={category:"IMAGE",urn:H}}let Z={shareCommentary:{text:x},shareMediaCategory:$?.category??"NONE",...$&&{media:[SE9($)]}},Q=await this.fetch(`${this.apiBaseUrl}/ugcPosts`,{method:"POST",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0"},body:JSON.stringify({author:f,lifecycleState:"PUBLISHED",specificContent:{"com.linkedin.ugc.ShareContent":Z},visibility:{"com.linkedin.ugc.MemberNetworkVisibility":"PUBLIC"}})});if(!Q.ok){let H=R_(await Q.text());throw this.logger.error("LinkedIn API error",{status:Q.status,error:H}),Error(`LinkedIn API error: ${Q.status} - ${H}`)}let Y=Q.headers.get("X-RestLi-Id")??"";this.logger.info("LinkedIn post created",{postId:Y,mediaCategory:$?.category??"NONE"});let W={id:Y};if(Y)W.url=`https://www.linkedin.com/feed/update/${Y}`;return W}getRestHeaders(){return{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json","Linkedin-Version":this.config.apiVersion??nE9,"X-Restli-Protocol-Version":"2.0.0"}}async uploadImage(x,B){try{let A=await this.fetch(`${this.apiBaseUrl}/assets?action=registerUpload`,{method:"POST",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0"},body:JSON.stringify({registerUploadRequest:{recipes:["urn:li:digitalmediaRecipe:feedshare-image"],owner:x,serviceRelationships:[{relationshipType:"OWNER",identifier:"urn:li:userGeneratedContent"}]}})});if(!A.ok){let Z=R_(await A.text());return this.logger.warn("LinkedIn image upload registration failed",{status:A.status,error:Z}),null}let w=iE9(await A.json());if(!w)return this.logger.warn("LinkedIn image upload registration was malformed"),null;let{uploadUrl:f,assetUrn:D}=w,$=await this.fetch(f,{method:"PUT",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":B.mimeType},body:new Uint8Array(B.data)});if(!$.ok)return this.logger.warn("LinkedIn image binary upload failed",{status:$.status}),null;return this.logger.info("LinkedIn image uploaded",{assetUrn:D}),D}catch(A){return this.logger.warn("LinkedIn image upload error",{error:A}),null}}async uploadDocument(x,B){let A=await this.fetch(`${this.restApiBaseUrl}/documents?action=initializeUpload`,{method:"POST",headers:this.getRestHeaders(),body:JSON.stringify({initializeUploadRequest:{owner:x}})});if(!A.ok){let D=R_(await A.text());throw Error(`LinkedIn document upload initialization failed: ${A.status} - ${D}`)}let w=lE9(await A.json());if(!w)throw Error("LinkedIn document upload initialization was malformed");let f=await this.fetch(w.uploadUrl,{method:"PUT",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":B.mimeType},body:new Uint8Array(B.data)});if(!f.ok)throw Error(`LinkedIn document binary upload failed: ${f.status}`);return this.logger.info("LinkedIn document uploaded",{documentUrn:w.documentUrn,filename:B.filename}),w.documentUrn}async publishDocumentPost(x,B,A,w){let f=await this.fetch(`${this.restApiBaseUrl}/posts`,{method:"POST",headers:this.getRestHeaders(),body:JSON.stringify({author:x,commentary:B,visibility:"PUBLIC",distribution:{feedDistribution:"MAIN_FEED",targetEntities:[],thirdPartyDistributionChannels:[]},content:{media:{id:A,title:w}},lifecycleState:"PUBLISHED",isReshareDisabledByAuthor:!1})});if(!f.ok){let Z=R_(await f.text());throw this.logger.error("LinkedIn document post API error",{status:f.status,error:Z}),Error(`LinkedIn document post API error: ${f.status} - ${Z}`)}let D=f.headers.get("X-RestLi-Id")??"";this.logger.info("LinkedIn document post created",{postId:D,documentUrn:A});let $={id:D};if(D)$.url=`https://www.linkedin.com/feed/update/${D}`;return $}async validateCredentials(){if(!this.config.accessToken)return!1;try{if(this.config.organizationId)return(await this.fetch(`${this.apiBaseUrl}/organizations/${this.config.organizationId}`,{headers:{Authorization:`Bearer ${this.config.accessToken}`}})).ok;return await this.getUserId(),!0}catch{return!1}}async getAuthor(){if(this.config.organizationId)return`urn:li:organization:${this.config.organizationId}`;return this.getUserId()}async getUserId(){if(this.cachedUserId)return this.cachedUserId;if(!this.config.accessToken)throw Error("LinkedIn access token not configured");try{let A=await this.fetch("https://api.linkedin.com/v2/userinfo",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(A.ok){let w=gE9.safeParse(await A.json());if(w.success)return this.cachedUserId=`urn:li:person:${w.data.sub}`,this.cachedUserId}}catch{}let x=await this.fetch("https://api.linkedin.com/v2/me",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(!x.ok){let A=R_(await x.text());throw Error(`Failed to get LinkedIn user ID: ${x.status} - ${A}`)}let B=TE9.parse(await x.json());return this.cachedUserId=`urn:li:person:${B.id}`,this.cachedUserId}}function L30(x,B,A={}){return new J30(x,B,A)}var Ayx=$C,dE9=X.object({posts:X.array(Ayx),totalCount:X.number().nullable().default(null),pagination:KB.nullable(),baseUrl:X.string().nullable().default(null)}),aE9=X.object({post:Ayx});function wyx(){return{linkedin:YC,"social-post-list":mx({name:"social-post-list",description:"Social post list page template",schema:dE9,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:QC}}),"social-post-detail":mx({name:"social-post-detail",description:"Individual social post template",schema:aE9,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:XC}})}}var sE9=X.object({prompt:X.string().optional(),content:X.string().optional(),platform:X.enum(["linkedin"]).default("linkedin")}),rE9=X.object({prompt:X.string().optional(),content:X.string().optional(),title:X.string().optional(),platform:X.enum(["linkedin"]).optional()});function fyx(x){x.eval.registerHandler("generation",async(B)=>{let A=sE9.parse(B),w=A.content?`Create an engaging LinkedIn post to share this content:
6338
6338
 
6339
- ${A.content}`:A.prompt??"Write an engaging LinkedIn post";return x.ai.generate({prompt:w,templateName:`social-media:${A.platform}`})}),x.eval.registerHandler("create",async(B)=>{let A=rE9.parse(B),w=[],f=IQ.from(async(Y)=>{let W={progress:Y.progress};if(Y.message!==void 0)W.message=Y.message;w.push(W)});if(!f)throw Error("Failed to create progress reporter");let $=await new aY(x.logger,x).process(A,`eval-${Date.now()}`,f),Z=!1,Q;if($.success&&$.entityId){let Y=await x.entityService.getEntity({entityType:"social-post",id:$.entityId});Z=!!Y,Q=Y?.content.slice(0,300)}return{...$,entityExists:Z,entityPreview:Q,progressSteps:w}})}class y_{sendMessage;logger;entityService;providers;permissions;resolveAttachment;constructor(x){this.sendMessage=x.sendMessage,this.logger=x.logger,this.entityService=x.entityService,this.providers=x.providers,this.permissions=x.permissions,this.resolveAttachment=x.resolveAttachment}async handle(x){let{entityType:B,entityId:A}=x;if(B!=="social-post")return;this.permissions.assertEntityActionAllowed(B,"publish",x.authContext??{userPermissionLevel:"admin"}),this.logger.debug("Handling publish:execute",{entityId:A});try{let w=await this.entityService.getEntity({entityType:"social-post",id:A});if(!w){await this.reportFailure(B,A,`Post not found: ${A}`);return}let f=w;if(f.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:A});return}let D=f.metadata.platform,$=this.providers.get(D);if(!$){await this.reportFailure(B,A,`No provider configured for platform: ${D}`);return}let Z=G9(f.content,aB),Q;if(Z.metadata.coverImageId)Q=await this.fetchImageData(Z.metadata.coverImageId);let Y=Z.metadata.documents??[],W=await this.fetchDocumentData(Y);try{if(Y.length>0&&W.length===0)throw Error(`Refusing to publish: ${Y.length} document(s) referenced but none could be fetched`);let H=Y.length===0?await this.resolveSourceAttachment(Z.metadata):[],F=W.length>0?W:H,K=F.length?await $.publish(Z.content,f.metadata,Q,F):await $.publish(Z.content,f.metadata,Q),q=new Date().toISOString(),V=K.id||void 0,b={...Z.metadata,status:"published",publishedAt:q,...V&&{platformPostId:V}},G=c1.createPostContent(b,Z.content);await this.entityService.updateEntity({entity:{...f,content:G,metadata:{...f.metadata,status:"published",publishedAt:q,platformPostId:V}}}),await this.reportSuccess(B,A,K.id),this.logger.info(`Post published successfully: ${A}`,{platform:D,platformPostId:V})}catch(H){let F=g(H),K={...Z.metadata,status:"failed"},q=c1.createPostContent(K,Z.content);await this.entityService.updateEntity({entity:{...f,content:q,metadata:{...f.metadata,status:"failed"}}}),await this.reportFailure(B,A,F),this.logger.error(`Post publish failed: ${A}`,{platform:D,error:F})}}catch(w){let f=g(w);this.logger.error("Unexpected error in publish handler",{entityId:A,error:f}),await this.reportFailure(B,A,f)}}async reportSuccess(x,B,A){await this.sendMessage({type:d5.reportSuccess,payload:{entityType:x,entityId:B,result:{id:A}}})}async reportFailure(x,B,A){await this.sendMessage({type:d5.reportFailure,payload:{entityType:x,entityId:B,error:A}})}async resolveSourceAttachment(x){if(!this.resolveAttachment||!x.sourceEntityType||!x.sourceEntityId)return[];let B=await this.resolveAttachment({sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:"carousel"});return B?[B]:[]}async fetchDocumentData(x){if(!x?.length)return[];let B=[];for(let A of x){let w=await this.fetchSingleDocumentData(A.id);if(w)B.push(w)}return B}async fetchSingleDocumentData(x){try{let B=await this.entityService.getEntity({entityType:"document",id:x});if(!B){this.logger.warn("Document not found",{documentId:x});return}let A=B.content.match(/^data:application\/pdf;base64,(.+)$/);if(!A?.[1]){this.logger.warn("Invalid document data URL format",{documentId:x});return}let w=typeof B.metadata.filename==="string"?B.metadata.filename:`${x}.pdf`;return{type:"document",data:Buffer.from(A[1],"base64"),mimeType:"application/pdf",filename:w}}catch(B){this.logger.warn("Failed to fetch document",{documentId:x,error:B});return}}async fetchImageData(x){try{let B=await this.entityService.getEntity({entityType:"image",id:x});if(!B){this.logger.warn("Cover image not found",{imageId:x});return}let w=B.content.match(/^data:([^;]+);base64,(.+)$/);if(!w?.[1]||!w[2]){this.logger.warn("Invalid image data URL format",{imageId:x});return}let f=w[1],D=w[2];return{data:Buffer.from(D,"base64"),mimeType:f}}catch(B){this.logger.warn("Failed to fetch cover image",{imageId:x,error:B});return}}}function Dyx(x,B,A){if(B.size===0){A.debug("No providers configured, skipping publish-pipeline registration");return}x.messaging.subscribe(e8.pluginsRegistered,async()=>{let w=B.values().next().value;return await x.messaging.send({type:d5.register,payload:{entityType:"social-post",provider:w,config:{publishResultIdField:"platformPostId"}}}),A.info("Registered social-post with publish-pipeline"),{success:!0}})}function $yx(x,B,A){let w=new y_({sendMessage:x.messaging.send,logger:A.child("PublishExecuteHandler"),entityService:x.entityService,providers:B,permissions:x.permissions,resolveAttachment:x.attachments.resolve});x.messaging.subscribe(d5.execute,async(f)=>{return await w.handle(f.payload),{success:!0}}),A.debug("Subscribed to publish:execute messages")}var k30={autoGenerate:"social:auto-generate"};function Zyx(x,B){x.messaging.subscribe(l8.updated,async(A)=>{let{entityType:w,entityId:f,entity:D}=A.payload;if(w!=="post")return{success:!0};if(D.metadata?.status!=="queued")return{success:!0};try{if((await x.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:f}},limit:1}})).length>0)return B.debug(`Social post already exists for ${f}, skipping auto-generate`),{success:!0};return await x.messaging.send({type:k30.autoGenerate,payload:{sourceEntityType:w,sourceEntityId:f,platform:"linkedin"}}),B.info(`Auto-generate social post triggered for queued post ${f}`),{success:!0}}catch(Z){let Q=g(Z);return B.error(`Failed to trigger auto-generate for ${f}:`,{error:Q}),{success:!0}}}),B.debug("Subscribed to entity:updated for auto-generation")}function Qyx(x,B){x.messaging.subscribe(k30.autoGenerate,async(A)=>{let{sourceEntityType:w,sourceEntityId:f,platform:D}=A.payload;try{let $=await x.jobs.enqueue({type:`${c1.entityType}:generation`,data:{sourceEntityType:w,sourceEntityId:f,platform:D,addToQueue:!1},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"social-media-auto-generate"}}});return B.info(`Social post generation job enqueued for ${w}/${f}`,{jobId:$}),{success:!0,jobId:$}}catch($){let Z=g($);return B.error(`Failed to enqueue social post generation for ${f}:`,{error:Z}),{success:!1}}}),B.debug("Subscribed to social:auto-generate messages")}function Xyx(x,B){x.messaging.subscribe(w7.execute,async(A)=>{let{entityType:w}=A.payload;if(w!=="social-post")return{success:!0};B.info("Received generate:execute for social-post");try{let f=await x.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:5}});if(f.length===0)return B.info("No published posts found for social post generation"),await x.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:"No published posts available for social post generation"}}),{success:!0};let D=null;for(let Z of f)if((await x.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:Z.id}},limit:1}})).length===0){D=Z;break}if(!D)return B.info("All recent posts already have social posts"),await x.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:"All recent posts already have social posts generated"}}),{success:!0};let $=await x.jobs.enqueue({type:`${c1.entityType}:generation`,data:{sourceEntityType:"post",sourceEntityId:D.id,platform:"linkedin",addToQueue:!1},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"social-media-auto-generate"}}});return B.info("Social post generation job queued",{jobId:$,sourcePostId:D.id}),{success:!0}}catch(f){let D=g(f);return B.error("Failed to handle generate:execute:",{error:D}),await x.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:D}}),{success:!0}}}),B.debug("Subscribed to generate:execute messages")}async function Yyx({entity:x,config:B}){let A=PZ.parse(x),w=c1.parsePostFrontmatter(A),f=c1.getPostContent(A);return{$type:"ai.rizom.brain.socialPost",title:w.title,platform:w.platform,body:f,format:"text/markdown",status:w.status,...w.publishedAt&&{publishedAt:w.publishedAt},...w.platformPostId&&{platformPostId:w.platformPostId},...w.sourceEntityType&&{sourceLocalEntityType:w.sourceEntityType},...w.sourceEntityId&&{sourceLocalEntityId:w.sourceEntityId},...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"social-post",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function M30(){return{entityType:"social-post",collection:"ai.rizom.brain.socialPost",lexicon:h4["ai.rizom.brain.socialPost"],validate:!1,buildRecord:Yyx}}var Wyx={name:"@brains/social-media",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Multi-provider social media posting with queue-based publishing",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class v30 extends g8{entityType=c1.entityType;schema=PZ;adapter=c1;providers=new Map;unregisterAtprotoProjection;constructor(x={}){super("social-media",Wyx,x,_30)}createGenerationHandler(x){return new aY(this.logger.child("GenerationJobHandler"),x)}getTemplates(){return wyx()}getDataSources(){return[new ZC(this.logger.child("SocialPostDataSource"))]}getEntityTypeConfig(){return{projectionSourceRole:"secondary",publish:{publishStatuses:["queued","published","failed"]}}}async onRegister(x){if(this.initializeProviders(),Dyx(x,this.providers,this.logger),$yx(x,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)Zyx(x,this.logger),Qyx(x,this.logger),this.logger.info("Auto-generate on blog publish enabled");Xyx(x,this.logger),fyx(x),this.unregisterAtprotoProjection=R4.getInstance().register(M30()),this.logger.info("Social media plugin registered successfully")}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}initializeProviders(){if(this.config.linkedin?.accessToken){let x=L30(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",x),this.logger.info("LinkedIn provider initialized")}}}function N30(x={}){return new v30(x)}class WC{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(x,B){this.apiKey=x,this.fetchFn=B}async searchPhotos(x,B){let A=new URL(`${this.baseUrl}/search/photos`);A.searchParams.set("query",x),A.searchParams.set("page",String(B.page)),A.searchParams.set("per_page",String(B.perPage));let w=await this.fetchFn(A.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!w.ok)throw Error(`Unsplash API error: ${w.status} ${w.statusText}`);let f=eE9.parse(await w.json());return{photos:f.results.map(xj9),total:f.total,totalPages:f.total_pages,page:B.page}}async triggerDownload(x){try{await this.fetchFn(x,{headers:{Authorization:`Client-ID ${this.apiKey}`}})}catch{}}}var tE9=X.looseObject({id:X.string(),description:X.string().nullable(),alt_description:X.string().nullable(),urls:X.looseObject({raw:X.url(),full:X.url(),regular:X.url(),small:X.url(),thumb:X.url()}),links:X.looseObject({html:X.url(),download_location:X.url()}),user:X.looseObject({name:X.string(),links:X.looseObject({html:X.url()})}),width:X.number().int().nonnegative(),height:X.number().int().nonnegative()}),eE9=X.looseObject({total:X.number().int().nonnegative(),total_pages:X.number().int().nonnegative(),results:X.array(tE9)});function xj9(x){return{id:x.id,description:x.description,altDescription:x.alt_description,thumbnailUrl:x.urls.thumb,imageUrl:x.urls.regular,photographerName:x.user.name,photographerUrl:x.user.links.html,sourceUrl:x.links.html,downloadLocation:x.links.download_location,width:x.width,height:x.height}}async function HC(x,B,A,w){let f=await x.getEntity({entityType:B,id:A});if(!f)return!1;return await x.updateEntity({entity:{...f,metadata:{...f.metadata,coverImageId:w}}}),!0}var Bj9=X.object({query:X.string().describe("Search terms for stock photos"),perPage:X.number().min(1).max(30).default(10).describe("Results per page (1-30)"),page:X.number().min(1).default(1).describe("Page number")}),Aj9=X.object({photoId:X.string().describe("Photo ID from search results"),downloadLocation:X.url().describe("Download tracking URL (required by provider ToS)"),photographerName:X.string().describe("Photographer name for attribution"),photographerUrl:X.url().describe("Photographer profile URL for attribution"),sourceUrl:X.url().describe("Photo page URL on provider"),imageUrl:X.url().describe("Image URL to download"),title:X.string().optional().describe("Image entity title"),alt:X.string().optional().describe("Alt text for the image"),targetEntityType:X.string().optional().describe("Entity type to set cover image on"),targetEntityId:X.string().optional().describe("Entity ID to set cover image on")});function Hyx(x,B){return[wj9(x,B),fj9(x,B)]}function wj9(x,B){return E1(x,"search","Search for stock photos. Returns photo candidates with preview URLs and metadata. Use stock-photo_select to materialize a chosen photo into an image entity.",Bj9,async(A)=>{try{return{success:!0,data:await B.provider.searchPhotos(A.query,{page:A.page,perPage:A.perPage})}}catch(w){return{success:!1,error:g(w,"Search failed")}}},{sideEffects:"none"})}function fj9(x,B){return E1(x,"select","Select a stock photo from search results and materialize it as an image entity. Triggers provider download tracking per ToS. Optionally sets as cover image on a target entity.",Aj9,async(A)=>{let{photoId:w,downloadLocation:f,photographerName:D,photographerUrl:$,sourceUrl:Z,imageUrl:Q,title:Y,alt:W,targetEntityType:H,targetEntityId:F}=A,K={photographerName:D,photographerUrl:$,sourceUrl:Z},q=await B.entityService.listEntities({entityType:"image",options:{limit:1,filter:{metadata:{sourceUrl:Q}}}});if(q[0]){let G={imageEntityId:q[0].id,alreadyExisted:!0,attribution:K};if(H&&F)G.coverSet=await HC(B.entityService,H,F,q[0].id);return{success:!0,data:G}}let V=await B.jobs.enqueue({type:"select-photo",data:{photoId:w,downloadLocation:f,photographerName:D,photographerUrl:$,sourceUrl:Z,imageUrl:Q,...Y!==void 0?{title:Y}:{},...W!==void 0?{alt:W}:{},...H!==void 0?{targetEntityType:H}:{},...F!==void 0?{targetEntityId:F}:{}}}),b={imageEntityId:w,alreadyExisted:!1,attribution:K,jobId:V,status:"generating"};if(H&&F)b.coverSet=!1;return{success:!0,data:b}},{sideEffects:"external"})}var Dj9=X.object({photoId:X.string(),downloadLocation:X.url(),photographerName:X.string(),photographerUrl:X.url(),sourceUrl:X.url(),imageUrl:X.url(),title:X.string().optional(),alt:X.string().optional(),targetEntityType:X.string().optional(),targetEntityId:X.string().optional()});class I30 extends $9{deps;constructor(x,B){super(x,{schema:Dj9,jobTypeName:"select-photo"});this.deps=B}async process(x,B,A){await this.reportProgress(A,{progress:10,message:"Tracking stock photo download"}),await this.deps.provider.triggerDownload(x.downloadLocation),await this.reportProgress(A,{progress:35,message:"Downloading stock photo"});let w=await this.deps.fetchImage(x.imageUrl),f=x.title??`Stock photo ${x.photoId}`,D=dB.createImageEntity({dataUrl:w,title:f,alt:x.alt??f});await this.reportProgress(A,{progress:75,message:"Saving stock photo"});let{entityId:$}=await this.deps.entityService.createEntity({entity:{id:x.photoId,...D,metadata:{...D.metadata,sourceUrl:x.imageUrl}}}),Z={imageEntityId:$,alreadyExisted:!1};if(x.targetEntityType&&x.targetEntityId){if(Z.coverSet=await HC(this.deps.entityService,x.targetEntityType,x.targetEntityId,$),!Z.coverSet)Z.warning=`Target entity ${x.targetEntityType}:${x.targetEntityId} not found; cover image not set`}return await this.reportProgress(A,{progress:100,message:"Stock photo selected"}),Z}summarizeDataForLog(x){return{photoId:x.photoId,hasTarget:x.targetEntityType!==void 0}}}var Fyx={name:"@brains/stock-photo",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Stock photo search and selection \u2014 Unsplash provider",dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Zj9=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class O30 extends D8{deps;cachedTools=null;constructor(x={},B={}){super("stock-photo",Fyx,x,Zj9);this.deps=B}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let x=this.getContext(),B=this.createProvider();return this.cachedTools=Hyx(this.id,{provider:B,entityService:x.entityService,fetchImage:this.deps.fetchImage??m3,jobs:x.jobs}),this.cachedTools}async registerJobHandlers(){if(!this.config.apiKey)return;let x=this.getContext();x.jobs.registerHandler("select-photo",new I30(this.logger.child("SelectPhotoJobHandler"),{provider:this.createProvider(),entityService:x.entityService,fetchImage:this.deps.fetchImage??m3}))}createProvider(){return new WC(this.config.apiKey??"",this.deps.fetch??globalThis.fetch)}}function h30(x={},B={}){return new O30(x,B)}var Qj9=X.enum(["public","shared","restricted"]),Kyx=X.enum(["canonical","primary","secondary","supporting","ambient","excluded"]),Xj9=X.object({weight:X.number().min(0).max(1),canMint:X.boolean()}),Yj9={canonical:{weight:1,canMint:!0},primary:{weight:1,canMint:!0},secondary:{weight:0.8,canMint:!0},supporting:{weight:0.55,canMint:!1},ambient:{weight:0.35,canMint:!1},excluded:{weight:0,canMint:!1}},qyx=X.object({includeEntityTypes:X.array(X.string()).default(["*"]),excludeEntityTypes:X.array(X.string()).default([]),minRelevanceScore:X.number().min(0).max(1).default(0.5),createRelevanceThreshold:X.number().min(0).max(1).default(0.7),reinforceRelevanceThreshold:X.number().min(0).max(1).default(0.5),sourceWeights:X.record(X.string(),X.number().min(0).max(1)).default({}),mintableEntityTypes:X.array(X.string()).default([]),sourceRolePolicies:X.partialRecord(Kyx,Xj9).default({}).transform((x)=>({...Yj9,...x})),sourceRoleOverrides:X.record(X.string(),Kyx).default({}),maxEntitiesPerBatch:X.number().int().min(1).default(4),topicSoftCeilingSourceRatio:X.number().min(1).default(5),mergeSimilarityThreshold:X.number().min(0).max(1).default(0.85),semanticMergeDistance:X.number().min(0).max(1).default(0.35),reconciliationMaxPairs:X.number().int().min(0).default(100),autoMerge:X.boolean().default(!0),extractableStatuses:X.array(X.string()).default(["published"]),enableAutoExtraction:X.boolean().default(!0),extractionVisibility:Qj9.default("public"),sourceChangeBatchDelayMs:X.number().int().min(0).default(1000)});var aD5=X.object({}),Wj9=X.record(X.string(),X.unknown()).transform(()=>({})),Kz=j8.extend({entityType:X.literal("topic"),metadata:Wj9}),sD5=X.object({content:X.string()}),zyx=X.object({title:X.string().describe("Topic title")});var sY="topics",R8="topic",R30="topics-projection",byx="topic:project",FC="topics-plugin",KC="topics:batch-completed",Vyx="topics-source-batch",qC="topics:knowledge-map";class D7 extends ox{constructor(){super({entityType:R8,purpose:"A recurring theme or subject derived from the user's content.",schema:Kz,frontmatterSchema:zyx})}buildFrontmatter(x){return{title:x}}toMarkdown(x){let B=this.parseTopicBody(x.content);return this.buildMarkdown(B.content,this.buildFrontmatter(B.title))}fromMarkdown(x){return{content:x,entityType:R8}}extractMetadata(x){return{}}generateFrontMatter(x){let B=this.parseTopicBody(x.content),w=this.buildMarkdown("",this.buildFrontmatter(B.title)).match(/^---\n[\s\S]*?\n---/);return w?w[0]:""}parseTopicBody(x){if(x.startsWith("---"))try{let B=this.parseFrontmatter(x);return{content:this.extractBody(x).replace(/\n*## Sources[\s\S]*$/,"").trim(),formatted:x,title:B.title}}catch{return{content:x,formatted:x,title:"Unknown Topic"}}return{content:x,formatted:x,title:"Unknown Topic"}}createTopicBody(x){return this.buildMarkdown(x.content,this.buildFrontmatter(x.title))}}var Hj9=X.object({title:X.string().max(100),content:X.string(),relevanceScore:X.number().min(0).max(1)}),Uyx=X.array(Hj9);var Fj9=X.object({topics:Uyx}),Gyx=mx({name:"topics:extraction",description:"Extract topics from conversation text",dataSourceId:"shell:ai-content",schema:Fj9,basePrompt:`You are an expert at analyzing content and extracting key topics.
6339
+ ${A.content}`:A.prompt??"Write an engaging LinkedIn post";return x.ai.generate({prompt:w,templateName:`social-media:${A.platform}`})}),x.eval.registerHandler("create",async(B)=>{let A=rE9.parse(B),w=[],f=IQ.from(async(Y)=>{let W={progress:Y.progress};if(Y.message!==void 0)W.message=Y.message;w.push(W)});if(!f)throw Error("Failed to create progress reporter");let $=await new aY(x.logger,x).process(A,`eval-${Date.now()}`,f),Z=!1,Q;if($.success&&$.entityId){let Y=await x.entityService.getEntity({entityType:"social-post",id:$.entityId});Z=!!Y,Q=Y?.content.slice(0,300)}return{...$,entityExists:Z,entityPreview:Q,progressSteps:w}})}class y_{sendMessage;logger;entityService;providers;permissions;resolveAttachment;constructor(x){this.sendMessage=x.sendMessage,this.logger=x.logger,this.entityService=x.entityService,this.providers=x.providers,this.permissions=x.permissions,this.resolveAttachment=x.resolveAttachment}async handle(x){let{entityType:B,entityId:A}=x;if(B!=="social-post")return;this.permissions.assertEntityActionAllowed(B,"publish",x.authContext??{userPermissionLevel:"admin"}),this.logger.debug("Handling publish:execute",{entityId:A});try{let w=await this.entityService.getEntity({entityType:"social-post",id:A});if(!w){await this.reportFailure(B,A,`Post not found: ${A}`);return}let f=w;if(f.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:A});return}let D=f.metadata.platform,$=this.providers.get(D);if(!$){await this.reportFailure(B,A,`No provider configured for platform: ${D}`);return}let Z=G9(f.content,aB),Q;if(Z.metadata.coverImageId)Q=await this.fetchImageData(Z.metadata.coverImageId);let Y=Z.metadata.documents??[],W=await this.fetchDocumentData(Y);try{if(Y.length>0&&W.length===0)throw Error(`Refusing to publish: ${Y.length} document(s) referenced but none could be fetched`);let H=Y.length===0?await this.resolveSourceAttachment(Z.metadata):[],F=W.length>0?W:H,K=F.length?await $.publish(Z.content,f.metadata,Q,F):await $.publish(Z.content,f.metadata,Q),q=new Date().toISOString(),V=K.id||void 0,b={...Z.metadata,status:"published",publishedAt:q,...V&&{platformPostId:V}},G=c1.createPostContent(b,Z.content);await this.entityService.updateEntity({entity:{...f,content:G,metadata:{...f.metadata,status:"published",publishedAt:q,platformPostId:V}}}),await this.reportSuccess(B,A,K.id),this.logger.info(`Post published successfully: ${A}`,{platform:D,platformPostId:V})}catch(H){let F=g(H),K={...Z.metadata,status:"failed"},q=c1.createPostContent(K,Z.content);await this.entityService.updateEntity({entity:{...f,content:q,metadata:{...f.metadata,status:"failed"}}}),await this.reportFailure(B,A,F),this.logger.error(`Post publish failed: ${A}`,{platform:D,error:F})}}catch(w){let f=g(w);this.logger.error("Unexpected error in publish handler",{entityId:A,error:f}),await this.reportFailure(B,A,f)}}async reportSuccess(x,B,A){await this.sendMessage({type:d5.reportSuccess,payload:{entityType:x,entityId:B,result:{id:A}}})}async reportFailure(x,B,A){await this.sendMessage({type:d5.reportFailure,payload:{entityType:x,entityId:B,error:A}})}async resolveSourceAttachment(x){if(!this.resolveAttachment||!x.sourceEntityType||!x.sourceEntityId)return[];let B=await this.resolveAttachment({sourceEntityType:x.sourceEntityType,sourceEntityId:x.sourceEntityId,attachmentType:"carousel"});return B?[B]:[]}async fetchDocumentData(x){if(!x?.length)return[];let B=[];for(let A of x){let w=await this.fetchSingleDocumentData(A.id);if(w)B.push(w)}return B}async fetchSingleDocumentData(x){try{let B=await this.entityService.getEntity({entityType:"document",id:x});if(!B){this.logger.warn("Document not found",{documentId:x});return}let A=B.content.match(/^data:application\/pdf;base64,(.+)$/);if(!A?.[1]){this.logger.warn("Invalid document data URL format",{documentId:x});return}let w=typeof B.metadata.filename==="string"?B.metadata.filename:`${x}.pdf`;return{type:"document",data:Buffer.from(A[1],"base64"),mimeType:"application/pdf",filename:w}}catch(B){this.logger.warn("Failed to fetch document",{documentId:x,error:B});return}}async fetchImageData(x){try{let B=await this.entityService.getEntity({entityType:"image",id:x});if(!B){this.logger.warn("Cover image not found",{imageId:x});return}let w=B.content.match(/^data:([^;]+);base64,(.+)$/);if(!w?.[1]||!w[2]){this.logger.warn("Invalid image data URL format",{imageId:x});return}let f=w[1],D=w[2];return{data:Buffer.from(D,"base64"),mimeType:f}}catch(B){this.logger.warn("Failed to fetch cover image",{imageId:x,error:B});return}}}function Dyx(x,B,A){if(B.size===0){A.debug("No providers configured, skipping publish-pipeline registration");return}x.messaging.subscribe(e8.pluginsRegistered,async()=>{let w=B.values().next().value;return await x.messaging.send({type:d5.register,payload:{entityType:"social-post",provider:w,config:{publishResultIdField:"platformPostId"}}}),A.info("Registered social-post with publish-pipeline"),{success:!0}})}function $yx(x,B,A){let w=new y_({sendMessage:x.messaging.send,logger:A.child("PublishExecuteHandler"),entityService:x.entityService,providers:B,permissions:x.permissions,resolveAttachment:x.attachments.resolve});x.messaging.subscribe(d5.execute,async(f)=>{return await w.handle(f.payload),{success:!0}}),A.debug("Subscribed to publish:execute messages")}var k30={autoGenerate:"social:auto-generate"};function Zyx(x,B){x.messaging.subscribe(l8.updated,async(A)=>{let{entityType:w,entityId:f,entity:D}=A.payload;if(w!=="post")return{success:!0};if(D.metadata?.status!=="queued")return{success:!0};try{if((await x.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:f}},limit:1}})).length>0)return B.debug(`Social post already exists for ${f}, skipping auto-generate`),{success:!0};return await x.messaging.send({type:k30.autoGenerate,payload:{sourceEntityType:w,sourceEntityId:f,platform:"linkedin"}}),B.info(`Auto-generate social post triggered for queued post ${f}`),{success:!0}}catch(Z){let Q=g(Z);return B.error(`Failed to trigger auto-generate for ${f}:`,{error:Q}),{success:!0}}}),B.debug("Subscribed to entity:updated for auto-generation")}function Qyx(x,B){x.messaging.subscribe(k30.autoGenerate,async(A)=>{let{sourceEntityType:w,sourceEntityId:f,platform:D}=A.payload;try{let $=await x.jobs.enqueue({type:`${c1.entityType}:generation`,data:{sourceEntityType:w,sourceEntityId:f,platform:D,addToQueue:!1},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"social-media-auto-generate"}}});return B.info(`Social post generation job enqueued for ${w}/${f}`,{jobId:$}),{success:!0,jobId:$}}catch($){let Z=g($);return B.error(`Failed to enqueue social post generation for ${f}:`,{error:Z}),{success:!1}}}),B.debug("Subscribed to social:auto-generate messages")}function Xyx(x,B){x.messaging.subscribe(w7.execute,async(A)=>{let{entityType:w}=A.payload;if(w!=="social-post")return{success:!0};B.info("Received generate:execute for social-post");try{let f=await x.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:5}});if(f.length===0)return B.info("No published posts found for social post generation"),await x.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:"No published posts available for social post generation"}}),{success:!0};let D=null;for(let Z of f)if((await x.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:Z.id}},limit:1}})).length===0){D=Z;break}if(!D)return B.info("All recent posts already have social posts"),await x.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:"All recent posts already have social posts generated"}}),{success:!0};let $=await x.jobs.enqueue({type:`${c1.entityType}:generation`,data:{sourceEntityType:"post",sourceEntityId:D.id,platform:"linkedin",addToQueue:!1},toolContext:{interfaceType:"job",actor:{kind:"service",serviceId:"social-media-auto-generate"}}});return B.info("Social post generation job queued",{jobId:$,sourcePostId:D.id}),{success:!0}}catch(f){let D=g(f);return B.error("Failed to handle generate:execute:",{error:D}),await x.messaging.send({type:w7.reportFailure,payload:{entityType:"social-post",error:D}}),{success:!0}}}),B.debug("Subscribed to generate:execute messages")}async function Yyx({entity:x,config:B}){let A=PZ.parse(x),w=c1.parsePostFrontmatter(A),f=c1.getPostContent(A);return{$type:"ai.rizom.brain.socialPost",title:w.title,platform:w.platform,body:f,format:"text/markdown",status:w.status,...w.publishedAt&&{publishedAt:w.publishedAt},...w.platformPostId&&{platformPostId:w.platformPostId},...w.sourceEntityType&&{sourceLocalEntityType:w.sourceEntityType},...w.sourceEntityId&&{sourceLocalEntityId:w.sourceEntityId},...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"social-post",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function M30(){return{entityType:"social-post",collection:"ai.rizom.brain.socialPost",lexicon:h4["ai.rizom.brain.socialPost"],validate:!1,buildRecord:Yyx}}var Wyx={name:"@brains/social-media",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Multi-provider social media posting with queue-based publishing",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/style-guide":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class v30 extends g8{entityType=c1.entityType;schema=PZ;adapter=c1;providers=new Map;unregisterAtprotoProjection;constructor(x={}){super("social-media",Wyx,x,_30)}createGenerationHandler(x){return new aY(this.logger.child("GenerationJobHandler"),x)}getTemplates(){return wyx()}getDataSources(){return[new ZC(this.logger.child("SocialPostDataSource"))]}getEntityTypeConfig(){return{projectionSourceRole:"secondary",publish:{publishStatuses:["queued","published","failed"]}}}async onRegister(x){if(this.initializeProviders(),Dyx(x,this.providers,this.logger),$yx(x,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)Zyx(x,this.logger),Qyx(x,this.logger),this.logger.info("Auto-generate on blog publish enabled");Xyx(x,this.logger),fyx(x),this.unregisterAtprotoProjection=R4.getInstance().register(M30()),this.logger.info("Social media plugin registered successfully")}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}initializeProviders(){if(this.config.linkedin?.accessToken){let x=L30(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",x),this.logger.info("LinkedIn provider initialized")}}}function N30(x={}){return new v30(x)}class WC{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(x,B){this.apiKey=x,this.fetchFn=B}async searchPhotos(x,B){let A=new URL(`${this.baseUrl}/search/photos`);A.searchParams.set("query",x),A.searchParams.set("page",String(B.page)),A.searchParams.set("per_page",String(B.perPage));let w=await this.fetchFn(A.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!w.ok)throw Error(`Unsplash API error: ${w.status} ${w.statusText}`);let f=eE9.parse(await w.json());return{photos:f.results.map(xj9),total:f.total,totalPages:f.total_pages,page:B.page}}async triggerDownload(x){try{await this.fetchFn(x,{headers:{Authorization:`Client-ID ${this.apiKey}`}})}catch{}}}var tE9=X.looseObject({id:X.string(),description:X.string().nullable(),alt_description:X.string().nullable(),urls:X.looseObject({raw:X.url(),full:X.url(),regular:X.url(),small:X.url(),thumb:X.url()}),links:X.looseObject({html:X.url(),download_location:X.url()}),user:X.looseObject({name:X.string(),links:X.looseObject({html:X.url()})}),width:X.number().int().nonnegative(),height:X.number().int().nonnegative()}),eE9=X.looseObject({total:X.number().int().nonnegative(),total_pages:X.number().int().nonnegative(),results:X.array(tE9)});function xj9(x){return{id:x.id,description:x.description,altDescription:x.alt_description,thumbnailUrl:x.urls.thumb,imageUrl:x.urls.regular,photographerName:x.user.name,photographerUrl:x.user.links.html,sourceUrl:x.links.html,downloadLocation:x.links.download_location,width:x.width,height:x.height}}async function HC(x,B,A,w){let f=await x.getEntity({entityType:B,id:A});if(!f)return!1;return await x.updateEntity({entity:{...f,metadata:{...f.metadata,coverImageId:w}}}),!0}var Bj9=X.object({query:X.string().describe("Search terms for stock photos"),perPage:X.number().min(1).max(30).default(10).describe("Results per page (1-30)"),page:X.number().min(1).default(1).describe("Page number")}),Aj9=X.object({photoId:X.string().describe("Photo ID from search results"),downloadLocation:X.url().describe("Download tracking URL (required by provider ToS)"),photographerName:X.string().describe("Photographer name for attribution"),photographerUrl:X.url().describe("Photographer profile URL for attribution"),sourceUrl:X.url().describe("Photo page URL on provider"),imageUrl:X.url().describe("Image URL to download"),title:X.string().optional().describe("Image entity title"),alt:X.string().optional().describe("Alt text for the image"),targetEntityType:X.string().optional().describe("Entity type to set cover image on"),targetEntityId:X.string().optional().describe("Entity ID to set cover image on")});function Hyx(x,B){return[wj9(x,B),fj9(x,B)]}function wj9(x,B){return E1(x,"search","Search for stock photos. Returns photo candidates with preview URLs and metadata. Use stock-photo_select to materialize a chosen photo into an image entity.",Bj9,async(A)=>{try{return{success:!0,data:await B.provider.searchPhotos(A.query,{page:A.page,perPage:A.perPage})}}catch(w){return{success:!1,error:g(w,"Search failed")}}},{sideEffects:"none"})}function fj9(x,B){return E1(x,"select","Select a stock photo from search results and materialize it as an image entity. Triggers provider download tracking per ToS. Optionally sets as cover image on a target entity.",Aj9,async(A)=>{let{photoId:w,downloadLocation:f,photographerName:D,photographerUrl:$,sourceUrl:Z,imageUrl:Q,title:Y,alt:W,targetEntityType:H,targetEntityId:F}=A,K={photographerName:D,photographerUrl:$,sourceUrl:Z},q=await B.entityService.listEntities({entityType:"image",options:{limit:1,filter:{metadata:{sourceUrl:Q}}}});if(q[0]){let G={imageEntityId:q[0].id,alreadyExisted:!0,attribution:K};if(H&&F)G.coverSet=await HC(B.entityService,H,F,q[0].id);return{success:!0,data:G}}let V=await B.jobs.enqueue({type:"select-photo",data:{photoId:w,downloadLocation:f,photographerName:D,photographerUrl:$,sourceUrl:Z,imageUrl:Q,...Y!==void 0?{title:Y}:{},...W!==void 0?{alt:W}:{},...H!==void 0?{targetEntityType:H}:{},...F!==void 0?{targetEntityId:F}:{}}}),b={imageEntityId:w,alreadyExisted:!1,attribution:K,jobId:V,status:"generating"};if(H&&F)b.coverSet=!1;return{success:!0,data:b}},{sideEffects:"external"})}var Dj9=X.object({photoId:X.string(),downloadLocation:X.url(),photographerName:X.string(),photographerUrl:X.url(),sourceUrl:X.url(),imageUrl:X.url(),title:X.string().optional(),alt:X.string().optional(),targetEntityType:X.string().optional(),targetEntityId:X.string().optional()});class I30 extends $9{deps;constructor(x,B){super(x,{schema:Dj9,jobTypeName:"select-photo"});this.deps=B}async process(x,B,A){await this.reportProgress(A,{progress:10,message:"Tracking stock photo download"}),await this.deps.provider.triggerDownload(x.downloadLocation),await this.reportProgress(A,{progress:35,message:"Downloading stock photo"});let w=await this.deps.fetchImage(x.imageUrl),f=x.title??`Stock photo ${x.photoId}`,D=dB.createImageEntity({dataUrl:w,title:f,alt:x.alt??f});await this.reportProgress(A,{progress:75,message:"Saving stock photo"});let{entityId:$}=await this.deps.entityService.createEntity({entity:{id:x.photoId,...D,metadata:{...D.metadata,sourceUrl:x.imageUrl}}}),Z={imageEntityId:$,alreadyExisted:!1};if(x.targetEntityType&&x.targetEntityId){if(Z.coverSet=await HC(this.deps.entityService,x.targetEntityType,x.targetEntityId,$),!Z.coverSet)Z.warning=`Target entity ${x.targetEntityType}:${x.targetEntityId} not found; cover image not set`}return await this.reportProgress(A,{progress:100,message:"Stock photo selected"}),Z}summarizeDataForLog(x){return{photoId:x.photoId,hasTarget:x.targetEntityType!==void 0}}}var Fyx={name:"@brains/stock-photo",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Stock photo search and selection \u2014 Unsplash provider",dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts","./env-schema":"./src/env-schema.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var Zj9=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class O30 extends D8{deps;cachedTools=null;constructor(x={},B={}){super("stock-photo",Fyx,x,Zj9);this.deps=B}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let x=this.getContext(),B=this.createProvider();return this.cachedTools=Hyx(this.id,{provider:B,entityService:x.entityService,fetchImage:this.deps.fetchImage??m3,jobs:x.jobs}),this.cachedTools}async registerJobHandlers(){if(!this.config.apiKey)return;let x=this.getContext();x.jobs.registerHandler("select-photo",new I30(this.logger.child("SelectPhotoJobHandler"),{provider:this.createProvider(),entityService:x.entityService,fetchImage:this.deps.fetchImage??m3}))}createProvider(){return new WC(this.config.apiKey??"",this.deps.fetch??globalThis.fetch)}}function h30(x={},B={}){return new O30(x,B)}var Qj9=X.enum(["public","shared","restricted"]),Kyx=X.enum(["canonical","primary","secondary","supporting","ambient","excluded"]),Xj9=X.object({weight:X.number().min(0).max(1),canMint:X.boolean()}),Yj9={canonical:{weight:1,canMint:!0},primary:{weight:1,canMint:!0},secondary:{weight:0.8,canMint:!0},supporting:{weight:0.55,canMint:!1},ambient:{weight:0.35,canMint:!1},excluded:{weight:0,canMint:!1}},qyx=X.object({includeEntityTypes:X.array(X.string()).default(["*"]),excludeEntityTypes:X.array(X.string()).default([]),minRelevanceScore:X.number().min(0).max(1).default(0.5),createRelevanceThreshold:X.number().min(0).max(1).default(0.7),reinforceRelevanceThreshold:X.number().min(0).max(1).default(0.5),sourceWeights:X.record(X.string(),X.number().min(0).max(1)).default({}),mintableEntityTypes:X.array(X.string()).default([]),sourceRolePolicies:X.partialRecord(Kyx,Xj9).default({}).transform((x)=>({...Yj9,...x})),sourceRoleOverrides:X.record(X.string(),Kyx).default({}),maxEntitiesPerBatch:X.number().int().min(1).default(4),topicSoftCeilingSourceRatio:X.number().min(1).default(5),mergeSimilarityThreshold:X.number().min(0).max(1).default(0.85),semanticMergeDistance:X.number().min(0).max(1).default(0.35),reconciliationMaxPairs:X.number().int().min(0).default(100),autoMerge:X.boolean().default(!0),extractableStatuses:X.array(X.string()).default(["published"]),enableAutoExtraction:X.boolean().default(!0),extractionVisibility:Qj9.default("public"),sourceChangeBatchDelayMs:X.number().int().min(0).default(1000)});var aD5=X.object({}),Wj9=X.record(X.string(),X.unknown()).transform(()=>({})),Kz=j8.extend({entityType:X.literal("topic"),metadata:Wj9}),sD5=X.object({content:X.string()}),zyx=X.object({title:X.string().describe("Topic title")});var sY="topics",R8="topic",R30="topics-projection",byx="topic:project",FC="topics-plugin",KC="topics:batch-completed",Vyx="topics-source-batch",qC="topics:knowledge-map";class D7 extends ox{constructor(){super({entityType:R8,purpose:"A recurring theme or subject derived from the user's content.",schema:Kz,frontmatterSchema:zyx})}buildFrontmatter(x){return{title:x}}toMarkdown(x){let B=this.parseTopicBody(x.content);return this.buildMarkdown(B.content,this.buildFrontmatter(B.title))}fromMarkdown(x){return{content:x,entityType:R8}}extractMetadata(x){return{}}generateFrontMatter(x){let B=this.parseTopicBody(x.content),w=this.buildMarkdown("",this.buildFrontmatter(B.title)).match(/^---\n[\s\S]*?\n---/);return w?w[0]:""}parseTopicBody(x){if(x.startsWith("---"))try{let B=this.parseFrontmatter(x);return{content:this.extractBody(x).replace(/\n*## Sources[\s\S]*$/,"").trim(),formatted:x,title:B.title}}catch{return{content:x,formatted:x,title:"Unknown Topic"}}return{content:x,formatted:x,title:"Unknown Topic"}}createTopicBody(x){return this.buildMarkdown(x.content,this.buildFrontmatter(x.title))}}var Hj9=X.object({title:X.string().max(100),content:X.string(),relevanceScore:X.number().min(0).max(1)}),Uyx=X.array(Hj9);var Fj9=X.object({topics:Uyx}),Gyx=mx({name:"topics:extraction",description:"Extract topics from conversation text",dataSourceId:"shell:ai-content",schema:Fj9,basePrompt:`You are an expert at analyzing content and extracting key topics.
6340
6340
 
6341
6341
  Analyze the provided content and extract meaningful topics discussed.
6342
6342
 
@@ -6749,7 +6749,7 @@ ${B.content}`}).join(`
6749
6749
 
6750
6750
  `)}var nj9={canonical:{weight:1,canMint:!0},primary:{weight:1,canMint:!0},secondary:{weight:0.8,canMint:!0},supporting:{weight:0.55,canMint:!1},ambient:{weight:0.35,canMint:!1},excluded:{weight:0,canMint:!1}};async function oY(x,B,A,w={}){if(x.length===0)return{created:0,merged:0,skipped:0,batches:0};let f=w.minRelevanceScore??0,D=w.createRelevanceThreshold??0.7,$=w.reinforceRelevanceThreshold??0.5,Z=w.sourceWeights??{},Q=new Set(w.mintableEntityTypes??[]),Y={...nj9,...w.sourceRolePolicies??{}},W=w.autoMerge??!1,H=w.semanticMergeDistance??w.mergeSimilarityThreshold??0.35,F=w.targetVisibility??"public",K=w.maxEntitiesPerBatch??4,q=dj9(cyx(x),K),V=new u2(B.entityService,A),b=w.topicMergeSynthesizer??new p_(B,A),G=await LC(B.entityService,void 0,F),E=w.sourceEntityCount??x.length,_=sj9(E,w.topicSoftCeilingSourceRatio??5),L=new Map,N=0,y=0,c=0;for(let R of q){A.info(`Processing batch of ${R.length} entities`);let M=lj9(R),B0=aj9({batch:R,getEntityTypeConfig:(I0)=>B.entityService.getEntityTypeConfig(I0),sourceWeights:Z,mintableEntityTypes:Q,sourceRolePolicies:Y,sourceRoleOverrides:w.sourceRoleOverrides??{}}),G0=kC({entityTitle:`Batch of ${R.length} entities`,entityType:"batch",content:M,existingTopicTitles:G});try{let J0=(await B.ai.generate({prompt:G0,templateName:"topics:extraction",representedIdentity:"none"})).topics.filter((v0)=>v0.relevanceScore>=f);for(let v0 of J0)try{let Ex=v0.relevanceScore*B0.weight;if(Ex<$){c++;continue}if(W){let F0=await V.findMergeCandidate({incoming:v0,threshold:H,additionalCandidates:Array.from(L.values()),targetVisibility:F});if(F0){let $0=await b.synthesize({existingTopic:F0.topic,incomingTopic:v0});if($0.verdict!=="distinct"){let qx=await V.applySynthesizedMerge({existingId:F0.topic.id,synthesized:{...$0,title:F0.title},visibility:F});if(!qx)throw Error(`Failed to merge topic: ${v0.title}`);L.set(qx.id,qx),y++;continue}}}let _0=G.length+L.size>=_;if(!(B0.canMint&&Ex>=D&&!_0)){c++;continue}let u=V.getTopicIdForTitle(v0.title,F);if(L.has(u)){c++;continue}let t=await V.createTopicOptimistic({title:v0.title,content:v0.content,visibility:F});if(t.topic)L.set(t.topic.id,t.topic);if(t.created)N++;else c++}catch(Ex){A.error("Topic batch item failed",{title:v0.title,error:g(Ex)})}}catch(I0){A.error("Batch topic extraction failed",{batchSize:R.length,promptChars:G0.length,error:g(I0)})}}let n={created:N,merged:y,skipped:c,batches:q.length};if(N>0||y>0)await B.messaging.send({type:KC,payload:n,broadcast:!0});return n}function dj9(x,B){if(B<=0)return x;return x.flatMap((A)=>{let w=[];for(let f=0;f<A.length;f+=B)w.push(A.slice(f,f+B));return w})}function aj9(x){let B=Object.keys(x.sourceWeights).length>0,A=x.mintableEntityTypes.size>0;return x.batch.reduce((w,f)=>{let D=x.getEntityTypeConfig(f.entityType),$=x.sourceRoleOverrides[f.entityType]??D.projectionSourceRole??(D.projectionSource===!1?"excluded":"primary"),Z=x.sourceRolePolicies[$],Q=B?x.sourceWeights[f.entityType]??1:Z.weight,Y=A?x.mintableEntityTypes.has(f.entityType):Z.canMint;return{weight:Math.max(w.weight,Q),canMint:w.canMint||Y}},{weight:0,canMint:!1})}function sj9(x,B){return Math.min(24,Math.max(5,Math.ceil(x/B)))}var MC=new D7;async function u_(x){let B=x.targetVisibility??"public",A=x.maxPairs??100,w=new u2(x.context.entityService,x.logger),f=x.synthesizer??new p_(x.context,x.logger),D={success:!0,scannedTopics:0,scannedPairs:0,merged:0,distinct:0,skipped:0,deletedIds:[]},$=new Set,Z=!0;while(Z&&D.scannedPairs<A){Z=!1;let Q=rj9(await w.listTopics({visibility:B}));D.scannedTopics+=Q.length;for(let Y of Q){if(D.scannedPairs>=A)break;if(D.deletedIds.includes(Y.id))continue;let W=MC.parseTopicBody(Y.content),H=await x.context.entityService.searchWithDistances({query:`${W.title}
6751
6751
 
6752
- ${W.content}`});for(let F of H){if(D.scannedPairs>=A)break;if(F.entityType!==R8)continue;if(F.entityId===Y.id)continue;if(F.distance>x.semanticMergeDistance)continue;let K=await w.getTopic(F.entityId,B);if(!K||K.id===Y.id)continue;let q=tj9(Y.id,K.id);if($.has(q))continue;$.add(q),D.scannedPairs++;let{canonical:V,absorbed:b}=oj9(Y,K),G=MC.parseTopicBody(b.content),E=await f.synthesize({existingTopic:V,incomingTopic:{title:G.title,content:G.content,relevanceScore:1}});if(E.verdict==="distinct"){D.distinct++;continue}if(!await w.applySynthesizedMerge({existingId:V.id,synthesized:{title:E.title,content:E.content},visibility:B})){D.skipped++;continue}await w.deleteTopic(b.id),D.deletedIds.push(b.id),D.merged++,Z=!0;break}if(Z)break}}if(D.merged>0&&x.emitEvent!==!1)await x.context.messaging.send({type:KC,payload:D,broadcast:!0});return D}function rj9(x){return[...x].sort((B,A)=>{let w=B.created.localeCompare(A.created);if(w!==0)return w;return B.id.localeCompare(A.id)})}function oj9(x,B){let A=MC.parseTopicBody(x.content).content.length,w=MC.parseTopicBody(B.content).content.length;if(A!==w)return A>w?{canonical:x,absorbed:B}:{canonical:B,absorbed:x};let f=x.created.localeCompare(B.created);if(f!==0)return f<0?{canonical:x,absorbed:B}:{canonical:B,absorbed:x};return x.id.localeCompare(B.id)<=0?{canonical:x,absorbed:B}:{canonical:B,absorbed:x}}function tj9(x,B){return[x,B].sort().join("\x00")}var ej9=X.discriminatedUnion("mode",[X.object({mode:X.literal("derive"),reason:X.string().optional()}),X.object({mode:X.literal("rebuild"),reason:X.string().optional()}),X.object({mode:X.literal("source-batch"),minRelevanceScore:X.number().min(0).max(1).optional()}),X.object({mode:X.literal("reconcile"),reason:X.string().optional()})]);class i30{refs=new Map;add(x){this.refs.set(`${x.entityType}:${x.entityId}`,x)}drain(){let x=Array.from(this.refs.values());return this.refs.clear(),x}}function gyx(x){let{context:B,logger:A,config:w}=x,f=x.reconcileTopics??(async()=>u_({context:B,logger:A,semanticMergeDistance:w.semanticMergeDistance,targetVisibility:w.extractionVisibility,maxPairs:w.reconciliationMaxPairs}));return{process:async(D)=>{if(D.mode==="derive")return await x.extractAllTopics(),await f(),{success:!0};if(D.mode==="rebuild")return await x.rebuildAllTopics(),await f(),{success:!0};if(D.mode==="reconcile")return f();let $=await x_9({context:B,logger:A,config:w,sourceBatch:x.sourceBatch,isEntityPublished:x.isEntityPublished,minRelevanceScore:D.minRelevanceScore??w.minRelevanceScore});if($.created>0||$.merged>0)await f();return $},validateAndParse:(D)=>{let $=ej9.safeParse(D??{});return $.success?$.data:null}}}async function x_9(x){let B=x.sourceBatch.drain(),A=await Promise.all(B.map(async(W)=>({ref:W,entity:await x.context.entityService.getEntity({entityType:W.entityType,id:W.entityId})}))),w=0,f=0,D=0,$=0,Z=[];for(let{ref:W,entity:H}of A){if(!H){f++;continue}if(H.contentHash!==W.contentHash){w++;continue}if(!x.isEntityPublished(H)){D++;continue}if(!vC(H.visibility,x.config.extractionVisibility)){$++;continue}Z.push(H)}if(Z.length===0)return{success:!0,sources:B.length,created:0,merged:0,skipped:0,batches:0,stale:w,missing:f,unpublished:D,hidden:$};let Q=await A_9(x.context,x.config),Y=await oY(Z,x.context,x.logger,{minRelevanceScore:x.minRelevanceScore,createRelevanceThreshold:x.config.createRelevanceThreshold,reinforceRelevanceThreshold:x.config.reinforceRelevanceThreshold,sourceWeights:x.config.sourceWeights,mintableEntityTypes:x.config.mintableEntityTypes,sourceRolePolicies:x.config.sourceRolePolicies,sourceRoleOverrides:x.config.sourceRoleOverrides,sourceEntityCount:Q,maxEntitiesPerBatch:x.config.maxEntitiesPerBatch,topicSoftCeilingSourceRatio:x.config.topicSoftCeilingSourceRatio,autoMerge:x.config.autoMerge,semanticMergeDistance:x.config.semanticMergeDistance,targetVisibility:x.config.extractionVisibility});return{success:!0,sources:B.length,...Y,stale:w,missing:f,unpublished:D,hidden:$}}function Tyx(){return{priority:5,source:FC,deduplication:"coalesce",deduplicationKey:"topics-initial-derivation",metadata:{operationType:"data_processing",operationTarget:"topics-initial-derivation",pluginId:sY}}}async function pyx(x){let B=await Syx(x);if(B.length===0){x.logger.info("No entities to extract topics from");return}x.logger.info(`Batch topic extraction: ${B.length} entities`);let A=await oY(B,x.context,x.logger,{minRelevanceScore:x.config.minRelevanceScore,createRelevanceThreshold:x.config.createRelevanceThreshold,reinforceRelevanceThreshold:x.config.reinforceRelevanceThreshold,sourceWeights:x.config.sourceWeights,mintableEntityTypes:x.config.mintableEntityTypes,sourceRolePolicies:x.config.sourceRolePolicies,sourceRoleOverrides:x.config.sourceRoleOverrides,sourceEntityCount:B.length,maxEntitiesPerBatch:x.config.maxEntitiesPerBatch,topicSoftCeilingSourceRatio:x.config.topicSoftCeilingSourceRatio,autoMerge:x.config.autoMerge,semanticMergeDistance:x.config.semanticMergeDistance,targetVisibility:x.config.extractionVisibility});x.logger.info("Batch topic extraction complete",A)}async function uyx(x){let B=await Syx(x),A=await NC(B,x.context,x.logger,x.config);x.logger.info("Topic rebuild complete",A)}async function NC(x,B,A,w){let f=new u2(B.entityService,A),D=await f.listTopics({visibility:w.extractionVisibility});for(let Z of D)await f.deleteTopic(Z.id);if(x.length===0)return{deleted:D.length,created:0,merged:0,skipped:0,batches:0};let $=await oY(x,B,A,{minRelevanceScore:w.minRelevanceScore,createRelevanceThreshold:w.createRelevanceThreshold,reinforceRelevanceThreshold:w.reinforceRelevanceThreshold,sourceWeights:w.sourceWeights,mintableEntityTypes:w.mintableEntityTypes,sourceRolePolicies:w.sourceRolePolicies,sourceRoleOverrides:w.sourceRoleOverrides,sourceEntityCount:x.length,maxEntitiesPerBatch:w.maxEntitiesPerBatch,topicSoftCeilingSourceRatio:w.topicSoftCeilingSourceRatio,autoMerge:w.autoMerge,semanticMergeDistance:w.semanticMergeDistance,targetVisibility:w.extractionVisibility});return{deleted:D.length,...$}}async function Syx(x){let B=B_9(x),A=[];for(let w of B){let f=await x.context.entityService.listEntities({entityType:w,options:{filter:{visibilityScope:x.config.extractionVisibility}}});for(let D of f){if(!x.isEntityPublished(D))continue;A.push(D)}}return A}function B_9(x){return x.context.entityService.getEntityTypes().filter((A)=>x.shouldProcessEntityType(A))}async function A_9(x,B){let A=x.entityService.getEntityTypes().filter((f)=>{if(f==="topic")return!1;if(B.excludeEntityTypes.includes(f))return!1;if(!B.includeEntityTypes.includes("*")&&!B.includeEntityTypes.includes(f))return!1;return x.entityService.getEntityTypeConfig(f).projectionSource!==!1});return(await Promise.all(A.map((f)=>x.entityService.countEntities({entityType:f,options:{filter:{visibilityScope:B.extractionVisibility}}})))).reduce((f,D)=>f+D,0)}var tY=X.object({entityType:X.string(),content:X.string(),metadata:X.record(X.string(),X.unknown()).optional()}),D_9=tY.extend({minRelevanceScore:X.number().optional()}),$_9=X.object({contentA:tY,contentB:tY,minRelevanceScore:X.number().optional(),threshold:X.number().min(0).max(1).optional()}),Vz=X.object({id:X.string().optional(),title:X.string(),content:X.string()}),Z_9=X.object({existingTopics:X.array(Vz),incomingTopic:Vz,threshold:X.number().optional()}),Q_9=X.object({existingTopics:X.array(Vz).default([]),incomingTopic:Vz.extend({relevanceScore:X.number().min(0).max(1).optional()}),threshold:X.number().optional()}),X_9=X.object({entities:X.array(tY).min(1),minRelevanceScore:X.number().optional()}),Y_9=X.object({existingTopics:X.array(Vz).optional(),entities:X.array(tY)}),W_9=X.object({existingTopics:X.array(Vz).min(2),threshold:X.number().optional(),maxPairs:X.number().int().min(0).optional()}),H_9=tY.extend({id:X.string()}),F_9=X.object({entities:X.array(H_9).min(1)}),K_9=X.object({fixture:X.string(),minTopicCount:X.number().int().min(0).default(5),maxTopicCount:X.number().int().min(0).default(14),requiredTitleMatches:X.array(X.string()).default([]),forbiddenTitleMatches:X.array(X.string()).default([]),forbiddenTitlePairs:X.array(X.object({left:X.string(),right:X.string()})).default([])}),q_9=X.object({entities:X.array(tY)});function bz(x,B=""){return{id:`eval${B}-${Date.now()}`,entityType:x.entityType,content:x.content,contentHash:_8(x.content),visibility:"public",metadata:x.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}}function iyx(x){return{title:x.title,relevanceScore:x.relevanceScore}}function z_9(x){let B=x.metadata.title;return typeof B==="string"?B:x.id}function b_9(x,B){let A=[];if(x.length<B.minTopicCount)A.push(`too few topics: ${x.length}`);if(x.length>B.maxTopicCount)A.push(`too many topics: ${x.length}`);for(let w of B.requiredTitleMatches){let f=new RegExp(w,"i");if(!x.some((D)=>f.test(D)))A.push(`missing required title match: ${w}`)}for(let w of B.forbiddenTitleMatches){let f=new RegExp(w,"i"),D=x.find(($)=>f.test($));if(D)A.push(`forbidden title matched ${w}: ${D}`)}for(let w of B.forbiddenTitlePairs){let f=new RegExp(w.left,"i"),D=new RegExp(w.right,"i"),$=x.some((Q)=>f.test(Q)),Z=x.some((Q)=>D.test(Q));if($&&Z)A.push(`forbidden duplicate pair present: ${w.left} / ${w.right}`)}return A}function V_9(x,B){return{...x,sources:[{id:B.id,type:B.entityType,title:z_9(B)}]}}async function BD(x){let B=await x.entityService.listEntities({entityType:R8});await Promise.all(B.map((A)=>x.entityService.deleteEntity({entityType:R8,id:A.id})))}async function IC(x){for(;;){if((await x.jobs.getActiveJobs([O_.embedding])).length===0)return;await new Promise((A)=>setTimeout(A,100))}}function lyx(x){let{context:B,logger:A,config:w}=x,f=new S30(B,A),D=new D7,$=async(Z,Q,Y="")=>{let W=bz(Z,Y);return f.extractFromEntity(W,Q)};B.eval.registerHandler("extractFromEntity",async(Z)=>{await BD(B);let Q=D_9.parse(Z),Y=Q.minRelevanceScore??w.minRelevanceScore,W=bz(Q);return(await f.extractFromEntity(W,Y)).map((F)=>V_9(F,W))}),B.eval.registerHandler("checkMergeSimilarity",async(Z)=>{await BD(B);let Q=$_9.parse(Z),Y=Q.minRelevanceScore??w.minRelevanceScore,W=Q.threshold??w.semanticMergeDistance,[H,F]=await Promise.all([$(Q.contentA,Y,"-a"),$(Q.contentB,Y,"-b")]),K=new u2(B.entityService,A),q=[];for(let G of H){let E=await K.createTopic(G);if(E)q.push(E)}await IC(B);let V=(await Promise.all(F.map(async(G)=>{let E=await K.findMergeCandidate({incoming:G,threshold:W,additionalCandidates:q});if(!E)return null;return{incomingTitle:G.title,candidateTitle:E.title,candidateScore:E.score}}))).filter((G)=>G!==null),b=V.map((G)=>G.candidateTitle);return{topicsA:H.map(iyx),topicsB:F.map(iyx),matchingTitles:b,mergeCandidates:V,wouldMerge:V.length>0}}),B.eval.registerHandler("detectMergeCandidate",async(Z)=>{await BD(B);let Q=Z_9.parse(Z),Y=Q.threshold??w.semanticMergeDistance,W=new u2(B.entityService,A),H=[];for(let K of Q.existingTopics){let q=await W.createTopic(K);if(q)H.push(q)}await IC(B);let F=await W.findMergeCandidate({incoming:{title:Q.incomingTopic.title,content:Q.incomingTopic.content},threshold:Y,additionalCandidates:H});return{found:F!==null,candidateTitle:F?.title,candidateScore:F?.score}}),B.eval.registerHandler("processTopicWithAutoMerge",async(Z)=>{await BD(B);let Q=Q_9.parse(Z),Y=new u2(B.entityService,A);for(let K of Q.existingTopics)await Y.createTopic({title:K.title,content:K.content});await IC(B);let W=bz({entityType:"post",content:Q.incomingTopic.content,metadata:{title:Q.incomingTopic.title}},"-source"),H=await oY([W],B,A,{minRelevanceScore:0,autoMerge:!0,semanticMergeDistance:Q.threshold??w.semanticMergeDistance}),F=await B.entityService.listEntities({entityType:R8});return{...H,topicCount:F.length,topics:F.map(g_)}}),B.eval.registerHandler("rebuildTopics",async(Z)=>{await BD(B);let Q=Y_9.parse(Z),Y=new u2(B.entityService,A);for(let K of Q.existingTopics??[])await Y.createTopic(K);let W=Q.entities.map((K,q)=>bz(K,`-rebuild-${q}`)),H=await NC(W,B,A,w),F=await B.entityService.listEntities({entityType:R8});return{...H,topicCount:F.length,topics:F.map(g_)}}),B.eval.registerHandler("reconcileExistingTopics",async(Z)=>{await BD(B);let Q=W_9.parse(Z);for(let H of Q.existingTopics){let F=D.createTopicBody({title:H.title,content:H.content});await B.entityService.createEntity({entity:{id:H.id??H.title,entityType:R8,content:F,visibility:"public",metadata:{}}})}await IC(B);let Y=await u_({context:B,logger:A,semanticMergeDistance:Q.threshold??w.semanticMergeDistance,targetVisibility:"public",maxPairs:Q.maxPairs??w.reconciliationMaxPairs}),W=await B.entityService.listEntities({entityType:R8});return{...Y,topicCount:W.length,topics:W.map(g_)}}),B.eval.registerHandler("extractSequentially",async(Z)=>{await BD(B);let Q=X_9.parse(Z),Y=Q.minRelevanceScore??w.minRelevanceScore,W=new u2(B.entityService,A),H=[];for(let[K,q]of Q.entities.entries()){let V=bz(q,`-sequential-${K}`),b=await f.extractFromEntity(V,Y);for(let G of b)await W.createTopic({title:G.title,content:G.content});H.push({extractedTitles:b.map((G)=>G.title),extractedCount:b.length})}let F=await B.entityService.listEntities({entityType:R8});return{totalTopics:F.length,perEntity:H,topics:F.map(qz)}}),B.eval.registerHandler("rebuildCorpusFixture",async(Z)=>{await BD(B);let Q=K_9.parse(Z),W=F_9.parse(JSON.parse(await w_9(f_9(process.cwd(),Q.fixture),"utf8"))).entities.map((b)=>({id:b.id,entityType:b.entityType,content:b.content,contentHash:_8(b.content),visibility:"public",metadata:b.metadata??{},created:"2026-01-01T00:00:00Z",updated:"2026-01-01T00:00:00Z"})),H=await NC(W,B,A,w),F=await u_({context:B,logger:A,semanticMergeDistance:w.semanticMergeDistance,targetVisibility:w.extractionVisibility,maxPairs:w.reconciliationMaxPairs}),K=(await B.entityService.listEntities({entityType:R8})).map(g_),q=K.map((b)=>b.title),V=b_9(q,Q);return{sourceCount:W.length,topicCount:K.length,topicTitles:q,issueCount:V.length,issues:V,rebuild:H,reconciliation:F,topics:K}}),B.eval.registerHandler("batchExtract",async(Z)=>{await BD(B);let Y=q_9.parse(Z).entities.map((F,K)=>bz(F,`-batch-${K}`)),W=await oY(Y,B,A,{minRelevanceScore:w.minRelevanceScore}),H=await B.entityService.listEntities({entityType:R8});return{...W,topicCount:H.length,topics:H.map(qz)}})}var U_9=new D7;async function nyx({entity:x,config:B}){let A=Kz.parse(x),w=U_9.parseTopicBody(A.content);return{$type:"ai.rizom.brain.topic",title:w.title,body:w.content,format:"text/markdown",...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"topic",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function l30(){return{entityType:"topic",collection:"ai.rizom.brain.topic",lexicon:h4["ai.rizom.brain.topic"],validate:!1,buildRecord:nyx}}var dyx={name:"@brains/topics",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Extract and manage topics from conversations",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},main:"./src/index.ts",private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};var E_9=new D7,j_9=X.looseObject({status:X.unknown().optional()});class ayx extends g8{entityType=R8;schema=Kz;adapter=E_9;unregisterAtprotoProjection;sourceBatch=new i30;constructor(x={}){super(sY,dyx,x,qyx)}getEntityTypeConfig(){return{weight:0.5,projectionSource:!1,projectionSourceRole:"excluded"}}getTemplates(){return{extraction:Gyx,"merge-synthesis":Eyx,"topic-list":jyx,"topic-detail":_yx,"knowledge-map":Iyx()}}getDataSources(){return[new C30(this.logger.child("TopicsDataSource")),new T30]}getDerivedEntityProjections(x){if(!this.config.enableAutoExtraction)return[];return[{id:R30,targetType:R8,job:{type:byx,handler:gyx({context:x,logger:this.logger,config:this.config,extractAllTopics:()=>this.extractAllTopics(x),rebuildAllTopics:()=>this.rebuildAllTopics(x),sourceBatch:this.sourceBatch,isEntityPublished:(B)=>this.isEntityPublished(B)})},initialSync:{shouldEnqueue:async()=>!await xF(x,R8,{visibility:this.config.extractionVisibility}),jobData:{mode:"derive",reason:"initial-sync"},jobOptions:Tyx()},sourceChange:{sourceTypes:this.config.includeEntityTypes,requireInitialSync:!0,jobData:(B)=>{let A=B.entity;if(!A)return null;if(!this.shouldProcessEntityType(A.entityType,x.entityService))return null;if(!this.isEntityPublished(A))return null;if(!vC(A.visibility,this.config.extractionVisibility))return null;return this.sourceBatch.add({entityId:A.id,entityType:A.entityType,contentHash:A.contentHash}),{mode:"source-batch"}},jobOptions:()=>({priority:5,source:FC,delayMs:this.config.sourceChangeBatchDelayMs,deduplication:"skip",deduplicationKey:Vyx,metadata:{operationType:"data_processing",operationTarget:"topic-source-batch",pluginId:sY}})}}]}async onRegister(x){x.insights.register("topic-distribution",Oyx()),hyx({context:x}),Ryx({context:x}),lyx({context:x,logger:this.logger,config:this.config}),this.unregisterAtprotoProjection=R4.getInstance().register(l30())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}hasRunInitialDerivation(){return this.getDerivedEntityProjectionController(R30)?.hasQueuedInitialSync()??!1}shouldProcessEntityType(x,B){if(x===R8)return!1;if(this.config.excludeEntityTypes.includes(x))return!1;if(!this.config.includeEntityTypes.includes("*")&&!this.config.includeEntityTypes.includes(x))return!1;return B.getEntityTypeConfig(x).projectionSource!==!1}isEntityPublished(x){let B=j_9.safeParse(x.metadata),A=B.success?B.data.status:void 0;if(A===void 0||A===null)return!0;if(typeof A!=="string")return!1;return this.config.extractableStatuses.includes(A)}async extractAllTopics(x){await pyx({context:x,logger:this.logger,config:this.config,shouldProcessEntityType:(B)=>this.shouldProcessEntityType(B,x.entityService),isEntityPublished:(B)=>this.isEntityPublished(B)})}async rebuildAllTopics(x){await uyx({context:x,logger:this.logger,config:this.config,shouldProcessEntityType:(B)=>this.shouldProcessEntityType(B,x.entityService),isEntityPublished:(B)=>this.isEntityPublished(B)})}}function syx(x={}){return new ayx(x)}var oyx=X.strictObject({source:n30,item:ryx}),tyx=X.strictObject({source:n30,error:X.literal("Source unavailable")}),d30=X.strictObject({entries:X.array(oyx).max(1e4),errors:X.array(tyx).max(1000)});class OC{id="unified-inbox:inbox";name="Unified Inbox DataSource";description="Aggregates live source-owned operator attention";registry;constructor(x){this.registry=x}async getInboxData(){let x=this.registry.listSources(),B=await Promise.allSettled(x.map(async(f)=>({source:f,items:await f.list()}))),A=[],w=[];for(let f=0;f<B.length;f++){let D=B[f],$=x[f];if(!D||!$)continue;let Z=__9($);if(D.status==="rejected"){w.push({source:Z,error:"Source unavailable"});continue}for(let Q of D.value.items)A.push({source:Z,item:Q})}return A.sort(P_9),w.sort((f,D)=>f.source.sourceId.localeCompare(D.source.sourceId)),d30.parse({entries:A,errors:w})}async fetch(x,B,A){return B.parse(await this.getInboxData())}}function __9(x){return{sourceId:x.sourceId,displayName:x.displayName}}function P_9(x,B){return eyx(x.item.urgency)-eyx(B.item.urgency)||B.item.receivedAt.localeCompare(x.item.receivedAt)||x.source.sourceId.localeCompare(B.source.sourceId)||x.item.id.localeCompare(B.item.id)}function eyx(x){return x==="high"?0:1}var xmx={name:"@brains/unified-inbox",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Live aggregation for source-owned operator attention",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var L_9=X.strictObject({});class a30 extends D8{constructor(){super("unified-inbox",xmx,{},L_9)}async onRegister(x){x.entities.registerDataSource(new OC(x.inbox))}}function s30(){return new a30}var Bmx={name:"@brains/web-chat",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Web chat interface for Brains",dependencies:{"@ai-sdk/react":"^3.0.208","@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@streamdown/cjk":"^1.0.3","@streamdown/code":"^1.1.1","@streamdown/math":"^1.0.2","@streamdown/mermaid":"^1.0.2","@tanstack/react-query":"^5.0.0",ai:"^6.0.206","class-variance-authority":"^0.7.0",cmdk:"^1.1.1","lucide-react":"^1.20.0",nanoid:"^5.0.4","radix-ui":"^1.6.0",react:"^19.2.7","react-dom":"^19.2.7",shiki:"^4.2.0",streamdown:"^2.5.0","tailwind-merge":"^3.6.0","use-stick-to-bottom":"^1.1.6"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.0.3","happy-dom":"^20.10.6",typescript:"^7.0.2",vite:"^8.0.16"},exports:{".":"./src/index.ts"},files:["src","dist","package.json"],private:!0,scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json"},type:"module"};async function Amx(x,B){let A=await B.resolvePermissionLevel(x);if(A==="public")return B.createAuthLoginRequiredResponse(x);let w=new URL(x.url),f=w.searchParams.get("id")?.trim();if(!f)return new Response("Missing document id",{status:400});let D=await fmx({entityType:"document",id:f,permissionLevel:A,entityService:B.entityService});if(!D)return new Response("Document not found",{status:404});if(typeof D.content!=="string")return new Response("Document content is not a PDF",{status:415});let $=oV("document",D.content);if(!$)return new Response("Document content is not a PDF",{status:415});let Z=tV(D.metadata,f,"document",$.mimeType);return Dmx({requestUrl:w,data:$.data,mediaType:$.mimeType,filename:Z})}async function wmx(x,B){let A=await B.resolvePermissionLevel(x);if(A==="public")return B.createAuthLoginRequiredResponse(x);let w=new URL(x.url),f=w.searchParams.get("id")?.trim();if(!f)return new Response("Missing image id",{status:400});let D=await fmx({entityType:"image",id:f,permissionLevel:A,entityService:B.entityService});if(!D)return new Response("Image not found",{status:404});if(typeof D.content!=="string")return new Response("Image content is not an image",{status:415});let $=oV("image",D.content);if(!$)return new Response("Image content is not an image",{status:415});let Z=tV(D.metadata,f,"image",$.mimeType);return Dmx({requestUrl:w,data:$.data,mediaType:$.mimeType,filename:Z})}async function fmx(x){let B={entityType:x.entityType,id:x.id},A=await Ik({entityRef:B,userLevel:x.permissionLevel,getEntity:(w)=>x.entityService.getEntity(w),getVisibleEntity:(w,f)=>x.entityService.getEntity({...w,visibilityScope:f})});return A.status==="visible"?A.entity:void 0}function Dmx(x){let B=new Headers({"Content-Type":x.mediaType,"Content-Length":String(x.data.byteLength),"Content-Disposition":ZF({disposition:x.requestUrl.searchParams.has("download")?"attachment":"inline",filename:x.filename})});return new Response(x.data,{headers:B})}var S_="upload",Zmx=$mx;var M_9={namespace:"upload",refKind:S_,routePath:"/api/chat/uploads"};function hC(){return M_9}var Ymx=Qmx;var Wmx=Xmx;var v_9="file",N_9=16384;async function Hmx(x,B){if(!await B.resolveAuthSession(x))return new Response("Forbidden",{status:403});let A=Number(x.headers.get("content-length"));if(Number.isFinite(A)&&A>Wmx+N_9)return new Response("File upload too large",{status:400});let w;try{w=await x.formData()}catch{return new Response("Invalid multipart upload",{status:400})}let f=w.get(v_9);if(!(f instanceof File))return new Response("Missing upload file",{status:400});let D=Buffer.from(await f.arrayBuffer()),$=mQ({filename:f.name,mediaType:f.type,content:D});if(!$.ok)return new Response($.message,{status:400});let Z=B.getUploadStore(),Q=await Z.save({filename:$.filename,mediaType:$.mediaType,content:D});return Response.json(Z.toResponseBody(Q),{status:201})}async function Fmx(x,B){if(!await B.resolveAuthSession(x))return new Response("Forbidden",{status:403});let A=new URL(x.url).searchParams.get("id")?.trim();if(!A)return new Response("Missing upload id",{status:400});let w=await zmx(A,B.getUploadStore());if(w instanceof Response)return w;let{record:f,content:D}=w,$=bmx(f,D);if($ instanceof Response)return $;let Z=new URL(x.url).searchParams.has("download")?"attachment":"inline",Q=new Uint8Array(D).buffer;return new Response(Q,{headers:{"Content-Type":f.mediaType,"Content-Length":String(D.byteLength),"Content-Disposition":ZF({disposition:Z,filename:f.filename})}})}function Kmx(x){let B=xU(x.filename??Ymx),A=O_9(x.url);if(!A)return new Response(`Unsupported file upload URL: ${B}`,{status:400});let w=mQ({filename:B,mediaType:x.mediaType,content:A.buffer});if(!w.ok)return new Response(w.message,{status:400});return Vmx(w,A.buffer)}async function qmx(x,B){let A=await zmx(x,B);if(A instanceof Response)return A;let{record:w,content:f}=A,D=bmx(w,f);if(D instanceof Response)return D;return Vmx(D,f,{kind:S_,id:x})}async function zmx(x,B){try{return await B.read(x)}catch(A){if(A instanceof r30)return I_9(A);throw A}}function bmx(x,B){let A=mQ({filename:x.filename,mediaType:x.mediaType,content:B});if(!A.ok)return new Response(A.message,{status:400});return A}function Vmx(x,B,A){if(x.kind==="text")return{kind:"text",filename:x.filename,mediaType:x.mediaType,content:x.text,sizeBytes:x.sizeBytes,...A!==void 0?{source:A}:{}};return{kind:"file",filename:x.filename,mediaType:x.mediaType,data:new Uint8Array(B),sizeBytes:x.sizeBytes,...A!==void 0?{source:A}:{}}}function I_9(x){switch(x.code){case"invalid_ref":return new Response("Invalid upload ref",{status:400});case"invalid_metadata":return new Response("Invalid upload metadata",{status:500});case"not_found":return new Response("Upload not found",{status:404})}}function O_9(x){let B=/^data:[^,]*,(.*)$/s.exec(x);if(!B)return null;let w=x.slice(5,x.indexOf(",")).split(";").some((f)=>f.toLowerCase()==="base64");try{let f=w?Buffer.from(B[1]??"","base64"):Buffer.from(decodeURIComponent(B[1]??""),"utf8");return{buffer:f,byteLength:f.byteLength}}catch{return null}}var h_9=X.object({type:X.literal("text"),text:X.string()}),R_9=X.object({type:X.literal("file"),mediaType:X.string().optional(),filename:X.string().optional(),url:X.string()}),y_9=X.looseObject({state:X.literal("approval-responded"),toolCallId:X.string().optional(),toolName:X.string().optional(),input:X.record(X.string(),X.unknown()).optional(),title:X.string().optional(),approval:X.object({id:X.string(),approved:X.boolean()})}),m_9=X.object({id:X.string().optional(),role:X.string(),parts:X.array(X.unknown()).optional(),content:X.string().optional()}),Umx=X.object({id:X.string().optional(),messages:X.array(m_9).min(1),trigger:X.string().optional()}),C_9=X.object({kind:X.literal(S_),id:X.string().regex(Zmx)}),c_9=X.object({type:X.literal("data-upload"),data:X.object({ref:C_9})});async function Gmx(x,B){let A=g_9(x);if(!A)return{message:"",attachments:[]};let w=[],f=[];for(let $ of A.parts??[]){let Z=h_9.safeParse($);if(Z.success){if(Z.data.text.length>0)w.push(Z.data.text);continue}let Q=R_9.safeParse($);if(Q.success){let W=Kmx(Q.data);if(W instanceof Response)return W;f.push(W);continue}let Y=c_9.safeParse($);if(Y.success){let W=await qmx(Y.data.data.ref.id,B.uploadStore);if(W instanceof Response)return W;f.push(W);continue}if(T_9($)==="data-upload")return new Response("Invalid upload ref",{status:400})}return{message:w.length>0?w.join(`
6752
+ ${W.content}`});for(let F of H){if(D.scannedPairs>=A)break;if(F.entityType!==R8)continue;if(F.entityId===Y.id)continue;if(F.distance>x.semanticMergeDistance)continue;let K=await w.getTopic(F.entityId,B);if(!K||K.id===Y.id)continue;let q=tj9(Y.id,K.id);if($.has(q))continue;$.add(q),D.scannedPairs++;let{canonical:V,absorbed:b}=oj9(Y,K),G=MC.parseTopicBody(b.content),E=await f.synthesize({existingTopic:V,incomingTopic:{title:G.title,content:G.content,relevanceScore:1}});if(E.verdict==="distinct"){D.distinct++;continue}if(!await w.applySynthesizedMerge({existingId:V.id,synthesized:{title:E.title,content:E.content},visibility:B})){D.skipped++;continue}await w.deleteTopic(b.id),D.deletedIds.push(b.id),D.merged++,Z=!0;break}if(Z)break}}if(D.merged>0&&x.emitEvent!==!1)await x.context.messaging.send({type:KC,payload:D,broadcast:!0});return D}function rj9(x){return[...x].sort((B,A)=>{let w=B.created.localeCompare(A.created);if(w!==0)return w;return B.id.localeCompare(A.id)})}function oj9(x,B){let A=MC.parseTopicBody(x.content).content.length,w=MC.parseTopicBody(B.content).content.length;if(A!==w)return A>w?{canonical:x,absorbed:B}:{canonical:B,absorbed:x};let f=x.created.localeCompare(B.created);if(f!==0)return f<0?{canonical:x,absorbed:B}:{canonical:B,absorbed:x};return x.id.localeCompare(B.id)<=0?{canonical:x,absorbed:B}:{canonical:B,absorbed:x}}function tj9(x,B){return[x,B].sort().join("\x00")}var ej9=X.discriminatedUnion("mode",[X.object({mode:X.literal("derive"),reason:X.string().optional()}),X.object({mode:X.literal("rebuild"),reason:X.string().optional()}),X.object({mode:X.literal("source-batch"),minRelevanceScore:X.number().min(0).max(1).optional()}),X.object({mode:X.literal("reconcile"),reason:X.string().optional()})]);class i30{refs=new Map;add(x){this.refs.set(`${x.entityType}:${x.entityId}`,x)}drain(){let x=Array.from(this.refs.values());return this.refs.clear(),x}}function gyx(x){let{context:B,logger:A,config:w}=x,f=x.reconcileTopics??(async()=>u_({context:B,logger:A,semanticMergeDistance:w.semanticMergeDistance,targetVisibility:w.extractionVisibility,maxPairs:w.reconciliationMaxPairs}));return{process:async(D)=>{if(D.mode==="derive")return await x.extractAllTopics(),await f(),{success:!0};if(D.mode==="rebuild")return await x.rebuildAllTopics(),await f(),{success:!0};if(D.mode==="reconcile")return f();let $=await x_9({context:B,logger:A,config:w,sourceBatch:x.sourceBatch,isEntityPublished:x.isEntityPublished,minRelevanceScore:D.minRelevanceScore??w.minRelevanceScore});if($.created>0||$.merged>0)await f();return $},validateAndParse:(D)=>{let $=ej9.safeParse(D??{});return $.success?$.data:null}}}async function x_9(x){let B=x.sourceBatch.drain(),A=await Promise.all(B.map(async(W)=>({ref:W,entity:await x.context.entityService.getEntity({entityType:W.entityType,id:W.entityId})}))),w=0,f=0,D=0,$=0,Z=[];for(let{ref:W,entity:H}of A){if(!H){f++;continue}if(H.contentHash!==W.contentHash){w++;continue}if(!x.isEntityPublished(H)){D++;continue}if(!vC(H.visibility,x.config.extractionVisibility)){$++;continue}Z.push(H)}if(Z.length===0)return{success:!0,sources:B.length,created:0,merged:0,skipped:0,batches:0,stale:w,missing:f,unpublished:D,hidden:$};let Q=await A_9(x.context,x.config),Y=await oY(Z,x.context,x.logger,{minRelevanceScore:x.minRelevanceScore,createRelevanceThreshold:x.config.createRelevanceThreshold,reinforceRelevanceThreshold:x.config.reinforceRelevanceThreshold,sourceWeights:x.config.sourceWeights,mintableEntityTypes:x.config.mintableEntityTypes,sourceRolePolicies:x.config.sourceRolePolicies,sourceRoleOverrides:x.config.sourceRoleOverrides,sourceEntityCount:Q,maxEntitiesPerBatch:x.config.maxEntitiesPerBatch,topicSoftCeilingSourceRatio:x.config.topicSoftCeilingSourceRatio,autoMerge:x.config.autoMerge,semanticMergeDistance:x.config.semanticMergeDistance,targetVisibility:x.config.extractionVisibility});return{success:!0,sources:B.length,...Y,stale:w,missing:f,unpublished:D,hidden:$}}function Tyx(){return{priority:5,source:FC,deduplication:"coalesce",deduplicationKey:"topics-initial-derivation",metadata:{operationType:"data_processing",operationTarget:"topics-initial-derivation",pluginId:sY}}}async function pyx(x){let B=await Syx(x);if(B.length===0){x.logger.info("No entities to extract topics from");return}x.logger.info(`Batch topic extraction: ${B.length} entities`);let A=await oY(B,x.context,x.logger,{minRelevanceScore:x.config.minRelevanceScore,createRelevanceThreshold:x.config.createRelevanceThreshold,reinforceRelevanceThreshold:x.config.reinforceRelevanceThreshold,sourceWeights:x.config.sourceWeights,mintableEntityTypes:x.config.mintableEntityTypes,sourceRolePolicies:x.config.sourceRolePolicies,sourceRoleOverrides:x.config.sourceRoleOverrides,sourceEntityCount:B.length,maxEntitiesPerBatch:x.config.maxEntitiesPerBatch,topicSoftCeilingSourceRatio:x.config.topicSoftCeilingSourceRatio,autoMerge:x.config.autoMerge,semanticMergeDistance:x.config.semanticMergeDistance,targetVisibility:x.config.extractionVisibility});x.logger.info("Batch topic extraction complete",A)}async function uyx(x){let B=await Syx(x),A=await NC(B,x.context,x.logger,x.config);x.logger.info("Topic rebuild complete",A)}async function NC(x,B,A,w){let f=new u2(B.entityService,A),D=await f.listTopics({visibility:w.extractionVisibility});for(let Z of D)await f.deleteTopic(Z.id);if(x.length===0)return{deleted:D.length,created:0,merged:0,skipped:0,batches:0};let $=await oY(x,B,A,{minRelevanceScore:w.minRelevanceScore,createRelevanceThreshold:w.createRelevanceThreshold,reinforceRelevanceThreshold:w.reinforceRelevanceThreshold,sourceWeights:w.sourceWeights,mintableEntityTypes:w.mintableEntityTypes,sourceRolePolicies:w.sourceRolePolicies,sourceRoleOverrides:w.sourceRoleOverrides,sourceEntityCount:x.length,maxEntitiesPerBatch:w.maxEntitiesPerBatch,topicSoftCeilingSourceRatio:w.topicSoftCeilingSourceRatio,autoMerge:w.autoMerge,semanticMergeDistance:w.semanticMergeDistance,targetVisibility:w.extractionVisibility});return{deleted:D.length,...$}}async function Syx(x){let B=B_9(x),A=[];for(let w of B){let f=await x.context.entityService.listEntities({entityType:w,options:{filter:{visibilityScope:x.config.extractionVisibility}}});for(let D of f){if(!x.isEntityPublished(D))continue;A.push(D)}}return A}function B_9(x){return x.context.entityService.getEntityTypes().filter((A)=>x.shouldProcessEntityType(A))}async function A_9(x,B){let A=x.entityService.getEntityTypes().filter((f)=>{if(f==="topic")return!1;if(B.excludeEntityTypes.includes(f))return!1;if(!B.includeEntityTypes.includes("*")&&!B.includeEntityTypes.includes(f))return!1;return x.entityService.getEntityTypeConfig(f).projectionSource!==!1});return(await Promise.all(A.map((f)=>x.entityService.countEntities({entityType:f,options:{filter:{visibilityScope:B.extractionVisibility}}})))).reduce((f,D)=>f+D,0)}var tY=X.object({entityType:X.string(),content:X.string(),metadata:X.record(X.string(),X.unknown()).optional()}),D_9=tY.extend({minRelevanceScore:X.number().optional()}),$_9=X.object({contentA:tY,contentB:tY,minRelevanceScore:X.number().optional(),threshold:X.number().min(0).max(1).optional()}),Vz=X.object({id:X.string().optional(),title:X.string(),content:X.string()}),Z_9=X.object({existingTopics:X.array(Vz),incomingTopic:Vz,threshold:X.number().optional()}),Q_9=X.object({existingTopics:X.array(Vz).default([]),incomingTopic:Vz.extend({relevanceScore:X.number().min(0).max(1).optional()}),threshold:X.number().optional()}),X_9=X.object({entities:X.array(tY).min(1),minRelevanceScore:X.number().optional()}),Y_9=X.object({existingTopics:X.array(Vz).optional(),entities:X.array(tY)}),W_9=X.object({existingTopics:X.array(Vz).min(2),threshold:X.number().optional(),maxPairs:X.number().int().min(0).optional()}),H_9=tY.extend({id:X.string()}),F_9=X.object({entities:X.array(H_9).min(1)}),K_9=X.object({fixture:X.string(),minTopicCount:X.number().int().min(0).default(5),maxTopicCount:X.number().int().min(0).default(14),requiredTitleMatches:X.array(X.string()).default([]),forbiddenTitleMatches:X.array(X.string()).default([]),forbiddenTitlePairs:X.array(X.object({left:X.string(),right:X.string()})).default([])}),q_9=X.object({entities:X.array(tY)});function bz(x,B=""){return{id:`eval${B}-${Date.now()}`,entityType:x.entityType,content:x.content,contentHash:_8(x.content),visibility:"public",metadata:x.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}}function iyx(x){return{title:x.title,relevanceScore:x.relevanceScore}}function z_9(x){let B=x.metadata.title;return typeof B==="string"?B:x.id}function b_9(x,B){let A=[];if(x.length<B.minTopicCount)A.push(`too few topics: ${x.length}`);if(x.length>B.maxTopicCount)A.push(`too many topics: ${x.length}`);for(let w of B.requiredTitleMatches){let f=new RegExp(w,"i");if(!x.some((D)=>f.test(D)))A.push(`missing required title match: ${w}`)}for(let w of B.forbiddenTitleMatches){let f=new RegExp(w,"i"),D=x.find(($)=>f.test($));if(D)A.push(`forbidden title matched ${w}: ${D}`)}for(let w of B.forbiddenTitlePairs){let f=new RegExp(w.left,"i"),D=new RegExp(w.right,"i"),$=x.some((Q)=>f.test(Q)),Z=x.some((Q)=>D.test(Q));if($&&Z)A.push(`forbidden duplicate pair present: ${w.left} / ${w.right}`)}return A}function V_9(x,B){return{...x,sources:[{id:B.id,type:B.entityType,title:z_9(B)}]}}async function BD(x){let B=await x.entityService.listEntities({entityType:R8});await Promise.all(B.map((A)=>x.entityService.deleteEntity({entityType:R8,id:A.id})))}async function IC(x){for(;;){if((await x.jobs.getActiveJobs([O_.embedding])).length===0)return;await new Promise((A)=>setTimeout(A,100))}}function lyx(x){let{context:B,logger:A,config:w}=x,f=new S30(B,A),D=new D7,$=async(Z,Q,Y="")=>{let W=bz(Z,Y);return f.extractFromEntity(W,Q)};B.eval.registerHandler("extractFromEntity",async(Z)=>{await BD(B);let Q=D_9.parse(Z),Y=Q.minRelevanceScore??w.minRelevanceScore,W=bz(Q);return(await f.extractFromEntity(W,Y)).map((F)=>V_9(F,W))}),B.eval.registerHandler("checkMergeSimilarity",async(Z)=>{await BD(B);let Q=$_9.parse(Z),Y=Q.minRelevanceScore??w.minRelevanceScore,W=Q.threshold??w.semanticMergeDistance,[H,F]=await Promise.all([$(Q.contentA,Y,"-a"),$(Q.contentB,Y,"-b")]),K=new u2(B.entityService,A),q=[];for(let G of H){let E=await K.createTopic(G);if(E)q.push(E)}await IC(B);let V=(await Promise.all(F.map(async(G)=>{let E=await K.findMergeCandidate({incoming:G,threshold:W,additionalCandidates:q});if(!E)return null;return{incomingTitle:G.title,candidateTitle:E.title,candidateScore:E.score}}))).filter((G)=>G!==null),b=V.map((G)=>G.candidateTitle);return{topicsA:H.map(iyx),topicsB:F.map(iyx),matchingTitles:b,mergeCandidates:V,wouldMerge:V.length>0}}),B.eval.registerHandler("detectMergeCandidate",async(Z)=>{await BD(B);let Q=Z_9.parse(Z),Y=Q.threshold??w.semanticMergeDistance,W=new u2(B.entityService,A),H=[];for(let K of Q.existingTopics){let q=await W.createTopic(K);if(q)H.push(q)}await IC(B);let F=await W.findMergeCandidate({incoming:{title:Q.incomingTopic.title,content:Q.incomingTopic.content},threshold:Y,additionalCandidates:H});return{found:F!==null,candidateTitle:F?.title,candidateScore:F?.score}}),B.eval.registerHandler("processTopicWithAutoMerge",async(Z)=>{await BD(B);let Q=Q_9.parse(Z),Y=new u2(B.entityService,A);for(let K of Q.existingTopics)await Y.createTopic({title:K.title,content:K.content});await IC(B);let W=bz({entityType:"post",content:Q.incomingTopic.content,metadata:{title:Q.incomingTopic.title}},"-source"),H=await oY([W],B,A,{minRelevanceScore:0,autoMerge:!0,semanticMergeDistance:Q.threshold??w.semanticMergeDistance}),F=await B.entityService.listEntities({entityType:R8});return{...H,topicCount:F.length,topics:F.map(g_)}}),B.eval.registerHandler("rebuildTopics",async(Z)=>{await BD(B);let Q=Y_9.parse(Z),Y=new u2(B.entityService,A);for(let K of Q.existingTopics??[])await Y.createTopic(K);let W=Q.entities.map((K,q)=>bz(K,`-rebuild-${q}`)),H=await NC(W,B,A,w),F=await B.entityService.listEntities({entityType:R8});return{...H,topicCount:F.length,topics:F.map(g_)}}),B.eval.registerHandler("reconcileExistingTopics",async(Z)=>{await BD(B);let Q=W_9.parse(Z);for(let H of Q.existingTopics){let F=D.createTopicBody({title:H.title,content:H.content});await B.entityService.createEntity({entity:{id:H.id??H.title,entityType:R8,content:F,visibility:"public",metadata:{}}})}await IC(B);let Y=await u_({context:B,logger:A,semanticMergeDistance:Q.threshold??w.semanticMergeDistance,targetVisibility:"public",maxPairs:Q.maxPairs??w.reconciliationMaxPairs}),W=await B.entityService.listEntities({entityType:R8});return{...Y,topicCount:W.length,topics:W.map(g_)}}),B.eval.registerHandler("extractSequentially",async(Z)=>{await BD(B);let Q=X_9.parse(Z),Y=Q.minRelevanceScore??w.minRelevanceScore,W=new u2(B.entityService,A),H=[];for(let[K,q]of Q.entities.entries()){let V=bz(q,`-sequential-${K}`),b=await f.extractFromEntity(V,Y);for(let G of b)await W.createTopic({title:G.title,content:G.content});H.push({extractedTitles:b.map((G)=>G.title),extractedCount:b.length})}let F=await B.entityService.listEntities({entityType:R8});return{totalTopics:F.length,perEntity:H,topics:F.map(qz)}}),B.eval.registerHandler("rebuildCorpusFixture",async(Z)=>{await BD(B);let Q=K_9.parse(Z),W=F_9.parse(JSON.parse(await w_9(f_9(process.cwd(),Q.fixture),"utf8"))).entities.map((b)=>({id:b.id,entityType:b.entityType,content:b.content,contentHash:_8(b.content),visibility:"public",metadata:b.metadata??{},created:"2026-01-01T00:00:00Z",updated:"2026-01-01T00:00:00Z"})),H=await NC(W,B,A,w),F=await u_({context:B,logger:A,semanticMergeDistance:w.semanticMergeDistance,targetVisibility:w.extractionVisibility,maxPairs:w.reconciliationMaxPairs}),K=(await B.entityService.listEntities({entityType:R8})).map(g_),q=K.map((b)=>b.title),V=b_9(q,Q);return{sourceCount:W.length,topicCount:K.length,topicTitles:q,issueCount:V.length,issues:V,rebuild:H,reconciliation:F,topics:K}}),B.eval.registerHandler("batchExtract",async(Z)=>{await BD(B);let Y=q_9.parse(Z).entities.map((F,K)=>bz(F,`-batch-${K}`)),W=await oY(Y,B,A,{minRelevanceScore:w.minRelevanceScore}),H=await B.entityService.listEntities({entityType:R8});return{...W,topicCount:H.length,topics:H.map(qz)}})}var U_9=new D7;async function nyx({entity:x,config:B}){let A=Kz.parse(x),w=U_9.parseTopicBody(A.content);return{$type:"ai.rizom.brain.topic",title:w.title,body:w.content,format:"text/markdown",...B.brainDid&&{brainDid:B.brainDid},...B.anchorDid&&{anchorDid:B.anchorDid},sourceEntityType:"topic",sourceEntityId:A.id,createdAt:A.created,...A.updated&&{updatedAt:A.updated}}}function l30(){return{entityType:"topic",collection:"ai.rizom.brain.topic",lexicon:h4["ai.rizom.brain.topic"],validate:!1,buildRecord:nyx}}var dyx={name:"@brains/topics",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Extract and manage topics from conversations",dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},main:"./src/index.ts",private:!0,scripts:{eval:"cd evals && bun run brain-eval",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module",types:"./src/index.ts"};var E_9=new D7,j_9=X.looseObject({status:X.unknown().optional()});class ayx extends g8{entityType=R8;schema=Kz;adapter=E_9;unregisterAtprotoProjection;sourceBatch=new i30;constructor(x={}){super(sY,dyx,x,qyx)}getEntityTypeConfig(){return{weight:0.5,projectionSource:!1,projectionSourceRole:"excluded"}}getTemplates(){return{extraction:Gyx,"merge-synthesis":Eyx,"topic-list":jyx,"topic-detail":_yx,"knowledge-map":Iyx()}}getDataSources(){return[new C30(this.logger.child("TopicsDataSource")),new T30]}getDerivedEntityProjections(x){if(!this.config.enableAutoExtraction)return[];return[{id:R30,targetType:R8,job:{type:byx,handler:gyx({context:x,logger:this.logger,config:this.config,extractAllTopics:()=>this.extractAllTopics(x),rebuildAllTopics:()=>this.rebuildAllTopics(x),sourceBatch:this.sourceBatch,isEntityPublished:(B)=>this.isEntityPublished(B)})},initialSync:{shouldEnqueue:async()=>!await xF(x,R8,{visibility:this.config.extractionVisibility}),jobData:{mode:"derive",reason:"initial-sync"},jobOptions:Tyx()},sourceChange:{sourceTypes:this.config.includeEntityTypes,requireInitialSync:!0,jobData:(B)=>{let A=B.entity;if(!A)return null;if(!this.shouldProcessEntityType(A.entityType,x.entityService))return null;if(!this.isEntityPublished(A))return null;if(!vC(A.visibility,this.config.extractionVisibility))return null;return this.sourceBatch.add({entityId:A.id,entityType:A.entityType,contentHash:A.contentHash}),{mode:"source-batch"}},jobOptions:()=>({priority:5,source:FC,delayMs:this.config.sourceChangeBatchDelayMs,deduplication:"skip",deduplicationKey:Vyx,metadata:{operationType:"data_processing",operationTarget:"topic-source-batch",pluginId:sY}})}}]}async onRegister(x){x.insights.register("topic-distribution",Oyx()),hyx({context:x}),Ryx({context:x}),lyx({context:x,logger:this.logger,config:this.config}),this.unregisterAtprotoProjection=R4.getInstance().register(l30())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}hasRunInitialDerivation(){return this.getDerivedEntityProjectionController(R30)?.hasQueuedInitialSync()??!1}shouldProcessEntityType(x,B){if(x===R8)return!1;if(this.config.excludeEntityTypes.includes(x))return!1;if(!this.config.includeEntityTypes.includes("*")&&!this.config.includeEntityTypes.includes(x))return!1;return B.getEntityTypeConfig(x).projectionSource!==!1}isEntityPublished(x){let B=j_9.safeParse(x.metadata),A=B.success?B.data.status:void 0;if(A===void 0||A===null)return!0;if(typeof A!=="string")return!1;return this.config.extractableStatuses.includes(A)}async extractAllTopics(x){await pyx({context:x,logger:this.logger,config:this.config,shouldProcessEntityType:(B)=>this.shouldProcessEntityType(B,x.entityService),isEntityPublished:(B)=>this.isEntityPublished(B)})}async rebuildAllTopics(x){await uyx({context:x,logger:this.logger,config:this.config,shouldProcessEntityType:(B)=>this.shouldProcessEntityType(B,x.entityService),isEntityPublished:(B)=>this.isEntityPublished(B)})}}function syx(x={}){return new ayx(x)}var oyx=X.strictObject({source:n30,item:ryx}),tyx=X.strictObject({source:n30,error:X.literal("Source unavailable")}),d30=X.strictObject({entries:X.array(oyx).max(1e4),errors:X.array(tyx).max(1000)});class OC{id="unified-inbox:inbox";name="Unified Inbox DataSource";description="Aggregates live source-owned operator attention";registry;constructor(x){this.registry=x}async getInboxData(){let x=this.registry.listSources(),B=await Promise.allSettled(x.map(async(f)=>({source:f,items:await f.list()}))),A=[],w=[];for(let f=0;f<B.length;f++){let D=B[f],$=x[f];if(!D||!$)continue;let Z=__9($);if(D.status==="rejected"){w.push({source:Z,error:"Source unavailable"});continue}for(let Q of D.value.items)A.push({source:Z,item:Q})}return A.sort(P_9),w.sort((f,D)=>f.source.sourceId.localeCompare(D.source.sourceId)),d30.parse({entries:A,errors:w})}async fetch(x,B,A){return B.parse(await this.getInboxData())}}function __9(x){return{sourceId:x.sourceId,displayName:x.displayName}}function P_9(x,B){return eyx(x.item.urgency)-eyx(B.item.urgency)||B.item.receivedAt.localeCompare(x.item.receivedAt)||x.source.sourceId.localeCompare(B.source.sourceId)||x.item.id.localeCompare(B.item.id)}function eyx(x){return x==="high"?0:1}var xmx={name:"@brains/unified-inbox",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Live aggregation for source-owned operator attention",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var L_9=X.strictObject({});class a30 extends D8{constructor(){super("unified-inbox",xmx,{},L_9)}async onRegister(x){x.entities.registerDataSource(new OC(x.inbox))}}function s30(){return new a30}var Bmx={name:"@brains/web-chat",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Web chat interface for Brains",dependencies:{"@ai-sdk/react":"^3.0.208","@brains/auth-service":"workspace:*","@brains/console-theme":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@streamdown/cjk":"^1.0.3","@streamdown/code":"^1.1.1","@streamdown/math":"^1.0.2","@streamdown/mermaid":"^1.0.2","@tanstack/react-query":"^5.0.0",ai:"^6.0.206","class-variance-authority":"^0.7.0",cmdk:"^1.1.1","lucide-react":"^1.20.0",nanoid:"^5.0.4","radix-ui":"^1.6.0",react:"^19.2.7","react-dom":"^19.2.7",shiki:"^4.2.0",streamdown:"^2.5.0","tailwind-merge":"^3.6.0","use-stick-to-bottom":"^1.1.6"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/react":"^19.2.17","@types/react-dom":"^19.0.3","happy-dom":"^20.10.6",typescript:"^7.0.2",vite:"^8.0.16"},exports:{".":"./src/index.ts"},files:["src","dist","package.json"],private:!0,scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json"},type:"module"};async function Amx(x,B){let A=await B.resolvePermissionLevel(x);if(A==="public")return B.createAuthLoginRequiredResponse(x);let w=new URL(x.url),f=w.searchParams.get("id")?.trim();if(!f)return new Response("Missing document id",{status:400});let D=await fmx({entityType:"document",id:f,permissionLevel:A,entityService:B.entityService});if(!D)return new Response("Document not found",{status:404});if(typeof D.content!=="string")return new Response("Document content is not a PDF",{status:415});let $=oV("document",D.content);if(!$)return new Response("Document content is not a PDF",{status:415});let Z=tV(D.metadata,f,"document",$.mimeType);return Dmx({requestUrl:w,data:$.data,mediaType:$.mimeType,filename:Z})}async function wmx(x,B){let A=await B.resolvePermissionLevel(x);if(A==="public")return B.createAuthLoginRequiredResponse(x);let w=new URL(x.url),f=w.searchParams.get("id")?.trim();if(!f)return new Response("Missing image id",{status:400});let D=await fmx({entityType:"image",id:f,permissionLevel:A,entityService:B.entityService});if(!D)return new Response("Image not found",{status:404});if(typeof D.content!=="string")return new Response("Image content is not an image",{status:415});let $=oV("image",D.content);if(!$)return new Response("Image content is not an image",{status:415});let Z=tV(D.metadata,f,"image",$.mimeType);return Dmx({requestUrl:w,data:$.data,mediaType:$.mimeType,filename:Z})}async function fmx(x){let B={entityType:x.entityType,id:x.id},A=await Ik({entityRef:B,userLevel:x.permissionLevel,getEntity:(w)=>x.entityService.getEntity(w),getVisibleEntity:(w,f)=>x.entityService.getEntity({...w,visibilityScope:f})});return A.status==="visible"?A.entity:void 0}function Dmx(x){let B=new Headers({"Content-Type":x.mediaType,"Content-Length":String(x.data.byteLength),"Content-Disposition":ZF({disposition:x.requestUrl.searchParams.has("download")?"attachment":"inline",filename:x.filename})});return new Response(x.data,{headers:B})}var S_="upload",Zmx=$mx;var M_9={namespace:"upload",refKind:S_,routePath:"/api/chat/uploads"};function hC(){return M_9}var Ymx=Qmx;var Wmx=Xmx;var v_9="file",N_9=16384;async function Hmx(x,B){if(!await B.resolveAuthSession(x))return new Response("Forbidden",{status:403});let A=Number(x.headers.get("content-length"));if(Number.isFinite(A)&&A>Wmx+N_9)return new Response("File upload too large",{status:400});let w;try{w=await x.formData()}catch{return new Response("Invalid multipart upload",{status:400})}let f=w.get(v_9);if(!(f instanceof File))return new Response("Missing upload file",{status:400});let D=Buffer.from(await f.arrayBuffer()),$=mQ({filename:f.name,mediaType:f.type,content:D});if(!$.ok)return new Response($.message,{status:400});let Z=B.getUploadStore(),Q=await Z.save({filename:$.filename,mediaType:$.mediaType,content:D});return Response.json(Z.toResponseBody(Q),{status:201})}async function Fmx(x,B){if(!await B.resolveAuthSession(x))return new Response("Forbidden",{status:403});let A=new URL(x.url).searchParams.get("id")?.trim();if(!A)return new Response("Missing upload id",{status:400});let w=await zmx(A,B.getUploadStore());if(w instanceof Response)return w;let{record:f,content:D}=w,$=bmx(f,D);if($ instanceof Response)return $;let Z=new URL(x.url).searchParams.has("download")?"attachment":"inline",Q=new Uint8Array(D).buffer;return new Response(Q,{headers:{"Content-Type":f.mediaType,"Content-Length":String(D.byteLength),"Content-Disposition":ZF({disposition:Z,filename:f.filename})}})}function Kmx(x){let B=xU(x.filename??Ymx),A=O_9(x.url);if(!A)return new Response(`Unsupported file upload URL: ${B}`,{status:400});let w=mQ({filename:B,mediaType:x.mediaType,content:A.buffer});if(!w.ok)return new Response(w.message,{status:400});return Vmx(w,A.buffer)}async function qmx(x,B){let A=await zmx(x,B);if(A instanceof Response)return A;let{record:w,content:f}=A,D=bmx(w,f);if(D instanceof Response)return D;return Vmx(D,f,{kind:S_,id:x})}async function zmx(x,B){try{return await B.read(x)}catch(A){if(A instanceof r30)return I_9(A);throw A}}function bmx(x,B){let A=mQ({filename:x.filename,mediaType:x.mediaType,content:B});if(!A.ok)return new Response(A.message,{status:400});return A}function Vmx(x,B,A){if(x.kind==="text")return{kind:"text",filename:x.filename,mediaType:x.mediaType,content:x.text,sizeBytes:x.sizeBytes,...A!==void 0?{source:A}:{}};return{kind:"file",filename:x.filename,mediaType:x.mediaType,data:new Uint8Array(B),sizeBytes:x.sizeBytes,...A!==void 0?{source:A}:{}}}function I_9(x){switch(x.code){case"invalid_ref":return new Response("Invalid upload ref",{status:400});case"invalid_metadata":return new Response("Invalid upload metadata",{status:500});case"not_found":return new Response("Upload not found",{status:404})}}function O_9(x){let B=/^data:[^,]*,(.*)$/s.exec(x);if(!B)return null;let w=x.slice(5,x.indexOf(",")).split(";").some((f)=>f.toLowerCase()==="base64");try{let f=w?Buffer.from(B[1]??"","base64"):Buffer.from(decodeURIComponent(B[1]??""),"utf8");return{buffer:f,byteLength:f.byteLength}}catch{return null}}var h_9=X.object({type:X.literal("text"),text:X.string()}),R_9=X.object({type:X.literal("file"),mediaType:X.string().optional(),filename:X.string().optional(),url:X.string()}),y_9=X.looseObject({state:X.literal("approval-responded"),toolCallId:X.string().optional(),toolName:X.string().optional(),input:X.record(X.string(),X.unknown()).optional(),title:X.string().optional(),approval:X.object({id:X.string(),approved:X.boolean()})}),m_9=X.object({id:X.string().optional(),role:X.string(),parts:X.array(X.unknown()).optional(),content:X.string().optional()}),Umx=X.object({id:X.string().optional(),messages:X.array(m_9).min(1),trigger:X.string().optional()}),C_9=X.object({kind:X.literal(S_),id:X.string().regex(Zmx)}),c_9=X.object({type:X.literal("data-upload"),data:X.object({ref:C_9})});async function Gmx(x,B){let A=g_9(x);if(!A)return{message:"",attachments:[]};let w=[],f=[];for(let $ of A.parts??[]){let Z=h_9.safeParse($);if(Z.success){if(Z.data.text.length>0)w.push(Z.data.text);continue}let Q=R_9.safeParse($);if(Q.success){let W=Kmx(Q.data);if(W instanceof Response)return W;f.push(W);continue}let Y=c_9.safeParse($);if(Y.success){let W=await qmx(Y.data.data.ref.id,B.uploadStore);if(W instanceof Response)return W;f.push(W);continue}if(T_9($)==="data-upload")return new Response("Invalid upload ref",{status:400})}return{message:w.length>0?w.join(`
6753
6753
 
6754
6754
  `):A.content??"",attachments:f,...A.id?{messageId:A.id}:{}}}function Emx(x){let B=x.messages.at(-1);if(!B||B.role==="user")return[];return(B.parts??[]).map((A)=>y_9.safeParse(A)).filter((A)=>A.success).map((A)=>({...A.data.approval,...A.data.toolCallId?{toolCallId:A.data.toolCallId}:{},...A.data.toolName?{toolName:A.data.toolName}:{},...A.data.input?{input:A.data.input}:{},...A.data.title?{title:A.data.title}:{}}))}function g_9(x){for(let B=x.messages.length-1;B>=0;B-=1){let A=x.messages[B];if(A?.role==="user")return A}return}function T_9(x){if(typeof x!=="object"||x===null||!("type"in x))return;let B=x.type;return typeof B==="string"?B:void 0}var p_9=/\n{0,2}\[Entities affected this turn: [\s\S]*? Reference these IDs directly in follow-ups instead of searching for them\.\]\s*$/;function i_(x){return x.replace(p_9,"").trimEnd()}function _mx(x,B,A){x.write({type:"text-start",id:B}),x.write({type:"text-delta",id:B,delta:A}),x.write({type:"text-end",id:B})}function o30(x,B){let A=B.directives.flatMap((w)=>{switch(w.kind){case"artifact":case"supplemental":return[w.card];case"approvals":return w.cards;default:return[]}});for(let w of A){let f=jmx(w);if(f.kind==="attachment"){x.write({type:"data-attachment",id:f.id,data:f});continue}if(f.kind==="sources"){x.write({type:"data-sources",id:f.id,data:f});continue}if(f.kind==="actions"){x.write({type:"data-actions",id:f.id,data:f});continue}let D=f.toolCallId??f.id,$=f.input??{};switch(x.write({type:"tool-input-available",toolCallId:D,toolName:f.toolName,input:$,dynamic:!0,title:f.preview?`${f.summary}
6755
6755
 
@@ -9351,7 +9351,7 @@ ${ymx}</style></head><body>${aw(x)}<main id="root" data-web-chat-root>Brain Chat
9351
9351
  <p>Once built, this page will be replaced with your actual website.</p>
9352
9352
  </div>
9353
9353
  </body>
9354
- </html>`;var HCx={name:"@brains/webserver",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@hono/bun-compress":"^0.1.1",hono:"^4.12.25"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/messaging-service":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class TC extends cH{serverManager;siteUrl;previewUrl;constructor(x={}){super("webserver",HCx,x,QA0)}async onRegister(x){if(this.siteUrl=x.siteUrl,this.previewUrl=x.previewUrl,this.siteUrl)x.endpoints.register({label:"Site",url:this.siteUrl,priority:10}),x.interactions.register({id:"site",label:"Public site",description:"Visit the published public site for this brain.",href:this.siteUrl,kind:"human",priority:10});if(this.config.enablePreview&&this.previewUrl)x.endpoints.register({label:"Preview",url:this.previewUrl,priority:20,visibility:"admin"}),x.interactions.register({id:"preview",label:"Preview site",description:"Open the private preview build.",href:this.previewUrl,kind:"admin",priority:20,visibility:"admin"});this.serverManager=new gC({logger:x.logger,productionDistDir:this.config.productionDistDir,sharedImagesDir:this.config.sharedImagesDir,productionPort:this.config.productionPort,...this.config.enablePreview&&this.config.previewDistDir&&{previewDistDir:this.config.previewDistDir},...this.config.enablePreview&&this.config.previewPort&&{previewPort:this.config.previewPort},getHealthData:()=>x.appInfo(),getWebRoutes:()=>x.webRoutes.getRoutes(),getApiRoutes:()=>x.apiRoutes.getRoutes(),messageBus:x.apiRoutes.getMessageBus()})}getServerManager(){if(!this.serverManager)throw Error("ServerManager not initialized \u2014 onRegister not called");return this.serverManager}requiresDaemonStartup(){return!0}createDaemon(){return{start:async()=>{await this.ensureDistDirectories(),await this.getServerManager().start()},stop:async()=>{await this.serverManager?.stop()},healthCheck:async()=>{let x=this.serverManager?.getStatus(),B=x?.running??!1,A=this.siteUrl??x?.productionUrl??`http://localhost:${this.config.productionPort}`,w=this.previewUrl??x?.previewUrl??`http://localhost:${this.config.previewPort}`,f=[];if(B){if(f.push(`Production: ${A}`),x?.previewUrl)f.push(`Preview: ${w}`)}return{status:B?"healthy":"error",message:B?f.join(", "):"Webserver not running",lastCheck:new Date,details:{preview:!!x?.previewUrl,production:B,previewUrl:x?.previewUrl?w:void 0,productionUrl:B?A:void 0}}}}}async handleProgressEvent(x,B){}async ensureDistDirectories(){let{mkdir:x,writeFile:B}=await import("fs/promises");if(this.config.enablePreview&&this.config.previewDistDir&&!FCx(this.config.previewDistDir))await x(this.config.previewDistDir,{recursive:!0}),await B(KCx(this.config.previewDistDir,"index.html"),XA0),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!FCx(this.config.productionDistDir))await x(this.config.productionDistDir,{recursive:!0}),await B(KCx(this.config.productionDistDir,"index.html"),XA0),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}var YA0=X.enum(["new","planned","in-progress","done","declined"]),WA0=X.enum(["low","medium","high","critical"]),n_=X.object({title:X.string(),status:YA0,priority:WA0.default("medium"),requested:X.number().int().default(1),declinedReason:X.string().optional()}),qCx=X.object({title:X.string(),status:YA0,priority:WA0,requested:X.number().int(),slug:X.string()}),d_=j8.extend({entityType:X.literal("wish"),metadata:qCx});var HA0=X.object({}).catchall(X.unknown()).transform(()=>({}));class a_ extends ox{constructor(){super({entityType:"wish",purpose:"A demand record the assistant proactively creates when a user requests a capability or outcome no installed tool can fulfill, unless the user declines.",schema:d_,frontmatterSchema:n_})}createWishContent(x,B){return this.buildMarkdown(B,x)}parseWishContent(x){let B=this.parseFrontMatter(x,n_);return{frontmatter:n_.parse(B),description:this.extractBody(x).trim()}}fromMarkdown(x){let{frontmatter:B}=this.parseWishContent(x),A=Gx(B.title);return{content:x,entityType:"wish",metadata:{title:B.title,status:B.status,priority:B.priority,requested:B.requested,slug:A}}}}var zCx=new a_;async function bCx(x,B){let A=`${B.title}: ${B.description}`,f=(await x.search({query:A,options:{types:["wish"],limit:1}}))[0];if(f&&f.score>=x.similarityThreshold)return f.entity;let D=Gx(B.title);return x.getEntity({entityType:"wish",id:D})}class pC{logger;context;adapter=new a_;constructor(x,B){this.logger=x,this.context=B}async process(x,B,A){let w=x.title??x.prompt??"Untitled wish",f=x.content??x.prompt??"",D=await bCx({search:(Y)=>this.context.entityService.search(Y),getEntity:(Y)=>this.context.entityService.getEntity(Y),similarityThreshold:0.85},{title:w,description:f});if(D){let{frontmatter:Y,description:W}=this.adapter.parseWishContent(D.content),H=Y.requested+1,F=this.adapter.createWishContent({...Y,requested:H},W);return await this.context.entityService.updateEntity({entity:{...D,content:F,metadata:{...D.metadata,requested:H}}}),this.logger.info("Incremented wish request count",{id:D.id,requested:H}),{success:!0,entityId:D.id,existed:!0,requested:H}}let $=Gx(w),Z=x.options?.priority??"medium",Q=this.adapter.createWishContent({title:w,status:"new",priority:Z,requested:1},f);return await this.context.entityService.createEntity({entity:{id:$,entityType:"wish",content:Q,metadata:{title:w,status:"new",priority:Z,requested:1,slug:$}}}),this.logger.info("Created new wish",{id:$,title:w}),{success:!0,entityId:$,existed:!1,requested:1}}}var VCx={critical:0,high:1,medium:2,low:3};function UCx(x){x.sort((B,A)=>{let w=A.metadata.requested-B.metadata.requested;if(w!==0)return w;return VCx[B.metadata.priority]-VCx[A.metadata.priority]})}var GCx={name:"@brains/wishlist",license:"AGPL-3.0-only",version:"0.2.0-alpha.254",description:"Wishlist plugin for tracking unfulfilled user requests",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var cP9=X.object({items:X.array(X.object({name:X.string(),count:X.number()}))}),gP9="wish";class ECx extends g8{entityType=gP9;schema=d_;adapter=zCx;constructor(x={}){super("wishlist",GCx,x,HA0)}getEntityTypeConfig(){return{projectionSource:!1,projectionSourceRole:"excluded"}}async interceptCreate(x,B,A){let w=await new pC(this.logger,A).process({...x.title?{title:x.title}:{},...x.prompt?{prompt:x.prompt}:{},...x.content?{content:x.content}:{}},`wish-create-${Date.now()}`,{});if(!w.success)return{kind:"handled",result:{success:!1,error:w.error??"Failed to create wish"}};return{kind:"handled",result:{success:!0,data:{...w.entityId?{entityId:w.entityId}:{},status:w.existed?"updated":"created"}}}}async onRegister(x){x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.dashboard.registerWidget({id:"top-wishes",title:"Top Wishes",group:"knowledge",section:"secondary",priority:30,rendererName:"ListWidget",digestProvider:(A)=>{let{items:w}=cP9.parse(A),f=w[0];return{digest:f?[{label:"Top wish",value:`${f.name} \xB7 \xD7${f.count}`}]:[{label:"Wishes",value:"none yet"}]}},dataProvider:async()=>{let A=await x.entityService.listEntities({entityType:"wish",options:{limit:10}});return UCx(A),{items:A.map((w)=>({id:w.id,name:w.metadata.title,count:w.metadata.requested,priority:w.metadata.priority,status:w.metadata.status}))}}}),{success:!0}});let B=new pC(this.logger,x);x.jobs.registerHandler("wish:create",{process:B.process.bind(B),validateAndParse:(A)=>A})}async getInstructions(){return'Mandatory unmet-request routing: Wish entities record requested capabilities or desired end states whose literal completion is outside the available toolset. When the user asks for an unavailable product, capability, or real-world outcome no installed tool can perform, explain the limitation and call system_create with entityType "wish" unless the user declines. Availability is determined by the callable tool surface: an installed interface or transport that exposes no tool for the requested action cannot fulfill it. If you recognize that no callable tool can perform the action, do not end the turn after explaining the limitation; in that same turn you MUST call system_create with entityType "wish". The unmet request itself is concrete source material; do not merely decline, offer alternatives, or wait for a separate save verb. Do not invent or look for a dedicated wishlist tool; wishlist entries use the generic entity tools. They track demand, priority, and status for future capability planning; they are not a substitute for first-class entities that already support the requested action. To show the whole wishlist, call system_list once with entityType wish and omit status; only include status when the user asks for a specific wish status.'}}function TP9(x={}){return new ECx(x)}var jCx=TP9;var uC="core",NCx="site",ICx="publishing",OCx="team",hCx=s_({id:uC,members:["prompt","profile","style-guide","image","document","note","link","wishlist","topics","decks","directory-sync","atproto-registry","agents","assessment","auth-service","account","notifications","playbook","playbooks","onboarding","email","cms","dashboard","admin","mcp","webserver","web-chat","chat","a2a"],config:[{member:"dashboard",value:{routePath:"/"}}],permissions:[{member:"admin",config:{rules:[{pattern:"cli:*",level:"admin"}]}},{member:"mcp",config:{rules:[{pattern:"mcp:stdio",level:"admin"},{pattern:"mcp:http",level:"public"}]}},{member:"chat",config:{rules:[{pattern:"discord:*",level:"public"}]}},{member:"web-chat",config:{rules:[{pattern:"web-chat:*",level:"admin"}]}}],evalDisable:["dashboard","email","mcp","webserver","web-chat","chat"]}),RCx=s_({id:NCx,members:["dashboard","site-info","site-content","site-builder","analytics"],config:[{member:"dashboard",value:{routePath:"/dashboard"},overrides:uC}],evalDisable:["dashboard","analytics"]}),yCx=s_({id:ICx,members:["blog","series","portfolio","content-pipeline","social-media","newsletter","stock-photo","atproto"],config:[{member:"content-pipeline",value:{generationSchedules:{newsletter:"0 9 * * 1","social-post":"0 10 * * *"},generationConditions:{newsletter:{skipIfDraftExists:!0,minSourceEntities:1,sourceEntityType:"post"},"social-post":{skipIfDraftExists:!0,maxUnpublishedDrafts:5}}}},{member:"social-media",value:{autoGenerateOnBlogPublish:!0}},{member:"newsletter",value:{doubleOptIn:!0}}],agentInstructions:["Use the installed publishing capabilities for professional website content, essays, projects, decks, newsletters, and social distribution workflows. Treat publishing requests as production and distribution work rather than generic shared-memory capture.",`When answering questions like "what have I written about X" or "which posts relate to this deck/source", search first and use semantic search results as candidates, not proof. Summarize only clearly relevant entities whose title or content directly matches the asked topic or has substantial overlap with the source's main themes; omit weak/tangential candidates rather than presenting them as definite matches. A match based on only an isolated shared term or pattern is not enough; when one candidate is clearly stronger than the rest, list only the strongest clear match and say the others were tangential rather than naming them as matches.`,'Draft blog posts are only post entities with status draft. If the user asks whether draft blog posts exist, call only system_list for entityType post with status draft; do not also list social-post, newsletter, deck, or other draft entity types. After telling the user there are no draft blog posts, treat follow-ups like "make one draft" or "make one a draft" as requests to change an existing published post back to draft: ask which existing published post they want changed; do not offer to create a brand-new post and do not call system_generate to create a fresh draft from that ambiguous follow-up.'],evalDisable:["atproto"]}),eY={create:"trusted",update:"trusted",delete:"admin",extract:"admin",publish:"admin"},mCx=s_({id:OCx,members:["image","note","link","topics","decks","mcp","chat","conversation-memory","docs"],config:[{member:"topics",value:{extractableStatuses:["published","draft"]}},{member:"conversation-memory",value:{memoryVisibility:"shared"}}],permissions:[{member:"image",config:{entityActions:{image:eY}}},{member:"note",config:{entityActions:{note:eY}}},{member:"link",config:{entityActions:{link:eY}}},{member:"decks",config:{entityActions:{deck:eY}}},{member:"docs",config:{entityActions:{doc:eY}}},{member:"conversation-memory",config:{entityActions:{decision:eY,"action-item":eY}}},{member:"mcp",config:{rules:[{pattern:"mcp:http",level:"admin"}]},overrides:uC}],agentInstructions:["This is a collaborative team-memory and synthesis posture. Optimize for capturing shared context, finding what the team already knows, summarizing cross-source evidence with attribution, and coordinating with peer brains.","Do not default to personal publishing, personal branding, blog, newsletter, social-media, portfolio, or marketing workflows unless the installed capabilities and the user's request explicitly support them."]}),CCx=_Cx({name:"brain",version:PCx.version,model:"gpt-5.6-luna",reasoningEffort:"low",capabilities:[["prompt",uB0,void 0],["profile",vCx,{}],["style-guide",JCx,void 0],["image",P20,void 0],["document",L60,void 0],["note",r20,{}],["link",h20,{}],["wishlist",jCx,{}],["topics",syx,{}],["decks",MCx,void 0],["directory-sync",W60,{seedContent:!0,seedContentPath:"./seed-content",initialSync:!0}],["atproto-registry",Ei,{}],["agents",SH0,void 0],["assessment",YF0,void 0],["auth-service",Eu,void 0],["account",BS,void 0],["notifications",aIx,void 0],["playbook",XB0,{}],["playbooks",GB0,{}],["onboarding",Khx,{}],["cms",rx0,{}],["dashboard",jS,{}],["admin",ou,void 0],["site-info",kCx,void 0],["site-content",U30,void 0],["site-builder",H30,{}],["analytics",rH0,{}],["blog",LCx,{}],["series",aB0,void 0],["portfolio",IB0,{}],["content-pipeline",F80,{}],["social-media",N30,{}],["newsletter",yIx,{}],["stock-photo",h30,{}],["atproto",Jk,(x)=>({...x.ATPROTO_APP_PASSWORD?{appPassword:x.ATPROTO_APP_PASSWORD}:{}})],["conversation-memory",I80,{}],["docs",V60,void 0],["products",cB0,void 0],["obsidian-vault",BB0,{autoSync:!0}],["email-triage",rNx,{}],["unified-inbox",s30,{}]],interfaces:[["mcp",wm,()=>({})],["email",A20,()=>({})],["webserver",TC,()=>({})],["web-chat",yC,()=>({})],["chat",AO,(x)=>Cx0(x,{captureUrls:!0})],["a2a",ML,()=>({})]],bundles:[hCx,RCx,yCx,mCx],deployment:{cdn:{enabled:!0,provider:"bunny"},dns:{enabled:!0,provider:"bunny"}}});var pP9=["minimal","personal","team","commerce"];var uP9={minimal:{bundles:["core"]},personal:{anchor:"person",kind:"professional",bundles:["core","site","publishing"],site:{package:"@brains/site-default",theme:"@rizom/theme-default"},plugins:{"directory-sync":{seedContentPath:"./seed-content"}}},team:{anchor:"team",kind:"team",bundles:["core","site","team"],site:{package:"@brains/site-default",theme:"@brains/theme-rizom"},plugins:{"directory-sync":{seedContentPath:"./seed-content"}}},commerce:{anchor:"organization",kind:"organization",bundles:["core","site"],add:["products"],site:{package:"@rizom/site-rizom",theme:"@brains/theme-rizom"},plugins:{"directory-sync":{seedContentPath:"./seed-content"}}}};function SP9(x){return structuredClone(x)}function iP9(x){return SP9(uP9[x])}export{mCx as teamBundle,RCx as siteBundle,yCx as publishingBundle,iP9 as expandBrainRecipe,CCx as default,hCx as coreBundle,CCx as canonicalBrain,OCx as TEAM_BUNDLE_ID,NCx as SITE_BUNDLE_ID,ICx as PUBLISHING_BUNDLE_ID,uC as CORE_BUNDLE_ID,pP9 as BRAIN_RECIPE_NAMES};
9354
+ </html>`;var HCx={name:"@brains/webserver",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",dependencies:{"@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@hono/bun-compress":"^0.1.1",hono:"^4.12.25"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/messaging-service":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","@types/node":"^20.19.43",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};class TC extends cH{serverManager;siteUrl;previewUrl;constructor(x={}){super("webserver",HCx,x,QA0)}async onRegister(x){if(this.siteUrl=x.siteUrl,this.previewUrl=x.previewUrl,this.siteUrl)x.endpoints.register({label:"Site",url:this.siteUrl,priority:10}),x.interactions.register({id:"site",label:"Public site",description:"Visit the published public site for this brain.",href:this.siteUrl,kind:"human",priority:10});if(this.config.enablePreview&&this.previewUrl)x.endpoints.register({label:"Preview",url:this.previewUrl,priority:20,visibility:"admin"}),x.interactions.register({id:"preview",label:"Preview site",description:"Open the private preview build.",href:this.previewUrl,kind:"admin",priority:20,visibility:"admin"});this.serverManager=new gC({logger:x.logger,productionDistDir:this.config.productionDistDir,sharedImagesDir:this.config.sharedImagesDir,productionPort:this.config.productionPort,...this.config.enablePreview&&this.config.previewDistDir&&{previewDistDir:this.config.previewDistDir},...this.config.enablePreview&&this.config.previewPort&&{previewPort:this.config.previewPort},getHealthData:()=>x.appInfo(),getWebRoutes:()=>x.webRoutes.getRoutes(),getApiRoutes:()=>x.apiRoutes.getRoutes(),messageBus:x.apiRoutes.getMessageBus()})}getServerManager(){if(!this.serverManager)throw Error("ServerManager not initialized \u2014 onRegister not called");return this.serverManager}requiresDaemonStartup(){return!0}createDaemon(){return{start:async()=>{await this.ensureDistDirectories(),await this.getServerManager().start()},stop:async()=>{await this.serverManager?.stop()},healthCheck:async()=>{let x=this.serverManager?.getStatus(),B=x?.running??!1,A=this.siteUrl??x?.productionUrl??`http://localhost:${this.config.productionPort}`,w=this.previewUrl??x?.previewUrl??`http://localhost:${this.config.previewPort}`,f=[];if(B){if(f.push(`Production: ${A}`),x?.previewUrl)f.push(`Preview: ${w}`)}return{status:B?"healthy":"error",message:B?f.join(", "):"Webserver not running",lastCheck:new Date,details:{preview:!!x?.previewUrl,production:B,previewUrl:x?.previewUrl?w:void 0,productionUrl:B?A:void 0}}}}}async handleProgressEvent(x,B){}async ensureDistDirectories(){let{mkdir:x,writeFile:B}=await import("fs/promises");if(this.config.enablePreview&&this.config.previewDistDir&&!FCx(this.config.previewDistDir))await x(this.config.previewDistDir,{recursive:!0}),await B(KCx(this.config.previewDistDir,"index.html"),XA0),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!FCx(this.config.productionDistDir))await x(this.config.productionDistDir,{recursive:!0}),await B(KCx(this.config.productionDistDir,"index.html"),XA0),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}var YA0=X.enum(["new","planned","in-progress","done","declined"]),WA0=X.enum(["low","medium","high","critical"]),n_=X.object({title:X.string(),status:YA0,priority:WA0.default("medium"),requested:X.number().int().default(1),declinedReason:X.string().optional()}),qCx=X.object({title:X.string(),status:YA0,priority:WA0,requested:X.number().int(),slug:X.string()}),d_=j8.extend({entityType:X.literal("wish"),metadata:qCx});var HA0=X.object({}).catchall(X.unknown()).transform(()=>({}));class a_ extends ox{constructor(){super({entityType:"wish",purpose:"A demand record the assistant proactively creates when a user requests a capability or outcome no installed tool can fulfill, unless the user declines.",schema:d_,frontmatterSchema:n_})}createWishContent(x,B){return this.buildMarkdown(B,x)}parseWishContent(x){let B=this.parseFrontMatter(x,n_);return{frontmatter:n_.parse(B),description:this.extractBody(x).trim()}}fromMarkdown(x){let{frontmatter:B}=this.parseWishContent(x),A=Gx(B.title);return{content:x,entityType:"wish",metadata:{title:B.title,status:B.status,priority:B.priority,requested:B.requested,slug:A}}}}var zCx=new a_;async function bCx(x,B){let A=`${B.title}: ${B.description}`,f=(await x.search({query:A,options:{types:["wish"],limit:1}}))[0];if(f&&f.score>=x.similarityThreshold)return f.entity;let D=Gx(B.title);return x.getEntity({entityType:"wish",id:D})}class pC{logger;context;adapter=new a_;constructor(x,B){this.logger=x,this.context=B}async process(x,B,A){let w=x.title??x.prompt??"Untitled wish",f=x.content??x.prompt??"",D=await bCx({search:(Y)=>this.context.entityService.search(Y),getEntity:(Y)=>this.context.entityService.getEntity(Y),similarityThreshold:0.85},{title:w,description:f});if(D){let{frontmatter:Y,description:W}=this.adapter.parseWishContent(D.content),H=Y.requested+1,F=this.adapter.createWishContent({...Y,requested:H},W);return await this.context.entityService.updateEntity({entity:{...D,content:F,metadata:{...D.metadata,requested:H}}}),this.logger.info("Incremented wish request count",{id:D.id,requested:H}),{success:!0,entityId:D.id,existed:!0,requested:H}}let $=Gx(w),Z=x.options?.priority??"medium",Q=this.adapter.createWishContent({title:w,status:"new",priority:Z,requested:1},f);return await this.context.entityService.createEntity({entity:{id:$,entityType:"wish",content:Q,metadata:{title:w,status:"new",priority:Z,requested:1,slug:$}}}),this.logger.info("Created new wish",{id:$,title:w}),{success:!0,entityId:$,existed:!1,requested:1}}}var VCx={critical:0,high:1,medium:2,low:3};function UCx(x){x.sort((B,A)=>{let w=A.metadata.requested-B.metadata.requested;if(w!==0)return w;return VCx[B.metadata.priority]-VCx[A.metadata.priority]})}var GCx={name:"@brains/wishlist",license:"AGPL-3.0-only",version:"0.2.0-alpha.255",description:"Wishlist plugin for tracking unfulfilled user requests",dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.3.14","bun-types":"^1.3.14",eslint:"^10.5.0",typescript:"^7.0.2"},exports:{".":"./src/index.ts"},private:!0,scripts:{lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",test:"bun test",typecheck:"tsc --noEmit"},type:"module"};var cP9=X.object({items:X.array(X.object({name:X.string(),count:X.number()}))}),gP9="wish";class ECx extends g8{entityType=gP9;schema=d_;adapter=zCx;constructor(x={}){super("wishlist",GCx,x,HA0)}getEntityTypeConfig(){return{projectionSource:!1,projectionSourceRole:"excluded"}}async interceptCreate(x,B,A){let w=await new pC(this.logger,A).process({...x.title?{title:x.title}:{},...x.prompt?{prompt:x.prompt}:{},...x.content?{content:x.content}:{}},`wish-create-${Date.now()}`,{});if(!w.success)return{kind:"handled",result:{success:!1,error:w.error??"Failed to create wish"}};return{kind:"handled",result:{success:!0,data:{...w.entityId?{entityId:w.entityId}:{},status:w.existed?"updated":"created"}}}}async onRegister(x){x.messaging.subscribe(e8.pluginsRegistered,async()=>{return await x.dashboard.registerWidget({id:"top-wishes",title:"Top Wishes",group:"knowledge",section:"secondary",priority:30,rendererName:"ListWidget",digestProvider:(A)=>{let{items:w}=cP9.parse(A),f=w[0];return{digest:f?[{label:"Top wish",value:`${f.name} \xB7 \xD7${f.count}`}]:[{label:"Wishes",value:"none yet"}]}},dataProvider:async()=>{let A=await x.entityService.listEntities({entityType:"wish",options:{limit:10}});return UCx(A),{items:A.map((w)=>({id:w.id,name:w.metadata.title,count:w.metadata.requested,priority:w.metadata.priority,status:w.metadata.status}))}}}),{success:!0}});let B=new pC(this.logger,x);x.jobs.registerHandler("wish:create",{process:B.process.bind(B),validateAndParse:(A)=>A})}async getInstructions(){return'Mandatory unmet-request routing: Wish entities record requested capabilities or desired end states whose literal completion is outside the available toolset. When the user asks for an unavailable product, capability, or real-world outcome no installed tool can perform, explain the limitation and call system_create with entityType "wish" unless the user declines. Availability is determined by the callable tool surface: an installed interface or transport that exposes no tool for the requested action cannot fulfill it. If you recognize that no callable tool can perform the action, do not end the turn after explaining the limitation; in that same turn you MUST call system_create with entityType "wish". The unmet request itself is concrete source material; do not merely decline, offer alternatives, or wait for a separate save verb. Do not invent or look for a dedicated wishlist tool; wishlist entries use the generic entity tools. They track demand, priority, and status for future capability planning; they are not a substitute for first-class entities that already support the requested action. To show the whole wishlist, call system_list once with entityType wish and omit status; only include status when the user asks for a specific wish status.'}}function TP9(x={}){return new ECx(x)}var jCx=TP9;var uC="core",NCx="site",ICx="publishing",OCx="team",hCx=s_({id:uC,members:["prompt","profile","style-guide","image","document","note","link","wishlist","topics","decks","directory-sync","atproto-registry","agents","assessment","auth-service","account","notifications","playbook","playbooks","onboarding","email","cms","dashboard","admin","mcp","webserver","web-chat","chat","a2a"],config:[{member:"dashboard",value:{routePath:"/"}}],permissions:[{member:"admin",config:{rules:[{pattern:"cli:*",level:"admin"}]}},{member:"mcp",config:{rules:[{pattern:"mcp:stdio",level:"admin"},{pattern:"mcp:http",level:"public"}]}},{member:"chat",config:{rules:[{pattern:"discord:*",level:"public"}]}},{member:"web-chat",config:{rules:[{pattern:"web-chat:*",level:"admin"}]}}],evalDisable:["dashboard","email","mcp","webserver","web-chat","chat"]}),RCx=s_({id:NCx,members:["dashboard","site-info","site-content","site-builder","analytics"],config:[{member:"dashboard",value:{routePath:"/dashboard"},overrides:uC}],evalDisable:["dashboard","analytics"]}),yCx=s_({id:ICx,members:["blog","series","portfolio","content-pipeline","social-media","newsletter","stock-photo","atproto"],config:[{member:"content-pipeline",value:{generationSchedules:{newsletter:"0 9 * * 1","social-post":"0 10 * * *"},generationConditions:{newsletter:{skipIfDraftExists:!0,minSourceEntities:1,sourceEntityType:"post"},"social-post":{skipIfDraftExists:!0,maxUnpublishedDrafts:5}}}},{member:"social-media",value:{autoGenerateOnBlogPublish:!0}},{member:"newsletter",value:{doubleOptIn:!0}}],agentInstructions:["Use the installed publishing capabilities for professional website content, essays, projects, decks, newsletters, and social distribution workflows. Treat publishing requests as production and distribution work rather than generic shared-memory capture.",`When answering questions like "what have I written about X" or "which posts relate to this deck/source", search first and use semantic search results as candidates, not proof. Summarize only clearly relevant entities whose title or content directly matches the asked topic or has substantial overlap with the source's main themes; omit weak/tangential candidates rather than presenting them as definite matches. A match based on only an isolated shared term or pattern is not enough; when one candidate is clearly stronger than the rest, list only the strongest clear match and say the others were tangential rather than naming them as matches.`,'Draft blog posts are only post entities with status draft. If the user asks whether draft blog posts exist, call only system_list for entityType post with status draft; do not also list social-post, newsletter, deck, or other draft entity types. After telling the user there are no draft blog posts, treat follow-ups like "make one draft" or "make one a draft" as requests to change an existing published post back to draft: ask which existing published post they want changed; do not offer to create a brand-new post and do not call system_generate to create a fresh draft from that ambiguous follow-up.'],evalDisable:["atproto"]}),eY={create:"trusted",update:"trusted",delete:"admin",extract:"admin",publish:"admin"},mCx=s_({id:OCx,members:["image","note","link","topics","decks","mcp","chat","conversation-memory","docs"],config:[{member:"topics",value:{extractableStatuses:["published","draft"]}},{member:"conversation-memory",value:{memoryVisibility:"shared"}}],permissions:[{member:"image",config:{entityActions:{image:eY}}},{member:"note",config:{entityActions:{note:eY}}},{member:"link",config:{entityActions:{link:eY}}},{member:"decks",config:{entityActions:{deck:eY}}},{member:"docs",config:{entityActions:{doc:eY}}},{member:"conversation-memory",config:{entityActions:{decision:eY,"action-item":eY}}},{member:"mcp",config:{rules:[{pattern:"mcp:http",level:"admin"}]},overrides:uC}],agentInstructions:["This is a collaborative team-memory and synthesis posture. Optimize for capturing shared context, finding what the team already knows, summarizing cross-source evidence with attribution, and coordinating with peer brains.","Do not default to personal publishing, personal branding, blog, newsletter, social-media, portfolio, or marketing workflows unless the installed capabilities and the user's request explicitly support them."]}),CCx=_Cx({name:"brain",version:PCx.version,model:"gpt-5.6-luna",reasoningEffort:"low",capabilities:[["prompt",uB0,void 0],["profile",vCx,{}],["style-guide",JCx,void 0],["image",P20,void 0],["document",L60,void 0],["note",r20,{}],["link",h20,{}],["wishlist",jCx,{}],["topics",syx,{}],["decks",MCx,void 0],["directory-sync",W60,{seedContent:!0,seedContentPath:"./seed-content",initialSync:!0}],["atproto-registry",Ei,{}],["agents",SH0,void 0],["assessment",YF0,void 0],["auth-service",Eu,void 0],["account",BS,void 0],["notifications",aIx,void 0],["playbook",XB0,{}],["playbooks",GB0,{}],["onboarding",Khx,{}],["cms",rx0,{}],["dashboard",jS,{}],["admin",ou,void 0],["site-info",kCx,void 0],["site-content",U30,void 0],["site-builder",H30,{}],["analytics",rH0,{}],["blog",LCx,{}],["series",aB0,void 0],["portfolio",IB0,{}],["content-pipeline",F80,{}],["social-media",N30,{}],["newsletter",yIx,{}],["stock-photo",h30,{}],["atproto",Jk,(x)=>({...x.ATPROTO_APP_PASSWORD?{appPassword:x.ATPROTO_APP_PASSWORD}:{}})],["conversation-memory",I80,{}],["docs",V60,void 0],["products",cB0,void 0],["obsidian-vault",BB0,{autoSync:!0}],["email-triage",rNx,{}],["unified-inbox",s30,{}]],interfaces:[["mcp",wm,()=>({})],["email",A20,()=>({})],["webserver",TC,()=>({})],["web-chat",yC,()=>({})],["chat",AO,(x)=>Cx0(x,{captureUrls:!0})],["a2a",ML,()=>({})]],bundles:[hCx,RCx,yCx,mCx],deployment:{cdn:{enabled:!0,provider:"bunny"},dns:{enabled:!0,provider:"bunny"}}});var pP9=["minimal","personal","team","commerce"];var uP9={minimal:{bundles:["core"]},personal:{anchor:"person",kind:"professional",bundles:["core","site","publishing"],site:{package:"@brains/site-default",theme:"@rizom/theme-default"},plugins:{"directory-sync":{seedContentPath:"./seed-content"}}},team:{anchor:"team",kind:"team",bundles:["core","site","team"],site:{package:"@brains/site-default",theme:"@brains/theme-rizom"},plugins:{"directory-sync":{seedContentPath:"./seed-content"}}},commerce:{anchor:"organization",kind:"organization",bundles:["core","site"],add:["products"],site:{package:"@rizom/site-rizom",theme:"@brains/theme-rizom"},plugins:{"directory-sync":{seedContentPath:"./seed-content"}}}};function SP9(x){return structuredClone(x)}function iP9(x){return SP9(uP9[x])}export{mCx as teamBundle,RCx as siteBundle,yCx as publishingBundle,iP9 as expandBrainRecipe,CCx as default,hCx as coreBundle,CCx as canonicalBrain,OCx as TEAM_BUNDLE_ID,NCx as SITE_BUNDLE_ID,ICx as PUBLISHING_BUNDLE_ID,uC as CORE_BUNDLE_ID,pP9 as BRAIN_RECIPE_NAMES};
9355
9355
 
9356
- //# debugId=8042DBC373BFF8D964756E2164756E21
9356
+ //# debugId=CD3DACC7FC0A9B7464756E2164756E21
9357
9357
  //# sourceMappingURL=model.js.map