@rizom/brain 0.2.0-alpha.8 → 0.2.0-alpha.9

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/brain.js CHANGED
@@ -489,7 +489,7 @@ This will delete existing topics and regenerate them from scratch.`,args:{...x,c
489
489
  hash text NOT NULL,
490
490
  created_at numeric
491
491
  )
492
- `;await A.session.run(B);let c=(await A.values(VA`SELECT id, hash, created_at FROM ${VA.identifier(Q)} ORDER BY created_at DESC LIMIT 1`))[0]??void 0,I=[];for(let $ of w)if(!c||Number(c[2])<$.folderMillis){for(let u of $.sql)I.push(A.run(VA.raw(u)));I.push(A.run(VA`INSERT INTO ${VA.identifier(Q)} ("hash", "created_at") VALUES(${$.hash}, ${$.folderMillis})`))}await A.session.migrate(I)}var tn=T(()=>{$oA();TB()});async function uoA(A,f){let w=f?.child("entity-migrate")??O2.getInstance().child("entity-migrate"),{db:Q,client:B,url:x}=iP(A);w.debug("Running entity database migrations...");try{await MP(B,x);let I=import.meta.url.includes("/dist/")?new URL("./migrations/entity-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Vh(Q,{migrationsFolder:I}),await OP(B),w.debug("Entity database migrations completed successfully")}catch(c){throw w.error("Entity database migration failed:",c),c}finally{B.close()}}var DoA=T(()=>{tn();$2A();YA()});async function YoA(A,f){let w=f?.child("job-queue-migrate")??O2.getInstance().child("job-queue-migrate"),{db:Q,client:B,url:x}=_P(A);w.debug("Running job queue migrations...");try{await VP(B,x);let I=import.meta.url.includes("/dist/")?new URL("./migrations/job-queue",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Vh(Q,{migrationsFolder:I}),w.debug("Job queue migrations completed successfully")}catch(c){throw w.error("Job queue migration failed:",c),c}finally{B.close()}}var HoA=T(()=>{tn();x2A();YA()});async function UoA(A,f){let w=f?.child("conversation-migrate")??O2.getInstance().child("conversation-migrate"),{db:Q,client:B,url:x}=mP(A);w.debug("Running conversation database migrations...");try{if(x.startsWith("file:"))await B.execute("PRAGMA journal_mode = WAL");let I=import.meta.url.includes("/dist/")?new URL("./migrations/conversation-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Vh(Q,{migrationsFolder:I}),w.debug("Conversation database migrations completed successfully")}catch(c){throw w.error("Conversation database migration failed:",c),c}finally{B.close()}}var FoA=T(()=>{tn();j2A();YA()});class YL{logger;migrations;constructor(A,f){this.logger=A,this.migrations=f??{getStandardConfigWithDirectories:TC,migrateEntities:uoA,migrateJobQueue:YoA,migrateConversations:UoA}}async runAllMigrations(A){this.logger.debug("Running database migrations...");let f=await this.migrations.getStandardConfigWithDirectories();if(A?.database)f.database.url=A.database;if(A?.jobQueueDatabase)f.jobQueueDatabase.url=A.jobQueueDatabase;if(A?.conversationDatabase)f.conversationDatabase.url=A.conversationDatabase;await this.migrateEntityDatabase(f),await this.migrateJobQueueDatabase(f),await this.migrateConversationDatabase(f),this.logger.debug("All database migrations completed successfully")}async migrateEntityDatabase(A){this.logger.debug("Running entity database migrations..."),await this.migrations.migrateEntities({url:A.database.url,...A.database.authToken&&{authToken:A.database.authToken}},this.logger)}async migrateJobQueueDatabase(A){this.logger.debug("Running job queue database migrations..."),await this.migrations.migrateJobQueue({url:A.jobQueueDatabase.url,...A.jobQueueDatabase.authToken&&{authToken:A.jobQueueDatabase.authToken}},this.logger)}async migrateConversationDatabase(A){this.logger.debug("Running conversation database migrations..."),await this.migrations.migrateConversations({url:A.conversationDatabase.url,...A.conversationDatabase.authToken&&{authToken:A.conversationDatabase.authToken}},this.logger)}}var k9A=T(()=>{an();DoA();HoA();FoA()});var en;var h9A=T(()=>{YA();en=X.object({theme:X.object({primaryColor:X.string().describe("Primary color for the CLI theme").default("#0066cc"),accentColor:X.string().describe("Accent color for the CLI theme").default("#ff6600")}).describe("Theme configuration for the CLI interface").default({primaryColor:"#0066cc",accentColor:"#ff6600"})})});var XoA;var KoA=T(()=>{XoA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.8",type:"module",main:"./src/index.ts",module:"./src/index.ts",types:"./src/index.ts",files:["src"],scripts:{dev:"tsc --watch",typecheck:"tsc --noEmit",lint:"eslint --max-warnings 0 .","lint:fix":"eslint --fix .",test:"bun test"},dependencies:{"@brains/plugins":"workspace:*",chalk:"^5.4.1",ink:"^6.0.1","ink-spinner":"^5.0.0","ink-text-input":"^6.0.0",marked:"^12.0.0",react:"^19.1.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/react":"^19.0.3",typescript:"^5.3.3"}}});var Xf=C((ib1,Am)=>{(function(){function A(fA,KA){Object.defineProperty(Q.prototype,fA,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",KA[0],KA[1])}})}function f(fA){if(fA===null||typeof fA!=="object")return null;return fA=aA&&fA[aA]||fA["@@iterator"],typeof fA==="function"?fA:null}function w(fA,KA){fA=(fA=fA.constructor)&&(fA.displayName||fA.name)||"ReactClass";var dA=fA+"."+KA;FA[dA]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",KA,fA),FA[dA]=!0)}function Q(fA,KA,dA){this.props=fA,this.context=KA,this.refs=jA,this.updater=dA||GA}function B(){}function x(fA,KA,dA){this.props=fA,this.context=KA,this.refs=jA,this.updater=dA||GA}function c(){}function I(fA){return""+fA}function $(fA){try{I(fA);var KA=!1}catch(m0){KA=!0}if(KA){KA=console;var dA=KA.error,n0=typeof Symbol==="function"&&Symbol.toStringTag&&fA[Symbol.toStringTag]||fA.constructor.name||"Object";return dA.call(KA,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n0),I(fA)}}function u(fA){if(fA==null)return null;if(typeof fA==="function")return fA.$$typeof===eA?null:fA.displayName||fA.name||null;if(typeof fA==="string")return fA;switch(fA){case e:return"Fragment";case HA:return"Profiler";case d:return"StrictMode";case P0:return"Suspense";case WA:return"SuspenseList";case kA:return"Activity"}if(typeof fA==="object")switch(typeof fA.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),fA.$$typeof){case p:return"Portal";case uA:return fA.displayName||"Context";case PA:return(fA._context.displayName||"Context")+".Consumer";case I0:var KA=fA.render;return fA=fA.displayName,fA||(fA=KA.displayName||KA.name||"",fA=fA!==""?"ForwardRef("+fA+")":"ForwardRef"),fA;case _0:return KA=fA.displayName||null,KA!==null?KA:u(fA.type)||"Memo";case $0:KA=fA._payload,fA=fA._init;try{return u(fA(KA))}catch(dA){}}return null}function Y(fA){if(fA===e)return"<>";if(typeof fA==="object"&&fA!==null&&fA.$$typeof===$0)return"<...>";try{var KA=u(fA);return KA?"<"+KA+">":"<...>"}catch(dA){return"<...>"}}function F(){var fA=rA.A;return fA===null?null:fA.getOwner()}function K(){return Error("react-stack-top-frame")}function Z(fA){if(zA.call(fA,"key")){var KA=Object.getOwnPropertyDescriptor(fA,"key").get;if(KA&&KA.isReactWarning)return!1}return fA.key!==void 0}function k(fA,KA){function dA(){AA||(AA=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",KA))}dA.isReactWarning=!0,Object.defineProperty(fA,"key",{get:dA,configurable:!0})}function h(){var fA=u(this.type);return T0[fA]||(T0[fA]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),fA=this.props.ref,fA!==void 0?fA:null}function G(fA,KA,dA,n0,m0,U1){var J0=dA.ref;return fA={$$typeof:a,type:fA,key:KA,props:dA,_owner:n0},(J0!==void 0?J0:null)!==null?Object.defineProperty(fA,"ref",{enumerable:!1,get:h}):Object.defineProperty(fA,"ref",{enumerable:!1,value:null}),fA._store={},Object.defineProperty(fA._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(fA,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(fA,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:m0}),Object.defineProperty(fA,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:U1}),Object.freeze&&(Object.freeze(fA.props),Object.freeze(fA)),fA}function E(fA,KA){return KA=G(fA.type,KA,fA.props,fA._owner,fA._debugStack,fA._debugTask),fA._store&&(KA._store.validated=fA._store.validated),KA}function V(fA){q(fA)?fA._store&&(fA._store.validated=1):typeof fA==="object"&&fA!==null&&fA.$$typeof===$0&&(fA._payload.status==="fulfilled"?q(fA._payload.value)&&fA._payload.value._store&&(fA._payload.value._store.validated=1):fA._store&&(fA._store.validated=1))}function q(fA){return typeof fA==="object"&&fA!==null&&fA.$$typeof===a}function y(fA){var KA={"=":"=0",":":"=2"};return"$"+fA.replace(/[=:]/g,function(dA){return KA[dA]})}function r(fA,KA){return typeof fA==="object"&&fA!==null&&fA.key!=null?($(fA.key),y(""+fA.key)):KA.toString(36)}function g(fA){switch(fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason;default:switch(typeof fA.status==="string"?fA.then(c,c):(fA.status="pending",fA.then(function(KA){fA.status==="pending"&&(fA.status="fulfilled",fA.value=KA)},function(KA){fA.status==="pending"&&(fA.status="rejected",fA.reason=KA)})),fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason}}throw fA}function M(fA,KA,dA,n0,m0){var U1=typeof fA;if(U1==="undefined"||U1==="boolean")fA=null;var J0=!1;if(fA===null)J0=!0;else switch(U1){case"bigint":case"string":case"number":J0=!0;break;case"object":switch(fA.$$typeof){case a:case p:J0=!0;break;case $0:return J0=fA._init,M(J0(fA._payload),KA,dA,n0,m0)}}if(J0){J0=fA,m0=m0(J0);var J1=n0===""?"."+r(J0,0):n0;return x0(m0)?(dA="",J1!=null&&(dA=J1.replace(_A,"$&/")+"/"),M(m0,KA,dA,"",function(N2){return N2})):m0!=null&&(q(m0)&&(m0.key!=null&&(J0&&J0.key===m0.key||$(m0.key)),dA=E(m0,dA+(m0.key==null||J0&&J0.key===m0.key?"":(""+m0.key).replace(_A,"$&/")+"/")+J1),n0!==""&&J0!=null&&q(J0)&&J0.key==null&&J0._store&&!J0._store.validated&&(dA._store.validated=2),m0=dA),KA.push(m0)),1}if(J0=0,J1=n0===""?".":n0+":",x0(fA))for(var h1=0;h1<fA.length;h1++)n0=fA[h1],U1=J1+r(n0,h1),J0+=M(n0,KA,dA,U1,m0);else if(h1=f(fA),typeof h1==="function")for(h1===fA.entries&&(OA||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),OA=!0),fA=h1.call(fA),h1=0;!(n0=fA.next()).done;)n0=n0.value,U1=J1+r(n0,h1++),J0+=M(n0,KA,dA,U1,m0);else if(U1==="object"){if(typeof fA.then==="function")return M(g(fA),KA,dA,n0,m0);throw KA=String(fA),Error("Objects are not valid as a React child (found: "+(KA==="[object Object]"?"object with keys {"+Object.keys(fA).join(", ")+"}":KA)+"). If you meant to render a collection of children, use an array instead.")}return J0}function j(fA,KA,dA){if(fA==null)return fA;var n0=[],m0=0;return M(fA,n0,"","",function(U1){return KA.call(dA,U1,m0++)}),n0}function P(fA){if(fA._status===-1){var KA=fA._ioInfo;KA!=null&&(KA.start=KA.end=performance.now()),KA=fA._result;var dA=KA();if(dA.then(function(m0){if(fA._status===0||fA._status===-1){fA._status=1,fA._result=m0;var U1=fA._ioInfo;U1!=null&&(U1.end=performance.now()),dA.status===void 0&&(dA.status="fulfilled",dA.value=m0)}},function(m0){if(fA._status===0||fA._status===-1){fA._status=2,fA._result=m0;var U1=fA._ioInfo;U1!=null&&(U1.end=performance.now()),dA.status===void 0&&(dA.status="rejected",dA.reason=m0)}}),KA=fA._ioInfo,KA!=null){KA.value=dA;var n0=dA.displayName;typeof n0==="string"&&(KA.name=n0)}fA._status===-1&&(fA._status=0,fA._result=dA)}if(fA._status===1)return KA=fA._result,KA===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
492
+ `;await A.session.run(B);let c=(await A.values(VA`SELECT id, hash, created_at FROM ${VA.identifier(Q)} ORDER BY created_at DESC LIMIT 1`))[0]??void 0,I=[];for(let $ of w)if(!c||Number(c[2])<$.folderMillis){for(let u of $.sql)I.push(A.run(VA.raw(u)));I.push(A.run(VA`INSERT INTO ${VA.identifier(Q)} ("hash", "created_at") VALUES(${$.hash}, ${$.folderMillis})`))}await A.session.migrate(I)}var tn=T(()=>{$oA();TB()});async function uoA(A,f){let w=f?.child("entity-migrate")??O2.getInstance().child("entity-migrate"),{db:Q,client:B,url:x}=iP(A);w.debug("Running entity database migrations...");try{await MP(B,x);let I=import.meta.url.includes("/dist/")?new URL("./migrations/entity-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Vh(Q,{migrationsFolder:I}),await OP(B),w.debug("Entity database migrations completed successfully")}catch(c){throw w.error("Entity database migration failed:",c),c}finally{B.close()}}var DoA=T(()=>{tn();$2A();YA()});async function YoA(A,f){let w=f?.child("job-queue-migrate")??O2.getInstance().child("job-queue-migrate"),{db:Q,client:B,url:x}=_P(A);w.debug("Running job queue migrations...");try{await VP(B,x);let I=import.meta.url.includes("/dist/")?new URL("./migrations/job-queue",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Vh(Q,{migrationsFolder:I}),w.debug("Job queue migrations completed successfully")}catch(c){throw w.error("Job queue migration failed:",c),c}finally{B.close()}}var HoA=T(()=>{tn();x2A();YA()});async function UoA(A,f){let w=f?.child("conversation-migrate")??O2.getInstance().child("conversation-migrate"),{db:Q,client:B,url:x}=mP(A);w.debug("Running conversation database migrations...");try{if(x.startsWith("file:"))await B.execute("PRAGMA journal_mode = WAL");let I=import.meta.url.includes("/dist/")?new URL("./migrations/conversation-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Vh(Q,{migrationsFolder:I}),w.debug("Conversation database migrations completed successfully")}catch(c){throw w.error("Conversation database migration failed:",c),c}finally{B.close()}}var FoA=T(()=>{tn();j2A();YA()});class YL{logger;migrations;constructor(A,f){this.logger=A,this.migrations=f??{getStandardConfigWithDirectories:TC,migrateEntities:uoA,migrateJobQueue:YoA,migrateConversations:UoA}}async runAllMigrations(A){this.logger.debug("Running database migrations...");let f=await this.migrations.getStandardConfigWithDirectories();if(A?.database)f.database.url=A.database;if(A?.jobQueueDatabase)f.jobQueueDatabase.url=A.jobQueueDatabase;if(A?.conversationDatabase)f.conversationDatabase.url=A.conversationDatabase;await this.migrateEntityDatabase(f),await this.migrateJobQueueDatabase(f),await this.migrateConversationDatabase(f),this.logger.debug("All database migrations completed successfully")}async migrateEntityDatabase(A){this.logger.debug("Running entity database migrations..."),await this.migrations.migrateEntities({url:A.database.url,...A.database.authToken&&{authToken:A.database.authToken}},this.logger)}async migrateJobQueueDatabase(A){this.logger.debug("Running job queue database migrations..."),await this.migrations.migrateJobQueue({url:A.jobQueueDatabase.url,...A.jobQueueDatabase.authToken&&{authToken:A.jobQueueDatabase.authToken}},this.logger)}async migrateConversationDatabase(A){this.logger.debug("Running conversation database migrations..."),await this.migrations.migrateConversations({url:A.conversationDatabase.url,...A.conversationDatabase.authToken&&{authToken:A.conversationDatabase.authToken}},this.logger)}}var k9A=T(()=>{an();DoA();HoA();FoA()});var en;var h9A=T(()=>{YA();en=X.object({theme:X.object({primaryColor:X.string().describe("Primary color for the CLI theme").default("#0066cc"),accentColor:X.string().describe("Accent color for the CLI theme").default("#ff6600")}).describe("Theme configuration for the CLI interface").default({primaryColor:"#0066cc",accentColor:"#ff6600"})})});var XoA;var KoA=T(()=>{XoA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.9",type:"module",main:"./src/index.ts",module:"./src/index.ts",types:"./src/index.ts",files:["src"],scripts:{dev:"tsc --watch",typecheck:"tsc --noEmit",lint:"eslint --max-warnings 0 .","lint:fix":"eslint --fix .",test:"bun test"},dependencies:{"@brains/plugins":"workspace:*",chalk:"^5.4.1",ink:"^6.0.1","ink-spinner":"^5.0.0","ink-text-input":"^6.0.0",marked:"^12.0.0",react:"^19.1.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/react":"^19.0.3",typescript:"^5.3.3"}}});var Xf=C((ib1,Am)=>{(function(){function A(fA,KA){Object.defineProperty(Q.prototype,fA,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",KA[0],KA[1])}})}function f(fA){if(fA===null||typeof fA!=="object")return null;return fA=aA&&fA[aA]||fA["@@iterator"],typeof fA==="function"?fA:null}function w(fA,KA){fA=(fA=fA.constructor)&&(fA.displayName||fA.name)||"ReactClass";var dA=fA+"."+KA;FA[dA]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",KA,fA),FA[dA]=!0)}function Q(fA,KA,dA){this.props=fA,this.context=KA,this.refs=jA,this.updater=dA||GA}function B(){}function x(fA,KA,dA){this.props=fA,this.context=KA,this.refs=jA,this.updater=dA||GA}function c(){}function I(fA){return""+fA}function $(fA){try{I(fA);var KA=!1}catch(m0){KA=!0}if(KA){KA=console;var dA=KA.error,n0=typeof Symbol==="function"&&Symbol.toStringTag&&fA[Symbol.toStringTag]||fA.constructor.name||"Object";return dA.call(KA,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n0),I(fA)}}function u(fA){if(fA==null)return null;if(typeof fA==="function")return fA.$$typeof===eA?null:fA.displayName||fA.name||null;if(typeof fA==="string")return fA;switch(fA){case e:return"Fragment";case HA:return"Profiler";case d:return"StrictMode";case P0:return"Suspense";case WA:return"SuspenseList";case kA:return"Activity"}if(typeof fA==="object")switch(typeof fA.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),fA.$$typeof){case p:return"Portal";case uA:return fA.displayName||"Context";case PA:return(fA._context.displayName||"Context")+".Consumer";case I0:var KA=fA.render;return fA=fA.displayName,fA||(fA=KA.displayName||KA.name||"",fA=fA!==""?"ForwardRef("+fA+")":"ForwardRef"),fA;case _0:return KA=fA.displayName||null,KA!==null?KA:u(fA.type)||"Memo";case $0:KA=fA._payload,fA=fA._init;try{return u(fA(KA))}catch(dA){}}return null}function Y(fA){if(fA===e)return"<>";if(typeof fA==="object"&&fA!==null&&fA.$$typeof===$0)return"<...>";try{var KA=u(fA);return KA?"<"+KA+">":"<...>"}catch(dA){return"<...>"}}function F(){var fA=rA.A;return fA===null?null:fA.getOwner()}function K(){return Error("react-stack-top-frame")}function Z(fA){if(zA.call(fA,"key")){var KA=Object.getOwnPropertyDescriptor(fA,"key").get;if(KA&&KA.isReactWarning)return!1}return fA.key!==void 0}function k(fA,KA){function dA(){AA||(AA=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",KA))}dA.isReactWarning=!0,Object.defineProperty(fA,"key",{get:dA,configurable:!0})}function h(){var fA=u(this.type);return T0[fA]||(T0[fA]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),fA=this.props.ref,fA!==void 0?fA:null}function G(fA,KA,dA,n0,m0,U1){var J0=dA.ref;return fA={$$typeof:a,type:fA,key:KA,props:dA,_owner:n0},(J0!==void 0?J0:null)!==null?Object.defineProperty(fA,"ref",{enumerable:!1,get:h}):Object.defineProperty(fA,"ref",{enumerable:!1,value:null}),fA._store={},Object.defineProperty(fA._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(fA,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(fA,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:m0}),Object.defineProperty(fA,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:U1}),Object.freeze&&(Object.freeze(fA.props),Object.freeze(fA)),fA}function E(fA,KA){return KA=G(fA.type,KA,fA.props,fA._owner,fA._debugStack,fA._debugTask),fA._store&&(KA._store.validated=fA._store.validated),KA}function V(fA){q(fA)?fA._store&&(fA._store.validated=1):typeof fA==="object"&&fA!==null&&fA.$$typeof===$0&&(fA._payload.status==="fulfilled"?q(fA._payload.value)&&fA._payload.value._store&&(fA._payload.value._store.validated=1):fA._store&&(fA._store.validated=1))}function q(fA){return typeof fA==="object"&&fA!==null&&fA.$$typeof===a}function y(fA){var KA={"=":"=0",":":"=2"};return"$"+fA.replace(/[=:]/g,function(dA){return KA[dA]})}function r(fA,KA){return typeof fA==="object"&&fA!==null&&fA.key!=null?($(fA.key),y(""+fA.key)):KA.toString(36)}function g(fA){switch(fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason;default:switch(typeof fA.status==="string"?fA.then(c,c):(fA.status="pending",fA.then(function(KA){fA.status==="pending"&&(fA.status="fulfilled",fA.value=KA)},function(KA){fA.status==="pending"&&(fA.status="rejected",fA.reason=KA)})),fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason}}throw fA}function M(fA,KA,dA,n0,m0){var U1=typeof fA;if(U1==="undefined"||U1==="boolean")fA=null;var J0=!1;if(fA===null)J0=!0;else switch(U1){case"bigint":case"string":case"number":J0=!0;break;case"object":switch(fA.$$typeof){case a:case p:J0=!0;break;case $0:return J0=fA._init,M(J0(fA._payload),KA,dA,n0,m0)}}if(J0){J0=fA,m0=m0(J0);var J1=n0===""?"."+r(J0,0):n0;return x0(m0)?(dA="",J1!=null&&(dA=J1.replace(_A,"$&/")+"/"),M(m0,KA,dA,"",function(N2){return N2})):m0!=null&&(q(m0)&&(m0.key!=null&&(J0&&J0.key===m0.key||$(m0.key)),dA=E(m0,dA+(m0.key==null||J0&&J0.key===m0.key?"":(""+m0.key).replace(_A,"$&/")+"/")+J1),n0!==""&&J0!=null&&q(J0)&&J0.key==null&&J0._store&&!J0._store.validated&&(dA._store.validated=2),m0=dA),KA.push(m0)),1}if(J0=0,J1=n0===""?".":n0+":",x0(fA))for(var h1=0;h1<fA.length;h1++)n0=fA[h1],U1=J1+r(n0,h1),J0+=M(n0,KA,dA,U1,m0);else if(h1=f(fA),typeof h1==="function")for(h1===fA.entries&&(OA||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),OA=!0),fA=h1.call(fA),h1=0;!(n0=fA.next()).done;)n0=n0.value,U1=J1+r(n0,h1++),J0+=M(n0,KA,dA,U1,m0);else if(U1==="object"){if(typeof fA.then==="function")return M(g(fA),KA,dA,n0,m0);throw KA=String(fA),Error("Objects are not valid as a React child (found: "+(KA==="[object Object]"?"object with keys {"+Object.keys(fA).join(", ")+"}":KA)+"). If you meant to render a collection of children, use an array instead.")}return J0}function j(fA,KA,dA){if(fA==null)return fA;var n0=[],m0=0;return M(fA,n0,"","",function(U1){return KA.call(dA,U1,m0++)}),n0}function P(fA){if(fA._status===-1){var KA=fA._ioInfo;KA!=null&&(KA.start=KA.end=performance.now()),KA=fA._result;var dA=KA();if(dA.then(function(m0){if(fA._status===0||fA._status===-1){fA._status=1,fA._result=m0;var U1=fA._ioInfo;U1!=null&&(U1.end=performance.now()),dA.status===void 0&&(dA.status="fulfilled",dA.value=m0)}},function(m0){if(fA._status===0||fA._status===-1){fA._status=2,fA._result=m0;var U1=fA._ioInfo;U1!=null&&(U1.end=performance.now()),dA.status===void 0&&(dA.status="rejected",dA.reason=m0)}}),KA=fA._ioInfo,KA!=null){KA.value=dA;var n0=dA.displayName;typeof n0==="string"&&(KA.name=n0)}fA._status===-1&&(fA._status=0,fA._result=dA)}if(fA._status===1)return KA=fA._result,KA===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
493
493
 
494
494
  Your code should look like:
495
495
  const MyComponent = lazy(() => import('./MyComponent'))
@@ -1848,7 +1848,7 @@ Example bad output: "A dreamlike crystal formation glowing with ethereal light i
1848
1848
  Title: "${A.entityTitle??I}"
1849
1849
 
1850
1850
  Content:
1851
- ${A.entityContent}`,wq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt distillation failed, using fallback",{error:h0(E)})}}await this.reportProgress(w,{progress:F2.PROCESS,message:"Generating image"});let u=this.context.identity.get(),Y=this.context.identity.getProfile(),K=UA0(u,Y)+$,Z;try{Z=await this.context.ai.generateImage(K,{...B&&{aspectRatio:B}})}catch(E){return this.logger.error("Image generation failed",{jobId:f,error:h0(E)}),h8.failure(E)}await this.reportProgress(w,{progress:F2.GENERATE,message:"Creating image entity"});let k=x2(I),h=dH.createImageEntity({dataUrl:Z.dataUrl,title:I});if(await this.context.entityService.getEntity("image",k))this.logger.debug("Deleting existing image for regeneration",{imageId:k}),await this.context.entityService.deleteEntity("image",k);if(await this.context.entityService.createEntity({...h,id:k}),this.logger.debug("Created image entity",{imageId:k}),x&&c){await this.reportProgress(w,{progress:F2.SAVE,message:`Updating ${x} with cover image`});let E=await this.context.entityService.getEntity(x,c);if(!E)return h8.failure(Error(`Target entity not found: ${x}/${c}`));let V=$k(E,k);await this.context.entities.update(V),this.logger.debug("Updated target entity with cover image",{targetEntityType:x,targetEntityId:c,imageId:k})}return await this.reportProgress(w,{progress:F2.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:f,imageId:k,targetEntityType:x,targetEntityId:c}),{success:!0,imageId:k}}catch($){return this.logger.error("Image generation job failed",{jobId:f,error:h0($)}),h8.failure($)}}summarizeDataForLog(A){return{title:A.title,promptLength:A.prompt.length,aspectRatio:A.aspectRatio,targetEntityType:A.targetEntityType,targetEntityId:A.targetEntityId}}}var FA0={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.8",description:"Plugin for AI-powered image generation and management",type:"module",main:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"}};var xq1=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")});class E5A extends Nf{entityType=dH.entityType;schema=sL;adapter=dH;constructor(A={}){super("image",FA0,A,xq1)}getEntityTypeConfig(){return{embeddable:!1}}createGenerationHandler(A){return new Fl(A,this.logger)}async onRegister(A){let f=new Fl(A,this.logger);A.jobs.registerHandler("image-generate",f)}}function Aq(A){return new E5A(A)}B0();import{StdioServerTransport as cq1}from"@modelcontextprotocol/sdk/server/stdio.js";function KA0(){return{info:(A,...f)=>console.error(`[STDIO MCP] ${A}`,...f),debug:(A,...f)=>console.error(`[STDIO MCP DEBUG] ${A}`,...f),error:(A,...f)=>console.error(`[STDIO MCP ERROR] ${A}`,...f),warn:(A,...f)=>console.error(`[STDIO MCP WARN] ${A}`,...f)}}function L5A(){return{info:(A,...f)=>console.log(`[HTTP MCP] ${A}`,...f),debug:(A,...f)=>console.debug(`[HTTP MCP DEBUG] ${A}`,...f),error:(A,...f)=>console.error(`[HTTP MCP ERROR] ${A}`,...f),warn:(A,...f)=>console.warn(`[HTTP MCP WARN] ${A}`,...f)}}function Kl(A){if(A&&typeof A==="object"&&"info"in A&&"debug"in A&&"error"in A&&"warn"in A){let f=A;return{info:(w,...Q)=>f.info(w,...Q),debug:(w,...Q)=>f.debug(w,...Q),error:(w,...Q)=>f.error(w,...Q),warn:(w,...Q)=>f.warn(w,...Q)}}return L5A()}class wI{static instance=null;mcpServer=null;transport=null;config;logger;static getInstance(A){return wI.instance??=new wI(A),wI.instance}static resetInstance(){if(wI.instance)wI.instance.stop(),wI.instance=null}static createFresh(A){return new wI(A)}constructor(A={}){this.config=A,this.logger=this.config.logger?Kl(this.config.logger):KA0()}connectMCPServer(A){this.mcpServer=A,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 cq1,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}}var m7A=o0(r80(),1),wB0=o0(t80(),1),w_=o0(AB0(),1);import{randomUUID as fB0}from"crypto";import{StreamableHTTPServerTransport as $l1}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as ul1}from"@modelcontextprotocol/sdk/types.js";class Y3{static instance=null;app;transports={};mcpServer=null;mcpTransport=null;agentService=null;server=null;boundPort=null;config;logger;authConfig;constructor(A={}){if(this.config=A,this.logger=this.config.logger?Kl(this.config.logger):L5A(),this.authConfig=A.auth??{},!this.authConfig.disabled&&!this.authConfig.token)throw Error("MCP HTTP transport requires an auth token. Set MCP_AUTH_TOKEN in your environment, or pass auth: { disabled: true } for local dev.");this.app=m7A.default(),this.setupMiddleware(),this.setupRoutes()}static getInstance(A){return Y3.instance??=new Y3(A),Y3.instance}static resetInstance(){Y3.instance=null}static createFresh(A){return new Y3(A)}authMiddleware=(A,f,w)=>{if(A.path==="/health"||A.path==="/status")return w();if(this.authConfig.disabled||!this.authConfig.token)return w();let Q=A.headers.authorization;if(!Q?.startsWith("Bearer ")){this.logger.warn(`Authentication failed: Missing Bearer token from ${A.ip}`),f.status(401).json({jsonrpc:"2.0",error:{code:-32001,message:"Unauthorized: Bearer token required"},id:null});return}if(Q.substring(7)!==this.authConfig.token){this.logger.warn(`Authentication failed: Invalid token from ${A.ip}`),f.status(401).json({jsonrpc:"2.0",error:{code:-32001,message:"Unauthorized: Invalid token"},id:null});return}this.logger.debug(`Authentication successful from ${A.ip}`),w()};setupMiddleware(){this.app.use(m7A.default.json()),this.app.use(wB0.default()),this.app.use((A,f,w)=>{this.logger.debug(`${A.method} ${A.path}`),w()}),this.app.use(this.authMiddleware)}setupRoutes(){this.app.get("/health",(A,f)=>{f.json({status:"ok",transport:"streamable-http",timestamp:new Date().toISOString()})}),this.app.get("/status",(A,f)=>{f.json({sessions:Object.keys(this.transports).length,uptime:process.uptime(),memory:process.memoryUsage(),port:this.boundPort??this.config.port??3333})}),this.app.post("/mcp",w_.default(async(A,f)=>{if(!this.mcpServer){f.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"Service Unavailable: MCP server not connected"},id:null});return}let w=this.mcpServer;this.logger.debug(`POST /mcp - Session: ${A.headers["mcp-session-id"]??"new"}`);try{let Q=A.headers["mcp-session-id"],B;if(Q&&this.transports[Q])B=this.transports[Q];else if(!Q&&ul1(A.body)){B=new $l1({sessionIdGenerator:()=>fB0(),onsessioninitialized:(c)=>{this.logger.info(`Session initialized: ${c}`),this.transports[c]=B},onsessionclosed:(c)=>{this.logger.info(`Session closed: ${c}`),delete this.transports[c]}}),await(this.mcpTransport?this.mcpTransport.createMcpServer():w).connect(B),await B.handleRequest(A,f,A.body);return}else{f.status(400).json({jsonrpc:"2.0",error:{code:-32000,message:"Bad Request: Server not initialized"},id:null});return}await B.handleRequest(A,f,A.body)}catch(Q){if(this.logger.error("MCP transport error:",Q),!f.headersSent)f.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}})}})),this.app.get("/mcp",w_.default(async(A,f)=>{let w=A.headers["mcp-session-id"];if(!w||!this.transports[w]){f.status(400).send("Invalid or missing session ID");return}this.logger.debug(`GET /mcp - SSE stream for session ${w}`),await this.transports[w].handleRequest(A,f)})),this.app.delete("/mcp",w_.default(async(A,f)=>{let w=A.headers["mcp-session-id"];if(!w||!this.transports[w]){f.status(400).send("Invalid or missing session ID");return}this.logger.info(`DELETE /mcp - Terminating session ${w}`),await this.transports[w].handleRequest(A,f)})),this.app.post("/api/chat",w_.default(async(A,f)=>{if(!this.agentService){f.status(503).json({error:"Agent service not connected"});return}let{message:w,conversationId:Q}=A.body;if(!w||typeof w!=="string"){f.status(400).json({error:"Missing or invalid 'message' field"});return}let B=Q??fB0();this.logger.debug(`POST /api/chat - conversation: ${B}`);try{let x=await this.agentService.chat(w,B);f.json(x)}catch(x){this.logger.error("Agent chat error:",x),f.status(500).json({error:x instanceof Error?x.message:"Internal error"})}}))}connectMCPServer(A,f){this.mcpServer=A,this.mcpTransport=f??null,this.logger.debug("MCP server connected to StreamableHTTP transport")}connectAgentService(A){this.agentService=A,this.logger.debug("Agent service connected to StreamableHTTP transport")}async start(){if(this.server)throw Error("Server is already running");let A=this.config.port??3333,f=this.config.host??"0.0.0.0";return new Promise((w,Q)=>{this.server=this.app.listen(Number(A),f,()=>{let B=this.server?.address();this.boundPort=typeof B==="object"&&B?B.port:Number(A),this.logger.info(`StreamableHTTP server listening on http://${f}:${this.boundPort}/mcp`),w()}).on("error",(B)=>{if(B.code==="EADDRINUSE")this.logger.error(`Port ${A} is already in use`);Q(B)})})}async stop(){for(let A in this.transports)try{let f=this.transports[A];if(f)this.logger.debug(`Closing transport for session ${A}`),await f.close(),delete this.transports[A]}catch(f){this.logger.error(`Error closing transport for session ${A}:`,f)}if(this.server)return new Promise((A)=>{this.server?.close(()=>{this.logger.info("StreamableHTTP server stopped"),this.server=null,this.boundPort=null,A()})})}getPort(){if(this.boundPort===null)throw Error("Server is not running");return this.boundPort}getApp(){return this.app}isRunning(){return this.server!==null}getSessionCount(){return Object.keys(this.transports).length}}YA();var l7A=X.object({transport:X.enum(["stdio","http"]).default("http"),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()});function QB0(A,f){return[]}B0();function T7A(A,f){A.messaging.subscribe("job-progress",async(w)=>{let Q=qk.safeParse(w.payload);if(!Q.success)return f.warn("Received invalid job-progress message",{error:Q.error.message}),{success:!1};let B=Q.data,x=B.type,c=B.status,I=B.id;if(f.debug(`${x} ${I} - ${c}:`,{id:B.id,message:B.message,progress:B.progress,metadata:B.metadata}),B.batchDetails)f.debug(`Batch details for ${I}:`,{totalOperations:B.batchDetails.totalOperations,completedOperations:B.batchDetails.completedOperations,failedOperations:B.batchDetails.failedOperations,currentOperation:B.batchDetails.currentOperation,errors:B.batchDetails.errors});if(B.jobDetails)f.debug(`Job details for ${I}:`,{jobType:B.jobDetails.jobType,priority:B.jobDetails.priority,retryCount:B.jobDetails.retryCount});return{success:!0}}),f.debug("Subscribed to job progress events")}var BB0={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.8",type:"module",main:"./src/index.ts",module:"./src/index.ts",types:"./src/index.ts",files:["src"],scripts:{typecheck:"tsc --noEmit",lint:"eslint --max-warnings 0 .","lint:fix":"eslint --fix .",test:"bun test"},dependencies:{"@brains/mcp-service":"workspace:*","@brains/plugins":"workspace:*","@modelcontextprotocol/sdk":"^1.24.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.1.14","@types/cors":"^2.8.17","@types/express":"^4.17.21",typescript:"^5.3.3"}};class QU extends _${mcpTransport;stdioServer;httpServer;domain;constructor(A={}){let f={...A,authToken:A.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",BB0,f,l7A)}async getTools(){return QB0(this.id,()=>this.context)}async getResources(){return[]}async onRegister(A){this.domain=A.domain,this.logger.debug(`MCP interface initialized with ${this.config.transport} transport`),T7A(A,this.logger)}createDaemon(){return{start:async()=>{await this.startServer()},stop:async()=>{await this.stopServer()},healthCheck:async()=>{let A=this.isServerRunning(),f="MCP server not running";if(A)if(this.config.transport==="http")f=`MCP HTTP: ${this.domain?`https://${this.domain}/mcp`:`http://localhost:${this.config.httpPort}/mcp`}`;else f="MCP stdio server running";return{status:A?"healthy":"error",message:f,lastCheck:new Date,details:{transport:this.config.transport,url:this.config.transport==="http"?this.domain?`https://${this.domain}/mcp`:`http://localhost:${this.config.httpPort}/mcp`:void 0,running:A}}}}}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");this.mcpTransport=this.context.mcpTransport;let A=this.config.transport==="stdio"?"stdio":"http",f=this.context.permissions.getUserLevel("mcp",A);if(this.config.transport==="http"&&this.config.authToken)f="anchor",this.logger.debug("HTTP auth token configured - authenticated users will have anchor permissions");if(this.mcpTransport.setPermissionLevel(f),this.logger.debug(`Starting MCP ${this.config.transport} transport with ${f} permissions`),this.config.transport==="stdio"){this.stdioServer=wI.createFresh();let w=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(w),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=Y3.createFresh({port:this.config.httpPort,logger:this.logger,auth:{token:this.config.authToken}});let w=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(w,this.mcpTransport),this.httpServer.connectAgentService(this.context.agentService),await this.httpServer.start(),this.logger.debug(`MCP HTTP transport started on port ${this.config.httpPort}`)}}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(A,f){}async onShutdown(){wI.resetInstance(),Y3.resetInstance()}}B0();YA();var g4=o0(JL0(),1);YA();B0();var zHA=X.object({botToken:X.string().min(1).describe("Discord bot token"),allowedChannels:X.array(X.string()).default([]),requireMention:X.boolean().default(!0),allowDMs:X.boolean().default(!0),showTypingIndicator:X.boolean().default(!0),statusMessage:X.string().default("Mention me to chat"),useThreads:X.boolean().default(!0),threadAutoArchive:X.union([X.literal(60),X.literal(1440),X.literal(4320),X.literal(10080)]).default(1440),...yP.shape,captureUrlEmoji:X.string().default("\uD83D\uDD16")});var bL0={name:"@brains/discord",private:!0,version:"0.2.0-alpha.8",description:"Discord interface for Brains",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",test:"bun test"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*","discord.js":"^14.14.1"},devDependencies:{"@brains/core":"workspace:*","@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest"}};var NHA=2000,zF2=8000,NF2=100;function Cp(A){return!!A&&typeof A==="object"&&"send"in A&&"sendTyping"in A}class PU extends n7{client=null;fetchText;pendingConfirmations=new Map;typingIntervals=new Map;constructor(A,f={}){super("discord",bL0,A,zHA);this.fetchText=f.fetchText??AP}async onRegister(A){await super.onRegister(A),this.client=new g4.Client({intents:[g4.GatewayIntentBits.Guilds,g4.GatewayIntentBits.GuildMessages,g4.GatewayIntentBits.MessageContent,g4.GatewayIntentBits.DirectMessages],partials:[g4.Partials.Channel]}),this.client.on(g4.Events.MessageCreate,(f)=>{this.handleMessage(f)}),this.client.once(g4.Events.ClientReady,()=>{this.logger.info("Discord bot connected",{tag:this.client?.user?.tag})})}createDaemon(){return{start:async()=>{if(!this.client)throw Error("Discord client not initialized");await this.client.login(this.config.botToken)},stop:async()=>{for(let A of this.typingIntervals.values())clearInterval(A);if(this.typingIntervals.clear(),this.client)await this.client.destroy(),this.client=null},healthCheck:async()=>({status:this.client?.user?"healthy":"error",message:this.client?.user?`Connected as ${this.client.user.tag}`:"Not connected",lastCheck:new Date})}}sendMessageToChannel(A,f){if(!A||!this.client)return;let w=this.client.channels.cache.get(A);if(!Cp(w))return;let Q=QC(f,NHA);for(let B of Q)w.send(B).catch((x)=>this.logger.error("Failed to send message",{error:x}))}async sendMessageWithId(A,f){if(!A||!this.client)return;let w=this.client.channels.cache.get(A);if(!Cp(w))return;let Q=QC(f,NHA),B;for(let x of Q)B=(await w.send(x)).id;return B}async editMessage(A,f,w){if(!A||!this.client)return!1;let Q=this.client.channels.cache.get(A);if(!Cp(Q))return!1;try{return await(await Q.messages.fetch(f)).edit(w.slice(0,NHA)),!0}catch{return!1}}supportsMessageEditing(){return!0}async handleMessage(A){if(A.author.id===this.client?.user?.id)return;if(!this.context)return;let f=!A.guild,w=A.channel.isThread();if(f&&!this.config.allowDMs)return;let Q=!!this.client?.user&&A.mentions.has(this.client.user,{ignoreEveryone:!0});if(A.author.bot&&!Q)return;let B=w&&"ownerId"in A.channel&&A.channel.ownerId===this.client?.user?.id;if(this.config.allowedChannels.length>0&&!f&&!this.config.allowedChannels.includes(A.channel.id))return;if(!f&&!B&&this.config.requireMention&&!Q){if(this.config.captureUrls){let I=this.extractCaptureableUrls(A.content,this.config.blockedUrlDomains);if(I.length>0){await A.react(this.config.captureUrlEmoji).catch(($)=>this.logger.debug("React failed",{error:$}));for(let $ of I)await this.captureUrlViaAgent($,A.channel.id,A.author.id,"discord").catch((u)=>this.logger.error("URL capture failed",{error:u,url:$}))}}return}let x=this.stripMention(A.content);if(A.attachments.size>0){let I=this.context.permissions.getUserLevel("discord",A.author.id);if(I==="anchor"||I==="trusted")for(let u of A.attachments.values()){let Y=u.name,F=u.contentType??void 0,K=u.size;if(!this.isUploadableTextFile(Y,F))continue;if(!this.isFileSizeAllowed(K))continue;try{let Z=await this.fetchText(u.url);x+=`
1851
+ ${A.entityContent}`,wq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt distillation failed, using fallback",{error:h0(E)})}}await this.reportProgress(w,{progress:F2.PROCESS,message:"Generating image"});let u=this.context.identity.get(),Y=this.context.identity.getProfile(),K=UA0(u,Y)+$,Z;try{Z=await this.context.ai.generateImage(K,{...B&&{aspectRatio:B}})}catch(E){return this.logger.error("Image generation failed",{jobId:f,error:h0(E)}),h8.failure(E)}await this.reportProgress(w,{progress:F2.GENERATE,message:"Creating image entity"});let k=x2(I),h=dH.createImageEntity({dataUrl:Z.dataUrl,title:I});if(await this.context.entityService.getEntity("image",k))this.logger.debug("Deleting existing image for regeneration",{imageId:k}),await this.context.entityService.deleteEntity("image",k);if(await this.context.entityService.createEntity({...h,id:k}),this.logger.debug("Created image entity",{imageId:k}),x&&c){await this.reportProgress(w,{progress:F2.SAVE,message:`Updating ${x} with cover image`});let E=await this.context.entityService.getEntity(x,c);if(!E)return h8.failure(Error(`Target entity not found: ${x}/${c}`));let V=$k(E,k);await this.context.entities.update(V),this.logger.debug("Updated target entity with cover image",{targetEntityType:x,targetEntityId:c,imageId:k})}return await this.reportProgress(w,{progress:F2.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:f,imageId:k,targetEntityType:x,targetEntityId:c}),{success:!0,imageId:k}}catch($){return this.logger.error("Image generation job failed",{jobId:f,error:h0($)}),h8.failure($)}}summarizeDataForLog(A){return{title:A.title,promptLength:A.prompt.length,aspectRatio:A.aspectRatio,targetEntityType:A.targetEntityType,targetEntityId:A.targetEntityId}}}var FA0={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.9",description:"Plugin for AI-powered image generation and management",type:"module",main:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"}};var xq1=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")});class E5A extends Nf{entityType=dH.entityType;schema=sL;adapter=dH;constructor(A={}){super("image",FA0,A,xq1)}getEntityTypeConfig(){return{embeddable:!1}}createGenerationHandler(A){return new Fl(A,this.logger)}async onRegister(A){let f=new Fl(A,this.logger);A.jobs.registerHandler("image-generate",f)}}function Aq(A){return new E5A(A)}B0();import{StdioServerTransport as cq1}from"@modelcontextprotocol/sdk/server/stdio.js";function KA0(){return{info:(A,...f)=>console.error(`[STDIO MCP] ${A}`,...f),debug:(A,...f)=>console.error(`[STDIO MCP DEBUG] ${A}`,...f),error:(A,...f)=>console.error(`[STDIO MCP ERROR] ${A}`,...f),warn:(A,...f)=>console.error(`[STDIO MCP WARN] ${A}`,...f)}}function L5A(){return{info:(A,...f)=>console.log(`[HTTP MCP] ${A}`,...f),debug:(A,...f)=>console.debug(`[HTTP MCP DEBUG] ${A}`,...f),error:(A,...f)=>console.error(`[HTTP MCP ERROR] ${A}`,...f),warn:(A,...f)=>console.warn(`[HTTP MCP WARN] ${A}`,...f)}}function Kl(A){if(A&&typeof A==="object"&&"info"in A&&"debug"in A&&"error"in A&&"warn"in A){let f=A;return{info:(w,...Q)=>f.info(w,...Q),debug:(w,...Q)=>f.debug(w,...Q),error:(w,...Q)=>f.error(w,...Q),warn:(w,...Q)=>f.warn(w,...Q)}}return L5A()}class wI{static instance=null;mcpServer=null;transport=null;config;logger;static getInstance(A){return wI.instance??=new wI(A),wI.instance}static resetInstance(){if(wI.instance)wI.instance.stop(),wI.instance=null}static createFresh(A){return new wI(A)}constructor(A={}){this.config=A,this.logger=this.config.logger?Kl(this.config.logger):KA0()}connectMCPServer(A){this.mcpServer=A,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 cq1,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}}var m7A=o0(r80(),1),wB0=o0(t80(),1),w_=o0(AB0(),1);import{randomUUID as fB0}from"crypto";import{StreamableHTTPServerTransport as $l1}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as ul1}from"@modelcontextprotocol/sdk/types.js";class Y3{static instance=null;app;transports={};mcpServer=null;mcpTransport=null;agentService=null;server=null;boundPort=null;config;logger;authConfig;constructor(A={}){if(this.config=A,this.logger=this.config.logger?Kl(this.config.logger):L5A(),this.authConfig=A.auth??{},!this.authConfig.disabled&&!this.authConfig.token)throw Error("MCP HTTP transport requires an auth token. Set MCP_AUTH_TOKEN in your environment, or pass auth: { disabled: true } for local dev.");this.app=m7A.default(),this.setupMiddleware(),this.setupRoutes()}static getInstance(A){return Y3.instance??=new Y3(A),Y3.instance}static resetInstance(){Y3.instance=null}static createFresh(A){return new Y3(A)}authMiddleware=(A,f,w)=>{if(A.path==="/health"||A.path==="/status")return w();if(this.authConfig.disabled||!this.authConfig.token)return w();let Q=A.headers.authorization;if(!Q?.startsWith("Bearer ")){this.logger.warn(`Authentication failed: Missing Bearer token from ${A.ip}`),f.status(401).json({jsonrpc:"2.0",error:{code:-32001,message:"Unauthorized: Bearer token required"},id:null});return}if(Q.substring(7)!==this.authConfig.token){this.logger.warn(`Authentication failed: Invalid token from ${A.ip}`),f.status(401).json({jsonrpc:"2.0",error:{code:-32001,message:"Unauthorized: Invalid token"},id:null});return}this.logger.debug(`Authentication successful from ${A.ip}`),w()};setupMiddleware(){this.app.use(m7A.default.json()),this.app.use(wB0.default()),this.app.use((A,f,w)=>{this.logger.debug(`${A.method} ${A.path}`),w()}),this.app.use(this.authMiddleware)}setupRoutes(){this.app.get("/health",(A,f)=>{f.json({status:"ok",transport:"streamable-http",timestamp:new Date().toISOString()})}),this.app.get("/status",(A,f)=>{f.json({sessions:Object.keys(this.transports).length,uptime:process.uptime(),memory:process.memoryUsage(),port:this.boundPort??this.config.port??3333})}),this.app.post("/mcp",w_.default(async(A,f)=>{if(!this.mcpServer){f.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"Service Unavailable: MCP server not connected"},id:null});return}let w=this.mcpServer;this.logger.debug(`POST /mcp - Session: ${A.headers["mcp-session-id"]??"new"}`);try{let Q=A.headers["mcp-session-id"],B;if(Q&&this.transports[Q])B=this.transports[Q];else if(!Q&&ul1(A.body)){B=new $l1({sessionIdGenerator:()=>fB0(),onsessioninitialized:(c)=>{this.logger.info(`Session initialized: ${c}`),this.transports[c]=B},onsessionclosed:(c)=>{this.logger.info(`Session closed: ${c}`),delete this.transports[c]}}),await(this.mcpTransport?this.mcpTransport.createMcpServer():w).connect(B),await B.handleRequest(A,f,A.body);return}else{f.status(400).json({jsonrpc:"2.0",error:{code:-32000,message:"Bad Request: Server not initialized"},id:null});return}await B.handleRequest(A,f,A.body)}catch(Q){if(this.logger.error("MCP transport error:",Q),!f.headersSent)f.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}})}})),this.app.get("/mcp",w_.default(async(A,f)=>{let w=A.headers["mcp-session-id"];if(!w||!this.transports[w]){f.status(400).send("Invalid or missing session ID");return}this.logger.debug(`GET /mcp - SSE stream for session ${w}`),await this.transports[w].handleRequest(A,f)})),this.app.delete("/mcp",w_.default(async(A,f)=>{let w=A.headers["mcp-session-id"];if(!w||!this.transports[w]){f.status(400).send("Invalid or missing session ID");return}this.logger.info(`DELETE /mcp - Terminating session ${w}`),await this.transports[w].handleRequest(A,f)})),this.app.post("/api/chat",w_.default(async(A,f)=>{if(!this.agentService){f.status(503).json({error:"Agent service not connected"});return}let{message:w,conversationId:Q}=A.body;if(!w||typeof w!=="string"){f.status(400).json({error:"Missing or invalid 'message' field"});return}let B=Q??fB0();this.logger.debug(`POST /api/chat - conversation: ${B}`);try{let x=await this.agentService.chat(w,B);f.json(x)}catch(x){this.logger.error("Agent chat error:",x),f.status(500).json({error:x instanceof Error?x.message:"Internal error"})}}))}connectMCPServer(A,f){this.mcpServer=A,this.mcpTransport=f??null,this.logger.debug("MCP server connected to StreamableHTTP transport")}connectAgentService(A){this.agentService=A,this.logger.debug("Agent service connected to StreamableHTTP transport")}async start(){if(this.server)throw Error("Server is already running");let A=this.config.port??3333,f=this.config.host??"0.0.0.0";return new Promise((w,Q)=>{this.server=this.app.listen(Number(A),f,()=>{let B=this.server?.address();this.boundPort=typeof B==="object"&&B?B.port:Number(A),this.logger.info(`StreamableHTTP server listening on http://${f}:${this.boundPort}/mcp`),w()}).on("error",(B)=>{if(B.code==="EADDRINUSE")this.logger.error(`Port ${A} is already in use`);Q(B)})})}async stop(){for(let A in this.transports)try{let f=this.transports[A];if(f)this.logger.debug(`Closing transport for session ${A}`),await f.close(),delete this.transports[A]}catch(f){this.logger.error(`Error closing transport for session ${A}:`,f)}if(this.server)return new Promise((A)=>{this.server?.close(()=>{this.logger.info("StreamableHTTP server stopped"),this.server=null,this.boundPort=null,A()})})}getPort(){if(this.boundPort===null)throw Error("Server is not running");return this.boundPort}getApp(){return this.app}isRunning(){return this.server!==null}getSessionCount(){return Object.keys(this.transports).length}}YA();var l7A=X.object({transport:X.enum(["stdio","http"]).default("http"),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()});function QB0(A,f){return[]}B0();function T7A(A,f){A.messaging.subscribe("job-progress",async(w)=>{let Q=qk.safeParse(w.payload);if(!Q.success)return f.warn("Received invalid job-progress message",{error:Q.error.message}),{success:!1};let B=Q.data,x=B.type,c=B.status,I=B.id;if(f.debug(`${x} ${I} - ${c}:`,{id:B.id,message:B.message,progress:B.progress,metadata:B.metadata}),B.batchDetails)f.debug(`Batch details for ${I}:`,{totalOperations:B.batchDetails.totalOperations,completedOperations:B.batchDetails.completedOperations,failedOperations:B.batchDetails.failedOperations,currentOperation:B.batchDetails.currentOperation,errors:B.batchDetails.errors});if(B.jobDetails)f.debug(`Job details for ${I}:`,{jobType:B.jobDetails.jobType,priority:B.jobDetails.priority,retryCount:B.jobDetails.retryCount});return{success:!0}}),f.debug("Subscribed to job progress events")}var BB0={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.9",type:"module",main:"./src/index.ts",module:"./src/index.ts",types:"./src/index.ts",files:["src"],scripts:{typecheck:"tsc --noEmit",lint:"eslint --max-warnings 0 .","lint:fix":"eslint --fix .",test:"bun test"},dependencies:{"@brains/mcp-service":"workspace:*","@brains/plugins":"workspace:*","@modelcontextprotocol/sdk":"^1.24.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.1.14","@types/cors":"^2.8.17","@types/express":"^4.17.21",typescript:"^5.3.3"}};class QU extends _${mcpTransport;stdioServer;httpServer;domain;constructor(A={}){let f={...A,authToken:A.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",BB0,f,l7A)}async getTools(){return QB0(this.id,()=>this.context)}async getResources(){return[]}async onRegister(A){this.domain=A.domain,this.logger.debug(`MCP interface initialized with ${this.config.transport} transport`),T7A(A,this.logger)}createDaemon(){return{start:async()=>{await this.startServer()},stop:async()=>{await this.stopServer()},healthCheck:async()=>{let A=this.isServerRunning(),f="MCP server not running";if(A)if(this.config.transport==="http")f=`MCP HTTP: ${this.domain?`https://${this.domain}/mcp`:`http://localhost:${this.config.httpPort}/mcp`}`;else f="MCP stdio server running";return{status:A?"healthy":"error",message:f,lastCheck:new Date,details:{transport:this.config.transport,url:this.config.transport==="http"?this.domain?`https://${this.domain}/mcp`:`http://localhost:${this.config.httpPort}/mcp`:void 0,running:A}}}}}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");this.mcpTransport=this.context.mcpTransport;let A=this.config.transport==="stdio"?"stdio":"http",f=this.context.permissions.getUserLevel("mcp",A);if(this.config.transport==="http"&&this.config.authToken)f="anchor",this.logger.debug("HTTP auth token configured - authenticated users will have anchor permissions");if(this.mcpTransport.setPermissionLevel(f),this.logger.debug(`Starting MCP ${this.config.transport} transport with ${f} permissions`),this.config.transport==="stdio"){this.stdioServer=wI.createFresh();let w=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(w),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=Y3.createFresh({port:this.config.httpPort,logger:this.logger,auth:{token:this.config.authToken}});let w=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(w,this.mcpTransport),this.httpServer.connectAgentService(this.context.agentService),await this.httpServer.start(),this.logger.debug(`MCP HTTP transport started on port ${this.config.httpPort}`)}}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(A,f){}async onShutdown(){wI.resetInstance(),Y3.resetInstance()}}B0();YA();var g4=o0(JL0(),1);YA();B0();var zHA=X.object({botToken:X.string().min(1).describe("Discord bot token"),allowedChannels:X.array(X.string()).default([]),requireMention:X.boolean().default(!0),allowDMs:X.boolean().default(!0),showTypingIndicator:X.boolean().default(!0),statusMessage:X.string().default("Mention me to chat"),useThreads:X.boolean().default(!0),threadAutoArchive:X.union([X.literal(60),X.literal(1440),X.literal(4320),X.literal(10080)]).default(1440),...yP.shape,captureUrlEmoji:X.string().default("\uD83D\uDD16")});var bL0={name:"@brains/discord",private:!0,version:"0.2.0-alpha.9",description:"Discord interface for Brains",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",test:"bun test"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*","discord.js":"^14.14.1"},devDependencies:{"@brains/core":"workspace:*","@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest"}};var NHA=2000,zF2=8000,NF2=100;function Cp(A){return!!A&&typeof A==="object"&&"send"in A&&"sendTyping"in A}class PU extends n7{client=null;fetchText;pendingConfirmations=new Map;typingIntervals=new Map;constructor(A,f={}){super("discord",bL0,A,zHA);this.fetchText=f.fetchText??AP}async onRegister(A){await super.onRegister(A),this.client=new g4.Client({intents:[g4.GatewayIntentBits.Guilds,g4.GatewayIntentBits.GuildMessages,g4.GatewayIntentBits.MessageContent,g4.GatewayIntentBits.DirectMessages],partials:[g4.Partials.Channel]}),this.client.on(g4.Events.MessageCreate,(f)=>{this.handleMessage(f)}),this.client.once(g4.Events.ClientReady,()=>{this.logger.info("Discord bot connected",{tag:this.client?.user?.tag})})}createDaemon(){return{start:async()=>{if(!this.client)throw Error("Discord client not initialized");await this.client.login(this.config.botToken)},stop:async()=>{for(let A of this.typingIntervals.values())clearInterval(A);if(this.typingIntervals.clear(),this.client)await this.client.destroy(),this.client=null},healthCheck:async()=>({status:this.client?.user?"healthy":"error",message:this.client?.user?`Connected as ${this.client.user.tag}`:"Not connected",lastCheck:new Date})}}sendMessageToChannel(A,f){if(!A||!this.client)return;let w=this.client.channels.cache.get(A);if(!Cp(w))return;let Q=QC(f,NHA);for(let B of Q)w.send(B).catch((x)=>this.logger.error("Failed to send message",{error:x}))}async sendMessageWithId(A,f){if(!A||!this.client)return;let w=this.client.channels.cache.get(A);if(!Cp(w))return;let Q=QC(f,NHA),B;for(let x of Q)B=(await w.send(x)).id;return B}async editMessage(A,f,w){if(!A||!this.client)return!1;let Q=this.client.channels.cache.get(A);if(!Cp(Q))return!1;try{return await(await Q.messages.fetch(f)).edit(w.slice(0,NHA)),!0}catch{return!1}}supportsMessageEditing(){return!0}async handleMessage(A){if(A.author.id===this.client?.user?.id)return;if(!this.context)return;let f=!A.guild,w=A.channel.isThread();if(f&&!this.config.allowDMs)return;let Q=!!this.client?.user&&A.mentions.has(this.client.user,{ignoreEveryone:!0});if(A.author.bot&&!Q)return;let B=w&&"ownerId"in A.channel&&A.channel.ownerId===this.client?.user?.id;if(this.config.allowedChannels.length>0&&!f&&!this.config.allowedChannels.includes(A.channel.id))return;if(!f&&!B&&this.config.requireMention&&!Q){if(this.config.captureUrls){let I=this.extractCaptureableUrls(A.content,this.config.blockedUrlDomains);if(I.length>0){await A.react(this.config.captureUrlEmoji).catch(($)=>this.logger.debug("React failed",{error:$}));for(let $ of I)await this.captureUrlViaAgent($,A.channel.id,A.author.id,"discord").catch((u)=>this.logger.error("URL capture failed",{error:u,url:$}))}}return}let x=this.stripMention(A.content);if(A.attachments.size>0){let I=this.context.permissions.getUserLevel("discord",A.author.id);if(I==="anchor"||I==="trusted")for(let u of A.attachments.values()){let Y=u.name,F=u.contentType??void 0,K=u.size;if(!this.isUploadableTextFile(Y,F))continue;if(!this.isFileSizeAllowed(K))continue;try{let Z=await this.fetchText(u.url);x+=`
1852
1852
 
1853
1853
  `+this.formatFileUploadMessage(Y,Z)}catch(Z){this.logger.error("Failed to download attachment",{error:Z,filename:Y})}}}if(x=x.trim(),!x)return;let c=A.channel.id;await this.routeToAgent(x,c,A)}async routeToAgent(A,f,w){if(!this.context)return;let Q=this.context.agentService,B=f;if(this.config.useThreads&&w.guild&&!w.channel.isThread())try{B=(await w.startThread({name:XH(A,NF2),autoArchiveDuration:this.config.threadAutoArchive})).id}catch($){this.logger.error("Failed to create thread",{error:$})}let x=`discord-${B}`,c=this.context.permissions.getUserLevel("discord",w.author.id),I=w.guild?.name??"DM";this.startProcessingInput(B);try{let $=this.client?.channels.cache.get(B);if(Cp($))this.startTypingIndicator($);if(this.pendingConfirmations.has(x)){await this.handleConfirmationResponse(A,x,B);return}let u=await Q.chat(A,x,{userPermissionLevel:c,interfaceType:"discord",channelId:B,channelName:I});if(u.pendingConfirmation)this.pendingConfirmations.set(x,!0);let Y=await this.sendMessageWithId(B,u.text);if(Y&&u.toolResults){for(let F of u.toolResults)if(F.jobId)this.trackAgentResponseForJob(F.jobId,Y,B)}}catch($){this.logger.error("Error handling message",{error:$,channelId:B}),this.sendMessageToChannel(B,`**Error:** ${$ instanceof Error?$.message:"Unknown error"}`)}finally{this.endProcessingInput(),this.stopTypingIndicator(B)}}async handleConfirmationResponse(A,f,w){let Q=Ok(A);if(!Q){this.sendMessageToChannel(w,"_Please reply with **yes** to confirm or **no/cancel** to abort._");return}this.pendingConfirmations.delete(f);let B=await this.context?.agentService.confirmPendingAction(f,Q.confirmed);if(B)await this.sendMessageWithId(w,B.text)}startTypingIndicator(A){if(!this.config.showTypingIndicator)return;A.sendTyping().catch((w)=>this.logger.debug("Typing indicator failed",{error:w}));let f=setInterval(()=>{A.sendTyping().catch((w)=>this.logger.debug("Typing indicator failed",{error:w}))},zF2);this.typingIntervals.set(A.id,f)}stopTypingIndicator(A){let f=this.typingIntervals.get(A);if(f)clearInterval(f),this.typingIntervals.delete(A)}stripMention(A){if(!this.client?.user)return A;return A.replace(new RegExp(`<@!?${this.client.user.id}>`,"g"),"").trim()}}B0();import{resolve as lJ,join as HK2}from"path";var CHA=(A,f,w)=>{return(Q,B)=>{let x=-1;return c(0);async function c(I){if(I<=x)throw Error("next() called multiple times");x=I;let $,u=!1,Y;if(A[I])Y=A[I][0][0],Q.req.routeIndex=I;else Y=I===A.length&&B||void 0;if(Y)try{$=await Y(Q,()=>c(I+1))}catch(F){if(F instanceof Error&&f)Q.error=F,$=await f(F,Q),u=!0;else throw F}else if(Q.finalized===!1&&w)$=await w(Q);if($&&(Q.finalized===!1||u))Q.res=$;return Q}}};var zL0=Symbol();var NL0=async(A,f=Object.create(null))=>{let{all:w=!1,dot:Q=!1}=f,x=(A instanceof Ep?A.raw.headers:A.headers).get("Content-Type");if(x?.startsWith("multipart/form-data")||x?.startsWith("application/x-www-form-urlencoded"))return CF2(A,{all:w,dot:Q});return{}};async function CF2(A,f){let w=await A.formData();if(w)return EF2(w,f);return{}}function EF2(A,f){let w=Object.create(null);if(A.forEach((Q,B)=>{if(!(f.all||B.endsWith("[]")))w[B]=Q;else LF2(w,B,Q)}),f.dot)Object.entries(w).forEach(([Q,B])=>{if(Q.includes("."))qF2(w,Q,B),delete w[Q]});return w}var LF2=(A,f,w)=>{if(A[f]!==void 0)if(Array.isArray(A[f]))A[f].push(w);else A[f]=[A[f],w];else if(!f.endsWith("[]"))A[f]=w;else A[f]=[w]},qF2=(A,f,w)=>{let Q=A,B=f.split(".");B.forEach((x,c)=>{if(c===B.length-1)Q[x]=w;else{if(!Q[x]||typeof Q[x]!=="object"||Array.isArray(Q[x])||Q[x]instanceof File)Q[x]=Object.create(null);Q=Q[x]}})};var LHA=(A)=>{let f=A.split("/");if(f[0]==="")f.shift();return f},CL0=(A)=>{let{groups:f,path:w}=_F2(A),Q=LHA(w);return VF2(Q,f)},_F2=(A)=>{let f=[];return A=A.replace(/\{[^}]+\}/g,(w,Q)=>{let B=`@${Q}`;return f.push([B,w]),B}),{groups:f,path:A}},VF2=(A,f)=>{for(let w=f.length-1;w>=0;w--){let[Q]=f[w];for(let B=A.length-1;B>=0;B--)if(A[B].includes(Q)){A[B]=A[B].replace(Q,f[w][1]);break}}return A},Lp={},EL0=(A,f)=>{if(A==="*")return"*";let w=A.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);if(w){let Q=`${A}#${f}`;if(!Lp[Q])if(w[2])Lp[Q]=f&&f[0]!==":"&&f[0]!=="*"?[Q,w[1],new RegExp(`^${w[2]}(?=/${f})`)]:[A,w[1],new RegExp(`^${w[2]}$`)];else Lp[Q]=[A,w[1],!0];return Lp[Q]}return null},qp=(A,f)=>{try{return f(A)}catch{return A.replace(/(?:%[0-9A-Fa-f]{2})+/g,(w)=>{try{return f(w)}catch{return w}})}},qHA=(A)=>qp(A,decodeURI),_HA=(A)=>{let f=A.url,w=f.indexOf("/",f.indexOf(":")+4),Q=w;for(;Q<f.length;Q++){let B=f.charCodeAt(Q);if(B===37){let x=f.indexOf("?",Q),c=f.indexOf("#",Q),I=x===-1?c===-1?void 0:c:c===-1?x:Math.min(x,c),$=f.slice(w,I);return qHA($.includes("%25")?$.replace(/%25/g,"%2525"):$)}else if(B===63||B===35)break}return f.slice(w,Q)};var LL0=(A)=>{let f=_HA(A);return f.length>1&&f.at(-1)==="/"?f.slice(0,-1):f},PZ=(A,f,...w)=>{if(w.length)f=PZ(f,...w);return`${A?.[0]==="/"?"":"/"}${A}${f==="/"?"":`${A?.at(-1)==="/"?"":"/"}${f?.[0]==="/"?f.slice(1):f}`}`},_p=(A)=>{if(A.charCodeAt(A.length-1)!==63||!A.includes(":"))return null;let f=A.split("/"),w=[],Q="";return f.forEach((B)=>{if(B!==""&&!/\:/.test(B))Q+="/"+B;else if(/\:/.test(B))if(/\?/.test(B)){if(w.length===0&&Q==="")w.push("/");else w.push(Q);let x=B.replace("?","");Q+="/"+x,w.push(Q)}else Q+="/"+B}),w.filter((B,x,c)=>c.indexOf(B)===x)},EHA=(A)=>{if(!/[%+]/.test(A))return A;if(A.indexOf("+")!==-1)A=A.replace(/\+/g," ");return A.indexOf("%")!==-1?qp(A,VHA):A},qL0=(A,f,w)=>{let Q;if(!w&&f&&!/[%+]/.test(f)){let c=A.indexOf("?",8);if(c===-1)return;if(!A.startsWith(f,c+1))c=A.indexOf(`&${f}`,c+1);while(c!==-1){let I=A.charCodeAt(c+f.length+1);if(I===61){let $=c+f.length+2,u=A.indexOf("&",$);return EHA(A.slice($,u===-1?void 0:u))}else if(I==38||isNaN(I))return"";c=A.indexOf(`&${f}`,c+1)}if(Q=/[%+]/.test(A),!Q)return}let B={};Q??=/[%+]/.test(A);let x=A.indexOf("?",8);while(x!==-1){let c=A.indexOf("&",x+1),I=A.indexOf("=",x);if(I>c&&c!==-1)I=-1;let $=A.slice(x+1,I===-1?c===-1?void 0:c:I);if(Q)$=EHA($);if(x=c,$==="")continue;let u;if(I===-1)u="";else if(u=A.slice(I+1,c===-1?void 0:c),Q)u=EHA(u);if(w){if(!(B[$]&&Array.isArray(B[$])))B[$]=[];B[$].push(u)}else B[$]??=u}return f?B[f]:B},_L0=qL0,VL0=(A,f)=>{return qL0(A,f,!0)},VHA=decodeURIComponent;var iL0=(A)=>qp(A,VHA),Ep=class{raw;#A;#f;routeIndex=0;path;bodyCache={};constructor(A,f="/",w=[[]]){this.raw=A,this.path=f,this.#f=w,this.#A={}}param(A){return A?this.#w(A):this.#x()}#w(A){let f=this.#f[0][this.routeIndex][1][A],w=this.#B(f);return w&&/\%/.test(w)?iL0(w):w}#x(){let A={},f=Object.keys(this.#f[0][this.routeIndex][1]);for(let w of f){let Q=this.#B(this.#f[0][this.routeIndex][1][w]);if(Q!==void 0)A[w]=/\%/.test(Q)?iL0(Q):Q}return A}#B(A){return this.#f[1]?this.#f[1][A]:A}query(A){return _L0(this.url,A)}queries(A){return VL0(this.url,A)}header(A){if(A)return this.raw.headers.get(A)??void 0;let f={};return this.raw.headers.forEach((w,Q)=>{f[Q]=w}),f}async parseBody(A){return this.bodyCache.parsedBody??=await NL0(this,A)}#Q=(A)=>{let{bodyCache:f,raw:w}=this,Q=f[A];if(Q)return Q;let B=Object.keys(f)[0];if(B)return f[B].then((x)=>{if(B==="json")x=JSON.stringify(x);return new Response(x)[A]()});return f[A]=w[A]()};json(){return this.#Q("text").then((A)=>JSON.parse(A))}text(){return this.#Q("text")}arrayBuffer(){return this.#Q("arrayBuffer")}blob(){return this.#Q("blob")}formData(){return this.#Q("formData")}addValidatedData(A,f){this.#A[A]=f}valid(A){return this.#A[A]}get url(){return this.raw.url}get method(){return this.raw.method}get[zL0](){return this.#f}get matchedRoutes(){return this.#f[0].map(([[,A]])=>A)}get routePath(){return this.#f[0].map(([[,A]])=>A)[this.routeIndex].path}};var ML0={Stringify:1,BeforeStream:2,Stream:3},OL0=(A,f)=>{let w=new String(A);return w.isEscaped=!0,w.callbacks=f,w};var iHA=async(A,f,w,Q,B)=>{if(typeof A==="object"&&!(A instanceof String)){if(!(A instanceof Promise))A=A.toString();if(A instanceof Promise)A=await A}let x=A.callbacks;if(!x?.length)return Promise.resolve(A);if(B)B[0]+=A;else B=[A];let c=Promise.all(x.map((I)=>I({phase:f,buffer:B,context:Q}))).then((I)=>Promise.all(I.filter(Boolean).map(($)=>iHA($,f,!1,Q,B))).then(()=>B[0]));if(w)return OL0(await c,x);else return c};var iF2="text/plain; charset=UTF-8",MHA=(A,f)=>{return{"Content-Type":A,...f}},nV=(A,f)=>new Response(A,f),jL0=class{#A;#f;env={};#w;finalized=!1;error;#x;#B;#Q;#D;#$;#u;#I;#Y;#H;constructor(A,f){if(this.#A=A,f)this.#B=f.executionCtx,this.env=f.env,this.#u=f.notFoundHandler,this.#H=f.path,this.#Y=f.matchResult}get req(){return this.#f??=new Ep(this.#A,this.#H,this.#Y),this.#f}get event(){if(this.#B&&"respondWith"in this.#B)return this.#B;else throw Error("This context has no FetchEvent")}get executionCtx(){if(this.#B)return this.#B;else throw Error("This context has no ExecutionContext")}get res(){return this.#Q||=nV(null,{headers:this.#I??=new Headers})}set res(A){if(this.#Q&&A){A=nV(A.body,A);for(let[f,w]of this.#Q.headers.entries()){if(f==="content-type")continue;if(f==="set-cookie"){let Q=this.#Q.headers.getSetCookie();A.headers.delete("set-cookie");for(let B of Q)A.headers.append("set-cookie",B)}else A.headers.set(f,w)}}this.#Q=A,this.finalized=!0}render=(...A)=>{return this.#$??=(f)=>this.html(f),this.#$(...A)};setLayout=(A)=>this.#D=A;getLayout=()=>this.#D;setRenderer=(A)=>{this.#$=A};header=(A,f,w)=>{if(this.finalized)this.#Q=nV(this.#Q.body,this.#Q);let Q=this.#Q?this.#Q.headers:this.#I??=new Headers;if(f===void 0)Q.delete(A);else if(w?.append)Q.append(A,f);else Q.set(A,f)};status=(A)=>{this.#x=A};set=(A,f)=>{this.#w??=new Map,this.#w.set(A,f)};get=(A)=>{return this.#w?this.#w.get(A):void 0};get var(){if(!this.#w)return{};return Object.fromEntries(this.#w)}#c(A,f,w){let Q=this.#Q?new Headers(this.#Q.headers):this.#I??new Headers;if(typeof f==="object"&&"headers"in f){let x=f.headers instanceof Headers?f.headers:new Headers(f.headers);for(let[c,I]of x)if(c.toLowerCase()==="set-cookie")Q.append(c,I);else Q.set(c,I)}if(w)for(let[x,c]of Object.entries(w))if(typeof c==="string")Q.set(x,c);else{Q.delete(x);for(let I of c)Q.append(x,I)}let B=typeof f==="number"?f:f?.status??this.#x;return nV(A,{status:B,headers:Q})}newResponse=(...A)=>this.#c(...A);body=(A,f,w)=>this.#c(A,f,w);text=(A,f,w)=>{return!this.#I&&!this.#x&&!f&&!w&&!this.finalized?new Response(A):this.#c(A,f,MHA(iF2,w))};json=(A,f,w)=>{return this.#c(JSON.stringify(A),f,MHA("application/json",w))};html=(A,f,w)=>{let Q=(B)=>this.#c(B,f,MHA("text/html; charset=UTF-8",w));return typeof A==="object"?iHA(A,ML0.Stringify,!1,{}).then(Q):Q(A)};redirect=(A,f)=>{let w=String(A);return this.header("Location",!/[^\x00-\xFF]/.test(w)?w:encodeURI(w)),this.newResponse(null,f??302)};notFound=()=>{return this.#u??=()=>nV(),this.#u(this)}};var aw="ALL",gL0="all",PL0=["get","post","put","delete","options","patch"],Vp="Can not add a route since the matcher is already built.",ip=class extends Error{};var OHA="__COMPOSED_HANDLER";var MF2=(A)=>{return A.text("404 Not Found",404)},RL0=(A,f)=>{if("getResponse"in A){let w=A.getResponse();return f.newResponse(w.body,w)}return console.error(A),f.text("Internal Server Error",500)},nL0=class A{get;post;put;delete;options;patch;all;on;use;router;getPath;_basePath="/";#A="/";routes=[];constructor(f={}){[...PL0,gL0].forEach((x)=>{this[x]=(c,...I)=>{if(typeof c==="string")this.#A=c;else this.#x(x,this.#A,c);return I.forEach(($)=>{this.#x(x,this.#A,$)}),this}}),this.on=(x,c,...I)=>{for(let $ of[c].flat()){this.#A=$;for(let u of[x].flat())I.map((Y)=>{this.#x(u.toUpperCase(),this.#A,Y)})}return this},this.use=(x,...c)=>{if(typeof x==="string")this.#A=x;else this.#A="*",c.unshift(x);return c.forEach((I)=>{this.#x(aw,this.#A,I)}),this};let{strict:Q,...B}=f;Object.assign(this,B),this.getPath=Q??!0?f.getPath??_HA:LL0}#f(){let f=new A({router:this.router,getPath:this.getPath});return f.errorHandler=this.errorHandler,f.#w=this.#w,f.routes=this.routes,f}#w=MF2;errorHandler=RL0;route(f,w){let Q=this.basePath(f);return w.routes.map((B)=>{let x;if(w.errorHandler===RL0)x=B.handler;else x=async(c,I)=>(await CHA([],w.errorHandler)(c,()=>B.handler(c,I))).res,x[OHA]=B.handler;Q.#x(B.method,B.path,x)}),this}basePath(f){let w=this.#f();return w._basePath=PZ(this._basePath,f),w}onError=(f)=>{return this.errorHandler=f,this};notFound=(f)=>{return this.#w=f,this};mount(f,w,Q){let B,x;if(Q)if(typeof Q==="function")x=Q;else if(x=Q.optionHandler,Q.replaceRequest===!1)B=($)=>$;else B=Q.replaceRequest;let c=x?($)=>{let u=x($);return Array.isArray(u)?u:[u]}:($)=>{let u=void 0;try{u=$.executionCtx}catch{}return[$.env,u]};B||=(()=>{let $=PZ(this._basePath,f),u=$==="/"?0:$.length;return(Y)=>{let F=new URL(Y.url);return F.pathname=F.pathname.slice(u)||"/",new Request(F,Y)}})();let I=async($,u)=>{let Y=await w(B($.req.raw),...c($));if(Y)return Y;await u()};return this.#x(aw,PZ(f,"*"),I),this}#x(f,w,Q){f=f.toUpperCase(),w=PZ(this._basePath,w);let B={basePath:this._basePath,path:w,method:f,handler:Q};this.router.add(f,w,[Q,B]),this.routes.push(B)}#B(f,w){if(f instanceof Error)return this.errorHandler(f,w);throw f}#Q(f,w,Q,B){if(B==="HEAD")return(async()=>new Response(null,await this.#Q(f,w,Q,"GET")))();let x=this.getPath(f,{env:Q}),c=this.router.match(B,x),I=new jL0(f,{path:x,matchResult:c,env:Q,executionCtx:w,notFoundHandler:this.#w});if(c[0].length===1){let u;try{u=c[0][0][0][0](I,async()=>{I.res=await this.#w(I)})}catch(Y){return this.#B(Y,I)}return u instanceof Promise?u.then((Y)=>Y||(I.finalized?I.res:this.#w(I))).catch((Y)=>this.#B(Y,I)):u??this.#w(I)}let $=CHA(c[0],this.errorHandler,this.#w);return(async()=>{try{let u=await $(I);if(!u.finalized)throw Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");return u.res}catch(u){return this.#B(u,I)}})()}fetch=(f,...w)=>{return this.#Q(f,w[1],w[0],f.method)};request=(f,w,Q,B)=>{if(f instanceof Request)return this.fetch(w?new Request(f,w):f,Q,B);return f=f.toString(),this.fetch(new Request(/^https?:\/\//.test(f)?f:`http://localhost${PZ("/",f)}`,w),Q,B)};fire=()=>{addEventListener("fetch",(f)=>{f.respondWith(this.#Q(f.request,f,void 0,f.request.method))})}};var mV=[];function Mp(A,f){let w=this.buildAllMatchers(),Q=(B,x)=>{let c=w[B]||w[aw],I=c[2][x];if(I)return I;let $=x.match(c[0]);if(!$)return[[],mV];let u=$.indexOf("",1);return[c[1][u],$]};return this.match=Q,Q(A,f)}var Op="[^/]+",lV=".*",TV="(?:|/.*)",RZ=Symbol(),OF2=new Set(".\\+*[^]$()");function jF2(A,f){if(A.length===1)return f.length===1?A<f?-1:1:-1;if(f.length===1)return 1;if(A===lV||A===TV)return 1;else if(f===lV||f===TV)return-1;if(A===Op)return 1;else if(f===Op)return-1;return A.length===f.length?A<f?-1:1:f.length-A.length}var mL0=class A{#A;#f;#w=Object.create(null);insert(f,w,Q,B,x){if(f.length===0){if(this.#A!==void 0)throw RZ;if(x)return;this.#A=w;return}let[c,...I]=f,$=c==="*"?I.length===0?["","",lV]:["","",Op]:c==="/*"?["","",TV]:c.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/),u;if($){let Y=$[1],F=$[2]||Op;if(Y&&$[2]){if(F===".*")throw RZ;if(F=F.replace(/^\((?!\?:)(?=[^)]+\)$)/,"(?:"),/\((?!\?:)/.test(F))throw RZ}if(u=this.#w[F],!u){if(Object.keys(this.#w).some((K)=>K!==lV&&K!==TV))throw RZ;if(x)return;if(u=this.#w[F]=new A,Y!=="")u.#f=B.varIndex++}if(!x&&Y!=="")Q.push([Y,u.#f])}else if(u=this.#w[c],!u){if(Object.keys(this.#w).some((Y)=>Y.length>1&&Y!==lV&&Y!==TV))throw RZ;if(x)return;u=this.#w[c]=new A}u.insert(I,w,Q,B,x)}buildRegExpStr(){let w=Object.keys(this.#w).sort(jF2).map((Q)=>{let B=this.#w[Q];return(typeof B.#f==="number"?`(${Q})@${B.#f}`:OF2.has(Q)?`\\${Q}`:Q)+B.buildRegExpStr()});if(typeof this.#A==="number")w.unshift(`#${this.#A}`);if(w.length===0)return"";if(w.length===1)return w[0];return"(?:"+w.join("|")+")"}};var lL0=class{#A={varIndex:0};#f=new mL0;insert(A,f,w){let Q=[],B=[];for(let c=0;;){let I=!1;if(A=A.replace(/\{[^}]+\}/g,($)=>{let u=`@\\${c}`;return B[c]=[u,$],c++,I=!0,u}),!I)break}let x=A.match(/(?::[^\/]+)|(?:\/\*$)|./g)||[];for(let c=B.length-1;c>=0;c--){let[I]=B[c];for(let $=x.length-1;$>=0;$--)if(x[$].indexOf(I)!==-1){x[$]=x[$].replace(I,B[c][1]);break}}return this.#f.insert(x,f,Q,this.#A,w),Q}buildRegExp(){let A=this.#f.buildRegExpStr();if(A==="")return[/^$/,[],[]];let f=0,w=[],Q=[];return A=A.replace(/#(\d+)|@(\d+)|\.\*\$/g,(B,x,c)=>{if(x!==void 0)return w[++f]=Number(x),"$()";if(c!==void 0)return Q[Number(c)]=++f,"";return""}),[new RegExp(`^${A}`),w,Q]}};var gF2=[/^$/,[],Object.create(null)],TL0=Object.create(null);function yL0(A){return TL0[A]??=new RegExp(A==="*"?"":`^${A.replace(/\/\*$|([.\\+*[^\]$()])/g,(f,w)=>w?`\\${w}`:"(?:|/.*)")}$`)}function PF2(){TL0=Object.create(null)}function RF2(A){let f=new lL0,w=[];if(A.length===0)return gF2;let Q=A.map((u)=>[!/\*|\/:/.test(u[0]),...u]).sort(([u,Y],[F,K])=>u?1:F?-1:Y.length-K.length),B=Object.create(null);for(let u=0,Y=-1,F=Q.length;u<F;u++){let[K,Z,k]=Q[u];if(K)B[Z]=[k.map(([G])=>[G,Object.create(null)]),mV];else Y++;let h;try{h=f.insert(Z,Y,K)}catch(G){throw G===RZ?new ip(Z):G}if(K)continue;w[Y]=k.map(([G,E])=>{let V=Object.create(null);E-=1;for(;E>=0;E--){let[q,y]=h[E];V[q]=y}return[G,V]})}let[x,c,I]=f.buildRegExp();for(let u=0,Y=w.length;u<Y;u++)for(let F=0,K=w[u].length;F<K;F++){let Z=w[u][F]?.[1];if(!Z)continue;let k=Object.keys(Z);for(let h=0,G=k.length;h<G;h++)Z[k[h]]=I[Z[k[h]]]}let $=[];for(let u in c)$[u]=w[c[u]];return[x,$,B]}function nJ(A,f){if(!A)return;for(let w of Object.keys(A).sort((Q,B)=>B.length-Q.length))if(yL0(w).test(f))return[...A[w]];return}var jp=class{name="RegExpRouter";#A;#f;constructor(){this.#A={[aw]:Object.create(null)},this.#f={[aw]:Object.create(null)}}add(A,f,w){let Q=this.#A,B=this.#f;if(!Q||!B)throw Error(Vp);if(!Q[A])[Q,B].forEach((I)=>{I[A]=Object.create(null),Object.keys(I[aw]).forEach(($)=>{I[A][$]=[...I[aw][$]]})});if(f==="/*")f="*";let x=(f.match(/\/:/g)||[]).length;if(/\*$/.test(f)){let I=yL0(f);if(A===aw)Object.keys(Q).forEach(($)=>{Q[$][f]||=nJ(Q[$],f)||nJ(Q[aw],f)||[]});else Q[A][f]||=nJ(Q[A],f)||nJ(Q[aw],f)||[];Object.keys(Q).forEach(($)=>{if(A===aw||A===$)Object.keys(Q[$]).forEach((u)=>{I.test(u)&&Q[$][u].push([w,x])})}),Object.keys(B).forEach(($)=>{if(A===aw||A===$)Object.keys(B[$]).forEach((u)=>I.test(u)&&B[$][u].push([w,x]))});return}let c=_p(f)||[f];for(let I=0,$=c.length;I<$;I++){let u=c[I];Object.keys(B).forEach((Y)=>{if(A===aw||A===Y)B[Y][u]||=[...nJ(Q[Y],u)||nJ(Q[aw],u)||[]],B[Y][u].push([w,x-$+I+1])})}}match=Mp;buildAllMatchers(){let A=Object.create(null);return Object.keys(this.#f).concat(Object.keys(this.#A)).forEach((f)=>{A[f]||=this.#w(f)}),this.#A=this.#f=void 0,PF2(),A}#w(A){let f=[],w=A===aw;if([this.#A,this.#f].forEach((Q)=>{let B=Q[A]?Object.keys(Q[A]).map((x)=>[x,Q[A][x]]):[];if(B.length!==0)w||=!0,f.push(...B);else if(A!==aw)f.push(...Object.keys(Q[aw]).map((x)=>[x,Q[aw][x]]))}),!w)return null;else return RF2(f)}};var nF2=class{name="PreparedRegExpRouter";#A;#f;constructor(A,f){this.#A=A,this.#f=f}#w(A,f){let w=this.#A[A];w[1].forEach((Q)=>Q&&Q.push(f)),Object.values(w[2]).forEach((Q)=>Q[0].push(f))}#x(A,f,w,Q,B){let x=this.#A[A];if(!B)x[2][f][0].push([w,{}]);else Q.forEach((c)=>{if(typeof c==="number")x[1][c].push([w,B]);else x[2][c||f][0].push([w,B])})}add(A,f,w){if(!this.#A[A]){let B=this.#A[aw],x={};for(let c in B[2])x[c]=[B[2][c][0].slice(),mV];this.#A[A]=[B[0],B[1].map((c)=>Array.isArray(c)?c.slice():0),x]}if(f==="/*"||f==="*"){let B=[w,{}];if(A===aw)for(let x in this.#A)this.#w(x,B);else this.#w(A,B);return}let Q=this.#f[f];if(!Q)throw Error(`Path ${f} is not registered`);for(let[B,x]of Q)if(A===aw)for(let c in this.#A)this.#x(c,f,w,B,x);else this.#x(A,f,w,B,x)}buildAllMatchers(){return this.#A}match=Mp};var jHA=class{name="SmartRouter";#A=[];#f=[];constructor(A){this.#A=A.routers}add(A,f,w){if(!this.#f)throw Error(Vp);this.#f.push([A,f,w])}match(A,f){if(!this.#f)throw Error("Fatal error");let w=this.#A,Q=this.#f,B=w.length,x=0,c;for(;x<B;x++){let I=w[x];try{for(let $=0,u=Q.length;$<u;$++)I.add(...Q[$]);c=I.match(A,f)}catch($){if($ instanceof ip)continue;throw $}this.match=I.match.bind(I),this.#A=[I],this.#f=void 0;break}if(x===B)throw Error("Fatal error");return this.name=`SmartRouter + ${this.activeRouter.name}`,c}get activeRouter(){if(this.#f||this.#A.length!==1)throw Error("No active router has been determined yet.");return this.#A[0]}};var yV=Object.create(null),mF2=(A)=>{for(let f in A)return!0;return!1},SL0=class A{#A;#f;#w;#x=0;#B=yV;constructor(f,w,Q){if(this.#f=Q||Object.create(null),this.#A=[],f&&w){let B=Object.create(null);B[f]={handler:w,possibleKeys:[],score:0},this.#A=[B]}this.#w=[]}insert(f,w,Q){this.#x=++this.#x;let B=this,x=CL0(w),c=[];for(let I=0,$=x.length;I<$;I++){let u=x[I],Y=x[I+1],F=EL0(u,Y),K=Array.isArray(F)?F[0]:u;if(K in B.#f){if(B=B.#f[K],F)c.push(F[1]);continue}if(B.#f[K]=new A,F)B.#w.push(F),c.push(F[1]);B=B.#f[K]}return B.#A.push({[f]:{handler:Q,possibleKeys:c.filter((I,$,u)=>u.indexOf(I)===$),score:this.#x}}),B}#Q(f,w,Q,B,x){for(let c=0,I=w.#A.length;c<I;c++){let $=w.#A[c],u=$[Q]||$[aw],Y={};if(u!==void 0){if(u.params=Object.create(null),f.push(u),B!==yV||x&&x!==yV)for(let F=0,K=u.possibleKeys.length;F<K;F++){let Z=u.possibleKeys[F],k=Y[u.score];u.params[Z]=x?.[Z]&&!k?x[Z]:B[Z]??x?.[Z],Y[u.score]=!0}}}}search(f,w){let Q=[];this.#B=yV;let x=[this],c=LHA(w),I=[],$=c.length,u=null;for(let Y=0;Y<$;Y++){let F=c[Y],K=Y===$-1,Z=[];for(let h=0,G=x.length;h<G;h++){let E=x[h],V=E.#f[F];if(V)if(V.#B=E.#B,K){if(V.#f["*"])this.#Q(Q,V.#f["*"],f,E.#B);this.#Q(Q,V,f,E.#B)}else Z.push(V);for(let q=0,y=E.#w.length;q<y;q++){let r=E.#w[q],g=E.#B===yV?{}:{...E.#B};if(r==="*"){let l=E.#f["*"];if(l)this.#Q(Q,l,f,E.#B),l.#B=g,Z.push(l);continue}let[M,j,P]=r;if(!F&&!(P instanceof RegExp))continue;let t=E.#f[M];if(P instanceof RegExp){if(u===null){u=Array($);let cA=w[0]==="/"?1:0;for(let _=0;_<$;_++)u[_]=cA,cA+=c[_].length+1}let l=w.substring(u[Y]),DA=P.exec(l);if(DA){if(g[j]=DA[0],this.#Q(Q,t,f,E.#B,g),mF2(t.#f)){t.#B=g;let cA=DA[0].match(/\//)?.length??0;(I[cA]||=[]).push(t)}continue}}if(P===!0||P.test(F))if(g[j]=F,K){if(this.#Q(Q,t,f,g,E.#B),t.#f["*"])this.#Q(Q,t.#f["*"],f,g,E.#B)}else t.#B=g,Z.push(t)}}let k=I.shift();x=k?Z.concat(k):Z}if(Q.length>1)Q.sort((Y,F)=>{return Y.score-F.score});return[Q.map(({handler:Y,params:F})=>[Y,F])]}};var gHA=class{name="TrieRouter";#A;constructor(){this.#A=new SL0}add(A,f,w){let Q=_p(f);if(Q){for(let B=0,x=Q.length;B<x;B++)this.#A.insert(A,Q[B],w);return}this.#A.insert(A,f,w)}match(A,f){return this.#A.search(A,f)}};var nZ=class extends nL0{constructor(A={}){super(A);this.router=A.router??new jHA({routers:[new jp,new gHA]})}};import{stat as pF2}from"fs/promises";import{join as rF2}from"path";var mJ=/^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;var PHA=(A,f=TF2)=>{let w=/\.([a-zA-Z0-9]+?)$/,Q=A.match(w);if(!Q)return;let B=f[Q[1]];if(B&&B.startsWith("text"))B+="; charset=utf-8";return B};var lF2={aac:"audio/aac",avi:"video/x-msvideo",avif:"image/avif",av1:"video/av1",bin:"application/octet-stream",bmp:"image/bmp",css:"text/css",csv:"text/csv",eot:"application/vnd.ms-fontobject",epub:"application/epub+zip",gif:"image/gif",gz:"application/gzip",htm:"text/html",html:"text/html",ico:"image/x-icon",ics:"text/calendar",jpeg:"image/jpeg",jpg:"image/jpeg",js:"text/javascript",json:"application/json",jsonld:"application/ld+json",map:"application/json",mid:"audio/x-midi",midi:"audio/x-midi",mjs:"text/javascript",mp3:"audio/mpeg",mp4:"video/mp4",mpeg:"video/mpeg",oga:"audio/ogg",ogv:"video/ogg",ogx:"application/ogg",opus:"audio/opus",otf:"font/otf",pdf:"application/pdf",png:"image/png",rtf:"application/rtf",svg:"image/svg+xml",tif:"image/tiff",tiff:"image/tiff",ts:"video/mp2t",ttf:"font/ttf",txt:"text/plain",wasm:"application/wasm",webm:"video/webm",weba:"audio/webm",webmanifest:"application/manifest+json",webp:"image/webp",woff:"font/woff",woff2:"font/woff2",xhtml:"application/xhtml+xml",xml:"application/xml",zip:"application/zip","3gp":"video/3gpp","3g2":"video/3gpp2",gltf:"model/gltf+json",glb:"model/gltf-binary"},TF2=lF2;var pL0=(...A)=>{let f=A.filter((B)=>B!=="").join("/");f=f.replace(/(?<=\/)\/+/g,"");let w=f.split("/"),Q=[];for(let B of w)if(B===".."&&Q.length>0&&Q.at(-1)!=="..")Q.pop();else if(B!==".")Q.push(B);return Q.join("/")||"."};var rL0={br:".br",zstd:".zst",gzip:".gz"},yF2=Object.keys(rL0),SF2="index.html",dL0=(A)=>{let f=A.root??"./",w=A.path,Q=A.join??pL0;return async(B,x)=>{if(B.finalized)return x();let c;if(A.path)c=A.path;else try{if(c=qHA(B.req.path),/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(c))throw Error()}catch{return await A.onNotFound?.(B.req.path,B),x()}let I=Q(f,!w&&A.rewriteRequestPath?A.rewriteRequestPath(c):c);if(A.isDir&&await A.isDir(I))I=Q(I,SF2);let $=A.getContent,u=await $(I,B);if(u instanceof Response)return B.newResponse(u.body,u);if(u){let Y=A.mimes&&PHA(I,A.mimes)||PHA(I);if(B.header("Content-Type",Y||"application/octet-stream"),A.precompressed&&(!Y||mJ.test(Y))){let F=new Set(B.req.header("Accept-Encoding")?.split(",").map((K)=>K.trim()));for(let K of yF2){if(!F.has(K))continue;let Z=await $(I+rL0[K],B);if(Z){u=Z,B.header("Content-Encoding",K),B.header("Vary","Accept-Encoding",{append:!0});break}}}return await A.onFound?.(I,B),B.body(u)}await A.onNotFound?.(I,B),await x();return}};var RHA=(A)=>{return async function(w,Q){return dL0({...A,getContent:async(c)=>{let I=Bun.file(c);return await I.exists()?I:null},join:rF2,isDir:async(c)=>{let I;try{I=(await pF2(c)).isDirectory()}catch{}return I}})(w,Q)}};var nHA="x-hono-disable-ssg",R8w=(()=>{try{return new Response("SSG is disabled",{status:404,headers:{[nHA]:"true"}})}catch{return null}})();var{write:kBw}=Bun;var aF2=class{#A;constructor(A){this.#A=A,this.raw=A.raw,this.url=A.url?new URL(A.url):null,this.protocol=A.protocol??null}send(A,f){this.#A.send(A,f??{})}raw;binaryType="arraybuffer";get readyState(){return this.#A.readyState}url;protocol;close(A,f){this.#A.close(A,f)}};var oL0=(A)=>{return(...f)=>{if(typeof f[0]==="function"){let[w,Q]=f;return async function(x,c){let I=await w(x),$=await A(x,I,Q);if($)return $;await c()}}else{let[w,Q,B]=f;return(async()=>{let x=await A(w,Q,B);if(!x)throw Error("Failed to upgrade WebSocket");return x})()}}};var gp=(A)=>("server"in A.env)?A.env.server:A.env;var sF2=oL0((A,f)=>{let w=gp(A);if(!w)throw TypeError("env has to include the 2nd argument of fetch.");if(w.upgrade(A.req.raw,{data:{events:f,url:new URL(A.req.url),protocol:A.req.url}}))return new Response(null);return});var tF2=["gzip","deflate"],eF2=/(?:^|,)\s*?no-transform\s*?(?:,|$)/i,aL0=(A)=>{let f=A?.threshold??1024;return async function(Q,B){await B();let x=Q.res.headers.get("Content-Length");if(Q.res.headers.has("Content-Encoding")||Q.res.headers.has("Transfer-Encoding")||Q.req.method==="HEAD"||x&&Number(x)<f||!AK2(Q.res)||!fK2(Q.res))return;let c=Q.req.header("Accept-Encoding"),I=A?.encoding??tF2.find((u)=>c?.includes(u));if(!I||!Q.res.body)return;let $=new CompressionStream(I);Q.res=new Response(Q.res.body.pipeThrough($),Q.res),Q.res.headers.delete("Content-Length"),Q.res.headers.set("Content-Encoding",I)}},AK2=(A)=>{let f=A.headers.get("Content-Type");return f&&mJ.test(f)},fK2=(A)=>{let f=A.headers.get("Cache-Control");return!f||!eF2.test(f)};import{Readable as sL0}from"stream";import{createDeflate as wK2,createGzip as QK2}from"zlib";var BK2=["gzip","deflate"],xK2=/(?:^|,)\s*?no-transform\s*?(?:,|$)/i,tL0=(A)=>{if(typeof CompressionStream<"u")return aL0(A);let f=A?.threshold??1024;return async function(Q,B){await B();let x=Q.res.headers.get("Content-Length");if(Q.res.headers.has("Content-Encoding")||Q.res.headers.has("Transfer-Encoding")||Q.req.method==="HEAD"||x&&Number(x)<f||!cK2(Q.res)||!IK2(Q.res))return;let c=Q.req.header("Accept-Encoding"),I=A?.encoding??BK2.find(($)=>c?.includes($));if(!I||!Q.res.body)return;try{let $=I==="gzip"?QK2():wK2(),u=Q.res.body,F=sL0.fromWeb(u).pipe($),K=sL0.toWeb(F);Q.res=new Response(K,Q.res),Q.res.headers.delete("Content-Length"),Q.res.headers.set("Content-Encoding",I)}catch($){console.error("Compression error:",$)}}},cK2=(A)=>{let f=A.headers.get("Content-Type");return f&&mJ.test(f)},IK2=(A)=>{let f=A.headers.get("Cache-Control");return!f||!xK2.test(f)};var $K2=(A,f)=>{if(!A)return f;let w=new Uint8Array(new ArrayBuffer(A.byteLength+f.byteLength));return w.set(new Uint8Array(A),0),w.set(f,A.byteLength),w},eL0=async(A,f)=>{if(!A)return null;let w=void 0,Q=A.getReader();for(;;){let{value:B,done:x}=await Q.read();if(x)break;w=await f($K2(w,B))}if(!w)return null;return Array.prototype.map.call(new Uint8Array(w),(B)=>B.toString(16).padStart(2,"0")).join("")};var uK2=["cache-control","content-location","date","etag","expires","vary"],Aq0=(A)=>A.replace(/^W\//,"");function DK2(A,f){return f!=null&&f.split(/,\s*/).some((w)=>Aq0(w)===Aq0(A))}function YK2(A){if(!A){if(crypto&&crypto.subtle)A=(f)=>crypto.subtle.digest({name:"SHA-1"},f)}return A}var fq0=(A)=>{let f=A?.retainedHeaders??uK2,w=A?.weak??!1,Q=YK2(A?.generateDigest);return async function(x,c){let I=x.req.header("If-None-Match")??null;await c();let $=x.res,u=$.headers.get("ETag");if(!u){if(!Q)return;let Y=await eL0($.clone().body,Q);if(Y===null)return;u=w?`W/"${Y}"`:`"${Y}"`}if(DK2(u,I))x.res=new Response(null,{status:304,statusText:"Not Modified",headers:{ETag:u}}),x.res.headers.forEach((Y,F)=>{if(f.indexOf(F.toLowerCase())===-1)x.res.headers.delete(F)});else x.res.headers.set("ETag",u)}};B0();function mHA(A,f){return async(w)=>{let Q=w.req.raw,B=Q.headers.get("content-type")??"",x=Q.headers.get("accept")?.includes("application/json"),c={};if(B.includes("application/json"))c=await Q.json();else if(B.includes("form")){let Z=await Q.formData();for(let[k,h]of Z.entries())c[k]=h}let I=`${A.pluginId}_${A.definition.tool}`,$=await f.send(`plugin:${A.pluginId}:tool:execute`,{toolName:I,args:c,interfaceType:"webserver",userId:"anonymous"},"webserver"),u=typeof $==="object"&&"data"in $?$.data:$,Y=YC.safeParse(u),F=Y.success?Y.data:u,K=Y.success&&Y.data.success===!0;if(x)return w.json(F,K?200:400);if(K&&A.definition.successRedirect)return w.redirect(A.definition.successRedirect);if(!K&&A.definition.errorRedirect)return w.redirect(A.definition.errorRedirect);return w.json(F,K?200:400)}}class Pp{server=null;logger;port;routes;messageBus;constructor(A){this.logger=A.logger,this.port=A.port,this.routes=A.routes,this.messageBus=A.messageBus}async start(){if(this.server)return this.logger.warn("API server already running"),`http://localhost:${this.port}`;if(this.routes.length===0)return this.logger.debug("No API routes registered, skipping API server"),"";let A=new nZ;for(let w of this.routes){let Q=mHA(w,this.messageBus),B=w.definition.method.toLowerCase();A[B](w.fullPath,Q),this.logger.debug(`Mounted API route: ${w.definition.method} ${w.fullPath} -> ${w.pluginId}_${w.definition.tool}`)}this.server=Bun.serve({port:this.port,fetch:A.fetch});let f=`http://localhost:${this.port}`;return this.logger.info(`API server started at ${f} (${this.routes.length} routes)`),f}async stop(){if(!this.server)return;await this.server.stop(),this.server=null,this.logger.debug("API server stopped")}}var wq0="public, max-age=31536000, immutable";class Rp{logger;options;productionServer=null;previewServer=null;constructor(A){this.logger=A.logger,this.options={...A,productionDistDir:lJ(process.cwd(),A.productionDistDir),sharedImagesDir:lJ(process.cwd(),A.sharedImagesDir),...A.previewDistDir&&{previewDistDir:lJ(process.cwd(),A.previewDistDir)}}}async start(){if(this.productionServer){this.logger.warn("Webserver already running");return}let A=this.createApp({distDir:this.options.productionDistDir,compress:!0,defaultCache:"public, max-age=3600",immutableExtensions:/\.(js|css|jpg|jpeg|png|gif|ico|woff|woff2)$/,healthEndpoint:!0});try{this.productionServer=Bun.serve({port:this.options.productionPort,fetch:async(f)=>{let w=await this.serveImageFastPath(f);if(w)return w;return A.fetch(f)}})}catch(f){let w=String(f);if(w.includes("EADDRINUSE")||w.includes("address already in use"))throw Error(`Port ${this.options.productionPort} is already in use. Another brain may be running \u2014 stop it first or configure a different port.`);throw f}if(this.logger.info(`Production server listening on http://localhost:${this.productionServer.port}`),this.options.previewDistDir){let f=this.createApp({distDir:this.options.previewDistDir,compress:!1,defaultCache:"no-cache",immutableExtensions:/\.(jpg|jpeg|png|gif|ico|webp|svg|woff|woff2)$/,healthEndpoint:!1});this.previewServer=Bun.serve({port:this.options.previewPort??4321,fetch:async(w)=>{let Q=await this.serveImageFastPath(w);if(Q)return Q;return f.fetch(w)}}),this.logger.info(`Preview server listening on http://localhost:${this.previewServer.port}`)}}async stop(){if(this.productionServer)await this.productionServer.stop(),this.productionServer=null;if(this.previewServer)await this.previewServer.stop(),this.previewServer=null;this.logger.debug("Webserver stopped")}getStatus(){return{running:this.productionServer!==null,productionUrl:this.productionServer?`http://localhost:${this.productionServer.port}`:void 0,previewUrl:this.previewServer?`http://localhost:${this.previewServer.port}`:void 0}}createApp(A){let f=new nZ;if(A.healthEndpoint)f.get("/health",async(w)=>{if(this.options.getHealthData){let Q=await this.options.getHealthData();return w.json({status:"healthy",...Q},200)}return w.json({status:"healthy"},200)});if(A.compress)f.use("/*",tL0());return f.use("/*",fq0()),f.use("/*",async(w,Q)=>{if(await Q(),A.immutableExtensions.test(w.req.path))w.header("Cache-Control",wq0);else w.header("Cache-Control",A.defaultCache)}),f.use("/*",this.createCleanUrlMiddleware(A.distDir)),f.use("/*",RHA({root:A.distDir})),f.notFound(async(w)=>{let Q=Bun.file(HK2(A.distDir,"404.html"));if(await Q.exists())return w.html(await Q.text(),404);return w.text("Not Found",404)}),f}async serveImageFastPath(A){let f;try{f=new URL(A.url)}catch{return null}if(!f.pathname.startsWith("/images/"))return null;let w=f.pathname.slice(8),Q=lJ(this.options.sharedImagesDir,w);if(!Q.startsWith(this.options.sharedImagesDir))return null;let B=Bun.file(Q);if(!await B.exists())return null;return new Response(B,{headers:{"Cache-Control":wq0}})}createCleanUrlMiddleware(A){return async(f,w)=>{let Q=f.req.path;if(Q.includes(".")||Q==="/"){await w();return}let B=lJ(A,`.${Q}`,"index.html");if(!B.startsWith(A)){await w();return}let x=Bun.file(B);if(await x.exists())return f.html(await x.text());let c=lJ(A,`.${Q}.html`);if(c.startsWith(A)){let I=Bun.file(c);if(await I.exists())return f.html(await I.text())}await w()}}}import{existsSync as Bq0}from"fs";import{join as xq0}from"path";YA();var lHA=X.object({previewDistDir:X.string().default("./dist/site-preview").describe("Directory for preview site files"),productionDistDir:X.string().describe("Directory for production site files").default("./dist/site-production"),sharedImagesDir:X.string().default("./dist/images").describe("Shared directory for optimized images"),previewPort:X.number().default(4321).describe("Port for preview server"),productionPort:X.number().describe("Port for production server").default(8080),apiPort:X.number().describe("Port for API route server (plugin HTTP endpoints)").default(3335)});var THA=`<!DOCTYPE html>
1854
1854
  <html lang="en">
@@ -1917,7 +1917,7 @@ ${A.entityContent}`,wq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt
1917
1917
  <p>Once built, this page will be replaced with your actual website.</p>
1918
1918
  </div>
1919
1919
  </body>
1920
- </html>`;var Qq0={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.8",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts"},dependencies:{"@brains/plugins":"workspace:*","@hono/bun-compress":"^0.1.0",hono:"^4.7.10"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};class RU extends _${serverManager;apiServer;siteUrl;previewUrl;constructor(A={}){super("webserver",Qq0,A,lHA)}async onRegister(A){this.siteUrl=A.siteUrl,this.previewUrl=A.previewUrl,this.serverManager=new Rp({logger:A.logger,productionDistDir:this.config.productionDistDir,sharedImagesDir:this.config.sharedImagesDir,productionPort:this.config.productionPort,...this.config.previewDistDir&&{previewDistDir:this.config.previewDistDir},...this.config.previewPort&&{previewPort:this.config.previewPort},getHealthData:()=>A.appInfo()});let f=A.apiRoutes.getRoutes();if(f.length>0){let w=A.apiRoutes.getMessageBus();this.apiServer=new Pp({logger:A.logger,port:this.config.apiPort,routes:f,messageBus:w}),A.logger.info(`Configured ${f.length} API routes on port ${this.config.apiPort}`)}}getServerManager(){if(!this.serverManager)throw Error("ServerManager not initialized \u2014 onRegister not called");return this.serverManager}createDaemon(){return{start:async()=>{if(await this.ensureDistDirectories(),await this.getServerManager().start(),this.apiServer)await this.apiServer.start()},stop:async()=>{await this.serverManager?.stop(),await this.apiServer?.stop()},healthCheck:async()=>{let A=this.serverManager?.getStatus(),f=A?.running??!1,w=this.siteUrl??A?.productionUrl??`http://localhost:${this.config.productionPort}`,Q=this.previewUrl??A?.previewUrl??`http://localhost:${this.config.previewPort}`,B=[];if(f){if(B.push(`Production: ${w}`),A?.previewUrl)B.push(`Preview: ${Q}`)}return{status:f?"healthy":"error",message:f?B.join(", "):"Webserver not running",lastCheck:new Date,details:{preview:!!A?.previewUrl,production:f,previewUrl:A?.previewUrl?Q:void 0,productionUrl:f?w:void 0}}}}}async handleProgressEvent(A,f){}async ensureDistDirectories(){let{mkdir:A,writeFile:f}=await import("fs/promises");if(this.config.previewDistDir&&!Bq0(this.config.previewDistDir))await A(this.config.previewDistDir,{recursive:!0}),await f(xq0(this.config.previewDistDir,"index.html"),THA),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!Bq0(this.config.productionDistDir))await A(this.config.productionDistDir,{recursive:!0}),await f(xq0(this.config.productionDistDir,"index.html"),THA),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}B0();YA();var cq0=X.object({port:X.number().default(3334),organization:X.string().optional(),trustedTokens:X.record(X.string()).optional(),outboundTokens:X.record(X.string()).optional()});B0();function FK2(A,f){return`${A.name} is ${f.name}'s ${A.role}. Its purpose is: ${A.purpose}.`}function Iq0(A){let{character:f,profile:w,version:Q,domain:B,organization:x,tools:c}=A,$=`${B?`https://${B}`:"http://localhost:3334"}/a2a`,u=A.skills&&A.skills.length>0?A.skills.map((K)=>({id:K.name.toLowerCase().replace(/\s+/g,"-"),name:K.name,description:K.description,tags:K.tags,examples:K.examples})):c.map((K)=>({id:K.name,name:K.name,description:K.description,tags:[],examples:[]})),Y={name:w.name};if(A.kind)Y.kind=A.kind;if(w.description)Y.description=w.description;if(x)Y.organization=x;let F=[{uri:pP,description:"Anchor (operator) identity for this brain",params:Y}];return{name:f.name,description:FK2(f,w),url:$,version:Q,protocolVersion:"0.2.2",capabilities:{streaming:!0,pushNotifications:!1,extensions:F},skills:u,defaultInputModes:["text/plain"],defaultOutputModes:["text/plain"],...x&&{provider:{organization:x,url:$}},...A.authEnabled&&{securitySchemes:{bearerAuth:{type:"http",scheme:"bearer"}},security:[{bearerAuth:[]}]}}}B0();var yHA=new Set(["completed","failed","canceled","rejected"]);class SHA{tasks=new Map;ttlMs;processingTimeoutMs;constructor(A=3600000,f=300000){this.ttlMs=A,this.processingTimeoutMs=f}evictExpired(){let A=Date.now();for(let[f,w]of this.tasks)if(yHA.has(w.task.status.state)&&A-new Date(w.updatedAt).getTime()>=this.ttlMs)this.tasks.delete(f)}createTask(A,f){this.evictExpired();let w=crypto.randomUUID(),Q=f??crypto.randomUUID(),B=new Date().toISOString(),x={kind:"message",messageId:crypto.randomUUID(),role:"user",parts:[{kind:"text",text:A}],contextId:Q,taskId:w},I={task:{id:w,contextId:Q,kind:"task",status:{state:"submitted",timestamp:B},history:[x]},conversationId:`a2a:${w}`,createdAt:B,updatedAt:B};return this.tasks.set(w,I),I}getTask(A){return this.tasks.get(A)}updateState(A,f,w){let Q=this.tasks.get(A);if(!Q)return;let B=new Date().toISOString();if(Q.task.status={state:f,timestamp:B},Q.updatedAt=B,f==="working")Q.workingStartedAt=B;if(w){let x={kind:"message",messageId:crypto.randomUUID(),role:"agent",parts:[{kind:"text",text:w}],contextId:Q.task.contextId,taskId:A};Q.task.status.message=x,Q.task.history??=[],Q.task.history.push(x)}return Q}addArtifact(A,f,w){let Q=this.tasks.get(A);if(!Q)return;return Q.task.artifacts??=[],Q.task.artifacts.push({artifactId:crypto.randomUUID(),name:f,parts:w}),Q.updatedAt=new Date().toISOString(),Q}getTaskWithHistory(A,f){let w=this.tasks.get(A);if(!w)return;if(w.task.status.state==="working"&&w.workingStartedAt&&Date.now()-new Date(w.workingStartedAt).getTime()>=this.processingTimeoutMs)this.updateState(A,"failed","Processing timed out");if(f===void 0||!w.task.history)return w.task;return{...w.task,history:w.task.history.slice(-f)}}deleteTask(A){return this.tasks.delete(A)}get size(){return this.tasks.size}}YA();var $q0=X.array(X.object({kind:X.string(),text:X.string().optional(),data:X.record(X.unknown()).optional()})),KK2=X.object({message:X.object({kind:X.literal("message").optional(),messageId:X.string().optional(),role:X.enum(["user","agent"]).optional(),parts:$q0,contextId:X.string().optional(),taskId:X.string().optional()}),configuration:X.object({historyLength:X.number().optional()}).optional()}),uq0=X.object({id:X.string(),historyLength:X.number().optional()});function pHA(A,f){return{jsonrpc:"2.0",id:A,result:f}}function Ku(A,f,w){return{jsonrpc:"2.0",id:A,error:{code:f,message:w}}}var Dq0=X.object({jsonrpc:X.string(),id:X.union([X.string(),X.number()]),method:X.string(),params:X.record(X.unknown()).optional()});async function Yq0(A,f){let{id:w,method:Q,params:B}=A;switch(Q){case"message/send":return XK2(w,B??{},f);case"tasks/get":return vK2(w,B??{},f);case"tasks/cancel":return WK2(w,B??{},f);default:return Ku(w,-32601,`Method not found: ${Q}`)}}async function XK2(A,f,w){let Q=KK2.safeParse(f);if(!Q.success)return Ku(A,-32602,`Invalid params: ${Q.error.message}`);let B=Q.data.message.parts.filter((Y)=>Y.kind==="text"&&typeof Y.text==="string");if(B.length===0)return Ku(A,-32602,"Message must contain at least one text part");let x=B.map((Y)=>Y.text).join(`
1920
+ </html>`;var Qq0={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.9",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts"},dependencies:{"@brains/plugins":"workspace:*","@hono/bun-compress":"^0.1.0",hono:"^4.7.10"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};class RU extends _${serverManager;apiServer;siteUrl;previewUrl;constructor(A={}){super("webserver",Qq0,A,lHA)}async onRegister(A){this.siteUrl=A.siteUrl,this.previewUrl=A.previewUrl,this.serverManager=new Rp({logger:A.logger,productionDistDir:this.config.productionDistDir,sharedImagesDir:this.config.sharedImagesDir,productionPort:this.config.productionPort,...this.config.previewDistDir&&{previewDistDir:this.config.previewDistDir},...this.config.previewPort&&{previewPort:this.config.previewPort},getHealthData:()=>A.appInfo()});let f=A.apiRoutes.getRoutes();if(f.length>0){let w=A.apiRoutes.getMessageBus();this.apiServer=new Pp({logger:A.logger,port:this.config.apiPort,routes:f,messageBus:w}),A.logger.info(`Configured ${f.length} API routes on port ${this.config.apiPort}`)}}getServerManager(){if(!this.serverManager)throw Error("ServerManager not initialized \u2014 onRegister not called");return this.serverManager}createDaemon(){return{start:async()=>{if(await this.ensureDistDirectories(),await this.getServerManager().start(),this.apiServer)await this.apiServer.start()},stop:async()=>{await this.serverManager?.stop(),await this.apiServer?.stop()},healthCheck:async()=>{let A=this.serverManager?.getStatus(),f=A?.running??!1,w=this.siteUrl??A?.productionUrl??`http://localhost:${this.config.productionPort}`,Q=this.previewUrl??A?.previewUrl??`http://localhost:${this.config.previewPort}`,B=[];if(f){if(B.push(`Production: ${w}`),A?.previewUrl)B.push(`Preview: ${Q}`)}return{status:f?"healthy":"error",message:f?B.join(", "):"Webserver not running",lastCheck:new Date,details:{preview:!!A?.previewUrl,production:f,previewUrl:A?.previewUrl?Q:void 0,productionUrl:f?w:void 0}}}}}async handleProgressEvent(A,f){}async ensureDistDirectories(){let{mkdir:A,writeFile:f}=await import("fs/promises");if(this.config.previewDistDir&&!Bq0(this.config.previewDistDir))await A(this.config.previewDistDir,{recursive:!0}),await f(xq0(this.config.previewDistDir,"index.html"),THA),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!Bq0(this.config.productionDistDir))await A(this.config.productionDistDir,{recursive:!0}),await f(xq0(this.config.productionDistDir,"index.html"),THA),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}B0();YA();var cq0=X.object({port:X.number().default(3334),organization:X.string().optional(),trustedTokens:X.record(X.string()).optional(),outboundTokens:X.record(X.string()).optional()});B0();function FK2(A,f){return`${A.name} is ${f.name}'s ${A.role}. Its purpose is: ${A.purpose}.`}function Iq0(A){let{character:f,profile:w,version:Q,domain:B,organization:x,tools:c}=A,$=`${B?`https://${B}`:"http://localhost:3334"}/a2a`,u=A.skills&&A.skills.length>0?A.skills.map((K)=>({id:K.name.toLowerCase().replace(/\s+/g,"-"),name:K.name,description:K.description,tags:K.tags,examples:K.examples})):c.map((K)=>({id:K.name,name:K.name,description:K.description,tags:[],examples:[]})),Y={name:w.name};if(A.kind)Y.kind=A.kind;if(w.description)Y.description=w.description;if(x)Y.organization=x;let F=[{uri:pP,description:"Anchor (operator) identity for this brain",params:Y}];return{name:f.name,description:FK2(f,w),url:$,version:Q,protocolVersion:"0.2.2",capabilities:{streaming:!0,pushNotifications:!1,extensions:F},skills:u,defaultInputModes:["text/plain"],defaultOutputModes:["text/plain"],...x&&{provider:{organization:x,url:$}},...A.authEnabled&&{securitySchemes:{bearerAuth:{type:"http",scheme:"bearer"}},security:[{bearerAuth:[]}]}}}B0();var yHA=new Set(["completed","failed","canceled","rejected"]);class SHA{tasks=new Map;ttlMs;processingTimeoutMs;constructor(A=3600000,f=300000){this.ttlMs=A,this.processingTimeoutMs=f}evictExpired(){let A=Date.now();for(let[f,w]of this.tasks)if(yHA.has(w.task.status.state)&&A-new Date(w.updatedAt).getTime()>=this.ttlMs)this.tasks.delete(f)}createTask(A,f){this.evictExpired();let w=crypto.randomUUID(),Q=f??crypto.randomUUID(),B=new Date().toISOString(),x={kind:"message",messageId:crypto.randomUUID(),role:"user",parts:[{kind:"text",text:A}],contextId:Q,taskId:w},I={task:{id:w,contextId:Q,kind:"task",status:{state:"submitted",timestamp:B},history:[x]},conversationId:`a2a:${w}`,createdAt:B,updatedAt:B};return this.tasks.set(w,I),I}getTask(A){return this.tasks.get(A)}updateState(A,f,w){let Q=this.tasks.get(A);if(!Q)return;let B=new Date().toISOString();if(Q.task.status={state:f,timestamp:B},Q.updatedAt=B,f==="working")Q.workingStartedAt=B;if(w){let x={kind:"message",messageId:crypto.randomUUID(),role:"agent",parts:[{kind:"text",text:w}],contextId:Q.task.contextId,taskId:A};Q.task.status.message=x,Q.task.history??=[],Q.task.history.push(x)}return Q}addArtifact(A,f,w){let Q=this.tasks.get(A);if(!Q)return;return Q.task.artifacts??=[],Q.task.artifacts.push({artifactId:crypto.randomUUID(),name:f,parts:w}),Q.updatedAt=new Date().toISOString(),Q}getTaskWithHistory(A,f){let w=this.tasks.get(A);if(!w)return;if(w.task.status.state==="working"&&w.workingStartedAt&&Date.now()-new Date(w.workingStartedAt).getTime()>=this.processingTimeoutMs)this.updateState(A,"failed","Processing timed out");if(f===void 0||!w.task.history)return w.task;return{...w.task,history:w.task.history.slice(-f)}}deleteTask(A){return this.tasks.delete(A)}get size(){return this.tasks.size}}YA();var $q0=X.array(X.object({kind:X.string(),text:X.string().optional(),data:X.record(X.unknown()).optional()})),KK2=X.object({message:X.object({kind:X.literal("message").optional(),messageId:X.string().optional(),role:X.enum(["user","agent"]).optional(),parts:$q0,contextId:X.string().optional(),taskId:X.string().optional()}),configuration:X.object({historyLength:X.number().optional()}).optional()}),uq0=X.object({id:X.string(),historyLength:X.number().optional()});function pHA(A,f){return{jsonrpc:"2.0",id:A,result:f}}function Ku(A,f,w){return{jsonrpc:"2.0",id:A,error:{code:f,message:w}}}var Dq0=X.object({jsonrpc:X.string(),id:X.union([X.string(),X.number()]),method:X.string(),params:X.record(X.unknown()).optional()});async function Yq0(A,f){let{id:w,method:Q,params:B}=A;switch(Q){case"message/send":return XK2(w,B??{},f);case"tasks/get":return vK2(w,B??{},f);case"tasks/cancel":return WK2(w,B??{},f);default:return Ku(w,-32601,`Method not found: ${Q}`)}}async function XK2(A,f,w){let Q=KK2.safeParse(f);if(!Q.success)return Ku(A,-32602,`Invalid params: ${Q.error.message}`);let B=Q.data.message.parts.filter((Y)=>Y.kind==="text"&&typeof Y.text==="string");if(B.length===0)return Ku(A,-32602,"Message must contain at least one text part");let x=B.map((Y)=>Y.text).join(`
1921
1921
  `),c=Q.data.message.contextId,I=w.taskManager.createTask(x,c),$=I.task.id;w.taskManager.updateState($,"working"),ZK2($,x,I.conversationId,w);let u=w.taskManager.getTask($);if(!u)return Ku(A,-32603,"Internal error: task disappeared");return pHA(A,u.task)}function ZK2(A,f,w,Q){Q.agentService.chat(f,w,{userPermissionLevel:Q.callerPermissionLevel,interfaceType:"a2a"}).then((B)=>{Q.taskManager.updateState(A,"completed",B.text)}).catch((B)=>{let x=B instanceof Error?B.message:"Unknown error";Q.taskManager.updateState(A,"failed",`Error: ${x}`)})}var Hq0=X.object({message:X.object({kind:X.string(),parts:$q0,contextId:X.string().optional()})});function Uq0(A,f,w){let B=f.parts.filter((u)=>u.kind==="text"&&typeof u.text==="string").map((u)=>u.text).join(`
1922
1922
  `)||"No message text",x=w.taskManager.createTask(B,f.contextId),c=x.task.id;w.taskManager.updateState(c,"working");let I=new TextEncoder,$=new ReadableStream({start(u){let Y=!1;function F(h){if(Y)return;try{u.enqueue(I.encode(`data: ${JSON.stringify(h)}
1923
1923
 
@@ -1925,7 +1925,7 @@ ${A.entityContent}`,wq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt
1925
1925
 
1926
1926
  `);Q=x.pop()??"";for(let c of x){let I=c.split(`
1927
1927
  `).find((h)=>h.startsWith("data: "));if(!I)continue;let u=JSON.parse(I.slice(6)).result;if(!u)continue;if(u.final!==!0)continue;f.cancel().catch(()=>{});let F=u.status,K=F?.state??"unknown",k=(F?.message?.parts??[]).filter((h)=>h.kind==="text"&&typeof h.text==="string").map((h)=>h.text).join(`
1928
- `)||"No response text";return{success:!0,data:{state:K,response:k}}}B=await f.read()}return{success:!1,error:"Stream ended without a terminal event"}}function Xq0(A={}){let f=A.fetch??globalThis.fetch;return{name:"a2a_call",description:"Call a remote A2A agent. Discovers the agent via its Agent Card, sends a message, and returns the response.",inputSchema:Fq0,visibility:"anchor",handler:async(w)=>{let Q=X.object(Fq0).safeParse(w);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};let{agent:B,message:x}=Q.data,c=B,I=B.startsWith("http://")||B.startsWith("https://");if(!I&&A.entityService){let K=await A.entityService.getEntity("agent",B);if(K){if(K.metadata.status==="archived")return{success:!1,error:`Agent ${B} is archived. Use agent_add to re-activate.`};let Z=K.metadata.url;if(typeof Z==="string")c=Z}}if(!c.startsWith("http"))c=`https://${c}`;let $=await kK2(c,f);if(!$)return{success:!1,error:`Could not fetch Agent Card from ${c}`};let u=$.url,Y;if(A.outboundTokens)try{let K=new URL(u).hostname;Y=A.outboundTokens[K]}catch{}let F=await hK2(u,x,f,Y);if("success"in F&&F.success&&I&&A.sendMessage){let K=new URL(u).hostname;A.sendMessage("a2a:call:completed",{domain:K}).catch(()=>{})}return F}}}var rHA={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.8",type:"module",main:"./src/index.ts",module:"./src/index.ts",types:"./src/index.ts",files:["src"],scripts:{typecheck:"tsc --noEmit",lint:"eslint --max-warnings 0 .","lint:fix":"eslint --fix .",test:"bun test"},dependencies:{"@a2a-js/sdk":"^0.3.12","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",hono:"^4.7.10"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14",typescript:"^5.3.3"}};class TJ extends _${agentCard;server;unsubscribeReady;unsubscribeSyncCompleted;taskManager=new SHA;agentService;permissionContext;constructor(A={}){super("a2a",rHA,A,cq0)}async onRegister(A){await super.onRegister(A),this.agentService=A.agentService,this.permissionContext=A.permissions,this.unsubscribeReady=A.messaging.subscribe("system:plugins:ready",()=>{return this.rebuildAgentCard(A),{noop:!0}}),this.unsubscribeSyncCompleted=A.messaging.subscribe("sync:initial:completed",()=>{return this.rebuildAgentCard(A),{success:!0}}),this.logger.info("A2A interface registered",{domain:A.domain})}async rebuildAgentCard(A){let f=A.identity.get(),w=A.identity.getProfile(),Q=A.tools.listForPermissionLevel("public"),B=this.config.trustedTokens&&Object.keys(this.config.trustedTokens).length>0,x;if(A.entityService.hasEntityType("skill"))try{let c=await A.entityService.listEntities("skill");if(c.length>0)x=c.map((I)=>mk.safeParse(I.metadata)).filter((I)=>I.success).map((I)=>I.data)}catch{}this.agentCard=Iq0({character:f,profile:w,version:rHA.version,domain:A.domain,organization:this.config.organization,tools:Q,skills:x,authEnabled:B}),this.logger.debug("Agent Card rebuilt",{skills:this.agentCard.skills.length})}getAgentCard(){return this.agentCard}resolveCallerPermission(A){if(!A?.startsWith("Bearer ")||!this.config.trustedTokens)return"public";let f=A.slice(7),w=this.config.trustedTokens[f];if(!w||!this.permissionContext)return"public";return this.permissionContext.getUserLevel("a2a",w)}async getTools(){return[Xq0({outboundTokens:this.config.outboundTokens,entityService:this.getContext().entityService,sendMessage:(A,f)=>this.getContext().messaging.send(A,f)})]}createDaemon(){let A=new nZ;return A.get("/.well-known/agent-card.json",(f)=>{if(!this.agentCard)return f.json({error:"Agent Card not ready"},503);return f.json(this.agentCard)}),A.post("/a2a",async(f)=>{if(!this.agentService)return f.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503);let w;try{w=await f.req.json()}catch{return f.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null})}let Q=Dq0.safeParse(w);if(!Q.success)return f.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null});let B=this.resolveCallerPermission(f.req.header("Authorization"));if(Q.data.method==="message/stream"){let c=Hq0.safeParse(Q.data.params??{});if(!c.success)return f.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${c.error.message}`},id:Q.data.id});let{stream:I}=Uq0(Q.data.id,c.data.message,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:B});return new Response(I,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}let x=await Yq0(Q.data,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:B});return f.json(x)}),{start:async()=>{this.server=Bun.serve({port:this.config.port,fetch:A.fetch}),this.logger.info(`A2A server listening on http://localhost:${this.config.port}`)},stop:async()=>{if(this.unsubscribeReady?.(),this.unsubscribeSyncCompleted?.(),this.server)await this.server.stop(),this.server=void 0;this.logger.info("A2A server stopped")}}}}B0();B0();class dHA{logger;syncPath;constructor(A,f){this.logger=A,this.syncPath=f}prepareBatchOperations(A,f){if(A.length===0)return{operations:[],exportOperationsCount:0,importOperationsCount:0,totalFiles:0};let w=[],Q=this.createImportOperations(A);w.push(...Q);let B=Q.length;if(f?.includeCleanup)w.push({type:"directory-cleanup",data:{}});let x=A.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:B,totalFiles:x}),{operations:w,exportOperationsCount:0,importOperationsCount:B,totalFiles:x}}async queueSyncBatch(A,f,w,Q,B){let x=this.prepareBatchOperations(w,B);if(x.operations.length===0)return this.logger.debug("No sync operations needed",{source:f}),null;return{batchId:await A.jobs.enqueueBatch(x.operations,{source:f,rootJobId:Q?.rootJobId??l8(),metadata:{progressToken:Q?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:Q?.pluginId??"directory-sync",interfaceType:Q?.interfaceType,channelId:Q?.channelId}}),operationCount:x.operations.length,exportOperationsCount:x.exportOperationsCount,importOperationsCount:x.importOperationsCount,totalFiles:x.totalFiles}}createImportOperations(A){if(A.length===0)return[];let f=50,w=[];for(let Q=0;Q<A.length;Q+=f){let B=A.slice(Q,Q+f);w.push({type:"directory-import",data:{batchIndex:Math.floor(Q/f),paths:B,batchSize:B.length}})}return w}}YA();import{resolve as jk2,isAbsolute as gk2}from"path";import{mkdir as Pk2}from"fs/promises";var jV0=o0(_V0(),1);R7();import{join as Xu,dirname as hk2,extname as cr}from"path";import{mkdir as rUA,readFile as xr,writeFile as VV0,readdir as Gk2,stat as iV0,utimes as Jk2,access as bk2}from"fs/promises";var Bi=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function MV0(A){let f=cr(A).toLowerCase();return Bi.includes(f)}function zk2(A){switch(A.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 OV0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}async function aJ(A){try{return await bk2(A),!0}catch{return!1}}class dUA{syncPath;entityService;constructor(A,f){this.syncPath=A,this.entityService=f}parseEntityFromPath(A){let Q=(A.startsWith(this.syncPath)?A:Xu(this.syncPath,A)).replace(this.syncPath+"/","").split("/"),B,x;if(Q.length===1)B="base",x=Q;else if(Q.length>1&&Q[0])B=Q[0],x=Q.slice(1);else B="base",x=Q;let c;if(x.length>1){let I=x[x.length-1];if(I){let $=cr(I).toLowerCase(),u=$===".md"||Bi.includes($)?I.slice(0,-$.length):I;x[x.length-1]=u}c=x.join(":")}else{let I=x[0]??"",$=cr(I).toLowerCase();c=$===".md"||Bi.includes($)?I.slice(0,-$.length):I}return{entityType:B,id:c}}async readEntity(A){let f=A.startsWith(this.syncPath)?A:Xu(this.syncPath,A),w=await iV0(f),{entityType:Q,id:B}=this.parseEntityFromPath(A),x=w.birthtime.getTime()>0?w.birthtime:w.mtime,c=w.mtime,I;if(MV0(A)){let u=(await xr(f)).toString("base64"),Y=cr(A);I=`data:${zk2(Y)};base64,${u}`}else I=await xr(f,"utf-8");return{entityType:Q,id:B,content:I,created:x,updated:c}}async writeEntity(A){let f=this.getEntityFilePath(A),w=A.entityType==="image",Q;if(w){let x=A.content.match(/^data:image\/[a-z+]+;base64,(.+)$/i);Q=x?.[1]?Buffer.from(x[1],"base64"):Buffer.from(A.content,"base64")}else Q=this.entityService.serializeEntity(A);if(await aJ(f)){let x=w?await xr(f):await xr(f,"utf-8"),c=IQ(w?x.toString("base64"):x),I=IQ(w?Q.toString("base64"):Q);if(c===I)return}if(A.entityType!=="base")await rUA(hk2(f),{recursive:!0});if(w)await VV0(f,Q);else await VV0(f,Q,"utf-8");let B=new Date(A.updated);await Jk2(f,B,B)}getFilePath(A,f,w=".md"){let Q=A.split(":").filter(($)=>$.length>0),B=f==="base";if(Q.length===1)return B?Xu(this.syncPath,`${Q[0]}${w}`):Xu(this.syncPath,f,`${Q[0]}${w}`);let x=Q;if(Q[0]===f)x=Q.slice(1);let c=x[x.length-1],I=x.slice(0,-1);if(B)return Xu(this.syncPath,...I,`${c}${w}`);else return Xu(this.syncPath,f,...I,`${c}${w}`)}getEntityFilePath(A){let f=".md";if(A.entityType==="image"){let w=A.metadata.format;if(w)f=OV0(w);else{let Q=A.content.match(/^data:image\/([a-z+]+);base64,/i);if(Q?.[1])f=OV0(Q[1])}}return this.getFilePath(A.id,A.entityType,f)}async getAllMarkdownFiles(){return this.findFiles({includeImages:!1})}async getAllSyncFiles(){return this.findFiles({includeImages:!0})}async findFiles(A){let f=[];if(!await aJ(this.syncPath))return f;let w=async(Q,B="",x=!1)=>{let c=await Gk2(Q,{withFileTypes:!0});for(let I of c){let $=B?Xu(B,I.name):I.name;if(I.isFile()&&!I.name.endsWith(".invalid")){if(I.name.endsWith(".md"))f.push($);else if(A.includeImages&&x&&MV0(I.name))f.push($)}else if(I.isDirectory()&&!I.name.startsWith(".")){if(B===""&&!this.entityService.hasEntityType(I.name))continue;let u=Xu(Q,I.name),Y=I.name==="image"&&B==="";await w(u,$,x||Y)}}};return await w(this.syncPath),f}async ensureDirectoryStructure(A){if(!await aJ(this.syncPath))await rUA(this.syncPath,{recursive:!0});for(let f of A)if(f!=="base")await rUA(Xu(this.syncPath,f),{recursive:!0})}shouldUpdateEntity(A,f){let w=IQ(f.content);return A.contentHash!==w}async gatherFileStatus(){let A=[],f={totalFiles:0,byEntityType:{}};if(!await aJ(this.syncPath))return{files:A,stats:f};let w=await this.getAllMarkdownFiles();for(let Q of w)try{let B=Xu(this.syncPath,Q),x=await iV0(B),{entityType:c}=this.parseEntityFromPath(Q);A.push({path:Q,entityType:c,modified:x.mtime}),f.totalFiles++,f.byEntityType[c]=(f.byEntityType[c]??0)+1}catch{continue}return{files:A,stats:f}}async syncDirectoryExists(){return aJ(this.syncPath)}async fileExists(A){return aJ(A)}}function Nk2(A,f){if(!A.replace(f+"/","").startsWith("image/"))return!1;return Bi.some((Q)=>A.toLowerCase().endsWith(Q))}function Ck2(A,f){if(A.replace(f+"/","").split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return Nk2(A,f)}class oUA{watcher;watchCallback;pendingChanges=new Map;batchTimeout;syncPath;watchInterval;logger;onFileChange;constructor(A){this.syncPath=A.syncPath,this.watchInterval=A.watchInterval,this.logger=A.logger,this.onFileChange=A.onFileChange}async start(){if(this.watcher){this.logger.debug("Already watching directory");return}if(this.logger.debug("Starting directory watch",{path:this.syncPath,interval:this.watchInterval}),this.watcher=jV0.default.watch(this.syncPath,{ignored:/(^|[/\\])\../,persistent:!0,interval:this.watchInterval,awaitWriteFinish:{stabilityThreshold:2000,pollInterval:100}}),this.watcher.on("add",(A)=>void this.handleFileChange("add",A)).on("change",(A)=>void this.handleFileChange("change",A)).on("unlink",(A)=>void this.handleFileChange("delete",A)).on("error",(A)=>this.logger.error("Watcher error",A)),this.watchCallback)this.watcher.on("all",this.watchCallback)}stop(){if(this.watcher)this.watcher.close(),this.watcher=void 0,this.logger.info("Stopped directory watch");if(this.batchTimeout)clearTimeout(this.batchTimeout),this.batchTimeout=void 0}setCallback(A){if(this.watchCallback=A,this.watcher)this.watcher.on("all",A)}async handleFileChange(A,f){if(!Ck2(f,this.syncPath))return;this.logger.debug("File change detected",{event:A,path:f});let w=f.replace(this.syncPath+"/","");if(this.pendingChanges.set(w,A),this.batchTimeout)clearTimeout(this.batchTimeout);this.batchTimeout=setTimeout(()=>{this.processPendingChanges()},500)}async processPendingChanges(){if(this.pendingChanges.size===0)return;let A=new Map(this.pendingChanges);this.pendingChanges.clear(),this.batchTimeout=void 0,this.logger.debug("Processing batched file changes",{changeCount:A.size});for(let[f,w]of A){let Q=`${this.syncPath}/${f}`;try{if(this.onFileChange)await this.onFileChange(w,Q)}catch(B){this.logger.error("Error processing file change",{path:f,event:w,error:B})}}}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}class aUA{logger;entityService;fileOperations;constructor(A,f,w){this.logger=A,this.entityService=f,this.fileOperations=w}async importEntitiesWithProgress(A,f,w,Q){this.logger.debug("Importing entities with progress reporting");let B={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},x=A??await this.fileOperations.getAllMarkdownFiles(),c=x.length;await f.report({progress:0,message:`Starting import of ${c} files`});for(let I=0;I<c;I+=w){let $=x.slice(I,I+w),u=await Q($);B.imported+=u.imported,B.skipped+=u.skipped,B.failed+=u.failed,B.errors.push(...u.errors),B.jobIds.push(...u.jobIds);let Y=Math.min(I+w,c),F=Math.round(Y/c*40);await f.report({progress:F,message:`Imported ${Y}/${c} files`})}return B}async exportEntitiesWithProgress(A,f,w){this.logger.debug("Exporting entities with progress reporting");let Q=A??this.entityService.getEntityTypes(),B={exported:0,failed:0,errors:[]},x=Q.length;await f.report({progress:50,message:`Starting export of ${x} entity types`});for(let c=0;c<x;c++){let I=Q[c];if(!I)continue;let $=await this.entityService.listEntities(I,{limit:1000});for(let u=0;u<$.length;u+=w){let Y=$.slice(u,u+w);for(let Z of Y)try{await this.fileOperations.writeEntity(Z),B.exported++,this.logger.debug("Exported entity",{entityType:I,id:Z.id})}catch(k){let h=k instanceof Error?k:Error(`Failed to export entity ${Z.id||"unknown"}`);B.failed++,B.errors.push({entityId:Z.id||"unknown",entityType:I,error:h.message}),this.logger.error("Failed to export entity",{entityType:I,id:Z.id||"unknown",error:h})}let F=(c+1)/x,K=50+Math.round(F*50);await f.report({progress:K,message:`Exported ${B.exported} entities`})}}return this.logger.debug("Export completed",B),B}}class sUA{logger;handleImport;handleDelete;deleteOnFileRemoval;fileOperations;constructor(A,f,w,Q,B=!0){if(this.logger=A,this.fileOperations=Q,this.deleteOnFileRemoval=B,w)this.handleImport=async(x)=>{let c=await w({type:"directory-import",data:{paths:[x]}});this.logger.debug("Queued import job for file change",{jobId:c,path:x})},this.handleDelete=async(x)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:x});return}try{let{entityType:c,id:I}=this.fileOperations.parseEntityFromPath(x),$=await w({type:"directory-delete",data:{entityId:I,entityType:c,filePath:x}});this.logger.info("Queued delete job for removed file",{jobId:$,path:x,entityId:I,entityType:c})}catch(c){this.logger.warn("Could not extract entity info from deleted file",{path:x,error:c})}};else this.handleImport=async(x)=>{await f([x])},this.handleDelete=async(x)=>{this.logger.warn("File deleted but no job queue available",{path:x})}}async handleFileChange(A,f){this.logger.debug("Processing file change",{event:A,path:f});try{switch(A){case"add":case"change":await this.handleImport(f);break;case"delete":case"unlink":await this.handleDelete(f);break;default:this.logger.debug("Unhandled file event",{event:A,path:f})}}catch(w){this.logger.error("Failed to handle file change",{event:A,path:f,error:w})}}}YA();async function Ir(A,f,w,Q){let{sourceUrl:B}=A,x=await f.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1});if(x[0])return Q.debug("Reusing existing image entity",{sourceUrl:B,imageId:x[0].id}),x[0].id;let c=await w(B),{base64:I}=pH(c),$=iX(I),u=rH(I);if(!$||!u)throw Error("Could not detect image format or dimensions");let Y=await f.createEntity({id:A.id,entityType:"image",content:c,metadata:{title:A.title,alt:A.alt,format:$,width:u.width,height:u.height,sourceUrl:B}});return Q.debug("Created image entity from URL",{sourceUrl:B,imageId:Y.entityId}),Y.entityId}var gV0=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.string().url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class tUA{entityService;fetcher;logger;constructor(A,f,w=Bc){this.entityService=A;this.fetcher=w;this.logger=f.child("FrontmatterImageConverter")}detectCoverImageUrl(A){let f;try{f=E7(A)}catch{return null}let{frontmatter:w}=f,Q=gV0.safeParse(w);if(!Q.success)return null;if(Q.data.coverImageId)return null;let{title:B,slug:x,coverImageUrl:c,coverImageAlt:I}=Q.data;if(!jD(c))return null;return{sourceUrl:c,postTitle:B,postSlug:x??x2(B),customAlt:I}}async convert(A){let f;try{f=E7(A)}catch(u){return this.logger.debug("Parse failed",{error:u}),{content:A,converted:!1}}let{frontmatter:w}=f,Q=gV0.safeParse(w);if(!Q.success)return{content:A,converted:!1};if(Q.data.coverImageId)return{content:A,converted:!1};let{title:B,slug:x,coverImageUrl:c,coverImageAlt:I}=Q.data;if(!jD(c))return{content:A,converted:!1};let $={postTitle:B,postSlug:x??x2(B),sourceUrl:c,customAlt:I};try{let u=await this.createImageEntity($),Y={...w};return delete Y.coverImageUrl,delete Y.coverImageAlt,Y.coverImageId=u,{content:_K(Y,f.content),converted:!0,imageId:u}}catch(u){return this.logger.warn("Failed to convert coverImageUrl",{url:c,error:h0(u)}),{content:A,converted:!1}}}async createImageEntity(A){let{postTitle:f,postSlug:w,sourceUrl:Q,customAlt:B}=A,x=`Cover image for ${f}`;return Ir({id:`${w}-cover`,title:x,alt:B??x,sourceUrl:Q},this.entityService,this.fetcher,this.logger)}}YA();class xi{entityService;fetcher;logger;constructor(A,f,w=Bc){this.entityService=A;this.fetcher=w;this.logger=f.child("MarkdownImageConverter")}detectInlineImages(A,f){let w=[],Q=Pg(A);for(let B of Q){if(!jD(B.url))continue;if(B.url.startsWith("entity://"))continue;let x=this.reconstructMarkdown(B);w.push({sourceUrl:B.url,alt:B.alt,originalMarkdown:x,postSlug:f})}return w}reconstructMarkdown(A){if(A.title)return`![${A.alt}](${A.url} "${A.title}")`;return`![${A.alt}](${A.url})`}async convert(A,f){let w=this.detectInlineImages(A,f);if(w.length===0)return{content:A,converted:!1,convertedCount:0};let Q=A,B=0,x=0;for(let c of w)try{let I=await this.createImageEntity(c,x++),$=`![${c.alt}](entity://image/${I})`;Q=Q.replace(c.originalMarkdown,$),B++,this.logger.debug("Converted inline image",{sourceUrl:c.sourceUrl,imageId:I})}catch(I){this.logger.warn("Failed to convert inline image",{sourceUrl:c.sourceUrl,error:h0(I)})}return{content:Q,converted:B>0,convertedCount:B}}async createImageEntity(A,f){let{sourceUrl:w,alt:Q,postSlug:B}=A;return Ir({id:`${B}-inline-${f}`,title:Q||`Inline image ${f+1} for ${B}`,alt:Q||"",sourceUrl:w},this.entityService,this.fetcher,this.logger)}}YA();import{rename as Ek2,appendFile as Lk2,readFile as qk2,writeFile as _k2,access as Vk2}from"fs/promises";import{join as PV0}from"path";class eUA{logger;syncPath;constructor(A,f){this.logger=A;this.syncPath=f}isValidationError(A){if(A instanceof X.ZodError)return!0;let f=h0(A);return f.includes("invalid_type")||f.includes("invalid_enum_value")||f.includes("Required")||f.includes("Invalid frontmatter")||f.includes("Unknown entity type")}async quarantineInvalidFile(A,f,w,Q){let B=Q(A),x=`${B}.invalid`;try{await Ek2(B,x),w.quarantined++,w.quarantinedFiles.push(A);let c=PV0(this.syncPath,".import-errors.log"),I=new Date().toISOString(),$=h0(f),u=`${I} - ${A}: ${$}
1928
+ `)||"No response text";return{success:!0,data:{state:K,response:k}}}B=await f.read()}return{success:!1,error:"Stream ended without a terminal event"}}function Xq0(A={}){let f=A.fetch??globalThis.fetch;return{name:"a2a_call",description:"Call a remote A2A agent. Discovers the agent via its Agent Card, sends a message, and returns the response.",inputSchema:Fq0,visibility:"anchor",handler:async(w)=>{let Q=X.object(Fq0).safeParse(w);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};let{agent:B,message:x}=Q.data,c=B,I=B.startsWith("http://")||B.startsWith("https://");if(!I&&A.entityService){let K=await A.entityService.getEntity("agent",B);if(K){if(K.metadata.status==="archived")return{success:!1,error:`Agent ${B} is archived. Use agent_add to re-activate.`};let Z=K.metadata.url;if(typeof Z==="string")c=Z}}if(!c.startsWith("http"))c=`https://${c}`;let $=await kK2(c,f);if(!$)return{success:!1,error:`Could not fetch Agent Card from ${c}`};let u=$.url,Y;if(A.outboundTokens)try{let K=new URL(u).hostname;Y=A.outboundTokens[K]}catch{}let F=await hK2(u,x,f,Y);if("success"in F&&F.success&&I&&A.sendMessage){let K=new URL(u).hostname;A.sendMessage("a2a:call:completed",{domain:K}).catch(()=>{})}return F}}}var rHA={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.9",type:"module",main:"./src/index.ts",module:"./src/index.ts",types:"./src/index.ts",files:["src"],scripts:{typecheck:"tsc --noEmit",lint:"eslint --max-warnings 0 .","lint:fix":"eslint --fix .",test:"bun test"},dependencies:{"@a2a-js/sdk":"^0.3.12","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",hono:"^4.7.10"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14",typescript:"^5.3.3"}};class TJ extends _${agentCard;server;unsubscribeReady;unsubscribeSyncCompleted;taskManager=new SHA;agentService;permissionContext;constructor(A={}){super("a2a",rHA,A,cq0)}async onRegister(A){await super.onRegister(A),this.agentService=A.agentService,this.permissionContext=A.permissions,this.unsubscribeReady=A.messaging.subscribe("system:plugins:ready",()=>{return this.rebuildAgentCard(A),{noop:!0}}),this.unsubscribeSyncCompleted=A.messaging.subscribe("sync:initial:completed",()=>{return this.rebuildAgentCard(A),{success:!0}}),this.logger.info("A2A interface registered",{domain:A.domain})}async rebuildAgentCard(A){let f=A.identity.get(),w=A.identity.getProfile(),Q=A.tools.listForPermissionLevel("public"),B=this.config.trustedTokens&&Object.keys(this.config.trustedTokens).length>0,x;if(A.entityService.hasEntityType("skill"))try{let c=await A.entityService.listEntities("skill");if(c.length>0)x=c.map((I)=>mk.safeParse(I.metadata)).filter((I)=>I.success).map((I)=>I.data)}catch{}this.agentCard=Iq0({character:f,profile:w,version:rHA.version,domain:A.domain,organization:this.config.organization,tools:Q,skills:x,authEnabled:B}),this.logger.debug("Agent Card rebuilt",{skills:this.agentCard.skills.length})}getAgentCard(){return this.agentCard}resolveCallerPermission(A){if(!A?.startsWith("Bearer ")||!this.config.trustedTokens)return"public";let f=A.slice(7),w=this.config.trustedTokens[f];if(!w||!this.permissionContext)return"public";return this.permissionContext.getUserLevel("a2a",w)}async getTools(){return[Xq0({outboundTokens:this.config.outboundTokens,entityService:this.getContext().entityService,sendMessage:(A,f)=>this.getContext().messaging.send(A,f)})]}createDaemon(){let A=new nZ;return A.get("/.well-known/agent-card.json",(f)=>{if(!this.agentCard)return f.json({error:"Agent Card not ready"},503);return f.json(this.agentCard)}),A.get("/",(f)=>{return f.redirect("/.well-known/agent-card.json",302)}),A.get("/a2a",(f)=>{return f.json({error:"Use POST with JSON-RPC 2.0 requests.",agentCard:"/.well-known/agent-card.json"},405)}),A.post("/a2a",async(f)=>{if(!this.agentService)return f.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503);let w;try{w=await f.req.json()}catch{return f.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null})}let Q=Dq0.safeParse(w);if(!Q.success)return f.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null});let B=this.resolveCallerPermission(f.req.header("Authorization"));if(Q.data.method==="message/stream"){let c=Hq0.safeParse(Q.data.params??{});if(!c.success)return f.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${c.error.message}`},id:Q.data.id});let{stream:I}=Uq0(Q.data.id,c.data.message,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:B});return new Response(I,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}let x=await Yq0(Q.data,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:B});return f.json(x)}),{start:async()=>{this.server=Bun.serve({port:this.config.port,fetch:A.fetch}),this.logger.info(`A2A server listening on http://localhost:${this.config.port}`)},stop:async()=>{if(this.unsubscribeReady?.(),this.unsubscribeSyncCompleted?.(),this.server)await this.server.stop(),this.server=void 0;this.logger.info("A2A server stopped")}}}}B0();B0();class dHA{logger;syncPath;constructor(A,f){this.logger=A,this.syncPath=f}prepareBatchOperations(A,f){if(A.length===0)return{operations:[],exportOperationsCount:0,importOperationsCount:0,totalFiles:0};let w=[],Q=this.createImportOperations(A);w.push(...Q);let B=Q.length;if(f?.includeCleanup)w.push({type:"directory-cleanup",data:{}});let x=A.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:B,totalFiles:x}),{operations:w,exportOperationsCount:0,importOperationsCount:B,totalFiles:x}}async queueSyncBatch(A,f,w,Q,B){let x=this.prepareBatchOperations(w,B);if(x.operations.length===0)return this.logger.debug("No sync operations needed",{source:f}),null;return{batchId:await A.jobs.enqueueBatch(x.operations,{source:f,rootJobId:Q?.rootJobId??l8(),metadata:{progressToken:Q?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:Q?.pluginId??"directory-sync",interfaceType:Q?.interfaceType,channelId:Q?.channelId}}),operationCount:x.operations.length,exportOperationsCount:x.exportOperationsCount,importOperationsCount:x.importOperationsCount,totalFiles:x.totalFiles}}createImportOperations(A){if(A.length===0)return[];let f=50,w=[];for(let Q=0;Q<A.length;Q+=f){let B=A.slice(Q,Q+f);w.push({type:"directory-import",data:{batchIndex:Math.floor(Q/f),paths:B,batchSize:B.length}})}return w}}YA();import{resolve as jk2,isAbsolute as gk2}from"path";import{mkdir as Pk2}from"fs/promises";var jV0=o0(_V0(),1);R7();import{join as Xu,dirname as hk2,extname as cr}from"path";import{mkdir as rUA,readFile as xr,writeFile as VV0,readdir as Gk2,stat as iV0,utimes as Jk2,access as bk2}from"fs/promises";var Bi=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function MV0(A){let f=cr(A).toLowerCase();return Bi.includes(f)}function zk2(A){switch(A.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 OV0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}async function aJ(A){try{return await bk2(A),!0}catch{return!1}}class dUA{syncPath;entityService;constructor(A,f){this.syncPath=A,this.entityService=f}parseEntityFromPath(A){let Q=(A.startsWith(this.syncPath)?A:Xu(this.syncPath,A)).replace(this.syncPath+"/","").split("/"),B,x;if(Q.length===1)B="base",x=Q;else if(Q.length>1&&Q[0])B=Q[0],x=Q.slice(1);else B="base",x=Q;let c;if(x.length>1){let I=x[x.length-1];if(I){let $=cr(I).toLowerCase(),u=$===".md"||Bi.includes($)?I.slice(0,-$.length):I;x[x.length-1]=u}c=x.join(":")}else{let I=x[0]??"",$=cr(I).toLowerCase();c=$===".md"||Bi.includes($)?I.slice(0,-$.length):I}return{entityType:B,id:c}}async readEntity(A){let f=A.startsWith(this.syncPath)?A:Xu(this.syncPath,A),w=await iV0(f),{entityType:Q,id:B}=this.parseEntityFromPath(A),x=w.birthtime.getTime()>0?w.birthtime:w.mtime,c=w.mtime,I;if(MV0(A)){let u=(await xr(f)).toString("base64"),Y=cr(A);I=`data:${zk2(Y)};base64,${u}`}else I=await xr(f,"utf-8");return{entityType:Q,id:B,content:I,created:x,updated:c}}async writeEntity(A){let f=this.getEntityFilePath(A),w=A.entityType==="image",Q;if(w){let x=A.content.match(/^data:image\/[a-z+]+;base64,(.+)$/i);Q=x?.[1]?Buffer.from(x[1],"base64"):Buffer.from(A.content,"base64")}else Q=this.entityService.serializeEntity(A);if(await aJ(f)){let x=w?await xr(f):await xr(f,"utf-8"),c=IQ(w?x.toString("base64"):x),I=IQ(w?Q.toString("base64"):Q);if(c===I)return}if(A.entityType!=="base")await rUA(hk2(f),{recursive:!0});if(w)await VV0(f,Q);else await VV0(f,Q,"utf-8");let B=new Date(A.updated);await Jk2(f,B,B)}getFilePath(A,f,w=".md"){let Q=A.split(":").filter(($)=>$.length>0),B=f==="base";if(Q.length===1)return B?Xu(this.syncPath,`${Q[0]}${w}`):Xu(this.syncPath,f,`${Q[0]}${w}`);let x=Q;if(Q[0]===f)x=Q.slice(1);let c=x[x.length-1],I=x.slice(0,-1);if(B)return Xu(this.syncPath,...I,`${c}${w}`);else return Xu(this.syncPath,f,...I,`${c}${w}`)}getEntityFilePath(A){let f=".md";if(A.entityType==="image"){let w=A.metadata.format;if(w)f=OV0(w);else{let Q=A.content.match(/^data:image\/([a-z+]+);base64,/i);if(Q?.[1])f=OV0(Q[1])}}return this.getFilePath(A.id,A.entityType,f)}async getAllMarkdownFiles(){return this.findFiles({includeImages:!1})}async getAllSyncFiles(){return this.findFiles({includeImages:!0})}async findFiles(A){let f=[];if(!await aJ(this.syncPath))return f;let w=async(Q,B="",x=!1)=>{let c=await Gk2(Q,{withFileTypes:!0});for(let I of c){let $=B?Xu(B,I.name):I.name;if(I.isFile()&&!I.name.endsWith(".invalid")){if(I.name.endsWith(".md"))f.push($);else if(A.includeImages&&x&&MV0(I.name))f.push($)}else if(I.isDirectory()&&!I.name.startsWith(".")){if(B===""&&!this.entityService.hasEntityType(I.name))continue;let u=Xu(Q,I.name),Y=I.name==="image"&&B==="";await w(u,$,x||Y)}}};return await w(this.syncPath),f}async ensureDirectoryStructure(A){if(!await aJ(this.syncPath))await rUA(this.syncPath,{recursive:!0});for(let f of A)if(f!=="base")await rUA(Xu(this.syncPath,f),{recursive:!0})}shouldUpdateEntity(A,f){let w=IQ(f.content);return A.contentHash!==w}async gatherFileStatus(){let A=[],f={totalFiles:0,byEntityType:{}};if(!await aJ(this.syncPath))return{files:A,stats:f};let w=await this.getAllMarkdownFiles();for(let Q of w)try{let B=Xu(this.syncPath,Q),x=await iV0(B),{entityType:c}=this.parseEntityFromPath(Q);A.push({path:Q,entityType:c,modified:x.mtime}),f.totalFiles++,f.byEntityType[c]=(f.byEntityType[c]??0)+1}catch{continue}return{files:A,stats:f}}async syncDirectoryExists(){return aJ(this.syncPath)}async fileExists(A){return aJ(A)}}function Nk2(A,f){if(!A.replace(f+"/","").startsWith("image/"))return!1;return Bi.some((Q)=>A.toLowerCase().endsWith(Q))}function Ck2(A,f){if(A.replace(f+"/","").split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return Nk2(A,f)}class oUA{watcher;watchCallback;pendingChanges=new Map;batchTimeout;syncPath;watchInterval;logger;onFileChange;constructor(A){this.syncPath=A.syncPath,this.watchInterval=A.watchInterval,this.logger=A.logger,this.onFileChange=A.onFileChange}async start(){if(this.watcher){this.logger.debug("Already watching directory");return}if(this.logger.debug("Starting directory watch",{path:this.syncPath,interval:this.watchInterval}),this.watcher=jV0.default.watch(this.syncPath,{ignored:/(^|[/\\])\../,persistent:!0,interval:this.watchInterval,awaitWriteFinish:{stabilityThreshold:2000,pollInterval:100}}),this.watcher.on("add",(A)=>void this.handleFileChange("add",A)).on("change",(A)=>void this.handleFileChange("change",A)).on("unlink",(A)=>void this.handleFileChange("delete",A)).on("error",(A)=>this.logger.error("Watcher error",A)),this.watchCallback)this.watcher.on("all",this.watchCallback)}stop(){if(this.watcher)this.watcher.close(),this.watcher=void 0,this.logger.info("Stopped directory watch");if(this.batchTimeout)clearTimeout(this.batchTimeout),this.batchTimeout=void 0}setCallback(A){if(this.watchCallback=A,this.watcher)this.watcher.on("all",A)}async handleFileChange(A,f){if(!Ck2(f,this.syncPath))return;this.logger.debug("File change detected",{event:A,path:f});let w=f.replace(this.syncPath+"/","");if(this.pendingChanges.set(w,A),this.batchTimeout)clearTimeout(this.batchTimeout);this.batchTimeout=setTimeout(()=>{this.processPendingChanges()},500)}async processPendingChanges(){if(this.pendingChanges.size===0)return;let A=new Map(this.pendingChanges);this.pendingChanges.clear(),this.batchTimeout=void 0,this.logger.debug("Processing batched file changes",{changeCount:A.size});for(let[f,w]of A){let Q=`${this.syncPath}/${f}`;try{if(this.onFileChange)await this.onFileChange(w,Q)}catch(B){this.logger.error("Error processing file change",{path:f,event:w,error:B})}}}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}class aUA{logger;entityService;fileOperations;constructor(A,f,w){this.logger=A,this.entityService=f,this.fileOperations=w}async importEntitiesWithProgress(A,f,w,Q){this.logger.debug("Importing entities with progress reporting");let B={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},x=A??await this.fileOperations.getAllMarkdownFiles(),c=x.length;await f.report({progress:0,message:`Starting import of ${c} files`});for(let I=0;I<c;I+=w){let $=x.slice(I,I+w),u=await Q($);B.imported+=u.imported,B.skipped+=u.skipped,B.failed+=u.failed,B.errors.push(...u.errors),B.jobIds.push(...u.jobIds);let Y=Math.min(I+w,c),F=Math.round(Y/c*40);await f.report({progress:F,message:`Imported ${Y}/${c} files`})}return B}async exportEntitiesWithProgress(A,f,w){this.logger.debug("Exporting entities with progress reporting");let Q=A??this.entityService.getEntityTypes(),B={exported:0,failed:0,errors:[]},x=Q.length;await f.report({progress:50,message:`Starting export of ${x} entity types`});for(let c=0;c<x;c++){let I=Q[c];if(!I)continue;let $=await this.entityService.listEntities(I,{limit:1000});for(let u=0;u<$.length;u+=w){let Y=$.slice(u,u+w);for(let Z of Y)try{await this.fileOperations.writeEntity(Z),B.exported++,this.logger.debug("Exported entity",{entityType:I,id:Z.id})}catch(k){let h=k instanceof Error?k:Error(`Failed to export entity ${Z.id||"unknown"}`);B.failed++,B.errors.push({entityId:Z.id||"unknown",entityType:I,error:h.message}),this.logger.error("Failed to export entity",{entityType:I,id:Z.id||"unknown",error:h})}let F=(c+1)/x,K=50+Math.round(F*50);await f.report({progress:K,message:`Exported ${B.exported} entities`})}}return this.logger.debug("Export completed",B),B}}class sUA{logger;handleImport;handleDelete;deleteOnFileRemoval;fileOperations;constructor(A,f,w,Q,B=!0){if(this.logger=A,this.fileOperations=Q,this.deleteOnFileRemoval=B,w)this.handleImport=async(x)=>{let c=await w({type:"directory-import",data:{paths:[x]}});this.logger.debug("Queued import job for file change",{jobId:c,path:x})},this.handleDelete=async(x)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:x});return}try{let{entityType:c,id:I}=this.fileOperations.parseEntityFromPath(x),$=await w({type:"directory-delete",data:{entityId:I,entityType:c,filePath:x}});this.logger.info("Queued delete job for removed file",{jobId:$,path:x,entityId:I,entityType:c})}catch(c){this.logger.warn("Could not extract entity info from deleted file",{path:x,error:c})}};else this.handleImport=async(x)=>{await f([x])},this.handleDelete=async(x)=>{this.logger.warn("File deleted but no job queue available",{path:x})}}async handleFileChange(A,f){this.logger.debug("Processing file change",{event:A,path:f});try{switch(A){case"add":case"change":await this.handleImport(f);break;case"delete":case"unlink":await this.handleDelete(f);break;default:this.logger.debug("Unhandled file event",{event:A,path:f})}}catch(w){this.logger.error("Failed to handle file change",{event:A,path:f,error:w})}}}YA();async function Ir(A,f,w,Q){let{sourceUrl:B}=A,x=await f.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1});if(x[0])return Q.debug("Reusing existing image entity",{sourceUrl:B,imageId:x[0].id}),x[0].id;let c=await w(B),{base64:I}=pH(c),$=iX(I),u=rH(I);if(!$||!u)throw Error("Could not detect image format or dimensions");let Y=await f.createEntity({id:A.id,entityType:"image",content:c,metadata:{title:A.title,alt:A.alt,format:$,width:u.width,height:u.height,sourceUrl:B}});return Q.debug("Created image entity from URL",{sourceUrl:B,imageId:Y.entityId}),Y.entityId}var gV0=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.string().url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class tUA{entityService;fetcher;logger;constructor(A,f,w=Bc){this.entityService=A;this.fetcher=w;this.logger=f.child("FrontmatterImageConverter")}detectCoverImageUrl(A){let f;try{f=E7(A)}catch{return null}let{frontmatter:w}=f,Q=gV0.safeParse(w);if(!Q.success)return null;if(Q.data.coverImageId)return null;let{title:B,slug:x,coverImageUrl:c,coverImageAlt:I}=Q.data;if(!jD(c))return null;return{sourceUrl:c,postTitle:B,postSlug:x??x2(B),customAlt:I}}async convert(A){let f;try{f=E7(A)}catch(u){return this.logger.debug("Parse failed",{error:u}),{content:A,converted:!1}}let{frontmatter:w}=f,Q=gV0.safeParse(w);if(!Q.success)return{content:A,converted:!1};if(Q.data.coverImageId)return{content:A,converted:!1};let{title:B,slug:x,coverImageUrl:c,coverImageAlt:I}=Q.data;if(!jD(c))return{content:A,converted:!1};let $={postTitle:B,postSlug:x??x2(B),sourceUrl:c,customAlt:I};try{let u=await this.createImageEntity($),Y={...w};return delete Y.coverImageUrl,delete Y.coverImageAlt,Y.coverImageId=u,{content:_K(Y,f.content),converted:!0,imageId:u}}catch(u){return this.logger.warn("Failed to convert coverImageUrl",{url:c,error:h0(u)}),{content:A,converted:!1}}}async createImageEntity(A){let{postTitle:f,postSlug:w,sourceUrl:Q,customAlt:B}=A,x=`Cover image for ${f}`;return Ir({id:`${w}-cover`,title:x,alt:B??x,sourceUrl:Q},this.entityService,this.fetcher,this.logger)}}YA();class xi{entityService;fetcher;logger;constructor(A,f,w=Bc){this.entityService=A;this.fetcher=w;this.logger=f.child("MarkdownImageConverter")}detectInlineImages(A,f){let w=[],Q=Pg(A);for(let B of Q){if(!jD(B.url))continue;if(B.url.startsWith("entity://"))continue;let x=this.reconstructMarkdown(B);w.push({sourceUrl:B.url,alt:B.alt,originalMarkdown:x,postSlug:f})}return w}reconstructMarkdown(A){if(A.title)return`![${A.alt}](${A.url} "${A.title}")`;return`![${A.alt}](${A.url})`}async convert(A,f){let w=this.detectInlineImages(A,f);if(w.length===0)return{content:A,converted:!1,convertedCount:0};let Q=A,B=0,x=0;for(let c of w)try{let I=await this.createImageEntity(c,x++),$=`![${c.alt}](entity://image/${I})`;Q=Q.replace(c.originalMarkdown,$),B++,this.logger.debug("Converted inline image",{sourceUrl:c.sourceUrl,imageId:I})}catch(I){this.logger.warn("Failed to convert inline image",{sourceUrl:c.sourceUrl,error:h0(I)})}return{content:Q,converted:B>0,convertedCount:B}}async createImageEntity(A,f){let{sourceUrl:w,alt:Q,postSlug:B}=A;return Ir({id:`${B}-inline-${f}`,title:Q||`Inline image ${f+1} for ${B}`,alt:Q||"",sourceUrl:w},this.entityService,this.fetcher,this.logger)}}YA();import{rename as Ek2,appendFile as Lk2,readFile as qk2,writeFile as _k2,access as Vk2}from"fs/promises";import{join as PV0}from"path";class eUA{logger;syncPath;constructor(A,f){this.logger=A;this.syncPath=f}isValidationError(A){if(A instanceof X.ZodError)return!0;let f=h0(A);return f.includes("invalid_type")||f.includes("invalid_enum_value")||f.includes("Required")||f.includes("Invalid frontmatter")||f.includes("Unknown entity type")}async quarantineInvalidFile(A,f,w,Q){let B=Q(A),x=`${B}.invalid`;try{await Ek2(B,x),w.quarantined++,w.quarantinedFiles.push(A);let c=PV0(this.syncPath,".import-errors.log"),I=new Date().toISOString(),$=h0(f),u=`${I} - ${A}: ${$}
1929
1929
  \u2192 ${A}.invalid
1930
1930
 
1931
1931
  `;await Lk2(c,u),this.logger.warn("Quarantined invalid entity file",{originalPath:A,quarantinePath:`${A}.invalid`,error:$})}catch(c){this.logger.error("Failed to quarantine invalid file",{path:A,error:c}),w.failed++,w.errors.push({path:A,error:"Failed to quarantine invalid file"})}}async markAsRecoveredIfNeeded(A){let f=PV0(this.syncPath,".import-errors.log");try{await Vk2(f)}catch{return}try{let w=await qk2(f,"utf-8");if(w.includes(A)){let B=`${new Date().toISOString()} - [RECOVERED] ${A}
@@ -1951,7 +1951,7 @@ ${A.entityContent}`,wq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt
1951
1951
  *...and ${A.files.length-10} more files*`)}if(A.exists&&A.stats.totalFiles===0)f.push(`
1952
1952
  ## Getting Started
1953
1953
  `),f.push("Your sync directory is empty. Entities will be organized as follows:"),f.push("- Base entities: `/<entity-id>.md`"),f.push("- Other types: `/<entity-type>/<entity-id>.md`");return f.join(`
1954
- `)}}B0();class _r extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:qO0,jobTypeName:"directory-export"});this.context=f,this.directorySync=w}async process(A,f,w){this.logger.debug("Processing directory export job",{jobId:f,data:A});let Q=Date.now(),B={exported:0,failed:0,errors:[]};try{let x=A.entityTypes??this.context.entityService.getEntityTypes();this.logger.debug("Starting export",{jobId:f,entityTypes:x}),await w.report({message:`Starting export of ${x.length} entity types`,progress:0,total:x.length});for(let[c,I]of x.entries())await this.exportEntityType(I,A.batchSize??100,f,B),await w.report({message:`Exported ${c+1}/${x.length} entity types (${B.exported} entities)`,progress:c+1,total:x.length});return this.logger.debug("Directory export job completed",{jobId:f,exported:B.exported,failed:B.failed,duration:Date.now()-Q}),B}catch(x){throw this.logger.error("Directory export job failed",{jobId:f,error:x}),x}}async exportEntityType(A,f,w,Q){let B=0,x=!0;while(x){let c=await this.context.entityService.listEntities(A,{limit:f,offset:B});if(c.length===0){x=!1;break}let I=c.map(async($)=>{let u=await this.directorySync.processEntityExport($);if(u.success)Q.exported++;else Q.failed++,Q.errors.push({entityId:$.id,entityType:A,error:u.error??"Unknown error"});return u});await Promise.all(I),this.logger.debug("Export progress",{jobId:w,entityType:A,processed:B+c.length,exported:Q.exported,failed:Q.failed}),B+=f,x=c.length===f}}summarizeDataForLog(A){return{entityTypes:A.entityTypes??"all",batchSize:A.batchSize}}}B0();YA();R7();class Vr extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:LO0,jobTypeName:"directory-import"});this.context=f,this.directorySync=w}async process(A,f,w){this.logger.debug("Processing directory import job",{jobId:f,data:A});let Q=Date.now(),B={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]};try{let x=A.paths??await this.directorySync.getAllMarkdownFiles();this.logger.debug("Starting import",{jobId:f,totalFiles:x.length}),await w.report({message:`Starting import of ${x.length} files`,progress:0,total:x.length});let c=A.batchSize??100;for(let I=0;I<x.length;I+=c){let $=x.slice(I,I+c);await this.importBatch($,f,B,I,x.length);let u=Math.min(I+c,x.length);await w.report({message:`Imported ${u}/${x.length} files (${B.imported} successful, ${B.failed} failed)`,progress:u,total:x.length})}return this.logger.debug("Directory import job completed",{jobId:f,imported:B.imported,skipped:B.skipped,failed:B.failed,duration:Date.now()-Q}),B}catch(x){throw this.logger.error("Directory import job failed",{jobId:f,error:x}),x}}async importBatch(A,f,w,Q,B){let x=A.map(async(c)=>{try{let I=await this.directorySync.fileOps.readEntity(c);if(!this.context.entityService.getEntityTypes().includes(I.entityType))return w.skipped++,{success:!1,skipped:!0};try{let u=this.context.entityService.deserializeEntity(I.content,I.entityType),Y=await this.context.entityService.getEntity(I.entityType,I.id);if(Y){let F=new Date(Y.updated).getTime(),K=I.updated.getTime(),Z=IQ(I.content),k=Y.contentHash!==Z;if(F<K||k){let h={...Y,content:I.content,...u,id:I.id,entityType:I.entityType,updated:I.updated.toISOString()};await this.context.entityService.updateEntity(h),w.imported++}else w.skipped++}else{let F={id:I.id,entityType:I.entityType,content:I.content,...u,metadata:u.metadata??{},created:I.created.toISOString(),updated:I.updated.toISOString()};await this.context.entityService.createEntity(F),w.imported++}return{success:!0}}catch{return w.skipped++,{success:!1,skipped:!0}}}catch(I){return w.failed++,w.errors.push({path:c,error:h0(I)}),{success:!1,error:I}}});await Promise.all(x),this.logger.debug("Import progress",{jobId:f,processed:Q+A.length,total:B,imported:w.imported,skipped:w.skipped,failed:w.failed})}summarizeDataForLog(A){return{pathCount:A.paths?.length??"all",batchSize:A.batchSize}}}B0();class ir extends Vw{directorySync;context;constructor(A,f,w){super(A,{schema:EO0,jobTypeName:"directory-sync"});this.context=f,this.directorySync=w}async process(A,f,w){let Q=Date.now(),B=A.syncDirection??"both";this.logger.info("Starting directory sync job",{jobId:f,operation:A.operation,syncDirection:B});let x={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},c={exported:0,failed:0,errors:[]};if(B!=="export")if(await w.report({progress:10,message:"Scanning directory for changes"}),x=await this.importWithProgress(A.paths,w),B==="import")await this.waitForImportJobs(x.jobIds,w),await w.report({progress:100,message:`Import complete: ${x.imported} imported`});else await w.report({progress:50,message:`Imported ${x.imported} entities`}),await this.waitForImportJobs(x.jobIds,w),await w.report({progress:56,message:"Processing complete, starting export"});if(B!=="import"){let $=B==="export"?10:60;await w.report({progress:$,message:"Exporting entities to directory"}),c=await this.exportWithProgress(A.entityTypes,w),await w.report({progress:100,message:B==="export"?`Export complete: ${c.exported} exported`:`Sync complete: ${x.imported} imported, ${c.exported} exported`})}let I=Date.now()-Q;return this.logger.info("Directory sync job completed",{jobId:f,duration:I,imported:x.imported,exported:c.exported}),{import:x,export:c,duration:I}}async importWithProgress(A,f){try{return await this.directorySync.importEntitiesWithProgress(A,f,10)}catch(w){throw this.logger.error("Import phase failed",{error:w}),w}}async exportWithProgress(A,f){try{return await this.directorySync.exportEntitiesWithProgress(A,f,10)}catch(w){throw this.logger.error("Export phase failed",{error:w}),w}}async waitForImportJobs(A,f){if(A.length===0)return;this.logger.debug(`Waiting for ${A.length} import jobs to complete`);let{entityService:w}=this.context,Q=300000,B=500,x=Date.now(),c=async()=>{let $=(await Promise.all(A.map((Y)=>w.getAsyncJobStatus(Y)))).filter((Y)=>Y&&(Y.status==="completed"||Y.status==="failed")).length;if($===A.length){this.logger.debug("All import jobs completed");return}if(Date.now()-x>Q){this.logger.warn(`Timeout waiting for import jobs (${$}/${A.length} completed)`);return}let u=Math.round($/A.length*100);return await f.report({progress:50+Math.round(u*0.05),message:`Processing ${$}/${A.length} entities`}),await new Promise((Y)=>setTimeout(Y,B)),c()};return c()}summarizeDataForLog(A){return{operation:A.operation,syncDirection:A.syncDirection}}}B0();class Mr extends Vw{context;constructor(A,f,w){super(A,{schema:dFA,jobTypeName:"directory-delete"});this.context=f}async process(A,f,w){let Q=dFA.parse(A);this.logger.info("Processing entity deletion for removed file",{entityId:Q.entityId,entityType:Q.entityType,filePath:Q.filePath}),await w.report({progress:0,total:1,message:`Deleting ${Q.entityType}:${Q.entityId}`});try{let B=await this.context.entityService.deleteEntity(Q.entityType,Q.entityId);if(B)this.logger.info("Successfully deleted entity for removed file",{entityId:Q.entityId,entityType:Q.entityType});else this.logger.warn("Entity not found in database",{entityId:Q.entityId,entityType:Q.entityType});return await w.report({progress:1,total:1,message:`Deleted ${Q.entityType}:${Q.entityId}`}),{deleted:B,entityId:Q.entityId,entityType:Q.entityType,filePath:Q.filePath}}catch(B){throw this.logger.error("Failed to delete entity",{entityId:Q.entityId,entityType:Q.entityType,error:B}),B}}summarizeDataForLog(A){return{entityId:A.entityId,entityType:A.entityType,filePath:A.filePath}}}B0();YA();var Fb2=X.object({});class Or extends Vw{directorySync;constructor(A,f){super(A,{schema:Fb2,jobTypeName:"directory-cleanup"});this.directorySync=f}async process(A,f,w){await w.report({progress:0,message:"Removing orphaned entities"});let Q=await this.directorySync.removeOrphanedEntities();return await w.report({progress:100,message:`Cleanup complete: ${Q.deleted} orphans removed`}),Q}}B0();YA();import{readFile as Kb2,writeFile as Xb2}from"fs/promises";var Zb2=X.object({filePath:X.string(),sourceUrl:X.string().url(),postTitle:X.string(),postSlug:X.string(),customAlt:X.string().optional()});class jr extends Vw{context;fetcher;constructor(A,f,w=Bc){super(f,{schema:Zb2,jobTypeName:"cover-image-convert"});this.context=A,this.fetcher=w}async process(A,f,w){let{filePath:Q,sourceUrl:B,postTitle:x,postSlug:c,customAlt:I}=A;this.logger.debug("Starting image conversion job",{jobId:f,filePath:Q,sourceUrl:B,postSlug:c});try{await this.reportProgress(w,{progress:F2.INIT,message:`Reading file: ${Q}`});let $;try{$=await Kb2(Q,"utf-8")}catch(h){return this.logger.error("Failed to read file",{filePath:Q,error:h0(h)}),h8.failure(h)}let u;try{u=E7($)}catch(h){return this.logger.warn("Failed to parse markdown",{filePath:Q,error:h0(h)}),h8.failure(h)}let Y=u.frontmatter;if(Y.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:Q}),await this.reportProgress(w,{progress:F2.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(w,{progress:F2.FETCH,message:"Checking for existing image"});let F=await this.context.entityService.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1}),K;if(F[0])K=F[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:B,imageId:K}),await this.reportProgress(w,{progress:F2.EXTRACT,message:`Reusing existing image: ${K}`});else{await this.reportProgress(w,{progress:F2.PROCESS,message:`Fetching image from ${B}`});let h;try{h=await this.fetcher(B)}catch(r){return this.logger.error("Failed to fetch image",{sourceUrl:B,error:h0(r)}),h8.failure(r)}await this.reportProgress(w,{progress:F2.GENERATE,message:"Creating image entity"});let{base64:G}=pH(h),E=iX(G),V=rH(G);if(!E||!V)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:B}),h8.failure(Error("Could not detect image format or dimensions"));K=`${c}-cover`;let q=`Cover image for ${x}`,y=I??q;await this.context.entityService.createEntity({id:K,entityType:"image",content:h,metadata:{title:q,alt:y,format:E,width:V.width,height:V.height,sourceUrl:B}}),this.logger.debug("Created image entity",{imageId:K,sourceUrl:B}),await this.reportProgress(w,{progress:F2.EXTRACT,message:`Created image: ${K}`})}await this.reportProgress(w,{progress:F2.SAVE,message:"Updating file"});let Z={...Y};delete Z.coverImageUrl,delete Z.coverImageAlt,Z.coverImageId=K;let k=_K(Z,u.content);try{await Xb2(Q,k,"utf-8")}catch(h){return this.logger.error("Failed to write file",{filePath:Q,error:h0(h)}),h8.failure(h)}return await this.reportProgress(w,{progress:F2.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:Q,imageId:K,sourceUrl:B}),{success:!0,imageId:K}}catch($){return this.logger.error("Image conversion job failed",{jobId:f,filePath:Q,error:h0($)}),h8.failure($)}}summarizeDataForLog(A){return{filePath:A.filePath,sourceUrl:A.sourceUrl,postSlug:A.postSlug}}}B0();YA();import{readFile as vb2,writeFile as Wb2}from"fs/promises";class gr extends Vw{converter;constructor(A,f,w=Bc){super(f,{schema:_O0,jobTypeName:"inline-image-convert"});this.converter=new xi(A.entityService,f,w)}async process(A,f,w){let{filePath:Q,postSlug:B}=A;this.logger.debug("Starting inline image conversion job",{jobId:f,filePath:Q,postSlug:B});try{await this.reportProgress(w,{progress:F2.INIT,message:`Reading file: ${Q}`});let x;try{x=await vb2(Q,"utf-8")}catch($){let u=h0($);return this.logger.error("Failed to read file",{filePath:Q,error:u}),{success:!1,error:u}}await this.reportProgress(w,{progress:F2.FETCH,message:"Detecting inline images"});let c=this.converter.detectInlineImages(x,B);if(c.length===0)return this.logger.debug("No inline images to convert",{filePath:Q}),await this.reportProgress(w,{progress:F2.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:Q,count:c.length}),await this.reportProgress(w,{progress:F2.PROCESS,message:`Converting ${c.length} images`});let I=await this.converter.convert(x,B);if(!I.converted)return this.logger.debug("No images were converted",{filePath:Q}),await this.reportProgress(w,{progress:F2.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(w,{progress:F2.SAVE,message:"Writing updated file"});try{await Wb2(Q,I.content,"utf-8")}catch($){let u=h0($);return this.logger.error("Failed to write file",{filePath:Q,error:u}),{success:!1,error:u}}return await this.reportProgress(w,{progress:F2.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:Q,convertedCount:I.convertedCount}),{success:!0,convertedCount:I.convertedCount}}catch(x){let c=h0(x);return this.logger.error("Inline image conversion job failed",{jobId:f,filePath:Q,error:c}),{success:!1,error:c}}}summarizeDataForLog(A){return{filePath:A.filePath,postSlug:A.postSlug}}}function MO0(A,f,w){let Q=(B)=>w.child(B);A.jobs.registerHandler("directory-sync",new ir(Q("DirectorySyncJobHandler"),A,f)),A.jobs.registerHandler("directory-export",new _r(Q("DirectoryExportJobHandler"),A,f)),A.jobs.registerHandler("directory-import",new Vr(Q("DirectoryImportJobHandler"),A,f)),A.jobs.registerHandler("directory-delete",new Mr(Q("DirectoryDeleteJobHandler"),A,f)),A.jobs.registerHandler("directory-cleanup",new Or(Q("DirectoryCleanupJobHandler"),f)),A.jobs.registerHandler("cover-image-convert",new jr(A,Q("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new gr(A,Q("InlineImageConversionJobHandler"))),w.debug("Registered async job handlers")}B0();import{unlink as kb2,access as hb2}from"fs/promises";function OO0(A,f,w,Q){let{subscribe:B}=A.messaging,{entityService:x}=A;B("entity:created",async(c)=>{let{entity:I}=c.payload;try{await f.fileOps.writeEntity(I),w.debug("Auto-exported created entity",{id:I.id,entityType:I.entityType})}catch($){w.error("Auto-export FAILED for created entity",{id:I.id,entityType:I.entityType,error:$ instanceof Error?$.message:String($),stack:$ instanceof Error?$.stack:void 0})}return{success:!0}}),B("entity:updated",async(c)=>{let{entityType:I,entityId:$}=c.payload;try{let u=await x.getEntity(I,$);if(!u)return w.debug("Entity not found in DB, skipping export",{entityType:I,entityId:$}),{success:!1};await f.fileOps.writeEntity(u),w.debug("Auto-exported updated entity",{id:u.id,entityType:u.entityType})}catch(u){w.error("Auto-export FAILED for updated entity",{entityType:I,entityId:$,error:u instanceof Error?u.message:String(u),stack:u instanceof Error?u.stack:void 0})}return{success:!0}}),B("entity:deleted",async(c)=>{let{entityId:I,entityType:$}=c.payload,u=f.fileOps.getFilePath(I,$);if(await hb2(u).then(()=>!0,()=>!1))await kb2(u),w.debug("Auto-deleted entity file",{id:I,entityType:$,path:u});return{success:!0}}),w.debug("Setup auto-sync for entity events",{entityTypes:Q})}function jO0(A,f,w){f.setJobQueueCallback(async(Q)=>{let B=[{type:Q.type,data:Q.data}];return A.jobs.enqueueBatch(B,{priority:5,source:"directory-sync-watcher",rootJobId:l8(),metadata:{operationType:"file_operations",operationTarget:w,pluginId:"directory-sync"}})})}YA();import{access as Gb2,readdir as gO0,mkdir as Jb2,copyFile as bb2}from"fs/promises";import{exec as zb2}from"child_process";import{promisify as Nb2}from"util";import{join as aFA,resolve as oFA}from"path";var Cb2=Nb2(zb2);async function Pr(A){try{return await Gb2(A),!0}catch{return!1}}async function Eb2(A,f){if(!await Pr(A))return!0;if((await gO0(A)).filter((B)=>!B.startsWith(".")&&!B.startsWith("_")).length>0)return!1;if(await Lb2(A))return f.debug("Git repository with remote detected - skipping seed content",{path:A}),!1;return!0}async function Lb2(A){let f=aFA(A,".git");if(!await Pr(f))return!1;try{let{stdout:w}=await Cb2("git remote",{cwd:A});return w.trim().length>0}catch{return!1}}async function PO0(A,f){let w=await gO0(A,{withFileTypes:!0});for(let Q of w){let B=aFA(A,Q.name),x=aFA(f,Q.name);if(Q.isDirectory()){if(!await Pr(x))await Jb2(x,{recursive:!0});await PO0(B,x)}else await bb2(B,x)}}async function RO0(A,f,w){let Q=oFA(process.cwd(),A);w=w?oFA(w):oFA(process.cwd(),"seed-content");let B=await Eb2(Q,f);if(B&&await Pr(w))f.debug("Copying seed content to brain-data directory"),await PO0(w,Q),f.debug("Seed content copied successfully");else if(B)f.debug("No seed content directory found, starting with empty brain-data");else f.debug("brain-data directory not empty, skipping seed content")}async function qb2(A,f,w,Q=300000){let x=Date.now();while(Date.now()-x<Q){let c=await A.jobs.getBatchStatus(f);if(c&&(c.status==="completed"||c.status==="failed")){w.debug("Batch completed",{batchId:f,status:c.status,completed:c.completedOperations,failed:c.failedOperations});return}await new Promise((I)=>setTimeout(I,500))}w.warn(`Timeout waiting for batch ${f} after ${Q}ms`)}function nO0(A,f,w,Q,B,x){let c=!1,I=async()=>{if(c)return;c=!0;let $=f();if(w.seedContent){let u=w.syncPath??A.dataDir;await RO0(u,B,w.seedContentPath)}try{if(x){B.debug("Git enabled \u2014 pulling before import");let Y=await x.pull();if(Y.files.length>0)B.info("Pulled changes from remote",{filesChanged:Y.files.length})}B.debug("Starting initial sync");let u=await $.queueSyncBatch(A,"initial-sync",void 0,{includeCleanup:!0});if(!u){B.debug("Initial sync: no files to import"),await A.messaging.send("sync:initial:completed",{success:!0},{broadcast:!0});return}B.debug("Initial sync: queued imports",{importOperations:u.importOperationsCount,totalFiles:u.totalFiles}),qb2(A,u.batchId,B).then(()=>A.messaging.send("sync:initial:completed",{success:!0},{broadcast:!0}),(Y)=>{B.error("Initial sync batch failed",Y),A.messaging.send("sync:initial:completed",{success:!1,error:h0(Y)},{broadcast:!0})})}catch(u){B.error("Initial sync failed",u),await A.messaging.send("sync:initial:completed",{success:!1,error:h0(u)},{broadcast:!0})}};A.messaging.subscribe("system:plugins:ready",async()=>{return B.debug("system:plugins:ready received, starting initial sync"),await I(),{success:!0}})}YA();function mO0(A,f,w,Q){let B=new jK(()=>{f.withLock(async()=>{try{await f.commit(),await f.push()}catch(I){Q.error("Git auto-commit failed",{error:I})}})},w),x=["entity:created","entity:updated","entity:deleted"],c=[];for(let I of x){let $=A.subscribe(I,async()=>{return B.trigger(),{success:!0}});c.push($)}return()=>{B.dispose();for(let I of c)I()}}function lO0(A,f,w,Q,B){if(Q<=0)return()=>{};let x=Q*60*1000,c=!1,I=async()=>{if(c)return;c=!0;try{let{files:u}=await A.withLock(()=>A.pull());if(u.length>0)B.info("Periodic sync: pulled changes",{filesChanged:u.length});let Y=await f.queueSyncBatch(w,"periodic-sync");if(Y)B.debug("Periodic sync: queued imports",{importOperations:Y.importOperationsCount,totalFiles:Y.totalFiles})}catch(u){B.error("Periodic git sync failed",{error:u})}finally{c=!1}},$=setInterval(()=>{I()},x);return B.info("Started periodic git sync",{intervalMinutes:Q}),()=>{clearInterval($)}}function TO0(A,f,w,Q,B){let{subscribe:x}=A.messaging;x("entity:export:request",async(c)=>{try{return{success:!0,data:await f().exportEntities(c.payload.entityTypes)}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Export failed"}}}),x("entity:import:request",async(c)=>{try{let I=f(),$=c.payload.paths,u=await I.importEntities($);if($&&$.length>0)await I.removeOrphanedEntities();return{success:!0,data:u}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Import failed"}}}),x("sync:status:request",async()=>{try{let I=await f().getStatus();return{success:!0,data:{syncPath:I.syncPath,isInitialized:I.exists,watchEnabled:I.watching}}}catch(c){return{success:!1,error:c instanceof Error?c.message:"Status check failed"}}}),x("sync:configure:request",async(c)=>{try{return await w({syncPath:c.payload.syncPath}),{success:!0,data:{syncPath:c.payload.syncPath,configured:!0}}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Configuration failed"}}}),x("git-sync:get-repo-info",async()=>{if(!B?.repo)return{success:!1,error:"Git not configured"};return{success:!0,data:{repo:B.repo,branch:B.branch??"main"}}}),Q.debug("Registered message handlers")}B0();YA();B0();YA();function yO0(A,f){return Tf(A,"history","Get version history for an entity from git. Without sha: returns commit list. With sha: returns entity content at that version.",X.object({entityType:X.string().describe("Entity type (e.g. post, note, link)"),id:X.string().describe("Entity ID"),sha:X.string().optional().describe("Commit SHA to retrieve content at. Omit to list commit history."),limit:X.number().int().positive().optional().default(10).describe("Max commits to return (list mode only)")}),async(w)=>{let Q=`${w.entityType}/${w.id}.md`;try{if(w.sha){let x=await f.show(w.sha,Q);return mB({sha:w.sha,entityType:w.entityType,id:w.id,content:x},`Content at ${w.sha.slice(0,7)}`)}let B=await f.log(Q,w.limit);if(B.length===0)return mB({commits:[]},`No history found for ${w.entityType}/${w.id}`);return mB({commits:B,entityType:w.entityType,id:w.id},`${B.length} version${B.length===1?"":"s"} found`)}catch(B){return r6(B instanceof Error?B.message:"History lookup failed")}})}function SO0(A,f,w,Q){let B=[Tf(w,"sync","Sync brain entities with the filesystem. Pulls from git if configured, then imports files. Git commit and push happen automatically after imports complete.",X.object({}),async(x,c)=>{try{let I=c.channelId?`${c.interfaceType}:${c.channelId}`:`plugin:${w}`,$={interfaceType:c.interfaceType,channelId:c.channelId},u=!1;if(Q)await Q.withLock(()=>Q.pull()),u=!0;let Y=await A.queueSyncBatch(f,I,$);if(!Y)return mB({gitPulled:u},"No files to sync");return mB({batchId:Y.batchId,importOperations:Y.importOperationsCount,totalFiles:Y.totalFiles,gitPulled:u},`Sync started: ${Y.importOperationsCount} import jobs queued for ${Y.totalFiles} files${u?" (pulled from git)":""}`)}catch(I){return r6(I instanceof Error?I.message:"Sync failed")}},{cli:{name:"sync"}}),Tf(w,"status","Get sync and git repository status \u2014 last sync time, watching state, pending git changes.",X.object({}),async()=>{try{let x=await A.getStatus(),c={syncPath:x.syncPath,lastSync:x.lastSync?.toISOString(),watching:x.watching};if(Q){let I=await Q.getStatus();c.git={isRepo:I.isRepo,branch:I.branch,hasChanges:I.hasChanges,ahead:I.ahead,behind:I.behind,remote:I.remote}}return mB(c)}catch(x){return r6(x instanceof Error?x.message:"Status check failed")}},{visibility:"public"})];if(Q)B.push(yO0(w,Q));return B}var pO0={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.8",description:"Directory-based entity synchronization plugin for Brains",type:"module",main:"./src/index.ts",types:"./src/index.ts",exports:{".":{types:"./src/index.ts",import:"./src/index.ts"}},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",clean:"rm -rf .turbo"},dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",chokidar:"^3.5.3","simple-git":"^3.21.0"},devDependencies:{"@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"},peerDependencies:{}};class sFA extends yQ{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",pO0,A,CO0)}requireDirectorySync(){if(!this.directorySync)throw Error("DirectorySync service not initialized");return this.directorySync}hasGitSync(){return this.gitSync!==void 0}async onRegister(A){let{logger:f,entityService:w}=A;A.templates.register({status:{name:"status",description:"Directory synchronization status",schema:Xi,basePrompt:"",formatter:new qr,requiredPermission:"anchor"}});let Q=this.config.syncPath??A.dataDir;this.directorySync=new ci({syncPath:Q,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:w,logger:f});try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:Q})}catch(c){throw this.logger.error("Failed to initialize directory",c),c}await this.registerJobHandlers(A);let B=this.requireDirectorySync();if(OO0(A,B,this.logger,this.config.entityTypes),this.config.autoSync)jO0(A,B,this.config.syncPath??A.dataDir);let x=this.config.git!==void 0&&(this.config.git.repo!==void 0||this.config.git.gitUrl!==void 0);if(this.config.git&&!x)this.logger.debug("Git block present but no repo/gitUrl configured \u2014 git sync disabled");if(x&&this.config.git){let c=this.config.syncPath??A.dataDir;if(this.gitSync=new rFA({logger:this.logger.child("GitSync"),dataDir:c,repo:this.config.git.repo,gitUrl:this.config.git.gitUrl,branch:this.config.git.branch,authToken:this.config.git.authToken,authorName:this.config.git.authorName,authorEmail:this.config.git.authorEmail}),await this.gitSync.initialize(),this.logger.info("Git integration enabled",{repo:this.config.git.repo}),this.gitCleanups.push(mO0(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push(lO0(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)nO0(A,()=>this.requireDirectorySync(),this.config,this.id,this.logger,this.gitSync);TO0(A,()=>this.requireDirectorySync(),(c)=>this.configure(c),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return SO0(A,this.getContext(),this.id,this.gitSync)}async onShutdown(){for(let A of this.gitCleanups)A();this.gitCleanups=[],this.directorySync?.stopWatching(),this.gitSync?.cleanup()}getDirectorySync(){return this.directorySync}async configure(A){this.requireDirectorySync();let f=this.getContext();this.directorySync=new ci({...this.config,syncPath:A.syncPath,entityService:f.entityService,logger:f.logger}),await this.directorySync.initialize(),this.logger.info("Directory sync reconfigured",{path:A.syncPath})}async registerJobHandlers(A){MO0(A,this.requireDirectorySync(),this.logger)}}function rZ(A={}){return new sFA(A)}B0();B0();YA();YA();var rO0=X.object({environment:X.enum(["preview","production"]),outputDir:X.string(),workingDir:X.string().optional(),sharedImagesDir:X.string().default("./dist/images"),enableContentGeneration:X.boolean().default(!1),cleanBeforeBuild:X.boolean().default(!0),siteConfig:X.object({title:X.string(),description:X.string(),url:X.string().optional(),copyright:X.string().optional(),themeMode:X.enum(["light","dark"]).optional(),analyticsScript:X.string().optional()}),layouts:X.record(X.any()),themeCSS:X.string().optional()}),s5w=X.object({success:X.boolean(),outputDir:X.string(),filesGenerated:X.number(),routesBuilt:X.number(),errors:X.array(X.string()).optional(),warnings:X.array(X.string()).optional()});import{render as kS0}from"preact-render-to-string";import{h as Wv}from"preact";class tFA{headProps=null;defaultTitle;constructor(A){this.defaultTitle=A}setHeadProps(A){this.headProps??=A}getHeadProps(){return this.headProps}reset(){this.headProps=null}generateHeadHTML(){let A=[];if(A.push('<meta charset="UTF-8">'),A.push('<meta name="viewport" content="width=device-width, initial-scale=1.0">'),A.push('<meta http-equiv="X-UA-Compatible" content="IE=edge">'),A.push('<link rel="icon" type="image/svg+xml" href="/favicon.svg">'),A.push('<link rel="icon" type="image/png" href="/favicon.png">'),A.push('<link rel="stylesheet" href="/styles/main.css">'),!this.headProps)return A.push(`<title>${this.escapeHtml(this.defaultTitle)}</title>`),A.join(`
1954
+ `)}}B0();class _r extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:qO0,jobTypeName:"directory-export"});this.context=f,this.directorySync=w}async process(A,f,w){this.logger.debug("Processing directory export job",{jobId:f,data:A});let Q=Date.now(),B={exported:0,failed:0,errors:[]};try{let x=A.entityTypes??this.context.entityService.getEntityTypes();this.logger.debug("Starting export",{jobId:f,entityTypes:x}),await w.report({message:`Starting export of ${x.length} entity types`,progress:0,total:x.length});for(let[c,I]of x.entries())await this.exportEntityType(I,A.batchSize??100,f,B),await w.report({message:`Exported ${c+1}/${x.length} entity types (${B.exported} entities)`,progress:c+1,total:x.length});return this.logger.debug("Directory export job completed",{jobId:f,exported:B.exported,failed:B.failed,duration:Date.now()-Q}),B}catch(x){throw this.logger.error("Directory export job failed",{jobId:f,error:x}),x}}async exportEntityType(A,f,w,Q){let B=0,x=!0;while(x){let c=await this.context.entityService.listEntities(A,{limit:f,offset:B});if(c.length===0){x=!1;break}let I=c.map(async($)=>{let u=await this.directorySync.processEntityExport($);if(u.success)Q.exported++;else Q.failed++,Q.errors.push({entityId:$.id,entityType:A,error:u.error??"Unknown error"});return u});await Promise.all(I),this.logger.debug("Export progress",{jobId:w,entityType:A,processed:B+c.length,exported:Q.exported,failed:Q.failed}),B+=f,x=c.length===f}}summarizeDataForLog(A){return{entityTypes:A.entityTypes??"all",batchSize:A.batchSize}}}B0();YA();R7();class Vr extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:LO0,jobTypeName:"directory-import"});this.context=f,this.directorySync=w}async process(A,f,w){this.logger.debug("Processing directory import job",{jobId:f,data:A});let Q=Date.now(),B={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]};try{let x=A.paths??await this.directorySync.getAllMarkdownFiles();this.logger.debug("Starting import",{jobId:f,totalFiles:x.length}),await w.report({message:`Starting import of ${x.length} files`,progress:0,total:x.length});let c=A.batchSize??100;for(let I=0;I<x.length;I+=c){let $=x.slice(I,I+c);await this.importBatch($,f,B,I,x.length);let u=Math.min(I+c,x.length);await w.report({message:`Imported ${u}/${x.length} files (${B.imported} successful, ${B.failed} failed)`,progress:u,total:x.length})}return this.logger.debug("Directory import job completed",{jobId:f,imported:B.imported,skipped:B.skipped,failed:B.failed,duration:Date.now()-Q}),B}catch(x){throw this.logger.error("Directory import job failed",{jobId:f,error:x}),x}}async importBatch(A,f,w,Q,B){let x=A.map(async(c)=>{try{let I=await this.directorySync.fileOps.readEntity(c);if(!this.context.entityService.getEntityTypes().includes(I.entityType))return w.skipped++,{success:!1,skipped:!0};try{let u=this.context.entityService.deserializeEntity(I.content,I.entityType),Y=await this.context.entityService.getEntity(I.entityType,I.id);if(Y){let F=new Date(Y.updated).getTime(),K=I.updated.getTime(),Z=IQ(I.content),k=Y.contentHash!==Z;if(F<K||k){let h={...Y,content:I.content,...u,id:I.id,entityType:I.entityType,updated:I.updated.toISOString()};await this.context.entityService.updateEntity(h),w.imported++}else w.skipped++}else{let F={id:I.id,entityType:I.entityType,content:I.content,...u,metadata:u.metadata??{},created:I.created.toISOString(),updated:I.updated.toISOString()};await this.context.entityService.createEntity(F),w.imported++}return{success:!0}}catch{return w.skipped++,{success:!1,skipped:!0}}}catch(I){return w.failed++,w.errors.push({path:c,error:h0(I)}),{success:!1,error:I}}});await Promise.all(x),this.logger.debug("Import progress",{jobId:f,processed:Q+A.length,total:B,imported:w.imported,skipped:w.skipped,failed:w.failed})}summarizeDataForLog(A){return{pathCount:A.paths?.length??"all",batchSize:A.batchSize}}}B0();class ir extends Vw{directorySync;context;constructor(A,f,w){super(A,{schema:EO0,jobTypeName:"directory-sync"});this.context=f,this.directorySync=w}async process(A,f,w){let Q=Date.now(),B=A.syncDirection??"both";this.logger.info("Starting directory sync job",{jobId:f,operation:A.operation,syncDirection:B});let x={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},c={exported:0,failed:0,errors:[]};if(B!=="export")if(await w.report({progress:10,message:"Scanning directory for changes"}),x=await this.importWithProgress(A.paths,w),B==="import")await this.waitForImportJobs(x.jobIds,w),await w.report({progress:100,message:`Import complete: ${x.imported} imported`});else await w.report({progress:50,message:`Imported ${x.imported} entities`}),await this.waitForImportJobs(x.jobIds,w),await w.report({progress:56,message:"Processing complete, starting export"});if(B!=="import"){let $=B==="export"?10:60;await w.report({progress:$,message:"Exporting entities to directory"}),c=await this.exportWithProgress(A.entityTypes,w),await w.report({progress:100,message:B==="export"?`Export complete: ${c.exported} exported`:`Sync complete: ${x.imported} imported, ${c.exported} exported`})}let I=Date.now()-Q;return this.logger.info("Directory sync job completed",{jobId:f,duration:I,imported:x.imported,exported:c.exported}),{import:x,export:c,duration:I}}async importWithProgress(A,f){try{return await this.directorySync.importEntitiesWithProgress(A,f,10)}catch(w){throw this.logger.error("Import phase failed",{error:w}),w}}async exportWithProgress(A,f){try{return await this.directorySync.exportEntitiesWithProgress(A,f,10)}catch(w){throw this.logger.error("Export phase failed",{error:w}),w}}async waitForImportJobs(A,f){if(A.length===0)return;this.logger.debug(`Waiting for ${A.length} import jobs to complete`);let{entityService:w}=this.context,Q=300000,B=500,x=Date.now(),c=async()=>{let $=(await Promise.all(A.map((Y)=>w.getAsyncJobStatus(Y)))).filter((Y)=>Y&&(Y.status==="completed"||Y.status==="failed")).length;if($===A.length){this.logger.debug("All import jobs completed");return}if(Date.now()-x>Q){this.logger.warn(`Timeout waiting for import jobs (${$}/${A.length} completed)`);return}let u=Math.round($/A.length*100);return await f.report({progress:50+Math.round(u*0.05),message:`Processing ${$}/${A.length} entities`}),await new Promise((Y)=>setTimeout(Y,B)),c()};return c()}summarizeDataForLog(A){return{operation:A.operation,syncDirection:A.syncDirection}}}B0();class Mr extends Vw{context;constructor(A,f,w){super(A,{schema:dFA,jobTypeName:"directory-delete"});this.context=f}async process(A,f,w){let Q=dFA.parse(A);this.logger.info("Processing entity deletion for removed file",{entityId:Q.entityId,entityType:Q.entityType,filePath:Q.filePath}),await w.report({progress:0,total:1,message:`Deleting ${Q.entityType}:${Q.entityId}`});try{let B=await this.context.entityService.deleteEntity(Q.entityType,Q.entityId);if(B)this.logger.info("Successfully deleted entity for removed file",{entityId:Q.entityId,entityType:Q.entityType});else this.logger.warn("Entity not found in database",{entityId:Q.entityId,entityType:Q.entityType});return await w.report({progress:1,total:1,message:`Deleted ${Q.entityType}:${Q.entityId}`}),{deleted:B,entityId:Q.entityId,entityType:Q.entityType,filePath:Q.filePath}}catch(B){throw this.logger.error("Failed to delete entity",{entityId:Q.entityId,entityType:Q.entityType,error:B}),B}}summarizeDataForLog(A){return{entityId:A.entityId,entityType:A.entityType,filePath:A.filePath}}}B0();YA();var Fb2=X.object({});class Or extends Vw{directorySync;constructor(A,f){super(A,{schema:Fb2,jobTypeName:"directory-cleanup"});this.directorySync=f}async process(A,f,w){await w.report({progress:0,message:"Removing orphaned entities"});let Q=await this.directorySync.removeOrphanedEntities();return await w.report({progress:100,message:`Cleanup complete: ${Q.deleted} orphans removed`}),Q}}B0();YA();import{readFile as Kb2,writeFile as Xb2}from"fs/promises";var Zb2=X.object({filePath:X.string(),sourceUrl:X.string().url(),postTitle:X.string(),postSlug:X.string(),customAlt:X.string().optional()});class jr extends Vw{context;fetcher;constructor(A,f,w=Bc){super(f,{schema:Zb2,jobTypeName:"cover-image-convert"});this.context=A,this.fetcher=w}async process(A,f,w){let{filePath:Q,sourceUrl:B,postTitle:x,postSlug:c,customAlt:I}=A;this.logger.debug("Starting image conversion job",{jobId:f,filePath:Q,sourceUrl:B,postSlug:c});try{await this.reportProgress(w,{progress:F2.INIT,message:`Reading file: ${Q}`});let $;try{$=await Kb2(Q,"utf-8")}catch(h){return this.logger.error("Failed to read file",{filePath:Q,error:h0(h)}),h8.failure(h)}let u;try{u=E7($)}catch(h){return this.logger.warn("Failed to parse markdown",{filePath:Q,error:h0(h)}),h8.failure(h)}let Y=u.frontmatter;if(Y.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:Q}),await this.reportProgress(w,{progress:F2.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(w,{progress:F2.FETCH,message:"Checking for existing image"});let F=await this.context.entityService.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1}),K;if(F[0])K=F[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:B,imageId:K}),await this.reportProgress(w,{progress:F2.EXTRACT,message:`Reusing existing image: ${K}`});else{await this.reportProgress(w,{progress:F2.PROCESS,message:`Fetching image from ${B}`});let h;try{h=await this.fetcher(B)}catch(r){return this.logger.error("Failed to fetch image",{sourceUrl:B,error:h0(r)}),h8.failure(r)}await this.reportProgress(w,{progress:F2.GENERATE,message:"Creating image entity"});let{base64:G}=pH(h),E=iX(G),V=rH(G);if(!E||!V)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:B}),h8.failure(Error("Could not detect image format or dimensions"));K=`${c}-cover`;let q=`Cover image for ${x}`,y=I??q;await this.context.entityService.createEntity({id:K,entityType:"image",content:h,metadata:{title:q,alt:y,format:E,width:V.width,height:V.height,sourceUrl:B}}),this.logger.debug("Created image entity",{imageId:K,sourceUrl:B}),await this.reportProgress(w,{progress:F2.EXTRACT,message:`Created image: ${K}`})}await this.reportProgress(w,{progress:F2.SAVE,message:"Updating file"});let Z={...Y};delete Z.coverImageUrl,delete Z.coverImageAlt,Z.coverImageId=K;let k=_K(Z,u.content);try{await Xb2(Q,k,"utf-8")}catch(h){return this.logger.error("Failed to write file",{filePath:Q,error:h0(h)}),h8.failure(h)}return await this.reportProgress(w,{progress:F2.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:Q,imageId:K,sourceUrl:B}),{success:!0,imageId:K}}catch($){return this.logger.error("Image conversion job failed",{jobId:f,filePath:Q,error:h0($)}),h8.failure($)}}summarizeDataForLog(A){return{filePath:A.filePath,sourceUrl:A.sourceUrl,postSlug:A.postSlug}}}B0();YA();import{readFile as vb2,writeFile as Wb2}from"fs/promises";class gr extends Vw{converter;constructor(A,f,w=Bc){super(f,{schema:_O0,jobTypeName:"inline-image-convert"});this.converter=new xi(A.entityService,f,w)}async process(A,f,w){let{filePath:Q,postSlug:B}=A;this.logger.debug("Starting inline image conversion job",{jobId:f,filePath:Q,postSlug:B});try{await this.reportProgress(w,{progress:F2.INIT,message:`Reading file: ${Q}`});let x;try{x=await vb2(Q,"utf-8")}catch($){let u=h0($);return this.logger.error("Failed to read file",{filePath:Q,error:u}),{success:!1,error:u}}await this.reportProgress(w,{progress:F2.FETCH,message:"Detecting inline images"});let c=this.converter.detectInlineImages(x,B);if(c.length===0)return this.logger.debug("No inline images to convert",{filePath:Q}),await this.reportProgress(w,{progress:F2.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:Q,count:c.length}),await this.reportProgress(w,{progress:F2.PROCESS,message:`Converting ${c.length} images`});let I=await this.converter.convert(x,B);if(!I.converted)return this.logger.debug("No images were converted",{filePath:Q}),await this.reportProgress(w,{progress:F2.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(w,{progress:F2.SAVE,message:"Writing updated file"});try{await Wb2(Q,I.content,"utf-8")}catch($){let u=h0($);return this.logger.error("Failed to write file",{filePath:Q,error:u}),{success:!1,error:u}}return await this.reportProgress(w,{progress:F2.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:Q,convertedCount:I.convertedCount}),{success:!0,convertedCount:I.convertedCount}}catch(x){let c=h0(x);return this.logger.error("Inline image conversion job failed",{jobId:f,filePath:Q,error:c}),{success:!1,error:c}}}summarizeDataForLog(A){return{filePath:A.filePath,postSlug:A.postSlug}}}function MO0(A,f,w){let Q=(B)=>w.child(B);A.jobs.registerHandler("directory-sync",new ir(Q("DirectorySyncJobHandler"),A,f)),A.jobs.registerHandler("directory-export",new _r(Q("DirectoryExportJobHandler"),A,f)),A.jobs.registerHandler("directory-import",new Vr(Q("DirectoryImportJobHandler"),A,f)),A.jobs.registerHandler("directory-delete",new Mr(Q("DirectoryDeleteJobHandler"),A,f)),A.jobs.registerHandler("directory-cleanup",new Or(Q("DirectoryCleanupJobHandler"),f)),A.jobs.registerHandler("cover-image-convert",new jr(A,Q("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new gr(A,Q("InlineImageConversionJobHandler"))),w.debug("Registered async job handlers")}B0();import{unlink as kb2,access as hb2}from"fs/promises";function OO0(A,f,w,Q){let{subscribe:B}=A.messaging,{entityService:x}=A;B("entity:created",async(c)=>{let{entity:I}=c.payload;try{await f.fileOps.writeEntity(I),w.debug("Auto-exported created entity",{id:I.id,entityType:I.entityType})}catch($){w.error("Auto-export FAILED for created entity",{id:I.id,entityType:I.entityType,error:$ instanceof Error?$.message:String($),stack:$ instanceof Error?$.stack:void 0})}return{success:!0}}),B("entity:updated",async(c)=>{let{entityType:I,entityId:$}=c.payload;try{let u=await x.getEntity(I,$);if(!u)return w.debug("Entity not found in DB, skipping export",{entityType:I,entityId:$}),{success:!1};await f.fileOps.writeEntity(u),w.debug("Auto-exported updated entity",{id:u.id,entityType:u.entityType})}catch(u){w.error("Auto-export FAILED for updated entity",{entityType:I,entityId:$,error:u instanceof Error?u.message:String(u),stack:u instanceof Error?u.stack:void 0})}return{success:!0}}),B("entity:deleted",async(c)=>{let{entityId:I,entityType:$}=c.payload,u=f.fileOps.getFilePath(I,$);if(await hb2(u).then(()=>!0,()=>!1))await kb2(u),w.debug("Auto-deleted entity file",{id:I,entityType:$,path:u});return{success:!0}}),w.debug("Setup auto-sync for entity events",{entityTypes:Q})}function jO0(A,f,w){f.setJobQueueCallback(async(Q)=>{let B=[{type:Q.type,data:Q.data}];return A.jobs.enqueueBatch(B,{priority:5,source:"directory-sync-watcher",rootJobId:l8(),metadata:{operationType:"file_operations",operationTarget:w,pluginId:"directory-sync"}})})}YA();import{access as Gb2,readdir as gO0,mkdir as Jb2,copyFile as bb2}from"fs/promises";import{exec as zb2}from"child_process";import{promisify as Nb2}from"util";import{join as aFA,resolve as oFA}from"path";var Cb2=Nb2(zb2);async function Pr(A){try{return await Gb2(A),!0}catch{return!1}}async function Eb2(A,f){if(!await Pr(A))return!0;if((await gO0(A)).filter((B)=>!B.startsWith(".")&&!B.startsWith("_")).length>0)return!1;if(await Lb2(A))return f.debug("Git repository with remote detected - skipping seed content",{path:A}),!1;return!0}async function Lb2(A){let f=aFA(A,".git");if(!await Pr(f))return!1;try{let{stdout:w}=await Cb2("git remote",{cwd:A});return w.trim().length>0}catch{return!1}}async function PO0(A,f){let w=await gO0(A,{withFileTypes:!0});for(let Q of w){let B=aFA(A,Q.name),x=aFA(f,Q.name);if(Q.isDirectory()){if(!await Pr(x))await Jb2(x,{recursive:!0});await PO0(B,x)}else await bb2(B,x)}}async function RO0(A,f,w){let Q=oFA(process.cwd(),A);w=w?oFA(w):oFA(process.cwd(),"seed-content");let B=await Eb2(Q,f);if(B&&await Pr(w))f.debug("Copying seed content to brain-data directory"),await PO0(w,Q),f.debug("Seed content copied successfully");else if(B)f.debug("No seed content directory found, starting with empty brain-data");else f.debug("brain-data directory not empty, skipping seed content")}async function qb2(A,f,w,Q=300000){let x=Date.now();while(Date.now()-x<Q){let c=await A.jobs.getBatchStatus(f);if(c&&(c.status==="completed"||c.status==="failed")){w.debug("Batch completed",{batchId:f,status:c.status,completed:c.completedOperations,failed:c.failedOperations});return}await new Promise((I)=>setTimeout(I,500))}w.warn(`Timeout waiting for batch ${f} after ${Q}ms`)}function nO0(A,f,w,Q,B,x){let c=!1,I=async()=>{if(c)return;c=!0;let $=f();if(w.seedContent){let u=w.syncPath??A.dataDir;await RO0(u,B,w.seedContentPath)}try{if(x){B.debug("Git enabled \u2014 pulling before import");let Y=await x.pull();if(Y.files.length>0)B.info("Pulled changes from remote",{filesChanged:Y.files.length})}B.debug("Starting initial sync");let u=await $.queueSyncBatch(A,"initial-sync",void 0,{includeCleanup:!0});if(!u){B.debug("Initial sync: no files to import"),await A.messaging.send("sync:initial:completed",{success:!0},{broadcast:!0});return}B.debug("Initial sync: queued imports",{importOperations:u.importOperationsCount,totalFiles:u.totalFiles}),qb2(A,u.batchId,B).then(()=>A.messaging.send("sync:initial:completed",{success:!0},{broadcast:!0}),(Y)=>{B.error("Initial sync batch failed",Y),A.messaging.send("sync:initial:completed",{success:!1,error:h0(Y)},{broadcast:!0})})}catch(u){B.error("Initial sync failed",u),await A.messaging.send("sync:initial:completed",{success:!1,error:h0(u)},{broadcast:!0})}};A.messaging.subscribe("system:plugins:ready",async()=>{return B.debug("system:plugins:ready received, starting initial sync"),await I(),{success:!0}})}YA();function mO0(A,f,w,Q){let B=new jK(()=>{f.withLock(async()=>{try{await f.commit(),await f.push()}catch(I){Q.error("Git auto-commit failed",{error:I})}})},w),x=["entity:created","entity:updated","entity:deleted"],c=[];for(let I of x){let $=A.subscribe(I,async()=>{return B.trigger(),{success:!0}});c.push($)}return()=>{B.dispose();for(let I of c)I()}}function lO0(A,f,w,Q,B){if(Q<=0)return()=>{};let x=Q*60*1000,c=!1,I=async()=>{if(c)return;c=!0;try{let{files:u}=await A.withLock(()=>A.pull());if(u.length>0)B.info("Periodic sync: pulled changes",{filesChanged:u.length});let Y=await f.queueSyncBatch(w,"periodic-sync");if(Y)B.debug("Periodic sync: queued imports",{importOperations:Y.importOperationsCount,totalFiles:Y.totalFiles})}catch(u){B.error("Periodic git sync failed",{error:u})}finally{c=!1}},$=setInterval(()=>{I()},x);return B.info("Started periodic git sync",{intervalMinutes:Q}),()=>{clearInterval($)}}function TO0(A,f,w,Q,B){let{subscribe:x}=A.messaging;x("entity:export:request",async(c)=>{try{return{success:!0,data:await f().exportEntities(c.payload.entityTypes)}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Export failed"}}}),x("entity:import:request",async(c)=>{try{let I=f(),$=c.payload.paths,u=await I.importEntities($);if($&&$.length>0)await I.removeOrphanedEntities();return{success:!0,data:u}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Import failed"}}}),x("sync:status:request",async()=>{try{let I=await f().getStatus();return{success:!0,data:{syncPath:I.syncPath,isInitialized:I.exists,watchEnabled:I.watching}}}catch(c){return{success:!1,error:c instanceof Error?c.message:"Status check failed"}}}),x("sync:configure:request",async(c)=>{try{return await w({syncPath:c.payload.syncPath}),{success:!0,data:{syncPath:c.payload.syncPath,configured:!0}}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Configuration failed"}}}),x("git-sync:get-repo-info",async()=>{if(!B?.repo)return{success:!1,error:"Git not configured"};return{success:!0,data:{repo:B.repo,branch:B.branch??"main"}}}),Q.debug("Registered message handlers")}B0();YA();B0();YA();function yO0(A,f){return Tf(A,"history","Get version history for an entity from git. Without sha: returns commit list. With sha: returns entity content at that version.",X.object({entityType:X.string().describe("Entity type (e.g. post, note, link)"),id:X.string().describe("Entity ID"),sha:X.string().optional().describe("Commit SHA to retrieve content at. Omit to list commit history."),limit:X.number().int().positive().optional().default(10).describe("Max commits to return (list mode only)")}),async(w)=>{let Q=`${w.entityType}/${w.id}.md`;try{if(w.sha){let x=await f.show(w.sha,Q);return mB({sha:w.sha,entityType:w.entityType,id:w.id,content:x},`Content at ${w.sha.slice(0,7)}`)}let B=await f.log(Q,w.limit);if(B.length===0)return mB({commits:[]},`No history found for ${w.entityType}/${w.id}`);return mB({commits:B,entityType:w.entityType,id:w.id},`${B.length} version${B.length===1?"":"s"} found`)}catch(B){return r6(B instanceof Error?B.message:"History lookup failed")}})}function SO0(A,f,w,Q){let B=[Tf(w,"sync","Sync brain entities with the filesystem. Pulls from git if configured, then imports files. Git commit and push happen automatically after imports complete.",X.object({}),async(x,c)=>{try{let I=c.channelId?`${c.interfaceType}:${c.channelId}`:`plugin:${w}`,$={interfaceType:c.interfaceType,channelId:c.channelId},u=!1;if(Q)await Q.withLock(()=>Q.pull()),u=!0;let Y=await A.queueSyncBatch(f,I,$);if(!Y)return mB({gitPulled:u},"No files to sync");return mB({batchId:Y.batchId,importOperations:Y.importOperationsCount,totalFiles:Y.totalFiles,gitPulled:u},`Sync started: ${Y.importOperationsCount} import jobs queued for ${Y.totalFiles} files${u?" (pulled from git)":""}`)}catch(I){return r6(I instanceof Error?I.message:"Sync failed")}},{cli:{name:"sync"}}),Tf(w,"status","Get sync and git repository status \u2014 last sync time, watching state, pending git changes.",X.object({}),async()=>{try{let x=await A.getStatus(),c={syncPath:x.syncPath,lastSync:x.lastSync?.toISOString(),watching:x.watching};if(Q){let I=await Q.getStatus();c.git={isRepo:I.isRepo,branch:I.branch,hasChanges:I.hasChanges,ahead:I.ahead,behind:I.behind,remote:I.remote}}return mB(c)}catch(x){return r6(x instanceof Error?x.message:"Status check failed")}},{visibility:"public"})];if(Q)B.push(yO0(w,Q));return B}var pO0={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.9",description:"Directory-based entity synchronization plugin for Brains",type:"module",main:"./src/index.ts",types:"./src/index.ts",exports:{".":{types:"./src/index.ts",import:"./src/index.ts"}},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",clean:"rm -rf .turbo"},dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",chokidar:"^3.5.3","simple-git":"^3.21.0"},devDependencies:{"@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"},peerDependencies:{}};class sFA extends yQ{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",pO0,A,CO0)}requireDirectorySync(){if(!this.directorySync)throw Error("DirectorySync service not initialized");return this.directorySync}hasGitSync(){return this.gitSync!==void 0}async onRegister(A){let{logger:f,entityService:w}=A;A.templates.register({status:{name:"status",description:"Directory synchronization status",schema:Xi,basePrompt:"",formatter:new qr,requiredPermission:"anchor"}});let Q=this.config.syncPath??A.dataDir;this.directorySync=new ci({syncPath:Q,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:w,logger:f});try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:Q})}catch(c){throw this.logger.error("Failed to initialize directory",c),c}await this.registerJobHandlers(A);let B=this.requireDirectorySync();if(OO0(A,B,this.logger,this.config.entityTypes),this.config.autoSync)jO0(A,B,this.config.syncPath??A.dataDir);let x=this.config.git!==void 0&&(this.config.git.repo!==void 0||this.config.git.gitUrl!==void 0);if(this.config.git&&!x)this.logger.debug("Git block present but no repo/gitUrl configured \u2014 git sync disabled");if(x&&this.config.git){let c=this.config.syncPath??A.dataDir;if(this.gitSync=new rFA({logger:this.logger.child("GitSync"),dataDir:c,repo:this.config.git.repo,gitUrl:this.config.git.gitUrl,branch:this.config.git.branch,authToken:this.config.git.authToken,authorName:this.config.git.authorName,authorEmail:this.config.git.authorEmail}),await this.gitSync.initialize(),this.logger.info("Git integration enabled",{repo:this.config.git.repo}),this.gitCleanups.push(mO0(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push(lO0(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)nO0(A,()=>this.requireDirectorySync(),this.config,this.id,this.logger,this.gitSync);TO0(A,()=>this.requireDirectorySync(),(c)=>this.configure(c),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return SO0(A,this.getContext(),this.id,this.gitSync)}async onShutdown(){for(let A of this.gitCleanups)A();this.gitCleanups=[],this.directorySync?.stopWatching(),this.gitSync?.cleanup()}getDirectorySync(){return this.directorySync}async configure(A){this.requireDirectorySync();let f=this.getContext();this.directorySync=new ci({...this.config,syncPath:A.syncPath,entityService:f.entityService,logger:f.logger}),await this.directorySync.initialize(),this.logger.info("Directory sync reconfigured",{path:A.syncPath})}async registerJobHandlers(A){MO0(A,this.requireDirectorySync(),this.logger)}}function rZ(A={}){return new sFA(A)}B0();B0();YA();YA();var rO0=X.object({environment:X.enum(["preview","production"]),outputDir:X.string(),workingDir:X.string().optional(),sharedImagesDir:X.string().default("./dist/images"),enableContentGeneration:X.boolean().default(!1),cleanBeforeBuild:X.boolean().default(!0),siteConfig:X.object({title:X.string(),description:X.string(),url:X.string().optional(),copyright:X.string().optional(),themeMode:X.enum(["light","dark"]).optional(),analyticsScript:X.string().optional()}),layouts:X.record(X.any()),themeCSS:X.string().optional()}),s5w=X.object({success:X.boolean(),outputDir:X.string(),filesGenerated:X.number(),routesBuilt:X.number(),errors:X.array(X.string()).optional(),warnings:X.array(X.string()).optional()});import{render as kS0}from"preact-render-to-string";import{h as Wv}from"preact";class tFA{headProps=null;defaultTitle;constructor(A){this.defaultTitle=A}setHeadProps(A){this.headProps??=A}getHeadProps(){return this.headProps}reset(){this.headProps=null}generateHeadHTML(){let A=[];if(A.push('<meta charset="UTF-8">'),A.push('<meta name="viewport" content="width=device-width, initial-scale=1.0">'),A.push('<meta http-equiv="X-UA-Compatible" content="IE=edge">'),A.push('<link rel="icon" type="image/svg+xml" href="/favicon.svg">'),A.push('<link rel="icon" type="image/png" href="/favicon.png">'),A.push('<link rel="stylesheet" href="/styles/main.css">'),!this.headProps)return A.push(`<title>${this.escapeHtml(this.defaultTitle)}</title>`),A.join(`
1955
1955
  `);let{title:f,description:w,ogImage:Q,ogType:B,twitterCard:x,canonicalUrl:c}=this.headProps;if(A.push(`<title>${this.escapeHtml(f)}</title>`),w)A.push(`<meta name="description" content="${this.escapeHtml(w)}">`);if(A.push(`<meta property="og:title" content="${this.escapeHtml(f)}">`),w)A.push(`<meta property="og:description" content="${this.escapeHtml(w)}">`);if(A.push(`<meta property="og:type" content="${B??"website"}">`),Q)A.push(`<meta property="og:image" content="${this.escapeHtml(Q)}">`);if(A.push(`<meta name="twitter:card" content="${x??"summary_large_image"}">`),A.push(`<meta name="twitter:title" content="${this.escapeHtml(f)}">`),w)A.push(`<meta name="twitter:description" content="${this.escapeHtml(w)}">`);if(Q)A.push(`<meta name="twitter:image" content="${this.escapeHtml(Q)}">`);if(c)A.push(`<link rel="canonical" href="${this.escapeHtml(c)}">`);return A.join(`
1956
1956
  `)}escapeHtml(A){let f={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return A.replace(/[&<>"']/g,(w)=>f[w]??w)}}function dO0(A){var f,w,Q="";if(typeof A=="string"||typeof A=="number")Q+=A;else if(typeof A=="object")if(Array.isArray(A)){var B=A.length;for(f=0;f<B;f++)A[f]&&(w=dO0(A[f]))&&(Q&&(Q+=" "),Q+=w)}else for(w in A)A[w]&&(Q&&(Q+=" "),Q+=w);return Q}function Rr(){for(var A,f,w=0,Q="",B=arguments.length;w<B;w++)(A=arguments[w])&&(f=dO0(A))&&(Q&&(Q+=" "),Q+=f);return Q}var Vb2=(A)=>{let f=Mb2(A),{conflictingClassGroups:w,conflictingClassGroupModifiers:Q}=A;return{getClassGroupId:(c)=>{let I=c.split("-");if(I[0]===""&&I.length!==1)I.shift();return eO0(I,f)||ib2(c)},getConflictingClassGroupIds:(c,I)=>{let $=w[c]||[];if(I&&Q[c])return[...$,...Q[c]];return $}}},eO0=(A,f)=>{if(A.length===0)return f.classGroupId;let w=A[0],Q=f.nextPart.get(w),B=Q?eO0(A.slice(1),Q):void 0;if(B)return B;if(f.validators.length===0)return;let x=A.join("-");return f.validators.find(({validator:c})=>c(x))?.classGroupId},oO0=/^\[(.+)\]$/,ib2=(A)=>{if(oO0.test(A)){let f=oO0.exec(A)[1],w=f?.substring(0,f.indexOf(":"));if(w)return"arbitrary.."+w}},Mb2=(A)=>{let{theme:f,prefix:w}=A,Q={nextPart:new Map,validators:[]};return jb2(Object.entries(A.classGroups),w).forEach(([x,c])=>{AKA(c,Q,x,f)}),Q},AKA=(A,f,w,Q)=>{A.forEach((B)=>{if(typeof B==="string"){let x=B===""?f:aO0(f,B);x.classGroupId=w;return}if(typeof B==="function"){if(Ob2(B)){AKA(B(Q),f,w,Q);return}f.validators.push({validator:B,classGroupId:w});return}Object.entries(B).forEach(([x,c])=>{AKA(c,aO0(f,x),w,Q)})})},aO0=(A,f)=>{let w=A;return f.split("-").forEach((Q)=>{if(!w.nextPart.has(Q))w.nextPart.set(Q,{nextPart:new Map,validators:[]});w=w.nextPart.get(Q)}),w},Ob2=(A)=>A.isThemeGetter,jb2=(A,f)=>{if(!f)return A;return A.map(([w,Q])=>{let B=Q.map((x)=>{if(typeof x==="string")return f+x;if(typeof x==="object")return Object.fromEntries(Object.entries(x).map(([c,I])=>[f+c,I]));return x});return[w,B]})},gb2=(A)=>{if(A<1)return{get:()=>{return},set:()=>{}};let f=0,w=new Map,Q=new Map,B=(x,c)=>{if(w.set(x,c),f++,f>A)f=0,Q=w,w=new Map};return{get(x){let c=w.get(x);if(c!==void 0)return c;if((c=Q.get(x))!==void 0)return B(x,c),c},set(x,c){if(w.has(x))w.set(x,c);else B(x,c)}}};var Pb2=(A)=>{let{separator:f,experimentalParseClassName:w}=A,Q=f.length===1,B=f[0],x=f.length,c=(I)=>{let $=[],u=0,Y=0,F;for(let G=0;G<I.length;G++){let E=I[G];if(u===0){if(E===B&&(Q||I.slice(G,G+x)===f)){$.push(I.slice(Y,G)),Y=G+x;continue}if(E==="/"){F=G;continue}}if(E==="[")u++;else if(E==="]")u--}let K=$.length===0?I:I.substring(Y),Z=K.startsWith("!"),k=Z?K.substring(1):K,h=F&&F>Y?F-Y:void 0;return{modifiers:$,hasImportantModifier:Z,baseClassName:k,maybePostfixModifierPosition:h}};if(w)return(I)=>w({className:I,parseClassName:c});return c},Rb2=(A)=>{if(A.length<=1)return A;let f=[],w=[];return A.forEach((Q)=>{if(Q[0]==="[")f.push(...w.sort(),Q),w=[];else w.push(Q)}),f.push(...w.sort()),f},nb2=(A)=>({cache:gb2(A.cacheSize),parseClassName:Pb2(A),...Vb2(A)}),mb2=/\s+/,lb2=(A,f)=>{let{parseClassName:w,getClassGroupId:Q,getConflictingClassGroupIds:B}=f,x=[],c=A.trim().split(mb2),I="";for(let $=c.length-1;$>=0;$-=1){let u=c[$],{modifiers:Y,hasImportantModifier:F,baseClassName:K,maybePostfixModifierPosition:Z}=w(u),k=Boolean(Z),h=Q(k?K.substring(0,Z):K);if(!h){if(!k){I=u+(I.length>0?" "+I:I);continue}if(h=Q(K),!h){I=u+(I.length>0?" "+I:I);continue}k=!1}let G=Rb2(Y).join(":"),E=F?G+"!":G,V=E+h;if(x.includes(V))continue;x.push(V);let q=B(h,k);for(let y=0;y<q.length;++y){let r=q[y];x.push(E+r)}I=u+(I.length>0?" "+I:I)}return I};function Tb2(){let A=0,f,w,Q="";while(A<arguments.length)if(f=arguments[A++]){if(w=Aj0(f))Q&&(Q+=" "),Q+=w}return Q}var Aj0=(A)=>{if(typeof A==="string")return A;let f,w="";for(let Q=0;Q<A.length;Q++)if(A[Q]){if(f=Aj0(A[Q]))w&&(w+=" "),w+=f}return w};function sO0(A,...f){let w,Q,B,x=c;function c($){let u=f.reduce((Y,F)=>F(Y),A());return w=nb2(u),Q=w.cache.get,B=w.cache.set,x=I,I($)}function I($){let u=Q($);if(u)return u;let Y=lb2($,w);return B($,Y),Y}return function(){return x(Tb2.apply(null,arguments))}}var VQ=(A)=>{let f=(w)=>w[A]||[];return f.isThemeGetter=!0,f},fj0=/^\[(?:([a-z-]+):)?(.+)\]$/i,yb2=/^\d+\/\d+$/,Sb2=new Set(["px","full","screen"]),pb2=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,rb2=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,db2=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,ob2=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,ab2=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,_3=(A)=>wb(A)||Sb2.has(A)||yb2.test(A),lU=(A)=>Qb(A,"length",Bz2),wb=(A)=>Boolean(A)&&!Number.isNaN(Number(A)),eFA=(A)=>Qb(A,"number",wb),Zi=(A)=>Boolean(A)&&Number.isInteger(Number(A)),sb2=(A)=>A.endsWith("%")&&wb(A.slice(0,-1)),If=(A)=>fj0.test(A),TU=(A)=>pb2.test(A),tb2=new Set(["length","size","percentage"]),eb2=(A)=>Qb(A,tb2,wj0),Az2=(A)=>Qb(A,"position",wj0),fz2=new Set(["image","url"]),wz2=(A)=>Qb(A,fz2,cz2),Qz2=(A)=>Qb(A,"",xz2),vi=()=>!0,Qb=(A,f,w)=>{let Q=fj0.exec(A);if(Q){if(Q[1])return typeof f==="string"?Q[1]===f:f.has(Q[1]);return w(Q[2])}return!1},Bz2=(A)=>rb2.test(A)&&!db2.test(A),wj0=()=>!1,xz2=(A)=>ob2.test(A),cz2=(A)=>ab2.test(A);var tO0=()=>{let A=VQ("colors"),f=VQ("spacing"),w=VQ("blur"),Q=VQ("brightness"),B=VQ("borderColor"),x=VQ("borderRadius"),c=VQ("borderSpacing"),I=VQ("borderWidth"),$=VQ("contrast"),u=VQ("grayscale"),Y=VQ("hueRotate"),F=VQ("invert"),K=VQ("gap"),Z=VQ("gradientColorStops"),k=VQ("gradientColorStopPositions"),h=VQ("inset"),G=VQ("margin"),E=VQ("opacity"),V=VQ("padding"),q=VQ("saturate"),y=VQ("scale"),r=VQ("sepia"),g=VQ("skew"),M=VQ("space"),j=VQ("translate"),P=()=>["auto","contain","none"],t=()=>["auto","hidden","clip","visible","scroll"],l=()=>["auto",If,f],DA=()=>[If,f],cA=()=>["",_3,lU],_=()=>["auto",wb,If],L=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],i=()=>["solid","dashed","dotted","double","none"],a=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],p=()=>["start","end","center","between","around","evenly","stretch"],e=()=>["","0",If],d=()=>["auto","avoid","all","avoid-page","page","left","right","column"],HA=()=>[wb,If];return{cacheSize:500,separator:":",theme:{colors:[vi],spacing:[_3,lU],blur:["none","",TU,If],brightness:HA(),borderColor:[A],borderRadius:["none","","full",TU,If],borderSpacing:DA(),borderWidth:cA(),contrast:HA(),grayscale:e(),hueRotate:HA(),invert:e(),gap:DA(),gradientColorStops:[A],gradientColorStopPositions:[sb2,lU],inset:l(),margin:l(),opacity:HA(),padding:DA(),saturate:HA(),scale:HA(),sepia:e(),skew:HA(),space:DA(),translate:DA()},classGroups:{aspect:[{aspect:["auto","square","video",If]}],container:["container"],columns:[{columns:[TU]}],"break-after":[{"break-after":d()}],"break-before":[{"break-before":d()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...L(),If]}],overflow:[{overflow:t()}],"overflow-x":[{"overflow-x":t()}],"overflow-y":[{"overflow-y":t()}],overscroll:[{overscroll:P()}],"overscroll-x":[{"overscroll-x":P()}],"overscroll-y":[{"overscroll-y":P()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[h]}],"inset-x":[{"inset-x":[h]}],"inset-y":[{"inset-y":[h]}],start:[{start:[h]}],end:[{end:[h]}],top:[{top:[h]}],right:[{right:[h]}],bottom:[{bottom:[h]}],left:[{left:[h]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",Zi,If]}],basis:[{basis:l()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",If]}],grow:[{grow:e()}],shrink:[{shrink:e()}],order:[{order:["first","last","none",Zi,If]}],"grid-cols":[{"grid-cols":[vi]}],"col-start-end":[{col:["auto",{span:["full",Zi,If]},If]}],"col-start":[{"col-start":_()}],"col-end":[{"col-end":_()}],"grid-rows":[{"grid-rows":[vi]}],"row-start-end":[{row:["auto",{span:[Zi,If]},If]}],"row-start":[{"row-start":_()}],"row-end":[{"row-end":_()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",If]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",If]}],gap:[{gap:[K]}],"gap-x":[{"gap-x":[K]}],"gap-y":[{"gap-y":[K]}],"justify-content":[{justify:["normal",...p()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...p(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...p(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[V]}],px:[{px:[V]}],py:[{py:[V]}],ps:[{ps:[V]}],pe:[{pe:[V]}],pt:[{pt:[V]}],pr:[{pr:[V]}],pb:[{pb:[V]}],pl:[{pl:[V]}],m:[{m:[G]}],mx:[{mx:[G]}],my:[{my:[G]}],ms:[{ms:[G]}],me:[{me:[G]}],mt:[{mt:[G]}],mr:[{mr:[G]}],mb:[{mb:[G]}],ml:[{ml:[G]}],"space-x":[{"space-x":[M]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[M]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",If,f]}],"min-w":[{"min-w":[If,f,"min","max","fit"]}],"max-w":[{"max-w":[If,f,"none","full","min","max","fit","prose",{screen:[TU]},TU]}],h:[{h:[If,f,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[If,f,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[If,f,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[If,f,"auto","min","max","fit"]}],"font-size":[{text:["base",TU,lU]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",eFA]}],"font-family":[{font:[vi]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",If]}],"line-clamp":[{"line-clamp":["none",wb,eFA]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",_3,If]}],"list-image":[{"list-image":["none",If]}],"list-style-type":[{list:["none","disc","decimal",If]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[A]}],"placeholder-opacity":[{"placeholder-opacity":[E]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[A]}],"text-opacity":[{"text-opacity":[E]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...i(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",_3,lU]}],"underline-offset":[{"underline-offset":["auto",_3,If]}],"text-decoration-color":[{decoration:[A]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:DA()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",If]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",If]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[E]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...L(),Az2]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",eb2]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},wz2]}],"bg-color":[{bg:[A]}],"gradient-from-pos":[{from:[k]}],"gradient-via-pos":[{via:[k]}],"gradient-to-pos":[{to:[k]}],"gradient-from":[{from:[Z]}],"gradient-via":[{via:[Z]}],"gradient-to":[{to:[Z]}],rounded:[{rounded:[x]}],"rounded-s":[{"rounded-s":[x]}],"rounded-e":[{"rounded-e":[x]}],"rounded-t":[{"rounded-t":[x]}],"rounded-r":[{"rounded-r":[x]}],"rounded-b":[{"rounded-b":[x]}],"rounded-l":[{"rounded-l":[x]}],"rounded-ss":[{"rounded-ss":[x]}],"rounded-se":[{"rounded-se":[x]}],"rounded-ee":[{"rounded-ee":[x]}],"rounded-es":[{"rounded-es":[x]}],"rounded-tl":[{"rounded-tl":[x]}],"rounded-tr":[{"rounded-tr":[x]}],"rounded-br":[{"rounded-br":[x]}],"rounded-bl":[{"rounded-bl":[x]}],"border-w":[{border:[I]}],"border-w-x":[{"border-x":[I]}],"border-w-y":[{"border-y":[I]}],"border-w-s":[{"border-s":[I]}],"border-w-e":[{"border-e":[I]}],"border-w-t":[{"border-t":[I]}],"border-w-r":[{"border-r":[I]}],"border-w-b":[{"border-b":[I]}],"border-w-l":[{"border-l":[I]}],"border-opacity":[{"border-opacity":[E]}],"border-style":[{border:[...i(),"hidden"]}],"divide-x":[{"divide-x":[I]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[I]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[E]}],"divide-style":[{divide:i()}],"border-color":[{border:[B]}],"border-color-x":[{"border-x":[B]}],"border-color-y":[{"border-y":[B]}],"border-color-s":[{"border-s":[B]}],"border-color-e":[{"border-e":[B]}],"border-color-t":[{"border-t":[B]}],"border-color-r":[{"border-r":[B]}],"border-color-b":[{"border-b":[B]}],"border-color-l":[{"border-l":[B]}],"divide-color":[{divide:[B]}],"outline-style":[{outline:["",...i()]}],"outline-offset":[{"outline-offset":[_3,If]}],"outline-w":[{outline:[_3,lU]}],"outline-color":[{outline:[A]}],"ring-w":[{ring:cA()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[A]}],"ring-opacity":[{"ring-opacity":[E]}],"ring-offset-w":[{"ring-offset":[_3,lU]}],"ring-offset-color":[{"ring-offset":[A]}],shadow:[{shadow:["","inner","none",TU,Qz2]}],"shadow-color":[{shadow:[vi]}],opacity:[{opacity:[E]}],"mix-blend":[{"mix-blend":[...a(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":a()}],filter:[{filter:["","none"]}],blur:[{blur:[w]}],brightness:[{brightness:[Q]}],contrast:[{contrast:[$]}],"drop-shadow":[{"drop-shadow":["","none",TU,If]}],grayscale:[{grayscale:[u]}],"hue-rotate":[{"hue-rotate":[Y]}],invert:[{invert:[F]}],saturate:[{saturate:[q]}],sepia:[{sepia:[r]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[w]}],"backdrop-brightness":[{"backdrop-brightness":[Q]}],"backdrop-contrast":[{"backdrop-contrast":[$]}],"backdrop-grayscale":[{"backdrop-grayscale":[u]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[Y]}],"backdrop-invert":[{"backdrop-invert":[F]}],"backdrop-opacity":[{"backdrop-opacity":[E]}],"backdrop-saturate":[{"backdrop-saturate":[q]}],"backdrop-sepia":[{"backdrop-sepia":[r]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[c]}],"border-spacing-x":[{"border-spacing-x":[c]}],"border-spacing-y":[{"border-spacing-y":[c]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",If]}],duration:[{duration:HA()}],ease:[{ease:["linear","in","out","in-out",If]}],delay:[{delay:HA()}],animate:[{animate:["none","spin","ping","pulse","bounce",If]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[y]}],"scale-x":[{"scale-x":[y]}],"scale-y":[{"scale-y":[y]}],rotate:[{rotate:[Zi,If]}],"translate-x":[{"translate-x":[j]}],"translate-y":[{"translate-y":[j]}],"skew-x":[{"skew-x":[g]}],"skew-y":[{"skew-y":[g]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",If]}],accent:[{accent:["auto",A]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",If]}],"caret-color":[{caret:[A]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":DA()}],"scroll-mx":[{"scroll-mx":DA()}],"scroll-my":[{"scroll-my":DA()}],"scroll-ms":[{"scroll-ms":DA()}],"scroll-me":[{"scroll-me":DA()}],"scroll-mt":[{"scroll-mt":DA()}],"scroll-mr":[{"scroll-mr":DA()}],"scroll-mb":[{"scroll-mb":DA()}],"scroll-ml":[{"scroll-ml":DA()}],"scroll-p":[{"scroll-p":DA()}],"scroll-px":[{"scroll-px":DA()}],"scroll-py":[{"scroll-py":DA()}],"scroll-ps":[{"scroll-ps":DA()}],"scroll-pe":[{"scroll-pe":DA()}],"scroll-pt":[{"scroll-pt":DA()}],"scroll-pr":[{"scroll-pr":DA()}],"scroll-pb":[{"scroll-pb":DA()}],"scroll-pl":[{"scroll-pl":DA()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",If]}],fill:[{fill:[A,"none"]}],"stroke-w":[{stroke:[_3,lU,eFA]}],stroke:[{stroke:[A,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},Iz2=(A,{cacheSize:f,prefix:w,separator:Q,experimentalParseClassName:B,extend:x={},override:c={}})=>{Wi(A,"cacheSize",f),Wi(A,"prefix",w),Wi(A,"separator",Q),Wi(A,"experimentalParseClassName",B);for(let I in c)$z2(A[I],c[I]);for(let I in x)uz2(A[I],x[I]);return A},Wi=(A,f,w)=>{if(w!==void 0)A[f]=w},$z2=(A,f)=>{if(f)for(let w in f)Wi(A,w,f[w])},uz2=(A,f)=>{if(f)for(let w in f){let Q=f[w];if(Q!==void 0)A[w]=(A[w]||[]).concat(Q)}},Qj0=(A,...f)=>typeof A==="function"?sO0(tO0,A,...f):sO0(()=>Iz2(tO0(),A),...f);var Dz2=Qj0({extend:{classGroups:{"font-size":[{text:["display-2xl","display-xl","display-lg","display-md","display-sm","heading-lg","heading-md","heading-sm","body-xl","body-lg","body-md","body-sm","body-xs","label-md","label-sm","label-xs"]}]}}});function C1(...A){return Dz2(Rr(A))}var Bj0=(A)=>typeof A==="boolean"?`${A}`:A===0?"0":A,xj0=Rr,sw=(A,f)=>(w)=>{var Q;if((f===null||f===void 0?void 0:f.variants)==null)return xj0(A,w===null||w===void 0?void 0:w.class,w===null||w===void 0?void 0:w.className);let{variants:B,defaultVariants:x}=f,c=Object.keys(B).map((u)=>{let Y=w===null||w===void 0?void 0:w[u],F=x===null||x===void 0?void 0:x[u];if(Y===null)return null;let K=Bj0(Y)||Bj0(F);return B[u][K]}),I=w&&Object.entries(w).reduce((u,Y)=>{let[F,K]=Y;if(K===void 0)return u;return u[F]=K,u},{}),$=f===null||f===void 0?void 0:(Q=f.compoundVariants)===null||Q===void 0?void 0:Q.reduce((u,Y)=>{let{class:F,className:K,...Z}=Y;return Object.entries(Z).every((k)=>{let[h,G]=k;return Array.isArray(G)?G.includes({...x,...I}[h]):{...x,...I}[h]===G})?[...u,F,K]:u},[]);return xj0(A,c,$,w===null||w===void 0?void 0:w.class,w===null||w===void 0?void 0:w.className)};import{jsxDEV as fKA}from"preact/jsx-dev-runtime";var cj0=sw("p-4 rounded-lg border",{variants:{variant:{warning:"bg-warning border-warning text-warning",error:"bg-error border-error text-error",success:"bg-success border-success text-success",info:"bg-info border-info text-info"}},defaultVariants:{variant:"info"}});function wKA({variant:A,title:f,children:w,className:Q}){return fKA("div",{className:C1(cj0({variant:A}),Q),role:"alert",children:[f&&fKA("p",{className:"font-medium text-current opacity-90",children:f},void 0,!1,void 0,this),fKA("div",{className:C1(f&&"mt-1","text-sm text-current opacity-75"),children:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as Yz2}from"preact/jsx-dev-runtime";var Ij0=sw("inline-flex items-center justify-center font-bold transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed",{variants:{variant:{default:"bg-brand hover:bg-brand-dark text-theme-inverse",secondary:"bg-theme-muted hover:bg-theme-subtle text-theme border border-theme",ghost:"hover:bg-theme-subtle text-theme"},size:{sm:"h-8 px-3 text-sm rounded-md",md:"h-10 px-4 py-2 text-sm rounded-lg",lg:"h-12 px-6 text-base rounded-lg"}},defaultVariants:{variant:"default",size:"md"}});function dZ({variant:A,size:f,className:w,children:Q,ssrOnClick:B,type:x="button",...c}){return Yz2("button",{type:x,className:C1(Ij0({variant:A,size:f}),w),...c,...B&&{onclick:B},children:Q},void 0,!1,void 0,this)}import{jsxDEV as Hz2}from"preact/jsx-dev-runtime";var $j0=sw("inline-flex items-center justify-center font-semibold transition-all text-center",{variants:{variant:{primary:"bg-brand text-theme-inverse hover:bg-brand-dark focus:ring-brand/20 focus:outline-none focus:ring-4",accent:"bg-accent text-theme-inverse hover:bg-accent-dark focus:ring-accent/20 focus:outline-none focus:ring-4",secondary:"bg-theme-muted text-theme hover:bg-theme-muted-dark focus:outline-none focus:ring-4",outline:"border-2 border-brand text-brand hover:bg-brand hover:text-theme-inverse focus:ring-brand/20 focus:outline-none focus:ring-4","outline-light":"border-2 border-theme-light text-theme-inverse hover:bg-theme-inverse hover:text-brand hover:border-theme-inverse focus:outline-none focus:ring-4",unstyled:""},size:{icon:"w-10 h-10 rounded-full",sm:"px-3 py-1.5 text-sm rounded-lg",md:"px-4 py-2 text-sm rounded-lg",lg:"px-6 py-3 text-base rounded-xl",xl:"px-8 py-4 text-lg rounded-xl","2xl":"px-10 py-5 text-lg rounded-2xl"}},defaultVariants:{size:"md"}});function _B({href:A,children:f,variant:w,size:Q,external:B=!1,className:x,"aria-label":c}){let I=B?{target:"_blank",rel:"noopener noreferrer"}:{};return Hz2("a",{href:A,className:C1($j0({variant:w,size:Q}),x),"aria-label":c,...I,children:f},void 0,!1,void 0,this)}import{jsxDEV as nr}from"preact/jsx-dev-runtime";var uj0=sw("rounded-full transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2",{variants:{variant:{default:"bg-theme-muted/50 hover:bg-theme-muted text-theme",light:"bg-theme-subtle hover:bg-theme-muted text-theme",dark:"bg-theme-dark hover:bg-theme-muted text-theme-inverse",footer:"bg-theme-toggle hover:bg-theme-toggle-hover text-theme-toggle-icon"},size:{sm:"p-1.5",md:"p-2",lg:"p-3"}},defaultVariants:{variant:"default",size:"md"}}),Uz2={sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6"};function Bb({variant:A,size:f,className:w}){let Q=Uz2[f??"md"];return nr("button",{onclick:"toggleTheme()",type:"button",className:C1(uj0({variant:A,size:f}),w),"aria-label":"Toggle dark mode",children:nr("svg",{className:C1(Q,"transition-colors"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:[nr("path",{className:"sun-icon",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"},void 0,!1,void 0,this),nr("path",{className:"moon-icon",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z",transform:"rotate(45 12 12)"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}import{jsxDEV as QKA}from"preact/jsx-dev-runtime";var Dj0=sw("flex flex-wrap",{variants:{orientation:{horizontal:"justify-center gap-6 items-center",vertical:"flex-col gap-2.5"}},defaultVariants:{orientation:"horizontal"}});function mr({items:A,className:f,linkClassName:w="hover:text-accent transition-colors",orientation:Q,children:B}){if(A.length===0&&!B)return null;let x=[...A].sort((c,I)=>c.priority-I.priority);return QKA("ul",{className:C1(Dj0({orientation:Q}),f),children:[x.map((c)=>QKA("li",{children:QKA("a",{href:c.href,className:w,children:c.label},void 0,!1,void 0,this)},c.href,!1,void 0,this)),B]},void 0,!0,void 0,this)}import{jsxDEV as E4w}from"preact/jsx-dev-runtime";import{jsxDEV as _4w}from"preact/jsx-dev-runtime";YA();YA();import{createContext as Fz2,h as Kz2}from"preact";import{useContext as Xz2}from"preact/hooks";var Yj0=Fz2(null);function lr({imageRenderer:A,children:f}){return Kz2(Yj0.Provider,{value:A??null},f)}function Hj0(){return Xz2(Yj0)}function oZ(){let A=Hj0();return(f)=>jg(f,A?{imageRenderer:A}:void 0)}import{jsxDEV as V3}from"preact/jsx-dev-runtime";var BKA=({markdown:A})=>{let f=oZ(),Q=A.split(/^---$/gm).map((c)=>c.trim()).map((c)=>{let{attributes:I,markdown:$}=wP(c),u=QP($),Y;if(u)Y=`<div class="slide-columns">${u.map((K)=>`<div class="slide-column">${cC(f(K.trim()))}</div>`).join("")}</div>`;else Y=cC(f($));return{attributes:I,htmlContent:Y}}),B=Q.some((c)=>c.htmlContent.includes('class="mermaid"')),x=Q.map(({attributes:c,htmlContent:I},$)=>V3("section",{...c,dangerouslySetInnerHTML:{__html:I}},$,!1,void 0,this));return V3("section",{className:"presentation-section",children:[V3("link",{rel:"stylesheet",href:"https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.min.css"},void 0,!1,void 0,this),V3("div",{className:"reveal",children:V3("div",{className:"slides",children:x},void 0,!1,void 0,this)},void 0,!1,void 0,this),V3("script",{src:"https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.min.js",defer:!0},void 0,!1,void 0,this),B&&V3("script",{src:"https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js",defer:!0},void 0,!1,void 0,this),V3("script",{dangerouslySetInnerHTML:{__html:`
1957
1957
  window.addEventListener('DOMContentLoaded', () => {
@@ -2698,7 +2698,7 @@ ${f.join(`
2698
2698
  `+B:w,c=Ju(this.outputDir,"styles","main.css");await this.cssProcessor.process(x,c,this.workingDir,this.outputDir,this.logger);let I=await ux.readFile(c,"utf-8"),$=Q.length>0?Q:f;if($.length>0){let u=$.join(`
2699
2699
  `)+`
2700
2700
 
2701
- `+I;await ux.writeFile(c,u,"utf-8")}this.logger.debug("CSS processed successfully with font imports")}async copyStaticAssets(){this.logger.debug("Copying static assets from public/ directory");let A=Ju(process.cwd(),"public");try{await ux.access(A)}catch{this.logger.debug("No public/ directory found, skipping static assets");return}let f=await ux.readdir(A,{withFileTypes:!0});for(let w of f){let Q=Ju(A,w.name),B=Ju(this.outputDir,w.name);if(w.isDirectory())await this.copyDirectory(Q,B);else await ux.copyFile(Q,B),this.logger.debug(`Copied static asset: ${w.name}`)}this.logger.debug("Static assets copied successfully")}async writeInlineStaticAssets(A){if(!A)return;let f=Object.entries(A);if(f.length===0)return;this.logger.debug(`Writing ${f.length} inline static asset(s) from SitePackage`),await Promise.all(f.map(async([w,Q])=>{let B=w.startsWith("/")?w.slice(1):w,x=Ju(this.outputDir,B);await ux.mkdir(SP2(x),{recursive:!0}),await ux.writeFile(x,Q,"utf-8"),this.logger.debug(`Wrote inline static asset: ${B}`)}))}async copyDirectory(A,f){await ux.mkdir(f,{recursive:!0});let w=await ux.readdir(A,{withFileTypes:!0});for(let Q of w){let B=Ju(A,Q.name),x=Ju(f,Q.name);if(Q.isDirectory())await this.copyDirectory(B,x);else await ux.copyFile(B,x)}}}function mZA(A){return new hS0(A)}function pP2(A,f){let w=new Map;for(let Q of A.sections){let B=f.getViewTemplate(Q.template);if(!B?.runtimeScripts)continue;for(let x of B.runtimeScripts)if(!w.has(x.src))w.set(x.src,x)}return[...w.values()].map((Q)=>{let B=[`src="${Q.src}"`];if(Q.defer)B.push("defer");if(Q.module)B.push('type="module"');return`<script ${B.join(" ")}></script>`})}import{join as WT2}from"path";YA();class lZA{context;routeRegistry;entityDisplay;constructor(A,f,w){this.context=A;this.routeRegistry=f;this.entityDisplay=w}async generateEntityRoutes(){let A=this.context.logger.child("DynamicRouteGenerator"),f=this.routeRegistry.list(),w=0;for(let B of f)if(B.sourceEntityType)this.routeRegistry.unregister(B.path),w++;if(w>0)A.debug(`Cleared ${w} dynamic routes before regeneration`);let Q=this.context.entityService.getEntityTypes();A.debug(`Found ${Q.length} entity types`,{entityTypes:Q});for(let B of Q)await this.generateRoutesForEntityType(B)}async generateRoutesForEntityType(A){let f=this.context.logger.child("DynamicRouteGenerator"),{listTemplateName:w,detailTemplateName:Q}=this.findTemplatesForEntityType(A);if(!w&&!Q){f.debug(`No matching templates found for entity type: ${A}`);return}if(f.debug(`Generating routes for entity type: ${A}`,{listTemplate:w,detailTemplate:Q}),w){let{pluralName:B,label:x,layout:c,paginate:I,pageSize:$,navigation:u}=this.getEntityDisplayConfig(A);if(I)await this.generatePaginatedRoutes(A,w,B,x,c,$,u,f);else{let Y={id:`${A}-index`,path:`/${B}`,title:x,description:`Browse all ${B}`,...c&&{layout:c},navigation:{show:u.show,label:x,slot:u.slot,priority:u.priority},sections:[{id:"list",template:w,dataQuery:{entityType:A,query:{limit:100}}}],sourceEntityType:A};try{this.routeRegistry.register(Y),f.debug(`Registered index route for ${A}`,{path:Y.path})}catch(F){f.warn(`Failed to register index route for ${A}`,{error:F})}}}if(Q)try{let B=await this.context.entityService.listEntities(A,{limit:1000});f.debug(`Found ${B.length} ${A} entities to generate routes for`);let{pluralName:x,layout:c}=this.getEntityDisplayConfig(A);for(let $ of B){let u="slug"in $.metadata?$.metadata.slug:$.id,Y={id:`${A}-${$.id}`,path:`/${x}/${u}`,title:`${this.capitalize(A)}: ${u}`,description:`View ${A} details`,...c&&{layout:c},sections:[{id:"detail",template:Q,dataQuery:{entityType:A,query:{id:u}}}],sourceEntityType:A};try{this.routeRegistry.register(Y)}catch(F){f.warn(`Failed to register detail route for ${A}/${$.id}`,{error:F})}}let I=w?B.length+1:B.length;f.debug(`Successfully registered ${I} routes for ${A}`)}catch(B){f.error(`Failed to list entities for type: ${A}`,{error:B})}}async generatePaginatedRoutes(A,f,w,Q,B,x,c,I){let u=(await this.context.entityService.listEntities(A,{limit:1000})).length,Y=Math.max(1,Math.ceil(u/x));I.debug(`Generating ${Y} paginated routes for ${A}`,{totalItems:u,pageSize:x});for(let F=1;F<=Y;F++){let K=F===1,Z=K?`/${w}`:`/${w}/page/${F}`,k={id:`${A}-index${K?"":`-page-${F}`}`,path:Z,title:K?Q:`${Q} - Page ${F}`,description:`Browse all ${w}${K?"":` - Page ${F}`}`,...B&&{layout:B},navigation:K?{show:c.show,label:Q,slot:c.slot,priority:c.priority}:void 0,sections:[{id:"list",template:f,dataQuery:{entityType:A,query:{page:F,pageSize:x,baseUrl:`/${w}`}}}],sourceEntityType:A};try{this.routeRegistry.register(k),I.debug(`Registered paginated route for ${A}`,{path:k.path,page:F})}catch(h){I.warn(`Failed to register paginated route for ${A} page ${F}`,{error:h})}}}findTemplatesForEntityType(A){let f=this.context.views.list(),w,Q,B=`${A}-list`,x=`${A}-detail`;for(let I of f){let $=I.name;if($.endsWith(B)){let u=$.slice(0,-B.length);if(u===""||u.endsWith(":"))w=$}if($.endsWith(x)){let u=$.slice(0,-x.length);if(u===""||u.endsWith(":"))Q=$}}let c={};if(w)c.listTemplateName=w;if(Q)c.detailTemplateName=Q;return c}getEntityDisplayConfig(A){let f=this.entityDisplay?.[A],w=10,Q=!0,B=!0,x="primary",c=40;if(f){let $=f.pluralName??q7(f.label.toLowerCase()),u=this.capitalize(q7(f.label.toLowerCase()));return{pluralName:$,label:u,...f.layout&&{layout:f.layout},paginate:f.paginate??!0,pageSize:f.pageSize??10,navigation:{show:f.navigation?.show??!0,slot:f.navigation?.slot??"primary",priority:f.navigation?.priority??40}}}let I=q7(A);return{pluralName:I,label:this.capitalize(I),paginate:!0,pageSize:10,navigation:{show:!0,slot:"primary",priority:40}}}capitalize(A){return A.split(" ").map((f)=>f.charAt(0).toUpperCase()+f.slice(1)).join(" ")}}B0();YA();B0();var GS0=X.object({}),bM=v2.extend({id:X.literal("site-info"),entityType:X.literal("site-info"),metadata:GS0}),zM=X.object({heading:X.string().describe("Main CTA heading text"),buttonText:X.string().describe("Call-to-action button text"),buttonLink:X.string().describe("URL or anchor for the CTA button")}),bu=X.object({title:X.string().describe("The site's title"),description:X.string().describe("The site's description"),copyright:X.string().optional().describe("Copyright notice text"),logo:X.boolean().optional().describe("Whether to display logo instead of title text in header"),themeMode:X.enum(["light","dark"]).optional().describe("Default theme mode"),cta:zM.optional().describe("Call-to-action configuration")});B0();class MI extends _2{constructor(){super({entityType:"site-info",schema:bM,frontmatterSchema:bu,isSingleton:!0,hasBody:!1})}createSiteInfoContent(A){let f=bu.parse(A);return this.buildMarkdown("",f)}parseSiteInfoBody(A){return this.parseFrontmatter(A)}toMarkdown(A){return A.content}fromMarkdown(A){return{content:A,entityType:"site-info"}}extractMetadata(A){return{}}generateFrontMatter(A){let f=this.parseFrontmatter(A.content);return this.buildMarkdown("",f)}}class zu{static instance=null;logger;entityService;adapter;defaultSiteInfo;static getDefaultSiteInfo(){return{title:"Brain",description:"A knowledge management system"}}static getInstance(A,f,w){return zu.instance??=new zu(A,f,w),zu.instance}static resetInstance(){zu.instance=null}static createFresh(A,f,w){return new zu(A,f,w)}constructor(A,f,w){this.entityService=A,this.logger=f.child("SiteInfoService"),this.adapter=new MI;let Q=zu.getDefaultSiteInfo();this.defaultSiteInfo={...Q,...w}}async initialize(){try{if(!await this.entityService.getEntity("site-info","site-info")){this.logger.info("No site info found, creating default site info");let f=this.adapter.createSiteInfoContent(this.defaultSiteInfo);await this.entityService.createEntity({id:"site-info",entityType:"site-info",content:f,metadata:{}}),this.logger.info("Default site info created successfully")}}catch(A){this.logger.error("Failed to initialize site info",{error:A})}}async getSiteInfo(){try{let A=await this.entityService.getEntity("site-info","site-info");if(A)return this.adapter.parseSiteInfoBody(A.content)}catch(A){this.logger.debug("Site info not found, using defaults",{error:A})}return this.defaultSiteInfo}}var rP2=new MI;class go{logger;id="site-info:entities";name="Site Info DataSource";description="Provides site metadata (title, description, CTA) and profile social links";constructor(A){this.logger=A}async fetch(A,f,w){let{entityService:Q}=w,B;try{let I=await Q.getEntity("site-info","site-info");B=I?rP2.parseSiteInfoBody(I.content):{title:"Brain",description:"A knowledge management system"}}catch{B={title:"Brain",description:"A knowledge management system"}}let x;try{let I=await Q.getEntity("anchor-profile","anchor-profile");if(I)x=I.metadata.socialLinks}catch{}let c={...B,socialLinks:x,copyright:B.copyright??"Powered by Rizom"};return this.logger.debug("SiteInfoDataSource returning",{title:c.title,hasSocialLinks:!!c.socialLinks}),f.parse(c)}}var JS0={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.8",description:"Site info entity \u2014 site metadata, title, description, CTA",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},dependencies:{"@brains/entity-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var oP2=new MI;class TZA extends Nf{entityType="site-info";schema=bM;adapter=oP2;defaultSiteInfo;constructor(A){super("site-info",JS0);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new go(this.logger.child("SiteInfoDataSource"))]}async onRegister(A){let f=zu.createFresh(A.entityService,this.logger,this.defaultSiteInfo);A.messaging.subscribe("sync:initial:completed",async()=>{return await f.initialize(),{success:!0}})}}function kv(A){return new TZA(A)}var aP2=new MI;async function d3(A){let w=(await A.listEntities("site-info",{limit:1}))[0];if(!w)throw Error("Site info not found \u2014 create a site-info entity");return aP2.parseSiteInfoBody(w.content)}YA();var sP2=bu.extend({navigation:X.object({primary:X.array(X.object({label:X.string(),href:X.string(),priority:X.number()})),secondary:X.array(X.object({label:X.string(),href:X.string(),priority:X.number()}))}),copyright:X.string(),socialLinks:X.array(X.object({platform:X.enum(["github","instagram","linkedin","email","website"]).describe("Social media platform"),url:X.string().describe("Profile or contact URL"),label:X.string().optional().describe("Optional display label")})).optional().describe("Social media links from profile entity")});async function bS0(A,f,w){let Q;try{Q=await d3(A)}catch{Q={title:"Brain",description:"A knowledge management system"}}let B=f.getProfile(),x=w.getNavigationItems("primary"),c=w.getNavigationItems("secondary");return{...Q,socialLinks:B.socialLinks,navigation:{primary:x,secondary:c},copyright:Q.copyright??"Powered by Rizom"}}YA();YA();import{promises as dr0}from"fs";import{join as vT2}from"path";import{createHash as UT2}from"crypto";import{promises as XvA}from"fs";import{join as yr0}from"path";var Sr0=null;async function FT2(){return Sr0??=Promise.resolve().then(() => o0(Tr0(),1)).then((A)=>A.default),Sr0}var KT2=[480,960,1920],XT2=80,ZT2="(max-width: 640px) 480px, (max-width: 1280px) 960px, 1920px";class ZvA{imagesDir;logger;constructor(A,f){this.imagesDir=A;this.logger=f.child("ImageOptimizer")}async optimize(A,f){try{let w=await FT2(),Q=UT2("sha256").update(A).digest("hex").slice(0,16),B=await w(A).metadata();if(!B.width||!B.height)return this.logger.warn("Could not determine image dimensions",{originalUrl:f}),null;let{width:x,height:c}=B,I=[];for(let F of KT2){if(F>x)continue;let K=`${Q}-${F}w.webp`,Z=yr0(this.imagesDir,K),k=`/images/${K}`;if(await XvA.access(Z).then(()=>!0).catch(()=>!1)){this.logger.debug("Cache hit, skipping optimization",{fileName:K}),I.push({width:F,url:k});continue}await w(A).resize(F,null,{withoutEnlargement:!0}).webp({quality:XT2}).toFile(Z),I.push({width:F,url:k}),this.logger.debug("Created WebP variant",{fileName:K,width:F})}if(I.length===0)return null;let $=I[I.length-1];if(!$)return null;let u=I.find((F)=>F.width===960)??$,Y=Math.round(c*(u.width/x));return{src:u.url,srcset:I.map((F)=>`${F.url} ${F.width}w`).join(", "),sizes:ZT2,width:u.width,height:Y}}catch(w){return this.logger.warn("Image optimization failed, using original",{originalUrl:f,error:w instanceof Error?w.message:String(w)}),null}}async optimizeAll(){let A={},f;try{f=await XvA.readdir(this.imagesDir,{withFileTypes:!0})}catch{return this.logger.debug("Images directory does not exist, nothing to optimize"),A}let w=f.filter((Q)=>Q.isFile()&&/\.(png|jpe?g)$/i.test(Q.name));if(w.length===0)return this.logger.debug("No PNG/JPEG images found to optimize"),A;this.logger.debug(`Optimizing ${w.length} images`);for(let Q of w){let B=yr0(this.imagesDir,Q.name),x=`/images/${Q.name}`;try{let c=await XvA.readFile(B),I=await this.optimize(c,x);if(I)A[x]=I}catch(c){this.logger.warn("Failed to optimize image",{file:Q.name,error:c instanceof Error?c.message:String(c)})}}return this.logger.debug(`Optimized ${Object.keys(A).length}/${w.length} images`),A}}function pr0(A,f){if(A.format)return A.format;return f.match(/^data:image\/([^;]+);/)?.[1]??"png"}function rr0(A){return A.match(/^data:image\/[^;]+;base64,(.+)$/)?.[1]??null}function gb(A){return A.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}class vvA{entityService;logger;imageMap={};imagesDir;optimizer;constructor(A,f,w){this.entityService=A;this.logger=f.child("ImageBuildService"),this.imagesDir=w,this.optimizer=new ZvA(this.imagesDir,this.logger)}async resolveAll(A){let f=[...new Set(A)];if(f.length===0)return;await dr0.mkdir(this.imagesDir,{recursive:!0});let w=VK(4);await Promise.all(f.map((Q)=>w(async()=>{try{await this.resolveImage(Q)}catch(B){this.logger.warn("Failed to resolve image",{imageId:Q,error:B instanceof Error?B.message:String(B)})}}))),this.logger.debug(`Resolved ${Object.keys(this.imageMap).length}/${f.length} images`)}async resolveImage(A){let f=await this.entityService.getEntity("image",A);if(!f?.content){this.logger.warn("Image entity not found or has no content",{imageId:A});return}let w=rr0(f.content);if(!w){this.logger.warn("Could not extract base64 from image",{imageId:A});return}let Q=Buffer.from(w,"base64"),B=pr0(f.metadata,f.content),x=`${A}.${B}`,c=vT2(this.imagesDir,x);await dr0.writeFile(c,Q);let I=`/images/${x}`,$=await this.optimizer.optimize(Q,I);if($)this.imageMap[A]={src:$.src,srcset:$.srcset,sizes:$.sizes,width:$.width,height:$.height};else this.imageMap[A]={src:I,width:f.metadata.width??0,height:f.metadata.height??0};this.logger.debug("Resolved image",{imageId:A,optimized:Boolean($)})}get(A){return this.imageMap[A]}getMap(){return this.imageMap}createImageRenderer(){let A=this.imageMap;return(f,w,Q)=>{let B=/^entity:\/\/image\/(.+)$/.exec(f);if(!B?.[1])return;let x=A[B[1]];if(!x)return;let c=[`src="${gb(x.src)}"`,`alt="${gb(Q)}"`];if(x.srcset)c.push(`srcset="${gb(x.srcset)}"`);if(x.sizes)c.push(`sizes="${gb(x.sizes)}"`);if(x.width)c.push(`width="${x.width}"`);if(x.height)c.push(`height="${x.height}"`);if(w)c.push(`title="${gb(w)}"`);return c.push('loading="lazy"'),c.push('decoding="async"'),`<img ${c.join(" ")}>`}}}var kT2=v2.extend({metadata:X.object({slug:X.string()}).passthrough()});class O5{static instance=null;static defaultStaticSiteBuilderFactory=mZA;logger;context;staticSiteBuilderFactory;routeRegistry;profileService;entityDisplay;imageBuildService=null;static setDefaultStaticSiteBuilderFactory(A){O5.defaultStaticSiteBuilderFactory=A}static getInstance(A,f,w,Q,B){return O5.instance??=new O5(A,O5.defaultStaticSiteBuilderFactory,f,w,Q,B),O5.instance}static resetInstance(){O5.instance=null}static createFresh(A,f,w,Q,B,x){return new O5(A,B??O5.defaultStaticSiteBuilderFactory,f,w,Q,x)}constructor(A,f,w,Q,B,x){this.logger=A,this.context=w,this.staticSiteBuilderFactory=f,this.routeRegistry=Q,this.profileService=B,this.entityDisplay=x,Qc.getInstance().configure(x)}async getSiteInfo(){return bS0(this.context.entityService,this.profileService,this.routeRegistry)}async build(A,f){let w=rO0.parse(A),Q=bx.from(f),B=[],x=[];try{await Q?.report({message:"Starting site build",progress:0,total:100}),await Q?.report({message:"Generating dynamic routes",progress:10,total:100}),await new lZA(this.context,this.routeRegistry,this.entityDisplay).generateEntityRoutes();let I=w.workingDir??WT2(w.outputDir,".preact-work"),$=this.staticSiteBuilderFactory({logger:this.logger.child("StaticSiteBuilder"),workingDir:I,outputDir:w.outputDir});if(w.cleanBeforeBuild)await $.clean();let u=this.routeRegistry.list();if(u.length===0)x.push("No routes registered for site build");await Q?.report({message:`Building ${u.length} routes`,progress:20,total:100}),await Q?.report({message:"Resolving images",progress:25,total:100}),this.imageBuildService=new vvA(this.context.entityService,this.logger,w.sharedImagesDir);let Y=await this.collectAllImageIds();if(Y.length>0)await this.imageBuildService.resolveAll(Y);let F=w.siteConfig,K={routes:u,pluginContext:this.context,siteConfig:{title:F.title,description:F.description,...F.url&&{url:F.url},...F.copyright&&{copyright:F.copyright},...F.themeMode&&{themeMode:F.themeMode},...F.analyticsScript&&{analyticsScript:F.analyticsScript}},headScripts:A.headScripts,...A.staticAssets&&{staticAssets:A.staticAssets},getContent:async(E,V)=>{let q=w.environment==="production";return this.getContentForSection(V,E,q)},getViewTemplate:(E)=>{return this.context.views.get(E)},layouts:w.layouts,getSiteInfo:async()=>{return this.getSiteInfo()},...w.themeCSS!==void 0&&{themeCSS:w.themeCSS},...A.slots&&{slots:A.slots},imageBuildService:this.imageBuildService},Z=0,k=u.length+4;await $.build(K,(E)=>{Z++;let V=85+Math.round(Z/k*10);Q?.report({message:E,progress:V,total:100}).catch(()=>{})}),await Q?.report({message:"Site build complete",progress:100,total:100});let h=u.length+1,G={success:B.length===0,outputDir:w.outputDir,filesGenerated:h,routesBuilt:u.length};if(B.length>0)G.errors=B;if(x.length>0)G.warnings=x;return G}catch(c){let I=Error("Site build process failed");return this.logger.error("Site build failed",{error:I,originalError:c}),B.push(I.message),{success:!1,outputDir:w.outputDir,filesGenerated:0,routesBuilt:0,errors:B}}}async getContentForSection(A,f,w){if(!A.template)return A.content??null;let Q=A.template,B=Qc.getInstance();if(A.dataQuery){let c={dataParams:A.dataQuery,fallback:A.content,publishedOnly:w},I=await this.context.templates.resolve(Q,c);if(I)return this.enrichWithUrls(I,B);return null}let x=await this.context.templates.resolve(Q,{savedContent:{entityType:"site-content",entityId:`${f.id}:${A.id}`},fallback:A.content});if(x)return this.enrichWithUrls(x,B);return null}async enrichWithUrls(A,f){if(A===null||A===void 0)return A;if(Array.isArray(A))return Promise.all(A.map((q)=>this.enrichWithUrls(q,f)));if(typeof A!=="object")return A;let w=A,Q={},B=Object.entries(w),x=await Promise.all(B.map(([,q])=>this.enrichWithUrls(q,f)));for(let q=0;q<B.length;q++){let y=B[q];if(y)Q[y[0]]=x[q]}let c=kT2.safeParse(w);if(!c.success)return Q;let I=c.data,$=I.entityType,u=I.metadata.slug,Y=this.entityDisplay?.[$],F=Y?Y.label:$.charAt(0).toUpperCase()+$.slice(1),K=Y?Y.pluralName??Y.label.toLowerCase()+"s":q7($),Z=`/${K}`,k=K.charAt(0).toUpperCase()+K.slice(1),h=tL(I),G=h?this.imageBuildService?.get(h):void 0,E={};if(G)E={coverImageUrl:G.src,coverImageWidth:G.width,coverImageHeight:G.height,...G.srcset&&{coverImageSrcset:G.srcset,coverImageSizes:G.sizes}};else{let q=await eL(I,this.context.entityService);if(q)E={coverImageUrl:q.url,coverImageWidth:q.width,coverImageHeight:q.height}}return{...Q,...I,url:f.generateUrl($,u),typeLabel:F,listUrl:Z,listLabel:k,...E}}async collectAllImageIds(){let A=new Set;try{let f=this.context.entityService.getEntityTypes();for(let w of f){if(w==="image")continue;let Q=await this.context.entityService.listEntities(w);for(let B of Q){let x=tL(B);if(x)A.add(x)}}}catch(f){this.logger.warn("Failed to collect image IDs for pre-resolution",{error:f instanceof Error?f.message:String(f)})}return[...A]}}B0();class WvA{logger;routes=new Map;constructor(A){this.logger=A}register(A){let f=Array.isArray(A)?A:[A];for(let w of f){let Q=gk.parse(w);if(this.routes.has(Q.path)){let B=this.routes.get(Q.path);this.logger.debug(`Overriding route "${Q.path}" (was registered by plugin "${B?.pluginId}")`)}this.routes.set(Q.path,Q)}}unregister(A){(Array.isArray(A)?A:[A]).forEach((w)=>this.routes.delete(w))}unregisterByPlugin(A){for(let[f,w]of this.routes.entries())if(w.pluginId===A)this.routes.delete(f)}get(A){return this.routes.get(A)}list(A){let f=Array.from(this.routes.values()).filter((w)=>!w.external);if(A?.pluginId)f=f.filter((w)=>w.pluginId===A.pluginId);return f}listByPlugin(A){return this.list({pluginId:A})}clear(){this.routes.clear()}size(){return this.routes.size}getNavigationItems(A){let f=[];for(let[w,Q]of this.routes.entries())if(Q.navigation?.show&&Q.navigation.slot===A)f.push({label:Q.navigation.label??Q.title,href:w,priority:Q.navigation.priority});return f.sort((w,Q)=>w.priority-Q.priority)}}class wa{slots=new Map;register(A,f){let w={...f,priority:f.priority??50},Q=this.slots.get(A)??[];Q.push(w),this.slots.set(A,Q)}getSlot(A){return[...this.slots.get(A)??[]].sort((w,Q)=>Q.priority-w.priority)}hasSlot(A){let f=this.slots.get(A);return f!==void 0&&f.length>0}unregister(A,f){let w=this.slots.get(A);if(!w)return;let Q=w.filter((B)=>B.pluginId!==f);if(Q.length>0)this.slots.set(A,Q);else this.slots.delete(A)}unregisterAll(A){for(let[f,w]of this.slots){let Q=w.filter((B)=>B.pluginId!==A);if(Q.length>0)this.slots.set(f,Q);else this.slots.delete(f)}}getSlotNames(){return Array.from(this.slots.keys())}clear(){this.slots.clear()}}YA();class kvA{config;context;pluginId;logger;debounces=new Map;unsubscribeFunctions=[];constructor(A,f,w,Q){this.config=A;this.context=f;this.pluginId=w;this.logger=Q}requestBuild(A){let f=A??(this.config.previewOutputDir?"preview":"production"),w=this.debounces.get(f);if(!w)w=new jK(()=>{this.enqueueBuild(f)},this.config.rebuildDebounce),this.debounces.set(f,w);w.trigger()}setupAutoRebuild(){let A=new Set(["base"]),f=async(Q)=>{let{entityType:B}=Q.payload;if(!A.has(B))this.logger.debug(`Entity type ${B} will trigger rebuild`),this.requestBuild();return{success:!0}},w=["entity:created","entity:updated","entity:deleted"];for(let Q of w)this.unsubscribeFunctions.push(this.context.messaging.subscribe(Q,f));this.logger.debug(`Auto-rebuild enabled (${this.config.rebuildDebounce}ms debounce), excluding types: ${[...A].join(", ")}`)}dispose(){for(let A of this.debounces.values())A.dispose();this.debounces.clear();for(let A of this.unsubscribeFunctions)A();this.unsubscribeFunctions=[]}async enqueueBuild(A){let f=A==="production"?this.config.productionOutputDir:this.config.previewOutputDir;this.logger.debug(`Triggering ${A} site rebuild`);try{await this.context.jobs.enqueue("site-build",{environment:A,outputDir:f,workingDir:this.config.workingDir,enableContentGeneration:!0,metadata:{trigger:"debounced-rebuild",timestamp:new Date().toISOString()}},null,{priority:0,source:this.pluginId,metadata:{operationType:"content_operations"},deduplication:"skip"}),this.logger.debug("Site rebuild enqueued")}catch(w){this.logger.error("Failed to enqueue site rebuild",{error:w})}}}B0();function hT2(A,f){return A.map((w)=>({...w,template:w.template.includes(":")?w.template:`${f}:${w.template}`}))}function Qa(A,f,w){for(let Q of A)w.register({...Q,pluginId:f,sections:Q.sections?hT2(Q.sections,f):[]})}function or0(A,f,w){A.messaging.subscribe("plugin:site-builder:route:register",async(Q)=>{try{let B=m2A.parse(Q.payload),{routes:x,pluginId:c}=B;return Qa(x,c,f),{success:!0}}catch(B){return w.error("Failed to register routes",{error:B}),{success:!1,error:"Failed to register routes"}}}),A.messaging.subscribe("plugin:site-builder:route:unregister",async(Q)=>{try{let B=l2A.parse(Q.payload),{paths:x,pluginId:c}=B;if(x)for(let I of x)f.unregister(I);else if(c)f.unregisterByPlugin(c);return{success:!0}}catch(B){return w.error("Failed to unregister routes",{error:B}),{success:!1,error:"Failed to unregister routes"}}}),A.messaging.subscribe("plugin:site-builder:route:list",async(Q)=>{try{let B=T2A.parse(Q.payload);return{success:!0,data:{routes:f.list(B.pluginId?B:void 0)}}}catch(B){return w.error("Failed to list routes",{error:B}),{success:!1,error:"Failed to list routes"}}}),A.messaging.subscribe("plugin:site-builder:route:get",async(Q)=>{try{let B=y2A.parse(Q.payload);return{success:!0,data:{route:f.get(B.path)}}}catch(B){return w.error("Failed to get route",{error:B}),{success:!1,error:"Failed to get route"}}}),A.messaging.subscribe("site-builder:routes:list",async()=>{return{success:!0,data:f.list()}})}YA();import{promises as VM}from"fs";import{join as iM}from"path";function ar0(A,f){if(f==="preview")return`User-agent: *
2701
+ `+I;await ux.writeFile(c,u,"utf-8")}this.logger.debug("CSS processed successfully with font imports")}async copyStaticAssets(){this.logger.debug("Copying static assets from public/ directory");let A=Ju(process.cwd(),"public");try{await ux.access(A)}catch{this.logger.debug("No public/ directory found, skipping static assets");return}let f=await ux.readdir(A,{withFileTypes:!0});for(let w of f){let Q=Ju(A,w.name),B=Ju(this.outputDir,w.name);if(w.isDirectory())await this.copyDirectory(Q,B);else await ux.copyFile(Q,B),this.logger.debug(`Copied static asset: ${w.name}`)}this.logger.debug("Static assets copied successfully")}async writeInlineStaticAssets(A){if(!A)return;let f=Object.entries(A);if(f.length===0)return;this.logger.debug(`Writing ${f.length} inline static asset(s) from SitePackage`),await Promise.all(f.map(async([w,Q])=>{let B=w.startsWith("/")?w.slice(1):w,x=Ju(this.outputDir,B);await ux.mkdir(SP2(x),{recursive:!0}),await ux.writeFile(x,Q,"utf-8"),this.logger.debug(`Wrote inline static asset: ${B}`)}))}async copyDirectory(A,f){await ux.mkdir(f,{recursive:!0});let w=await ux.readdir(A,{withFileTypes:!0});for(let Q of w){let B=Ju(A,Q.name),x=Ju(f,Q.name);if(Q.isDirectory())await this.copyDirectory(B,x);else await ux.copyFile(B,x)}}}function mZA(A){return new hS0(A)}function pP2(A,f){let w=new Map;for(let Q of A.sections){let B=f.getViewTemplate(Q.template);if(!B?.runtimeScripts)continue;for(let x of B.runtimeScripts)if(!w.has(x.src))w.set(x.src,x)}return[...w.values()].map((Q)=>{let B=[`src="${Q.src}"`];if(Q.defer)B.push("defer");if(Q.module)B.push('type="module"');return`<script ${B.join(" ")}></script>`})}import{join as WT2}from"path";YA();class lZA{context;routeRegistry;entityDisplay;constructor(A,f,w){this.context=A;this.routeRegistry=f;this.entityDisplay=w}async generateEntityRoutes(){let A=this.context.logger.child("DynamicRouteGenerator"),f=this.routeRegistry.list(),w=0;for(let B of f)if(B.sourceEntityType)this.routeRegistry.unregister(B.path),w++;if(w>0)A.debug(`Cleared ${w} dynamic routes before regeneration`);let Q=this.context.entityService.getEntityTypes();A.debug(`Found ${Q.length} entity types`,{entityTypes:Q});for(let B of Q)await this.generateRoutesForEntityType(B)}async generateRoutesForEntityType(A){let f=this.context.logger.child("DynamicRouteGenerator"),{listTemplateName:w,detailTemplateName:Q}=this.findTemplatesForEntityType(A);if(!w&&!Q){f.debug(`No matching templates found for entity type: ${A}`);return}if(f.debug(`Generating routes for entity type: ${A}`,{listTemplate:w,detailTemplate:Q}),w){let{pluralName:B,label:x,layout:c,paginate:I,pageSize:$,navigation:u}=this.getEntityDisplayConfig(A);if(I)await this.generatePaginatedRoutes(A,w,B,x,c,$,u,f);else{let Y={id:`${A}-index`,path:`/${B}`,title:x,description:`Browse all ${B}`,...c&&{layout:c},navigation:{show:u.show,label:x,slot:u.slot,priority:u.priority},sections:[{id:"list",template:w,dataQuery:{entityType:A,query:{limit:100}}}],sourceEntityType:A};try{this.routeRegistry.register(Y),f.debug(`Registered index route for ${A}`,{path:Y.path})}catch(F){f.warn(`Failed to register index route for ${A}`,{error:F})}}}if(Q)try{let B=await this.context.entityService.listEntities(A,{limit:1000});f.debug(`Found ${B.length} ${A} entities to generate routes for`);let{pluralName:x,layout:c}=this.getEntityDisplayConfig(A);for(let $ of B){let u="slug"in $.metadata?$.metadata.slug:$.id,Y={id:`${A}-${$.id}`,path:`/${x}/${u}`,title:`${this.capitalize(A)}: ${u}`,description:`View ${A} details`,...c&&{layout:c},sections:[{id:"detail",template:Q,dataQuery:{entityType:A,query:{id:u}}}],sourceEntityType:A};try{this.routeRegistry.register(Y)}catch(F){f.warn(`Failed to register detail route for ${A}/${$.id}`,{error:F})}}let I=w?B.length+1:B.length;f.debug(`Successfully registered ${I} routes for ${A}`)}catch(B){f.error(`Failed to list entities for type: ${A}`,{error:B})}}async generatePaginatedRoutes(A,f,w,Q,B,x,c,I){let u=(await this.context.entityService.listEntities(A,{limit:1000})).length,Y=Math.max(1,Math.ceil(u/x));I.debug(`Generating ${Y} paginated routes for ${A}`,{totalItems:u,pageSize:x});for(let F=1;F<=Y;F++){let K=F===1,Z=K?`/${w}`:`/${w}/page/${F}`,k={id:`${A}-index${K?"":`-page-${F}`}`,path:Z,title:K?Q:`${Q} - Page ${F}`,description:`Browse all ${w}${K?"":` - Page ${F}`}`,...B&&{layout:B},navigation:K?{show:c.show,label:Q,slot:c.slot,priority:c.priority}:void 0,sections:[{id:"list",template:f,dataQuery:{entityType:A,query:{page:F,pageSize:x,baseUrl:`/${w}`}}}],sourceEntityType:A};try{this.routeRegistry.register(k),I.debug(`Registered paginated route for ${A}`,{path:k.path,page:F})}catch(h){I.warn(`Failed to register paginated route for ${A} page ${F}`,{error:h})}}}findTemplatesForEntityType(A){let f=this.context.views.list(),w,Q,B=`${A}-list`,x=`${A}-detail`;for(let I of f){let $=I.name;if($.endsWith(B)){let u=$.slice(0,-B.length);if(u===""||u.endsWith(":"))w=$}if($.endsWith(x)){let u=$.slice(0,-x.length);if(u===""||u.endsWith(":"))Q=$}}let c={};if(w)c.listTemplateName=w;if(Q)c.detailTemplateName=Q;return c}getEntityDisplayConfig(A){let f=this.entityDisplay?.[A],w=10,Q=!0,B=!0,x="primary",c=40;if(f){let $=f.pluralName??q7(f.label.toLowerCase()),u=this.capitalize(q7(f.label.toLowerCase()));return{pluralName:$,label:u,...f.layout&&{layout:f.layout},paginate:f.paginate??!0,pageSize:f.pageSize??10,navigation:{show:f.navigation?.show??!0,slot:f.navigation?.slot??"primary",priority:f.navigation?.priority??40}}}let I=q7(A);return{pluralName:I,label:this.capitalize(I),paginate:!0,pageSize:10,navigation:{show:!0,slot:"primary",priority:40}}}capitalize(A){return A.split(" ").map((f)=>f.charAt(0).toUpperCase()+f.slice(1)).join(" ")}}B0();YA();B0();var GS0=X.object({}),bM=v2.extend({id:X.literal("site-info"),entityType:X.literal("site-info"),metadata:GS0}),zM=X.object({heading:X.string().describe("Main CTA heading text"),buttonText:X.string().describe("Call-to-action button text"),buttonLink:X.string().describe("URL or anchor for the CTA button")}),bu=X.object({title:X.string().describe("The site's title"),description:X.string().describe("The site's description"),copyright:X.string().optional().describe("Copyright notice text"),logo:X.boolean().optional().describe("Whether to display logo instead of title text in header"),themeMode:X.enum(["light","dark"]).optional().describe("Default theme mode"),cta:zM.optional().describe("Call-to-action configuration")});B0();class MI extends _2{constructor(){super({entityType:"site-info",schema:bM,frontmatterSchema:bu,isSingleton:!0,hasBody:!1})}createSiteInfoContent(A){let f=bu.parse(A);return this.buildMarkdown("",f)}parseSiteInfoBody(A){return this.parseFrontmatter(A)}toMarkdown(A){return A.content}fromMarkdown(A){return{content:A,entityType:"site-info"}}extractMetadata(A){return{}}generateFrontMatter(A){let f=this.parseFrontmatter(A.content);return this.buildMarkdown("",f)}}class zu{static instance=null;logger;entityService;adapter;defaultSiteInfo;static getDefaultSiteInfo(){return{title:"Brain",description:"A knowledge management system"}}static getInstance(A,f,w){return zu.instance??=new zu(A,f,w),zu.instance}static resetInstance(){zu.instance=null}static createFresh(A,f,w){return new zu(A,f,w)}constructor(A,f,w){this.entityService=A,this.logger=f.child("SiteInfoService"),this.adapter=new MI;let Q=zu.getDefaultSiteInfo();this.defaultSiteInfo={...Q,...w}}async initialize(){try{if(!await this.entityService.getEntity("site-info","site-info")){this.logger.info("No site info found, creating default site info");let f=this.adapter.createSiteInfoContent(this.defaultSiteInfo);await this.entityService.createEntity({id:"site-info",entityType:"site-info",content:f,metadata:{}}),this.logger.info("Default site info created successfully")}}catch(A){this.logger.error("Failed to initialize site info",{error:A})}}async getSiteInfo(){try{let A=await this.entityService.getEntity("site-info","site-info");if(A)return this.adapter.parseSiteInfoBody(A.content)}catch(A){this.logger.debug("Site info not found, using defaults",{error:A})}return this.defaultSiteInfo}}var rP2=new MI;class go{logger;id="site-info:entities";name="Site Info DataSource";description="Provides site metadata (title, description, CTA) and profile social links";constructor(A){this.logger=A}async fetch(A,f,w){let{entityService:Q}=w,B;try{let I=await Q.getEntity("site-info","site-info");B=I?rP2.parseSiteInfoBody(I.content):{title:"Brain",description:"A knowledge management system"}}catch{B={title:"Brain",description:"A knowledge management system"}}let x;try{let I=await Q.getEntity("anchor-profile","anchor-profile");if(I)x=I.metadata.socialLinks}catch{}let c={...B,socialLinks:x,copyright:B.copyright??"Powered by Rizom"};return this.logger.debug("SiteInfoDataSource returning",{title:c.title,hasSocialLinks:!!c.socialLinks}),f.parse(c)}}var JS0={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.9",description:"Site info entity \u2014 site metadata, title, description, CTA",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},dependencies:{"@brains/entity-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var oP2=new MI;class TZA extends Nf{entityType="site-info";schema=bM;adapter=oP2;defaultSiteInfo;constructor(A){super("site-info",JS0);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new go(this.logger.child("SiteInfoDataSource"))]}async onRegister(A){let f=zu.createFresh(A.entityService,this.logger,this.defaultSiteInfo);A.messaging.subscribe("sync:initial:completed",async()=>{return await f.initialize(),{success:!0}})}}function kv(A){return new TZA(A)}var aP2=new MI;async function d3(A){let w=(await A.listEntities("site-info",{limit:1}))[0];if(!w)throw Error("Site info not found \u2014 create a site-info entity");return aP2.parseSiteInfoBody(w.content)}YA();var sP2=bu.extend({navigation:X.object({primary:X.array(X.object({label:X.string(),href:X.string(),priority:X.number()})),secondary:X.array(X.object({label:X.string(),href:X.string(),priority:X.number()}))}),copyright:X.string(),socialLinks:X.array(X.object({platform:X.enum(["github","instagram","linkedin","email","website"]).describe("Social media platform"),url:X.string().describe("Profile or contact URL"),label:X.string().optional().describe("Optional display label")})).optional().describe("Social media links from profile entity")});async function bS0(A,f,w){let Q;try{Q=await d3(A)}catch{Q={title:"Brain",description:"A knowledge management system"}}let B=f.getProfile(),x=w.getNavigationItems("primary"),c=w.getNavigationItems("secondary");return{...Q,socialLinks:B.socialLinks,navigation:{primary:x,secondary:c},copyright:Q.copyright??"Powered by Rizom"}}YA();YA();import{promises as dr0}from"fs";import{join as vT2}from"path";import{createHash as UT2}from"crypto";import{promises as XvA}from"fs";import{join as yr0}from"path";var Sr0=null;async function FT2(){return Sr0??=Promise.resolve().then(() => o0(Tr0(),1)).then((A)=>A.default),Sr0}var KT2=[480,960,1920],XT2=80,ZT2="(max-width: 640px) 480px, (max-width: 1280px) 960px, 1920px";class ZvA{imagesDir;logger;constructor(A,f){this.imagesDir=A;this.logger=f.child("ImageOptimizer")}async optimize(A,f){try{let w=await FT2(),Q=UT2("sha256").update(A).digest("hex").slice(0,16),B=await w(A).metadata();if(!B.width||!B.height)return this.logger.warn("Could not determine image dimensions",{originalUrl:f}),null;let{width:x,height:c}=B,I=[];for(let F of KT2){if(F>x)continue;let K=`${Q}-${F}w.webp`,Z=yr0(this.imagesDir,K),k=`/images/${K}`;if(await XvA.access(Z).then(()=>!0).catch(()=>!1)){this.logger.debug("Cache hit, skipping optimization",{fileName:K}),I.push({width:F,url:k});continue}await w(A).resize(F,null,{withoutEnlargement:!0}).webp({quality:XT2}).toFile(Z),I.push({width:F,url:k}),this.logger.debug("Created WebP variant",{fileName:K,width:F})}if(I.length===0)return null;let $=I[I.length-1];if(!$)return null;let u=I.find((F)=>F.width===960)??$,Y=Math.round(c*(u.width/x));return{src:u.url,srcset:I.map((F)=>`${F.url} ${F.width}w`).join(", "),sizes:ZT2,width:u.width,height:Y}}catch(w){return this.logger.warn("Image optimization failed, using original",{originalUrl:f,error:w instanceof Error?w.message:String(w)}),null}}async optimizeAll(){let A={},f;try{f=await XvA.readdir(this.imagesDir,{withFileTypes:!0})}catch{return this.logger.debug("Images directory does not exist, nothing to optimize"),A}let w=f.filter((Q)=>Q.isFile()&&/\.(png|jpe?g)$/i.test(Q.name));if(w.length===0)return this.logger.debug("No PNG/JPEG images found to optimize"),A;this.logger.debug(`Optimizing ${w.length} images`);for(let Q of w){let B=yr0(this.imagesDir,Q.name),x=`/images/${Q.name}`;try{let c=await XvA.readFile(B),I=await this.optimize(c,x);if(I)A[x]=I}catch(c){this.logger.warn("Failed to optimize image",{file:Q.name,error:c instanceof Error?c.message:String(c)})}}return this.logger.debug(`Optimized ${Object.keys(A).length}/${w.length} images`),A}}function pr0(A,f){if(A.format)return A.format;return f.match(/^data:image\/([^;]+);/)?.[1]??"png"}function rr0(A){return A.match(/^data:image\/[^;]+;base64,(.+)$/)?.[1]??null}function gb(A){return A.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}class vvA{entityService;logger;imageMap={};imagesDir;optimizer;constructor(A,f,w){this.entityService=A;this.logger=f.child("ImageBuildService"),this.imagesDir=w,this.optimizer=new ZvA(this.imagesDir,this.logger)}async resolveAll(A){let f=[...new Set(A)];if(f.length===0)return;await dr0.mkdir(this.imagesDir,{recursive:!0});let w=VK(4);await Promise.all(f.map((Q)=>w(async()=>{try{await this.resolveImage(Q)}catch(B){this.logger.warn("Failed to resolve image",{imageId:Q,error:B instanceof Error?B.message:String(B)})}}))),this.logger.debug(`Resolved ${Object.keys(this.imageMap).length}/${f.length} images`)}async resolveImage(A){let f=await this.entityService.getEntity("image",A);if(!f?.content){this.logger.warn("Image entity not found or has no content",{imageId:A});return}let w=rr0(f.content);if(!w){this.logger.warn("Could not extract base64 from image",{imageId:A});return}let Q=Buffer.from(w,"base64"),B=pr0(f.metadata,f.content),x=`${A}.${B}`,c=vT2(this.imagesDir,x);await dr0.writeFile(c,Q);let I=`/images/${x}`,$=await this.optimizer.optimize(Q,I);if($)this.imageMap[A]={src:$.src,srcset:$.srcset,sizes:$.sizes,width:$.width,height:$.height};else this.imageMap[A]={src:I,width:f.metadata.width??0,height:f.metadata.height??0};this.logger.debug("Resolved image",{imageId:A,optimized:Boolean($)})}get(A){return this.imageMap[A]}getMap(){return this.imageMap}createImageRenderer(){let A=this.imageMap;return(f,w,Q)=>{let B=/^entity:\/\/image\/(.+)$/.exec(f);if(!B?.[1])return;let x=A[B[1]];if(!x)return;let c=[`src="${gb(x.src)}"`,`alt="${gb(Q)}"`];if(x.srcset)c.push(`srcset="${gb(x.srcset)}"`);if(x.sizes)c.push(`sizes="${gb(x.sizes)}"`);if(x.width)c.push(`width="${x.width}"`);if(x.height)c.push(`height="${x.height}"`);if(w)c.push(`title="${gb(w)}"`);return c.push('loading="lazy"'),c.push('decoding="async"'),`<img ${c.join(" ")}>`}}}var kT2=v2.extend({metadata:X.object({slug:X.string()}).passthrough()});class O5{static instance=null;static defaultStaticSiteBuilderFactory=mZA;logger;context;staticSiteBuilderFactory;routeRegistry;profileService;entityDisplay;imageBuildService=null;static setDefaultStaticSiteBuilderFactory(A){O5.defaultStaticSiteBuilderFactory=A}static getInstance(A,f,w,Q,B){return O5.instance??=new O5(A,O5.defaultStaticSiteBuilderFactory,f,w,Q,B),O5.instance}static resetInstance(){O5.instance=null}static createFresh(A,f,w,Q,B,x){return new O5(A,B??O5.defaultStaticSiteBuilderFactory,f,w,Q,x)}constructor(A,f,w,Q,B,x){this.logger=A,this.context=w,this.staticSiteBuilderFactory=f,this.routeRegistry=Q,this.profileService=B,this.entityDisplay=x,Qc.getInstance().configure(x)}async getSiteInfo(){return bS0(this.context.entityService,this.profileService,this.routeRegistry)}async build(A,f){let w=rO0.parse(A),Q=bx.from(f),B=[],x=[];try{await Q?.report({message:"Starting site build",progress:0,total:100}),await Q?.report({message:"Generating dynamic routes",progress:10,total:100}),await new lZA(this.context,this.routeRegistry,this.entityDisplay).generateEntityRoutes();let I=w.workingDir??WT2(w.outputDir,".preact-work"),$=this.staticSiteBuilderFactory({logger:this.logger.child("StaticSiteBuilder"),workingDir:I,outputDir:w.outputDir});if(w.cleanBeforeBuild)await $.clean();let u=this.routeRegistry.list();if(u.length===0)x.push("No routes registered for site build");await Q?.report({message:`Building ${u.length} routes`,progress:20,total:100}),await Q?.report({message:"Resolving images",progress:25,total:100}),this.imageBuildService=new vvA(this.context.entityService,this.logger,w.sharedImagesDir);let Y=await this.collectAllImageIds();if(Y.length>0)await this.imageBuildService.resolveAll(Y);let F=w.siteConfig,K={routes:u,pluginContext:this.context,siteConfig:{title:F.title,description:F.description,...F.url&&{url:F.url},...F.copyright&&{copyright:F.copyright},...F.themeMode&&{themeMode:F.themeMode},...F.analyticsScript&&{analyticsScript:F.analyticsScript}},headScripts:A.headScripts,...A.staticAssets&&{staticAssets:A.staticAssets},getContent:async(E,V)=>{let q=w.environment==="production";return this.getContentForSection(V,E,q)},getViewTemplate:(E)=>{return this.context.views.get(E)},layouts:w.layouts,getSiteInfo:async()=>{return this.getSiteInfo()},...w.themeCSS!==void 0&&{themeCSS:w.themeCSS},...A.slots&&{slots:A.slots},imageBuildService:this.imageBuildService},Z=0,k=u.length+4;await $.build(K,(E)=>{Z++;let V=85+Math.round(Z/k*10);Q?.report({message:E,progress:V,total:100}).catch(()=>{})}),await Q?.report({message:"Site build complete",progress:100,total:100});let h=u.length+1,G={success:B.length===0,outputDir:w.outputDir,filesGenerated:h,routesBuilt:u.length};if(B.length>0)G.errors=B;if(x.length>0)G.warnings=x;return G}catch(c){let I=Error("Site build process failed");return this.logger.error("Site build failed",{error:I,originalError:c}),B.push(I.message),{success:!1,outputDir:w.outputDir,filesGenerated:0,routesBuilt:0,errors:B}}}async getContentForSection(A,f,w){if(!A.template)return A.content??null;let Q=A.template,B=Qc.getInstance();if(A.dataQuery){let c={dataParams:A.dataQuery,fallback:A.content,publishedOnly:w},I=await this.context.templates.resolve(Q,c);if(I)return this.enrichWithUrls(I,B);return null}let x=await this.context.templates.resolve(Q,{savedContent:{entityType:"site-content",entityId:`${f.id}:${A.id}`},fallback:A.content});if(x)return this.enrichWithUrls(x,B);return null}async enrichWithUrls(A,f){if(A===null||A===void 0)return A;if(Array.isArray(A))return Promise.all(A.map((q)=>this.enrichWithUrls(q,f)));if(typeof A!=="object")return A;let w=A,Q={},B=Object.entries(w),x=await Promise.all(B.map(([,q])=>this.enrichWithUrls(q,f)));for(let q=0;q<B.length;q++){let y=B[q];if(y)Q[y[0]]=x[q]}let c=kT2.safeParse(w);if(!c.success)return Q;let I=c.data,$=I.entityType,u=I.metadata.slug,Y=this.entityDisplay?.[$],F=Y?Y.label:$.charAt(0).toUpperCase()+$.slice(1),K=Y?Y.pluralName??Y.label.toLowerCase()+"s":q7($),Z=`/${K}`,k=K.charAt(0).toUpperCase()+K.slice(1),h=tL(I),G=h?this.imageBuildService?.get(h):void 0,E={};if(G)E={coverImageUrl:G.src,coverImageWidth:G.width,coverImageHeight:G.height,...G.srcset&&{coverImageSrcset:G.srcset,coverImageSizes:G.sizes}};else{let q=await eL(I,this.context.entityService);if(q)E={coverImageUrl:q.url,coverImageWidth:q.width,coverImageHeight:q.height}}return{...Q,...I,url:f.generateUrl($,u),typeLabel:F,listUrl:Z,listLabel:k,...E}}async collectAllImageIds(){let A=new Set;try{let f=this.context.entityService.getEntityTypes();for(let w of f){if(w==="image")continue;let Q=await this.context.entityService.listEntities(w);for(let B of Q){let x=tL(B);if(x)A.add(x)}}}catch(f){this.logger.warn("Failed to collect image IDs for pre-resolution",{error:f instanceof Error?f.message:String(f)})}return[...A]}}B0();class WvA{logger;routes=new Map;constructor(A){this.logger=A}register(A){let f=Array.isArray(A)?A:[A];for(let w of f){let Q=gk.parse(w);if(this.routes.has(Q.path)){let B=this.routes.get(Q.path);this.logger.debug(`Overriding route "${Q.path}" (was registered by plugin "${B?.pluginId}")`)}this.routes.set(Q.path,Q)}}unregister(A){(Array.isArray(A)?A:[A]).forEach((w)=>this.routes.delete(w))}unregisterByPlugin(A){for(let[f,w]of this.routes.entries())if(w.pluginId===A)this.routes.delete(f)}get(A){return this.routes.get(A)}list(A){let f=Array.from(this.routes.values()).filter((w)=>!w.external);if(A?.pluginId)f=f.filter((w)=>w.pluginId===A.pluginId);return f}listByPlugin(A){return this.list({pluginId:A})}clear(){this.routes.clear()}size(){return this.routes.size}getNavigationItems(A){let f=[];for(let[w,Q]of this.routes.entries())if(Q.navigation?.show&&Q.navigation.slot===A)f.push({label:Q.navigation.label??Q.title,href:w,priority:Q.navigation.priority});return f.sort((w,Q)=>w.priority-Q.priority)}}class wa{slots=new Map;register(A,f){let w={...f,priority:f.priority??50},Q=this.slots.get(A)??[];Q.push(w),this.slots.set(A,Q)}getSlot(A){return[...this.slots.get(A)??[]].sort((w,Q)=>Q.priority-w.priority)}hasSlot(A){let f=this.slots.get(A);return f!==void 0&&f.length>0}unregister(A,f){let w=this.slots.get(A);if(!w)return;let Q=w.filter((B)=>B.pluginId!==f);if(Q.length>0)this.slots.set(A,Q);else this.slots.delete(A)}unregisterAll(A){for(let[f,w]of this.slots){let Q=w.filter((B)=>B.pluginId!==A);if(Q.length>0)this.slots.set(f,Q);else this.slots.delete(f)}}getSlotNames(){return Array.from(this.slots.keys())}clear(){this.slots.clear()}}YA();class kvA{config;context;pluginId;logger;debounces=new Map;unsubscribeFunctions=[];constructor(A,f,w,Q){this.config=A;this.context=f;this.pluginId=w;this.logger=Q}requestBuild(A){let f=A??(this.config.previewOutputDir?"preview":"production"),w=this.debounces.get(f);if(!w)w=new jK(()=>{this.enqueueBuild(f)},this.config.rebuildDebounce),this.debounces.set(f,w);w.trigger()}setupAutoRebuild(){let A=new Set(["base"]),f=async(Q)=>{let{entityType:B}=Q.payload;if(!A.has(B))this.logger.debug(`Entity type ${B} will trigger rebuild`),this.requestBuild();return{success:!0}},w=["entity:created","entity:updated","entity:deleted"];for(let Q of w)this.unsubscribeFunctions.push(this.context.messaging.subscribe(Q,f));this.logger.debug(`Auto-rebuild enabled (${this.config.rebuildDebounce}ms debounce), excluding types: ${[...A].join(", ")}`)}dispose(){for(let A of this.debounces.values())A.dispose();this.debounces.clear();for(let A of this.unsubscribeFunctions)A();this.unsubscribeFunctions=[]}async enqueueBuild(A){let f=A==="production"?this.config.productionOutputDir:this.config.previewOutputDir;this.logger.debug(`Triggering ${A} site rebuild`);try{await this.context.jobs.enqueue("site-build",{environment:A,outputDir:f,workingDir:this.config.workingDir,enableContentGeneration:!0,metadata:{trigger:"debounced-rebuild",timestamp:new Date().toISOString()}},null,{priority:0,source:this.pluginId,metadata:{operationType:"content_operations"},deduplication:"skip"}),this.logger.debug("Site rebuild enqueued")}catch(w){this.logger.error("Failed to enqueue site rebuild",{error:w})}}}B0();function hT2(A,f){return A.map((w)=>({...w,template:w.template.includes(":")?w.template:`${f}:${w.template}`}))}function Qa(A,f,w){for(let Q of A)w.register({...Q,pluginId:f,sections:Q.sections?hT2(Q.sections,f):[]})}function or0(A,f,w){A.messaging.subscribe("plugin:site-builder:route:register",async(Q)=>{try{let B=m2A.parse(Q.payload),{routes:x,pluginId:c}=B;return Qa(x,c,f),{success:!0}}catch(B){return w.error("Failed to register routes",{error:B}),{success:!1,error:"Failed to register routes"}}}),A.messaging.subscribe("plugin:site-builder:route:unregister",async(Q)=>{try{let B=l2A.parse(Q.payload),{paths:x,pluginId:c}=B;if(x)for(let I of x)f.unregister(I);else if(c)f.unregisterByPlugin(c);return{success:!0}}catch(B){return w.error("Failed to unregister routes",{error:B}),{success:!1,error:"Failed to unregister routes"}}}),A.messaging.subscribe("plugin:site-builder:route:list",async(Q)=>{try{let B=T2A.parse(Q.payload);return{success:!0,data:{routes:f.list(B.pluginId?B:void 0)}}}catch(B){return w.error("Failed to list routes",{error:B}),{success:!1,error:"Failed to list routes"}}}),A.messaging.subscribe("plugin:site-builder:route:get",async(Q)=>{try{let B=y2A.parse(Q.payload);return{success:!0,data:{route:f.get(B.path)}}}catch(B){return w.error("Failed to get route",{error:B}),{success:!1,error:"Failed to get route"}}}),A.messaging.subscribe("site-builder:routes:list",async()=>{return{success:!0,data:f.list()}})}YA();import{promises as VM}from"fs";import{join as iM}from"path";function ar0(A,f){if(f==="preview")return`User-agent: *
2702
2702
  Disallow: /
2703
2703
 
2704
2704
  Sitemap: ${A}/sitemap.xml
@@ -2727,7 +2727,7 @@ ${A.map((x)=>({url:`${f}${x.path}`,lastmod:w,changefreq:x.path==="/"?"daily":"we
2727
2727
  <script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
2728
2728
  </body>
2729
2729
  </html>
2730
- `;async function zT2(A,f,w){let Q=A.siteConfig.url??"https://example.com",B=f.list(),x=ar0(Q,A.environment);await VM.writeFile(iM(A.outputDir,"robots.txt"),x,"utf-8"),w.info(`Generated robots.txt for ${A.environment} environment`);let c=sr0(B,Q);await VM.writeFile(iM(A.outputDir,"sitemap.xml"),c,"utf-8"),w.info(`Generated sitemap.xml with ${B.length} URLs`)}async function NT2(A,f,w,Q){if(!w.cms)return;let B=await f.messaging.send("git-sync:get-repo-info",{});if("noop"in B||!B.success||!B.data?.repo){Q.warn("CMS enabled but git-sync repo info unavailable \u2014 skipping CMS generation");return}let x=f.entityService.getEntityTypes(),c=er0({repo:B.data.repo,branch:B.data.branch,...f.siteUrl&&{baseUrl:f.siteUrl},entityTypes:x,getFrontmatterSchema:($)=>f.entities.getEffectiveFrontmatterSchema($),getAdapter:($)=>f.entities.getAdapter($),...w.entityDisplay&&{entityDisplay:w.entityDisplay}}),I=iM(A.outputDir,"admin");await VM.mkdir(I,{recursive:!0}),await VM.writeFile(iM(I,"config.yml"),k$(c),"utf-8"),await VM.writeFile(iM(I,"index.html"),Ad0,"utf-8"),Q.info("Generated CMS admin page and config.yml")}function fd0(A){let{context:f,routeRegistry:w,config:Q,logger:B}=A;f.messaging.subscribe("site:build:completed",async(x)=>{try{let c=x.payload;return B.info(`Received site:build:completed event for ${c.environment} environment - generating SEO files`),await zT2(c,w,B),await NT2(c,f,Q,B),{success:!0}}catch(c){return B.error("Failed to generate SEO files",c),{success:!1}}})}B0();YA();var wd0=X.object({environment:X.enum(["preview","production"]).optional(),outputDir:X.string(),workingDir:X.string().optional(),enableContentGeneration:X.boolean().optional(),siteConfig:X.object({title:X.string(),description:X.string(),url:X.string().optional(),analyticsScript:X.string().optional()}).optional()});YA();class bvA extends Vw{sendMessage;cfg;constructor(A,f,w){super(A,{schema:wd0,jobTypeName:"site-build"});this.sendMessage=f;this.cfg=w}async process(A,f,w){let Q=A.environment??"preview",B=A.enableContentGeneration??!1;try{this.logger.debug("Starting site build job",{jobId:f,environment:Q,outputDir:A.outputDir}),await w.report({progress:0,total:100,message:`Starting site build for ${Q} environment`});let x=w.createSub({scale:{start:10,end:90}}),c=await this.cfg.siteBuilder.build({outputDir:A.outputDir,workingDir:A.workingDir,sharedImagesDir:this.cfg.sharedImagesDir,enableContentGeneration:B,environment:Q,cleanBeforeBuild:!0,siteConfig:A.siteConfig??this.cfg.defaultSiteConfig,layouts:this.cfg.layouts,themeCSS:this.cfg.themeCSS,slots:this.cfg.slots,headScripts:this.cfg.getHeadScripts?.(),...this.cfg.staticAssets&&{staticAssets:this.cfg.staticAssets}},x.toCallback());if(await w.report({progress:100,total:100,message:`Site build completed: ${c.routesBuilt} routes built`}),this.logger.debug("Site build job completed",{jobId:f,environment:Q,routesBuilt:c.routesBuilt,success:c.success}),c.success){this.logger.info(`Emitting site:build:completed event for ${Q} environment`);let I=Q==="preview"?this.cfg.previewUrl??this.cfg.siteUrl:this.cfg.siteUrl;await this.sendMessage("site:build:completed",{outputDir:A.outputDir,environment:Q,routesBuilt:c.routesBuilt,siteConfig:{...A.siteConfig??this.cfg.defaultSiteConfig,url:I},generateEntityUrl:($,u)=>Qc.getInstance().generateUrl($,u)},{broadcast:!0})}return{success:c.success,routesBuilt:c.routesBuilt,outputDir:A.outputDir,environment:Q,...c.errors&&{errors:c.errors},...c.warnings&&{warnings:c.warnings}}}catch(x){throw this.logger.error("Site build job failed",x),x}}summarizeDataForLog(A){return{environment:A.environment,outputDir:A.outputDir}}}YA();B0();var CT2=X.object({slot:X.enum(jk).optional().default("primary"),limit:X.number().optional()});class zvA{routeRegistry;logger;id="site:navigation";name="Site Navigation DataSource";description="Provides navigation items for site menus";constructor(A,f){this.routeRegistry=A;this.logger=f;this.logger.debug("NavigationDataSource initialized")}async fetch(A,f,w){let Q=CT2.parse(A??{});this.logger.debug("NavigationDataSource fetch called",{params:Q});let B=this.routeRegistry.getNavigationItems(Q.slot),x=Q.limit?B.slice(0,Q.limit):B,c=x.map(($)=>({label:$.label,href:$.href}));this.logger.debug("NavigationDataSource returning",{slot:Q.slot,itemCount:x.length,items:c});let I={navigation:c};return f.parse(I)}}B0();YA();var ET2=X.object({environment:X.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function Qd0(A,f){return[Tf(A,"build-site","Build a static site from registered routes",ET2,async(w)=>{return f(w.environment),{success:!0,message:`Site build requested${w.environment?` for ${w.environment}`:""} (debounced)`,data:{}}},{cli:{name:"build"}})]}YA();B0();var Bd0=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:bu.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(gk).optional().describe("Routes to register"),layouts:X.record(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.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(jk).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()).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."),cms:X.object({}).optional().describe("Sveltia CMS configuration (enables /admin/ CMS, requires git-sync plugin)")});var xd0={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.8",description:"Static site generation plugin for Brain system",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint .",clean:"rm -rf dist"},dependencies:{"@brains/plugins":"workspace:*","@brains/site-info":"workspace:*","@brains/ui-library":"workspace:*","@tailwindcss/postcss":"^4.1.13","@tailwindcss/typography":"^0.5.19",postcss:"^8.5.6",preact:"^10.27.2","preact-render-to-string":"^6.3.1",sharp:"^0.34.5",tailwindcss:"^4.1.11"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/sharp":"^0.32.0",eslint:"^8.56.0",typescript:"^5.3.3"}};class NvA extends yQ{siteBuilder;pluginContext;_routeRegistry;_slotRegistry;profileService;layouts;rebuildManager;headScripts=new Map;get routeRegistry(){if(!this._routeRegistry)throw Error("RouteRegistry not initialized - plugin not registered");return this._routeRegistry}constructor(A={}){let f=A.layouts??{};super("site-builder",xd0,{...A,layouts:f},Bd0);this.layouts=f}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new WvA(A.logger),this._slotRegistry=new wa,A.messaging.subscribe("plugin:site-builder:slot:register",async(f)=>{let{slotName:w,pluginId:Q,render:B,priority:x}=f.payload;return this._slotRegistry?.register(w,{pluginId:Q,render:B,...x!==void 0&&{priority:x}}),{success:!0}}),A.messaging.subscribe("plugin:site-builder:head-script:register",async(f)=>{let{pluginId:w,script:Q}=f.payload;return this.headScripts.set(w,Q),{success:!0}}),A.entities.registerDataSource(new zvA(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=uc.getInstance(A.entityService,A.logger),A.messaging.subscribe("sync:initial:completed",async()=>{return await this.profileService?.initialize(),this.logger.info("AnchorProfileService initialized"),{success:!0}}),or0(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)Qa(this.config.routes,this.id,this.routeRegistry);if(this.siteBuilder=O5.getInstance(A.logger.child("SiteBuilder"),A,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new bvA(this.logger.child("SiteBuildJobHandler"),A.messaging.send,{siteBuilder:this.siteBuilder,layouts:this.layouts,defaultSiteConfig:this.config.siteInfo,sharedImagesDir:this.config.sharedImagesDir,siteUrl:A.siteUrl,previewUrl:A.previewUrl,themeCSS:this.config.themeCSS,slots:this._slotRegistry,getHeadScripts:()=>this.getRegisteredHeadScripts(),...this.config.staticAssets&&{staticAssets:this.config.staticAssets}})),this.rebuildManager=new kvA(this.config,A,this.id,this.logger),this.config.autoRebuild)this.logger.debug("Auto-rebuild enabled"),this.rebuildManager.setupAutoRebuild();if(this.config.cms)this._routeRegistry.register({id:"cms-admin",path:"/admin/",title:"Admin",external:!0,navigation:{show:!1,slot:"secondary",label:"Admin",priority:100}});A.messaging.subscribe("entity:updated",async(f)=>{if(f.payload.entityType==="site-info"){let Q=await this.getInstructions();if(Q)A.registerInstructions(Q)}return{success:!0}}),fd0({context:A,routeRegistry:this._routeRegistry,config:this.config,logger:this.logger})}getRegisteredHeadScripts(){return Array.from(this.headScripts.values())}async getTools(){if(!this.pluginContext||!this.rebuildManager)throw Error("Plugin context not initialized");let A=this.rebuildManager;return Qd0(this.id,(f)=>A.requestBuild(f))}async getResources(){let A=this.getContext();return[{uri:"brain://site",name:"Site Info",description:"Site metadata \u2014 title, description, domain, URLs",mimeType:"application/json",handler:async()=>{let f;try{f=await d3(A.entityService)}catch{f={title:"Brain",description:""}}return{contents:[{uri:"brain://site",mimeType:"application/json",text:JSON.stringify({...f,domain:A.domain,siteUrl:A.siteUrl,previewUrl:A.previewUrl},null,2)}]}}},{uri:"site://routes",name:"Site Routes",description:"All registered routes with sections and templates",mimeType:"application/json",handler:async()=>{let f=this.routeRegistry.list();return{contents:[{uri:"site://routes",mimeType:"application/json",text:JSON.stringify(f.map((w)=>({id:w.id,path:w.path,title:w.title,description:w.description,sections:w.sections.map((Q)=>({id:Q.id,template:Q.template}))})),null,2)}]}}},{uri:"site://templates",name:"View Templates",description:"All registered view templates",mimeType:"application/json",handler:async()=>{let f=A.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(f.map((w)=>({name:w.name,description:w.description,hasWebRenderer:!!w.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let A=this.getContext();try{let f=await d3(A.entityService);return`## Your Site
2730
+ `;async function zT2(A,f,w){let Q=A.siteConfig.url??"https://example.com",B=f.list(),x=ar0(Q,A.environment);await VM.writeFile(iM(A.outputDir,"robots.txt"),x,"utf-8"),w.info(`Generated robots.txt for ${A.environment} environment`);let c=sr0(B,Q);await VM.writeFile(iM(A.outputDir,"sitemap.xml"),c,"utf-8"),w.info(`Generated sitemap.xml with ${B.length} URLs`)}async function NT2(A,f,w,Q){if(!w.cms)return;let B=await f.messaging.send("git-sync:get-repo-info",{});if("noop"in B||!B.success||!B.data?.repo){Q.warn("CMS enabled but git-sync repo info unavailable \u2014 skipping CMS generation");return}let x=f.entityService.getEntityTypes(),c=er0({repo:B.data.repo,branch:B.data.branch,...f.siteUrl&&{baseUrl:f.siteUrl},entityTypes:x,getFrontmatterSchema:($)=>f.entities.getEffectiveFrontmatterSchema($),getAdapter:($)=>f.entities.getAdapter($),...w.entityDisplay&&{entityDisplay:w.entityDisplay}}),I=iM(A.outputDir,"admin");await VM.mkdir(I,{recursive:!0}),await VM.writeFile(iM(I,"config.yml"),k$(c),"utf-8"),await VM.writeFile(iM(I,"index.html"),Ad0,"utf-8"),Q.info("Generated CMS admin page and config.yml")}function fd0(A){let{context:f,routeRegistry:w,config:Q,logger:B}=A;f.messaging.subscribe("site:build:completed",async(x)=>{try{let c=x.payload;return B.info(`Received site:build:completed event for ${c.environment} environment - generating SEO files`),await zT2(c,w,B),await NT2(c,f,Q,B),{success:!0}}catch(c){return B.error("Failed to generate SEO files",c),{success:!1}}})}B0();YA();var wd0=X.object({environment:X.enum(["preview","production"]).optional(),outputDir:X.string(),workingDir:X.string().optional(),enableContentGeneration:X.boolean().optional(),siteConfig:X.object({title:X.string(),description:X.string(),url:X.string().optional(),analyticsScript:X.string().optional()}).optional()});YA();class bvA extends Vw{sendMessage;cfg;constructor(A,f,w){super(A,{schema:wd0,jobTypeName:"site-build"});this.sendMessage=f;this.cfg=w}async process(A,f,w){let Q=A.environment??"preview",B=A.enableContentGeneration??!1;try{this.logger.debug("Starting site build job",{jobId:f,environment:Q,outputDir:A.outputDir}),await w.report({progress:0,total:100,message:`Starting site build for ${Q} environment`});let x=w.createSub({scale:{start:10,end:90}}),c=await this.cfg.siteBuilder.build({outputDir:A.outputDir,workingDir:A.workingDir,sharedImagesDir:this.cfg.sharedImagesDir,enableContentGeneration:B,environment:Q,cleanBeforeBuild:!0,siteConfig:A.siteConfig??this.cfg.defaultSiteConfig,layouts:this.cfg.layouts,themeCSS:this.cfg.themeCSS,slots:this.cfg.slots,headScripts:this.cfg.getHeadScripts?.(),...this.cfg.staticAssets&&{staticAssets:this.cfg.staticAssets}},x.toCallback());if(await w.report({progress:100,total:100,message:`Site build completed: ${c.routesBuilt} routes built`}),this.logger.debug("Site build job completed",{jobId:f,environment:Q,routesBuilt:c.routesBuilt,success:c.success}),c.success){this.logger.info(`Emitting site:build:completed event for ${Q} environment`);let I=Q==="preview"?this.cfg.previewUrl??this.cfg.siteUrl:this.cfg.siteUrl;await this.sendMessage("site:build:completed",{outputDir:A.outputDir,environment:Q,routesBuilt:c.routesBuilt,siteConfig:{...A.siteConfig??this.cfg.defaultSiteConfig,url:I},generateEntityUrl:($,u)=>Qc.getInstance().generateUrl($,u)},{broadcast:!0})}return{success:c.success,routesBuilt:c.routesBuilt,outputDir:A.outputDir,environment:Q,...c.errors&&{errors:c.errors},...c.warnings&&{warnings:c.warnings}}}catch(x){throw this.logger.error("Site build job failed",x),x}}summarizeDataForLog(A){return{environment:A.environment,outputDir:A.outputDir}}}YA();B0();var CT2=X.object({slot:X.enum(jk).optional().default("primary"),limit:X.number().optional()});class zvA{routeRegistry;logger;id="site:navigation";name="Site Navigation DataSource";description="Provides navigation items for site menus";constructor(A,f){this.routeRegistry=A;this.logger=f;this.logger.debug("NavigationDataSource initialized")}async fetch(A,f,w){let Q=CT2.parse(A??{});this.logger.debug("NavigationDataSource fetch called",{params:Q});let B=this.routeRegistry.getNavigationItems(Q.slot),x=Q.limit?B.slice(0,Q.limit):B,c=x.map(($)=>({label:$.label,href:$.href}));this.logger.debug("NavigationDataSource returning",{slot:Q.slot,itemCount:x.length,items:c});let I={navigation:c};return f.parse(I)}}B0();YA();var ET2=X.object({environment:X.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function Qd0(A,f){return[Tf(A,"build-site","Build a static site from registered routes",ET2,async(w)=>{return f(w.environment),{success:!0,message:`Site build requested${w.environment?` for ${w.environment}`:""} (debounced)`,data:{}}},{cli:{name:"build"}})]}YA();B0();var Bd0=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:bu.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(gk).optional().describe("Routes to register"),layouts:X.record(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.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(jk).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()).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."),cms:X.object({}).optional().describe("Sveltia CMS configuration (enables /admin/ CMS, requires git-sync plugin)")});var xd0={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.9",description:"Static site generation plugin for Brain system",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint .",clean:"rm -rf dist"},dependencies:{"@brains/plugins":"workspace:*","@brains/site-info":"workspace:*","@brains/ui-library":"workspace:*","@tailwindcss/postcss":"^4.1.13","@tailwindcss/typography":"^0.5.19",postcss:"^8.5.6",preact:"^10.27.2","preact-render-to-string":"^6.3.1",sharp:"^0.34.5",tailwindcss:"^4.1.11"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/sharp":"^0.32.0",eslint:"^8.56.0",typescript:"^5.3.3"}};class NvA extends yQ{siteBuilder;pluginContext;_routeRegistry;_slotRegistry;profileService;layouts;rebuildManager;headScripts=new Map;get routeRegistry(){if(!this._routeRegistry)throw Error("RouteRegistry not initialized - plugin not registered");return this._routeRegistry}constructor(A={}){let f=A.layouts??{};super("site-builder",xd0,{...A,layouts:f},Bd0);this.layouts=f}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new WvA(A.logger),this._slotRegistry=new wa,A.messaging.subscribe("plugin:site-builder:slot:register",async(f)=>{let{slotName:w,pluginId:Q,render:B,priority:x}=f.payload;return this._slotRegistry?.register(w,{pluginId:Q,render:B,...x!==void 0&&{priority:x}}),{success:!0}}),A.messaging.subscribe("plugin:site-builder:head-script:register",async(f)=>{let{pluginId:w,script:Q}=f.payload;return this.headScripts.set(w,Q),{success:!0}}),A.entities.registerDataSource(new zvA(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=uc.getInstance(A.entityService,A.logger),A.messaging.subscribe("sync:initial:completed",async()=>{return await this.profileService?.initialize(),this.logger.info("AnchorProfileService initialized"),{success:!0}}),or0(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)Qa(this.config.routes,this.id,this.routeRegistry);if(this.siteBuilder=O5.getInstance(A.logger.child("SiteBuilder"),A,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new bvA(this.logger.child("SiteBuildJobHandler"),A.messaging.send,{siteBuilder:this.siteBuilder,layouts:this.layouts,defaultSiteConfig:this.config.siteInfo,sharedImagesDir:this.config.sharedImagesDir,siteUrl:A.siteUrl,previewUrl:A.previewUrl,themeCSS:this.config.themeCSS,slots:this._slotRegistry,getHeadScripts:()=>this.getRegisteredHeadScripts(),...this.config.staticAssets&&{staticAssets:this.config.staticAssets}})),this.rebuildManager=new kvA(this.config,A,this.id,this.logger),this.config.autoRebuild)this.logger.debug("Auto-rebuild enabled"),this.rebuildManager.setupAutoRebuild();if(this.config.cms)this._routeRegistry.register({id:"cms-admin",path:"/admin/",title:"Admin",external:!0,navigation:{show:!1,slot:"secondary",label:"Admin",priority:100}});A.messaging.subscribe("entity:updated",async(f)=>{if(f.payload.entityType==="site-info"){let Q=await this.getInstructions();if(Q)A.registerInstructions(Q)}return{success:!0}}),fd0({context:A,routeRegistry:this._routeRegistry,config:this.config,logger:this.logger})}getRegisteredHeadScripts(){return Array.from(this.headScripts.values())}async getTools(){if(!this.pluginContext||!this.rebuildManager)throw Error("Plugin context not initialized");let A=this.rebuildManager;return Qd0(this.id,(f)=>A.requestBuild(f))}async getResources(){let A=this.getContext();return[{uri:"brain://site",name:"Site Info",description:"Site metadata \u2014 title, description, domain, URLs",mimeType:"application/json",handler:async()=>{let f;try{f=await d3(A.entityService)}catch{f={title:"Brain",description:""}}return{contents:[{uri:"brain://site",mimeType:"application/json",text:JSON.stringify({...f,domain:A.domain,siteUrl:A.siteUrl,previewUrl:A.previewUrl},null,2)}]}}},{uri:"site://routes",name:"Site Routes",description:"All registered routes with sections and templates",mimeType:"application/json",handler:async()=>{let f=this.routeRegistry.list();return{contents:[{uri:"site://routes",mimeType:"application/json",text:JSON.stringify(f.map((w)=>({id:w.id,path:w.path,title:w.title,description:w.description,sections:w.sections.map((Q)=>({id:Q.id,template:Q.template}))})),null,2)}]}}},{uri:"site://templates",name:"View Templates",description:"All registered view templates",mimeType:"application/json",handler:async()=>{let f=A.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(f.map((w)=>({name:w.name,description:w.description,hasWebRenderer:!!w.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let A=this.getContext();try{let f=await d3(A.entityService);return`## Your Site
2731
2731
  ${[`**Title:** ${f.title}`,`**Description:** ${f.description}`,A.domain&&`**Domain:** ${A.domain}`,A.siteUrl&&`**URL:** ${A.siteUrl}`].filter(Boolean).join(`
2732
2732
  `)}`}catch{return}}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),this.rebuildManager?.dispose(),O5.resetInstance(),this.logger.debug("Cleaned up all event subscriptions")}}function Nv(A={}){return new NvA(A)}YA();var qT2=bu.extend({navigation:X.object({primary:X.array(X.object({label:X.string(),href:X.string(),priority:X.number()})),secondary:X.array(X.object({label:X.string(),href:X.string(),priority:X.number()}))}),copyright:X.string(),socialLinks:X.array(X.object({platform:X.enum(["github","instagram","linkedin","email","website"]).describe("Social media platform"),url:X.string().describe("Profile or contact URL"),label:X.string().optional().describe("Optional display label")})).optional().describe("Social media links from profile entity")});import{h as _T2,Fragment as VT2}from"preact";function CvA({name:A,slots:f}){if(!f?.hasSlot(A))return null;let Q=f.getSlot(A).map((B)=>B.render());return _T2(VT2,{},...Q)}B0();iu();jM();YA();var EvA=X.object({defaultPrompt:X.string().default("Write a blog post about my recent work and insights"),paginate:X.boolean().default(!0),pageSize:X.number().default(10)});B0();YA();var OT2=X.object({prompt:X.string().optional(),title:X.string().optional(),content:X.string().optional(),excerpt:X.string().optional(),coverImageId:X.string().optional(),seriesName:X.string().optional(),seriesIndex:X.number().optional(),skipAi:X.boolean().optional()}),NXw=xc.extend({title:X.string().optional(),slug:X.string().optional()});class LvA extends Cx{constructor(A,f){super(A,f,{schema:OT2,jobTypeName:"blog-generation",entityType:"post"})}async generate(A,f){let{prompt:w,coverImageId:Q,seriesName:B,seriesIndex:x,skipAi:c}=A,{title:I,content:$,excerpt:u}=A;if(c){if(!I)this.failEarly("Title is required when skipAi is true");$=$??`## Introduction
2733
2733
 
@@ -2772,7 +2772,7 @@ The excerpt should be clear, concise, and compelling.`});YA();P2();iu();import{j
2772
2772
  Note: This is part of a series called "${w.seriesName}".`:""}`;return A.ai.generate({prompt:Q,templateName:"blog:generation"})}),A.eval.registerHandler("generateExcerpt",async(f)=>{let w=aT2.parse(f);return A.ai.generate({prompt:`Title: ${w.title}
2773
2773
 
2774
2774
  Content:
2775
- ${w.content}`,templateName:"blog:excerpt"})})}var kd0={name:"@brains/blog",private:!0,version:"0.2.0-alpha.8",description:"AI-powered blog post generation from existing brain content",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class ivA extends Nf{entityType=Cv.entityType;schema=Pb;adapter=Cv;constructor(A={}){super("blog",kd0,A,EvA)}getEntityTypeConfig(){return{weight:2}}createGenerationHandler(A){return new LvA(this.logger.child("BlogGenerationJobHandler"),A)}getTemplates(){return Fd0()}getDataSources(){return[new _vA(this.logger.child("BlogDataSource"))]}async onRegister(A){let{RSSDataSource:f}=await Promise.resolve().then(() => (Jd0(),Gd0));A.entities.registerDataSource(new f(this.logger.child("RSSDataSource"))),await Kd0(A,this.logger),Xd0(A,this.logger),vd0(A,this.logger),Wd0(A),this.logger.info("Blog plugin registered (routes auto-generated at /posts/)")}}function MvA(A={}){return new ivA(A)}iu();jM();B0();YA();H6();var y4=X.object({title:X.string(),slug:X.string(),coverImageId:X.string().optional()}),bd0=y4.pick({title:!0,slug:!0}),mb=v2.extend({metadata:bd0}),Ia=mb.extend({frontmatter:y4}),$a=Ia.extend({description:X.string().optional(),postCount:X.number(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),zd0=X.object({description:X.string().optional()});function Ev(A){return new R1(zd0,{title:A,mappings:[{key:"description",label:"Description",type:"string"}]})}H6();class OvA extends _2{constructor(){super({entityType:"series",schema:mb,frontmatterSchema:y4,supportsCoverImage:!0,bodyFormatter:Ev("")})}toMarkdown(A){let f,w={};try{f=this.parseFrontMatter(A.content,y4).coverImageId,w=Ev(A.metadata.title).parse(this.extractBody(A.content))}catch{}let Q={title:A.metadata.title,slug:A.metadata.slug,...f&&{coverImageId:f}},x=Ev(A.metadata.title).format(w);return this.buildMarkdown(x,Q)}fromMarkdown(A){let f=this.parseFrontMatter(A,y4);return{content:A,entityType:"series",metadata:{title:f.title,slug:f.slug}}}parseBody(A){try{let f=this.parseFrontMatter(A,y4);return Ev(f.title).parse(this.extractBody(A))}catch{return{}}}generateFrontMatter(){return""}}var lb=new OvA;B0();YA();R7();class jvA{entityService;logger;constructor(A,f){this.entityService=A;this.logger=f}async syncAllSeries(){this.logger.debug("Syncing series from all entity types");let A=await this.collectSeriesNames();this.logger.debug(`Found ${A.size} unique series`);let f=await this.entityService.listEntities("series",{limit:1000}),w=new Map(f.map((B)=>[B.id,B])),Q=new Set;for(let B of A){let x=x2(B);Q.add(x);let c=w.get(x),I=c?.content??this.createSeriesContent(B),$=IQ(I);if(c?.contentHash===$)continue;let u={id:x,entityType:"series",content:I,contentHash:$,created:c?.created??new Date().toISOString(),updated:new Date().toISOString(),metadata:{title:B,slug:x2(B)}};await this.entityService.upsertEntity(u),this.logger.debug(`Upserted series: ${B}`)}for(let B of f)if(!Q.has(B.id))await this.entityService.deleteEntity("series",B.id),this.logger.debug(`Deleted orphaned series: ${B.id}`)}async handleEntityChange(A,f){let w=this.getSeriesName(A);if(w)await this.ensureSeriesExists(w);if(f&&f!==w)await this.cleanupOrphanedSeries(f)}async handleEntityDeleted(){await this.syncAllSeries()}getSeriesName(A){let w=A.metadata.seriesName;return typeof w==="string"?w:void 0}async ensureSeriesExists(A){let f=x2(A);if(await this.entityService.getEntity("series",f))return;let Q=this.createSeriesContent(A),B={id:f,entityType:"series",content:Q,contentHash:IQ(Q),created:new Date().toISOString(),updated:new Date().toISOString(),metadata:{title:A,slug:x2(A)}};await this.entityService.upsertEntity(B),this.logger.debug(`Created series: ${A}`)}async cleanupOrphanedSeries(A){let f=x2(A);if(!await this.entityService.getEntity("series",f))return;if(!await this.hasSeriesReferences(A))await this.entityService.deleteEntity("series",f),this.logger.debug(`Deleted orphaned series: ${A}`)}async hasSeriesReferences(A){let f=this.entityService.getEntityTypes();for(let w of f){if(w==="series")continue;if((await this.entityService.listEntities(w,{filter:{metadata:{seriesName:A}},limit:1})).length>0)return!0}return!1}async collectSeriesNames(){let A=new Set,f=this.entityService.getEntityTypes();for(let w of f){if(w==="series")continue;let Q=await this.entityService.listEntities(w,{limit:1000});for(let B of Q){let x=this.getSeriesName(B);if(x)A.add(x)}}return A}createSeriesContent(A){let f={title:A,slug:x2(A)};return Y6("",f)}}B0();YA();var eT2=X.object({entityType:X.literal("series"),query:X.object({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional()}).passthrough()}),Ay2=X.object({type:X.enum(["list","detail"]),seriesName:X.string().optional()});function fy2(A){let f=Ay2.safeParse(A);if(f.success)return{type:f.data.type,seriesName:f.data.seriesName};let w=eT2.safeParse(A);if(w.success){let{query:Q}=w.data;if(Q.id)return{type:"detail",seriesSlug:Q.id};return{type:"list"}}throw Error('Invalid series query format. Expected { type: "list"|"detail" } or { entityType: "series", query: { id?: string } }')}function Nd0(A){let f=K2(A.content,y4);return Ia.parse({...A,frontmatter:f.metadata})}class gvA{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(A){this.logger=A}async fetch(A,f,w){let Q=fy2(A),B=w.entityService;if(Q.type==="list")return this.fetchSeriesList(f,B);if(Q.seriesName)return this.fetchSeriesDetail(Q.seriesName,f,B);if(Q.seriesSlug)return this.fetchSeriesDetailBySlug(Q.seriesSlug,f,B);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(A,f){let w=await f.listEntities("series",{limit:1000}),Q=await this.countEntitiesPerSeries(f),B=w.map((x)=>{let c=Nd0(x),I=lb.parseBody(x.content);return{...c,description:I.description,postCount:Q.get(x.metadata.title)??0}});return this.logger.debug(`Found ${B.length} series entities`),A.parse({series:B})}async fetchSeriesDetail(A,f,w,Q){if(!Q)Q=(await w.listEntities("series",{filter:{metadata:{title:A}}}))[0];if(!Q)throw Error(`Series not found: ${A}`);let B=Nd0(Q),x=lb.parseBody(Q.content),c=await this.getSeriesMembers(A,w);return this.logger.debug(`Found ${c.length} entities in series "${A}"`),f.parse({seriesName:A,posts:c,series:{...B,description:x.description,postCount:c.length},description:x.description})}async fetchSeriesDetailBySlug(A,f,w){let B=(await w.listEntities("series",{filter:{metadata:{slug:A}}}))[0];if(!B)return this.logger.warn(`Series not found with slug: ${A}`),f.parse({seriesName:A,posts:[]});return this.fetchSeriesDetail(B.metadata.title,f,w,B)}async countEntitiesPerSeries(A){let f=new Map,w=A.getEntityTypes();for(let Q of w){if(Q==="series")continue;let B=await A.listEntities(Q,{limit:1000});for(let x of B){let c=this.getSeriesName(x);if(c)f.set(c,(f.get(c)??0)+1)}}return f}async getSeriesMembers(A,f){let w=[],Q=f.getEntityTypes();for(let B of Q){if(B==="series")continue;let x=await f.listEntities(B,{filter:{metadata:{seriesName:A}}});w.push(...x)}return w.sort((B,x)=>{let c=B.metadata.seriesIndex,I=x.metadata.seriesIndex;return(typeof c==="number"?c:999)-(typeof I==="number"?I:999)}),w}getSeriesName(A){let w=A.metadata.seriesName;return typeof w==="string"?w:void 0}}B0();YA();R7();var wy2=X.object({prompt:X.string().optional(),title:X.string().optional(),seriesId:X.string().optional()});class ua{logger;context;constructor(A,f){this.logger=A;this.context=f}async process(A){let f=A.seriesId??A.title;if(!f)return{success:!1,error:"seriesId or title required"};let w=await this.context.entityService.getEntity("series",f);if(!w)return{success:!1,error:`Series not found: ${f}`};let Q=await this.gatherMemberSummaries(w.metadata.title);if(Q.length===0)return{success:!1,error:`No members found in series: ${w.metadata.title}`};let B=A.prompt??`Series name: ${w.metadata.title}
2775
+ ${w.content}`,templateName:"blog:excerpt"})})}var kd0={name:"@brains/blog",private:!0,version:"0.2.0-alpha.9",description:"AI-powered blog post generation from existing brain content",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class ivA extends Nf{entityType=Cv.entityType;schema=Pb;adapter=Cv;constructor(A={}){super("blog",kd0,A,EvA)}getEntityTypeConfig(){return{weight:2}}createGenerationHandler(A){return new LvA(this.logger.child("BlogGenerationJobHandler"),A)}getTemplates(){return Fd0()}getDataSources(){return[new _vA(this.logger.child("BlogDataSource"))]}async onRegister(A){let{RSSDataSource:f}=await Promise.resolve().then(() => (Jd0(),Gd0));A.entities.registerDataSource(new f(this.logger.child("RSSDataSource"))),await Kd0(A,this.logger),Xd0(A,this.logger),vd0(A,this.logger),Wd0(A),this.logger.info("Blog plugin registered (routes auto-generated at /posts/)")}}function MvA(A={}){return new ivA(A)}iu();jM();B0();YA();H6();var y4=X.object({title:X.string(),slug:X.string(),coverImageId:X.string().optional()}),bd0=y4.pick({title:!0,slug:!0}),mb=v2.extend({metadata:bd0}),Ia=mb.extend({frontmatter:y4}),$a=Ia.extend({description:X.string().optional(),postCount:X.number(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),zd0=X.object({description:X.string().optional()});function Ev(A){return new R1(zd0,{title:A,mappings:[{key:"description",label:"Description",type:"string"}]})}H6();class OvA extends _2{constructor(){super({entityType:"series",schema:mb,frontmatterSchema:y4,supportsCoverImage:!0,bodyFormatter:Ev("")})}toMarkdown(A){let f,w={};try{f=this.parseFrontMatter(A.content,y4).coverImageId,w=Ev(A.metadata.title).parse(this.extractBody(A.content))}catch{}let Q={title:A.metadata.title,slug:A.metadata.slug,...f&&{coverImageId:f}},x=Ev(A.metadata.title).format(w);return this.buildMarkdown(x,Q)}fromMarkdown(A){let f=this.parseFrontMatter(A,y4);return{content:A,entityType:"series",metadata:{title:f.title,slug:f.slug}}}parseBody(A){try{let f=this.parseFrontMatter(A,y4);return Ev(f.title).parse(this.extractBody(A))}catch{return{}}}generateFrontMatter(){return""}}var lb=new OvA;B0();YA();R7();class jvA{entityService;logger;constructor(A,f){this.entityService=A;this.logger=f}async syncAllSeries(){this.logger.debug("Syncing series from all entity types");let A=await this.collectSeriesNames();this.logger.debug(`Found ${A.size} unique series`);let f=await this.entityService.listEntities("series",{limit:1000}),w=new Map(f.map((B)=>[B.id,B])),Q=new Set;for(let B of A){let x=x2(B);Q.add(x);let c=w.get(x),I=c?.content??this.createSeriesContent(B),$=IQ(I);if(c?.contentHash===$)continue;let u={id:x,entityType:"series",content:I,contentHash:$,created:c?.created??new Date().toISOString(),updated:new Date().toISOString(),metadata:{title:B,slug:x2(B)}};await this.entityService.upsertEntity(u),this.logger.debug(`Upserted series: ${B}`)}for(let B of f)if(!Q.has(B.id))await this.entityService.deleteEntity("series",B.id),this.logger.debug(`Deleted orphaned series: ${B.id}`)}async handleEntityChange(A,f){let w=this.getSeriesName(A);if(w)await this.ensureSeriesExists(w);if(f&&f!==w)await this.cleanupOrphanedSeries(f)}async handleEntityDeleted(){await this.syncAllSeries()}getSeriesName(A){let w=A.metadata.seriesName;return typeof w==="string"?w:void 0}async ensureSeriesExists(A){let f=x2(A);if(await this.entityService.getEntity("series",f))return;let Q=this.createSeriesContent(A),B={id:f,entityType:"series",content:Q,contentHash:IQ(Q),created:new Date().toISOString(),updated:new Date().toISOString(),metadata:{title:A,slug:x2(A)}};await this.entityService.upsertEntity(B),this.logger.debug(`Created series: ${A}`)}async cleanupOrphanedSeries(A){let f=x2(A);if(!await this.entityService.getEntity("series",f))return;if(!await this.hasSeriesReferences(A))await this.entityService.deleteEntity("series",f),this.logger.debug(`Deleted orphaned series: ${A}`)}async hasSeriesReferences(A){let f=this.entityService.getEntityTypes();for(let w of f){if(w==="series")continue;if((await this.entityService.listEntities(w,{filter:{metadata:{seriesName:A}},limit:1})).length>0)return!0}return!1}async collectSeriesNames(){let A=new Set,f=this.entityService.getEntityTypes();for(let w of f){if(w==="series")continue;let Q=await this.entityService.listEntities(w,{limit:1000});for(let B of Q){let x=this.getSeriesName(B);if(x)A.add(x)}}return A}createSeriesContent(A){let f={title:A,slug:x2(A)};return Y6("",f)}}B0();YA();var eT2=X.object({entityType:X.literal("series"),query:X.object({id:X.string().optional(),limit:X.number().optional(),page:X.number().optional(),pageSize:X.number().optional()}).passthrough()}),Ay2=X.object({type:X.enum(["list","detail"]),seriesName:X.string().optional()});function fy2(A){let f=Ay2.safeParse(A);if(f.success)return{type:f.data.type,seriesName:f.data.seriesName};let w=eT2.safeParse(A);if(w.success){let{query:Q}=w.data;if(Q.id)return{type:"detail",seriesSlug:Q.id};return{type:"list"}}throw Error('Invalid series query format. Expected { type: "list"|"detail" } or { entityType: "series", query: { id?: string } }')}function Nd0(A){let f=K2(A.content,y4);return Ia.parse({...A,frontmatter:f.metadata})}class gvA{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(A){this.logger=A}async fetch(A,f,w){let Q=fy2(A),B=w.entityService;if(Q.type==="list")return this.fetchSeriesList(f,B);if(Q.seriesName)return this.fetchSeriesDetail(Q.seriesName,f,B);if(Q.seriesSlug)return this.fetchSeriesDetailBySlug(Q.seriesSlug,f,B);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(A,f){let w=await f.listEntities("series",{limit:1000}),Q=await this.countEntitiesPerSeries(f),B=w.map((x)=>{let c=Nd0(x),I=lb.parseBody(x.content);return{...c,description:I.description,postCount:Q.get(x.metadata.title)??0}});return this.logger.debug(`Found ${B.length} series entities`),A.parse({series:B})}async fetchSeriesDetail(A,f,w,Q){if(!Q)Q=(await w.listEntities("series",{filter:{metadata:{title:A}}}))[0];if(!Q)throw Error(`Series not found: ${A}`);let B=Nd0(Q),x=lb.parseBody(Q.content),c=await this.getSeriesMembers(A,w);return this.logger.debug(`Found ${c.length} entities in series "${A}"`),f.parse({seriesName:A,posts:c,series:{...B,description:x.description,postCount:c.length},description:x.description})}async fetchSeriesDetailBySlug(A,f,w){let B=(await w.listEntities("series",{filter:{metadata:{slug:A}}}))[0];if(!B)return this.logger.warn(`Series not found with slug: ${A}`),f.parse({seriesName:A,posts:[]});return this.fetchSeriesDetail(B.metadata.title,f,w,B)}async countEntitiesPerSeries(A){let f=new Map,w=A.getEntityTypes();for(let Q of w){if(Q==="series")continue;let B=await A.listEntities(Q,{limit:1000});for(let x of B){let c=this.getSeriesName(x);if(c)f.set(c,(f.get(c)??0)+1)}}return f}async getSeriesMembers(A,f){let w=[],Q=f.getEntityTypes();for(let B of Q){if(B==="series")continue;let x=await f.listEntities(B,{filter:{metadata:{seriesName:A}}});w.push(...x)}return w.sort((B,x)=>{let c=B.metadata.seriesIndex,I=x.metadata.seriesIndex;return(typeof c==="number"?c:999)-(typeof I==="number"?I:999)}),w}getSeriesName(A){let w=A.metadata.seriesName;return typeof w==="string"?w:void 0}}B0();YA();R7();var wy2=X.object({prompt:X.string().optional(),title:X.string().optional(),seriesId:X.string().optional()});class ua{logger;context;constructor(A,f){this.logger=A;this.context=f}async process(A){let f=A.seriesId??A.title;if(!f)return{success:!1,error:"seriesId or title required"};let w=await this.context.entityService.getEntity("series",f);if(!w)return{success:!1,error:`Series not found: ${f}`};let Q=await this.gatherMemberSummaries(w.metadata.title);if(Q.length===0)return{success:!1,error:`No members found in series: ${w.metadata.title}`};let B=A.prompt??`Series name: ${w.metadata.title}
2776
2776
 
2777
2777
  Content in this series:
2778
2778
  ${Q.join(`
@@ -2784,7 +2784,7 @@ Your task is to write a series description (2-3 sentences) that:
2784
2784
  3. Is engaging and makes readers want to explore the content
2785
2785
  4. Works well as a series overview on a website
2786
2786
 
2787
- Be concise and focus on what makes this series unique and valuable.`});var id0={name:"@brains/series",private:!0,version:"0.2.0-alpha.8",description:"Cross-content series \u2014 auto-derived from entities with seriesName metadata",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts,.tsx","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class PvA extends Nf{entityType="series";schema=mb;adapter=lb;manager;constructor(){super("series",id0)}getEntityTypeConfig(){return{weight:0.5}}createGenerationHandler(A){return new ua(this.logger.child("SeriesGenerationHandler"),A)}getTemplates(){return{..._d0(),description:Vd0}}getDataSources(){return[new gvA(this.logger.child("SeriesDataSource"))]}async onRegister(A){this.manager=new jvA(A.entityService,this.logger.child("SeriesManager"));let f=this.manager;for(let w of["entity:created","entity:updated"])A.messaging.subscribe(w,async(Q)=>{try{let B=Q.payload;if(B.entityType==="series")return{success:!0};if(B.entity){if(f.getSeriesName(B.entity))await f.handleEntityChange(B.entity)}return{success:!0}}catch(B){return this.logger.error("Failed to handle entity event for series",{error:B}),{success:!1,error:"Series derivation failed"}}});A.messaging.subscribe("entity:deleted",async(w)=>{try{if(w.payload.entityType==="series")return{success:!0};return await f.handleEntityDeleted(),{success:!0}}catch(Q){return this.logger.error("Failed to handle entity deletion for series",{error:Q}),{success:!1,error:"Series cleanup failed"}}}),A.messaging.subscribe("sync:initial:completed",async()=>{try{return this.logger.info("Initial sync completed, syncing series"),await f.syncAllSeries(),{success:!0}}catch(w){return this.logger.error("Failed to sync series after initial sync",{error:w}),{success:!1,error:"Series sync failed"}}})}requireManager(){if(!this.manager)throw Error("SeriesPlugin not registered");return this.manager}async derive(A,f,w){await this.requireManager().handleEntityChange(A)}async deriveAll(A){await this.requireManager().syncAllSeries();let f=new ua(this.logger.child("SeriesGenerationHandler"),A),w=await A.entityService.listEntities("series",{limit:1000});for(let Q of w)try{if(!this.adapter.parseBody(Q.content).description)this.logger.info(`Generating description for series: ${Q.metadata.title}`),await f.process({seriesId:Q.id})}catch(B){this.logger.error(`Failed to generate description for series: ${Q.id}`,{error:B})}}}function RvA(){return new PvA}B0();YA();B0();YA();YA();B0();var Iy2=X.enum(["draft","queued","published"]),DF=X.object({title:X.string(),slug:X.string().optional(),description:X.string().optional(),author:X.string().optional(),status:Iy2,publishedAt:X.string().datetime().optional(),event:X.string().optional(),coverImageId:X.string().optional()}),$y2=DF.pick({title:!0,description:!0,status:!0,publishedAt:!0,coverImageId:!0}).extend({slug:X.string()}),Da=v2.extend({entityType:X.literal("deck"),metadata:$y2}),Ya=Da.extend({frontmatter:DF,body:X.string()}),RM=Ya.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});class nvA extends _2{constructor(){super({entityType:"deck",schema:Da,frontmatterSchema:DF,supportsCoverImage:!0})}validateSlideStructure(A){if(!/^---$/gm.test(A))throw Error("Invalid deck: markdown must contain slide separators (---) to be a valid presentation")}toMarkdown(A){let f=this.extractBody(A.content);this.validateSlideStructure(f);try{let w=this.parseFrontMatter(A.content,DF),Q={...w,slug:w.slug??A.metadata.slug};return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontmatter(A),w=this.extractBody(A);this.validateSlideStructure(w);let Q=f.slug??x2(f.title),B=f.status;return{entityType:"deck",content:A,metadata:{slug:Q,title:f.title,description:f.description,status:B,publishedAt:f.publishedAt,coverImageId:f.coverImageId}}}generateTitle(A){return A.metadata.title}generateSummary(A){if(A.metadata.description)return A.metadata.description;return`Presentation: ${A.metadata.title}`}generateFrontMatter(A){return this.toMarkdown(A)}}var nM=new nvA;YA();P2();var uy2=X.object({markdown:X.string().describe("Markdown content with slide separators (---)")}),mvA=i0({name:"deck-detail",description:"Render a presentation deck as Reveal.js slides",schema:uy2,dataSourceId:"decks:entities",requiredPermission:"public",layout:{component:BKA,fullscreen:!0}});P2();YA();var lvA=X.object({decks:X.array(Ya)}),TvA=X.object({decks:X.array(RM),pageTitle:X.string().optional()});import{jsxDEV as yvA}from"preact/jsx-dev-runtime";var SvA=({decks:A,pageTitle:f})=>{let w=A.map((Q)=>({id:Q.id,url:Q.url,title:Q.frontmatter.title,date:Q.frontmatter.publishedAt??Q.created,description:Q.frontmatter.description}));return yvA("div",{className:"deck-list bg-theme",children:yvA("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:yvA(M3,{title:f??"Presentations",items:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)};YA();class Ha extends R1{constructor(){super(lvA,{title:"Deck List",mappings:[{key:"decks",label:"Decks",type:"array",itemType:"object"}]})}}var pvA=i0({name:"deck-list",description:"List view of all presentation decks",schema:TvA,dataSourceId:"decks:entities",requiredPermission:"public",formatter:new Ha,layout:{component:SvA}});YA();B0();var Dy2=X.object({title:X.string().max(80).describe("A short, punchy title (2-5 words) that's memorable and evocative"),content:X.string().describe("Full slide deck content in markdown format with slide separators (---). Each slide should have a header and focused content."),description:X.string().describe("A concise 1-2 sentence summary that captures the essence of the talk")}),Md0=i0({name:"decks:generation",description:"Template for AI to generate complete slide decks from prompts",schema:Dy2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are creating slide decks in a distinctive voice that blends philosophy, technology, and culture.
2787
+ Be concise and focus on what makes this series unique and valuable.`});var id0={name:"@brains/series",private:!0,version:"0.2.0-alpha.9",description:"Cross-content series \u2014 auto-derived from entities with seriesName metadata",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts,.tsx","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class PvA extends Nf{entityType="series";schema=mb;adapter=lb;manager;constructor(){super("series",id0)}getEntityTypeConfig(){return{weight:0.5}}createGenerationHandler(A){return new ua(this.logger.child("SeriesGenerationHandler"),A)}getTemplates(){return{..._d0(),description:Vd0}}getDataSources(){return[new gvA(this.logger.child("SeriesDataSource"))]}async onRegister(A){this.manager=new jvA(A.entityService,this.logger.child("SeriesManager"));let f=this.manager;for(let w of["entity:created","entity:updated"])A.messaging.subscribe(w,async(Q)=>{try{let B=Q.payload;if(B.entityType==="series")return{success:!0};if(B.entity){if(f.getSeriesName(B.entity))await f.handleEntityChange(B.entity)}return{success:!0}}catch(B){return this.logger.error("Failed to handle entity event for series",{error:B}),{success:!1,error:"Series derivation failed"}}});A.messaging.subscribe("entity:deleted",async(w)=>{try{if(w.payload.entityType==="series")return{success:!0};return await f.handleEntityDeleted(),{success:!0}}catch(Q){return this.logger.error("Failed to handle entity deletion for series",{error:Q}),{success:!1,error:"Series cleanup failed"}}}),A.messaging.subscribe("sync:initial:completed",async()=>{try{return this.logger.info("Initial sync completed, syncing series"),await f.syncAllSeries(),{success:!0}}catch(w){return this.logger.error("Failed to sync series after initial sync",{error:w}),{success:!1,error:"Series sync failed"}}})}requireManager(){if(!this.manager)throw Error("SeriesPlugin not registered");return this.manager}async derive(A,f,w){await this.requireManager().handleEntityChange(A)}async deriveAll(A){await this.requireManager().syncAllSeries();let f=new ua(this.logger.child("SeriesGenerationHandler"),A),w=await A.entityService.listEntities("series",{limit:1000});for(let Q of w)try{if(!this.adapter.parseBody(Q.content).description)this.logger.info(`Generating description for series: ${Q.metadata.title}`),await f.process({seriesId:Q.id})}catch(B){this.logger.error(`Failed to generate description for series: ${Q.id}`,{error:B})}}}function RvA(){return new PvA}B0();YA();B0();YA();YA();B0();var Iy2=X.enum(["draft","queued","published"]),DF=X.object({title:X.string(),slug:X.string().optional(),description:X.string().optional(),author:X.string().optional(),status:Iy2,publishedAt:X.string().datetime().optional(),event:X.string().optional(),coverImageId:X.string().optional()}),$y2=DF.pick({title:!0,description:!0,status:!0,publishedAt:!0,coverImageId:!0}).extend({slug:X.string()}),Da=v2.extend({entityType:X.literal("deck"),metadata:$y2}),Ya=Da.extend({frontmatter:DF,body:X.string()}),RM=Ya.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});class nvA extends _2{constructor(){super({entityType:"deck",schema:Da,frontmatterSchema:DF,supportsCoverImage:!0})}validateSlideStructure(A){if(!/^---$/gm.test(A))throw Error("Invalid deck: markdown must contain slide separators (---) to be a valid presentation")}toMarkdown(A){let f=this.extractBody(A.content);this.validateSlideStructure(f);try{let w=this.parseFrontMatter(A.content,DF),Q={...w,slug:w.slug??A.metadata.slug};return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontmatter(A),w=this.extractBody(A);this.validateSlideStructure(w);let Q=f.slug??x2(f.title),B=f.status;return{entityType:"deck",content:A,metadata:{slug:Q,title:f.title,description:f.description,status:B,publishedAt:f.publishedAt,coverImageId:f.coverImageId}}}generateTitle(A){return A.metadata.title}generateSummary(A){if(A.metadata.description)return A.metadata.description;return`Presentation: ${A.metadata.title}`}generateFrontMatter(A){return this.toMarkdown(A)}}var nM=new nvA;YA();P2();var uy2=X.object({markdown:X.string().describe("Markdown content with slide separators (---)")}),mvA=i0({name:"deck-detail",description:"Render a presentation deck as Reveal.js slides",schema:uy2,dataSourceId:"decks:entities",requiredPermission:"public",layout:{component:BKA,fullscreen:!0}});P2();YA();var lvA=X.object({decks:X.array(Ya)}),TvA=X.object({decks:X.array(RM),pageTitle:X.string().optional()});import{jsxDEV as yvA}from"preact/jsx-dev-runtime";var SvA=({decks:A,pageTitle:f})=>{let w=A.map((Q)=>({id:Q.id,url:Q.url,title:Q.frontmatter.title,date:Q.frontmatter.publishedAt??Q.created,description:Q.frontmatter.description}));return yvA("div",{className:"deck-list bg-theme",children:yvA("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:yvA(M3,{title:f??"Presentations",items:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)};YA();class Ha extends R1{constructor(){super(lvA,{title:"Deck List",mappings:[{key:"decks",label:"Decks",type:"array",itemType:"object"}]})}}var pvA=i0({name:"deck-list",description:"List view of all presentation decks",schema:TvA,dataSourceId:"decks:entities",requiredPermission:"public",formatter:new Ha,layout:{component:SvA}});YA();B0();var Dy2=X.object({title:X.string().max(80).describe("A short, punchy title (2-5 words) that's memorable and evocative"),content:X.string().describe("Full slide deck content in markdown format with slide separators (---). Each slide should have a header and focused content."),description:X.string().describe("A concise 1-2 sentence summary that captures the essence of the talk")}),Md0=i0({name:"decks:generation",description:"Template for AI to generate complete slide decks from prompts",schema:Dy2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are creating slide decks in a distinctive voice that blends philosophy, technology, and culture.
2788
2788
 
2789
2789
  Your task is to generate a complete slide deck based on the user's prompt.
2790
2790
 
@@ -2852,7 +2852,7 @@ Add your conclusion here`,$=$??`Presentation: ${c}`,await this.reportProgress(f,
2852
2852
  Note: This presentation is for "${B}".`:""}`,E=await this.context.ai.generate({prompt:G,templateName:"decks:generation"});c=c??E.title,I=I??E.content,$=$??E.description,await this.reportProgress(f,{progress:50,message:`Generated deck: "${c}"`})}else if(!$)await this.reportProgress(f,{progress:30,message:"Generating description with AI"}),$=(await this.context.ai.generate({prompt:`Title: ${c}
2853
2853
 
2854
2854
  Content:
2855
- ${I}`,templateName:"decks:description"})).description,await this.reportProgress(f,{progress:50,message:"Description generated"});else await this.reportProgress(f,{progress:50,message:"Using provided content"});if(!c||!I)this.failEarly("Title and content are required");let Y={slug:x2(c),title:c,status:"draft"},F=await yD({entityType:"deck",title:c,deriveId:(k)=>k,regeneratePrompt:"Generate a different presentation deck title on the same topic.",context:this.context});if(F!==c)Y.title=F,Y.slug=x2(F);let K={title:Y.title,status:Y.status,slug:Y.slug,description:$,author:Q,event:B},Z=Y6(I,K);return{id:F,content:Z,metadata:Y,title:F,resultExtras:{title:F,slug:Y.slug},createOptions:{deduplicateId:!0}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var jd0={name:"@brains/decks",private:!0,version:"0.2.0-alpha.8",description:"Presentation decks plugin for creating and viewing slide presentations",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class ovA extends Nf{entityType=nM.entityType;schema=nM.schema;adapter=nM;constructor(){super("decks",jd0)}createGenerationHandler(A){return new dvA(this.logger.child("DeckGenerationJobHandler"),A)}getTemplates(){return{"deck-detail":mvA,"deck-list":pvA,generation:Md0,description:Od0}}getDataSources(){return[new rvA(this.logger)]}getEntityTypeConfig(){return{weight:1.5}}async onRegister(A){await this.registerWithPublishPipeline(A),this.subscribeToPublishExecute(A),this.registerEvalHandlers(A),this.logger.info("Decks plugin registered")}async registerWithPublishPipeline(A){await A.messaging.send("publish:register",{entityType:"deck",provider:{name:"internal",publish:async()=>({id:"internal"})}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(f)=>{let{entityType:w,entityId:Q}=f.payload;if(w!=="deck")return{success:!0};try{let B=await A.entityService.getEntity("deck",Q);if(!B)return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:`Deck not found: ${Q}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=new Date().toISOString(),c={...B,metadata:{...B.metadata,status:"published",publishedAt:x}};await A.entityService.updateEntity({...c,content:this.adapter.toMarkdown(c)}),await A.messaging.send("publish:report:success",{entityType:w,entityId:Q,result:{id:Q}})}catch(B){await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:h0(B)})}return{success:!0}})}registerEvalHandlers(A){A.eval.registerHandler("generateDeck",async(f)=>{let w=X.object({prompt:X.string(),event:X.string().optional()}).parse(f);return A.ai.generate({prompt:`${w.prompt}${w.event?`
2855
+ ${I}`,templateName:"decks:description"})).description,await this.reportProgress(f,{progress:50,message:"Description generated"});else await this.reportProgress(f,{progress:50,message:"Using provided content"});if(!c||!I)this.failEarly("Title and content are required");let Y={slug:x2(c),title:c,status:"draft"},F=await yD({entityType:"deck",title:c,deriveId:(k)=>k,regeneratePrompt:"Generate a different presentation deck title on the same topic.",context:this.context});if(F!==c)Y.title=F,Y.slug=x2(F);let K={title:Y.title,status:Y.status,slug:Y.slug,description:$,author:Q,event:B},Z=Y6(I,K);return{id:F,content:Z,metadata:Y,title:F,resultExtras:{title:F,slug:Y.slug},createOptions:{deduplicateId:!0}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var jd0={name:"@brains/decks",private:!0,version:"0.2.0-alpha.9",description:"Presentation decks plugin for creating and viewing slide presentations",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class ovA extends Nf{entityType=nM.entityType;schema=nM.schema;adapter=nM;constructor(){super("decks",jd0)}createGenerationHandler(A){return new dvA(this.logger.child("DeckGenerationJobHandler"),A)}getTemplates(){return{"deck-detail":mvA,"deck-list":pvA,generation:Md0,description:Od0}}getDataSources(){return[new rvA(this.logger)]}getEntityTypeConfig(){return{weight:1.5}}async onRegister(A){await this.registerWithPublishPipeline(A),this.subscribeToPublishExecute(A),this.registerEvalHandlers(A),this.logger.info("Decks plugin registered")}async registerWithPublishPipeline(A){await A.messaging.send("publish:register",{entityType:"deck",provider:{name:"internal",publish:async()=>({id:"internal"})}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(f)=>{let{entityType:w,entityId:Q}=f.payload;if(w!=="deck")return{success:!0};try{let B=await A.entityService.getEntity("deck",Q);if(!B)return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:`Deck not found: ${Q}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=new Date().toISOString(),c={...B,metadata:{...B.metadata,status:"published",publishedAt:x}};await A.entityService.updateEntity({...c,content:this.adapter.toMarkdown(c)}),await A.messaging.send("publish:report:success",{entityType:w,entityId:Q,result:{id:Q}})}catch(B){await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:h0(B)})}return{success:!0}})}registerEvalHandlers(A){A.eval.registerHandler("generateDeck",async(f)=>{let w=X.object({prompt:X.string(),event:X.string().optional()}).parse(f);return A.ai.generate({prompt:`${w.prompt}${w.event?`
2856
2856
 
2857
2857
  Note: This presentation is for "${w.event}".`:""}`,templateName:"decks:generation"})}),A.eval.registerHandler("generateDescription",async(f)=>{let w=X.object({title:X.string(),content:X.string()}).parse(f);return A.ai.generate({prompt:`Title: ${w.title}
2858
2858
 
@@ -2867,7 +2867,7 @@ Guidelines:
2867
2867
  3. Depth: Provide enough detail to be useful as a reference, but stay focused on the topic.
2868
2868
  4. Style: Informative and educational. Write as if explaining to yourself for future reference.
2869
2869
  5. Length: Adjust based on topic complexity - concise for simple topics, more detailed for complex ones.
2870
- 6. No meta-commentary: Just provide the content directly without phrases like "Here is..." or "This note covers..."`});B0();YA();var Rd0=X.object({prompt:X.string(),title:X.string().optional()}),Ky2=xc.extend({title:X.string().optional()});class Ua extends Cx{constructor(A,f){super(A,f,{schema:Rd0,jobTypeName:"note-generation",entityType:"base"})}async generate(A,f){await this.reportProgress(f,{progress:10,message:"Generating note content with AI"});let w=await this.context.ai.generate({prompt:A.prompt,templateName:"note:generation"}),Q=A.title??w.title;return await this.reportProgress(f,{progress:50,message:`Generated note: "${Q}"`}),{id:Q,content:yb.createNoteContent(Q,w.body),metadata:{title:Q},title:Q,resultExtras:{title:Q}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var nd0={name:"@brains/note",private:!0,version:"0.2.0-alpha.8",description:"Personal knowledge capture with markdown-first workflow",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class evA extends Nf{entityType=yb.entityType;schema=Tb;adapter=yb;constructor(A={}){super("note",nd0,A,svA)}createGenerationHandler(A){return new Ua(this.logger.child("NoteGenerationJobHandler"),A)}getTemplates(){return{generation:tvA}}async onRegister(A){A.eval.registerHandler("generateNote",async(f)=>{let w=X.object({prompt:X.string()}).parse(f);return A.ai.generate({prompt:w.prompt,templateName:"note:generation"})})}}function Lv(A={}){return new evA(A)}B0();YA();YA();B0();var md0=X.object({ref:X.string(),label:X.string()}),ld0=X.enum(["pending","draft","published"]),fY=X.object({status:ld0,title:X.string(),url:X.string().url(),description:X.string().optional(),keywords:X.array(X.string()),domain:X.string(),capturedAt:X.string().datetime(),source:md0}),Td0=fY.pick({title:!0,status:!0}),TM=v2.extend({entityType:X.literal("link"),metadata:Td0}),AWA=X.object({enableSummarization:X.boolean().default(!0).describe("Generate AI summaries for captured links"),autoExtractKeywords:X.boolean().default(!0).describe("Automatically extract keywords from content"),jinaApiKey:X.string().optional().describe("Jina Reader API key for higher rate limits (500 RPM vs 20 RPM without key)")});B0();class HF extends _2{constructor(){super({entityType:"link",schema:TM,frontmatterSchema:fY})}createLinkContent(A){let f={status:A.status,title:A.title,url:A.url,description:A.description,keywords:A.keywords,domain:A.domain,capturedAt:A.capturedAt,source:A.source},w=A.summary??"";return this.buildMarkdown(w,f)}parseLinkContent(A){return{frontmatter:this.parseFrontMatter(A,fY),summary:this.extractBody(A).trim()}}toMarkdown(A){return A.content}fromMarkdown(A){let{frontmatter:f}=this.parseLinkContent(A);return{content:A,entityType:"link",metadata:{title:f.title,status:f.status}}}}var fWA=new HF;B0();YA();var Zy2=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().optional().describe("If success is false, explain why content could not be extracted"),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."),keywords:X.array(X.string()).describe("3-5 relevant keywords that categorize this content. Leave empty array if success is false.")}),yd0=i0({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:Zy2,basePrompt:`You are an expert at extracting key information from webpage content.
2870
+ 6. No meta-commentary: Just provide the content directly without phrases like "Here is..." or "This note covers..."`});B0();YA();var Rd0=X.object({prompt:X.string(),title:X.string().optional()}),Ky2=xc.extend({title:X.string().optional()});class Ua extends Cx{constructor(A,f){super(A,f,{schema:Rd0,jobTypeName:"note-generation",entityType:"base"})}async generate(A,f){await this.reportProgress(f,{progress:10,message:"Generating note content with AI"});let w=await this.context.ai.generate({prompt:A.prompt,templateName:"note:generation"}),Q=A.title??w.title;return await this.reportProgress(f,{progress:50,message:`Generated note: "${Q}"`}),{id:Q,content:yb.createNoteContent(Q,w.body),metadata:{title:Q},title:Q,resultExtras:{title:Q}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var nd0={name:"@brains/note",private:!0,version:"0.2.0-alpha.9",description:"Personal knowledge capture with markdown-first workflow",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class evA extends Nf{entityType=yb.entityType;schema=Tb;adapter=yb;constructor(A={}){super("note",nd0,A,svA)}createGenerationHandler(A){return new Ua(this.logger.child("NoteGenerationJobHandler"),A)}getTemplates(){return{generation:tvA}}async onRegister(A){A.eval.registerHandler("generateNote",async(f)=>{let w=X.object({prompt:X.string()}).parse(f);return A.ai.generate({prompt:w.prompt,templateName:"note:generation"})})}}function Lv(A={}){return new evA(A)}B0();YA();YA();B0();var md0=X.object({ref:X.string(),label:X.string()}),ld0=X.enum(["pending","draft","published"]),fY=X.object({status:ld0,title:X.string(),url:X.string().url(),description:X.string().optional(),keywords:X.array(X.string()),domain:X.string(),capturedAt:X.string().datetime(),source:md0}),Td0=fY.pick({title:!0,status:!0}),TM=v2.extend({entityType:X.literal("link"),metadata:Td0}),AWA=X.object({enableSummarization:X.boolean().default(!0).describe("Generate AI summaries for captured links"),autoExtractKeywords:X.boolean().default(!0).describe("Automatically extract keywords from content"),jinaApiKey:X.string().optional().describe("Jina Reader API key for higher rate limits (500 RPM vs 20 RPM without key)")});B0();class HF extends _2{constructor(){super({entityType:"link",schema:TM,frontmatterSchema:fY})}createLinkContent(A){let f={status:A.status,title:A.title,url:A.url,description:A.description,keywords:A.keywords,domain:A.domain,capturedAt:A.capturedAt,source:A.source},w=A.summary??"";return this.buildMarkdown(w,f)}parseLinkContent(A){return{frontmatter:this.parseFrontMatter(A,fY),summary:this.extractBody(A).trim()}}toMarkdown(A){return A.content}fromMarkdown(A){let{frontmatter:f}=this.parseLinkContent(A);return{content:A,entityType:"link",metadata:{title:f.title,status:f.status}}}}var fWA=new HF;B0();YA();var Zy2=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().optional().describe("If success is false, explain why content could not be extracted"),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."),keywords:X.array(X.string()).describe("3-5 relevant keywords that categorize this content. Leave empty array if success is false.")}),yd0=i0({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:Zy2,basePrompt:`You are an expert at extracting key information from webpage content.
2871
2871
 
2872
2872
  You will receive webpage content in markdown format. Your job is to extract structured information from it.
2873
2873
 
@@ -2883,7 +2883,7 @@ Focus only on information present in the provided content. Do not make up or hal
2883
2883
 
2884
2884
  `))return{success:!1,error:c.trim(),errorType:"fetch_failed"};return{success:!0,content:c}}catch(w){return this.handleFetchError(w,A)}}handleHttpError(A,f){if(A===400)return{success:!1,error:`Invalid or non-existent URL: ${f}`,errorType:"url_not_found"};if(A===404)return{success:!1,error:`Page not found: ${f}`,errorType:"url_not_found"};if(A>=500)return{success:!1,error:`Server error while fetching ${f}`,errorType:"url_unreachable"};return{success:!1,error:`HTTP ${A} error while fetching ${f}`,errorType:"fetch_failed"}}handleFetchError(A,f){if(A instanceof Error){if(A.name==="AbortError")return{success:!1,error:`Request timeout while fetching ${f}`,errorType:"url_unreachable"};if(A.message.includes("ENOTFOUND")||A.message.includes("getaddrinfo"))return{success:!1,error:`Domain not found: ${new URL(f).hostname}`,errorType:"url_not_found"};if(A.message.includes("ECONNREFUSED")||A.message.includes("ETIMEDOUT"))return{success:!1,error:`Could not connect to ${f}`,errorType:"url_unreachable"};return{success:!1,error:`Failed to fetch ${f}: ${A.message}`,errorType:"fetch_failed"}}return{success:!1,error:`Unknown error fetching ${f}`,errorType:"fetch_failed"}}}B0();YA();import{createHash as hy2}from"crypto";class SM{static URL_PATTERN=/https?:\/\/[^\s<>"{}|\\^`[\]]+?(?=[,;:\s]|$)/gi;static extractUrls(A){let f=A.match(SM.URL_PATTERN)??[];return[...new Set(f)]}static normalizeUrl(A){try{let f=new URL(A),w=f.pathname.replace(/\/$/,"")||"/";return`${f.protocol}//${f.host}${w}`}catch{return A}}static generateEntityId(A){let f=this.normalizeUrl(A),w=hy2("sha256").update(f).digest("hex");try{return`${new URL(f).hostname.replace(/\./g,"-")}-${w.substring(0,6)}`}catch{return w.substring(0,12)}}static isValidUrl(A){try{let f=new URL(A);return["http:","https:"].includes(f.protocol)}catch{return!1}}}var Gy2=X.object({url:X.string().url(),metadata:X.object({interfaceId:X.string().optional(),userId:X.string().optional(),channelId:X.string().optional(),channelName:X.string().optional(),timestamp:X.string().optional()}).optional()}),yhw=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 IWA extends Vw{context;linkAdapter;urlFetcher;constructor(A,f,w){super(A,{schema:Gy2,jobTypeName:"link-capture"});this.context=f,this.linkAdapter=new HF,this.urlFetcher=new Sb(w?.jinaApiKey?{jinaApiKey:w.jinaApiKey}:void 0)}async process(A,f,w){let{url:Q,metadata:B}=A;try{await w.report({progress:F2.START,total:100,message:"Starting link capture"});let x=SM.generateEntityId(Q);await w.report({progress:F2.INIT,total:100,message:"Checking for existing link"});let c=await this.context.entityService.getEntity("link",x);if(c){this.logger.info("Link already captured, returning existing",{url:Q,entityId:x});let{frontmatter:Z}=this.linkAdapter.parseLinkContent(c.content);return{success:!0,entityId:c.id,title:Z.title,url:Q,status:c.metadata.status}}await w.report({progress:F2.FETCH,total:100,message:"Fetching webpage content"});let I=await this.urlFetcher.fetch(Q);if(!I.success){if(I.errorType==="url_not_found"||I.errorType==="url_unreachable")return this.logger.warn("Link URL not accessible",{url:Q,errorType:I.errorType,error:I.error}),{success:!1,error:`Could not capture link: ${I.error}`}}await w.report({progress:F2.PROCESS,total:100,message:"Extracting content with AI"});let $=await this.context.ai.generate({templateName:"link:extraction",prompt:I.success?`Extract structured information from this webpage content:
2885
2885
 
2886
- ${I.content}`:`The URL ${Q} could not be fetched. Return success: false with error: "${I.error}"`,data:{url:Q,hasContent:I.success},interfacePermissionGrant:"public"});this.logger.debug("AI extraction result",{result:$}),await w.report({progress:F2.EXTRACT,total:100,message:"Processing extraction results"});let u=this.resolveSource(B),Y=new Date().toISOString();if($.success===!1||!$.title||!$.description||!$.summary){let Z=$.title||new URL(Q).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:Q}),await w.report({progress:F2.SAVE,total:100,message:"Saving link as pending"});let k=this.linkAdapter.createLinkContent({status:"pending",title:Z,url:Q,description:$.description,summary:$.summary,keywords:$.keywords,domain:new URL(Q).hostname,capturedAt:Y,source:u}),h=await this.context.entityService.createEntity({id:x,entityType:"link",content:k,metadata:{status:"pending",title:Z}});return await w.report({progress:F2.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:h.entityId,title:Z,url:Q,status:"pending"}}await w.report({progress:F2.SAVE,total:100,message:`Saving link: "${$.title}"`});let F=this.linkAdapter.createLinkContent({status:"draft",title:$.title,url:Q,description:$.description,summary:$.summary,keywords:$.keywords,domain:new URL(Q).hostname,capturedAt:Y,source:u}),K=await this.context.entityService.createEntity({id:x,entityType:"link",content:F,metadata:{status:"draft",title:$.title}});return await w.report({progress:F2.COMPLETE,total:100,message:`Link captured: "${$.title}"`}),{success:!0,entityId:K.entityId,title:$.title,url:Q,status:"draft"}}catch(x){return this.logger.error("Link capture job failed",{error:x,jobId:f,data:A}),h8.failure(x)}}resolveSource(A){let f=A?.channelId,w=A?.channelName;if(f)return{ref:`matrix:${f}`,label:w??f};let Q=A?.interfaceId??"cli";return{ref:`${Q}:local`,label:Q.toUpperCase()}}summarizeDataForLog(A){return{url:A.url,interfaceId:A.metadata?.interfaceId}}}var rd0={name:"@brains/link",private:!0,version:"0.2.0-alpha.8",description:"Web content capture plugin with AI-powered extraction and structured storage",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class $WA extends Nf{entityType=fWA.entityType;schema=TM;adapter=fWA;constructor(A={}){super("link",rd0,A,AWA)}createGenerationHandler(A){return new IWA(this.logger.child("LinkCaptureJobHandler"),A,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:yd0,"link-list":Sd0,"link-detail":pd0}}getDataSources(){return[new cWA(this.logger.child("LinksDataSource"))]}async onRegister(A){A.eval.registerHandler("extractContent",async(f)=>{let{url:w}=X.object({url:X.string().url()}).parse(f),B=await new Sb(this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0).fetch(w);if(!B.success)return{success:!1,error:B.error,errorType:B.errorType};return A.ai.generate({templateName:"link:extraction",prompt:`Extract structured information from this webpage content:
2886
+ ${I.content}`:`The URL ${Q} could not be fetched. Return success: false with error: "${I.error}"`,data:{url:Q,hasContent:I.success},interfacePermissionGrant:"public"});this.logger.debug("AI extraction result",{result:$}),await w.report({progress:F2.EXTRACT,total:100,message:"Processing extraction results"});let u=this.resolveSource(B),Y=new Date().toISOString();if($.success===!1||!$.title||!$.description||!$.summary){let Z=$.title||new URL(Q).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:Q}),await w.report({progress:F2.SAVE,total:100,message:"Saving link as pending"});let k=this.linkAdapter.createLinkContent({status:"pending",title:Z,url:Q,description:$.description,summary:$.summary,keywords:$.keywords,domain:new URL(Q).hostname,capturedAt:Y,source:u}),h=await this.context.entityService.createEntity({id:x,entityType:"link",content:k,metadata:{status:"pending",title:Z}});return await w.report({progress:F2.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:h.entityId,title:Z,url:Q,status:"pending"}}await w.report({progress:F2.SAVE,total:100,message:`Saving link: "${$.title}"`});let F=this.linkAdapter.createLinkContent({status:"draft",title:$.title,url:Q,description:$.description,summary:$.summary,keywords:$.keywords,domain:new URL(Q).hostname,capturedAt:Y,source:u}),K=await this.context.entityService.createEntity({id:x,entityType:"link",content:F,metadata:{status:"draft",title:$.title}});return await w.report({progress:F2.COMPLETE,total:100,message:`Link captured: "${$.title}"`}),{success:!0,entityId:K.entityId,title:$.title,url:Q,status:"draft"}}catch(x){return this.logger.error("Link capture job failed",{error:x,jobId:f,data:A}),h8.failure(x)}}resolveSource(A){let f=A?.channelId,w=A?.channelName;if(f)return{ref:`matrix:${f}`,label:w??f};let Q=A?.interfaceId??"cli";return{ref:`${Q}:local`,label:Q.toUpperCase()}}summarizeDataForLog(A){return{url:A.url,interfaceId:A.metadata?.interfaceId}}}var rd0={name:"@brains/link",private:!0,version:"0.2.0-alpha.9",description:"Web content capture plugin with AI-powered extraction and structured storage",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class $WA extends Nf{entityType=fWA.entityType;schema=TM;adapter=fWA;constructor(A={}){super("link",rd0,A,AWA)}createGenerationHandler(A){return new IWA(this.logger.child("LinkCaptureJobHandler"),A,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:yd0,"link-list":Sd0,"link-detail":pd0}}getDataSources(){return[new cWA(this.logger.child("LinksDataSource"))]}async onRegister(A){A.eval.registerHandler("extractContent",async(f)=>{let{url:w}=X.object({url:X.string().url()}).parse(f),B=await new Sb(this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0).fetch(w);if(!B.success)return{success:!1,error:B.error,errorType:B.errorType};return A.ai.generate({templateName:"link:extraction",prompt:`Extract structured information from this webpage content:
2887
2887
 
2888
2888
  ${B.content}`,data:{url:w,hasContent:!0},interfacePermissionGrant:"public"})})}}function dd0(A={}){return new $WA(A)}var qv=dd0;YA();var uGw=X.object({id:X.string().optional(),metadata:X.object({conversationId:X.string().optional(),interfaceId:X.string().optional(),userId:X.string().optional(),messageId:X.string().optional(),timestamp:X.string().optional()}).optional()});B0();YA();P2();YA();B0();var od0=X.enum(["draft","published"]),S4=X.object({title:X.string(),slug:X.string().optional(),status:od0,publishedAt:X.string().datetime().optional(),description:X.string(),year:X.number(),coverImageId:X.string().optional(),url:X.string().url().optional()}),ad0=S4.pick({title:!0,status:!0,publishedAt:!0,year:!0}).extend({slug:X.string()}),pb=v2.extend({entityType:X.literal("project"),metadata:ad0}),Ka=X.object({context:X.string(),problem:X.string(),solution:X.string(),outcome:X.string()}),pM=pb.extend({frontmatter:S4,body:X.string(),structuredContent:Ka.optional(),coverImageUrl:X.string().optional()}),rb=pM.extend({url:X.string().optional(),typeLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),by2=pM.extend({url:X.string(),typeLabel:X.string(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});B0();YA();YA();class uWA extends R1{constructor(){super(Ka,{title:"Project",mappings:[{key:"context",label:"Context",type:"string"},{key:"problem",label:"Problem",type:"string"},{key:"solution",label:"Solution",type:"string"},{key:"outcome",label:"Outcome",type:"string"}]})}}var DWA=new uWA;class YWA extends _2{constructor(){super({entityType:"project",schema:pb,frontmatterSchema:S4,supportsCoverImage:!0,bodyFormatter:DWA})}toMarkdown(A){let f=this.extractBody(A.content);try{let w=this.parseFrontMatter(A.content,S4),Q={...w,slug:w.slug??A.metadata.slug};return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,S4),w=f.slug??x2(f.title);return{content:A,entityType:"project",metadata:{title:f.title,slug:w,status:f.status,publishedAt:f.publishedAt,year:f.year}}}parseProjectFrontmatter(A){return this.parseFrontMatter(A.content,S4)}parseStructuredContent(A){return DWA.parse(this.extractBody(A.content))}createProjectContent(A,f){let w=DWA.format(f);return this.buildMarkdown(w,A)}}var UF=new YWA;YA();var HWA=X.object({});import{jsxDEV as g5,Fragment as Ny2}from"preact/jsx-dev-runtime";var zy2=({project:A})=>{let{frontmatter:f,url:w,coverImageUrl:Q}=A;return g5(Gf,{href:w,children:[Q&&g5("img",{src:Q,alt:f.title,className:"w-full h-56 object-cover rounded-md mb-4"},void 0,!1,void 0,this),g5(Rx,{children:f.title},void 0,!1,void 0,this),g5("p",{className:"text-theme leading-relaxed",children:f.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},UWA=({projects:A,pageTitle:f,pagination:w,baseUrl:Q="/projects"})=>{let B=f??"Projects",x=w?.totalItems??A.length,c=`Browse all ${x} ${x===1?"project":"projects"}`;return g5(Ny2,{children:[g5(o2,{title:B,description:c},void 0,!1,void 0,this),g5("div",{className:"project-list bg-theme",children:g5("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[g5("h1",{className:"text-4xl font-bold text-heading mb-12",children:B},void 0,!1,void 0,this),g5("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-8",children:A.map((I)=>g5(zy2,{project:I},I.id,!1,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&g5("div",{className:"mt-12",children:g5(WI,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:Q},void 0,!1,void 0,this)},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 Fw,Fragment as sd0}from"preact/jsx-dev-runtime";var Cy2=({prevProject:A,nextProject:f})=>{if(!A&&!f)return null;return Fw("nav",{className:"pt-12 mt-12 border-t border-theme-muted",children:Fw("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[A?Fw(Gf,{href:A.url,variant:"compact",children:[Fw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Previous"},void 0,!1,void 0,this),Fw("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:A.metadata.title},void 0,!1,void 0,this)]},void 0,!0,void 0,this):Fw("div",{},void 0,!1,void 0,this),f&&Fw(Gf,{href:f.url,variant:"compact",className:"md:text-right",children:[Fw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Next"},void 0,!1,void 0,this),Fw("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:f.metadata.title},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},Xa=({title:A,content:f})=>{if(!f)return null;return Fw("section",{className:"mb-12",children:[Fw("h2",{className:"text-2xl font-bold text-heading mb-4",children:A},void 0,!1,void 0,this),Fw(vI,{markdown:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},FWA=({project:A,prevProject:f,nextProject:w})=>{let{frontmatter:Q,structuredContent:B,metadata:x,coverImageUrl:c}=A;return Fw(sd0,{children:[Fw(o2,{title:Q.title,description:Q.description,...c&&{ogImage:c},ogType:"article"},void 0,!1,void 0,this),Fw("article",{className:"project-detail",children:Fw("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:Fw("div",{className:"max-w-3xl mx-auto",children:[c&&A.coverImageWidth&&A.coverImageHeight&&Fw(i3,{src:c,alt:Q.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8 shadow-lg"},void 0,!1,void 0,this),Fw("h1",{className:"text-4xl md:text-5xl font-bold text-heading leading-tight tracking-tight mb-4",children:Q.title},void 0,!1,void 0,this),Fw("div",{className:"flex flex-wrap items-center gap-4 text-theme-muted mb-8",children:[Fw("span",{className:"text-sm",children:x.year},void 0,!1,void 0,this),Q.url&&Fw(sd0,{children:[Fw("span",{className:"text-theme-muted",children:"|"},void 0,!1,void 0,this),Fw("a",{href:Q.url,target:"_blank",rel:"noopener noreferrer",className:"text-brand hover:text-brand-dark transition-colors",children:"View Project"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Fw("p",{className:"text-lg text-theme mb-12 leading-relaxed",children:Q.description},void 0,!1,void 0,this),B&&Fw("div",{className:"case-study",children:[Fw(Xa,{title:"Context",content:B.context},void 0,!1,void 0,this),Fw(Xa,{title:"Problem",content:B.problem},void 0,!1,void 0,this),Fw(Xa,{title:"Solution",content:B.solution},void 0,!1,void 0,this),Fw(Xa,{title:"Outcome",content:B.outcome},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Fw(Cy2,{prevProject:f,nextProject:w},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)};YA();B0();var Ey2=X.object({title:X.string().max(80).describe("A clear, compelling project title (3-8 words). Should capture the essence of the project."),description:X.string().describe("A 1-2 sentence summary of the project for portfolio cards. Focus on the core value delivered."),context:X.string().describe("Background information: Who was the client/user? What was the situation? What constraints existed? (2-4 paragraphs)"),problem:X.string().describe("The challenge: What specific problem needed solving? What were the pain points? (2-3 paragraphs)"),solution:X.string().describe("The approach: What was built? What technologies/methods were used? How did it work? (3-5 paragraphs)"),outcome:X.string().describe("The results: What impact did this have? What metrics improved? What was learned? (2-3 paragraphs)")}),KWA=i0({name:"portfolio:generation",description:"Template for AI to generate portfolio project case studies",schema:Ey2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are helping to create a professional portfolio case study based on REAL project information.
2889
2889
 
@@ -2902,7 +2902,7 @@ Guidelines:
2902
2902
  CRITICAL: Only include information that can be derived from the provided content. If information is missing, keep that section brief rather than inventing details.
2903
2903
 
2904
2904
  Tone: Professional but accessible. Write for someone evaluating real work.
2905
- Structure: Use markdown formatting. Break long sections into paragraphs for readability.`});B0();YA();var Ly2=X.object({prompt:X.string(),year:X.number(),title:X.string().optional()}),lGw=xc.extend({title:X.string().optional()});class Za extends Cx{constructor(A,f){super(A,f,{schema:Ly2,jobTypeName:"project-generation",entityType:"project"})}async generate(A,f){let{prompt:w,year:Q}=A;await this.reportProgress(f,{progress:10,message:"Generating project content with AI"});let B=await this.context.ai.generate({prompt:w,templateName:"portfolio:generation"}),x=A.title??B.title,c=x2(x);await this.reportProgress(f,{progress:50,message:`Generated project: "${x}"`});let I={title:x,slug:c,status:"draft",description:B.description,year:Q},$={context:B.context,problem:B.problem,solution:B.solution,outcome:B.outcome};return{id:c,content:UF.createProjectContent(I,$),metadata:{title:x,slug:c,status:"draft",year:Q},title:x,resultExtras:{title:x}}}summarizeDataForLog(A){return{prompt:A.prompt.substring(0,100),year:A.year,title:A.title}}}B0();B0();function qy2(A){let f=K2(A.content,S4),w=UF.parseStructuredContent(A);return pM.parse({...A,frontmatter:f.metadata,body:f.content,structuredContent:w})}class va extends U6{id="portfolio:entities";name="Portfolio Project DataSource";description="Fetches and transforms project entities for rendering";config={entityType:"project",defaultSort:[{field:"year",direction:"desc"},{field:"title",direction:"asc"}],defaultLimit:10,enableNavigation:!0};constructor(A){super(A);this.logger.debug("ProjectDataSource initialized")}transformEntity(A){return qy2(A)}buildDetailResult(A,f){return{project:A,prevProject:f?.prev??null,nextProject:f?.next??null}}buildListResult(A,f,w){return{projects:A,pagination:f,baseUrl:w.baseUrl}}}var td0={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.8",description:"Portfolio showcase for projects and case studies",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"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":"latest",typescript:"^5.3.3"}};var Vy2=X.object({projects:X.array(rb),pageTitle:X.string().optional(),pagination:$c.nullable(),baseUrl:X.string().optional()});class XWA extends Nf{entityType=UF.entityType;schema=pb;adapter=UF;constructor(A={}){super("portfolio",td0,A,HWA)}createGenerationHandler(A){return new Za(this.logger.child("ProjectGenerationJobHandler"),A)}getTemplates(){return{"project-list":i0({name:"project-list",description:"Portfolio project list page template",schema:Vy2,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:UWA}}),"project-detail":i0({name:"project-detail",description:"Individual project case study template",schema:X.object({project:rb,prevProject:rb.nullable(),nextProject:rb.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:FWA}}),generation:KWA}}getDataSources(){return[new va(this.logger.child("ProjectDataSource"))]}async onRegister(A){this.registerEvalHandlers(A),await this.registerWithPublishPipeline(A),this.subscribeToPublishExecute(A)}registerEvalHandlers(A){A.eval.registerHandler("generateProject",async(f)=>{let w=X.object({prompt:X.string(),year:X.number()}).parse(f);return A.ai.generate({prompt:w.prompt,templateName:"portfolio:generation"})})}async registerWithPublishPipeline(A){let f={name:"internal",publish:async()=>({id:"internal"})};await A.messaging.send("publish:register",{entityType:"project",provider:f})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(f)=>{let{entityType:w,entityId:Q}=f.payload;if(w!=="project")return{success:!0};try{let B=await A.entityService.getEntity("project",Q);if(!B)return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:`Project not found: ${Q}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=K2(B.content,S4),c=new Date().toISOString(),I=Y6(x.content,{...x.metadata,status:"published",publishedAt:c});await A.entityService.updateEntity({...B,content:I,metadata:{...B.metadata,status:"published",publishedAt:c}}),await A.messaging.send("publish:report:success",{entityType:w,entityId:Q,publishedAt:c})}catch(B){await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:h0(B)})}return{success:!0}})}}function ZWA(A={}){return new XWA(A)}B0();YA();YA();var ed0=X.object({includeEntityTypes:X.array(X.string()).default([]),minRelevanceScore:X.number().min(0).max(1).default(0.5),mergeSimilarityThreshold:X.number().min(0).max(1).default(0.85),autoMerge:X.boolean().default(!0),enableAutoExtraction:X.boolean().default(!0)});B0();YA();B0();var iy2=X.object({aliases:X.array(X.string()).optional()}),Wa=v2.extend({entityType:X.literal("topic"),metadata:iy2}),JJw=X.object({content:X.string(),keywords:X.array(X.string())}),Ao0=X.object({title:X.string().describe("Topic title"),keywords:X.array(X.string()).optional().describe("Topic keywords")}),bJw=X.object({timeWindowHours:X.number().min(1),minRelevanceScore:X.number().min(0).max(1)}),zJw=X.object({topicIds:X.array(X.string()).min(2),similarityThreshold:X.number().min(0).max(1)});class P5 extends _2{constructor(){super({entityType:"topic",schema:Wa,frontmatterSchema:Ao0})}buildFrontmatter(A,f){return{title:A,...f.length>0&&{keywords:f}}}toMarkdown(A){let f=this.parseTopicBody(A.content);return this.buildMarkdown(f.content,this.buildFrontmatter(f.title,f.keywords))}fromMarkdown(A){return{content:A,entityType:"topic"}}extractMetadata(A){return{aliases:A.metadata.aliases??[]}}generateFrontMatter(A){let f=this.parseTopicBody(A.content),Q=this.buildMarkdown("",this.buildFrontmatter(f.title,f.keywords)).match(/^---\n[\s\S]*?\n---/);return Q?Q[0]:""}parseTopicBody(A){if(A.startsWith("---"))try{let f=this.parseFrontmatter(A);return{content:this.extractBody(A).replace(/\n*## Sources[\s\S]*$/,"").trim(),keywords:f.keywords??[],formatted:A,title:f.title}}catch{return{content:A,keywords:[],formatted:A,title:"Unknown Topic"}}return{content:A,keywords:[],formatted:A,title:"Unknown Topic"}}createTopicBody(A){return this.buildMarkdown(A.content,this.buildFrontmatter(A.title,A.keywords))}}YA();var fo0=40,My2=new P5;async function ka(A,f=fo0){return(await A.listEntities("topic",{limit:f})).map((Q)=>My2.parseTopicBody(Q.content).title).filter((Q)=>Q.trim().length>0)}function ha(A){let f=(A.existingTopicTitles??[]).slice(0,fo0),w=f.length>0?`
2905
+ Structure: Use markdown formatting. Break long sections into paragraphs for readability.`});B0();YA();var Ly2=X.object({prompt:X.string(),year:X.number(),title:X.string().optional()}),lGw=xc.extend({title:X.string().optional()});class Za extends Cx{constructor(A,f){super(A,f,{schema:Ly2,jobTypeName:"project-generation",entityType:"project"})}async generate(A,f){let{prompt:w,year:Q}=A;await this.reportProgress(f,{progress:10,message:"Generating project content with AI"});let B=await this.context.ai.generate({prompt:w,templateName:"portfolio:generation"}),x=A.title??B.title,c=x2(x);await this.reportProgress(f,{progress:50,message:`Generated project: "${x}"`});let I={title:x,slug:c,status:"draft",description:B.description,year:Q},$={context:B.context,problem:B.problem,solution:B.solution,outcome:B.outcome};return{id:c,content:UF.createProjectContent(I,$),metadata:{title:x,slug:c,status:"draft",year:Q},title:x,resultExtras:{title:x}}}summarizeDataForLog(A){return{prompt:A.prompt.substring(0,100),year:A.year,title:A.title}}}B0();B0();function qy2(A){let f=K2(A.content,S4),w=UF.parseStructuredContent(A);return pM.parse({...A,frontmatter:f.metadata,body:f.content,structuredContent:w})}class va extends U6{id="portfolio:entities";name="Portfolio Project DataSource";description="Fetches and transforms project entities for rendering";config={entityType:"project",defaultSort:[{field:"year",direction:"desc"},{field:"title",direction:"asc"}],defaultLimit:10,enableNavigation:!0};constructor(A){super(A);this.logger.debug("ProjectDataSource initialized")}transformEntity(A){return qy2(A)}buildDetailResult(A,f){return{project:A,prevProject:f?.prev??null,nextProject:f?.next??null}}buildListResult(A,f,w){return{projects:A,pagination:f,baseUrl:w.baseUrl}}}var td0={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.9",description:"Portfolio showcase for projects and case studies",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"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":"latest",typescript:"^5.3.3"}};var Vy2=X.object({projects:X.array(rb),pageTitle:X.string().optional(),pagination:$c.nullable(),baseUrl:X.string().optional()});class XWA extends Nf{entityType=UF.entityType;schema=pb;adapter=UF;constructor(A={}){super("portfolio",td0,A,HWA)}createGenerationHandler(A){return new Za(this.logger.child("ProjectGenerationJobHandler"),A)}getTemplates(){return{"project-list":i0({name:"project-list",description:"Portfolio project list page template",schema:Vy2,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:UWA}}),"project-detail":i0({name:"project-detail",description:"Individual project case study template",schema:X.object({project:rb,prevProject:rb.nullable(),nextProject:rb.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:FWA}}),generation:KWA}}getDataSources(){return[new va(this.logger.child("ProjectDataSource"))]}async onRegister(A){this.registerEvalHandlers(A),await this.registerWithPublishPipeline(A),this.subscribeToPublishExecute(A)}registerEvalHandlers(A){A.eval.registerHandler("generateProject",async(f)=>{let w=X.object({prompt:X.string(),year:X.number()}).parse(f);return A.ai.generate({prompt:w.prompt,templateName:"portfolio:generation"})})}async registerWithPublishPipeline(A){let f={name:"internal",publish:async()=>({id:"internal"})};await A.messaging.send("publish:register",{entityType:"project",provider:f})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(f)=>{let{entityType:w,entityId:Q}=f.payload;if(w!=="project")return{success:!0};try{let B=await A.entityService.getEntity("project",Q);if(!B)return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:`Project not found: ${Q}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=K2(B.content,S4),c=new Date().toISOString(),I=Y6(x.content,{...x.metadata,status:"published",publishedAt:c});await A.entityService.updateEntity({...B,content:I,metadata:{...B.metadata,status:"published",publishedAt:c}}),await A.messaging.send("publish:report:success",{entityType:w,entityId:Q,publishedAt:c})}catch(B){await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:h0(B)})}return{success:!0}})}}function ZWA(A={}){return new XWA(A)}B0();YA();YA();var ed0=X.object({includeEntityTypes:X.array(X.string()).default([]),minRelevanceScore:X.number().min(0).max(1).default(0.5),mergeSimilarityThreshold:X.number().min(0).max(1).default(0.85),autoMerge:X.boolean().default(!0),enableAutoExtraction:X.boolean().default(!0)});B0();YA();B0();var iy2=X.object({aliases:X.array(X.string()).optional()}),Wa=v2.extend({entityType:X.literal("topic"),metadata:iy2}),JJw=X.object({content:X.string(),keywords:X.array(X.string())}),Ao0=X.object({title:X.string().describe("Topic title"),keywords:X.array(X.string()).optional().describe("Topic keywords")}),bJw=X.object({timeWindowHours:X.number().min(1),minRelevanceScore:X.number().min(0).max(1)}),zJw=X.object({topicIds:X.array(X.string()).min(2),similarityThreshold:X.number().min(0).max(1)});class P5 extends _2{constructor(){super({entityType:"topic",schema:Wa,frontmatterSchema:Ao0})}buildFrontmatter(A,f){return{title:A,...f.length>0&&{keywords:f}}}toMarkdown(A){let f=this.parseTopicBody(A.content);return this.buildMarkdown(f.content,this.buildFrontmatter(f.title,f.keywords))}fromMarkdown(A){return{content:A,entityType:"topic"}}extractMetadata(A){return{aliases:A.metadata.aliases??[]}}generateFrontMatter(A){let f=this.parseTopicBody(A.content),Q=this.buildMarkdown("",this.buildFrontmatter(f.title,f.keywords)).match(/^---\n[\s\S]*?\n---/);return Q?Q[0]:""}parseTopicBody(A){if(A.startsWith("---"))try{let f=this.parseFrontmatter(A);return{content:this.extractBody(A).replace(/\n*## Sources[\s\S]*$/,"").trim(),keywords:f.keywords??[],formatted:A,title:f.title}}catch{return{content:A,keywords:[],formatted:A,title:"Unknown Topic"}}return{content:A,keywords:[],formatted:A,title:"Unknown Topic"}}createTopicBody(A){return this.buildMarkdown(A.content,this.buildFrontmatter(A.title,A.keywords))}}YA();var fo0=40,My2=new P5;async function ka(A,f=fo0){return(await A.listEntities("topic",{limit:f})).map((Q)=>My2.parseTopicBody(Q.content).title).filter((Q)=>Q.trim().length>0)}function ha(A){let f=(A.existingTopicTitles??[]).slice(0,fo0),w=f.length>0?`
2906
2906
 
2907
2907
  Existing topic titles to reuse when they clearly fit:
2908
2908
  ${f.map((Q)=>`- ${Q}`).join(`
@@ -3010,13 +3010,13 @@ RULES:
3010
3010
  Return JSON with:
3011
3011
  - title
3012
3012
  - content
3013
- - keywords`,requiredPermission:"public"});P2();YA();var dy2=X.object({id:X.string(),title:X.string(),summary:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()}),dM=X.object({topics:X.array(dy2),totalCount:X.number()});import{jsxDEV as jI}from"preact/jsx-dev-runtime";var kWA=({topics:A,totalCount:f})=>{return jI("div",{className:"topic-list-container w-full max-w-4xl mx-auto p-6 bg-theme",children:[jI(ZI,{title:"Topics",count:f,singularLabel:"topic",description:"discovered from your knowledge base"},void 0,!1,void 0,this),jI("div",{className:"space-y-6",children:A.map((w)=>jI(Gf,{variant:"vertical",children:[jI(Rx,{href:`/topics/${w.id}`,className:"text-xl",children:w.title},void 0,!1,void 0,this),jI("p",{className:"text-theme-muted mb-4",children:w.summary},void 0,!1,void 0,this),jI(nx,{tags:w.keywords,maxVisible:5,variant:"muted",className:"mb-3"},void 0,!1,void 0,this),jI(O9,{children:jI("div",{className:"flex justify-between text-sm text-theme-muted",children:jI("time",{dateTime:w.updated,children:["Updated ",sQ(w.updated)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},w.id,!0,void 0,this))},void 0,!1,void 0,this),A.length===0&&jI(_5,{message:"No topics discovered yet.",description:"Topics will appear here as they are extracted from your content."},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();class Na extends R1{constructor(){super(dM,{title:"Topic List",mappings:[{key:"topics",label:"Topics",type:"array",itemType:"object"},{key:"totalCount",label:"Total Count",type:"number"}]})}}var Fo0=i0({name:"topics:topic-list",description:"List view of all discovered topics",schema:dM,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new Na,layout:{component:kWA}});P2();YA();var oM=X.object({id:X.string(),title:X.string(),content:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()});import{jsxDEV as FF}from"preact/jsx-dev-runtime";var hWA=({title:A,content:f,keywords:w,created:Q,updated:B})=>{return FF("article",{className:"topic-detail-container max-w-4xl mx-auto p-6 bg-theme",children:[FF(tZ,{title:A,created:Q,updated:B},void 0,!1,void 0,this),FF("div",{className:"prose prose-lg max-w-none mb-8 text-theme-muted",children:FF("div",{dangerouslySetInnerHTML:{__html:f}},void 0,!1,void 0,this)},void 0,!1,void 0,this),w.length>0&&FF("section",{className:"mb-8",children:[FF("h2",{className:"text-xl font-semibold mb-3 text-theme",children:"Keywords"},void 0,!1,void 0,this),FF(nx,{tags:w,maxVisible:w.length,size:"sm"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),FF(aZ,{href:"/topics",children:"Back to Topics"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();class Ca extends R1{constructor(){super(oM,{title:"Topic Detail",mappings:[{key:"id",label:"ID",type:"string"},{key:"title",label:"Title",type:"string"},{key:"content",label:"Content",type:"string"},{key:"keywords",label:"Keywords",type:"array",itemType:"string"},{key:"created",label:"Created",type:"string"},{key:"updated",label:"Updated",type:"string"}]})}}var Ko0=i0({name:"topics:topic-detail",description:"Detailed view of a single topic",schema:oM,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new Ca,layout:{component:hWA}});B0();YA();class GWA extends U6{id="topics:entities";name="Topics Entity DataSource";description="Fetches and transforms topic entities for rendering";config={entityType:"topic",defaultSort:[{field:"updated",direction:"desc"}],defaultLimit:100,lookupField:"id"};adapter=new P5;constructor(A){super(A);this.logger.debug("TopicsDataSource initialized")}transformEntity(A){let f=this.adapter.parseTopicBody(A.content);return{id:A.id,title:f.title,summary:XH(f.content,200),keywords:f.keywords,created:A.created,updated:A.updated}}buildListResult(A,f,w){return{topics:A,totalCount:A.length}}async fetch(A,f,w){let{query:Q}=this.parseQuery(A);if(Q.id){let x=await w.entityService.getEntity(this.config.entityType,Q.id);if(!x)throw Error(`Entity not found: ${Q.id}`);let c=this.adapter.parseTopicBody(x.content);return f.parse({id:x.id,title:c.title,content:c.content,keywords:c.keywords,created:x.created,updated:x.updated})}return super.fetch(A,f,w)}}R7();function Xo0(){let A=new P5;return async(f)=>{if(!f.hasEntityType("topic"))return{topics:[]};return{topics:(await f.listEntities("topic")).map((B)=>{let x=A.parseTopicBody(B.content);return{topic:B.id,title:x.title,keywords:x.keywords}})}}}var Zo0={name:"@brains/topics",private:!0,version:"0.2.0-alpha.8",description:"Extract and manage topics from conversations",type:"module",main:"./src/index.ts",types:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"}};var ay2=new P5;class vo0 extends Nf{entityType="topic";schema=Wa;adapter=ay2;autoExtractionEnabled=!1;initialDerivationDone=!1;constructor(A={}){super("topics",Zo0,A,ed0)}getEntityTypeConfig(){return{weight:0.5}}getTemplates(){return{extraction:Ho0,"merge-synthesis":Uo0,"topic-list":Fo0,"topic-detail":Ko0}}getDataSources(){return[new GWA(this.logger.child("TopicsDataSource"))]}async onRegister(A){let f=new za(A,this.logger);A.jobs.registerHandler("process-single",f);let w=new WWA(A,this.logger);if(A.jobs.registerHandler("extract",w),A.insights.register("topic-distribution",Xo0()),this.registerEvalHandler(A),this.config.enableAutoExtraction){A.messaging.subscribe("sync:initial:completed",async()=>{if(this.enableAutoExtraction(),!this.initialDerivationDone)this.initialDerivationDone=!0,await this.deriveAll(A);return{success:!0}});let Q=async(B)=>{if(!this.autoExtractionEnabled)return{success:!0};let{entityType:x,entity:c}=B.payload;if(!this.shouldProcessEntityType(x))return{success:!0};if(!c)return{success:!0};return await this.handleEntityChanged(A,c),{success:!0}};A.messaging.subscribe("entity:created",Q),A.messaging.subscribe("entity:updated",Q)}}async derive(A,f,w){if(!this.shouldProcessEntityType(A.entityType))return;if(!this.isEntityPublished(A))return;await this.handleEntityChanged(w,A)}async deriveAll(A){let f=await this.getEntitiesToExtract(A);if(f.length===0){this.logger.info("No entities to extract topics from");return}this.logger.info(`Batch topic extraction: ${f.length} entities`);let w=await ba(f,A,this.logger);this.logger.info("Batch topic extraction complete",w)}async rebuildAll(A){let f=await this.getEntitiesToExtract(A),w=await this.replaceAllTopics(f,A);this.logger.info("Topic rebuild complete",w)}isAutoExtractionEnabled(){return this.autoExtractionEnabled}hasRunInitialDerivation(){return this.initialDerivationDone}enableAutoExtraction(){if(this.config.enableAutoExtraction)this.autoExtractionEnabled=!0,this.logger.info("Auto-extraction enabled after initial sync")}shouldProcessEntityType(A){if(A==="topic")return!1;return this.config.includeEntityTypes.includes(A)}isEntityPublished(A){let w=A.metadata.status;return w==="published"||w===void 0||w===null}async replaceAllTopics(A,f){let w=new p4(f.entityService,this.logger),Q=await w.listTopics();for(let x of Q)await w.deleteTopic(x.id);if(A.length===0)return{deleted:Q.length,created:0,skipped:0,batches:0};let B=await ba(A,f,this.logger);return{deleted:Q.length,...B}}async getEntitiesToExtract(A){let f=this.getExtractableEntityTypes(A),w=[];for(let Q of f){let B=await A.entityService.listEntities(Q);for(let x of B){if(!this.isEntityPublished(x))continue;w.push(x)}}return w}getExtractableEntityTypes(A){return A.entityService.getEntityTypes().filter((w)=>this.shouldProcessEntityType(w))}async handleEntityChanged(A,f){if(!this.isEntityPublished(f))return;try{await A.jobs.enqueue("extract",{entityId:f.id,entityType:f.entityType,contentHash:f.contentHash,minRelevanceScore:this.config.minRelevanceScore,autoMerge:this.config.autoMerge,mergeSimilarityThreshold:this.config.mergeSimilarityThreshold},null,{priority:5,source:"topics-plugin",metadata:{operationType:"data_processing",operationTarget:`topic-extraction:${f.entityType}:${f.id}`,pluginId:"topics"}})}catch(w){this.logger.error("Failed to queue topic extraction job",{error:h0(w),entityId:f.id,entityType:f.entityType})}}registerEvalHandler(A){let f=new rM(A,this.logger),w=X.object({entityType:X.string(),content:X.string(),metadata:X.record(X.unknown()).optional()}),Q=(k,h="")=>({id:`eval${h}-${Date.now()}`,entityType:k.entityType,content:k.content,contentHash:IQ(k.content),metadata:k.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}),B=async(k,h,G="")=>{let E=Q(k,G);return f.extractFromEntity(E,h)},x=w.extend({minRelevanceScore:X.number().optional()});A.eval.registerHandler("extractFromEntity",async(k)=>{let h=x.parse(k),G=h.minRelevanceScore??this.config.minRelevanceScore;return B(h,G)});let c=X.object({contentA:w,contentB:w,minRelevanceScore:X.number().optional()});A.eval.registerHandler("checkMergeSimilarity",async(k)=>{let h=c.parse(k),G=h.minRelevanceScore??this.config.minRelevanceScore,[E,V]=await Promise.all([B(h.contentA,G,"-a"),B(h.contentB,G,"-b")]),q=E.map((g)=>g.title.toLowerCase()),y=V.map((g)=>g.title.toLowerCase()),r=q.filter((g)=>y.includes(g));return{topicsA:E.map((g)=>({title:g.title,relevanceScore:g.relevanceScore})),topicsB:V.map((g)=>({title:g.title,relevanceScore:g.relevanceScore})),matchingTitles:r,wouldMerge:r.length>0}});let I=X.object({title:X.string(),content:X.string(),keywords:X.array(X.string())}),$=X.object({existingTopics:X.array(I),incomingTopic:I,threshold:X.number().optional()});A.eval.registerHandler("detectMergeCandidate",async(k)=>{let h=$.parse(k),G=h.threshold??this.config.mergeSimilarityThreshold,E=new p4(A.entityService,this.logger);for(let q of h.existingTopics)await E.createTopic(q);let V=await E.findMergeCandidate({title:h.incomingTopic.title,keywords:h.incomingTopic.keywords},G);return{found:V!==null,candidateTitle:V?.title,candidateScore:V?.score}});let u=X.object({existingAliases:X.array(X.string()).optional(),canonicalTitle:X.string(),candidateAliases:X.array(X.string())});A.eval.registerHandler("mergeAliases",async(k)=>{let h=u.parse(k);return{aliases:new p4(A.entityService,this.logger).mergeAliases(h.existingAliases,h.canonicalTitle,h.candidateAliases)}});let Y=X.object({existingTopics:X.array(I.extend({aliases:X.array(X.string()).optional()})).default([]),incomingTopic:I.extend({relevanceScore:X.number().min(0).max(1).optional()}),threshold:X.number().optional()});A.eval.registerHandler("processTopicWithAutoMerge",async(k)=>{let h=Y.parse(k),G=new p4(A.entityService,this.logger);for(let r of h.existingTopics)await G.createTopic({title:r.title,content:r.content,keywords:r.keywords,metadata:{aliases:r.aliases??[]}});let E=new za(A,this.logger),V=bx.from(async()=>{});if(!V)throw Error("Failed to create progress reporter");let q=await E.process({topic:{title:h.incomingTopic.title,content:h.incomingTopic.content,keywords:h.incomingTopic.keywords,relevanceScore:h.incomingTopic.relevanceScore??0.9},sourceEntityId:"eval-source",sourceEntityType:"post",autoMerge:!0,mergeSimilarityThreshold:h.threshold??this.config.mergeSimilarityThreshold},`eval-job-${Date.now()}`,V),y=await A.entityService.listEntities("topic");return{...q,topicCount:y.length,topics:y.map((r)=>{let g=this.adapter.parseTopicBody(r.content);return{id:r.id,title:g.title,content:g.content,keywords:g.keywords,metadata:r.metadata}})}});let F=X.object({entities:X.array(w).min(1),minRelevanceScore:X.number().optional()}),K=X.object({existingTopics:X.array(I).optional(),entities:X.array(w)});A.eval.registerHandler("rebuildTopics",async(k)=>{let h=K.parse(k),G=new p4(A.entityService,this.logger);for(let y of h.existingTopics??[])await G.createTopic(y);let E=h.entities.map((y,r)=>Q(y,`-rebuild-${r}`)),V=await this.replaceAllTopics(E,A),q=await A.entityService.listEntities("topic");return{...V,topicCount:q.length,topics:q.map((y)=>{let r=this.adapter.parseTopicBody(y.content);return{id:y.id,title:r.title,content:r.content,keywords:r.keywords,metadata:y.metadata}})}}),A.eval.registerHandler("extractSequentially",async(k)=>{let h=F.parse(k),G=h.minRelevanceScore??this.config.minRelevanceScore,E=new p4(A.entityService,this.logger),V=[];for(let[y,r]of h.entities.entries()){let g=Q(r,`-sequential-${y}`),M=await f.extractFromEntity(g,G);for(let j of M)await E.createTopic({title:j.title,content:j.content,keywords:j.keywords});V.push({extractedTitles:M.map((j)=>j.title)})}let q=await A.entityService.listEntities("topic");return{totalTopics:q.length,perEntity:V,topics:q.map((y)=>{let r=this.adapter.parseTopicBody(y.content);return{id:y.id,title:r.title,content:r.content,keywords:r.keywords}})}});let Z=X.object({entities:X.array(w)});A.eval.registerHandler("batchExtract",async(k)=>{let G=Z.parse(k).entities.map((q,y)=>Q(q,`-batch-${y}`)),E=await ba(G,A,this.logger),V=await A.entityService.listEntities("topic");return{...E,topics:V.map((q)=>{let y=this.adapter.parseTopicBody(q.content);return{id:q.id,title:y.title,content:y.content,keywords:y.keywords}})}})}}function Ea(A){return new vo0(A)}B0();YA();B0();var Wo0=X.enum(["linkedin"]),ko0=X.enum(["draft","queued","published","failed"]),ho0=X.enum(["post","deck"]),r4=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:Wo0.describe("Target platform"),status:ko0,coverImageId:X.string().optional().describe("Image entity ID for post image"),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:ho0.optional().describe("Source entity type (post, deck)")}),Go0=r4.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}")}),db=v2.extend({entityType:X.literal("social-post"),metadata:Go0}),La=db.extend({frontmatter:r4,body:X.string()}),qa=La.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()});B0();YA();class JWA extends _2{constructor(){super({entityType:"social-post",schema:db,frontmatterSchema:r4,supportsCoverImage:!0})}toMarkdown(A){let f="",w={};try{w=this.parseFrontMatter(A.content,r4),f=this.extractBody(A.content)}catch{f=A.content}let Q={...w,title:A.metadata.title,platform:A.metadata.platform,status:A.metadata.status,...A.metadata.publishedAt!==void 0&&{publishedAt:A.metadata.publishedAt},...A.metadata.platformPostId!==void 0&&{platformPostId:A.metadata.platformPostId}};return this.buildMarkdown(f,Q)}fromMarkdown(A){let f=this.parseFrontMatter(A,r4),w=`${f.platform}-${x2(f.title)}`;return{content:A,entityType:"social-post",metadata:{title:f.title,slug:w,platform:f.platform,status:f.status,publishedAt:f.publishedAt,platformPostId:f.platformPostId}}}parsePostFrontmatter(A){return this.parseFrontMatter(A.content,r4)}getPostContent(A){return this.extractBody(A.content)}createPostContent(A,f){return this.buildMarkdown(f,A)}}var Vc=new JWA;B0();B0();YA();var sy2=bH.extend({platform:X.enum(["linkedin"]).optional(),status:X.enum(["draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),ty2=zH.extend({query:sy2.optional()});function Jo0(A){let f=K2(A.content,r4);return La.parse({...A,frontmatter:f.metadata,body:f.content})}class _a extends U6{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(A){super(A);this.logger.debug("SocialPostDataSource initialized")}parseQuery(A){let f=ty2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){return Jo0(A)}buildDetailResult(A,f){return{post:A}}buildListResult(A,f,w){return{posts:A,totalCount:f?.totalItems??A.length,pagination:f,baseUrl:w.baseUrl}}async fetch(A,f,w){let{query:Q}=this.parseQuery(A),B=w.entityService;if(Q.nextInQueue)return this.fetchNextInQueue(f,B);if(Q.id){let{item:Y}=await this.fetchDetail(Q.id,B);return f.parse(this.buildDetailResult(Y,null))}let x={};if(Q.platform)x.platform=Q.platform;if(Q.status)x.status=Q.status;let c=Object.keys(x).length>0,I=Q.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:$,pagination:u}=await this.fetchList(Q,B,{...c&&{filter:{metadata:x}},sortFields:I});return f.parse(this.buildListResult($,u,Q))}async fetchNextInQueue(A,f){let Q=(await f.listEntities(this.config.entityType,{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}))[0],B=Q?Jo0(Q):null;return A.parse({post:B})}}YA();var bo0=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional()}),bWA=X.object({linkedin:bo0.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)});B0();YA();NWA();import{jsxDEV as e8,Fragment as fS2}from"preact/jsx-dev-runtime";function ey2(A,f){if(A.length<=f)return A;return A.slice(0,f).trim()+"..."}function AS2(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var ia=({posts:A,pageTitle:f,pagination:w,baseUrl:Q="/social-posts"})=>{let B=f??"Social Posts",x=w?.totalItems??A.length,c=`Browse all ${x} social ${x===1?"post":"posts"}`;return e8(fS2,{children:[e8(o2,{title:B,description:c},void 0,!1,void 0,this),e8("div",{className:"social-post-list bg-theme",children:e8("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[e8("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:B},void 0,!1,void 0,this),A.length===0?e8("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):e8("ul",{className:"space-y-6",children:A.map((I)=>e8("li",{children:e8(Gf,{href:I.url,variant:"horizontal",children:e8("div",{className:"flex flex-col sm:flex-row gap-4",children:[I.coverImageUrl&&e8("img",{src:I.coverImageUrl,alt:I.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),e8("div",{className:"flex-1 min-w-0",children:[e8("div",{className:"flex items-start justify-between gap-4 mb-2",children:[e8("h2",{className:"text-lg font-semibold text-heading",children:I.frontmatter.title},void 0,!1,void 0,this),e8("time",{className:"text-sm text-theme-muted shrink-0",children:AS2(I.frontmatter.publishedAt??I.created)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),e8("div",{className:"flex items-center gap-2 mb-3",children:[e8(Ec,{status:I.frontmatter.status},void 0,!1,void 0,this),e8("span",{className:"text-xs text-theme-muted uppercase",children:I.frontmatter.platform},void 0,!1,void 0,this),e8("span",{className:"text-xs text-theme-muted font-mono",children:I.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),e8("p",{className:"text-theme leading-relaxed",children:ey2(I.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)},I.id,!1,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&e8(WI,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:Q},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 AB,Fragment as wS2}from"preact/jsx-dev-runtime";function zo0(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var Ma=({post:A})=>{let f=`Social Post - ${A.frontmatter.platform}`,w=A.body.slice(0,160),Q=[{label:"Home",href:"/"},{label:A.listLabel??"Social Posts",href:A.listUrl??"/social-posts"},{label:A.frontmatter.platform}];return AB(wS2,{children:[AB(o2,{title:f,description:w},void 0,!1,void 0,this),AB("section",{className:"social-post-detail",children:AB("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:AB("div",{className:"max-w-3xl mx-auto",children:[AB(n4,{items:Q},void 0,!1,void 0,this),AB("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:A.frontmatter.title},void 0,!1,void 0,this),AB("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[AB(Ec,{status:A.frontmatter.status},void 0,!1,void 0,this),AB("span",{className:"text-sm text-theme-muted uppercase",children:A.frontmatter.platform},void 0,!1,void 0,this),AB("span",{className:"text-sm text-theme-muted font-mono",children:A.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.coverImageUrl&&A.coverImageWidth&&A.coverImageHeight&&AB(i3,{src:A.coverImageUrl,alt:A.frontmatter.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),AB(Gf,{className:"p-8 mb-8",children:AB("p",{className:"text-lg text-theme leading-relaxed whitespace-pre-wrap",children:A.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),AB("div",{className:"space-y-4 text-sm text-theme-muted",children:[AB("div",{children:[AB("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",zo0(A.created)]},void 0,!0,void 0,this),A.frontmatter.publishedAt&&AB("div",{children:[AB("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",zo0(A.frontmatter.publishedAt)]},void 0,!0,void 0,this),A.frontmatter.platformPostId&&AB("div",{children:AB("a",{href:`https://www.linkedin.com/feed/update/${A.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 aM(A){return`social-media:${A}`}var CWA=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")}),QS2=xc.extend({slug:X.string().optional()});class _v extends Cx{constructor(A,f){super(A,f,{schema:CWA,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(A,f){let w=A.platform??"linkedin",Q=A.addToQueue??!1,{prompt:B,sourceEntityType:x,sourceEntityId:c}=A,{content:I,title:$}=A;if(I&&$)await this.reportProgress(f,{progress:50,message:"Using provided content"});else if(I&&!$){await this.reportProgress(f,{progress:10,message:"Shaping content with AI"});let G=await this.context.ai.generate({prompt:I,templateName:aM(w)});$=G.title,I=G.content,await this.reportProgress(f,{progress:50,message:"Social post shaped from content"})}else if(c&&x){await this.reportProgress(f,{progress:10,message:`Fetching source ${x}`});let G=await this.context.entityService.getEntity(x,c);if(!G)this.failEarly(`Source entity not found: ${x}/${c}`);await this.reportProgress(f,{progress:30,message:"Generating social post from source content"});let V=X.object({slug:X.string()}).safeParse(G.metadata),q=V.success?V.data.slug:c,y=await this.context.ai.generate({prompt:`Create an engaging ${w} post to promote this ${x}:
3013
+ - keywords`,requiredPermission:"public"});P2();YA();var dy2=X.object({id:X.string(),title:X.string(),summary:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()}),dM=X.object({topics:X.array(dy2),totalCount:X.number()});import{jsxDEV as jI}from"preact/jsx-dev-runtime";var kWA=({topics:A,totalCount:f})=>{return jI("div",{className:"topic-list-container w-full max-w-4xl mx-auto p-6 bg-theme",children:[jI(ZI,{title:"Topics",count:f,singularLabel:"topic",description:"discovered from your knowledge base"},void 0,!1,void 0,this),jI("div",{className:"space-y-6",children:A.map((w)=>jI(Gf,{variant:"vertical",children:[jI(Rx,{href:`/topics/${w.id}`,className:"text-xl",children:w.title},void 0,!1,void 0,this),jI("p",{className:"text-theme-muted mb-4",children:w.summary},void 0,!1,void 0,this),jI(nx,{tags:w.keywords,maxVisible:5,variant:"muted",className:"mb-3"},void 0,!1,void 0,this),jI(O9,{children:jI("div",{className:"flex justify-between text-sm text-theme-muted",children:jI("time",{dateTime:w.updated,children:["Updated ",sQ(w.updated)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},w.id,!0,void 0,this))},void 0,!1,void 0,this),A.length===0&&jI(_5,{message:"No topics discovered yet.",description:"Topics will appear here as they are extracted from your content."},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();class Na extends R1{constructor(){super(dM,{title:"Topic List",mappings:[{key:"topics",label:"Topics",type:"array",itemType:"object"},{key:"totalCount",label:"Total Count",type:"number"}]})}}var Fo0=i0({name:"topics:topic-list",description:"List view of all discovered topics",schema:dM,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new Na,layout:{component:kWA}});P2();YA();var oM=X.object({id:X.string(),title:X.string(),content:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()});import{jsxDEV as FF}from"preact/jsx-dev-runtime";var hWA=({title:A,content:f,keywords:w,created:Q,updated:B})=>{return FF("article",{className:"topic-detail-container max-w-4xl mx-auto p-6 bg-theme",children:[FF(tZ,{title:A,created:Q,updated:B},void 0,!1,void 0,this),FF("div",{className:"prose prose-lg max-w-none mb-8 text-theme-muted",children:FF("div",{dangerouslySetInnerHTML:{__html:f}},void 0,!1,void 0,this)},void 0,!1,void 0,this),w.length>0&&FF("section",{className:"mb-8",children:[FF("h2",{className:"text-xl font-semibold mb-3 text-theme",children:"Keywords"},void 0,!1,void 0,this),FF(nx,{tags:w,maxVisible:w.length,size:"sm"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),FF(aZ,{href:"/topics",children:"Back to Topics"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();class Ca extends R1{constructor(){super(oM,{title:"Topic Detail",mappings:[{key:"id",label:"ID",type:"string"},{key:"title",label:"Title",type:"string"},{key:"content",label:"Content",type:"string"},{key:"keywords",label:"Keywords",type:"array",itemType:"string"},{key:"created",label:"Created",type:"string"},{key:"updated",label:"Updated",type:"string"}]})}}var Ko0=i0({name:"topics:topic-detail",description:"Detailed view of a single topic",schema:oM,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new Ca,layout:{component:hWA}});B0();YA();class GWA extends U6{id="topics:entities";name="Topics Entity DataSource";description="Fetches and transforms topic entities for rendering";config={entityType:"topic",defaultSort:[{field:"updated",direction:"desc"}],defaultLimit:100,lookupField:"id"};adapter=new P5;constructor(A){super(A);this.logger.debug("TopicsDataSource initialized")}transformEntity(A){let f=this.adapter.parseTopicBody(A.content);return{id:A.id,title:f.title,summary:XH(f.content,200),keywords:f.keywords,created:A.created,updated:A.updated}}buildListResult(A,f,w){return{topics:A,totalCount:A.length}}async fetch(A,f,w){let{query:Q}=this.parseQuery(A);if(Q.id){let x=await w.entityService.getEntity(this.config.entityType,Q.id);if(!x)throw Error(`Entity not found: ${Q.id}`);let c=this.adapter.parseTopicBody(x.content);return f.parse({id:x.id,title:c.title,content:c.content,keywords:c.keywords,created:x.created,updated:x.updated})}return super.fetch(A,f,w)}}R7();function Xo0(){let A=new P5;return async(f)=>{if(!f.hasEntityType("topic"))return{topics:[]};return{topics:(await f.listEntities("topic")).map((B)=>{let x=A.parseTopicBody(B.content);return{topic:B.id,title:x.title,keywords:x.keywords}})}}}var Zo0={name:"@brains/topics",private:!0,version:"0.2.0-alpha.9",description:"Extract and manage topics from conversations",type:"module",main:"./src/index.ts",types:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"}};var ay2=new P5;class vo0 extends Nf{entityType="topic";schema=Wa;adapter=ay2;autoExtractionEnabled=!1;initialDerivationDone=!1;constructor(A={}){super("topics",Zo0,A,ed0)}getEntityTypeConfig(){return{weight:0.5}}getTemplates(){return{extraction:Ho0,"merge-synthesis":Uo0,"topic-list":Fo0,"topic-detail":Ko0}}getDataSources(){return[new GWA(this.logger.child("TopicsDataSource"))]}async onRegister(A){let f=new za(A,this.logger);A.jobs.registerHandler("process-single",f);let w=new WWA(A,this.logger);if(A.jobs.registerHandler("extract",w),A.insights.register("topic-distribution",Xo0()),this.registerEvalHandler(A),this.config.enableAutoExtraction){A.messaging.subscribe("sync:initial:completed",async()=>{if(this.enableAutoExtraction(),!this.initialDerivationDone)this.initialDerivationDone=!0,await this.deriveAll(A);return{success:!0}});let Q=async(B)=>{if(!this.autoExtractionEnabled)return{success:!0};let{entityType:x,entity:c}=B.payload;if(!this.shouldProcessEntityType(x))return{success:!0};if(!c)return{success:!0};return await this.handleEntityChanged(A,c),{success:!0}};A.messaging.subscribe("entity:created",Q),A.messaging.subscribe("entity:updated",Q)}}async derive(A,f,w){if(!this.shouldProcessEntityType(A.entityType))return;if(!this.isEntityPublished(A))return;await this.handleEntityChanged(w,A)}async deriveAll(A){let f=await this.getEntitiesToExtract(A);if(f.length===0){this.logger.info("No entities to extract topics from");return}this.logger.info(`Batch topic extraction: ${f.length} entities`);let w=await ba(f,A,this.logger);this.logger.info("Batch topic extraction complete",w)}async rebuildAll(A){let f=await this.getEntitiesToExtract(A),w=await this.replaceAllTopics(f,A);this.logger.info("Topic rebuild complete",w)}isAutoExtractionEnabled(){return this.autoExtractionEnabled}hasRunInitialDerivation(){return this.initialDerivationDone}enableAutoExtraction(){if(this.config.enableAutoExtraction)this.autoExtractionEnabled=!0,this.logger.info("Auto-extraction enabled after initial sync")}shouldProcessEntityType(A){if(A==="topic")return!1;return this.config.includeEntityTypes.includes(A)}isEntityPublished(A){let w=A.metadata.status;return w==="published"||w===void 0||w===null}async replaceAllTopics(A,f){let w=new p4(f.entityService,this.logger),Q=await w.listTopics();for(let x of Q)await w.deleteTopic(x.id);if(A.length===0)return{deleted:Q.length,created:0,skipped:0,batches:0};let B=await ba(A,f,this.logger);return{deleted:Q.length,...B}}async getEntitiesToExtract(A){let f=this.getExtractableEntityTypes(A),w=[];for(let Q of f){let B=await A.entityService.listEntities(Q);for(let x of B){if(!this.isEntityPublished(x))continue;w.push(x)}}return w}getExtractableEntityTypes(A){return A.entityService.getEntityTypes().filter((w)=>this.shouldProcessEntityType(w))}async handleEntityChanged(A,f){if(!this.isEntityPublished(f))return;try{await A.jobs.enqueue("extract",{entityId:f.id,entityType:f.entityType,contentHash:f.contentHash,minRelevanceScore:this.config.minRelevanceScore,autoMerge:this.config.autoMerge,mergeSimilarityThreshold:this.config.mergeSimilarityThreshold},null,{priority:5,source:"topics-plugin",metadata:{operationType:"data_processing",operationTarget:`topic-extraction:${f.entityType}:${f.id}`,pluginId:"topics"}})}catch(w){this.logger.error("Failed to queue topic extraction job",{error:h0(w),entityId:f.id,entityType:f.entityType})}}registerEvalHandler(A){let f=new rM(A,this.logger),w=X.object({entityType:X.string(),content:X.string(),metadata:X.record(X.unknown()).optional()}),Q=(k,h="")=>({id:`eval${h}-${Date.now()}`,entityType:k.entityType,content:k.content,contentHash:IQ(k.content),metadata:k.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}),B=async(k,h,G="")=>{let E=Q(k,G);return f.extractFromEntity(E,h)},x=w.extend({minRelevanceScore:X.number().optional()});A.eval.registerHandler("extractFromEntity",async(k)=>{let h=x.parse(k),G=h.minRelevanceScore??this.config.minRelevanceScore;return B(h,G)});let c=X.object({contentA:w,contentB:w,minRelevanceScore:X.number().optional()});A.eval.registerHandler("checkMergeSimilarity",async(k)=>{let h=c.parse(k),G=h.minRelevanceScore??this.config.minRelevanceScore,[E,V]=await Promise.all([B(h.contentA,G,"-a"),B(h.contentB,G,"-b")]),q=E.map((g)=>g.title.toLowerCase()),y=V.map((g)=>g.title.toLowerCase()),r=q.filter((g)=>y.includes(g));return{topicsA:E.map((g)=>({title:g.title,relevanceScore:g.relevanceScore})),topicsB:V.map((g)=>({title:g.title,relevanceScore:g.relevanceScore})),matchingTitles:r,wouldMerge:r.length>0}});let I=X.object({title:X.string(),content:X.string(),keywords:X.array(X.string())}),$=X.object({existingTopics:X.array(I),incomingTopic:I,threshold:X.number().optional()});A.eval.registerHandler("detectMergeCandidate",async(k)=>{let h=$.parse(k),G=h.threshold??this.config.mergeSimilarityThreshold,E=new p4(A.entityService,this.logger);for(let q of h.existingTopics)await E.createTopic(q);let V=await E.findMergeCandidate({title:h.incomingTopic.title,keywords:h.incomingTopic.keywords},G);return{found:V!==null,candidateTitle:V?.title,candidateScore:V?.score}});let u=X.object({existingAliases:X.array(X.string()).optional(),canonicalTitle:X.string(),candidateAliases:X.array(X.string())});A.eval.registerHandler("mergeAliases",async(k)=>{let h=u.parse(k);return{aliases:new p4(A.entityService,this.logger).mergeAliases(h.existingAliases,h.canonicalTitle,h.candidateAliases)}});let Y=X.object({existingTopics:X.array(I.extend({aliases:X.array(X.string()).optional()})).default([]),incomingTopic:I.extend({relevanceScore:X.number().min(0).max(1).optional()}),threshold:X.number().optional()});A.eval.registerHandler("processTopicWithAutoMerge",async(k)=>{let h=Y.parse(k),G=new p4(A.entityService,this.logger);for(let r of h.existingTopics)await G.createTopic({title:r.title,content:r.content,keywords:r.keywords,metadata:{aliases:r.aliases??[]}});let E=new za(A,this.logger),V=bx.from(async()=>{});if(!V)throw Error("Failed to create progress reporter");let q=await E.process({topic:{title:h.incomingTopic.title,content:h.incomingTopic.content,keywords:h.incomingTopic.keywords,relevanceScore:h.incomingTopic.relevanceScore??0.9},sourceEntityId:"eval-source",sourceEntityType:"post",autoMerge:!0,mergeSimilarityThreshold:h.threshold??this.config.mergeSimilarityThreshold},`eval-job-${Date.now()}`,V),y=await A.entityService.listEntities("topic");return{...q,topicCount:y.length,topics:y.map((r)=>{let g=this.adapter.parseTopicBody(r.content);return{id:r.id,title:g.title,content:g.content,keywords:g.keywords,metadata:r.metadata}})}});let F=X.object({entities:X.array(w).min(1),minRelevanceScore:X.number().optional()}),K=X.object({existingTopics:X.array(I).optional(),entities:X.array(w)});A.eval.registerHandler("rebuildTopics",async(k)=>{let h=K.parse(k),G=new p4(A.entityService,this.logger);for(let y of h.existingTopics??[])await G.createTopic(y);let E=h.entities.map((y,r)=>Q(y,`-rebuild-${r}`)),V=await this.replaceAllTopics(E,A),q=await A.entityService.listEntities("topic");return{...V,topicCount:q.length,topics:q.map((y)=>{let r=this.adapter.parseTopicBody(y.content);return{id:y.id,title:r.title,content:r.content,keywords:r.keywords,metadata:y.metadata}})}}),A.eval.registerHandler("extractSequentially",async(k)=>{let h=F.parse(k),G=h.minRelevanceScore??this.config.minRelevanceScore,E=new p4(A.entityService,this.logger),V=[];for(let[y,r]of h.entities.entries()){let g=Q(r,`-sequential-${y}`),M=await f.extractFromEntity(g,G);for(let j of M)await E.createTopic({title:j.title,content:j.content,keywords:j.keywords});V.push({extractedTitles:M.map((j)=>j.title)})}let q=await A.entityService.listEntities("topic");return{totalTopics:q.length,perEntity:V,topics:q.map((y)=>{let r=this.adapter.parseTopicBody(y.content);return{id:y.id,title:r.title,content:r.content,keywords:r.keywords}})}});let Z=X.object({entities:X.array(w)});A.eval.registerHandler("batchExtract",async(k)=>{let G=Z.parse(k).entities.map((q,y)=>Q(q,`-batch-${y}`)),E=await ba(G,A,this.logger),V=await A.entityService.listEntities("topic");return{...E,topics:V.map((q)=>{let y=this.adapter.parseTopicBody(q.content);return{id:q.id,title:y.title,content:y.content,keywords:y.keywords}})}})}}function Ea(A){return new vo0(A)}B0();YA();B0();var Wo0=X.enum(["linkedin"]),ko0=X.enum(["draft","queued","published","failed"]),ho0=X.enum(["post","deck"]),r4=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:Wo0.describe("Target platform"),status:ko0,coverImageId:X.string().optional().describe("Image entity ID for post image"),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:ho0.optional().describe("Source entity type (post, deck)")}),Go0=r4.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}")}),db=v2.extend({entityType:X.literal("social-post"),metadata:Go0}),La=db.extend({frontmatter:r4,body:X.string()}),qa=La.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()});B0();YA();class JWA extends _2{constructor(){super({entityType:"social-post",schema:db,frontmatterSchema:r4,supportsCoverImage:!0})}toMarkdown(A){let f="",w={};try{w=this.parseFrontMatter(A.content,r4),f=this.extractBody(A.content)}catch{f=A.content}let Q={...w,title:A.metadata.title,platform:A.metadata.platform,status:A.metadata.status,...A.metadata.publishedAt!==void 0&&{publishedAt:A.metadata.publishedAt},...A.metadata.platformPostId!==void 0&&{platformPostId:A.metadata.platformPostId}};return this.buildMarkdown(f,Q)}fromMarkdown(A){let f=this.parseFrontMatter(A,r4),w=`${f.platform}-${x2(f.title)}`;return{content:A,entityType:"social-post",metadata:{title:f.title,slug:w,platform:f.platform,status:f.status,publishedAt:f.publishedAt,platformPostId:f.platformPostId}}}parsePostFrontmatter(A){return this.parseFrontMatter(A.content,r4)}getPostContent(A){return this.extractBody(A.content)}createPostContent(A,f){return this.buildMarkdown(f,A)}}var Vc=new JWA;B0();B0();YA();var sy2=bH.extend({platform:X.enum(["linkedin"]).optional(),status:X.enum(["draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),ty2=zH.extend({query:sy2.optional()});function Jo0(A){let f=K2(A.content,r4);return La.parse({...A,frontmatter:f.metadata,body:f.content})}class _a extends U6{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(A){super(A);this.logger.debug("SocialPostDataSource initialized")}parseQuery(A){let f=ty2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){return Jo0(A)}buildDetailResult(A,f){return{post:A}}buildListResult(A,f,w){return{posts:A,totalCount:f?.totalItems??A.length,pagination:f,baseUrl:w.baseUrl}}async fetch(A,f,w){let{query:Q}=this.parseQuery(A),B=w.entityService;if(Q.nextInQueue)return this.fetchNextInQueue(f,B);if(Q.id){let{item:Y}=await this.fetchDetail(Q.id,B);return f.parse(this.buildDetailResult(Y,null))}let x={};if(Q.platform)x.platform=Q.platform;if(Q.status)x.status=Q.status;let c=Object.keys(x).length>0,I=Q.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:$,pagination:u}=await this.fetchList(Q,B,{...c&&{filter:{metadata:x}},sortFields:I});return f.parse(this.buildListResult($,u,Q))}async fetchNextInQueue(A,f){let Q=(await f.listEntities(this.config.entityType,{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}))[0],B=Q?Jo0(Q):null;return A.parse({post:B})}}YA();var bo0=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional()}),bWA=X.object({linkedin:bo0.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)});B0();YA();NWA();import{jsxDEV as e8,Fragment as fS2}from"preact/jsx-dev-runtime";function ey2(A,f){if(A.length<=f)return A;return A.slice(0,f).trim()+"..."}function AS2(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var ia=({posts:A,pageTitle:f,pagination:w,baseUrl:Q="/social-posts"})=>{let B=f??"Social Posts",x=w?.totalItems??A.length,c=`Browse all ${x} social ${x===1?"post":"posts"}`;return e8(fS2,{children:[e8(o2,{title:B,description:c},void 0,!1,void 0,this),e8("div",{className:"social-post-list bg-theme",children:e8("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[e8("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:B},void 0,!1,void 0,this),A.length===0?e8("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):e8("ul",{className:"space-y-6",children:A.map((I)=>e8("li",{children:e8(Gf,{href:I.url,variant:"horizontal",children:e8("div",{className:"flex flex-col sm:flex-row gap-4",children:[I.coverImageUrl&&e8("img",{src:I.coverImageUrl,alt:I.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),e8("div",{className:"flex-1 min-w-0",children:[e8("div",{className:"flex items-start justify-between gap-4 mb-2",children:[e8("h2",{className:"text-lg font-semibold text-heading",children:I.frontmatter.title},void 0,!1,void 0,this),e8("time",{className:"text-sm text-theme-muted shrink-0",children:AS2(I.frontmatter.publishedAt??I.created)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),e8("div",{className:"flex items-center gap-2 mb-3",children:[e8(Ec,{status:I.frontmatter.status},void 0,!1,void 0,this),e8("span",{className:"text-xs text-theme-muted uppercase",children:I.frontmatter.platform},void 0,!1,void 0,this),e8("span",{className:"text-xs text-theme-muted font-mono",children:I.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),e8("p",{className:"text-theme leading-relaxed",children:ey2(I.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)},I.id,!1,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&e8(WI,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:Q},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 AB,Fragment as wS2}from"preact/jsx-dev-runtime";function zo0(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var Ma=({post:A})=>{let f=`Social Post - ${A.frontmatter.platform}`,w=A.body.slice(0,160),Q=[{label:"Home",href:"/"},{label:A.listLabel??"Social Posts",href:A.listUrl??"/social-posts"},{label:A.frontmatter.platform}];return AB(wS2,{children:[AB(o2,{title:f,description:w},void 0,!1,void 0,this),AB("section",{className:"social-post-detail",children:AB("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:AB("div",{className:"max-w-3xl mx-auto",children:[AB(n4,{items:Q},void 0,!1,void 0,this),AB("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:A.frontmatter.title},void 0,!1,void 0,this),AB("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[AB(Ec,{status:A.frontmatter.status},void 0,!1,void 0,this),AB("span",{className:"text-sm text-theme-muted uppercase",children:A.frontmatter.platform},void 0,!1,void 0,this),AB("span",{className:"text-sm text-theme-muted font-mono",children:A.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.coverImageUrl&&A.coverImageWidth&&A.coverImageHeight&&AB(i3,{src:A.coverImageUrl,alt:A.frontmatter.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),AB(Gf,{className:"p-8 mb-8",children:AB("p",{className:"text-lg text-theme leading-relaxed whitespace-pre-wrap",children:A.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),AB("div",{className:"space-y-4 text-sm text-theme-muted",children:[AB("div",{children:[AB("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",zo0(A.created)]},void 0,!0,void 0,this),A.frontmatter.publishedAt&&AB("div",{children:[AB("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",zo0(A.frontmatter.publishedAt)]},void 0,!0,void 0,this),A.frontmatter.platformPostId&&AB("div",{children:AB("a",{href:`https://www.linkedin.com/feed/update/${A.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 aM(A){return`social-media:${A}`}var CWA=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")}),QS2=xc.extend({slug:X.string().optional()});class _v extends Cx{constructor(A,f){super(A,f,{schema:CWA,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(A,f){let w=A.platform??"linkedin",Q=A.addToQueue??!1,{prompt:B,sourceEntityType:x,sourceEntityId:c}=A,{content:I,title:$}=A;if(I&&$)await this.reportProgress(f,{progress:50,message:"Using provided content"});else if(I&&!$){await this.reportProgress(f,{progress:10,message:"Shaping content with AI"});let G=await this.context.ai.generate({prompt:I,templateName:aM(w)});$=G.title,I=G.content,await this.reportProgress(f,{progress:50,message:"Social post shaped from content"})}else if(c&&x){await this.reportProgress(f,{progress:10,message:`Fetching source ${x}`});let G=await this.context.entityService.getEntity(x,c);if(!G)this.failEarly(`Source entity not found: ${x}/${c}`);await this.reportProgress(f,{progress:30,message:"Generating social post from source content"});let V=X.object({slug:X.string()}).safeParse(G.metadata),q=V.success?V.data.slug:c,y=await this.context.ai.generate({prompt:`Create an engaging ${w} post to promote this ${x}:
3014
3014
 
3015
3015
  Source: ${x}/${q}
3016
3016
 
3017
3017
  ${G.content}`,templateName:aM(w)});$=y.title,I=y.content,await this.reportProgress(f,{progress:50,message:"Social post generated from source"})}else if(B){await this.reportProgress(f,{progress:10,message:"Generating social post with AI"});let G=await this.context.ai.generate({prompt:B,templateName:aM(w)});$=G.title,I=G.content,await this.reportProgress(f,{progress:50,message:"Social post generated"})}else this.failEarly("No content source provided (prompt, sourceEntityId, or content)");if(!I||!$)this.failEarly("Content or title was not generated");let Y={title:$,platform:w,status:Q?"queued":"draft",...c&&{sourceEntityId:c},...x&&{sourceEntityType:x}},F=Vc.createPostContent(Y,I),Z=Vc.fromMarkdown(F).metadata;if(!Z)this.failEarly("Failed to parse social post metadata");let k=await yD({entityType:"social-post",title:$,deriveId:(G)=>`${w}-${x2(G)}`,regeneratePrompt:"Generate a different social media post title on the same topic.",context:this.context}),h=F;if(k!==$){Z.title=k,Z.slug=`${w}-${x2(k)}`;let G={...Y,title:k};h=Vc.createPostContent(G,I)}return{id:Z.slug,content:h,metadata:Z,title:k,resultExtras:{slug:Z.slug},createOptions:{deduplicateId:!0}}}async onGenerationFailure(A,f){await this.context.messaging.send("generate:report:failure",{entityType:"social-post",error:f})}async afterCreate(A,f,w,Q){if(A.generateImage){await this.reportProgress(w,{progress:90,message:"Queueing image generation"});let B=Q.title??"Social Post";await this.context.jobs.enqueue("image:image-generate",{prompt:`Social media graphic for: ${B}`,title:`${B} Image`,aspectRatio:"16:9",targetEntityType:"social-post",targetEntityId:f},{interfaceType:"job",userId:"system"})}await this.context.messaging.send("generate:report:success",{entityType:"social-post",entityId:f})}summarizeDataForLog(A){return{platform:A.platform??"linkedin",hasPrompt:!!A.prompt,sourceEntityType:A.sourceEntityType,addToQueue:A.addToQueue??!1,generateImage:A.generateImage??!1}}}class EWA{config;logger;name="linkedin";apiBaseUrl="https://api.linkedin.com/v2";cachedUserId=null;constructor(A,f){this.config=A;this.logger=f}async publish(A,f,w){if(!this.config.accessToken)throw Error("LinkedIn access token not configured");let Q=await this.getAuthor(),B=null;if(w)B=await this.uploadImage(Q,w);let x={shareCommentary:{text:A},shareMediaCategory:B?"IMAGE":"NONE",...B&&{media:[{status:"READY",media:B}]}},c=await 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:Q,lifecycleState:"PUBLISHED",specificContent:{"com.linkedin.ugc.ShareContent":x},visibility:{"com.linkedin.ugc.MemberNetworkVisibility":"PUBLIC"}})});if(!c.ok){let u=await c.text();throw this.logger.error("LinkedIn API error",{status:c.status,error:u}),Error(`LinkedIn API error: ${c.status} - ${u}`)}let I=c.headers.get("X-RestLi-Id")??"";this.logger.info("LinkedIn post created",{postId:I,hasImage:!!B});let $={id:I};if(I)$.url=`https://www.linkedin.com/feed/update/${I}`;return $}async uploadImage(A,f){try{let w=await 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:A,serviceRelationships:[{relationshipType:"OWNER",identifier:"urn:li:userGeneratedContent"}]}})});if(!w.ok){let I=await w.text();return this.logger.warn("LinkedIn image upload registration failed",{status:w.status,error:I}),null}let Q=await w.json(),B=Q.value.uploadMechanism["com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest"].uploadUrl,x=Q.value.asset,c=await fetch(B,{method:"PUT",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":f.mimeType},body:new Uint8Array(f.data)});if(!c.ok)return this.logger.warn("LinkedIn image binary upload failed",{status:c.status}),null;return this.logger.info("LinkedIn image uploaded",{assetUrn:x}),x}catch(w){return this.logger.warn("LinkedIn image upload error",{error:w}),null}}async validateCredentials(){if(!this.config.accessToken)return!1;try{if(this.config.organizationId)return(await 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 w=await fetch("https://api.linkedin.com/v2/userinfo",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(w.ok){let Q=await w.json();return this.cachedUserId=`urn:li:person:${Q.sub}`,this.cachedUserId}}catch{}let A=await fetch("https://api.linkedin.com/v2/me",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(!A.ok){let w=await A.text();throw Error(`Failed to get LinkedIn user ID: ${A.status} - ${w}`)}let f=await A.json();return this.cachedUserId=`urn:li:person:${f.id}`,this.cachedUserId}}function LWA(A,f){return new EWA(A,f)}B0();YA();P2();NWA();var BS2=X.object({posts:X.array(qa),totalCount:X.number().optional(),pagination:$c.nullable(),baseUrl:X.string().optional()}),xS2=X.object({post:qa});function No0(){return{linkedin:Va,"social-post-list":i0({name:"social-post-list",description:"Social post list page template",schema:BS2,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:ia}}),"social-post-detail":i0({name:"social-post-detail",description:"Individual social post template",schema:xS2,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:Ma}})}}YA();var cS2=X.object({prompt:X.string().optional(),content:X.string().optional(),platform:X.enum(["linkedin"]).default("linkedin")}),IS2=X.object({prompt:X.string().optional(),content:X.string().optional(),title:X.string().optional(),platform:X.enum(["linkedin"]).optional()});function Co0(A){A.eval.registerHandler("generation",async(f)=>{let w=cS2.parse(f),Q=w.content?`Create an engaging LinkedIn post to share this content:
3018
3018
 
3019
- ${w.content}`:w.prompt??"Write an engaging LinkedIn post";return A.ai.generate({prompt:Q,templateName:`social-media:${w.platform}`})}),A.eval.registerHandler("create",async(f)=>{let w=IS2.parse(f),Q=[],B=bx.from(async(u)=>{let Y={progress:u.progress};if(u.message!==void 0)Y.message=u.message;Q.push(Y)});if(!B)throw Error("Failed to create progress reporter");let c=await new _v(A.logger,A).process(w,`eval-${Date.now()}`,B),I=!1,$;if(c.success&&c.entityId){let u=await A.entityService.getEntity("social-post",c.entityId);I=!!u,$=u?.content.slice(0,300)}return{...c,entityExists:I,entityPreview:$,progressSteps:Q}})}YA();B0();class sM{sendMessage;logger;entityService;providers;constructor(A){this.sendMessage=A.sendMessage,this.logger=A.logger,this.entityService=A.entityService,this.providers=A.providers}async handle(A){let{entityType:f,entityId:w}=A;if(f!=="social-post")return;this.logger.debug("Handling publish:execute",{entityId:w});try{let Q=await this.entityService.getEntity("social-post",w);if(!Q){await this.reportFailure(f,w,`Post not found: ${w}`);return}if(Q.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:w});return}let B=Q.metadata.platform,x=this.providers.get(B);if(!x){await this.reportFailure(f,w,`No provider configured for platform: ${B}`);return}let c=K2(Q.content,r4),I;if(c.metadata.coverImageId)I=await this.fetchImageData(c.metadata.coverImageId);try{let $=await x.publish(c.content,Q.metadata,I),u=new Date().toISOString(),Y=$.id||void 0,F={...c.metadata,status:"published",publishedAt:u,...Y&&{platformPostId:Y}},K=Vc.createPostContent(F,c.content);await this.entityService.updateEntity({...Q,content:K,metadata:{...Q.metadata,status:"published",publishedAt:u,platformPostId:Y}}),await this.reportSuccess(f,w,$.id),this.logger.info(`Post published successfully: ${w}`,{platform:B,platformPostId:Y})}catch($){let u=$ instanceof Error?$.message:String($),Y={...c.metadata,status:"failed"},F=Vc.createPostContent(Y,c.content);await this.entityService.updateEntity({...Q,content:F,metadata:{...Q.metadata,status:"failed"}}),await this.reportFailure(f,w,u),this.logger.error(`Post publish failed: ${w}`,{platform:B,error:u})}}catch(Q){let B=h0(Q);this.logger.error("Unexpected error in publish handler",{entityId:w,error:B}),await this.reportFailure(f,w,B)}}async reportSuccess(A,f,w){await this.sendMessage("publish:report:success",{entityType:A,entityId:f,result:{id:w}})}async reportFailure(A,f,w){await this.sendMessage("publish:report:failure",{entityType:A,entityId:f,error:w})}async fetchImageData(A){try{let f=await this.entityService.getEntity("image",A);if(!f){this.logger.warn("Cover image not found",{imageId:A});return}let Q=f.content.match(/^data:([^;]+);base64,(.+)$/);if(!Q?.[1]||!Q[2]){this.logger.warn("Invalid image data URL format",{imageId:A});return}let B=Q[1],x=Q[2];return{data:Buffer.from(x,"base64"),mimeType:B}}catch(f){this.logger.warn("Failed to fetch cover image",{imageId:A,error:f});return}}}function Eo0(A,f,w){if(f.size===0){w.debug("No providers configured, skipping publish-pipeline registration");return}A.messaging.subscribe("system:plugins:ready",async()=>{let Q=f.values().next().value;return await A.messaging.send("publish:register",{entityType:"social-post",provider:Q}),w.info("Registered social-post with publish-pipeline"),{success:!0}})}function Lo0(A,f,w){let Q=new sM({sendMessage:A.messaging.send,logger:w.child("PublishExecuteHandler"),entityService:A.entityService,providers:f});A.messaging.subscribe("publish:execute",async(B)=>{return await Q.handle(B.payload),{success:!0}}),w.debug("Subscribed to publish:execute messages")}YA();function qo0(A,f){A.messaging.subscribe("entity:updated",async(w)=>{let{entityType:Q,entityId:B,entity:x}=w.payload;if(Q!=="post")return{success:!0};if(x.metadata?.status!=="queued")return{success:!0};try{if((await A.entityService.listEntities("social-post",{filter:{metadata:{sourceEntityType:"post",sourceEntityId:B}},limit:1})).length>0)return f.debug(`Social post already exists for ${B}, skipping auto-generate`),{success:!0};return await A.messaging.send("social:auto-generate",{sourceEntityType:Q,sourceEntityId:B,platform:"linkedin"}),f.info(`Auto-generate social post triggered for queued post ${B}`),{success:!0}}catch(I){let $=h0(I);return f.error(`Failed to trigger auto-generate for ${B}:`,{error:$}),{success:!0}}}),f.debug("Subscribed to entity:updated for auto-generation")}function _o0(A,f){A.messaging.subscribe("social:auto-generate",async(w)=>{let{sourceEntityType:Q,sourceEntityId:B,platform:x}=w.payload;try{let c=await A.jobs.enqueue(`${Vc.entityType}:generation`,{sourceEntityType:Q,sourceEntityId:B,platform:x,addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info(`Social post generation job enqueued for ${Q}/${B}`,{jobId:c}),{success:!0,jobId:c}}catch(c){let I=h0(c);return f.error(`Failed to enqueue social post generation for ${B}:`,{error:I}),{success:!1}}}),f.debug("Subscribed to social:auto-generate messages")}function Vo0(A,f){A.messaging.subscribe("generate:execute",async(w)=>{let{entityType:Q}=w.payload;if(Q!=="social-post")return{success:!0};f.info("Received generate:execute for social-post");try{let B=await A.entityService.listEntities("post",{filter:{metadata:{status:"published"}},limit:5});if(B.length===0)return f.info("No published posts found for social post generation"),await A.messaging.send("generate:report:failure",{entityType:"social-post",error:"No published posts available for social post generation"}),{success:!0};let x=null;for(let I of B)if((await A.entityService.listEntities("social-post",{filter:{metadata:{sourceEntityType:"post",sourceEntityId:I.id}},limit:1})).length===0){x=I;break}if(!x)return f.info("All recent posts already have social posts"),await A.messaging.send("generate:report:failure",{entityType:"social-post",error:"All recent posts already have social posts generated"}),{success:!0};let c=await A.jobs.enqueue(`${Vc.entityType}:generation`,{sourceEntityType:"post",sourceEntityId:x.id,platform:"linkedin",addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info("Social post generation job queued",{jobId:c,sourcePostId:x.id}),{success:!0}}catch(B){let x=h0(B);return f.error("Failed to handle generate:execute:",{error:x}),await A.messaging.send("generate:report:failure",{entityType:"social-post",error:x}),{success:!0}}}),f.debug("Subscribed to generate:execute messages")}var io0={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.8",description:"Multi-provider social media posting with queue-based publishing",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class qWA extends Nf{entityType=Vc.entityType;schema=db;adapter=Vc;providers=new Map;constructor(A){super("social-media",io0,A,bWA)}createGenerationHandler(A){return new _v(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return No0()}getDataSources(){return[new _a(this.logger.child("SocialPostDataSource"))]}async onRegister(A){if(this.initializeProviders(),Eo0(A,this.providers,this.logger),Lo0(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)qo0(A,this.logger),_o0(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");Vo0(A,this.logger),Co0(A),this.logger.info("Social media plugin registered successfully")}async derive(A,f,w){if(A.metadata.status!=="published")return;await w.jobs.enqueue(`${this.entityType}:generation`,{sourceEntityId:A.id,sourceEntityType:A.entityType},null,{priority:5,source:"social-media-plugin",metadata:{operationType:"content_operations",operationTarget:`social-post:${A.entityType}:${A.id}`,pluginId:"social-media"}})}initializeProviders(){if(this.config.linkedin?.accessToken){let A=LWA(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function tM(A){return new qWA(A)}YA();var uS2=X.enum(["draft","queued","published","failed"]),yNw=X.object({status:uS2.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class _WA{name="internal";async publish(A,f){return{id:"internal"}}}var fB={REGISTER:"publish:register",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",EXECUTE:"publish:execute",QUEUED:"publish:queued",COMPLETED:"publish:completed",FAILED:"publish:failed",LIST_RESPONSE:"publish:list:response"},Mu={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"};YA();var DS2=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),Mo0=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),DS2).optional(),maxRetries:X.number().optional().default(3),retryBaseDelayMs:X.number().optional().default(5000)});class Ou{static instance=null;queues=new Map;static getInstance(){return Ou.instance??=new Ou,Ou.instance}static resetInstance(){Ou.instance=null}static createFresh(){return new Ou}constructor(){}async add(A,f){let w=this.getOrCreateQueue(A),Q=w.find((c)=>c.entityId===f);if(Q)return{position:Q.position};let B=w.length+1,x={entityId:f,entityType:A,position:B,queuedAt:new Date().toISOString()};return w.push(x),{position:B}}async remove(A,f){let w=this.queues.get(A);if(!w)return;let Q=w.findIndex((B)=>B.entityId===f);if(Q===-1)return;w.splice(Q,1),this.recalculatePositions(w)}async reorder(A,f,w){let Q=this.queues.get(A);if(!Q)return;let B=Q.findIndex((I)=>I.entityId===f);if(B===-1)return;let[x]=Q.splice(B,1);if(!x)return;let c=Math.max(0,Math.min(w-1,Q.length));Q.splice(c,0,x),this.recalculatePositions(Q)}async list(A){let f=this.queues.get(A);if(!f)return[];return[...f]}async getNext(A){let f=this.queues.get(A);if(!f||f.length===0)return null;return f[0]??null}async getNextAcrossTypes(){let A=null;for(let f of this.queues.values()){let w=f[0];if(!w)continue;if(!A||w.queuedAt<A.queuedAt)A=w}return A}async popNext(A){let f=this.queues.get(A);if(!f||f.length===0)return null;let w=f.shift()??null;if(w)this.recalculatePositions(f);return w}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let A=[];for(let[f,w]of this.queues.entries())if(w.length>0)A.push(f);return A}getOrCreateQueue(A){let f=this.queues.get(A);if(!f)f=[],this.queues.set(A,f);return f}recalculatePositions(A){A.forEach((f,w)=>{f.position=w+1})}}class ju{static instance=null;providers=new Map;defaultProvider=new _WA;static getInstance(){return ju.instance??=new ju,ju.instance}static resetInstance(){ju.instance=null}static createFresh(){return new ju}constructor(){}register(A,f){this.providers.set(A,f)}get(A){return this.providers.get(A)??this.defaultProvider}has(A){return this.providers.has(A)}unregister(A){this.providers.delete(A)}getRegisteredTypes(){return Array.from(this.providers.keys())}}YA();YA();async function Oo0(A,f){let w={entityType:A.entityType,entityId:A.entityId};if(f.messageBus)await f.messageBus.send(fB.EXECUTE,w,"publish-service");f.onExecute?.(w)}async function jo0(A,f){let w=f.providerRegistry.get(A.entityType);if(!f.entityService){f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:"EntityService not available for provider mode",retryCount:0,willRetry:!1});return}let Q=await f.entityService.getEntity(A.entityType,A.entityId);if(!Q){f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:`Entity not found: ${A.entityType}/${A.entityId}`,retryCount:0,willRetry:!1});return}try{let B=await w.publish(Q.content,Q.metadata);f.retryTracker.clearRetries(A.entityId),f.onPublish?.({entityType:A.entityType,entityId:A.entityId,result:B})}catch(B){let x=h0(B);f.retryTracker.recordFailure(A.entityId,x);let c=f.retryTracker.getRetryInfo(A.entityId);f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:x,retryCount:c?.retryCount??1,willRetry:c?.willRetry??!1})}}function go0(A,f,w,Q){if(Q.retryTracker.clearRetries(f),Q.messageBus)Q.messageBus.send(fB.COMPLETED,{entityType:A,entityId:f,result:w},"publish-service");Q.onPublish?.({entityType:A,entityId:f,result:w})}function Po0(A,f,w,Q){Q.retryTracker.recordFailure(f,w);let B=Q.retryTracker.getRetryInfo(f),x={entityType:A,entityId:f,error:w,retryCount:B?.retryCount??1,willRetry:B?.willRetry??!1};if(Q.messageBus)Q.messageBus.send(fB.FAILED,x,"publish-service");Q.onFailed?.(x)}async function Ro0(A,f){let w=f.generationConditions[A];if(w&&f.onCheckGenerationConditions){let B=await f.onCheckGenerationConditions(A,w);if(!B.shouldGenerate){if(f.messageBus)f.messageBus.send(Mu.SKIPPED,{entityType:A,reason:B.reason??"Conditions not met"},"content-pipeline");return}}let Q={entityType:A};if(f.messageBus)await f.messageBus.send(Mu.EXECUTE,Q,"content-pipeline");f.onGenerate?.(Q)}function no0(A,f,w){if(w)w.send(Mu.COMPLETED,{entityType:A,entityId:f},"content-pipeline")}function mo0(A,f,w){if(w)w.send(Mu.FAILED,{entityType:A,error:f},"content-pipeline")}var YS2=1000;class gI{static instance=null;config;publishJobs=new Map;generationJobs=new Map;immediateIntervalJob=null;running=!1;static getInstance(A){return gI.instance??=new gI(A),gI.instance}static resetInstance(){if(gI.instance)gI.instance.stop();gI.instance=null}static createFresh(A){return new gI(A)}constructor(A){this.config={...A,entitySchedules:A.entitySchedules??{},generationSchedules:A.generationSchedules??{},generationConditions:A.generationConditions??{}},this.validateCronExpressions()}async start(){if(this.running)return;this.running=!0;for(let[A,f]of Object.entries(this.entitySchedules)){let w=this.config.backend.scheduleCron(f,()=>this.processEntityType(A));this.publishJobs.set(A,w)}for(let[A,f]of Object.entries(this.generationSchedules)){let w=this.config.backend.scheduleCron(f,()=>this.handleTriggerGeneration(A));this.generationJobs.set(A,w)}this.immediateIntervalJob=this.config.backend.scheduleInterval(YS2,()=>this.processUnscheduledTypes())}async stop(){if(this.running=!1,this.stopAndClearJobs(this.publishJobs),this.stopAndClearJobs(this.generationJobs),this.immediateIntervalJob)this.immediateIntervalJob.stop(),this.immediateIntervalJob=null}isRunning(){return this.running}async processEntityType(A){if(!this.running)return;try{let f=await this.config.queueManager.getNext(A);if(f)await this.processEntry(f)}catch(f){this.config.logger.error(`Scheduler error for ${A}:`,f)}}async processUnscheduledTypes(){if(!this.running)return;try{let A=await this.config.queueManager.getQueuedEntityTypes();for(let f of A)if(!this.entitySchedules[f]){let w=await this.config.queueManager.getNext(f);if(w){await this.processEntry(w);break}}}catch(A){this.config.logger.error("Scheduler error for unscheduled types:",A)}}async processEntry(A){if(await this.config.queueManager.remove(A.entityType,A.entityId),this.config.messageBus!==void 0)await Oo0(A,this.publishDeps);else await jo0(A,this.publishDeps)}completePublish(A,f,w){go0(A,f,w,this.publishDeps)}failPublish(A,f,w){Po0(A,f,w,this.publishDeps)}async publishDirect(A,f,w,Q){return this.config.providerRegistry.get(A).publish(w,Q)}async handleTriggerGeneration(A){if(!this.running)return;try{await Ro0(A,this.generationDeps)}catch(f){this.config.logger.error(`Generation trigger error for ${A}:`,f)}}completeGeneration(A,f){no0(A,f,this.config.messageBus)}failGeneration(A,f){mo0(A,f,this.config.messageBus)}stopAndClearJobs(A){for(let f of A.values())f.stop();A.clear()}get entitySchedules(){return this.config.entitySchedules}get generationSchedules(){return this.config.generationSchedules}get publishDeps(){return{providerRegistry:this.config.providerRegistry,retryTracker:this.config.retryTracker,messageBus:this.config.messageBus,entityService:this.config.entityService,onExecute:this.config.onExecute,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[A,f]of Object.entries(this.entitySchedules))this.validateCronExpression(A,f,"publish");for(let[A,f]of Object.entries(this.generationSchedules))this.validateCronExpression(A,f,"generation")}validateCronExpression(A,f,w){try{this.config.backend.validateCron(f)}catch(Q){throw Error(`Invalid ${w} cron expression for ${A}: "${f}" - ${h0(Q)}`)}}}var lo0={maxRetries:3,baseDelayMs:5000};class gu{static instance=null;retries=new Map;config;static getInstance(A){return gu.instance??=new gu(A??lo0),gu.instance}static resetInstance(){gu.instance=null}static createFresh(A){return new gu(A??lo0)}constructor(A){this.config=A}recordFailure(A,f){let Q=(this.retries.get(A)?.retryCount??0)+1,B=this.config.baseDelayMs*Math.pow(2,Q-1),x=Date.now()+B;this.retries.set(A,{entityId:A,retryCount:Q,lastError:f,nextRetryAt:x})}shouldRetry(A){let f=this.retries.get(A);if(!f)return!1;return f.retryCount<this.config.maxRetries}isReadyForRetry(A){let f=this.retries.get(A);if(!f)return!1;return Date.now()>=f.nextRetryAt}clearRetries(A){this.retries.delete(A)}getRetryInfo(A){let f=this.retries.get(A);if(!f)return null;return{entityId:f.entityId,retryCount:f.retryCount,lastError:f.lastError,nextRetryAt:f.nextRetryAt,willRetry:f.retryCount<this.config.maxRetries}}}function px(A,f,w,Q,B,x,c,I){return px.fromTZ(px.tp(A,f,w,Q,B,x,c),I)}px.fromTZISO=(A,f,w)=>px.fromTZ(HS2(A,f),w);px.fromTZ=function(A,f){let w=new Date(Date.UTC(A.y,A.m-1,A.d,A.h,A.i,A.s)),Q=VWA(A.tz,w),B=new Date(w.getTime()-Q),x=VWA(A.tz,B);if(x-Q===0)return B;{let c=new Date(w.getTime()-x),I=VWA(A.tz,c);if(I-x===0)return c;if(!f&&I-x>0)return c;if(f)throw Error("Invalid date passed to fromTZ()");return B}};px.toTZ=function(A,f){let w=A.toLocaleString("en-US",{timeZone:f}).replace(/[\u202f]/," "),Q=new Date(w);return{y:Q.getFullYear(),m:Q.getMonth()+1,d:Q.getDate(),h:Q.getHours(),i:Q.getMinutes(),s:Q.getSeconds(),tz:f}};px.tp=(A,f,w,Q,B,x,c)=>({y:A,m:f,d:w,h:Q,i:B,s:x,tz:c});function VWA(A,f=new Date){let w=f.toLocaleString("en-US",{timeZone:A,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],Q=f.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${Q} GMT`)-Date.parse(`${Q} ${w}`)}function HS2(A,f){let w=new Date(Date.parse(A));if(isNaN(w))throw Error("minitz: Invalid ISO8601 passed to parser.");let Q=A.substring(9);return A.includes("Z")||Q.includes("-")||Q.includes("+")?px.tp(w.getUTCFullYear(),w.getUTCMonth()+1,w.getUTCDate(),w.getUTCHours(),w.getUTCMinutes(),w.getUTCSeconds(),"Etc/UTC"):px.tp(w.getFullYear(),w.getMonth()+1,w.getDate(),w.getHours(),w.getMinutes(),w.getSeconds(),f)}px.minitz=px;var iWA=32,AO=31|iWA,po0=[1,2,4,8,16],To0=class{pattern;timezone;second;minute;hour;day;month;dayOfWeek;lastDayOfMonth;starDOM;starDOW;constructor(A,f){this.pattern=A,this.timezone=f,this.second=Array(60).fill(0),this.minute=Array(60).fill(0),this.hour=Array(24).fill(0),this.day=Array(31).fill(0),this.month=Array(12).fill(0),this.dayOfWeek=Array(7).fill(0),this.lastDayOfMonth=!1,this.starDOM=!1,this.starDOW=!1,this.parse()}parse(){if(!(typeof this.pattern=="string"||this.pattern instanceof String))throw TypeError("CronPattern: Pattern has to be of type string.");this.pattern.indexOf("@")>=0&&(this.pattern=this.handleNicknames(this.pattern).trim());let A=this.pattern.replace(/\s+/g," ").split(" ");if(A.length<5||A.length>6)throw TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exactly five or six space separated parts are required.");if(A.length===5&&A.unshift("0"),A[3].indexOf("L")>=0&&(A[3]=A[3].replace("L",""),this.lastDayOfMonth=!0),A[3]=="*"&&(this.starDOM=!0),A[4].length>=3&&(A[4]=this.replaceAlphaMonths(A[4])),A[5].length>=3&&(A[5]=this.replaceAlphaDays(A[5])),A[5]=="*"&&(this.starDOW=!0),this.pattern.indexOf("?")>=0){let f=new d4(new Date,this.timezone).getDate(!0);A[0]=A[0].replace("?",f.getSeconds().toString()),A[1]=A[1].replace("?",f.getMinutes().toString()),A[2]=A[2].replace("?",f.getHours().toString()),this.starDOM||(A[3]=A[3].replace("?",f.getDate().toString())),A[4]=A[4].replace("?",(f.getMonth()+1).toString()),this.starDOW||(A[5]=A[5].replace("?",f.getDay().toString()))}this.throwAtIllegalCharacters(A),this.partToArray("second",A[0],0,1),this.partToArray("minute",A[1],0,1),this.partToArray("hour",A[2],0,1),this.partToArray("day",A[3],-1,1),this.partToArray("month",A[4],-1,1),this.partToArray("dayOfWeek",A[5],0,AO),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(A,f,w,Q){let B=this[A],x=A==="day"&&this.lastDayOfMonth;if(f===""&&!x)throw TypeError("CronPattern: configuration entry "+A+" ("+f+") is empty, check for trailing spaces.");if(f==="*")return B.fill(Q);let c=f.split(",");if(c.length>1)for(let I=0;I<c.length;I++)this.partToArray(A,c[I],w,Q);else f.indexOf("-")!==-1&&f.indexOf("/")!==-1?this.handleRangeWithStepping(f,A,w,Q):f.indexOf("-")!==-1?this.handleRange(f,A,w,Q):f.indexOf("/")!==-1?this.handleStepping(f,A,w,Q):f!==""&&this.handleNumber(f,A,w,Q)}throwAtIllegalCharacters(A){for(let f=0;f<A.length;f++)if((f===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(A[f]))throw TypeError("CronPattern: configuration entry "+f+" ("+A[f]+") contains illegal characters.")}handleNumber(A,f,w,Q){let B=this.extractNth(A,f),x=parseInt(B[0],10)+w;if(isNaN(x))throw TypeError("CronPattern: "+f+" is not a number: '"+A+"'");this.setPart(f,x,B[1]||Q)}setPart(A,f,w){if(!Object.prototype.hasOwnProperty.call(this,A))throw TypeError("CronPattern: Invalid part specified: "+A);if(A==="dayOfWeek"){if(f===7&&(f=0),f<0||f>6)throw RangeError("CronPattern: Invalid value for dayOfWeek: "+f);this.setNthWeekdayOfMonth(f,w);return}if(A==="second"||A==="minute"){if(f<0||f>=60)throw RangeError("CronPattern: Invalid value for "+A+": "+f)}else if(A==="hour"){if(f<0||f>=24)throw RangeError("CronPattern: Invalid value for "+A+": "+f)}else if(A==="day"){if(f<0||f>=31)throw RangeError("CronPattern: Invalid value for "+A+": "+f)}else if(A==="month"&&(f<0||f>=12))throw RangeError("CronPattern: Invalid value for "+A+": "+f);this[A][f]=w}handleRangeWithStepping(A,f,w,Q){let B=this.extractNth(A,f),x=B[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(x===null)throw TypeError("CronPattern: Syntax error, illegal range with stepping: '"+A+"'");let[,c,I,$]=x,u=parseInt(c,10)+w,Y=parseInt(I,10)+w,F=parseInt($,10);if(isNaN(u))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(Y))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(F))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(F===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(F>this[f].length)throw TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[f].length+")");if(u>Y)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let K=u;K<=Y;K+=F)this.setPart(f,K,B[1]||Q)}extractNth(A,f){let w=A,Q;if(w.includes("#")){if(f!=="dayOfWeek")throw Error("CronPattern: nth (#) only allowed in day-of-week field");Q=w.split("#")[1],w=w.split("#")[0]}return[w,Q]}handleRange(A,f,w,Q){let B=this.extractNth(A,f),x=B[0].split("-");if(x.length!==2)throw TypeError("CronPattern: Syntax error, illegal range: '"+A+"'");let c=parseInt(x[0],10)+w,I=parseInt(x[1],10)+w;if(isNaN(c))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(I))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(c>I)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let $=c;$<=I;$++)this.setPart(f,$,B[1]||Q)}handleStepping(A,f,w,Q){let B=this.extractNth(A,f),x=B[0].split("/");if(x.length!==2)throw TypeError("CronPattern: Syntax error, illegal stepping: '"+A+"'");x[0]===""&&(x[0]="*");let c=0;x[0]!=="*"&&(c=parseInt(x[0],10)+w);let I=parseInt(x[1],10);if(isNaN(I))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(I===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(I>this[f].length)throw TypeError("CronPattern: Syntax error, max steps for part is ("+this[f].length+")");for(let $=c;$<this[f].length;$+=I)this.setPart(f,$,B[1]||Q)}replaceAlphaDays(A){return A.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")}replaceAlphaMonths(A){return A.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")}handleNicknames(A){let f=A.trim().toLowerCase();return f==="@yearly"||f==="@annually"?"0 0 1 1 *":f==="@monthly"?"0 0 1 * *":f==="@weekly"?"0 0 * * 0":f==="@daily"?"0 0 * * *":f==="@hourly"?"0 * * * *":A}setNthWeekdayOfMonth(A,f){if(typeof f!="number"&&f==="L")this.dayOfWeek[A]=this.dayOfWeek[A]|iWA;else if(f===AO)this.dayOfWeek[A]=AO;else if(f<6&&f>0)this.dayOfWeek[A]=this.dayOfWeek[A]|po0[f-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${f}, Type: ${typeof f}`)}},yo0=[31,28,31,30,31,30,31,31,30,31,30,31],wY=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],d4=class A{tz;ms;second;minute;hour;day;month;year;constructor(f,w){if(this.tz=w,f&&f instanceof Date)if(!isNaN(f))this.fromDate(f);else throw TypeError("CronDate: Invalid date passed to CronDate constructor");else if(f===void 0)this.fromDate(new Date);else if(f&&typeof f=="string")this.fromString(f);else if(f instanceof A)this.fromCronDate(f);else throw TypeError("CronDate: Invalid type ("+typeof f+") passed to CronDate constructor")}isNthWeekdayOfMonth(f,w,Q,B){let x=new Date(Date.UTC(f,w,Q)).getUTCDay(),c=0;for(let I=1;I<=Q;I++)new Date(Date.UTC(f,w,I)).getUTCDay()===x&&c++;if(B&AO&&po0[c-1]&B)return!0;if(B&iWA){let I=new Date(Date.UTC(f,w+1,0)).getUTCDate();for(let $=Q+1;$<=I;$++)if(new Date(Date.UTC(f,w,$)).getUTCDay()===x)return!1;return!0}return!1}fromDate(f){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=f.getUTCMilliseconds(),this.second=f.getUTCSeconds(),this.minute=f.getUTCMinutes()+this.tz,this.hour=f.getUTCHours(),this.day=f.getUTCDate(),this.month=f.getUTCMonth(),this.year=f.getUTCFullYear(),this.apply();else{let w=px.toTZ(f,this.tz);this.ms=f.getMilliseconds(),this.second=w.s,this.minute=w.i,this.hour=w.h,this.day=w.d,this.month=w.m-1,this.year=w.y}else this.ms=f.getMilliseconds(),this.second=f.getSeconds(),this.minute=f.getMinutes(),this.hour=f.getHours(),this.day=f.getDate(),this.month=f.getMonth(),this.year=f.getFullYear()}fromCronDate(f){this.tz=f.tz,this.year=f.year,this.month=f.month,this.day=f.day,this.hour=f.hour,this.minute=f.minute,this.second=f.second,this.ms=f.ms}apply(){if(this.month>11||this.day>yo0[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let f=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return this.ms=f.getUTCMilliseconds(),this.second=f.getUTCSeconds(),this.minute=f.getUTCMinutes(),this.hour=f.getUTCHours(),this.day=f.getUTCDate(),this.month=f.getUTCMonth(),this.year=f.getUTCFullYear(),!0}else return!1}fromString(f){if(typeof this.tz=="number"){let w=px.fromTZISO(f);this.ms=w.getUTCMilliseconds(),this.second=w.getUTCSeconds(),this.minute=w.getUTCMinutes(),this.hour=w.getUTCHours(),this.day=w.getUTCDate(),this.month=w.getUTCMonth(),this.year=w.getUTCFullYear(),this.apply()}else return this.fromDate(px.fromTZISO(f,this.tz))}findNext(f,w,Q,B){let x=this[w],c;Q.lastDayOfMonth&&(this.month!==1?c=yo0[this.month]:c=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let I=!Q.starDOW&&w=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let $=this[w]+B;$<Q[w].length;$++){let u=Q[w][$];if(w==="day"&&Q.lastDayOfMonth&&$-B==c&&(u=1),w==="day"&&!Q.starDOW){let Y=Q.dayOfWeek[(I+($-B-1))%7];if(Y&&Y&AO)Y=this.isNthWeekdayOfMonth(this.year,this.month,$-B,Y)?1:0;else if(Y)throw Error(`CronDate: Invalid value for dayOfWeek encountered. ${Y}`);f.legacyMode&&!Q.starDOM?u=u||Y:u=u&&Y}if(u)return this[w]=$-B,x!==this[w]?2:1}return 3}recurse(f,w,Q){let B=this.findNext(w,wY[Q][0],f,wY[Q][2]);if(B>1){let x=Q+1;for(;x<wY.length;)this[wY[x][0]]=-wY[x][2],x++;if(B===3)return this[wY[Q][1]]++,this[wY[Q][0]]=-wY[Q][2],this.apply(),this.recurse(f,w,0);if(this.apply())return this.recurse(f,w,Q-1)}return Q+=1,Q>=wY.length?this:this.year>=3000?null:this.recurse(f,w,Q)}increment(f,w,Q){return this.second+=w.interval!==void 0&&w.interval>1&&Q?w.interval:1,this.ms=0,this.apply(),this.recurse(f,w,0)}getDate(f){return f||this.tz===void 0?new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms):typeof this.tz=="number"?new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms)):px.fromTZ(px.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function US2(A){if(A===void 0&&(A={}),delete A.name,A.legacyMode=A.legacyMode===void 0?!0:A.legacyMode,A.paused=A.paused===void 0?!1:A.paused,A.maxRuns=A.maxRuns===void 0?1/0:A.maxRuns,A.catch=A.catch===void 0?!1:A.catch,A.interval=A.interval===void 0?0:parseInt(A.interval.toString(),10),A.utcOffset=A.utcOffset===void 0?void 0:parseInt(A.utcOffset.toString(),10),A.unref=A.unref===void 0?!1:A.unref,A.startAt&&(A.startAt=new d4(A.startAt,A.timezone)),A.stopAt&&(A.stopAt=new d4(A.stopAt,A.timezone)),A.interval!==null){if(isNaN(A.interval))throw Error("CronOptions: Supplied value for interval is not a number");if(A.interval<0)throw Error("CronOptions: Supplied value for interval can not be negative")}if(A.utcOffset!==void 0){if(isNaN(A.utcOffset))throw Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");if(A.utcOffset<-870||A.utcOffset>870)throw Error("CronOptions: utcOffset out of bounds.");if(A.utcOffset!==void 0&&A.timezone)throw Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}if(A.unref!==!0&&A.unref!==!1)throw Error("CronOptions: Unref should be either true, false or undefined(false).");return A}function eM(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function FS2(A){return eM(A)}function KS2(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var So0=30000,Oa=[],MWA=class{name;options;_states;fn;constructor(A,f,w){let Q,B;if(eM(f))B=f;else if(typeof f=="object")Q=f;else if(f!==void 0)throw Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(eM(w))B=w;else if(typeof w=="object")Q=w;else if(w!==void 0)throw Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=Q?.name,this.options=US2(Q),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:Q?Q.maxRuns:void 0,paused:Q?Q.paused:!1,pattern:new To0("* * * * *")},A&&(A instanceof Date||typeof A=="string"&&A.indexOf(":")>0)?this._states.once=new d4(A,this.options.timezone||this.options.utcOffset):this._states.pattern=new To0(A,this.options.timezone),this.name){if(Oa.find((x)=>x.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");Oa.push(this)}return B!==void 0&&FS2(B)&&(this.fn=B,this.schedule()),this}nextRun(A){let f=this._next(A);return f?f.getDate(!1):null}nextRuns(A,f){this._states.maxRuns!==void 0&&A>this._states.maxRuns&&(A=this._states.maxRuns);let w=[],Q=f||this._states.currentRun||void 0;for(;A--&&(Q=this.nextRun(Q));)w.push(Q);return w}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let A=this.nextRun(this._states.currentRun),f=!this._states.paused,w=this.fn!==void 0,Q=!this._states.kill;return f&&w&&Q&&A!==null}isStopped(){return this._states.kill}isBusy(){return this._states.blocking}currentRun(){return this._states.currentRun?this._states.currentRun.getDate():null}previousRun(){return this._states.previousRun?this._states.previousRun.getDate():null}msToNext(A){let f=this._next(A);return f?A instanceof d4||A instanceof Date?f.getTime()-A.getTime():f.getTime()-new d4(A).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let A=Oa.indexOf(this);A>=0&&Oa.splice(A,1)}pause(){return this._states.paused=!0,!this._states.kill}resume(){return this._states.paused=!1,!this._states.kill}schedule(A){if(A&&this.fn)throw Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");A&&(this.fn=A);let f=this.msToNext(),w=this.nextRun(this._states.currentRun);return f==null||isNaN(f)||w===null?this:(f>So0&&(f=So0),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(w),f),this._states.currentTimeout&&this.options.unref&&KS2(this._states.currentTimeout),this)}async _trigger(A){if(this._states.blocking=!0,this._states.currentRun=new d4(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{this.fn!==void 0&&await this.fn(this,this.options.context)}catch(f){eM(this.options.catch)&&this.options.catch(f,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new d4(A,this.options.timezone||this.options.utcOffset),this._states.blocking=!1}async trigger(){await this._trigger()}runsLeft(){return this._states.maxRuns}_checkTrigger(A){let f=new Date,w=!this._states.paused&&f.getTime()>=A.getTime(),Q=this._states.blocking&&this.options.protect;w&&!Q?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):w&&Q&&eM(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(A){let f=!!(A||this._states.currentRun),w=!1;!A&&this.options.startAt&&this.options.interval&&([A,f]=this._calculatePreviousRun(A,f),w=!A),A=new d4(A,this.options.timezone||this.options.utcOffset),this.options.startAt&&A&&A.getTime()<this.options.startAt.getTime()&&(A=this.options.startAt);let Q=this._states.once||new d4(A,this.options.timezone||this.options.utcOffset);return!w&&Q!==this._states.once&&(Q=Q.increment(this._states.pattern,this.options,f)),this._states.once&&this._states.once.getTime()<=A.getTime()||Q===null||this._states.maxRuns!==void 0&&this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&Q.getTime()>=this.options.stopAt.getTime()?null:Q}_calculatePreviousRun(A,f){let w=new d4(void 0,this.options.timezone||this.options.utcOffset),Q=A;if(this.options.startAt.getTime()<=w.getTime()){Q=this.options.startAt;let B=Q.getTime()+this.options.interval*1000;for(;B<=w.getTime();)Q=new d4(Q,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),B=Q.getTime()+this.options.interval*1000;f=!0}return Q===null&&(Q=void 0),[Q,f]}};class ja{scheduleCron(A,f){let w=new MWA(A,()=>{f()});return{stop:()=>w.stop()}}scheduleInterval(A,f){let w=setInterval(()=>{f()},A);return{stop:()=>clearInterval(w)}}validateCron(A){new MWA(A).stop()}}B0();YA();var OWA=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)")}),jWA=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),XS2=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array(jWA).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),ZS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),gWA=X.union([XS2,ZS2]);function ga(A,f,w){return{...Tf(f,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",OWA,async(B)=>{let{action:x,entityType:c,entityId:I,position:$}=B;switch(x){case"list":return vS2(w,c);case"add":return WS2(w,c,I);case"remove":return kS2(w,c,I);case"reorder":return hS2(w,c,I,$);default:return{success:!1,error:`Unknown action: ${x}`}}}),outputSchema:gWA}}async function vS2(A,f){let w=[];if(f)w=await A.list(f);else{let B=A.getRegisteredTypes();for(let x of B){let c=await A.list(x);w.push(...c)}w.sort((x,c)=>new Date(x.queuedAt).getTime()-new Date(c.queuedAt).getTime())}if(w.length===0)return{success:!0,data:{queue:[]},message:"No items in queue"};return{success:!0,data:{queue:w.map((B,x)=>({position:x+1,entityType:B.entityType,entityId:B.entityId,queuedAt:B.queuedAt}))},message:`${w.length} items in queue`}}async function WS2(A,f,w){if(!f)return{success:!1,error:"entityType is required for add action"};if(!w)return{success:!1,error:"entityId is required for add action"};let Q=await A.add(f,w);return{success:!0,data:{entityType:f,entityId:w,position:Q.position},message:`Added to queue at position ${Q.position}`}}async function kS2(A,f,w){if(!f)return{success:!1,error:"entityType is required for remove action"};if(!w)return{success:!1,error:"entityId is required for remove action"};return await A.remove(f,w),{success:!0,data:{entityType:f,entityId:w},message:"Removed from queue"}}async function hS2(A,f,w,Q){if(!f)return{success:!1,error:"entityType is required for reorder action"};if(!w)return{success:!1,error:"entityId is required for reorder action"};if(Q===void 0)return{success:!1,error:"position is required for reorder action"};if(Q<1)return{success:!1,error:"position must be a positive number"};return await A.reorder(f,w,Q),{success:!0,data:{entityType:f,entityId:w,position:Q},message:`Moved to position ${Q}`}}B0();YA();var PWA=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")}),GS2=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()}),JS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),RWA=X.union([GS2,JS2]);function Pa(A,f,w){return{...Tf(f,"publish","Publish an entity directly to its platform. Works with any registered entity type (social-post, post, deck, etc.)",PWA,async(B)=>{let{entityType:x,id:c,slug:I}=B;if(!c&&!I)return{success:!1,error:"Either 'id' or 'slug' must be provided"};let $=null;if(c)$=await A.entityService.getEntity(x,c);else if(I)$=(await A.entityService.listEntities(x,{filter:{metadata:{slug:I}},limit:1}))[0]??null;if(!$)return{success:!1,error:`Entity not found: ${x}:${c??I}`};if($.metadata.status==="published")return{success:!1,error:"Entity is already published"};if(!w.has(x))return{success:!1,error:`No publish provider registered for ${x}. Check that the required credentials are configured.`};let u=w.get(x),Y=$.content,F;try{let k=K2($.content,X.record(X.unknown()));Y=k.content;let h=k.metadata.coverImageId;F=typeof h==="string"?h:void 0}catch{}let K;if(F){let k=await A.entityService.getEntity("image",F);if(k?.content){let h=k.content.match(/^data:([^;]+);base64,(.+)$/);if(h?.[1]&&h[2])K={data:Buffer.from(h[2],"base64"),mimeType:h[1]}}}let Z=await u.publish(Y,$.metadata,K);return await A.entityService.updateEntity({...$,metadata:{...$.metadata,status:"published",publishedAt:new Date().toISOString(),platformId:Z.id}}),{success:!0,data:{entityType:x,entityId:$.id,platformId:Z.id,url:Z.url},message:`Published ${x}:${$.id}`}}),outputSchema:RWA}}B0();YA();function ro0(A,f){let{logger:w}=f;A.messaging.subscribe(fB.REGISTER,async(Q)=>bS2(f,Q.payload)),A.messaging.subscribe(fB.QUEUE,async(Q)=>zS2(A,f,Q.payload)),A.messaging.subscribe(fB.DIRECT,async(Q)=>NS2(A,f,Q.payload)),A.messaging.subscribe(fB.REMOVE,async(Q)=>CS2(f,Q.payload)),A.messaging.subscribe(fB.REORDER,async(Q)=>ES2(f,Q.payload)),A.messaging.subscribe(fB.LIST,async(Q)=>LS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_SUCCESS,async(Q)=>qS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_FAILURE,async(Q)=>_S2(A,f,Q.payload)),w.debug("Subscribed to publish messages"),A.messaging.subscribe(Mu.REPORT_SUCCESS,async(Q)=>{let{entityType:B,entityId:x}=Q.payload;return f.scheduler.completeGeneration(B,x),w.info("Generation completed",{entityType:B,entityId:x}),{success:!0}}),A.messaging.subscribe(Mu.REPORT_FAILURE,async(Q)=>{let{entityType:B,error:x}=Q.payload;return f.scheduler.failGeneration(B,x),w.warn("Generation failed",{entityType:B,error:x}),{success:!0}}),w.debug("Subscribed to generation messages")}async function bS2(A,f){let{entityType:w,provider:Q}=f;try{if(Q)A.providerRegistry.register(w,Q),A.logger.info(`Registered provider for entity type: ${w}`,{providerName:Q.name});return{success:!0}}catch(B){let x=h0(B);return A.logger.error(`Failed to register provider: ${x}`),{success:!1}}}async function zS2(A,f,w){let{entityType:Q,entityId:B}=w;try{let x=await f.queueManager.add(Q,B);return await A.messaging.send(fB.QUEUED,{entityType:Q,entityId:B,position:x.position}),f.logger.debug(`Entity queued: ${B}`,{entityType:Q,position:x.position}),{success:!0}}catch(x){let c=h0(x);return f.logger.error(`Failed to queue entity: ${c}`),{success:!1}}}async function NS2(A,f,w){let{entityType:Q,entityId:B}=w;return await A.messaging.send(fB.EXECUTE,{entityType:Q,entityId:B}),f.logger.debug(`Direct publish requested: ${B}`,{entityType:Q}),{success:!0}}async function CS2(A,f){let{entityType:w,entityId:Q}=f;try{return await A.queueManager.remove(w,Q),A.logger.debug(`Entity removed from queue: ${Q}`,{entityType:w}),{success:!0}}catch(B){let x=h0(B);return A.logger.error(`Failed to remove entity: ${x}`),{success:!1}}}async function ES2(A,f){let{entityType:w,entityId:Q,position:B}=f;try{return await A.queueManager.reorder(w,Q,B),A.logger.debug(`Entity reordered: ${Q}`,{entityType:w,newPosition:B}),{success:!0}}catch(x){let c=h0(x);return A.logger.error(`Failed to reorder entity: ${c}`),{success:!1}}}async function LS2(A,f,w){let{entityType:Q}=w;try{let B=await f.queueManager.list(Q);return await A.messaging.send(fB.LIST_RESPONSE,{entityType:Q,queue:B.map((x)=>({entityId:x.entityId,position:x.position,queuedAt:x.queuedAt}))}),{success:!0}}catch(B){let x=h0(B);return f.logger.error(`Failed to list queue: ${x}`),{success:!1}}}async function qS2(A,f,w){let{entityType:Q,entityId:B,result:x}=w;return f.retryTracker.clearRetries(B),await A.messaging.send(fB.COMPLETED,{entityType:Q,entityId:B,result:x}),f.logger.info(`Publish reported success: ${B}`,{entityType:Q}),{success:!0}}async function _S2(A,f,w){let{entityType:Q,entityId:B,error:x}=w;f.retryTracker.recordFailure(B,x);let c=f.retryTracker.getRetryInfo(B);return await A.messaging.send(fB.FAILED,{entityType:Q,entityId:B,error:x,retryCount:c?.retryCount??1,willRetry:c?.willRetry??!1}),f.logger.info(`Publish reported failure: ${B}`,{entityType:Q,error:x,retryCount:c?.retryCount,willRetry:c?.willRetry}),{success:!0}}YA();async function do0(A,f,w,Q){try{if(Q.skipIfDraftExists!==!1){if((await A.listEntities(w,{filter:{metadata:{status:"draft"}},limit:1})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(Q.maxUnpublishedDrafts!==void 0){let B=await A.listEntities(w,{filter:{metadata:{status:"draft"}},limit:Q.maxUnpublishedDrafts+1});if(B.length>=Q.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${B.length}/${Q.maxUnpublishedDrafts})`}}if(Q.minSourceEntities!==void 0&&Q.sourceEntityType){let B=await A.listEntities(Q.sourceEntityType,{publishedOnly:!0,limit:Q.minSourceEntities});if(B.length<Q.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${B.length}/${Q.minSourceEntities} ${Q.sourceEntityType})`}}return{shouldGenerate:!0}}catch(B){return f.error("Failed to check generation conditions",{entityType:w,error:h0(B)}),{shouldGenerate:!1,reason:`Condition check failed: ${h0(B)}`}}}function oo0(A){let{context:f,config:w,queueManager:Q,providerRegistry:B,retryTracker:x,logger:c}=A,I={send:async($,u)=>{return f.messaging.send($,u)},subscribe:()=>()=>{}};return gI.createFresh({queueManager:Q,providerRegistry:B,retryTracker:x,logger:c,backend:new ja,...w.entitySchedules&&{entitySchedules:w.entitySchedules},...w.generationSchedules&&{generationSchedules:w.generationSchedules},...w.generationConditions&&{generationConditions:w.generationConditions},messageBus:I,entityService:f.entityService,onPublish:($)=>{f.messaging.send(fB.COMPLETED,{entityType:$.entityType,entityId:$.entityId,result:$.result})},onFailed:($)=>{f.messaging.send(fB.FAILED,{entityType:$.entityType,entityId:$.entityId,error:$.error,retryCount:$.retryCount,willRetry:$.willRetry})},onCheckGenerationConditions:($,u)=>do0(f.entityService,c,$,u),onGenerate:($)=>{c.info(`Generation triggered for ${$.entityType}`),f.messaging.send(Mu.EXECUTE,{entityType:$.entityType})}})}async function ao0(A,f,w){let Q=A.getEntityTypes();for(let x of Q){let c=await A.listEntities(x,{filter:{metadata:{status:"queued"}}});for(let I of c)await f.add(I.entityType,I.id)}let B=0;for(let x of Q){let c=await f.list(x);B+=c.length}if(B>0)w.info(`Rebuilt queue with ${B} queued entities`)}var so0={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.8",description:"Content pipeline plugin for managing entity publishing queues, scheduling, and generation",type:"module",main:"src/index.ts",types:"src/index.ts",scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*",croner:"^9.1.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14",typescript:"^5.3.3"},exports:{".":{types:"./src/index.ts",default:"./src/index.ts"}},files:["src"]};class nWA extends yQ{pluginContext;queueManager;providerRegistry;retryTracker;scheduler;constructor(A){super("content-pipeline",so0,A??{},Mo0)}async onRegister(A){this.pluginContext=A,this.queueManager=Ou.createFresh(),this.providerRegistry=ju.createFresh(),this.retryTracker=gu.createFresh({maxRetries:this.config.maxRetries,baseDelayMs:this.config.retryBaseDelayMs}),this.scheduler=oo0({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,logger:this.logger}),ro0(A,{queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,scheduler:this.scheduler,logger:this.logger}),A.messaging.subscribe("sync:initial:completed",async()=>{return await ao0(A.entityService,this.queueManager,this.logger),{success:!0}}),A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("dashboard:register-widget",{id:"publication-pipeline",pluginId:this.id,title:"Publication Pipeline",section:"secondary",priority:15,rendererName:"PipelineWidget",dataProvider:async()=>{let f=A.entityService.getEntityTypes(),w=[],Q={draft:0,queued:0,published:0,failed:0};for(let B of f){let x=await A.entityService.listEntities(B);for(let c of x){let I=c.metadata.status;if(I!=="draft"&&I!=="queued"&&I!=="published"&&I!=="failed")continue;Q[I]++;let $=c.metadata.title;w.push({id:c.id,title:typeof $==="string"?$:c.id,type:B,status:I})}}return{summary:Q,items:w}}}),{success:!0}}),await this.scheduler.start(),this.logger.info("Content pipeline plugin started")}async getTools(){if(!this.pluginContext)throw Error("Plugin context not initialized");return[ga(this.pluginContext,this.id,this.queueManager),Pa(this.pluginContext,this.id,this.providerRegistry)]}async getInstructions(){return'## Publishing\n- Use `content-pipeline_queue` to manage the publish queue \u2014 list queued items, add entities to the queue, remove them, or reorder.\n- Use `content-pipeline_publish` to publish an entity directly to its platform (e.g. LinkedIn, Buttondown).\n- When users ask about their "publish queue", "publishing queue", or "what\'s queued", use `content-pipeline_queue`.'}async cleanup(){await this.scheduler.stop(),this.logger.info("Content pipeline plugin stopped")}getQueueManager(){return this.queueManager}getProviderRegistry(){return this.providerRegistry}getRetryTracker(){return this.retryTracker}getScheduler(){return this.scheduler}async onShutdown(){Ou.resetInstance(),ju.resetInstance(),gu.resetInstance()}}function mWA(A){return new nWA(A)}B0();YA();var to0=X.object({accountId:X.string().describe("Cloudflare account ID"),apiToken:X.string().describe("Cloudflare API token with Analytics:Read permission"),siteTag:X.string().describe("Cloudflare Web Analytics site tag")}),lWA=X.object({cloudflare:to0.optional()});B0();YA();var iS2=X.object({date:X.string().describe("Single date in YYYY-MM-DD format").optional(),days:X.number().min(1).max(365).describe("Number of days back from yesterday (e.g., 7 for last week)").optional(),startDate:X.string().describe("Start date in YYYY-MM-DD format (use with endDate)").optional(),endDate:X.string().describe("End date in YYYY-MM-DD format (use with startDate)").optional(),limit:X.number().min(1).max(100).default(20).describe("Maximum items for breakdowns (pages, referrers, countries)")});function MS2(A){if(A.date&&(A.days||A.startDate||A.endDate))return"Cannot combine 'date' with 'days' or 'startDate'/'endDate'";if(A.days&&(A.startDate||A.endDate))return"Cannot combine 'days' with 'startDate'/'endDate'";if(A.startDate&&!A.endDate||!A.startDate&&A.endDate)return"Both 'startDate' and 'endDate' must be provided for custom range";return null}function eo0(A,f,w){let Q=[];if(!w)return Q;return Q.push(Tf(A,"query",`Query website analytics from Cloudflare.
3019
+ ${w.content}`:w.prompt??"Write an engaging LinkedIn post";return A.ai.generate({prompt:Q,templateName:`social-media:${w.platform}`})}),A.eval.registerHandler("create",async(f)=>{let w=IS2.parse(f),Q=[],B=bx.from(async(u)=>{let Y={progress:u.progress};if(u.message!==void 0)Y.message=u.message;Q.push(Y)});if(!B)throw Error("Failed to create progress reporter");let c=await new _v(A.logger,A).process(w,`eval-${Date.now()}`,B),I=!1,$;if(c.success&&c.entityId){let u=await A.entityService.getEntity("social-post",c.entityId);I=!!u,$=u?.content.slice(0,300)}return{...c,entityExists:I,entityPreview:$,progressSteps:Q}})}YA();B0();class sM{sendMessage;logger;entityService;providers;constructor(A){this.sendMessage=A.sendMessage,this.logger=A.logger,this.entityService=A.entityService,this.providers=A.providers}async handle(A){let{entityType:f,entityId:w}=A;if(f!=="social-post")return;this.logger.debug("Handling publish:execute",{entityId:w});try{let Q=await this.entityService.getEntity("social-post",w);if(!Q){await this.reportFailure(f,w,`Post not found: ${w}`);return}if(Q.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:w});return}let B=Q.metadata.platform,x=this.providers.get(B);if(!x){await this.reportFailure(f,w,`No provider configured for platform: ${B}`);return}let c=K2(Q.content,r4),I;if(c.metadata.coverImageId)I=await this.fetchImageData(c.metadata.coverImageId);try{let $=await x.publish(c.content,Q.metadata,I),u=new Date().toISOString(),Y=$.id||void 0,F={...c.metadata,status:"published",publishedAt:u,...Y&&{platformPostId:Y}},K=Vc.createPostContent(F,c.content);await this.entityService.updateEntity({...Q,content:K,metadata:{...Q.metadata,status:"published",publishedAt:u,platformPostId:Y}}),await this.reportSuccess(f,w,$.id),this.logger.info(`Post published successfully: ${w}`,{platform:B,platformPostId:Y})}catch($){let u=$ instanceof Error?$.message:String($),Y={...c.metadata,status:"failed"},F=Vc.createPostContent(Y,c.content);await this.entityService.updateEntity({...Q,content:F,metadata:{...Q.metadata,status:"failed"}}),await this.reportFailure(f,w,u),this.logger.error(`Post publish failed: ${w}`,{platform:B,error:u})}}catch(Q){let B=h0(Q);this.logger.error("Unexpected error in publish handler",{entityId:w,error:B}),await this.reportFailure(f,w,B)}}async reportSuccess(A,f,w){await this.sendMessage("publish:report:success",{entityType:A,entityId:f,result:{id:w}})}async reportFailure(A,f,w){await this.sendMessage("publish:report:failure",{entityType:A,entityId:f,error:w})}async fetchImageData(A){try{let f=await this.entityService.getEntity("image",A);if(!f){this.logger.warn("Cover image not found",{imageId:A});return}let Q=f.content.match(/^data:([^;]+);base64,(.+)$/);if(!Q?.[1]||!Q[2]){this.logger.warn("Invalid image data URL format",{imageId:A});return}let B=Q[1],x=Q[2];return{data:Buffer.from(x,"base64"),mimeType:B}}catch(f){this.logger.warn("Failed to fetch cover image",{imageId:A,error:f});return}}}function Eo0(A,f,w){if(f.size===0){w.debug("No providers configured, skipping publish-pipeline registration");return}A.messaging.subscribe("system:plugins:ready",async()=>{let Q=f.values().next().value;return await A.messaging.send("publish:register",{entityType:"social-post",provider:Q}),w.info("Registered social-post with publish-pipeline"),{success:!0}})}function Lo0(A,f,w){let Q=new sM({sendMessage:A.messaging.send,logger:w.child("PublishExecuteHandler"),entityService:A.entityService,providers:f});A.messaging.subscribe("publish:execute",async(B)=>{return await Q.handle(B.payload),{success:!0}}),w.debug("Subscribed to publish:execute messages")}YA();function qo0(A,f){A.messaging.subscribe("entity:updated",async(w)=>{let{entityType:Q,entityId:B,entity:x}=w.payload;if(Q!=="post")return{success:!0};if(x.metadata?.status!=="queued")return{success:!0};try{if((await A.entityService.listEntities("social-post",{filter:{metadata:{sourceEntityType:"post",sourceEntityId:B}},limit:1})).length>0)return f.debug(`Social post already exists for ${B}, skipping auto-generate`),{success:!0};return await A.messaging.send("social:auto-generate",{sourceEntityType:Q,sourceEntityId:B,platform:"linkedin"}),f.info(`Auto-generate social post triggered for queued post ${B}`),{success:!0}}catch(I){let $=h0(I);return f.error(`Failed to trigger auto-generate for ${B}:`,{error:$}),{success:!0}}}),f.debug("Subscribed to entity:updated for auto-generation")}function _o0(A,f){A.messaging.subscribe("social:auto-generate",async(w)=>{let{sourceEntityType:Q,sourceEntityId:B,platform:x}=w.payload;try{let c=await A.jobs.enqueue(`${Vc.entityType}:generation`,{sourceEntityType:Q,sourceEntityId:B,platform:x,addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info(`Social post generation job enqueued for ${Q}/${B}`,{jobId:c}),{success:!0,jobId:c}}catch(c){let I=h0(c);return f.error(`Failed to enqueue social post generation for ${B}:`,{error:I}),{success:!1}}}),f.debug("Subscribed to social:auto-generate messages")}function Vo0(A,f){A.messaging.subscribe("generate:execute",async(w)=>{let{entityType:Q}=w.payload;if(Q!=="social-post")return{success:!0};f.info("Received generate:execute for social-post");try{let B=await A.entityService.listEntities("post",{filter:{metadata:{status:"published"}},limit:5});if(B.length===0)return f.info("No published posts found for social post generation"),await A.messaging.send("generate:report:failure",{entityType:"social-post",error:"No published posts available for social post generation"}),{success:!0};let x=null;for(let I of B)if((await A.entityService.listEntities("social-post",{filter:{metadata:{sourceEntityType:"post",sourceEntityId:I.id}},limit:1})).length===0){x=I;break}if(!x)return f.info("All recent posts already have social posts"),await A.messaging.send("generate:report:failure",{entityType:"social-post",error:"All recent posts already have social posts generated"}),{success:!0};let c=await A.jobs.enqueue(`${Vc.entityType}:generation`,{sourceEntityType:"post",sourceEntityId:x.id,platform:"linkedin",addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info("Social post generation job queued",{jobId:c,sourcePostId:x.id}),{success:!0}}catch(B){let x=h0(B);return f.error("Failed to handle generate:execute:",{error:x}),await A.messaging.send("generate:report:failure",{entityType:"social-post",error:x}),{success:!0}}}),f.debug("Subscribed to generate:execute messages")}var io0={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.9",description:"Multi-provider social media posting with queue-based publishing",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class qWA extends Nf{entityType=Vc.entityType;schema=db;adapter=Vc;providers=new Map;constructor(A){super("social-media",io0,A,bWA)}createGenerationHandler(A){return new _v(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return No0()}getDataSources(){return[new _a(this.logger.child("SocialPostDataSource"))]}async onRegister(A){if(this.initializeProviders(),Eo0(A,this.providers,this.logger),Lo0(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)qo0(A,this.logger),_o0(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");Vo0(A,this.logger),Co0(A),this.logger.info("Social media plugin registered successfully")}async derive(A,f,w){if(A.metadata.status!=="published")return;await w.jobs.enqueue(`${this.entityType}:generation`,{sourceEntityId:A.id,sourceEntityType:A.entityType},null,{priority:5,source:"social-media-plugin",metadata:{operationType:"content_operations",operationTarget:`social-post:${A.entityType}:${A.id}`,pluginId:"social-media"}})}initializeProviders(){if(this.config.linkedin?.accessToken){let A=LWA(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function tM(A){return new qWA(A)}YA();var uS2=X.enum(["draft","queued","published","failed"]),yNw=X.object({status:uS2.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class _WA{name="internal";async publish(A,f){return{id:"internal"}}}var fB={REGISTER:"publish:register",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",EXECUTE:"publish:execute",QUEUED:"publish:queued",COMPLETED:"publish:completed",FAILED:"publish:failed",LIST_RESPONSE:"publish:list:response"},Mu={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"};YA();var DS2=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),Mo0=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),DS2).optional(),maxRetries:X.number().optional().default(3),retryBaseDelayMs:X.number().optional().default(5000)});class Ou{static instance=null;queues=new Map;static getInstance(){return Ou.instance??=new Ou,Ou.instance}static resetInstance(){Ou.instance=null}static createFresh(){return new Ou}constructor(){}async add(A,f){let w=this.getOrCreateQueue(A),Q=w.find((c)=>c.entityId===f);if(Q)return{position:Q.position};let B=w.length+1,x={entityId:f,entityType:A,position:B,queuedAt:new Date().toISOString()};return w.push(x),{position:B}}async remove(A,f){let w=this.queues.get(A);if(!w)return;let Q=w.findIndex((B)=>B.entityId===f);if(Q===-1)return;w.splice(Q,1),this.recalculatePositions(w)}async reorder(A,f,w){let Q=this.queues.get(A);if(!Q)return;let B=Q.findIndex((I)=>I.entityId===f);if(B===-1)return;let[x]=Q.splice(B,1);if(!x)return;let c=Math.max(0,Math.min(w-1,Q.length));Q.splice(c,0,x),this.recalculatePositions(Q)}async list(A){let f=this.queues.get(A);if(!f)return[];return[...f]}async getNext(A){let f=this.queues.get(A);if(!f||f.length===0)return null;return f[0]??null}async getNextAcrossTypes(){let A=null;for(let f of this.queues.values()){let w=f[0];if(!w)continue;if(!A||w.queuedAt<A.queuedAt)A=w}return A}async popNext(A){let f=this.queues.get(A);if(!f||f.length===0)return null;let w=f.shift()??null;if(w)this.recalculatePositions(f);return w}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let A=[];for(let[f,w]of this.queues.entries())if(w.length>0)A.push(f);return A}getOrCreateQueue(A){let f=this.queues.get(A);if(!f)f=[],this.queues.set(A,f);return f}recalculatePositions(A){A.forEach((f,w)=>{f.position=w+1})}}class ju{static instance=null;providers=new Map;defaultProvider=new _WA;static getInstance(){return ju.instance??=new ju,ju.instance}static resetInstance(){ju.instance=null}static createFresh(){return new ju}constructor(){}register(A,f){this.providers.set(A,f)}get(A){return this.providers.get(A)??this.defaultProvider}has(A){return this.providers.has(A)}unregister(A){this.providers.delete(A)}getRegisteredTypes(){return Array.from(this.providers.keys())}}YA();YA();async function Oo0(A,f){let w={entityType:A.entityType,entityId:A.entityId};if(f.messageBus)await f.messageBus.send(fB.EXECUTE,w,"publish-service");f.onExecute?.(w)}async function jo0(A,f){let w=f.providerRegistry.get(A.entityType);if(!f.entityService){f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:"EntityService not available for provider mode",retryCount:0,willRetry:!1});return}let Q=await f.entityService.getEntity(A.entityType,A.entityId);if(!Q){f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:`Entity not found: ${A.entityType}/${A.entityId}`,retryCount:0,willRetry:!1});return}try{let B=await w.publish(Q.content,Q.metadata);f.retryTracker.clearRetries(A.entityId),f.onPublish?.({entityType:A.entityType,entityId:A.entityId,result:B})}catch(B){let x=h0(B);f.retryTracker.recordFailure(A.entityId,x);let c=f.retryTracker.getRetryInfo(A.entityId);f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:x,retryCount:c?.retryCount??1,willRetry:c?.willRetry??!1})}}function go0(A,f,w,Q){if(Q.retryTracker.clearRetries(f),Q.messageBus)Q.messageBus.send(fB.COMPLETED,{entityType:A,entityId:f,result:w},"publish-service");Q.onPublish?.({entityType:A,entityId:f,result:w})}function Po0(A,f,w,Q){Q.retryTracker.recordFailure(f,w);let B=Q.retryTracker.getRetryInfo(f),x={entityType:A,entityId:f,error:w,retryCount:B?.retryCount??1,willRetry:B?.willRetry??!1};if(Q.messageBus)Q.messageBus.send(fB.FAILED,x,"publish-service");Q.onFailed?.(x)}async function Ro0(A,f){let w=f.generationConditions[A];if(w&&f.onCheckGenerationConditions){let B=await f.onCheckGenerationConditions(A,w);if(!B.shouldGenerate){if(f.messageBus)f.messageBus.send(Mu.SKIPPED,{entityType:A,reason:B.reason??"Conditions not met"},"content-pipeline");return}}let Q={entityType:A};if(f.messageBus)await f.messageBus.send(Mu.EXECUTE,Q,"content-pipeline");f.onGenerate?.(Q)}function no0(A,f,w){if(w)w.send(Mu.COMPLETED,{entityType:A,entityId:f},"content-pipeline")}function mo0(A,f,w){if(w)w.send(Mu.FAILED,{entityType:A,error:f},"content-pipeline")}var YS2=1000;class gI{static instance=null;config;publishJobs=new Map;generationJobs=new Map;immediateIntervalJob=null;running=!1;static getInstance(A){return gI.instance??=new gI(A),gI.instance}static resetInstance(){if(gI.instance)gI.instance.stop();gI.instance=null}static createFresh(A){return new gI(A)}constructor(A){this.config={...A,entitySchedules:A.entitySchedules??{},generationSchedules:A.generationSchedules??{},generationConditions:A.generationConditions??{}},this.validateCronExpressions()}async start(){if(this.running)return;this.running=!0;for(let[A,f]of Object.entries(this.entitySchedules)){let w=this.config.backend.scheduleCron(f,()=>this.processEntityType(A));this.publishJobs.set(A,w)}for(let[A,f]of Object.entries(this.generationSchedules)){let w=this.config.backend.scheduleCron(f,()=>this.handleTriggerGeneration(A));this.generationJobs.set(A,w)}this.immediateIntervalJob=this.config.backend.scheduleInterval(YS2,()=>this.processUnscheduledTypes())}async stop(){if(this.running=!1,this.stopAndClearJobs(this.publishJobs),this.stopAndClearJobs(this.generationJobs),this.immediateIntervalJob)this.immediateIntervalJob.stop(),this.immediateIntervalJob=null}isRunning(){return this.running}async processEntityType(A){if(!this.running)return;try{let f=await this.config.queueManager.getNext(A);if(f)await this.processEntry(f)}catch(f){this.config.logger.error(`Scheduler error for ${A}:`,f)}}async processUnscheduledTypes(){if(!this.running)return;try{let A=await this.config.queueManager.getQueuedEntityTypes();for(let f of A)if(!this.entitySchedules[f]){let w=await this.config.queueManager.getNext(f);if(w){await this.processEntry(w);break}}}catch(A){this.config.logger.error("Scheduler error for unscheduled types:",A)}}async processEntry(A){if(await this.config.queueManager.remove(A.entityType,A.entityId),this.config.messageBus!==void 0)await Oo0(A,this.publishDeps);else await jo0(A,this.publishDeps)}completePublish(A,f,w){go0(A,f,w,this.publishDeps)}failPublish(A,f,w){Po0(A,f,w,this.publishDeps)}async publishDirect(A,f,w,Q){return this.config.providerRegistry.get(A).publish(w,Q)}async handleTriggerGeneration(A){if(!this.running)return;try{await Ro0(A,this.generationDeps)}catch(f){this.config.logger.error(`Generation trigger error for ${A}:`,f)}}completeGeneration(A,f){no0(A,f,this.config.messageBus)}failGeneration(A,f){mo0(A,f,this.config.messageBus)}stopAndClearJobs(A){for(let f of A.values())f.stop();A.clear()}get entitySchedules(){return this.config.entitySchedules}get generationSchedules(){return this.config.generationSchedules}get publishDeps(){return{providerRegistry:this.config.providerRegistry,retryTracker:this.config.retryTracker,messageBus:this.config.messageBus,entityService:this.config.entityService,onExecute:this.config.onExecute,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[A,f]of Object.entries(this.entitySchedules))this.validateCronExpression(A,f,"publish");for(let[A,f]of Object.entries(this.generationSchedules))this.validateCronExpression(A,f,"generation")}validateCronExpression(A,f,w){try{this.config.backend.validateCron(f)}catch(Q){throw Error(`Invalid ${w} cron expression for ${A}: "${f}" - ${h0(Q)}`)}}}var lo0={maxRetries:3,baseDelayMs:5000};class gu{static instance=null;retries=new Map;config;static getInstance(A){return gu.instance??=new gu(A??lo0),gu.instance}static resetInstance(){gu.instance=null}static createFresh(A){return new gu(A??lo0)}constructor(A){this.config=A}recordFailure(A,f){let Q=(this.retries.get(A)?.retryCount??0)+1,B=this.config.baseDelayMs*Math.pow(2,Q-1),x=Date.now()+B;this.retries.set(A,{entityId:A,retryCount:Q,lastError:f,nextRetryAt:x})}shouldRetry(A){let f=this.retries.get(A);if(!f)return!1;return f.retryCount<this.config.maxRetries}isReadyForRetry(A){let f=this.retries.get(A);if(!f)return!1;return Date.now()>=f.nextRetryAt}clearRetries(A){this.retries.delete(A)}getRetryInfo(A){let f=this.retries.get(A);if(!f)return null;return{entityId:f.entityId,retryCount:f.retryCount,lastError:f.lastError,nextRetryAt:f.nextRetryAt,willRetry:f.retryCount<this.config.maxRetries}}}function px(A,f,w,Q,B,x,c,I){return px.fromTZ(px.tp(A,f,w,Q,B,x,c),I)}px.fromTZISO=(A,f,w)=>px.fromTZ(HS2(A,f),w);px.fromTZ=function(A,f){let w=new Date(Date.UTC(A.y,A.m-1,A.d,A.h,A.i,A.s)),Q=VWA(A.tz,w),B=new Date(w.getTime()-Q),x=VWA(A.tz,B);if(x-Q===0)return B;{let c=new Date(w.getTime()-x),I=VWA(A.tz,c);if(I-x===0)return c;if(!f&&I-x>0)return c;if(f)throw Error("Invalid date passed to fromTZ()");return B}};px.toTZ=function(A,f){let w=A.toLocaleString("en-US",{timeZone:f}).replace(/[\u202f]/," "),Q=new Date(w);return{y:Q.getFullYear(),m:Q.getMonth()+1,d:Q.getDate(),h:Q.getHours(),i:Q.getMinutes(),s:Q.getSeconds(),tz:f}};px.tp=(A,f,w,Q,B,x,c)=>({y:A,m:f,d:w,h:Q,i:B,s:x,tz:c});function VWA(A,f=new Date){let w=f.toLocaleString("en-US",{timeZone:A,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],Q=f.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${Q} GMT`)-Date.parse(`${Q} ${w}`)}function HS2(A,f){let w=new Date(Date.parse(A));if(isNaN(w))throw Error("minitz: Invalid ISO8601 passed to parser.");let Q=A.substring(9);return A.includes("Z")||Q.includes("-")||Q.includes("+")?px.tp(w.getUTCFullYear(),w.getUTCMonth()+1,w.getUTCDate(),w.getUTCHours(),w.getUTCMinutes(),w.getUTCSeconds(),"Etc/UTC"):px.tp(w.getFullYear(),w.getMonth()+1,w.getDate(),w.getHours(),w.getMinutes(),w.getSeconds(),f)}px.minitz=px;var iWA=32,AO=31|iWA,po0=[1,2,4,8,16],To0=class{pattern;timezone;second;minute;hour;day;month;dayOfWeek;lastDayOfMonth;starDOM;starDOW;constructor(A,f){this.pattern=A,this.timezone=f,this.second=Array(60).fill(0),this.minute=Array(60).fill(0),this.hour=Array(24).fill(0),this.day=Array(31).fill(0),this.month=Array(12).fill(0),this.dayOfWeek=Array(7).fill(0),this.lastDayOfMonth=!1,this.starDOM=!1,this.starDOW=!1,this.parse()}parse(){if(!(typeof this.pattern=="string"||this.pattern instanceof String))throw TypeError("CronPattern: Pattern has to be of type string.");this.pattern.indexOf("@")>=0&&(this.pattern=this.handleNicknames(this.pattern).trim());let A=this.pattern.replace(/\s+/g," ").split(" ");if(A.length<5||A.length>6)throw TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exactly five or six space separated parts are required.");if(A.length===5&&A.unshift("0"),A[3].indexOf("L")>=0&&(A[3]=A[3].replace("L",""),this.lastDayOfMonth=!0),A[3]=="*"&&(this.starDOM=!0),A[4].length>=3&&(A[4]=this.replaceAlphaMonths(A[4])),A[5].length>=3&&(A[5]=this.replaceAlphaDays(A[5])),A[5]=="*"&&(this.starDOW=!0),this.pattern.indexOf("?")>=0){let f=new d4(new Date,this.timezone).getDate(!0);A[0]=A[0].replace("?",f.getSeconds().toString()),A[1]=A[1].replace("?",f.getMinutes().toString()),A[2]=A[2].replace("?",f.getHours().toString()),this.starDOM||(A[3]=A[3].replace("?",f.getDate().toString())),A[4]=A[4].replace("?",(f.getMonth()+1).toString()),this.starDOW||(A[5]=A[5].replace("?",f.getDay().toString()))}this.throwAtIllegalCharacters(A),this.partToArray("second",A[0],0,1),this.partToArray("minute",A[1],0,1),this.partToArray("hour",A[2],0,1),this.partToArray("day",A[3],-1,1),this.partToArray("month",A[4],-1,1),this.partToArray("dayOfWeek",A[5],0,AO),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(A,f,w,Q){let B=this[A],x=A==="day"&&this.lastDayOfMonth;if(f===""&&!x)throw TypeError("CronPattern: configuration entry "+A+" ("+f+") is empty, check for trailing spaces.");if(f==="*")return B.fill(Q);let c=f.split(",");if(c.length>1)for(let I=0;I<c.length;I++)this.partToArray(A,c[I],w,Q);else f.indexOf("-")!==-1&&f.indexOf("/")!==-1?this.handleRangeWithStepping(f,A,w,Q):f.indexOf("-")!==-1?this.handleRange(f,A,w,Q):f.indexOf("/")!==-1?this.handleStepping(f,A,w,Q):f!==""&&this.handleNumber(f,A,w,Q)}throwAtIllegalCharacters(A){for(let f=0;f<A.length;f++)if((f===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(A[f]))throw TypeError("CronPattern: configuration entry "+f+" ("+A[f]+") contains illegal characters.")}handleNumber(A,f,w,Q){let B=this.extractNth(A,f),x=parseInt(B[0],10)+w;if(isNaN(x))throw TypeError("CronPattern: "+f+" is not a number: '"+A+"'");this.setPart(f,x,B[1]||Q)}setPart(A,f,w){if(!Object.prototype.hasOwnProperty.call(this,A))throw TypeError("CronPattern: Invalid part specified: "+A);if(A==="dayOfWeek"){if(f===7&&(f=0),f<0||f>6)throw RangeError("CronPattern: Invalid value for dayOfWeek: "+f);this.setNthWeekdayOfMonth(f,w);return}if(A==="second"||A==="minute"){if(f<0||f>=60)throw RangeError("CronPattern: Invalid value for "+A+": "+f)}else if(A==="hour"){if(f<0||f>=24)throw RangeError("CronPattern: Invalid value for "+A+": "+f)}else if(A==="day"){if(f<0||f>=31)throw RangeError("CronPattern: Invalid value for "+A+": "+f)}else if(A==="month"&&(f<0||f>=12))throw RangeError("CronPattern: Invalid value for "+A+": "+f);this[A][f]=w}handleRangeWithStepping(A,f,w,Q){let B=this.extractNth(A,f),x=B[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(x===null)throw TypeError("CronPattern: Syntax error, illegal range with stepping: '"+A+"'");let[,c,I,$]=x,u=parseInt(c,10)+w,Y=parseInt(I,10)+w,F=parseInt($,10);if(isNaN(u))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(Y))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(F))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(F===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(F>this[f].length)throw TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[f].length+")");if(u>Y)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let K=u;K<=Y;K+=F)this.setPart(f,K,B[1]||Q)}extractNth(A,f){let w=A,Q;if(w.includes("#")){if(f!=="dayOfWeek")throw Error("CronPattern: nth (#) only allowed in day-of-week field");Q=w.split("#")[1],w=w.split("#")[0]}return[w,Q]}handleRange(A,f,w,Q){let B=this.extractNth(A,f),x=B[0].split("-");if(x.length!==2)throw TypeError("CronPattern: Syntax error, illegal range: '"+A+"'");let c=parseInt(x[0],10)+w,I=parseInt(x[1],10)+w;if(isNaN(c))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(I))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(c>I)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let $=c;$<=I;$++)this.setPart(f,$,B[1]||Q)}handleStepping(A,f,w,Q){let B=this.extractNth(A,f),x=B[0].split("/");if(x.length!==2)throw TypeError("CronPattern: Syntax error, illegal stepping: '"+A+"'");x[0]===""&&(x[0]="*");let c=0;x[0]!=="*"&&(c=parseInt(x[0],10)+w);let I=parseInt(x[1],10);if(isNaN(I))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(I===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(I>this[f].length)throw TypeError("CronPattern: Syntax error, max steps for part is ("+this[f].length+")");for(let $=c;$<this[f].length;$+=I)this.setPart(f,$,B[1]||Q)}replaceAlphaDays(A){return A.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")}replaceAlphaMonths(A){return A.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")}handleNicknames(A){let f=A.trim().toLowerCase();return f==="@yearly"||f==="@annually"?"0 0 1 1 *":f==="@monthly"?"0 0 1 * *":f==="@weekly"?"0 0 * * 0":f==="@daily"?"0 0 * * *":f==="@hourly"?"0 * * * *":A}setNthWeekdayOfMonth(A,f){if(typeof f!="number"&&f==="L")this.dayOfWeek[A]=this.dayOfWeek[A]|iWA;else if(f===AO)this.dayOfWeek[A]=AO;else if(f<6&&f>0)this.dayOfWeek[A]=this.dayOfWeek[A]|po0[f-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${f}, Type: ${typeof f}`)}},yo0=[31,28,31,30,31,30,31,31,30,31,30,31],wY=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],d4=class A{tz;ms;second;minute;hour;day;month;year;constructor(f,w){if(this.tz=w,f&&f instanceof Date)if(!isNaN(f))this.fromDate(f);else throw TypeError("CronDate: Invalid date passed to CronDate constructor");else if(f===void 0)this.fromDate(new Date);else if(f&&typeof f=="string")this.fromString(f);else if(f instanceof A)this.fromCronDate(f);else throw TypeError("CronDate: Invalid type ("+typeof f+") passed to CronDate constructor")}isNthWeekdayOfMonth(f,w,Q,B){let x=new Date(Date.UTC(f,w,Q)).getUTCDay(),c=0;for(let I=1;I<=Q;I++)new Date(Date.UTC(f,w,I)).getUTCDay()===x&&c++;if(B&AO&&po0[c-1]&B)return!0;if(B&iWA){let I=new Date(Date.UTC(f,w+1,0)).getUTCDate();for(let $=Q+1;$<=I;$++)if(new Date(Date.UTC(f,w,$)).getUTCDay()===x)return!1;return!0}return!1}fromDate(f){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=f.getUTCMilliseconds(),this.second=f.getUTCSeconds(),this.minute=f.getUTCMinutes()+this.tz,this.hour=f.getUTCHours(),this.day=f.getUTCDate(),this.month=f.getUTCMonth(),this.year=f.getUTCFullYear(),this.apply();else{let w=px.toTZ(f,this.tz);this.ms=f.getMilliseconds(),this.second=w.s,this.minute=w.i,this.hour=w.h,this.day=w.d,this.month=w.m-1,this.year=w.y}else this.ms=f.getMilliseconds(),this.second=f.getSeconds(),this.minute=f.getMinutes(),this.hour=f.getHours(),this.day=f.getDate(),this.month=f.getMonth(),this.year=f.getFullYear()}fromCronDate(f){this.tz=f.tz,this.year=f.year,this.month=f.month,this.day=f.day,this.hour=f.hour,this.minute=f.minute,this.second=f.second,this.ms=f.ms}apply(){if(this.month>11||this.day>yo0[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let f=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return this.ms=f.getUTCMilliseconds(),this.second=f.getUTCSeconds(),this.minute=f.getUTCMinutes(),this.hour=f.getUTCHours(),this.day=f.getUTCDate(),this.month=f.getUTCMonth(),this.year=f.getUTCFullYear(),!0}else return!1}fromString(f){if(typeof this.tz=="number"){let w=px.fromTZISO(f);this.ms=w.getUTCMilliseconds(),this.second=w.getUTCSeconds(),this.minute=w.getUTCMinutes(),this.hour=w.getUTCHours(),this.day=w.getUTCDate(),this.month=w.getUTCMonth(),this.year=w.getUTCFullYear(),this.apply()}else return this.fromDate(px.fromTZISO(f,this.tz))}findNext(f,w,Q,B){let x=this[w],c;Q.lastDayOfMonth&&(this.month!==1?c=yo0[this.month]:c=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let I=!Q.starDOW&&w=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let $=this[w]+B;$<Q[w].length;$++){let u=Q[w][$];if(w==="day"&&Q.lastDayOfMonth&&$-B==c&&(u=1),w==="day"&&!Q.starDOW){let Y=Q.dayOfWeek[(I+($-B-1))%7];if(Y&&Y&AO)Y=this.isNthWeekdayOfMonth(this.year,this.month,$-B,Y)?1:0;else if(Y)throw Error(`CronDate: Invalid value for dayOfWeek encountered. ${Y}`);f.legacyMode&&!Q.starDOM?u=u||Y:u=u&&Y}if(u)return this[w]=$-B,x!==this[w]?2:1}return 3}recurse(f,w,Q){let B=this.findNext(w,wY[Q][0],f,wY[Q][2]);if(B>1){let x=Q+1;for(;x<wY.length;)this[wY[x][0]]=-wY[x][2],x++;if(B===3)return this[wY[Q][1]]++,this[wY[Q][0]]=-wY[Q][2],this.apply(),this.recurse(f,w,0);if(this.apply())return this.recurse(f,w,Q-1)}return Q+=1,Q>=wY.length?this:this.year>=3000?null:this.recurse(f,w,Q)}increment(f,w,Q){return this.second+=w.interval!==void 0&&w.interval>1&&Q?w.interval:1,this.ms=0,this.apply(),this.recurse(f,w,0)}getDate(f){return f||this.tz===void 0?new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms):typeof this.tz=="number"?new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms)):px.fromTZ(px.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function US2(A){if(A===void 0&&(A={}),delete A.name,A.legacyMode=A.legacyMode===void 0?!0:A.legacyMode,A.paused=A.paused===void 0?!1:A.paused,A.maxRuns=A.maxRuns===void 0?1/0:A.maxRuns,A.catch=A.catch===void 0?!1:A.catch,A.interval=A.interval===void 0?0:parseInt(A.interval.toString(),10),A.utcOffset=A.utcOffset===void 0?void 0:parseInt(A.utcOffset.toString(),10),A.unref=A.unref===void 0?!1:A.unref,A.startAt&&(A.startAt=new d4(A.startAt,A.timezone)),A.stopAt&&(A.stopAt=new d4(A.stopAt,A.timezone)),A.interval!==null){if(isNaN(A.interval))throw Error("CronOptions: Supplied value for interval is not a number");if(A.interval<0)throw Error("CronOptions: Supplied value for interval can not be negative")}if(A.utcOffset!==void 0){if(isNaN(A.utcOffset))throw Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");if(A.utcOffset<-870||A.utcOffset>870)throw Error("CronOptions: utcOffset out of bounds.");if(A.utcOffset!==void 0&&A.timezone)throw Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}if(A.unref!==!0&&A.unref!==!1)throw Error("CronOptions: Unref should be either true, false or undefined(false).");return A}function eM(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function FS2(A){return eM(A)}function KS2(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var So0=30000,Oa=[],MWA=class{name;options;_states;fn;constructor(A,f,w){let Q,B;if(eM(f))B=f;else if(typeof f=="object")Q=f;else if(f!==void 0)throw Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(eM(w))B=w;else if(typeof w=="object")Q=w;else if(w!==void 0)throw Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=Q?.name,this.options=US2(Q),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:Q?Q.maxRuns:void 0,paused:Q?Q.paused:!1,pattern:new To0("* * * * *")},A&&(A instanceof Date||typeof A=="string"&&A.indexOf(":")>0)?this._states.once=new d4(A,this.options.timezone||this.options.utcOffset):this._states.pattern=new To0(A,this.options.timezone),this.name){if(Oa.find((x)=>x.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");Oa.push(this)}return B!==void 0&&FS2(B)&&(this.fn=B,this.schedule()),this}nextRun(A){let f=this._next(A);return f?f.getDate(!1):null}nextRuns(A,f){this._states.maxRuns!==void 0&&A>this._states.maxRuns&&(A=this._states.maxRuns);let w=[],Q=f||this._states.currentRun||void 0;for(;A--&&(Q=this.nextRun(Q));)w.push(Q);return w}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let A=this.nextRun(this._states.currentRun),f=!this._states.paused,w=this.fn!==void 0,Q=!this._states.kill;return f&&w&&Q&&A!==null}isStopped(){return this._states.kill}isBusy(){return this._states.blocking}currentRun(){return this._states.currentRun?this._states.currentRun.getDate():null}previousRun(){return this._states.previousRun?this._states.previousRun.getDate():null}msToNext(A){let f=this._next(A);return f?A instanceof d4||A instanceof Date?f.getTime()-A.getTime():f.getTime()-new d4(A).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let A=Oa.indexOf(this);A>=0&&Oa.splice(A,1)}pause(){return this._states.paused=!0,!this._states.kill}resume(){return this._states.paused=!1,!this._states.kill}schedule(A){if(A&&this.fn)throw Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");A&&(this.fn=A);let f=this.msToNext(),w=this.nextRun(this._states.currentRun);return f==null||isNaN(f)||w===null?this:(f>So0&&(f=So0),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(w),f),this._states.currentTimeout&&this.options.unref&&KS2(this._states.currentTimeout),this)}async _trigger(A){if(this._states.blocking=!0,this._states.currentRun=new d4(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{this.fn!==void 0&&await this.fn(this,this.options.context)}catch(f){eM(this.options.catch)&&this.options.catch(f,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new d4(A,this.options.timezone||this.options.utcOffset),this._states.blocking=!1}async trigger(){await this._trigger()}runsLeft(){return this._states.maxRuns}_checkTrigger(A){let f=new Date,w=!this._states.paused&&f.getTime()>=A.getTime(),Q=this._states.blocking&&this.options.protect;w&&!Q?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):w&&Q&&eM(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(A){let f=!!(A||this._states.currentRun),w=!1;!A&&this.options.startAt&&this.options.interval&&([A,f]=this._calculatePreviousRun(A,f),w=!A),A=new d4(A,this.options.timezone||this.options.utcOffset),this.options.startAt&&A&&A.getTime()<this.options.startAt.getTime()&&(A=this.options.startAt);let Q=this._states.once||new d4(A,this.options.timezone||this.options.utcOffset);return!w&&Q!==this._states.once&&(Q=Q.increment(this._states.pattern,this.options,f)),this._states.once&&this._states.once.getTime()<=A.getTime()||Q===null||this._states.maxRuns!==void 0&&this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&Q.getTime()>=this.options.stopAt.getTime()?null:Q}_calculatePreviousRun(A,f){let w=new d4(void 0,this.options.timezone||this.options.utcOffset),Q=A;if(this.options.startAt.getTime()<=w.getTime()){Q=this.options.startAt;let B=Q.getTime()+this.options.interval*1000;for(;B<=w.getTime();)Q=new d4(Q,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),B=Q.getTime()+this.options.interval*1000;f=!0}return Q===null&&(Q=void 0),[Q,f]}};class ja{scheduleCron(A,f){let w=new MWA(A,()=>{f()});return{stop:()=>w.stop()}}scheduleInterval(A,f){let w=setInterval(()=>{f()},A);return{stop:()=>clearInterval(w)}}validateCron(A){new MWA(A).stop()}}B0();YA();var OWA=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)")}),jWA=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),XS2=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array(jWA).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),ZS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),gWA=X.union([XS2,ZS2]);function ga(A,f,w){return{...Tf(f,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",OWA,async(B)=>{let{action:x,entityType:c,entityId:I,position:$}=B;switch(x){case"list":return vS2(w,c);case"add":return WS2(w,c,I);case"remove":return kS2(w,c,I);case"reorder":return hS2(w,c,I,$);default:return{success:!1,error:`Unknown action: ${x}`}}}),outputSchema:gWA}}async function vS2(A,f){let w=[];if(f)w=await A.list(f);else{let B=A.getRegisteredTypes();for(let x of B){let c=await A.list(x);w.push(...c)}w.sort((x,c)=>new Date(x.queuedAt).getTime()-new Date(c.queuedAt).getTime())}if(w.length===0)return{success:!0,data:{queue:[]},message:"No items in queue"};return{success:!0,data:{queue:w.map((B,x)=>({position:x+1,entityType:B.entityType,entityId:B.entityId,queuedAt:B.queuedAt}))},message:`${w.length} items in queue`}}async function WS2(A,f,w){if(!f)return{success:!1,error:"entityType is required for add action"};if(!w)return{success:!1,error:"entityId is required for add action"};let Q=await A.add(f,w);return{success:!0,data:{entityType:f,entityId:w,position:Q.position},message:`Added to queue at position ${Q.position}`}}async function kS2(A,f,w){if(!f)return{success:!1,error:"entityType is required for remove action"};if(!w)return{success:!1,error:"entityId is required for remove action"};return await A.remove(f,w),{success:!0,data:{entityType:f,entityId:w},message:"Removed from queue"}}async function hS2(A,f,w,Q){if(!f)return{success:!1,error:"entityType is required for reorder action"};if(!w)return{success:!1,error:"entityId is required for reorder action"};if(Q===void 0)return{success:!1,error:"position is required for reorder action"};if(Q<1)return{success:!1,error:"position must be a positive number"};return await A.reorder(f,w,Q),{success:!0,data:{entityType:f,entityId:w,position:Q},message:`Moved to position ${Q}`}}B0();YA();var PWA=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")}),GS2=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()}),JS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),RWA=X.union([GS2,JS2]);function Pa(A,f,w){return{...Tf(f,"publish","Publish an entity directly to its platform. Works with any registered entity type (social-post, post, deck, etc.)",PWA,async(B)=>{let{entityType:x,id:c,slug:I}=B;if(!c&&!I)return{success:!1,error:"Either 'id' or 'slug' must be provided"};let $=null;if(c)$=await A.entityService.getEntity(x,c);else if(I)$=(await A.entityService.listEntities(x,{filter:{metadata:{slug:I}},limit:1}))[0]??null;if(!$)return{success:!1,error:`Entity not found: ${x}:${c??I}`};if($.metadata.status==="published")return{success:!1,error:"Entity is already published"};if(!w.has(x))return{success:!1,error:`No publish provider registered for ${x}. Check that the required credentials are configured.`};let u=w.get(x),Y=$.content,F;try{let k=K2($.content,X.record(X.unknown()));Y=k.content;let h=k.metadata.coverImageId;F=typeof h==="string"?h:void 0}catch{}let K;if(F){let k=await A.entityService.getEntity("image",F);if(k?.content){let h=k.content.match(/^data:([^;]+);base64,(.+)$/);if(h?.[1]&&h[2])K={data:Buffer.from(h[2],"base64"),mimeType:h[1]}}}let Z=await u.publish(Y,$.metadata,K);return await A.entityService.updateEntity({...$,metadata:{...$.metadata,status:"published",publishedAt:new Date().toISOString(),platformId:Z.id}}),{success:!0,data:{entityType:x,entityId:$.id,platformId:Z.id,url:Z.url},message:`Published ${x}:${$.id}`}}),outputSchema:RWA}}B0();YA();function ro0(A,f){let{logger:w}=f;A.messaging.subscribe(fB.REGISTER,async(Q)=>bS2(f,Q.payload)),A.messaging.subscribe(fB.QUEUE,async(Q)=>zS2(A,f,Q.payload)),A.messaging.subscribe(fB.DIRECT,async(Q)=>NS2(A,f,Q.payload)),A.messaging.subscribe(fB.REMOVE,async(Q)=>CS2(f,Q.payload)),A.messaging.subscribe(fB.REORDER,async(Q)=>ES2(f,Q.payload)),A.messaging.subscribe(fB.LIST,async(Q)=>LS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_SUCCESS,async(Q)=>qS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_FAILURE,async(Q)=>_S2(A,f,Q.payload)),w.debug("Subscribed to publish messages"),A.messaging.subscribe(Mu.REPORT_SUCCESS,async(Q)=>{let{entityType:B,entityId:x}=Q.payload;return f.scheduler.completeGeneration(B,x),w.info("Generation completed",{entityType:B,entityId:x}),{success:!0}}),A.messaging.subscribe(Mu.REPORT_FAILURE,async(Q)=>{let{entityType:B,error:x}=Q.payload;return f.scheduler.failGeneration(B,x),w.warn("Generation failed",{entityType:B,error:x}),{success:!0}}),w.debug("Subscribed to generation messages")}async function bS2(A,f){let{entityType:w,provider:Q}=f;try{if(Q)A.providerRegistry.register(w,Q),A.logger.info(`Registered provider for entity type: ${w}`,{providerName:Q.name});return{success:!0}}catch(B){let x=h0(B);return A.logger.error(`Failed to register provider: ${x}`),{success:!1}}}async function zS2(A,f,w){let{entityType:Q,entityId:B}=w;try{let x=await f.queueManager.add(Q,B);return await A.messaging.send(fB.QUEUED,{entityType:Q,entityId:B,position:x.position}),f.logger.debug(`Entity queued: ${B}`,{entityType:Q,position:x.position}),{success:!0}}catch(x){let c=h0(x);return f.logger.error(`Failed to queue entity: ${c}`),{success:!1}}}async function NS2(A,f,w){let{entityType:Q,entityId:B}=w;return await A.messaging.send(fB.EXECUTE,{entityType:Q,entityId:B}),f.logger.debug(`Direct publish requested: ${B}`,{entityType:Q}),{success:!0}}async function CS2(A,f){let{entityType:w,entityId:Q}=f;try{return await A.queueManager.remove(w,Q),A.logger.debug(`Entity removed from queue: ${Q}`,{entityType:w}),{success:!0}}catch(B){let x=h0(B);return A.logger.error(`Failed to remove entity: ${x}`),{success:!1}}}async function ES2(A,f){let{entityType:w,entityId:Q,position:B}=f;try{return await A.queueManager.reorder(w,Q,B),A.logger.debug(`Entity reordered: ${Q}`,{entityType:w,newPosition:B}),{success:!0}}catch(x){let c=h0(x);return A.logger.error(`Failed to reorder entity: ${c}`),{success:!1}}}async function LS2(A,f,w){let{entityType:Q}=w;try{let B=await f.queueManager.list(Q);return await A.messaging.send(fB.LIST_RESPONSE,{entityType:Q,queue:B.map((x)=>({entityId:x.entityId,position:x.position,queuedAt:x.queuedAt}))}),{success:!0}}catch(B){let x=h0(B);return f.logger.error(`Failed to list queue: ${x}`),{success:!1}}}async function qS2(A,f,w){let{entityType:Q,entityId:B,result:x}=w;return f.retryTracker.clearRetries(B),await A.messaging.send(fB.COMPLETED,{entityType:Q,entityId:B,result:x}),f.logger.info(`Publish reported success: ${B}`,{entityType:Q}),{success:!0}}async function _S2(A,f,w){let{entityType:Q,entityId:B,error:x}=w;f.retryTracker.recordFailure(B,x);let c=f.retryTracker.getRetryInfo(B);return await A.messaging.send(fB.FAILED,{entityType:Q,entityId:B,error:x,retryCount:c?.retryCount??1,willRetry:c?.willRetry??!1}),f.logger.info(`Publish reported failure: ${B}`,{entityType:Q,error:x,retryCount:c?.retryCount,willRetry:c?.willRetry}),{success:!0}}YA();async function do0(A,f,w,Q){try{if(Q.skipIfDraftExists!==!1){if((await A.listEntities(w,{filter:{metadata:{status:"draft"}},limit:1})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(Q.maxUnpublishedDrafts!==void 0){let B=await A.listEntities(w,{filter:{metadata:{status:"draft"}},limit:Q.maxUnpublishedDrafts+1});if(B.length>=Q.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${B.length}/${Q.maxUnpublishedDrafts})`}}if(Q.minSourceEntities!==void 0&&Q.sourceEntityType){let B=await A.listEntities(Q.sourceEntityType,{publishedOnly:!0,limit:Q.minSourceEntities});if(B.length<Q.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${B.length}/${Q.minSourceEntities} ${Q.sourceEntityType})`}}return{shouldGenerate:!0}}catch(B){return f.error("Failed to check generation conditions",{entityType:w,error:h0(B)}),{shouldGenerate:!1,reason:`Condition check failed: ${h0(B)}`}}}function oo0(A){let{context:f,config:w,queueManager:Q,providerRegistry:B,retryTracker:x,logger:c}=A,I={send:async($,u)=>{return f.messaging.send($,u)},subscribe:()=>()=>{}};return gI.createFresh({queueManager:Q,providerRegistry:B,retryTracker:x,logger:c,backend:new ja,...w.entitySchedules&&{entitySchedules:w.entitySchedules},...w.generationSchedules&&{generationSchedules:w.generationSchedules},...w.generationConditions&&{generationConditions:w.generationConditions},messageBus:I,entityService:f.entityService,onPublish:($)=>{f.messaging.send(fB.COMPLETED,{entityType:$.entityType,entityId:$.entityId,result:$.result})},onFailed:($)=>{f.messaging.send(fB.FAILED,{entityType:$.entityType,entityId:$.entityId,error:$.error,retryCount:$.retryCount,willRetry:$.willRetry})},onCheckGenerationConditions:($,u)=>do0(f.entityService,c,$,u),onGenerate:($)=>{c.info(`Generation triggered for ${$.entityType}`),f.messaging.send(Mu.EXECUTE,{entityType:$.entityType})}})}async function ao0(A,f,w){let Q=A.getEntityTypes();for(let x of Q){let c=await A.listEntities(x,{filter:{metadata:{status:"queued"}}});for(let I of c)await f.add(I.entityType,I.id)}let B=0;for(let x of Q){let c=await f.list(x);B+=c.length}if(B>0)w.info(`Rebuilt queue with ${B} queued entities`)}var so0={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.9",description:"Content pipeline plugin for managing entity publishing queues, scheduling, and generation",type:"module",main:"src/index.ts",types:"src/index.ts",scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*",croner:"^9.1.0"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14",typescript:"^5.3.3"},exports:{".":{types:"./src/index.ts",default:"./src/index.ts"}},files:["src"]};class nWA extends yQ{pluginContext;queueManager;providerRegistry;retryTracker;scheduler;constructor(A){super("content-pipeline",so0,A??{},Mo0)}async onRegister(A){this.pluginContext=A,this.queueManager=Ou.createFresh(),this.providerRegistry=ju.createFresh(),this.retryTracker=gu.createFresh({maxRetries:this.config.maxRetries,baseDelayMs:this.config.retryBaseDelayMs}),this.scheduler=oo0({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,logger:this.logger}),ro0(A,{queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,scheduler:this.scheduler,logger:this.logger}),A.messaging.subscribe("sync:initial:completed",async()=>{return await ao0(A.entityService,this.queueManager,this.logger),{success:!0}}),A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("dashboard:register-widget",{id:"publication-pipeline",pluginId:this.id,title:"Publication Pipeline",section:"secondary",priority:15,rendererName:"PipelineWidget",dataProvider:async()=>{let f=A.entityService.getEntityTypes(),w=[],Q={draft:0,queued:0,published:0,failed:0};for(let B of f){let x=await A.entityService.listEntities(B);for(let c of x){let I=c.metadata.status;if(I!=="draft"&&I!=="queued"&&I!=="published"&&I!=="failed")continue;Q[I]++;let $=c.metadata.title;w.push({id:c.id,title:typeof $==="string"?$:c.id,type:B,status:I})}}return{summary:Q,items:w}}}),{success:!0}}),await this.scheduler.start(),this.logger.info("Content pipeline plugin started")}async getTools(){if(!this.pluginContext)throw Error("Plugin context not initialized");return[ga(this.pluginContext,this.id,this.queueManager),Pa(this.pluginContext,this.id,this.providerRegistry)]}async getInstructions(){return'## Publishing\n- Use `content-pipeline_queue` to manage the publish queue \u2014 list queued items, add entities to the queue, remove them, or reorder.\n- Use `content-pipeline_publish` to publish an entity directly to its platform (e.g. LinkedIn, Buttondown).\n- When users ask about their "publish queue", "publishing queue", or "what\'s queued", use `content-pipeline_queue`.'}async cleanup(){await this.scheduler.stop(),this.logger.info("Content pipeline plugin stopped")}getQueueManager(){return this.queueManager}getProviderRegistry(){return this.providerRegistry}getRetryTracker(){return this.retryTracker}getScheduler(){return this.scheduler}async onShutdown(){Ou.resetInstance(),ju.resetInstance(),gu.resetInstance()}}function mWA(A){return new nWA(A)}B0();YA();var to0=X.object({accountId:X.string().describe("Cloudflare account ID"),apiToken:X.string().describe("Cloudflare API token with Analytics:Read permission"),siteTag:X.string().describe("Cloudflare Web Analytics site tag")}),lWA=X.object({cloudflare:to0.optional()});B0();YA();var iS2=X.object({date:X.string().describe("Single date in YYYY-MM-DD format").optional(),days:X.number().min(1).max(365).describe("Number of days back from yesterday (e.g., 7 for last week)").optional(),startDate:X.string().describe("Start date in YYYY-MM-DD format (use with endDate)").optional(),endDate:X.string().describe("End date in YYYY-MM-DD format (use with startDate)").optional(),limit:X.number().min(1).max(100).default(20).describe("Maximum items for breakdowns (pages, referrers, countries)")});function MS2(A){if(A.date&&(A.days||A.startDate||A.endDate))return"Cannot combine 'date' with 'days' or 'startDate'/'endDate'";if(A.days&&(A.startDate||A.endDate))return"Cannot combine 'days' with 'startDate'/'endDate'";if(A.startDate&&!A.endDate||!A.startDate&&A.endDate)return"Both 'startDate' and 'endDate' must be provided for custom range";return null}function eo0(A,f,w){let Q=[];if(!w)return Q;return Q.push(Tf(A,"query",`Query website analytics from Cloudflare.
3020
3020
 
3021
3021
  Date range options (use only one):
3022
3022
  - No params: yesterday only
@@ -3154,7 +3154,7 @@ Returns pageviews, visitors, top pages, referrers, devices, and countries.`,iS2,
3154
3154
  }
3155
3155
  }
3156
3156
  }
3157
- `,variables:w})});if(!Q.ok){let c=await Q.text();throw Error(`Cloudflare API error: ${Q.status} - ${c}`)}let B=await Q.json();if(B.errors&&B.errors.length>0)throw Error(`Cloudflare GraphQL error: ${B.errors.map((c)=>c.message).join(", ")}`);return(B.data.viewer.accounts[0]?.rumPageloadEventsAdaptiveGroups??[]).map((c)=>({country:c.dimensions.countryName,visits:c.sum.visits}))}}YA();var yWA=7,OS2=10;function fa0(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let f=hk(),w=eg(yWA),Q=ZH(w),B=ZH(f);try{let[x,c]=await Promise.all([A.getWebsiteStats({startDate:Q,endDate:B}),A.getTopPages({startDate:Q,endDate:B,limit:OS2})]);return{days:yWA,startDate:Q,endDate:B,pageviews:x.pageviews,visitors:x.visitors,topPages:c}}catch(x){return{error:x instanceof Error?x.message:"Failed to fetch analytics",days:yWA}}}}var wa0={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.8",description:"Analytics plugin for collecting website and social media metrics",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class Qa0 extends yQ{cloudflareClient;constructor(A={}){super("analytics",wa0,A,lWA)}async onRegister(A){this.cloudflareClient=this.config.cloudflare?new TWA(this.config.cloudflare):void 0,A.insights.register("traffic-overview",fa0(this.cloudflareClient));let f=this.config.cloudflare?.siteTag;if(f)A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("plugin:site-builder:head-script:register",{pluginId:this.id,script:Aa0(f)}),{success:!0}})}async getTools(){return eo0(this.id,this.getContext(),this.cloudflareClient)}}function gS2(A={}){return new Qa0(A)}var Ra=gS2;B0();YA();YA();var fO=["StatsWidget","ListWidget","CustomWidget","PipelineWidget","IdentityWidget","ProfileWidget","SystemWidget"],PS2=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),priority:X.number().default(50),section:X.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:X.enum(fO)});class na{widgets=new Map;logger;constructor(A){this.logger=A.child("DashboardWidgetRegistry")}register(A){let f=`${A.pluginId}:${A.id}`;this.widgets.set(f,A),this.logger.debug("Dashboard widget registered",{key:f,title:A.title})}unregister(A,f){if(f)this.widgets.delete(`${A}:${f}`);else for(let w of this.widgets.keys())if(w.startsWith(`${A}:`))this.widgets.delete(w)}list(A){return Array.from(this.widgets.values()).filter((f)=>!A||f.section===A).sort((f,w)=>f.priority-w.priority)}get size(){return this.widgets.size}}YA();class ma{id="dashboard:dashboard";name="Dashboard DataSource";description="Aggregates dashboard widgets from all plugins";registry;logger;constructor(A,f){this.registry=A,this.logger=f.child("DashboardDataSource")}async fetch(A,f,w){let Q={},B=this.registry.list(),x=await Promise.allSettled(B.map(async(I)=>{let $=await I.dataProvider(),{dataProvider:u,...Y}=I;return{key:`${I.pluginId}:${I.id}`,widget:Y,data:$}}));for(let I=0;I<x.length;I++){let $=x[I],u=B[I];if(!$||!u)continue;if($.status==="fulfilled")Q[$.value.key]={widget:$.value.widget,data:$.value.data};else this.logger.error("Widget data provider failed",{widgetId:u.id,pluginId:u.pluginId,error:h0($.reason)})}return{widgets:Q}}}import{jsxDEV as wO}from"preact/jsx-dev-runtime";var RS2={StatsWidget:pr,ListWidget:rr,CustomWidget:dr,PipelineWidget:or,IdentityWidget:ar,ProfileWidget:sr,SystemWidget:tr};function nS2(A){let f={primary:[],secondary:[],sidebar:[]};for(let Q of Object.values(A)){let B=Q.widget.section;f[B].push(Q)}let w=(Q,B)=>Q.widget.priority-B.widget.priority;for(let Q of Object.keys(f))f[Q].sort(w);return f}function SWA(A,f){let{widget:w,data:Q}=A,B=`${w.pluginId}:${w.id}`,x=RS2[w.rendererName];return wO("div",{className:f?"col-span-1 lg:col-span-2":"",children:wO(x,{title:w.title,description:w.description,data:Q},void 0,!1,void 0,this)},B,!1,void 0,this)}function mS2({widgets:A}){let f=nS2(A);return wO("div",{className:"dashboard w-full max-w-layout mx-auto px-6 py-8 bg-theme","data-component":"dashboard:dashboard",children:wO("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_280px] gap-4",children:[f.primary.map((w)=>SWA(w,!0)),f.sidebar.length>0&&wO("aside",{className:"row-span-3 lg:col-start-3 space-y-4",children:f.sidebar.map((w)=>SWA(w))},void 0,!1,void 0,this),f.secondary.map((w)=>SWA(w,!0))]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var pWA=(A)=>{return mS2(A)};YA();var lS2=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),priority:X.number(),section:X.enum(["primary","secondary","sidebar"]),rendererName:X.enum(fO)}),TS2=X.object({widget:lS2,data:X.unknown()}),la=X.object({widgets:X.record(TS2)});class Ta{format(A){return JSON.stringify(A,null,2)}parse(A){return JSON.parse(A)}}P2();var Ba0=`var { h, hydrate, useState, useMemo, useEffect, useCallback, useRef, useContext, createContext, jsx, jsxs } = window.preact;
3157
+ `,variables:w})});if(!Q.ok){let c=await Q.text();throw Error(`Cloudflare API error: ${Q.status} - ${c}`)}let B=await Q.json();if(B.errors&&B.errors.length>0)throw Error(`Cloudflare GraphQL error: ${B.errors.map((c)=>c.message).join(", ")}`);return(B.data.viewer.accounts[0]?.rumPageloadEventsAdaptiveGroups??[]).map((c)=>({country:c.dimensions.countryName,visits:c.sum.visits}))}}YA();var yWA=7,OS2=10;function fa0(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let f=hk(),w=eg(yWA),Q=ZH(w),B=ZH(f);try{let[x,c]=await Promise.all([A.getWebsiteStats({startDate:Q,endDate:B}),A.getTopPages({startDate:Q,endDate:B,limit:OS2})]);return{days:yWA,startDate:Q,endDate:B,pageviews:x.pageviews,visitors:x.visitors,topPages:c}}catch(x){return{error:x instanceof Error?x.message:"Failed to fetch analytics",days:yWA}}}}var wa0={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.9",description:"Analytics plugin for collecting website and social media metrics",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class Qa0 extends yQ{cloudflareClient;constructor(A={}){super("analytics",wa0,A,lWA)}async onRegister(A){this.cloudflareClient=this.config.cloudflare?new TWA(this.config.cloudflare):void 0,A.insights.register("traffic-overview",fa0(this.cloudflareClient));let f=this.config.cloudflare?.siteTag;if(f)A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("plugin:site-builder:head-script:register",{pluginId:this.id,script:Aa0(f)}),{success:!0}})}async getTools(){return eo0(this.id,this.getContext(),this.cloudflareClient)}}function gS2(A={}){return new Qa0(A)}var Ra=gS2;B0();YA();YA();var fO=["StatsWidget","ListWidget","CustomWidget","PipelineWidget","IdentityWidget","ProfileWidget","SystemWidget"],PS2=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),priority:X.number().default(50),section:X.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:X.enum(fO)});class na{widgets=new Map;logger;constructor(A){this.logger=A.child("DashboardWidgetRegistry")}register(A){let f=`${A.pluginId}:${A.id}`;this.widgets.set(f,A),this.logger.debug("Dashboard widget registered",{key:f,title:A.title})}unregister(A,f){if(f)this.widgets.delete(`${A}:${f}`);else for(let w of this.widgets.keys())if(w.startsWith(`${A}:`))this.widgets.delete(w)}list(A){return Array.from(this.widgets.values()).filter((f)=>!A||f.section===A).sort((f,w)=>f.priority-w.priority)}get size(){return this.widgets.size}}YA();class ma{id="dashboard:dashboard";name="Dashboard DataSource";description="Aggregates dashboard widgets from all plugins";registry;logger;constructor(A,f){this.registry=A,this.logger=f.child("DashboardDataSource")}async fetch(A,f,w){let Q={},B=this.registry.list(),x=await Promise.allSettled(B.map(async(I)=>{let $=await I.dataProvider(),{dataProvider:u,...Y}=I;return{key:`${I.pluginId}:${I.id}`,widget:Y,data:$}}));for(let I=0;I<x.length;I++){let $=x[I],u=B[I];if(!$||!u)continue;if($.status==="fulfilled")Q[$.value.key]={widget:$.value.widget,data:$.value.data};else this.logger.error("Widget data provider failed",{widgetId:u.id,pluginId:u.pluginId,error:h0($.reason)})}return{widgets:Q}}}import{jsxDEV as wO}from"preact/jsx-dev-runtime";var RS2={StatsWidget:pr,ListWidget:rr,CustomWidget:dr,PipelineWidget:or,IdentityWidget:ar,ProfileWidget:sr,SystemWidget:tr};function nS2(A){let f={primary:[],secondary:[],sidebar:[]};for(let Q of Object.values(A)){let B=Q.widget.section;f[B].push(Q)}let w=(Q,B)=>Q.widget.priority-B.widget.priority;for(let Q of Object.keys(f))f[Q].sort(w);return f}function SWA(A,f){let{widget:w,data:Q}=A,B=`${w.pluginId}:${w.id}`,x=RS2[w.rendererName];return wO("div",{className:f?"col-span-1 lg:col-span-2":"",children:wO(x,{title:w.title,description:w.description,data:Q},void 0,!1,void 0,this)},B,!1,void 0,this)}function mS2({widgets:A}){let f=nS2(A);return wO("div",{className:"dashboard w-full max-w-layout mx-auto px-6 py-8 bg-theme","data-component":"dashboard:dashboard",children:wO("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_280px] gap-4",children:[f.primary.map((w)=>SWA(w,!0)),f.sidebar.length>0&&wO("aside",{className:"row-span-3 lg:col-start-3 space-y-4",children:f.sidebar.map((w)=>SWA(w))},void 0,!1,void 0,this),f.secondary.map((w)=>SWA(w,!0))]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var pWA=(A)=>{return mS2(A)};YA();var lS2=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),priority:X.number(),section:X.enum(["primary","secondary","sidebar"]),rendererName:X.enum(fO)}),TS2=X.object({widget:lS2,data:X.unknown()}),la=X.object({widgets:X.record(TS2)});class Ta{format(A){return JSON.stringify(A,null,2)}parse(A){return JSON.parse(A)}}P2();var Ba0=`var { h, hydrate, useState, useMemo, useEffect, useCallback, useRef, useContext, createContext, jsx, jsxs } = window.preact;
3158
3158
  var __require = function(mod) {
3159
3159
  if (mod === "crypto") return { randomUUID: () => window.crypto.randomUUID() };
3160
3160
  throw new Error("Cannot require " + mod + " in browser");
@@ -26442,7 +26442,7 @@ Please report this to https://github.com/markedjs/marked.\`;
26442
26442
  }
26443
26443
  })();
26444
26444
  })();
26445
- `;var xa0=i0({name:"dashboard",description:"Extensible dashboard with plugin-contributed widgets",schema:la,requiredPermission:"public",formatter:new Ta,dataSourceId:"dashboard:dashboard",layout:{component:pWA,interactive:Ba0}});var ca0={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.8",description:"Dashboard plugin with extensible widget system",type:"module",exports:{".":"./src/index.ts"},scripts:{precompile:"bun ../../scripts/compile-hydration.ts",typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/plugins":"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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var pS2=X.object({version:X.string().default("1.0.0")}),rS2=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),priority:X.number().default(50),section:X.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:X.enum(fO),dataProvider:X.function().returns(X.promise(X.unknown()))}),dS2=X.object({pluginId:X.string(),widgetId:X.string().optional()});class rWA extends yQ{dependencies=["site-builder"];widgetRegistry=null;datasource=null;constructor(A){super("dashboard",ca0,A??{},pS2)}async onRegister(A){this.widgetRegistry=new na(this.logger),this.datasource=new ma(this.widgetRegistry,this.logger),A.entities.registerDataSource(this.datasource),A.templates.register({dashboard:xa0}),await A.messaging.send("plugin:site-builder:route:register",{pluginId:this.id,routes:[{id:"dashboard",path:"/dashboard",title:"System Dashboard",description:"Monitor your Brain system statistics and activity",layout:"default",navigation:{show:!1,label:"Dashboard",slot:"secondary",priority:100},sections:[{id:"main",template:`${this.id}:dashboard`}]}]}),A.messaging.subscribe("dashboard:register-widget",async(f)=>{try{let w=rS2.parse(f.payload),Q={id:w.id,pluginId:w.pluginId,title:w.title,description:w.description,priority:w.priority,section:w.section,rendererName:w.rendererName,dataProvider:w.dataProvider};return this.widgetRegistry?.register(Q),this.logger.debug("Widget registered via messaging",{widgetId:w.id,pluginId:w.pluginId}),{success:!0}}catch(w){return this.logger.error("Failed to register widget",{error:h0(w),payload:f.payload}),{success:!1,error:"Widget registration failed"}}}),A.messaging.subscribe("dashboard:unregister-widget",async(f)=>{let w=dS2.parse(f.payload);return this.widgetRegistry?.unregister(w.pluginId,w.widgetId),this.logger.debug("Widget unregistered via messaging",{pluginId:w.pluginId,widgetId:w.widgetId}),{success:!0}}),this.logger.info("Dashboard plugin registered")}async getTools(){return[]}getWidgetRegistry(){return this.widgetRegistry}}function QO(A){return new rWA(A)}YA();B0();YA();import{h as $p2}from"preact";YA();R7();B0();var ob=X.enum(["draft","queued","published","failed"]),BO=X.object({subject:X.string(),status:ob,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional()}),Ia0=BO.pick({subject:!0,status:!0,entityIds:!0,scheduledFor:!0,sentAt:!0,buttondownId:!0,sourceEntityType:!0}),xO=v2.extend({entityType:X.literal("newsletter"),metadata:Ia0});B0();class $a0 extends _2{constructor(){super({entityType:"newsletter",schema:xO,frontmatterSchema:BO})}toMarkdown(A){let f=this.extractBody(A.content);return this.buildMarkdown(f,A.metadata)}fromMarkdown(A){let f=this.parseFrontmatter(A);return{entityType:"newsletter",content:A,metadata:f}}}var ua0=new $a0;B0();B0();YA();var oS2=bH.extend({status:X.enum(["draft","queued","published","failed"]).optional()}),aS2=zH.extend({query:oS2.optional()});function Da0(A){try{let{content:f}=K2(A.content,BO);return f}catch{return A.content}}class dWA extends U6{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(A){super(A);this.logger.debug("NewsletterDataSource initialized")}parseQuery(A){let f=aS2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){let f=Da0(A),w={id:A.id,subject:A.metadata.subject,status:A.metadata.status,excerpt:XH(f,150),created:A.created,url:`/newsletters/${A.id}`};if(A.metadata.sentAt)w.sentAt=A.metadata.sentAt;return w}buildListResult(A,f,w){return{newsletters:A,totalCount:f?.totalItems??A.length,pagination:f}}async fetch(A,f,w){let{query:Q}=this.parseQuery(A),B=w.entityService;if(Q.id)return this.fetchSingleNewsletter(Q.id,f,B);let x=Q.status,c=x?{filter:{metadata:{status:x}}}:void 0,{items:I,pagination:$}=await this.fetchList(Q,B,c);return f.parse(this.buildListResult(I,$,Q))}async fetchSingleNewsletter(A,f,w){let Q=await w.getEntity(this.config.entityType,A);if(!Q)throw Error(`Newsletter not found: ${A}`);let B=await this.resolveNavigation(Q,w),x=[];if(Q.metadata.entityIds?.length){let $=Q.metadata.sourceEntityType??"post";x=(await Promise.all(Q.metadata.entityIds.map(async(Y)=>{let F=await w.getEntity($,Y);if(F){let K=F.metadata;return{id:Y,title:K.title??Y,url:`/${$}s/${K.slug??Y}`}}return null}))).filter((Y)=>Y!==null)}let c=Da0(Q),I={id:Q.id,subject:Q.metadata.subject,status:Q.metadata.status,content:c,created:Q.created,updated:Q.updated,sentAt:Q.metadata.sentAt,scheduledFor:Q.metadata.scheduledFor,newsletter:Q,prevNewsletter:B.prev?{id:B.prev.id,subject:B.prev.subject,url:B.prev.url}:null,nextNewsletter:B.next?{id:B.next.id,subject:B.next.subject,url:B.next.url}:null,sourceEntities:x.length>0?x:void 0};return f.parse(I)}}B0();YA();var sS2=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 oWA extends Cx{constructor(A,f){super(A,f,{schema:sS2,jobTypeName:"newsletter:generation",entityType:"newsletter"})}async generate(A,f){let w=A.addToQueue??!1,{prompt:Q,sourceEntityIds:B,sourceEntityType:x}=A,{content:c,subject:I}=A;if(c){if(!I)this.failEarly("Subject is required when providing content directly");await this.reportProgress(f,{progress:50,message:"Using provided content"})}else if(B&&B.length>0){let K=x??"post";await this.reportProgress(f,{progress:10,message:`Fetching ${B.length} source entities`});let k=(await Promise.all(B.map((q)=>this.context.entityService.getEntity(K,q)))).filter((q)=>q!=null);if(k.length===0)this.failEarly(`No source entities found for IDs: ${B.join(", ")}`);await this.reportProgress(f,{progress:30,message:`Generating newsletter from ${k.length} posts`});let G=`Create an engaging newsletter that highlights these blog posts:
26445
+ `;var xa0=i0({name:"dashboard",description:"Extensible dashboard with plugin-contributed widgets",schema:la,requiredPermission:"public",formatter:new Ta,dataSourceId:"dashboard:dashboard",layout:{component:pWA,interactive:Ba0}});var ca0={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.9",description:"Dashboard plugin with extensible widget system",type:"module",exports:{".":"./src/index.ts"},scripts:{precompile:"bun ../../scripts/compile-hydration.ts",typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/plugins":"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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var pS2=X.object({version:X.string().default("1.0.0")}),rS2=X.object({id:X.string(),pluginId:X.string(),title:X.string(),description:X.string().optional(),priority:X.number().default(50),section:X.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:X.enum(fO),dataProvider:X.function().returns(X.promise(X.unknown()))}),dS2=X.object({pluginId:X.string(),widgetId:X.string().optional()});class rWA extends yQ{dependencies=["site-builder"];widgetRegistry=null;datasource=null;constructor(A){super("dashboard",ca0,A??{},pS2)}async onRegister(A){this.widgetRegistry=new na(this.logger),this.datasource=new ma(this.widgetRegistry,this.logger),A.entities.registerDataSource(this.datasource),A.templates.register({dashboard:xa0}),await A.messaging.send("plugin:site-builder:route:register",{pluginId:this.id,routes:[{id:"dashboard",path:"/dashboard",title:"System Dashboard",description:"Monitor your Brain system statistics and activity",layout:"default",navigation:{show:!1,label:"Dashboard",slot:"secondary",priority:100},sections:[{id:"main",template:`${this.id}:dashboard`}]}]}),A.messaging.subscribe("dashboard:register-widget",async(f)=>{try{let w=rS2.parse(f.payload),Q={id:w.id,pluginId:w.pluginId,title:w.title,description:w.description,priority:w.priority,section:w.section,rendererName:w.rendererName,dataProvider:w.dataProvider};return this.widgetRegistry?.register(Q),this.logger.debug("Widget registered via messaging",{widgetId:w.id,pluginId:w.pluginId}),{success:!0}}catch(w){return this.logger.error("Failed to register widget",{error:h0(w),payload:f.payload}),{success:!1,error:"Widget registration failed"}}}),A.messaging.subscribe("dashboard:unregister-widget",async(f)=>{let w=dS2.parse(f.payload);return this.widgetRegistry?.unregister(w.pluginId,w.widgetId),this.logger.debug("Widget unregistered via messaging",{pluginId:w.pluginId,widgetId:w.widgetId}),{success:!0}}),this.logger.info("Dashboard plugin registered")}async getTools(){return[]}getWidgetRegistry(){return this.widgetRegistry}}function QO(A){return new rWA(A)}YA();B0();YA();import{h as $p2}from"preact";YA();R7();B0();var ob=X.enum(["draft","queued","published","failed"]),BO=X.object({subject:X.string(),status:ob,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional()}),Ia0=BO.pick({subject:!0,status:!0,entityIds:!0,scheduledFor:!0,sentAt:!0,buttondownId:!0,sourceEntityType:!0}),xO=v2.extend({entityType:X.literal("newsletter"),metadata:Ia0});B0();class $a0 extends _2{constructor(){super({entityType:"newsletter",schema:xO,frontmatterSchema:BO})}toMarkdown(A){let f=this.extractBody(A.content);return this.buildMarkdown(f,A.metadata)}fromMarkdown(A){let f=this.parseFrontmatter(A);return{entityType:"newsletter",content:A,metadata:f}}}var ua0=new $a0;B0();B0();YA();var oS2=bH.extend({status:X.enum(["draft","queued","published","failed"]).optional()}),aS2=zH.extend({query:oS2.optional()});function Da0(A){try{let{content:f}=K2(A.content,BO);return f}catch{return A.content}}class dWA extends U6{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(A){super(A);this.logger.debug("NewsletterDataSource initialized")}parseQuery(A){let f=aS2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){let f=Da0(A),w={id:A.id,subject:A.metadata.subject,status:A.metadata.status,excerpt:XH(f,150),created:A.created,url:`/newsletters/${A.id}`};if(A.metadata.sentAt)w.sentAt=A.metadata.sentAt;return w}buildListResult(A,f,w){return{newsletters:A,totalCount:f?.totalItems??A.length,pagination:f}}async fetch(A,f,w){let{query:Q}=this.parseQuery(A),B=w.entityService;if(Q.id)return this.fetchSingleNewsletter(Q.id,f,B);let x=Q.status,c=x?{filter:{metadata:{status:x}}}:void 0,{items:I,pagination:$}=await this.fetchList(Q,B,c);return f.parse(this.buildListResult(I,$,Q))}async fetchSingleNewsletter(A,f,w){let Q=await w.getEntity(this.config.entityType,A);if(!Q)throw Error(`Newsletter not found: ${A}`);let B=await this.resolveNavigation(Q,w),x=[];if(Q.metadata.entityIds?.length){let $=Q.metadata.sourceEntityType??"post";x=(await Promise.all(Q.metadata.entityIds.map(async(Y)=>{let F=await w.getEntity($,Y);if(F){let K=F.metadata;return{id:Y,title:K.title??Y,url:`/${$}s/${K.slug??Y}`}}return null}))).filter((Y)=>Y!==null)}let c=Da0(Q),I={id:Q.id,subject:Q.metadata.subject,status:Q.metadata.status,content:c,created:Q.created,updated:Q.updated,sentAt:Q.metadata.sentAt,scheduledFor:Q.metadata.scheduledFor,newsletter:Q,prevNewsletter:B.prev?{id:B.prev.id,subject:B.prev.subject,url:B.prev.url}:null,nextNewsletter:B.next?{id:B.next.id,subject:B.next.subject,url:B.next.url}:null,sourceEntities:x.length>0?x:void 0};return f.parse(I)}}B0();YA();var sS2=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 oWA extends Cx{constructor(A,f){super(A,f,{schema:sS2,jobTypeName:"newsletter:generation",entityType:"newsletter"})}async generate(A,f){let w=A.addToQueue??!1,{prompt:Q,sourceEntityIds:B,sourceEntityType:x}=A,{content:c,subject:I}=A;if(c){if(!I)this.failEarly("Subject is required when providing content directly");await this.reportProgress(f,{progress:50,message:"Using provided content"})}else if(B&&B.length>0){let K=x??"post";await this.reportProgress(f,{progress:10,message:`Fetching ${B.length} source entities`});let k=(await Promise.all(B.map((q)=>this.context.entityService.getEntity(K,q)))).filter((q)=>q!=null);if(k.length===0)this.failEarly(`No source entities found for IDs: ${B.join(", ")}`);await this.reportProgress(f,{progress:30,message:`Generating newsletter from ${k.length} posts`});let G=`Create an engaging newsletter that highlights these blog posts:
26446
26446
 
26447
26447
  ${k.map((q)=>`## ${q.metadata.title}
26448
26448
 
@@ -26511,16 +26511,16 @@ Newsletter-specific guidelines:
26511
26511
  - "Reply and let me know..."
26512
26512
  - "Until next time..."
26513
26513
 
26514
- The goal is to build a relationship with readers through valuable, authentic content.`});YA();B0();import{jsxDEV as m9,Fragment as wp2}from"preact/jsx-dev-runtime";var eS2=X.object({id:X.string(),subject:X.string(),status:ob,excerpt:X.string(),created:X.string(),sentAt:X.string().optional(),url:X.string()}),Ap2=X.object({newsletters:X.array(eS2),totalCount:X.number(),pagination:$c.nullable()}),fp2=({newsletters:A,totalCount:f,pageTitle:w,pagination:Q,baseUrl:B="/newsletters"})=>{let x=w??"Newsletters",c=`Browse all ${f} ${f===1?"newsletter":"newsletters"}`;return m9(wp2,{children:[m9(o2,{title:x,description:c},void 0,!1,void 0,this),m9("div",{className:"newsletter-list bg-theme",children:m9("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[m9("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:x},void 0,!1,void 0,this),A.length===0?m9("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):m9("div",{className:"space-y-4",children:A.map((I)=>m9(Gf,{href:I.url,children:[m9(Rx,{className:"text-lg",children:I.subject},void 0,!1,void 0,this),m9(O9,{children:m9("div",{className:"flex items-center gap-3",children:[m9(Ec,{status:I.status},void 0,!1,void 0,this),m9("span",{className:"text-sm text-theme-muted",children:sQ(I.sentAt??I.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),I.excerpt&&m9("p",{className:"text-theme-muted line-clamp-2",children:I.excerpt},void 0,!1,void 0,this)]},I.id,!0,void 0,this))},void 0,!1,void 0,this),Q&&Q.totalPages>1&&m9(WI,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},Ha0=i0({name:"newsletter-list",description:"Newsletter list page template",schema:Ap2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:fp2}});YA();B0();import{jsxDEV as KQ,Fragment as cp2}from"preact/jsx-dev-runtime";var Qp2=X.object({id:X.string(),title:X.string(),url:X.string()}),Ua0=X.object({id:X.string(),subject:X.string(),url:X.string()}),Bp2=X.object({id:X.string(),subject:X.string(),status:ob,content:X.string(),created:X.string(),updated:X.string(),sentAt:X.string().optional(),scheduledFor:X.string().optional(),sourceEntities:X.array(Qp2).optional(),prevNewsletter:Ua0.nullable().optional(),nextNewsletter:Ua0.nullable().optional()}),xp2=({subject:A,status:f,content:w,created:Q,sentAt:B,scheduledFor:x,sourceEntities:c,prevNewsletter:I,nextNewsletter:$})=>{let u=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:A}],Y=B??Q,F=B?"Sent":"Created";return KQ(cp2,{children:[KQ(o2,{title:A,description:`Newsletter: ${A}`},void 0,!1,void 0,this),KQ("section",{className:"newsletter-detail-section",children:KQ("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:KQ("div",{className:"max-w-3xl mx-auto",children:[KQ(n4,{items:u},void 0,!1,void 0,this),KQ("h1",{className:"text-3xl md:text-4xl font-bold text-heading leading-tight tracking-tight mb-4",children:A},void 0,!1,void 0,this),KQ("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[KQ(Ec,{status:f},void 0,!1,void 0,this),KQ("span",{children:[F,": ",sQ(Y,{style:"long"})]},void 0,!0,void 0,this),x&&f==="queued"&&KQ("span",{children:["Scheduled for: ",sQ(x,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c&&c.length>0&&KQ(Gf,{variant:"compact",className:"mb-8",children:[KQ("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),KQ("ul",{className:"space-y-1",children:c.map((K)=>KQ("li",{children:KQ("a",{href:K.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:K.title},void 0,!1,void 0,this)},K.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),KQ(vI,{markdown:w},void 0,!1,void 0,this),(I??$)&&KQ("nav",{className:"mt-12 pt-8 border-t border-theme",children:KQ("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[I?KQ(Gf,{href:I.url,variant:"compact",children:[KQ("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),KQ("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:I.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this):KQ("div",{},void 0,!1,void 0,this),$&&KQ(Gf,{href:$.url,variant:"compact",className:"md:text-right",children:[KQ("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),KQ("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:$.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)},Fa0=i0({name:"newsletter-detail",description:"Individual newsletter detail template",schema:Bp2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:xp2}});var Ka0={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.8",description:"Newsletter entity type with AI generation and publish pipeline",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts,.tsx","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@brains/entity-service":"workspace:*","@brains/plugins":"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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var up2=X.object({});class aWA extends Nf{entityType="newsletter";schema=xO;adapter=ua0;constructor(A={}){super("newsletter",Ka0,A,up2)}createGenerationHandler(A){return new oWA(this.logger,A)}getTemplates(){return{generation:Ya0,"newsletter-list":Ha0,"newsletter-detail":Fa0}}getDataSources(){return[new dWA(this.logger.child("NewsletterDataSource"))]}async onRegister(A){this.deferPublishRegistration(A),this.subscribeToPublishExecute(A),this.subscribeToGenerateExecute(A),this.registerEvalHandlers(A),A.messaging.subscribe("system:plugins:ready",async()=>{let f=await A.messaging.send("buttondown:is-configured",{});if(!("noop"in f)&&f.success)await A.messaging.send("plugin:site-builder:slot:register",{pluginId:this.id,slotName:"footer-top",render:()=>$p2(bKA,{variant:"inline"})});return{success:!0}}),this.logger.debug("Newsletter plugin registered")}deferPublishRegistration(A){let f={name:"internal",publish:async()=>({id:"internal"})};A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("publish:register",{entityType:"newsletter",provider:f}),{success:!0}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(f)=>{let{entityType:w,entityId:Q}=f.payload;if(w!=="newsletter")return{success:!0};try{let B=await A.entityService.getEntity("newsletter",Q);if(!B)return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:`Newsletter not found: ${Q}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=await A.messaging.send("buttondown:send",{entityId:Q,subject:B.metadata.subject,content:B.content}),c=new Date().toISOString(),I=!("noop"in x)&&x.data?x.data.emailId:void 0;return await A.entityService.updateEntity({...B,metadata:{...B.metadata,status:"published",sentAt:c,buttondownId:I}}),await A.messaging.send("publish:report:success",{entityType:w,entityId:Q,sentAt:c}),this.logger.info(`Published newsletter: ${Q}`),{success:!0}}catch(B){let x=h0(B);return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:x}),{success:!0}}})}subscribeToGenerateExecute(A){A.messaging.subscribe("generate:execute",async(f)=>{if(f.payload.entityType!=="newsletter")return{success:!0};try{let w=await A.entityService.listEntities("post",{filter:{metadata:{status:"published"}},limit:10});if(w.length===0)return await A.messaging.send("generate:report:failure",{entityType:"newsletter",error:"No published posts available for newsletter"}),{success:!0};return await A.jobs.enqueue("newsletter:generation",{sourceEntityIds:w.map((Q)=>Q.id),sourceEntityType:"post",addToQueue:!1},{interfaceType:"job",userId:"system"}),{success:!0}}catch(w){return await A.messaging.send("generate:report:failure",{entityType:"newsletter",error:h0(w)}),{success:!0}}})}registerEvalHandlers(A){let f=X.object({prompt:X.string().optional(),content:X.string().optional()});A.eval.registerHandler("generation",async(w)=>{let Q=f.parse(w),B=Q.content?`Create an engaging newsletter based on this content:
26514
+ The goal is to build a relationship with readers through valuable, authentic content.`});YA();B0();import{jsxDEV as m9,Fragment as wp2}from"preact/jsx-dev-runtime";var eS2=X.object({id:X.string(),subject:X.string(),status:ob,excerpt:X.string(),created:X.string(),sentAt:X.string().optional(),url:X.string()}),Ap2=X.object({newsletters:X.array(eS2),totalCount:X.number(),pagination:$c.nullable()}),fp2=({newsletters:A,totalCount:f,pageTitle:w,pagination:Q,baseUrl:B="/newsletters"})=>{let x=w??"Newsletters",c=`Browse all ${f} ${f===1?"newsletter":"newsletters"}`;return m9(wp2,{children:[m9(o2,{title:x,description:c},void 0,!1,void 0,this),m9("div",{className:"newsletter-list bg-theme",children:m9("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[m9("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:x},void 0,!1,void 0,this),A.length===0?m9("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):m9("div",{className:"space-y-4",children:A.map((I)=>m9(Gf,{href:I.url,children:[m9(Rx,{className:"text-lg",children:I.subject},void 0,!1,void 0,this),m9(O9,{children:m9("div",{className:"flex items-center gap-3",children:[m9(Ec,{status:I.status},void 0,!1,void 0,this),m9("span",{className:"text-sm text-theme-muted",children:sQ(I.sentAt??I.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),I.excerpt&&m9("p",{className:"text-theme-muted line-clamp-2",children:I.excerpt},void 0,!1,void 0,this)]},I.id,!0,void 0,this))},void 0,!1,void 0,this),Q&&Q.totalPages>1&&m9(WI,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},Ha0=i0({name:"newsletter-list",description:"Newsletter list page template",schema:Ap2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:fp2}});YA();B0();import{jsxDEV as KQ,Fragment as cp2}from"preact/jsx-dev-runtime";var Qp2=X.object({id:X.string(),title:X.string(),url:X.string()}),Ua0=X.object({id:X.string(),subject:X.string(),url:X.string()}),Bp2=X.object({id:X.string(),subject:X.string(),status:ob,content:X.string(),created:X.string(),updated:X.string(),sentAt:X.string().optional(),scheduledFor:X.string().optional(),sourceEntities:X.array(Qp2).optional(),prevNewsletter:Ua0.nullable().optional(),nextNewsletter:Ua0.nullable().optional()}),xp2=({subject:A,status:f,content:w,created:Q,sentAt:B,scheduledFor:x,sourceEntities:c,prevNewsletter:I,nextNewsletter:$})=>{let u=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:A}],Y=B??Q,F=B?"Sent":"Created";return KQ(cp2,{children:[KQ(o2,{title:A,description:`Newsletter: ${A}`},void 0,!1,void 0,this),KQ("section",{className:"newsletter-detail-section",children:KQ("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:KQ("div",{className:"max-w-3xl mx-auto",children:[KQ(n4,{items:u},void 0,!1,void 0,this),KQ("h1",{className:"text-3xl md:text-4xl font-bold text-heading leading-tight tracking-tight mb-4",children:A},void 0,!1,void 0,this),KQ("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[KQ(Ec,{status:f},void 0,!1,void 0,this),KQ("span",{children:[F,": ",sQ(Y,{style:"long"})]},void 0,!0,void 0,this),x&&f==="queued"&&KQ("span",{children:["Scheduled for: ",sQ(x,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c&&c.length>0&&KQ(Gf,{variant:"compact",className:"mb-8",children:[KQ("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),KQ("ul",{className:"space-y-1",children:c.map((K)=>KQ("li",{children:KQ("a",{href:K.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:K.title},void 0,!1,void 0,this)},K.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),KQ(vI,{markdown:w},void 0,!1,void 0,this),(I??$)&&KQ("nav",{className:"mt-12 pt-8 border-t border-theme",children:KQ("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[I?KQ(Gf,{href:I.url,variant:"compact",children:[KQ("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),KQ("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:I.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this):KQ("div",{},void 0,!1,void 0,this),$&&KQ(Gf,{href:$.url,variant:"compact",className:"md:text-right",children:[KQ("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),KQ("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:$.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)},Fa0=i0({name:"newsletter-detail",description:"Individual newsletter detail template",schema:Bp2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:xp2}});var Ka0={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.9",description:"Newsletter entity type with AI generation and publish pipeline",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts,.tsx","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@brains/entity-service":"workspace:*","@brains/plugins":"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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var up2=X.object({});class aWA extends Nf{entityType="newsletter";schema=xO;adapter=ua0;constructor(A={}){super("newsletter",Ka0,A,up2)}createGenerationHandler(A){return new oWA(this.logger,A)}getTemplates(){return{generation:Ya0,"newsletter-list":Ha0,"newsletter-detail":Fa0}}getDataSources(){return[new dWA(this.logger.child("NewsletterDataSource"))]}async onRegister(A){this.deferPublishRegistration(A),this.subscribeToPublishExecute(A),this.subscribeToGenerateExecute(A),this.registerEvalHandlers(A),A.messaging.subscribe("system:plugins:ready",async()=>{let f=await A.messaging.send("buttondown:is-configured",{});if(!("noop"in f)&&f.success)await A.messaging.send("plugin:site-builder:slot:register",{pluginId:this.id,slotName:"footer-top",render:()=>$p2(bKA,{variant:"inline"})});return{success:!0}}),this.logger.debug("Newsletter plugin registered")}deferPublishRegistration(A){let f={name:"internal",publish:async()=>({id:"internal"})};A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("publish:register",{entityType:"newsletter",provider:f}),{success:!0}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(f)=>{let{entityType:w,entityId:Q}=f.payload;if(w!=="newsletter")return{success:!0};try{let B=await A.entityService.getEntity("newsletter",Q);if(!B)return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:`Newsletter not found: ${Q}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=await A.messaging.send("buttondown:send",{entityId:Q,subject:B.metadata.subject,content:B.content}),c=new Date().toISOString(),I=!("noop"in x)&&x.data?x.data.emailId:void 0;return await A.entityService.updateEntity({...B,metadata:{...B.metadata,status:"published",sentAt:c,buttondownId:I}}),await A.messaging.send("publish:report:success",{entityType:w,entityId:Q,sentAt:c}),this.logger.info(`Published newsletter: ${Q}`),{success:!0}}catch(B){let x=h0(B);return await A.messaging.send("publish:report:failure",{entityType:w,entityId:Q,error:x}),{success:!0}}})}subscribeToGenerateExecute(A){A.messaging.subscribe("generate:execute",async(f)=>{if(f.payload.entityType!=="newsletter")return{success:!0};try{let w=await A.entityService.listEntities("post",{filter:{metadata:{status:"published"}},limit:10});if(w.length===0)return await A.messaging.send("generate:report:failure",{entityType:"newsletter",error:"No published posts available for newsletter"}),{success:!0};return await A.jobs.enqueue("newsletter:generation",{sourceEntityIds:w.map((Q)=>Q.id),sourceEntityType:"post",addToQueue:!1},{interfaceType:"job",userId:"system"}),{success:!0}}catch(w){return await A.messaging.send("generate:report:failure",{entityType:"newsletter",error:h0(w)}),{success:!0}}})}registerEvalHandlers(A){let f=X.object({prompt:X.string().optional(),content:X.string().optional()});A.eval.registerHandler("generation",async(w)=>{let Q=f.parse(w),B=Q.content?`Create an engaging newsletter based on this content:
26515
26515
 
26516
- ${Q.content}`:Q.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:B,templateName:"newsletter:generation"})})}}function sWA(A={}){return new aWA(A)}B0();YA();class ab{config;logger;constructor(A,f){this.config=A;this.logger=f}async request(A,f={}){let w=`https://api.buttondown.email/v1${A}`;this.logger.debug("Buttondown API request",{endpoint:A,method:f.method??"GET"});let Q=await fetch(w,{...f,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...f.headers}});if(!Q.ok){let B=await Q.json().catch(()=>({})),x=B.detail??B.message??`HTTP ${Q.status}`;throw this.logger.error("Buttondown API error",{endpoint:A,status:Q.status,error:x}),Error(`Buttondown API error: ${x}`)}return Q.json()}async createSubscriber(A){let f={email_address:A.email,type:this.config.doubleOptIn?"unactivated":"regular"};if(A.name)f.metadata={name:A.name};if(A.tags&&A.tags.length>0)f.tags=A.tags;this.logger.info("Creating subscriber",{email:A.email});try{return await this.request("/subscribers",{method:"POST",body:JSON.stringify(f)})}catch(w){if(w instanceof Error&&w.message.includes("already subscribed")){let Q=w.message.match(/id=([a-f0-9-]+)/);return this.logger.info("Subscriber already exists",{email:A.email}),{id:Q?.[1]??"existing",email:A.email,subscriber_type:"already_subscribed"}}throw w}}async unsubscribe(A){this.logger.info("Unsubscribing",{email:A}),await this.request(`/subscribers/${encodeURIComponent(A)}`,{method:"DELETE"})}async listSubscribers(A){let f=new URLSearchParams;if(A?.type)f.set("type",A.type);if(A?.limit)f.set("page_size",String(A.limit));let w=f.toString(),Q=w?`/subscribers?${w}`:"/subscribers";return this.request(Q)}async createEmail(A){let f={subject:A.subject,body:A.body,status:A.status??"draft"};if(A.publish_date)f.publish_date=A.publish_date;return this.logger.info("Creating email",{subject:A.subject,status:A.status??"draft"}),this.request("/emails",{method:"POST",body:JSON.stringify(f)})}async getEmail(A){return this.request(`/emails/${A}`)}async validateCredentials(){try{return await this.request("/subscribers?page_size=1"),!0}catch{return!1}}}B0();YA();var Dp2=X.object({email:X.string().email().describe("Email address to subscribe"),name:X.string().optional().describe("Subscriber name (optional)"),tags:X.array(X.string()).optional().describe("Tags to apply to subscriber (optional)")}),Yp2=X.object({email:X.string().email().describe("Email address to unsubscribe")}),Hp2=X.object({type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:X.number().optional().describe("Maximum number of results")});function Xa0(A,f,w){let Q=new ab(f,w);return[Tf(A,"subscribe","Subscribe an email address to the newsletter. Uses double opt-in by default.",Dp2,async(B)=>{try{let x=await Q.createSubscriber({email:B.email,...B.name&&{name:B.name},...B.tags&&{tags:B.tags}}),c=x.subscriber_type==="already_subscribed";return mB({subscriberId:x.id,email:x.email,status:x.subscriber_type,message:c?"already_subscribed":"subscribed"},c?`${B.email} is already subscribed`:`Subscribed ${B.email} successfully`)}catch(x){return r6(h0(x))}}),Tf(A,"unsubscribe","Unsubscribe an email address from the newsletter.",Yp2,async(B)=>{try{return await Q.unsubscribe(B.email),mB({email:B.email},`Unsubscribed ${B.email} successfully`)}catch(x){return r6(h0(x))}}),Tf(A,"list_subscribers","List newsletter subscribers with optional filtering by status.",Hp2,async(B)=>{try{let x=await Q.listSubscribers({...B.type&&{type:B.type},...B.limit&&{limit:B.limit}});return mB({subscribers:x.results.map((c)=>({id:c.id,email:c.email,status:c.subscriber_type})),count:x.count},`Found ${x.count} subscribers`)}catch(x){return r6(h0(x))}})]}YA();async function Za0(A,f,w,Q){if(A.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let B=await w.getEntity("post",A.entityId);if(!B)return{success:!1,error:`Post ${A.entityId} not found`};Q.info("Auto-sending newsletter for published post",{postId:B.id,title:B.metadata.title});try{let x=await f.createEmail({subject:B.metadata.title,body:B.content,status:"about_to_send"});return Q.info("Newsletter sent for post",{postId:B.id,emailId:x.id}),{success:!0,emailId:x.id}}catch(x){let c=h0(x);return Q.error("Failed to send newsletter for post",{postId:B.id,error:c}),{success:!1,error:c}}}var va0={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.8",description:"Buttondown newsletter integration \u2014 subscriber management and API routes",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Fp2=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 tWA extends yQ{constructor(A={}){super("buttondown",va0,A,Fp2)}async onRegister(A){if(A.messaging.subscribe("buttondown:is-configured",async()=>{return{success:!!this.config.apiKey}}),this.config.apiKey){let f=new ab({apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger);if(A.messaging.subscribe("buttondown:send",async(w)=>{try{return{success:!0,data:{emailId:(await f.createEmail({subject:w.payload.subject,body:w.payload.content,status:"about_to_send"})).id}}}catch(Q){return this.logger.error("Buttondown send failed",{error:h0(Q)}),{success:!1}}}),this.config.autoSendOnPublish)A.messaging.subscribe("publish:completed",async(w)=>{return await Za0(w.payload,f,A.entityService,this.logger),{success:!0}}),this.logger.info("Buttondown auto-send on publish enabled")}}async getTools(){if(!this.config.apiKey)return[];return Xa0(this.id,{apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger)}getApiRoutes(){if(!this.config.apiKey)return[];return[{path:"/subscribe",method:"POST",tool:"subscribe",public:!0,successRedirect:"/subscribe/thanks",errorRedirect:"/subscribe/error"}]}}function eWA(A={}){return new tWA(A)}var Kp2=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 Wa0(A={}){let f=Kp2.parse(A);return[sWA({}),eWA({...f.apiKey!==void 0&&{apiKey:f.apiKey},...f.doubleOptIn!==void 0&&{doubleOptIn:f.doubleOptIn},...f.autoSendOnPublish!==void 0&&{autoSendOnPublish:f.autoSendOnPublish}})]}B0();YA();import{existsSync as Cp2,mkdirSync as Ep2,writeFileSync as Lp2}from"fs";import{join as QY}from"path";YA();var AkA=X.object({baseFolder:X.string().default("_obsidian")});YA();function Xp2(A){let f=A,w=!0,Q=void 0,B=!1,x=!0;while(x){if(x=!1,f instanceof X.ZodOptional)w=!1,f=f._def.innerType,x=!0;if(f instanceof X.ZodDefault)w=!1,B=!0,Q=f._def.defaultValue(),f=f._def.innerType,x=!0;if(f instanceof X.ZodNullable)w=!1,f=f._def.innerType,x=!0}let c={inner:f,required:w};if(B)c.defaultValue=Q;return c}function Zp2(A){if(A instanceof X.ZodEnum)return{type:"enum",enumValues:A._def.values};if(A instanceof X.ZodLiteral)return{type:"string",defaultValue:A._def.value};if(A instanceof X.ZodString)return{type:"string"};if(A instanceof X.ZodNumber)return{type:"number"};if(A instanceof X.ZodBoolean)return{type:"boolean"};if(A instanceof X.ZodArray)return{type:"array"};if(A instanceof X.ZodDate)return{type:"date"};if(A instanceof X.ZodPipeline){if(A._def.out instanceof X.ZodDate)return{type:"date"}}return{type:"unknown"}}function ka0(A){let f=A.shape,w=[];for(let[Q,B]of Object.entries(f)){let{inner:x,required:c,defaultValue:I}=Xp2(B),$=Zp2(x),u={name:Q,type:$.type,required:c},Y=I!==void 0?I:$.defaultValue;if(Y!==void 0)u.defaultValue=Y;if($.enumValues)u.enumValues=$.enumValues;w.push(u)}return w}function vp2(A,f){if(A.name==="entityType")return String(A.defaultValue??f);if(A.name==="title")return'"{{title}}"';if(A.type==="date"&&(A.name==="created"||A.name==="updated"))return'"{{date}}"';if(A.defaultValue!==void 0){if(Array.isArray(A.defaultValue))return"[]";if(typeof A.defaultValue==="boolean")return String(A.defaultValue);if(typeof A.defaultValue==="number")return String(A.defaultValue);return String(A.defaultValue)}if(A.type==="enum"&&A.enumValues&&A.enumValues.length>0)return A.enumValues[0]??"";switch(A.type){case"string":return'""';case"number":return"";case"boolean":return"false";case"array":return"[]";case"date":return'""';default:return'""'}}function ha0(A,f,w=""){let Q=["---"];for(let B of f){let x=vp2(B,A);if(x==="")Q.push(`${B.name}:`);else Q.push(`${B.name}: ${x}`)}if(Q.push("---"),Q.push(""),w)Q.push(w);else Q.push("<!-- Write your content here -->"),Q.push("");return Q.join(`
26516
+ ${Q.content}`:Q.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:B,templateName:"newsletter:generation"})})}}function sWA(A={}){return new aWA(A)}B0();YA();class ab{config;logger;constructor(A,f){this.config=A;this.logger=f}async request(A,f={}){let w=`https://api.buttondown.email/v1${A}`;this.logger.debug("Buttondown API request",{endpoint:A,method:f.method??"GET"});let Q=await fetch(w,{...f,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...f.headers}});if(!Q.ok){let B=await Q.json().catch(()=>({})),x=B.detail??B.message??`HTTP ${Q.status}`;throw this.logger.error("Buttondown API error",{endpoint:A,status:Q.status,error:x}),Error(`Buttondown API error: ${x}`)}return Q.json()}async createSubscriber(A){let f={email_address:A.email,type:this.config.doubleOptIn?"unactivated":"regular"};if(A.name)f.metadata={name:A.name};if(A.tags&&A.tags.length>0)f.tags=A.tags;this.logger.info("Creating subscriber",{email:A.email});try{return await this.request("/subscribers",{method:"POST",body:JSON.stringify(f)})}catch(w){if(w instanceof Error&&w.message.includes("already subscribed")){let Q=w.message.match(/id=([a-f0-9-]+)/);return this.logger.info("Subscriber already exists",{email:A.email}),{id:Q?.[1]??"existing",email:A.email,subscriber_type:"already_subscribed"}}throw w}}async unsubscribe(A){this.logger.info("Unsubscribing",{email:A}),await this.request(`/subscribers/${encodeURIComponent(A)}`,{method:"DELETE"})}async listSubscribers(A){let f=new URLSearchParams;if(A?.type)f.set("type",A.type);if(A?.limit)f.set("page_size",String(A.limit));let w=f.toString(),Q=w?`/subscribers?${w}`:"/subscribers";return this.request(Q)}async createEmail(A){let f={subject:A.subject,body:A.body,status:A.status??"draft"};if(A.publish_date)f.publish_date=A.publish_date;return this.logger.info("Creating email",{subject:A.subject,status:A.status??"draft"}),this.request("/emails",{method:"POST",body:JSON.stringify(f)})}async getEmail(A){return this.request(`/emails/${A}`)}async validateCredentials(){try{return await this.request("/subscribers?page_size=1"),!0}catch{return!1}}}B0();YA();var Dp2=X.object({email:X.string().email().describe("Email address to subscribe"),name:X.string().optional().describe("Subscriber name (optional)"),tags:X.array(X.string()).optional().describe("Tags to apply to subscriber (optional)")}),Yp2=X.object({email:X.string().email().describe("Email address to unsubscribe")}),Hp2=X.object({type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:X.number().optional().describe("Maximum number of results")});function Xa0(A,f,w){let Q=new ab(f,w);return[Tf(A,"subscribe","Subscribe an email address to the newsletter. Uses double opt-in by default.",Dp2,async(B)=>{try{let x=await Q.createSubscriber({email:B.email,...B.name&&{name:B.name},...B.tags&&{tags:B.tags}}),c=x.subscriber_type==="already_subscribed";return mB({subscriberId:x.id,email:x.email,status:x.subscriber_type,message:c?"already_subscribed":"subscribed"},c?`${B.email} is already subscribed`:`Subscribed ${B.email} successfully`)}catch(x){return r6(h0(x))}}),Tf(A,"unsubscribe","Unsubscribe an email address from the newsletter.",Yp2,async(B)=>{try{return await Q.unsubscribe(B.email),mB({email:B.email},`Unsubscribed ${B.email} successfully`)}catch(x){return r6(h0(x))}}),Tf(A,"list_subscribers","List newsletter subscribers with optional filtering by status.",Hp2,async(B)=>{try{let x=await Q.listSubscribers({...B.type&&{type:B.type},...B.limit&&{limit:B.limit}});return mB({subscribers:x.results.map((c)=>({id:c.id,email:c.email,status:c.subscriber_type})),count:x.count},`Found ${x.count} subscribers`)}catch(x){return r6(h0(x))}})]}YA();async function Za0(A,f,w,Q){if(A.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let B=await w.getEntity("post",A.entityId);if(!B)return{success:!1,error:`Post ${A.entityId} not found`};Q.info("Auto-sending newsletter for published post",{postId:B.id,title:B.metadata.title});try{let x=await f.createEmail({subject:B.metadata.title,body:B.content,status:"about_to_send"});return Q.info("Newsletter sent for post",{postId:B.id,emailId:x.id}),{success:!0,emailId:x.id}}catch(x){let c=h0(x);return Q.error("Failed to send newsletter for post",{postId:B.id,error:c}),{success:!1,error:c}}}var va0={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.9",description:"Buttondown newsletter integration \u2014 subscriber management and API routes",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Fp2=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 tWA extends yQ{constructor(A={}){super("buttondown",va0,A,Fp2)}async onRegister(A){if(A.messaging.subscribe("buttondown:is-configured",async()=>{return{success:!!this.config.apiKey}}),this.config.apiKey){let f=new ab({apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger);if(A.messaging.subscribe("buttondown:send",async(w)=>{try{return{success:!0,data:{emailId:(await f.createEmail({subject:w.payload.subject,body:w.payload.content,status:"about_to_send"})).id}}}catch(Q){return this.logger.error("Buttondown send failed",{error:h0(Q)}),{success:!1}}}),this.config.autoSendOnPublish)A.messaging.subscribe("publish:completed",async(w)=>{return await Za0(w.payload,f,A.entityService,this.logger),{success:!0}}),this.logger.info("Buttondown auto-send on publish enabled")}}async getTools(){if(!this.config.apiKey)return[];return Xa0(this.id,{apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger)}getApiRoutes(){if(!this.config.apiKey)return[];return[{path:"/subscribe",method:"POST",tool:"subscribe",public:!0,successRedirect:"/subscribe/thanks",errorRedirect:"/subscribe/error"}]}}function eWA(A={}){return new tWA(A)}var Kp2=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 Wa0(A={}){let f=Kp2.parse(A);return[sWA({}),eWA({...f.apiKey!==void 0&&{apiKey:f.apiKey},...f.doubleOptIn!==void 0&&{doubleOptIn:f.doubleOptIn},...f.autoSendOnPublish!==void 0&&{autoSendOnPublish:f.autoSendOnPublish}})]}B0();YA();import{existsSync as Cp2,mkdirSync as Ep2,writeFileSync as Lp2}from"fs";import{join as QY}from"path";YA();var AkA=X.object({baseFolder:X.string().default("_obsidian")});YA();function Xp2(A){let f=A,w=!0,Q=void 0,B=!1,x=!0;while(x){if(x=!1,f instanceof X.ZodOptional)w=!1,f=f._def.innerType,x=!0;if(f instanceof X.ZodDefault)w=!1,B=!0,Q=f._def.defaultValue(),f=f._def.innerType,x=!0;if(f instanceof X.ZodNullable)w=!1,f=f._def.innerType,x=!0}let c={inner:f,required:w};if(B)c.defaultValue=Q;return c}function Zp2(A){if(A instanceof X.ZodEnum)return{type:"enum",enumValues:A._def.values};if(A instanceof X.ZodLiteral)return{type:"string",defaultValue:A._def.value};if(A instanceof X.ZodString)return{type:"string"};if(A instanceof X.ZodNumber)return{type:"number"};if(A instanceof X.ZodBoolean)return{type:"boolean"};if(A instanceof X.ZodArray)return{type:"array"};if(A instanceof X.ZodDate)return{type:"date"};if(A instanceof X.ZodPipeline){if(A._def.out instanceof X.ZodDate)return{type:"date"}}return{type:"unknown"}}function ka0(A){let f=A.shape,w=[];for(let[Q,B]of Object.entries(f)){let{inner:x,required:c,defaultValue:I}=Xp2(B),$=Zp2(x),u={name:Q,type:$.type,required:c},Y=I!==void 0?I:$.defaultValue;if(Y!==void 0)u.defaultValue=Y;if($.enumValues)u.enumValues=$.enumValues;w.push(u)}return w}function vp2(A,f){if(A.name==="entityType")return String(A.defaultValue??f);if(A.name==="title")return'"{{title}}"';if(A.type==="date"&&(A.name==="created"||A.name==="updated"))return'"{{date}}"';if(A.defaultValue!==void 0){if(Array.isArray(A.defaultValue))return"[]";if(typeof A.defaultValue==="boolean")return String(A.defaultValue);if(typeof A.defaultValue==="number")return String(A.defaultValue);return String(A.defaultValue)}if(A.type==="enum"&&A.enumValues&&A.enumValues.length>0)return A.enumValues[0]??"";switch(A.type){case"string":return'""';case"number":return"";case"boolean":return"false";case"array":return"[]";case"date":return'""';default:return'""'}}function ha0(A,f,w=""){let Q=["---"];for(let B of f){let x=vp2(B,A);if(x==="")Q.push(`${B.name}:`);else Q.push(`${B.name}: ${x}`)}if(Q.push("---"),Q.push(""),w)Q.push(w);else Q.push("<!-- Write your content here -->"),Q.push("");return Q.join(`
26517
26517
  `)}YA();var Wp2={string:"Input",number:"Number",boolean:"Boolean",date:"Date",enum:"Select",array:"Multi",unknown:"Input"};function kp2(A){let f={name:A.name,id:A.name,type:Wp2[A.type]};if(A.type==="enum"&&A.enumValues){let w={};A.enumValues.forEach((Q,B)=>{w[String(B)]=Q}),f.options=w}return f}function Ga0(A,f){let w={filesPaths:A,fields:f.map(kp2)};return`---
26518
26518
  ${k$(w)}---
26519
- `}YA();var hp2=new Set(["entityType"]),Gp2={base:"Notes"},Jp2=new Set(["base"]);function bp2(A){let f=["file.name"];for(let w of A)if(!hp2.has(w.name))f.push(w.name);return f}function zp2(A){return A.some((f)=>f.name==="status"&&f.type==="enum")}function Ja0(A,f){let w=Gp2[A]??sg(A),Q=zp2(f),B=bp2(f),x=[{type:"table",name:`All ${w}`,order:B}];if(Q)x.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:B});let I={filters:{and:[Jp2.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:x};return{filename:`${w}.base`,content:k$(I),hasStatus:Q}}function ba0(A){if(A.length===0)return null;let f=A.map((Q)=>`file.inFolder("${Q}")`),w={filters:{and:[f.length===1?f[0]:{or:f}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return k$(w)}function za0(A){if(A.length===0)return null;let f=A.map((Q)=>`file.inFolder("${Q.entityType}")`),w={filters:{and:[f.length===1?f[0]:{or:f},'status != "published"']},views:[{type:"table",name:"Pipeline",groupBy:{property:"status",direction:"ASC"},order:["file.name","file.folder","status"]}]};return k$(w)}var Na0={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.8",description:"Obsidian vault integration \u2014 generates templates from entity schemas",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var qp2={mkdir:Ep2,writeFile:Lp2,existsFile:Cp2},_p2=X.object({entityTypes:X.array(X.string()).optional().describe("Entity types to generate templates for (default: all)")});class fkA extends yQ{deps;constructor(A={},f={}){super("obsidian-vault",Na0,A,AkA);this.deps={...qp2,...f}}async onRegister(A){A.messaging.subscribe("system:plugins:ready",async()=>{return this.logger.info("Auto-syncing Obsidian templates, fileClasses, and bases"),await this.sync(A),{success:!0}})}async getTools(){let A=this.getContext();return[Tf(this.id,"sync-templates","Generate Obsidian templates, Metadata Menu fileClass definitions, and Bases views for all registered entity types.",_p2,async(f)=>{return this.sync(A,f.entityTypes)})]}async sync(A,f){try{let w=A.entityService.getEntityTypes(),Q=f?w.filter((G)=>f.includes(G)):w,B=QY(A.dataDir,this.config.baseFolder),x=QY(B,"templates"),c=QY(B,"fileClasses"),I=QY(B,"bases");this.deps.mkdir(x,{recursive:!0}),this.deps.mkdir(c,{recursive:!0}),this.deps.mkdir(I,{recursive:!0});let $=[],u=[],Y=[],F=[],K=[],Z=[];for(let G of Q){let E=A.entities.getEffectiveFrontmatterSchema(G);if(!E){this.logger.debug(`Skipping ${G}: no frontmatter schema`),u.push(G);continue}let V=ka0(E),q=A.entities.getAdapter(G),y=q?.isSingleton===!0,r=Ga0(G,V);if(this.deps.writeFile(QY(c,`${G}.md`),r),Y.push(G),y){K.push(G),this.logger.debug(`Generated fileClass (singleton): ${G}`);continue}let g=q?.getBodyTemplate()??"",M=ha0(G,V,g);this.deps.writeFile(QY(x,`${G}.md`),M),$.push(G);let j=Ja0(G,V),P=QY(I,j.filename);if(!this.deps.existsFile(P))this.deps.writeFile(P,j.content),F.push(G),this.logger.debug(`Generated base: ${j.filename}`);if(j.hasStatus)Z.push({entityType:G,fields:V});this.logger.debug(`Generated template + fileClass: ${G}`)}let k=ba0(K);if(k){let G=QY(I,"Settings.base");if(!this.deps.existsFile(G))this.deps.writeFile(G,k),F.push("Settings"),this.logger.debug("Generated Settings.base")}let h=za0(Z);if(h){let G=QY(I,"Pipeline.base");if(!this.deps.existsFile(G))this.deps.writeFile(G,h),F.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${$.length} templates, ${Y.length} fileClasses, ${F.length} bases (${u.length} skipped)`),mB({generated:$,skipped:u,fileClasses:Y,bases:F})}catch(w){return this.logger.error("Failed to sync",{error:w}),r6(w instanceof Error?w.message:"Unknown error")}}}function wkA(A,f){return new fkA(A,f)}B0();YA();B0();var QkA=X.enum(["new","planned","in-progress","done","declined"]),BkA=X.enum(["low","medium","high","critical"]),cO=X.object({title:X.string(),status:QkA,priority:BkA.default("medium"),requested:X.number().int().default(1),tags:X.array(X.string()).default([]),declinedReason:X.string().optional()}),Ca0=X.object({title:X.string(),status:QkA,priority:BkA,requested:X.number().int(),slug:X.string()}),IO=v2.extend({entityType:X.literal("wish"),metadata:Ca0}),xkA=X.object({});B0();YA();class $O extends _2{constructor(){super({entityType:"wish",schema:IO,frontmatterSchema:cO})}createWishContent(A,f){return this.buildMarkdown(f,A)}parseWishContent(A){let f=this.parseFrontMatter(A,cO);return{frontmatter:cO.parse(f),description:this.extractBody(A).trim()}}toMarkdown(A){return A.content}fromMarkdown(A){let{frontmatter:f}=this.parseWishContent(A),w=x2(f.title);return{content:A,entityType:"wish",metadata:{title:f.title,status:f.status,priority:f.priority,requested:f.requested,slug:w}}}}var ckA=new $O;YA();YA();async function Ea0(A,f){let w=`${f.title}: ${f.description}`,B=(await A.search(w,{types:["wish"],limit:1}))[0];if(B&&B.score>=A.similarityThreshold)return B.entity;let x=x2(f.title);return A.getEntity("wish",x)}class IkA{logger;context;adapter=new $O;constructor(A,f){this.logger=A;this.context=f}async process(A,f,w){let Q=A.title??A.prompt??"Untitled wish",B=A.content??A.prompt??"",x=await Ea0({search:(u,Y)=>this.context.entityService.search(u,Y),getEntity:(u,Y)=>this.context.entityService.getEntity(u,Y),similarityThreshold:0.85},{title:Q,description:B});if(x){let{frontmatter:u,description:Y}=this.adapter.parseWishContent(x.content),F=u.requested+1,K=this.adapter.createWishContent({...u,requested:F},Y);return await this.context.entityService.updateEntity({...x,content:K,metadata:{...x.metadata,requested:F}}),this.logger.info("Incremented wish request count",{id:x.id,requested:F}),{success:!0,entityId:x.id,existed:!0,requested:F}}let c=x2(Q),I=A.options?.priority??"medium",$=this.adapter.createWishContent({title:Q,status:"new",priority:I,requested:1,tags:A.options?.tags??[]},B);return await this.context.entityService.createEntity({id:c,entityType:"wish",content:$,metadata:{title:Q,status:"new",priority:I,requested:1,slug:c}}),this.logger.info("Created new wish",{id:c,title:Q}),{success:!0,entityId:c,existed:!1,requested:1}}}var La0={critical:0,high:1,medium:2,low:3};function qa0(A){A.sort((f,w)=>{let Q=w.metadata.requested-f.metadata.requested;if(Q!==0)return Q;return La0[f.metadata.priority]-La0[w.metadata.priority]})}var _a0={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.8",description:"Wishlist plugin for tracking unfulfilled user requests",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class Va0 extends Nf{entityType=ckA.entityType;schema=IO;adapter=ckA;constructor(A={}){super("wishlist",_a0,A,xkA)}async onRegister(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("dashboard:register-widget",{id:"top-wishes",pluginId:this.id,title:"Top Wishes",section:"secondary",priority:30,rendererName:"ListWidget",dataProvider:async()=>{let w=await A.entityService.listEntities("wish",{limit:10});return qa0(w),{items:w.map((Q)=>({id:Q.id,name:Q.metadata.title,count:Q.metadata.requested,priority:Q.metadata.priority,status:Q.metadata.status}))}}}),{success:!0}});let f=new IkA(this.logger,A);A.jobs.registerHandler("wish:create",{process:f.process.bind(f),validateAndParse:(w)=>w})}async getInstructions(){return"**CRITICAL \u2014 Unfulfilled requests**: ALWAYS call `system_create` with entityType "+`"wish" BEFORE responding when you cannot fulfill a user's request. This applies to ALL unfulfillable requests: physical actions, missing integrations, and any capability `+"you lack. Do NOT just explain you can't do it \u2014 create the wish first, THEN respond. "+"In your response, tell the user their request has been added to the wishlist."}}function ip2(A={}){return new Va0(A)}var ya=ip2;B0();YA();B0();var uO=X.object({title:X.string(),target:X.string()}),ia0=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),DO=v2.extend({entityType:X.literal("prompt"),metadata:ia0});B0();YA();class $kA extends _2{constructor(){super({entityType:"prompt",schema:DO,frontmatterSchema:uO})}toMarkdown(A){let f=this.extractBody(A.content),w=this.parseFrontMatter(A.content,uO);return this.buildMarkdown(f,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,uO),w=x2(f.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:f.title,target:f.target,slug:w}}}}var Sa=new $kA;var Ma0={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.8",description:"Prompt entity type \u2014 AI prompts as editable markdown entities",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"latest",typescript:"^5.3.3"}};class ukA extends Nf{entityType=Sa.entityType;schema=DO;adapter=Sa;constructor(){super("prompt",Ma0,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function Vv(){return new ukA}B0();YA();class pa{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(A,f){this.apiKey=A,this.fetchFn=f}async searchPhotos(A,f){let w=new URL(`${this.baseUrl}/search/photos`);w.searchParams.set("query",A),w.searchParams.set("page",String(f.page)),w.searchParams.set("per_page",String(f.perPage));let Q=await this.fetchFn(w.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!Q.ok)throw Error(`Unsplash API error: ${Q.status} ${Q.statusText}`);let B=await Q.json();return{photos:B.results.map(Op2),total:B.total,totalPages:B.total_pages,page:f.page}}async triggerDownload(A){try{await this.fetchFn(A,{headers:{Authorization:`Client-ID ${this.apiKey}`}})}catch{}}}function Op2(A){return{id:A.id,description:A.description,altDescription:A.alt_description,thumbnailUrl:A.urls.thumb,imageUrl:A.urls.regular,photographerName:A.user.name,photographerUrl:A.user.links.html,sourceUrl:A.links.html,downloadLocation:A.links.download_location,width:A.width,height:A.height}}YA();var Oa0={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")},ja0={photoId:X.string().describe("Photo ID from search results"),downloadLocation:X.string().url().describe("Download tracking URL (required by provider ToS)"),photographerName:X.string().describe("Photographer name for attribution"),photographerUrl:X.string().url().describe("Photographer profile URL for attribution"),sourceUrl:X.string().url().describe("Photo page URL on provider"),imageUrl:X.string().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 Pa0(A,f){return[jp2(A,f),gp2(A,f)]}function jp2(A,f){return{name:`${A}_search`,description:"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.",inputSchema:Oa0,handler:async(w)=>{let Q=X.object(Oa0).safeParse(w);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};try{return{success:!0,data:await f.provider.searchPhotos(Q.data.query,{page:Q.data.page,perPage:Q.data.perPage})}}catch(B){return{success:!1,error:B instanceof Error?B.message:"Search failed"}}}}}function gp2(A,f){return{name:`${A}_select`,description:"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.",inputSchema:ja0,handler:async(w)=>{let Q=X.object(ja0).safeParse(w);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};let{photoId:B,downloadLocation:x,photographerName:c,photographerUrl:I,sourceUrl:$,imageUrl:u,title:Y,alt:F,targetEntityType:K,targetEntityId:Z}=Q.data,k={photographerName:c,photographerUrl:I,sourceUrl:$},h=await f.entityService.listEntities("image",{limit:1,filter:{metadata:{sourceUrl:u}}});if(h[0]){let g={imageEntityId:h[0].id,alreadyExisted:!0,attribution:k};if(K&&Z)await ga0(f.entityService,K,Z,h[0].id),g.coverSet=!0;return{success:!0,data:g}}f.provider.triggerDownload(x).catch(()=>{});let G;try{G=await f.fetchImage(u)}catch(g){return{success:!1,error:g instanceof Error?g.message:"Image download failed"}}let E=Y??`Stock photo ${B}`,V=dH.createImageEntity({dataUrl:G,title:E,alt:F??E}),q={id:B,...V,metadata:{...V.metadata,sourceUrl:u}},{entityId:y}=await f.entityService.createEntity(q),r={imageEntityId:y,alreadyExisted:!1,attribution:k};if(K&&Z)await ga0(f.entityService,K,Z,y),r.coverSet=!0;return{success:!0,data:r}}}}async function ga0(A,f,w,Q){let B=await A.getEntity(f,w);if(!B)return;await A.updateEntity({...B,metadata:{...B.metadata,coverImageId:Q}})}YA();var Ra0={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.8",description:"Stock photo search and selection \u2014 Unsplash provider",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Rp2=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class DkA extends yQ{deps;cachedTools=null;constructor(A={},f={}){super("stock-photo",Ra0,A,Rp2);this.deps=f}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),f=new pa(this.config.apiKey,this.deps.fetch??globalThis.fetch);return this.cachedTools=Pa0(this.id,{provider:f,entityService:A.entityService,fetchImage:this.deps.fetchImage??Bc}),this.cachedTools}}function YkA(A={},f={}){return new DkA(A,f)}YA();B0();YA();B0();var na0=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),KF=l7.pick({name:!0,kind:!0,organization:!0}).extend({brainName:X.string().optional().describe("Name of the brain"),url:X.string().url().describe("Brain endpoint URL"),did:X.string().optional().describe("Decentralized identifier (public)"),status:X.enum(["active","archived"]).describe("Active or archived"),discoveredAt:X.string().datetime().describe("When this agent was first discovered"),discoveredVia:X.enum(["atproto","manual"]).describe("How this agent was discovered")}),ma0=KF.pick({name:!0,url:!0,status:!0}).extend({slug:X.string()}),sb=v2.extend({entityType:X.literal("agent"),metadata:ma0}),YO=sb.extend({frontmatter:KF,about:X.string(),skills:X.array(na0),notes:X.string()}),tb=YO.extend({url:X.string().optional(),typeLabel:X.string().optional()}),np2=YO.extend({url:X.string(),typeLabel:X.string()});B0();YA();var mp2=X.object({about:X.string(),skills:X.array(X.object({name:X.string(),description:X.string(),tags:X.array(X.string())})),notes:X.string()});function lp2(A){if(!Array.isArray(A)||A.length===0)return"";return A.map((w)=>{let Q=w.tags.length>0?` [${w.tags.join(", ")}]`:"";return`- ${w.name}: ${w.description}${Q}`}).join(`
26519
+ `}YA();var hp2=new Set(["entityType"]),Gp2={base:"Notes"},Jp2=new Set(["base"]);function bp2(A){let f=["file.name"];for(let w of A)if(!hp2.has(w.name))f.push(w.name);return f}function zp2(A){return A.some((f)=>f.name==="status"&&f.type==="enum")}function Ja0(A,f){let w=Gp2[A]??sg(A),Q=zp2(f),B=bp2(f),x=[{type:"table",name:`All ${w}`,order:B}];if(Q)x.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:B});let I={filters:{and:[Jp2.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:x};return{filename:`${w}.base`,content:k$(I),hasStatus:Q}}function ba0(A){if(A.length===0)return null;let f=A.map((Q)=>`file.inFolder("${Q}")`),w={filters:{and:[f.length===1?f[0]:{or:f}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return k$(w)}function za0(A){if(A.length===0)return null;let f=A.map((Q)=>`file.inFolder("${Q.entityType}")`),w={filters:{and:[f.length===1?f[0]:{or:f},'status != "published"']},views:[{type:"table",name:"Pipeline",groupBy:{property:"status",direction:"ASC"},order:["file.name","file.folder","status"]}]};return k$(w)}var Na0={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.9",description:"Obsidian vault integration \u2014 generates templates from entity schemas",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var qp2={mkdir:Ep2,writeFile:Lp2,existsFile:Cp2},_p2=X.object({entityTypes:X.array(X.string()).optional().describe("Entity types to generate templates for (default: all)")});class fkA extends yQ{deps;constructor(A={},f={}){super("obsidian-vault",Na0,A,AkA);this.deps={...qp2,...f}}async onRegister(A){A.messaging.subscribe("system:plugins:ready",async()=>{return this.logger.info("Auto-syncing Obsidian templates, fileClasses, and bases"),await this.sync(A),{success:!0}})}async getTools(){let A=this.getContext();return[Tf(this.id,"sync-templates","Generate Obsidian templates, Metadata Menu fileClass definitions, and Bases views for all registered entity types.",_p2,async(f)=>{return this.sync(A,f.entityTypes)})]}async sync(A,f){try{let w=A.entityService.getEntityTypes(),Q=f?w.filter((G)=>f.includes(G)):w,B=QY(A.dataDir,this.config.baseFolder),x=QY(B,"templates"),c=QY(B,"fileClasses"),I=QY(B,"bases");this.deps.mkdir(x,{recursive:!0}),this.deps.mkdir(c,{recursive:!0}),this.deps.mkdir(I,{recursive:!0});let $=[],u=[],Y=[],F=[],K=[],Z=[];for(let G of Q){let E=A.entities.getEffectiveFrontmatterSchema(G);if(!E){this.logger.debug(`Skipping ${G}: no frontmatter schema`),u.push(G);continue}let V=ka0(E),q=A.entities.getAdapter(G),y=q?.isSingleton===!0,r=Ga0(G,V);if(this.deps.writeFile(QY(c,`${G}.md`),r),Y.push(G),y){K.push(G),this.logger.debug(`Generated fileClass (singleton): ${G}`);continue}let g=q?.getBodyTemplate()??"",M=ha0(G,V,g);this.deps.writeFile(QY(x,`${G}.md`),M),$.push(G);let j=Ja0(G,V),P=QY(I,j.filename);if(!this.deps.existsFile(P))this.deps.writeFile(P,j.content),F.push(G),this.logger.debug(`Generated base: ${j.filename}`);if(j.hasStatus)Z.push({entityType:G,fields:V});this.logger.debug(`Generated template + fileClass: ${G}`)}let k=ba0(K);if(k){let G=QY(I,"Settings.base");if(!this.deps.existsFile(G))this.deps.writeFile(G,k),F.push("Settings"),this.logger.debug("Generated Settings.base")}let h=za0(Z);if(h){let G=QY(I,"Pipeline.base");if(!this.deps.existsFile(G))this.deps.writeFile(G,h),F.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${$.length} templates, ${Y.length} fileClasses, ${F.length} bases (${u.length} skipped)`),mB({generated:$,skipped:u,fileClasses:Y,bases:F})}catch(w){return this.logger.error("Failed to sync",{error:w}),r6(w instanceof Error?w.message:"Unknown error")}}}function wkA(A,f){return new fkA(A,f)}B0();YA();B0();var QkA=X.enum(["new","planned","in-progress","done","declined"]),BkA=X.enum(["low","medium","high","critical"]),cO=X.object({title:X.string(),status:QkA,priority:BkA.default("medium"),requested:X.number().int().default(1),tags:X.array(X.string()).default([]),declinedReason:X.string().optional()}),Ca0=X.object({title:X.string(),status:QkA,priority:BkA,requested:X.number().int(),slug:X.string()}),IO=v2.extend({entityType:X.literal("wish"),metadata:Ca0}),xkA=X.object({});B0();YA();class $O extends _2{constructor(){super({entityType:"wish",schema:IO,frontmatterSchema:cO})}createWishContent(A,f){return this.buildMarkdown(f,A)}parseWishContent(A){let f=this.parseFrontMatter(A,cO);return{frontmatter:cO.parse(f),description:this.extractBody(A).trim()}}toMarkdown(A){return A.content}fromMarkdown(A){let{frontmatter:f}=this.parseWishContent(A),w=x2(f.title);return{content:A,entityType:"wish",metadata:{title:f.title,status:f.status,priority:f.priority,requested:f.requested,slug:w}}}}var ckA=new $O;YA();YA();async function Ea0(A,f){let w=`${f.title}: ${f.description}`,B=(await A.search(w,{types:["wish"],limit:1}))[0];if(B&&B.score>=A.similarityThreshold)return B.entity;let x=x2(f.title);return A.getEntity("wish",x)}class IkA{logger;context;adapter=new $O;constructor(A,f){this.logger=A;this.context=f}async process(A,f,w){let Q=A.title??A.prompt??"Untitled wish",B=A.content??A.prompt??"",x=await Ea0({search:(u,Y)=>this.context.entityService.search(u,Y),getEntity:(u,Y)=>this.context.entityService.getEntity(u,Y),similarityThreshold:0.85},{title:Q,description:B});if(x){let{frontmatter:u,description:Y}=this.adapter.parseWishContent(x.content),F=u.requested+1,K=this.adapter.createWishContent({...u,requested:F},Y);return await this.context.entityService.updateEntity({...x,content:K,metadata:{...x.metadata,requested:F}}),this.logger.info("Incremented wish request count",{id:x.id,requested:F}),{success:!0,entityId:x.id,existed:!0,requested:F}}let c=x2(Q),I=A.options?.priority??"medium",$=this.adapter.createWishContent({title:Q,status:"new",priority:I,requested:1,tags:A.options?.tags??[]},B);return await this.context.entityService.createEntity({id:c,entityType:"wish",content:$,metadata:{title:Q,status:"new",priority:I,requested:1,slug:c}}),this.logger.info("Created new wish",{id:c,title:Q}),{success:!0,entityId:c,existed:!1,requested:1}}}var La0={critical:0,high:1,medium:2,low:3};function qa0(A){A.sort((f,w)=>{let Q=w.metadata.requested-f.metadata.requested;if(Q!==0)return Q;return La0[f.metadata.priority]-La0[w.metadata.priority]})}var _a0={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.9",description:"Wishlist plugin for tracking unfulfilled user requests",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class Va0 extends Nf{entityType=ckA.entityType;schema=IO;adapter=ckA;constructor(A={}){super("wishlist",_a0,A,xkA)}async onRegister(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send("dashboard:register-widget",{id:"top-wishes",pluginId:this.id,title:"Top Wishes",section:"secondary",priority:30,rendererName:"ListWidget",dataProvider:async()=>{let w=await A.entityService.listEntities("wish",{limit:10});return qa0(w),{items:w.map((Q)=>({id:Q.id,name:Q.metadata.title,count:Q.metadata.requested,priority:Q.metadata.priority,status:Q.metadata.status}))}}}),{success:!0}});let f=new IkA(this.logger,A);A.jobs.registerHandler("wish:create",{process:f.process.bind(f),validateAndParse:(w)=>w})}async getInstructions(){return"**CRITICAL \u2014 Unfulfilled requests**: ALWAYS call `system_create` with entityType "+`"wish" BEFORE responding when you cannot fulfill a user's request. This applies to ALL unfulfillable requests: physical actions, missing integrations, and any capability `+"you lack. Do NOT just explain you can't do it \u2014 create the wish first, THEN respond. "+"In your response, tell the user their request has been added to the wishlist."}}function ip2(A={}){return new Va0(A)}var ya=ip2;B0();YA();B0();var uO=X.object({title:X.string(),target:X.string()}),ia0=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),DO=v2.extend({entityType:X.literal("prompt"),metadata:ia0});B0();YA();class $kA extends _2{constructor(){super({entityType:"prompt",schema:DO,frontmatterSchema:uO})}toMarkdown(A){let f=this.extractBody(A.content),w=this.parseFrontMatter(A.content,uO);return this.buildMarkdown(f,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,uO),w=x2(f.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:f.title,target:f.target,slug:w}}}}var Sa=new $kA;var Ma0={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.9",description:"Prompt entity type \u2014 AI prompts as editable markdown entities",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"latest",typescript:"^5.3.3"}};class ukA extends Nf{entityType=Sa.entityType;schema=DO;adapter=Sa;constructor(){super("prompt",Ma0,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function Vv(){return new ukA}B0();YA();class pa{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(A,f){this.apiKey=A,this.fetchFn=f}async searchPhotos(A,f){let w=new URL(`${this.baseUrl}/search/photos`);w.searchParams.set("query",A),w.searchParams.set("page",String(f.page)),w.searchParams.set("per_page",String(f.perPage));let Q=await this.fetchFn(w.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!Q.ok)throw Error(`Unsplash API error: ${Q.status} ${Q.statusText}`);let B=await Q.json();return{photos:B.results.map(Op2),total:B.total,totalPages:B.total_pages,page:f.page}}async triggerDownload(A){try{await this.fetchFn(A,{headers:{Authorization:`Client-ID ${this.apiKey}`}})}catch{}}}function Op2(A){return{id:A.id,description:A.description,altDescription:A.alt_description,thumbnailUrl:A.urls.thumb,imageUrl:A.urls.regular,photographerName:A.user.name,photographerUrl:A.user.links.html,sourceUrl:A.links.html,downloadLocation:A.links.download_location,width:A.width,height:A.height}}YA();var Oa0={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")},ja0={photoId:X.string().describe("Photo ID from search results"),downloadLocation:X.string().url().describe("Download tracking URL (required by provider ToS)"),photographerName:X.string().describe("Photographer name for attribution"),photographerUrl:X.string().url().describe("Photographer profile URL for attribution"),sourceUrl:X.string().url().describe("Photo page URL on provider"),imageUrl:X.string().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 Pa0(A,f){return[jp2(A,f),gp2(A,f)]}function jp2(A,f){return{name:`${A}_search`,description:"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.",inputSchema:Oa0,handler:async(w)=>{let Q=X.object(Oa0).safeParse(w);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};try{return{success:!0,data:await f.provider.searchPhotos(Q.data.query,{page:Q.data.page,perPage:Q.data.perPage})}}catch(B){return{success:!1,error:B instanceof Error?B.message:"Search failed"}}}}}function gp2(A,f){return{name:`${A}_select`,description:"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.",inputSchema:ja0,handler:async(w)=>{let Q=X.object(ja0).safeParse(w);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};let{photoId:B,downloadLocation:x,photographerName:c,photographerUrl:I,sourceUrl:$,imageUrl:u,title:Y,alt:F,targetEntityType:K,targetEntityId:Z}=Q.data,k={photographerName:c,photographerUrl:I,sourceUrl:$},h=await f.entityService.listEntities("image",{limit:1,filter:{metadata:{sourceUrl:u}}});if(h[0]){let g={imageEntityId:h[0].id,alreadyExisted:!0,attribution:k};if(K&&Z)await ga0(f.entityService,K,Z,h[0].id),g.coverSet=!0;return{success:!0,data:g}}f.provider.triggerDownload(x).catch(()=>{});let G;try{G=await f.fetchImage(u)}catch(g){return{success:!1,error:g instanceof Error?g.message:"Image download failed"}}let E=Y??`Stock photo ${B}`,V=dH.createImageEntity({dataUrl:G,title:E,alt:F??E}),q={id:B,...V,metadata:{...V.metadata,sourceUrl:u}},{entityId:y}=await f.entityService.createEntity(q),r={imageEntityId:y,alreadyExisted:!1,attribution:k};if(K&&Z)await ga0(f.entityService,K,Z,y),r.coverSet=!0;return{success:!0,data:r}}}}async function ga0(A,f,w,Q){let B=await A.getEntity(f,w);if(!B)return;await A.updateEntity({...B,metadata:{...B.metadata,coverImageId:Q}})}YA();var Ra0={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.9",description:"Stock photo search and selection \u2014 Unsplash provider",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint src test --ext .ts","lint:fix":"eslint src test --ext .ts --fix"},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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Rp2=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class DkA extends yQ{deps;cachedTools=null;constructor(A={},f={}){super("stock-photo",Ra0,A,Rp2);this.deps=f}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),f=new pa(this.config.apiKey,this.deps.fetch??globalThis.fetch);return this.cachedTools=Pa0(this.id,{provider:f,entityService:A.entityService,fetchImage:this.deps.fetchImage??Bc}),this.cachedTools}}function YkA(A={},f={}){return new DkA(A,f)}YA();B0();YA();B0();var na0=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),KF=l7.pick({name:!0,kind:!0,organization:!0}).extend({brainName:X.string().optional().describe("Name of the brain"),url:X.string().url().describe("Brain endpoint URL"),did:X.string().optional().describe("Decentralized identifier (public)"),status:X.enum(["active","archived"]).describe("Active or archived"),discoveredAt:X.string().datetime().describe("When this agent was first discovered"),discoveredVia:X.enum(["atproto","manual"]).describe("How this agent was discovered")}),ma0=KF.pick({name:!0,url:!0,status:!0}).extend({slug:X.string()}),sb=v2.extend({entityType:X.literal("agent"),metadata:ma0}),YO=sb.extend({frontmatter:KF,about:X.string(),skills:X.array(na0),notes:X.string()}),tb=YO.extend({url:X.string().optional(),typeLabel:X.string().optional()}),np2=YO.extend({url:X.string(),typeLabel:X.string()});B0();YA();var mp2=X.object({about:X.string(),skills:X.array(X.object({name:X.string(),description:X.string(),tags:X.array(X.string())})),notes:X.string()});function lp2(A){if(!Array.isArray(A)||A.length===0)return"";return A.map((w)=>{let Q=w.tags.length>0?` [${w.tags.join(", ")}]`:"";return`- ${w.name}: ${w.description}${Q}`}).join(`
26520
26520
  `)}function Tp2(A){if(!A.trim())return[];let f=[];for(let w of A.split(`
26521
26521
  `)){let Q=w.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/);if(Q){let B=Q[1]??"",x=Q[2]??"",c=Q[3],I=c?c.split(",").map(($)=>$.trim()).filter(Boolean):[];f.push({name:B,description:x,tags:I})}}return f}var la0=new R1(mp2,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:lp2,parser:Tp2},{key:"notes",label:"Notes",type:"string"}]});class XF extends _2{constructor(){super({entityType:"agent",schema:sb,frontmatterSchema:KF})}toMarkdown(A){return A.content}fromMarkdown(A){let f=this.parseFrontMatter(A,KF),w=kk(f.url);return{content:A,entityType:"agent",metadata:{name:f.name,url:f.url,status:f.status,slug:w}}}createAgentContent(A){let f={name:A.name,kind:A.kind,...A.organization&&{organization:A.organization},...A.brainName&&{brainName:A.brainName},url:A.url,...A.did&&{did:A.did},status:A.status,discoveredAt:A.discoveredAt,discoveredVia:A.discoveredVia},w=la0.format({about:A.about,skills:A.skills,notes:A.notes});return this.buildMarkdown(w,f)}parseAgentContent(A){let f=this.stripFrontmatter(A);if(!f.trim())return{about:"",skills:[],notes:""};try{let w=la0.parse(f);return{about:w.about,skills:w.skills,notes:w.notes}}catch{return{about:"",skills:[],notes:""}}}stripFrontmatter(A){let f=A.match(/^---\n[\s\S]*?\n---\n?([\s\S]*)$/);return f?f[1]??"":A}}B0();var yp2=new XF;function Sp2(A){let f=K2(A.content,KF),w=yp2.parseAgentContent(A.content);return YO.parse({...A,frontmatter:f.metadata,about:w.about,skills:w.skills,notes:w.notes})}class ra extends U6{id="agent-discovery:entities";name="Agent Directory DataSource";description="Fetches and transforms agent entities for rendering";config={entityType:"agent",defaultSort:[{field:"discoveredAt",direction:"desc"}],defaultLimit:50,lookupField:"slug",enableNavigation:!0};constructor(A){super(A)}transformEntity(A){return Sp2(A)}buildDetailResult(A,f){return{agent:A,prevAgent:f?.prev??null,nextAgent:f?.next??null}}buildListResult(A,f,w){return{agents:A,pagination:f,baseUrl:w.baseUrl}}}B0();YA();B0();async function da(A,f){let Q=`${(A.startsWith("http")?A:`https://${A}`).replace(/\/$/,"")}/.well-known/agent-card.json`;try{let B=await f(Q);if(!B.ok)return null;let x=await B.json();return RC(x)}catch{return null}}function Ta0(A){let f=A.trim();if(f.startsWith("http://")||f.startsWith("https://"))try{return new URL(f).hostname}catch{return f}let w=f.match(/https?:\/\/[^\s]+?(?=[.,;:!?)]*(?:\s|$))/);if(w)try{return new URL(w[0]).hostname}catch{return w[0]}if(/^[^\s]+\.[^\s]+$/.test(f))return f;return""}YA();var pp2=new XF;function oa(A){let f=A.anchor?.name??A.brainName,w=A.anchor?.kind??"professional",Q=[];if(A.anchor?.description)Q.push(A.anchor.description);if(A.description)Q.push(A.description);return{content:pp2.createAgentContent({name:f,kind:w,...A.anchor?.organization&&{organization:A.anchor.organization},brainName:A.brainName,url:A.url,status:"active",discoveredAt:new Date().toISOString(),discoveredVia:"manual",about:Q.join(`
26522
26522
 
26523
- `),skills:A.skills.map((x)=>({name:x.name,description:x.description,tags:x.tags})),notes:""}),metadata:{name:f,url:A.url,status:"active",slug:kk(A.url)},anchorName:f}}var rp2=X.object({prompt:X.string().optional(),url:X.string().optional(),content:X.string().optional(),skipAi:X.boolean().optional()}),UVw=xc.extend({name:X.string().optional(),domain:X.string().optional()});class HkA extends Cx{constructor(A,f){super(A,f,{schema:rp2,jobTypeName:"agent-generation",entityType:"agent"})}async generate(A,f){let w=A.url??A.prompt??"",Q=Ta0(w);if(!Q)throw Error("No URL or domain provided. Use: system_create agent with a domain like yeehaa.io");let B=await da(Q,globalThis.fetch);if(!B)throw Error(`Could not fetch Agent Card from ${Q}. Make sure the agent is running and accessible.`);let{content:x,metadata:c,anchorName:I}=oa(B);return{id:Q,content:x,metadata:c,title:I}}}B0();P2();YA();import{jsxDEV as ya0}from"preact/jsx-dev-runtime";function aa(A){try{return new URL(A).hostname}catch{return A}}var sa=({name:A,className:f=""})=>{let w=A.charAt(0).toUpperCase(),Q=0;for(let x=0;x<A.length;x++)Q=A.charCodeAt(x)+((Q<<5)-Q);let B=Math.abs(Q)%360;return ya0("div",{className:`flex items-center justify-center rounded-full text-white font-bold flex-shrink-0 ${f}`,style:{backgroundColor:`hsl(${B}, 55%, 45%)`},children:w},void 0,!1,void 0,this)},ta=({kind:A,size:f="md"})=>{let Q={professional:"bg-status-success text-status-success",team:"bg-status-info text-status-info",collective:"bg-brand/10 text-brand"}[A]??"bg-status-neutral text-status-neutral";return ya0("span",{className:`inline-flex items-center rounded-full font-medium ${f==="sm"?"px-2 py-0.5 text-xs":"px-2.5 py-0.5 text-[13px]"} ${Q}`,children:A},void 0,!1,void 0,this)};import{jsxDEV as XQ,Fragment as sp2}from"preact/jsx-dev-runtime";var dp2=({skills:A})=>{if(A.length===0)return null;return XQ("div",{className:"flex gap-1.5 flex-wrap mt-2",children:A.map((f)=>XQ("span",{className:"text-[11px] px-2 py-0.5 bg-theme-subtle rounded-md text-theme-muted",children:f.name},f.name,!1,void 0,this))},void 0,!1,void 0,this)};function op2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var ap2=({agent:A})=>{let{frontmatter:f,about:w,skills:Q,url:B}=A,x=f.status==="archived";return XQ("a",{href:B,className:`flex items-start gap-5 p-6 rounded-xl border border-theme bg-theme-subtle hover:shadow-lg transition-shadow ${x?"opacity-40":""}`,children:[XQ(sa,{name:f.name,className:"w-12 h-12 text-lg"},void 0,!1,void 0,this),XQ("div",{className:"flex-1 min-w-0",children:[XQ("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[XQ("span",{className:"text-lg font-semibold text-heading",children:f.name},void 0,!1,void 0,this),XQ(ta,{kind:x?"archived":f.kind,size:"sm"},void 0,!1,void 0,this),f.organization&&XQ("span",{className:"text-xs text-theme-muted",children:["\xB7 ",f.organization]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w&&XQ("p",{className:"text-sm text-theme-muted line-clamp-2 mb-0",children:w},void 0,!1,void 0,this),!x&&XQ(dp2,{skills:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),XQ("div",{className:"flex flex-col items-end gap-1 flex-shrink-0 text-right",children:[XQ("span",{className:"text-xs text-theme-muted",children:aa(f.url)},void 0,!1,void 0,this),XQ("span",{className:"text-[11px] text-theme-muted opacity-60",children:x?"Archived":`Discovered ${op2(f.discoveredAt)}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},Sa0=({agents:A,pageTitle:f,pagination:w,baseUrl:Q="/agents"})=>{let B=f??"Agent Directory",x=w?.totalItems??A.length,c=`Your network of ${x} ${x===1?"brain":"brains"} and their anchors`;return XQ(sp2,{children:[XQ(o2,{title:B,description:c},void 0,!1,void 0,this),XQ("div",{className:"agent-list bg-theme",children:XQ("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[XQ("div",{className:"mb-8 pb-6 border-b border-theme",children:[XQ("h1",{className:"text-4xl font-bold text-heading mb-2",children:B},void 0,!1,void 0,this),XQ("p",{className:"text-theme-muted",children:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this),XQ("div",{className:"flex flex-col gap-4",children:A.map((I)=>XQ(ap2,{agent:I},I.id,!1,void 0,this))},void 0,!1,void 0,this),A.length===0&&XQ("p",{className:"text-center text-theme-muted py-16",children:"No agents in your directory yet."},void 0,!1,void 0,this),w&&w.totalPages>1&&XQ("div",{className:"mt-12",children:XQ(WI,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:Q},void 0,!1,void 0,this)},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 c2,Fragment as Ar2}from"preact/jsx-dev-runtime";function tp2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var HO=({children:A})=>c2("h2",{className:"text-sm font-semibold text-theme-muted uppercase tracking-wide mb-3",children:A},void 0,!1,void 0,this),ep2=({skill:A})=>c2("div",{className:"flex items-start gap-3 px-4 py-3 bg-theme-subtle rounded-lg",children:[c2("div",{className:"flex-1",children:[c2("div",{className:"text-sm font-semibold text-heading",children:A.name},void 0,!1,void 0,this),c2("div",{className:"text-[13px] text-theme-muted",children:A.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.tags.length>0&&c2("div",{className:"flex gap-1 flex-shrink-0",children:A.tags.map((f)=>c2("span",{className:"text-[11px] px-2 py-0.5 bg-theme rounded-md text-theme-muted",children:f},f,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),pa0=({label:A,value:f,valueClassName:w})=>c2("div",{className:"flex justify-between text-[13px]",children:[c2("span",{className:"text-theme-muted",children:A},void 0,!1,void 0,this),c2("span",{className:w??"text-heading",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ra0=({agent:A})=>{let{frontmatter:f,about:w,skills:Q,notes:B}=A,x=aa(f.url);return c2(Ar2,{children:[c2(o2,{title:f.name,description:w||`Agent profile for ${f.name}`},void 0,!1,void 0,this),c2("article",{className:"agent-detail",children:c2("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:[c2("a",{href:"/agents",className:"text-sm text-theme-muted hover:text-brand transition-colors mb-6 inline-block",children:"\u2190 Back to Directory"},void 0,!1,void 0,this),c2("div",{className:"flex items-start gap-6 mb-8",children:[c2(sa,{name:f.name,className:"w-[72px] h-[72px] text-3xl"},void 0,!1,void 0,this),c2("div",{children:[c2("div",{className:"flex items-center gap-3 mb-1",children:[c2("h1",{className:"text-3xl md:text-4xl font-bold text-heading",children:f.name},void 0,!1,void 0,this),c2(ta,{kind:f.kind},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c2("div",{className:"flex items-center gap-3 text-theme-muted",children:[f.organization&&c2("span",{className:"text-[15px]",children:f.organization},void 0,!1,void 0,this),f.organization&&c2("span",{className:"text-theme-muted opacity-40",children:"\xB7"},void 0,!1,void 0,this),c2("span",{className:"text-sm",children:["Discovered ",tp2(f.discoveredAt)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("div",{className:"border-b border-theme mb-8"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col md:flex-row gap-12",children:[c2("div",{className:"flex-[2] min-w-0",children:[w&&c2("section",{className:"mb-8",children:[c2(HO,{children:"About"},void 0,!1,void 0,this),c2("p",{className:"text-[15px] text-theme leading-relaxed",children:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Q.length>0&&c2("section",{className:"mb-8",children:[c2(HO,{children:"Skills"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col gap-2.5",children:Q.map((c)=>c2(ep2,{skill:c},c.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B&&c2("section",{className:"mb-8",children:[c2(HO,{children:"Notes"},void 0,!1,void 0,this),c2("p",{className:"text-[15px] text-theme leading-relaxed",children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("aside",{className:"flex-1 md:pl-8 md:border-l border-theme-muted/20",children:[c2("section",{className:"mb-8",children:[c2(HO,{children:"Brain"},void 0,!1,void 0,this),c2("div",{className:"p-4 bg-theme-subtle rounded-xl",children:[c2("div",{className:"text-[15px] font-semibold text-heading mb-1",children:f.brainName??`${f.name}'s Brain`},void 0,!1,void 0,this),f.did&&c2("div",{className:"text-xs text-theme-muted font-mono",children:f.did},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("section",{className:"mb-8",children:[c2(HO,{children:"Connection"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col gap-3",children:[c2("div",{children:[c2("div",{className:"text-[13px] text-theme-muted mb-0.5",children:"Endpoint"},void 0,!1,void 0,this),c2("div",{className:"text-xs text-heading font-mono",children:f.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c2(pa0,{label:"Status",value:f.status==="active"?"Active":"Archived",valueClassName:f.status==="active"?"text-status-success font-medium":"text-theme-muted"},void 0,!1,void 0,this),c2(pa0,{label:"Discovered via",value:f.discoveredVia==="atproto"?"AT Protocol":"Manual"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("a",{href:f.url.replace(/\/a2a\/?$/,""),target:"_blank",rel:"noopener noreferrer",className:"flex items-center justify-center px-5 py-3 bg-theme-dark text-theme-inverse rounded-lg text-sm font-medium hover:opacity-90 transition-opacity",children:["Visit ",x," \u2197"]},void 0,!0,void 0,this)]},void 0,!0,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)};var fr2=X.object({agents:X.array(tb),pageTitle:X.string().optional(),pagination:$c.nullable(),baseUrl:X.string().optional()});function da0(){return{"agent-list":i0({name:"agent-list",description:"Agent directory list page template",schema:fr2,dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:Sa0}}),"agent-detail":i0({name:"agent-detail",description:"Individual agent profile template",schema:X.object({agent:tb,prevAgent:tb.nullable(),nextAgent:tb.nullable()}),dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:ra0}})}}function oa0(A){A.messaging.subscribe("a2a:call:completed",async(f)=>{try{let{domain:w}=f.payload;if(await A.entityService.getEntity("agent",w))return{success:!0};let B=await da(w,globalThis.fetch);if(!B)return{success:!0};let{content:x,metadata:c}=oa(B);await A.entityService.createEntity({id:w,entityType:"agent",content:x,metadata:c})}catch{}return{success:!0}})}var ea={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.8",description:"Agent discovery \u2014 brain+anchor contacts and skills",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Qr2=new XF;class UkA extends Nf{entityType="agent";schema=sb;adapter=Qr2;constructor(){super("agent-discovery",ea)}createGenerationHandler(A){return new HkA(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return da0()}getDataSources(){return[new ra(this.logger.child("AgentDataSource"))]}async onRegister(A){oa0(A)}}function FkA(){return new UkA}B0();YA();YA();B0();var eb=mk,aa0=mk,UO=v2.extend({entityType:X.literal("skill"),metadata:aa0});B0();class Az extends _2{constructor(){super({entityType:"skill",schema:UO,frontmatterSchema:eb})}toMarkdown(A){return A.content}fromMarkdown(A){let f=this.parseFrontMatter(A,eb);return{content:A,entityType:"skill",metadata:f}}createSkillContent(A){return this.buildMarkdown("",A)}}YA();function Br2(A){let f=[];if(A.topicTitles.length>0)f.push(`The brain's knowledge domains (from content analysis):
26523
+ `),skills:A.skills.map((x)=>({name:x.name,description:x.description,tags:x.tags})),notes:""}),metadata:{name:f,url:A.url,status:"active",slug:kk(A.url)},anchorName:f}}var rp2=X.object({prompt:X.string().optional(),url:X.string().optional(),content:X.string().optional(),skipAi:X.boolean().optional()}),UVw=xc.extend({name:X.string().optional(),domain:X.string().optional()});class HkA extends Cx{constructor(A,f){super(A,f,{schema:rp2,jobTypeName:"agent-generation",entityType:"agent"})}async generate(A,f){let w=A.url??A.prompt??"",Q=Ta0(w);if(!Q)throw Error("No URL or domain provided. Use: system_create agent with a domain like yeehaa.io");let B=await da(Q,globalThis.fetch);if(!B)throw Error(`Could not fetch Agent Card from ${Q}. Make sure the agent is running and accessible.`);let{content:x,metadata:c,anchorName:I}=oa(B);return{id:Q,content:x,metadata:c,title:I}}}B0();P2();YA();import{jsxDEV as ya0}from"preact/jsx-dev-runtime";function aa(A){try{return new URL(A).hostname}catch{return A}}var sa=({name:A,className:f=""})=>{let w=A.charAt(0).toUpperCase(),Q=0;for(let x=0;x<A.length;x++)Q=A.charCodeAt(x)+((Q<<5)-Q);let B=Math.abs(Q)%360;return ya0("div",{className:`flex items-center justify-center rounded-full text-white font-bold flex-shrink-0 ${f}`,style:{backgroundColor:`hsl(${B}, 55%, 45%)`},children:w},void 0,!1,void 0,this)},ta=({kind:A,size:f="md"})=>{let Q={professional:"bg-status-success text-status-success",team:"bg-status-info text-status-info",collective:"bg-brand/10 text-brand"}[A]??"bg-status-neutral text-status-neutral";return ya0("span",{className:`inline-flex items-center rounded-full font-medium ${f==="sm"?"px-2 py-0.5 text-xs":"px-2.5 py-0.5 text-[13px]"} ${Q}`,children:A},void 0,!1,void 0,this)};import{jsxDEV as XQ,Fragment as sp2}from"preact/jsx-dev-runtime";var dp2=({skills:A})=>{if(A.length===0)return null;return XQ("div",{className:"flex gap-1.5 flex-wrap mt-2",children:A.map((f)=>XQ("span",{className:"text-[11px] px-2 py-0.5 bg-theme-subtle rounded-md text-theme-muted",children:f.name},f.name,!1,void 0,this))},void 0,!1,void 0,this)};function op2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var ap2=({agent:A})=>{let{frontmatter:f,about:w,skills:Q,url:B}=A,x=f.status==="archived";return XQ("a",{href:B,className:`flex items-start gap-5 p-6 rounded-xl border border-theme bg-theme-subtle hover:shadow-lg transition-shadow ${x?"opacity-40":""}`,children:[XQ(sa,{name:f.name,className:"w-12 h-12 text-lg"},void 0,!1,void 0,this),XQ("div",{className:"flex-1 min-w-0",children:[XQ("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[XQ("span",{className:"text-lg font-semibold text-heading",children:f.name},void 0,!1,void 0,this),XQ(ta,{kind:x?"archived":f.kind,size:"sm"},void 0,!1,void 0,this),f.organization&&XQ("span",{className:"text-xs text-theme-muted",children:["\xB7 ",f.organization]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w&&XQ("p",{className:"text-sm text-theme-muted line-clamp-2 mb-0",children:w},void 0,!1,void 0,this),!x&&XQ(dp2,{skills:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),XQ("div",{className:"flex flex-col items-end gap-1 flex-shrink-0 text-right",children:[XQ("span",{className:"text-xs text-theme-muted",children:aa(f.url)},void 0,!1,void 0,this),XQ("span",{className:"text-[11px] text-theme-muted opacity-60",children:x?"Archived":`Discovered ${op2(f.discoveredAt)}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},Sa0=({agents:A,pageTitle:f,pagination:w,baseUrl:Q="/agents"})=>{let B=f??"Agent Directory",x=w?.totalItems??A.length,c=`Your network of ${x} ${x===1?"brain":"brains"} and their anchors`;return XQ(sp2,{children:[XQ(o2,{title:B,description:c},void 0,!1,void 0,this),XQ("div",{className:"agent-list bg-theme",children:XQ("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[XQ("div",{className:"mb-8 pb-6 border-b border-theme",children:[XQ("h1",{className:"text-4xl font-bold text-heading mb-2",children:B},void 0,!1,void 0,this),XQ("p",{className:"text-theme-muted",children:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this),XQ("div",{className:"flex flex-col gap-4",children:A.map((I)=>XQ(ap2,{agent:I},I.id,!1,void 0,this))},void 0,!1,void 0,this),A.length===0&&XQ("p",{className:"text-center text-theme-muted py-16",children:"No agents in your directory yet."},void 0,!1,void 0,this),w&&w.totalPages>1&&XQ("div",{className:"mt-12",children:XQ(WI,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:Q},void 0,!1,void 0,this)},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 c2,Fragment as Ar2}from"preact/jsx-dev-runtime";function tp2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var HO=({children:A})=>c2("h2",{className:"text-sm font-semibold text-theme-muted uppercase tracking-wide mb-3",children:A},void 0,!1,void 0,this),ep2=({skill:A})=>c2("div",{className:"flex items-start gap-3 px-4 py-3 bg-theme-subtle rounded-lg",children:[c2("div",{className:"flex-1",children:[c2("div",{className:"text-sm font-semibold text-heading",children:A.name},void 0,!1,void 0,this),c2("div",{className:"text-[13px] text-theme-muted",children:A.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.tags.length>0&&c2("div",{className:"flex gap-1 flex-shrink-0",children:A.tags.map((f)=>c2("span",{className:"text-[11px] px-2 py-0.5 bg-theme rounded-md text-theme-muted",children:f},f,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),pa0=({label:A,value:f,valueClassName:w})=>c2("div",{className:"flex justify-between text-[13px]",children:[c2("span",{className:"text-theme-muted",children:A},void 0,!1,void 0,this),c2("span",{className:w??"text-heading",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ra0=({agent:A})=>{let{frontmatter:f,about:w,skills:Q,notes:B}=A,x=aa(f.url);return c2(Ar2,{children:[c2(o2,{title:f.name,description:w||`Agent profile for ${f.name}`},void 0,!1,void 0,this),c2("article",{className:"agent-detail",children:c2("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:[c2("a",{href:"/agents",className:"text-sm text-theme-muted hover:text-brand transition-colors mb-6 inline-block",children:"\u2190 Back to Directory"},void 0,!1,void 0,this),c2("div",{className:"flex items-start gap-6 mb-8",children:[c2(sa,{name:f.name,className:"w-[72px] h-[72px] text-3xl"},void 0,!1,void 0,this),c2("div",{children:[c2("div",{className:"flex items-center gap-3 mb-1",children:[c2("h1",{className:"text-3xl md:text-4xl font-bold text-heading",children:f.name},void 0,!1,void 0,this),c2(ta,{kind:f.kind},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c2("div",{className:"flex items-center gap-3 text-theme-muted",children:[f.organization&&c2("span",{className:"text-[15px]",children:f.organization},void 0,!1,void 0,this),f.organization&&c2("span",{className:"text-theme-muted opacity-40",children:"\xB7"},void 0,!1,void 0,this),c2("span",{className:"text-sm",children:["Discovered ",tp2(f.discoveredAt)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("div",{className:"border-b border-theme mb-8"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col md:flex-row gap-12",children:[c2("div",{className:"flex-[2] min-w-0",children:[w&&c2("section",{className:"mb-8",children:[c2(HO,{children:"About"},void 0,!1,void 0,this),c2("p",{className:"text-[15px] text-theme leading-relaxed",children:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Q.length>0&&c2("section",{className:"mb-8",children:[c2(HO,{children:"Skills"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col gap-2.5",children:Q.map((c)=>c2(ep2,{skill:c},c.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B&&c2("section",{className:"mb-8",children:[c2(HO,{children:"Notes"},void 0,!1,void 0,this),c2("p",{className:"text-[15px] text-theme leading-relaxed",children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("aside",{className:"flex-1 md:pl-8 md:border-l border-theme-muted/20",children:[c2("section",{className:"mb-8",children:[c2(HO,{children:"Brain"},void 0,!1,void 0,this),c2("div",{className:"p-4 bg-theme-subtle rounded-xl",children:[c2("div",{className:"text-[15px] font-semibold text-heading mb-1",children:f.brainName??`${f.name}'s Brain`},void 0,!1,void 0,this),f.did&&c2("div",{className:"text-xs text-theme-muted font-mono",children:f.did},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("section",{className:"mb-8",children:[c2(HO,{children:"Connection"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col gap-3",children:[c2("div",{children:[c2("div",{className:"text-[13px] text-theme-muted mb-0.5",children:"Endpoint"},void 0,!1,void 0,this),c2("div",{className:"text-xs text-heading font-mono",children:f.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c2(pa0,{label:"Status",value:f.status==="active"?"Active":"Archived",valueClassName:f.status==="active"?"text-status-success font-medium":"text-theme-muted"},void 0,!1,void 0,this),c2(pa0,{label:"Discovered via",value:f.discoveredVia==="atproto"?"AT Protocol":"Manual"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),c2("a",{href:f.url.replace(/\/a2a\/?$/,""),target:"_blank",rel:"noopener noreferrer",className:"flex items-center justify-center px-5 py-3 bg-theme-dark text-theme-inverse rounded-lg text-sm font-medium hover:opacity-90 transition-opacity",children:["Visit ",x," \u2197"]},void 0,!0,void 0,this)]},void 0,!0,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)};var fr2=X.object({agents:X.array(tb),pageTitle:X.string().optional(),pagination:$c.nullable(),baseUrl:X.string().optional()});function da0(){return{"agent-list":i0({name:"agent-list",description:"Agent directory list page template",schema:fr2,dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:Sa0}}),"agent-detail":i0({name:"agent-detail",description:"Individual agent profile template",schema:X.object({agent:tb,prevAgent:tb.nullable(),nextAgent:tb.nullable()}),dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:ra0}})}}function oa0(A){A.messaging.subscribe("a2a:call:completed",async(f)=>{try{let{domain:w}=f.payload;if(await A.entityService.getEntity("agent",w))return{success:!0};let B=await da(w,globalThis.fetch);if(!B)return{success:!0};let{content:x,metadata:c}=oa(B);await A.entityService.createEntity({id:w,entityType:"agent",content:x,metadata:c})}catch{}return{success:!0}})}var ea={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.9",description:"Agent discovery \u2014 brain+anchor contacts and skills",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Qr2=new XF;class UkA extends Nf{entityType="agent";schema=sb;adapter=Qr2;constructor(){super("agent-discovery",ea)}createGenerationHandler(A){return new HkA(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return da0()}getDataSources(){return[new ra(this.logger.child("AgentDataSource"))]}async onRegister(A){oa0(A)}}function FkA(){return new UkA}B0();YA();YA();B0();var eb=mk,aa0=mk,UO=v2.extend({entityType:X.literal("skill"),metadata:aa0});B0();class Az extends _2{constructor(){super({entityType:"skill",schema:UO,frontmatterSchema:eb})}toMarkdown(A){return A.content}fromMarkdown(A){let f=this.parseFrontMatter(A,eb);return{content:A,entityType:"skill",metadata:f}}createSkillContent(A){return this.buildMarkdown("",A)}}YA();function Br2(A){let f=[];if(A.topicTitles.length>0)f.push(`The brain's knowledge domains (from content analysis):
26524
26524
  ${A.topicTitles.map((w)=>`- ${w}`).join(`
26525
26525
  `)}`);if(A.toolDescriptions.length>0)f.push(`The brain has these capabilities:
26526
26526
  ${A.toolDescriptions.map((w)=>`- ${w}`).join(`
@@ -26562,7 +26562,7 @@ Return 2-5 skills as a JSON object with a "skills" array.`,requiredPermission:"p
26562
26562
  title: ${c}
26563
26563
  keywords: []
26564
26564
  ---
26565
- ${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,metadata:{}})}catch{}}let B=await As(A,this.logger),x=await A.entityService.listEntities("skill");return{...B,skills:x.map((c)=>c.metadata)}})}async deriveAll(A){this.logger.info("Deriving skills from topics (replace-all)");let f=await As(A,this.logger,{replaceAll:!0});this.logger.info("Skill derivation complete",f)}hasRunInitialDerivation(){return this.initialDerivationDone}}function XkA(){return new KkA}var Ir2=X.object({}).strict();function fs(A={}){return Ir2.parse(A),[FkA(),XkA()]}B0();YA();P2();YA();B0();var ws=SP.extend({expertise:X.array(X.string()).optional().describe("Skills, domains, areas of focus"),currentFocus:X.string().optional().describe("What you're currently working on"),availability:X.string().optional().describe("What you're open to (consulting, speaking, etc.)")}),ZF=l7.extend(ws.shape);B0();NH();YA();var $r2=new V$;class Qs{postsListUrl;decksListUrl;id="professional:homepage-list";name="Homepage List DataSource";description="Fetches profile, blog posts, and presentation decks for homepage";constructor(A,f){this.postsListUrl=A;this.decksListUrl=f}async fetch(A,f,w){let Q=w.entityService,[B,x,c,I]=await Promise.all([nk(Q),Q.listEntities("post",{limit:20}),Q.listEntities("deck",{limit:20}),d3(Q)]),$=$r2.parseProfileBody(B,ZF),u=x.sort(BC).slice(0,3).map(gM),Y=c.sort(BC).slice(0,3).map(mM);if(!I.cta)throw Error("CTA not configured in site-info");let F={profile:$,posts:u,decks:Y,postsListUrl:this.postsListUrl,decksListUrl:this.decksListUrl,cta:I.cta};return f.parse(F)}}B0();NH();var ur2=new V$;class Bs{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,f,w){let Q=await nk(w.entityService),x={profile:ur2.parseProfileBody(Q,ZF)};return f.parse(x)}}import{jsxDEV as wB,Fragment as ta0}from"preact/jsx-dev-runtime";var ZkA=({profile:A,posts:f,decks:w,postsListUrl:Q,decksListUrl:B,cta:x})=>{let c=A.tagline||A.description,I=f.map((F)=>({id:F.id,url:F.url,title:F.metadata.title,date:F.metadata.publishedAt||F.created,description:F.frontmatter.excerpt,series:F.frontmatter.seriesName&&F.frontmatter.seriesIndex?{name:F.frontmatter.seriesName,index:F.frontmatter.seriesIndex}:void 0})),$=w.map((F)=>({id:F.id,url:F.url,title:F.frontmatter.title||F.id,date:F.frontmatter.publishedAt??F.created,description:F.frontmatter.description})),u=A.name||"Home",Y=A.intro||A.description||c||"Professional site";return wB(ta0,{children:[wB(o2,{title:u,description:Y,ogType:"website"},void 0,!1,void 0,this),wB("div",{className:"homepage-list bg-theme",children:[wB("header",{className:"hero-bg-pattern relative w-full min-h-[70vh] flex items-end px-6 md:px-12 bg-theme overflow-hidden",children:wB("div",{className:"relative z-10 max-w-6xl mx-auto w-full pb-16 md:pb-24",children:[c&&wB("h1",{className:"text-5xl md:text-6xl lg:text-7xl font-semibold text-heading leading-[1.08] tracking-tight",children:c},void 0,!1,void 0,this),A.intro&&wB(ta0,{children:[wB("div",{className:"w-12 border-t border-theme mt-8 mb-6 md:mt-10 md:mb-8"},void 0,!1,void 0,this),wB("p",{className:"text-lg md:text-xl text-theme-muted leading-relaxed max-w-xl md:max-w-lg",children:A.intro},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),wB("div",{className:"section-divider"},void 0,!1,void 0,this),wB("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[wB("div",{className:"content-section-reveal mb-20 md:mb-32",children:wB(M3,{title:"Essays",items:I,viewAllUrl:Q},void 0,!1,void 0,this)},void 0,!1,void 0,this),$.length>0&&wB("div",{className:"content-section-reveal mb-20 md:mb-32",children:wB(M3,{title:"Presentations",items:$,viewAllUrl:B},void 0,!1,void 0,this)},void 0,!1,void 0,this),(A.description||A.expertise&&A.expertise.length>0)&&wB("div",{className:"content-section-reveal mb-20 md:mb-32",children:wB(M3,{title:"About",viewAllUrl:"/about",variant:"stacked",children:wB("div",{className:"space-y-6",children:[A.description&&wB("p",{className:"text-lg text-theme leading-relaxed",children:A.description},void 0,!1,void 0,this),A.expertise&&A.expertise.length>0&&wB(nx,{tags:A.expertise,variant:"accent",size:"sm"},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),wB(cKA,{cta:x,variant:"editorial",socialLinks:A.socialLinks},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as Nw,Fragment as Dr2}from"preact/jsx-dev-runtime";var vkA=({profile:A})=>{let f=`About ${A.name||"Me"}`,w=A.description||A.intro||"About page",Q=A.expertise&&A.expertise.length>0||A.currentFocus||A.availability||A.email||A.website||A.socialLinks&&A.socialLinks.length>0;return Nw(Dr2,{children:[Nw(o2,{title:f,description:w,ogType:"profile"},void 0,!1,void 0,this),Nw("div",{className:"about-page bg-theme",children:[Nw("header",{className:"hero-bg-pattern relative w-full py-16 md:py-24 px-6 md:px-12 bg-theme overflow-hidden",children:Nw("div",{className:"relative z-10 max-w-4xl mx-auto",children:[Nw("h1",{className:"text-5xl md:text-6xl font-semibold mb-6 text-heading",children:["About ",A.name||"Me"]},void 0,!0,void 0,this),A.description&&Nw("p",{className:"text-xl md:text-2xl text-theme-muted leading-relaxed",children:A.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Nw("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-12 md:py-16",children:[A.story&&Nw("section",{className:"content-section-reveal mb-20 md:mb-28",children:Nw(vI,{markdown:A.story},void 0,!1,void 0,this)},void 0,!1,void 0,this),Q&&Nw("div",{className:"content-section-reveal grid md:grid-cols-2 gap-x-16 gap-y-12",children:[A.expertise&&A.expertise.length>0&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Expertise"},void 0,!1,void 0,this),Nw("ul",{className:"flex flex-wrap gap-3",children:A.expertise.map((B,x)=>Nw("li",{className:ki({variant:"accent",size:"lg"}),children:B},x,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.currentFocus&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Current Focus"},void 0,!1,void 0,this),Nw("p",{className:"text-lg text-theme leading-relaxed",children:A.currentFocus},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.availability&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Availability"},void 0,!1,void 0,this),Nw("p",{className:"text-lg text-theme leading-relaxed",children:A.availability},void 0,!1,void 0,this)]},void 0,!0,void 0,this),(A.email||A.website||A.socialLinks&&A.socialLinks.length>0)&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Contact"},void 0,!1,void 0,this),Nw("div",{className:"space-y-4",children:[A.email&&Nw("p",{className:"text-lg",children:Nw("a",{href:`mailto:${A.email}`,className:"text-brand hover:text-brand-dark transition-colors",children:A.email},void 0,!1,void 0,this)},void 0,!1,void 0,this),A.website&&Nw("p",{className:"text-lg",children:Nw("a",{href:A.website,target:"_blank",rel:"noopener noreferrer",className:"text-brand hover:text-brand-dark transition-colors",children:A.website},void 0,!1,void 0,this)},void 0,!1,void 0,this),A.socialLinks&&A.socialLinks.length>0&&Nw("div",{className:"flex flex-wrap gap-4 mt-4",children:A.socialLinks.map((B,x)=>Nw(_B,{href:B.url,external:!0,variant:"secondary",size:"md",children:B.label||B.platform},x,!1,void 0,this))},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)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as rx,Fragment as ea0}from"preact/jsx-dev-runtime";var WkA=()=>{return rx(ea0,{children:[rx(o2,{title:"Thanks for subscribing!",description:"You've successfully subscribed to the newsletter."},void 0,!1,void 0,this),rx("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:rx("div",{className:"text-center max-w-md",children:[rx("div",{className:"text-6xl mb-6",children:"\uD83C\uDF89"},void 0,!1,void 0,this),rx("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Thanks for subscribing!"},void 0,!1,void 0,this),rx("p",{className:"text-lg text-theme-muted mb-8",children:"You'll receive a confirmation email shortly. Check your inbox to confirm your subscription."},void 0,!1,void 0,this),rx(_B,{href:"/",variant:"primary",children:"Back to Home"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},kkA=()=>{return rx(ea0,{children:[rx(o2,{title:"Subscription failed",description:"There was a problem with your subscription."},void 0,!1,void 0,this),rx("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:rx("div",{className:"text-center max-w-md",children:[rx("div",{className:"text-6xl mb-6",children:"\uD83D\uDE22"},void 0,!1,void 0,this),rx("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Something went wrong"},void 0,!1,void 0,this),rx("p",{className:"text-lg text-theme-muted mb-8",children:"We couldn't process your subscription. Please try again or contact us if the problem persists."},void 0,!1,void 0,this),rx(_B,{href:"/",variant:"primary",children:"Back to Home"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();var As0=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')")}),fs0=X.object({entityDisplay:X.object({post:As0,deck:As0}).describe("Display metadata for post and deck entity types (required for homepage)")});var ws0={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.8",description:"Professional site composition package",type:"module",exports:{".":"./src/index.ts"},files:["src"],scripts:{typecheck:"tsc --noEmit",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/blog":"workspace:*","@brains/decks":"workspace:*","@brains/identity-service":"workspace:*","@brains/plugins":"workspace:*","@brains/site-builder-plugin":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-info":"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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class hkA extends yQ{dependencies=["blog","decks"];constructor(A){super("professional-site",ws0,A,fs0)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",ws);let f=this.config.entityDisplay.post,w=this.config.entityDisplay.deck,Q=`/${f.pluralName??f.label.toLowerCase()+"s"}`,B=`/${w.pluralName??w.label.toLowerCase()+"s"}`,x=new Qs(Q,B);A.entities.registerDataSource(x);let c=new Bs;A.entities.registerDataSource(c);let I=X.object({profile:ZF,posts:X.array(e3),decks:X.array(RM),postsListUrl:X.string(),decksListUrl:X.string(),cta:zM}),$=X.object({profile:ZF}),u=X.object({});A.templates.register({"homepage-list":i0({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:I,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:ZkA}}),about:i0({name:"about",description:"About page with full profile information",schema:$,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:vkA}}),"subscribe-thanks":i0({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:u,requiredPermission:"public",layout:{component:WkA}}),"subscribe-error":i0({name:"subscribe-error",description:"Newsletter subscription error page",schema:u,requiredPermission:"public",layout:{component:kkA}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function Qs0(A){return new hkA(A??{})}var Bs0=[{id:"home",path:"/",title:"Home",description:"Professional site homepage",layout:"default",navigation:{show:!0,label:"Home",slot:"secondary",priority:10},sections:[{id:"homepage",template:"professional-site:homepage-list",dataQuery:{}}]},{id:"about",path:"/about",title:"About",description:"About page",layout:"default",navigation:{show:!0,label:"About",slot:"primary",priority:90},sections:[{id:"about",template:"professional-site:about",dataQuery:{}}]},{id:"subscribe-thanks",path:"/subscribe/thanks",title:"Thanks for subscribing",description:"Newsletter subscription confirmation",layout:"default",navigation:{show:!1},sections:[{id:"subscribe-thanks",template:"professional-site:subscribe-thanks",dataQuery:{},content:{}}]},{id:"subscribe-error",path:"/subscribe/error",title:"Subscription failed",description:"Newsletter subscription error",layout:"default",navigation:{show:!1},sections:[{id:"subscribe-error",template:"professional-site:subscribe-error",dataQuery:{},content:{}}]}];import{jsxDEV as fz}from"preact/jsx-dev-runtime";function xs0({sections:A,siteInfo:f,slots:w}){return fz("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[fz(DKA,{title:f.title,navigation:f.navigation.primary,...f.logo!==void 0?{logo:f.logo}:{}},void 0,!1,void 0,this),fz("main",{className:"flex-grow flex flex-col bg-theme",children:A},void 0,!1,void 0,this),fz("div",{className:"section-divider"},void 0,!1,void 0,this),fz($KA,{primaryNavigation:f.navigation.primary,secondaryNavigation:f.navigation.secondary,copyright:f.copyright,socialLinks:f.socialLinks,children:fz(CvA,{name:"footer-top",slots:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Hr2={layouts:{default:xs0},routes:Bs0,plugin:Qs0,entityDisplay:{post:{label:"Post"},deck:{label:"Deck"},project:{label:"Project"},series:{label:"Series",navigation:{slot:"secondary"}},topic:{label:"Topic",navigation:{slot:"secondary"}},link:{label:"Link",navigation:{slot:"secondary"}},base:{label:"Note",navigation:{show:!1}},"social-post":{label:"Social Post",pluralName:"social-posts",navigation:{slot:"secondary"}},newsletter:{label:"Newsletter",navigation:{slot:"secondary"}}}},FO=Hr2;var cs0=`/* Default font imports */
26565
+ ${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,metadata:{}})}catch{}}let B=await As(A,this.logger),x=await A.entityService.listEntities("skill");return{...B,skills:x.map((c)=>c.metadata)}})}async deriveAll(A){this.logger.info("Deriving skills from topics (replace-all)");let f=await As(A,this.logger,{replaceAll:!0});this.logger.info("Skill derivation complete",f)}hasRunInitialDerivation(){return this.initialDerivationDone}}function XkA(){return new KkA}var Ir2=X.object({}).strict();function fs(A={}){return Ir2.parse(A),[FkA(),XkA()]}B0();YA();P2();YA();B0();var ws=SP.extend({expertise:X.array(X.string()).optional().describe("Skills, domains, areas of focus"),currentFocus:X.string().optional().describe("What you're currently working on"),availability:X.string().optional().describe("What you're open to (consulting, speaking, etc.)")}),ZF=l7.extend(ws.shape);B0();NH();YA();var $r2=new V$;class Qs{postsListUrl;decksListUrl;id="professional:homepage-list";name="Homepage List DataSource";description="Fetches profile, blog posts, and presentation decks for homepage";constructor(A,f){this.postsListUrl=A;this.decksListUrl=f}async fetch(A,f,w){let Q=w.entityService,[B,x,c,I]=await Promise.all([nk(Q),Q.listEntities("post",{limit:20}),Q.listEntities("deck",{limit:20}),d3(Q)]),$=$r2.parseProfileBody(B,ZF),u=x.sort(BC).slice(0,3).map(gM),Y=c.sort(BC).slice(0,3).map(mM);if(!I.cta)throw Error("CTA not configured in site-info");let F={profile:$,posts:u,decks:Y,postsListUrl:this.postsListUrl,decksListUrl:this.decksListUrl,cta:I.cta};return f.parse(F)}}B0();NH();var ur2=new V$;class Bs{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,f,w){let Q=await nk(w.entityService),x={profile:ur2.parseProfileBody(Q,ZF)};return f.parse(x)}}import{jsxDEV as wB,Fragment as ta0}from"preact/jsx-dev-runtime";var ZkA=({profile:A,posts:f,decks:w,postsListUrl:Q,decksListUrl:B,cta:x})=>{let c=A.tagline||A.description,I=f.map((F)=>({id:F.id,url:F.url,title:F.metadata.title,date:F.metadata.publishedAt||F.created,description:F.frontmatter.excerpt,series:F.frontmatter.seriesName&&F.frontmatter.seriesIndex?{name:F.frontmatter.seriesName,index:F.frontmatter.seriesIndex}:void 0})),$=w.map((F)=>({id:F.id,url:F.url,title:F.frontmatter.title||F.id,date:F.frontmatter.publishedAt??F.created,description:F.frontmatter.description})),u=A.name||"Home",Y=A.intro||A.description||c||"Professional site";return wB(ta0,{children:[wB(o2,{title:u,description:Y,ogType:"website"},void 0,!1,void 0,this),wB("div",{className:"homepage-list bg-theme",children:[wB("header",{className:"hero-bg-pattern relative w-full min-h-[70vh] flex items-end px-6 md:px-12 bg-theme overflow-hidden",children:wB("div",{className:"relative z-10 max-w-6xl mx-auto w-full pb-16 md:pb-24",children:[c&&wB("h1",{className:"text-5xl md:text-6xl lg:text-7xl font-semibold text-heading leading-[1.08] tracking-tight",children:c},void 0,!1,void 0,this),A.intro&&wB(ta0,{children:[wB("div",{className:"w-12 border-t border-theme mt-8 mb-6 md:mt-10 md:mb-8"},void 0,!1,void 0,this),wB("p",{className:"text-lg md:text-xl text-theme-muted leading-relaxed max-w-xl md:max-w-lg",children:A.intro},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),wB("div",{className:"section-divider"},void 0,!1,void 0,this),wB("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[wB("div",{className:"content-section-reveal mb-20 md:mb-32",children:wB(M3,{title:"Essays",items:I,viewAllUrl:Q},void 0,!1,void 0,this)},void 0,!1,void 0,this),$.length>0&&wB("div",{className:"content-section-reveal mb-20 md:mb-32",children:wB(M3,{title:"Presentations",items:$,viewAllUrl:B},void 0,!1,void 0,this)},void 0,!1,void 0,this),(A.description||A.expertise&&A.expertise.length>0)&&wB("div",{className:"content-section-reveal mb-20 md:mb-32",children:wB(M3,{title:"About",viewAllUrl:"/about",variant:"stacked",children:wB("div",{className:"space-y-6",children:[A.description&&wB("p",{className:"text-lg text-theme leading-relaxed",children:A.description},void 0,!1,void 0,this),A.expertise&&A.expertise.length>0&&wB(nx,{tags:A.expertise,variant:"accent",size:"sm"},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),wB(cKA,{cta:x,variant:"editorial",socialLinks:A.socialLinks},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as Nw,Fragment as Dr2}from"preact/jsx-dev-runtime";var vkA=({profile:A})=>{let f=`About ${A.name||"Me"}`,w=A.description||A.intro||"About page",Q=A.expertise&&A.expertise.length>0||A.currentFocus||A.availability||A.email||A.website||A.socialLinks&&A.socialLinks.length>0;return Nw(Dr2,{children:[Nw(o2,{title:f,description:w,ogType:"profile"},void 0,!1,void 0,this),Nw("div",{className:"about-page bg-theme",children:[Nw("header",{className:"hero-bg-pattern relative w-full py-16 md:py-24 px-6 md:px-12 bg-theme overflow-hidden",children:Nw("div",{className:"relative z-10 max-w-4xl mx-auto",children:[Nw("h1",{className:"text-5xl md:text-6xl font-semibold mb-6 text-heading",children:["About ",A.name||"Me"]},void 0,!0,void 0,this),A.description&&Nw("p",{className:"text-xl md:text-2xl text-theme-muted leading-relaxed",children:A.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Nw("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-12 md:py-16",children:[A.story&&Nw("section",{className:"content-section-reveal mb-20 md:mb-28",children:Nw(vI,{markdown:A.story},void 0,!1,void 0,this)},void 0,!1,void 0,this),Q&&Nw("div",{className:"content-section-reveal grid md:grid-cols-2 gap-x-16 gap-y-12",children:[A.expertise&&A.expertise.length>0&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Expertise"},void 0,!1,void 0,this),Nw("ul",{className:"flex flex-wrap gap-3",children:A.expertise.map((B,x)=>Nw("li",{className:ki({variant:"accent",size:"lg"}),children:B},x,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.currentFocus&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Current Focus"},void 0,!1,void 0,this),Nw("p",{className:"text-lg text-theme leading-relaxed",children:A.currentFocus},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.availability&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Availability"},void 0,!1,void 0,this),Nw("p",{className:"text-lg text-theme leading-relaxed",children:A.availability},void 0,!1,void 0,this)]},void 0,!0,void 0,this),(A.email||A.website||A.socialLinks&&A.socialLinks.length>0)&&Nw("section",{children:[Nw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Contact"},void 0,!1,void 0,this),Nw("div",{className:"space-y-4",children:[A.email&&Nw("p",{className:"text-lg",children:Nw("a",{href:`mailto:${A.email}`,className:"text-brand hover:text-brand-dark transition-colors",children:A.email},void 0,!1,void 0,this)},void 0,!1,void 0,this),A.website&&Nw("p",{className:"text-lg",children:Nw("a",{href:A.website,target:"_blank",rel:"noopener noreferrer",className:"text-brand hover:text-brand-dark transition-colors",children:A.website},void 0,!1,void 0,this)},void 0,!1,void 0,this),A.socialLinks&&A.socialLinks.length>0&&Nw("div",{className:"flex flex-wrap gap-4 mt-4",children:A.socialLinks.map((B,x)=>Nw(_B,{href:B.url,external:!0,variant:"secondary",size:"md",children:B.label||B.platform},x,!1,void 0,this))},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)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as rx,Fragment as ea0}from"preact/jsx-dev-runtime";var WkA=()=>{return rx(ea0,{children:[rx(o2,{title:"Thanks for subscribing!",description:"You've successfully subscribed to the newsletter."},void 0,!1,void 0,this),rx("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:rx("div",{className:"text-center max-w-md",children:[rx("div",{className:"text-6xl mb-6",children:"\uD83C\uDF89"},void 0,!1,void 0,this),rx("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Thanks for subscribing!"},void 0,!1,void 0,this),rx("p",{className:"text-lg text-theme-muted mb-8",children:"You'll receive a confirmation email shortly. Check your inbox to confirm your subscription."},void 0,!1,void 0,this),rx(_B,{href:"/",variant:"primary",children:"Back to Home"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},kkA=()=>{return rx(ea0,{children:[rx(o2,{title:"Subscription failed",description:"There was a problem with your subscription."},void 0,!1,void 0,this),rx("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:rx("div",{className:"text-center max-w-md",children:[rx("div",{className:"text-6xl mb-6",children:"\uD83D\uDE22"},void 0,!1,void 0,this),rx("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Something went wrong"},void 0,!1,void 0,this),rx("p",{className:"text-lg text-theme-muted mb-8",children:"We couldn't process your subscription. Please try again or contact us if the problem persists."},void 0,!1,void 0,this),rx(_B,{href:"/",variant:"primary",children:"Back to Home"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();var As0=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')")}),fs0=X.object({entityDisplay:X.object({post:As0,deck:As0}).describe("Display metadata for post and deck entity types (required for homepage)")});var ws0={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.9",description:"Professional site composition package",type:"module",exports:{".":"./src/index.ts"},files:["src"],scripts:{typecheck:"tsc --noEmit",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/blog":"workspace:*","@brains/decks":"workspace:*","@brains/identity-service":"workspace:*","@brains/plugins":"workspace:*","@brains/site-builder-plugin":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-info":"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":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class hkA extends yQ{dependencies=["blog","decks"];constructor(A){super("professional-site",ws0,A,fs0)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",ws);let f=this.config.entityDisplay.post,w=this.config.entityDisplay.deck,Q=`/${f.pluralName??f.label.toLowerCase()+"s"}`,B=`/${w.pluralName??w.label.toLowerCase()+"s"}`,x=new Qs(Q,B);A.entities.registerDataSource(x);let c=new Bs;A.entities.registerDataSource(c);let I=X.object({profile:ZF,posts:X.array(e3),decks:X.array(RM),postsListUrl:X.string(),decksListUrl:X.string(),cta:zM}),$=X.object({profile:ZF}),u=X.object({});A.templates.register({"homepage-list":i0({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:I,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:ZkA}}),about:i0({name:"about",description:"About page with full profile information",schema:$,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:vkA}}),"subscribe-thanks":i0({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:u,requiredPermission:"public",layout:{component:WkA}}),"subscribe-error":i0({name:"subscribe-error",description:"Newsletter subscription error page",schema:u,requiredPermission:"public",layout:{component:kkA}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function Qs0(A){return new hkA(A??{})}var Bs0=[{id:"home",path:"/",title:"Home",description:"Professional site homepage",layout:"default",navigation:{show:!0,label:"Home",slot:"secondary",priority:10},sections:[{id:"homepage",template:"professional-site:homepage-list",dataQuery:{}}]},{id:"about",path:"/about",title:"About",description:"About page",layout:"default",navigation:{show:!0,label:"About",slot:"primary",priority:90},sections:[{id:"about",template:"professional-site:about",dataQuery:{}}]},{id:"subscribe-thanks",path:"/subscribe/thanks",title:"Thanks for subscribing",description:"Newsletter subscription confirmation",layout:"default",navigation:{show:!1},sections:[{id:"subscribe-thanks",template:"professional-site:subscribe-thanks",dataQuery:{},content:{}}]},{id:"subscribe-error",path:"/subscribe/error",title:"Subscription failed",description:"Newsletter subscription error",layout:"default",navigation:{show:!1},sections:[{id:"subscribe-error",template:"professional-site:subscribe-error",dataQuery:{},content:{}}]}];import{jsxDEV as fz}from"preact/jsx-dev-runtime";function xs0({sections:A,siteInfo:f,slots:w}){return fz("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[fz(DKA,{title:f.title,navigation:f.navigation.primary,...f.logo!==void 0?{logo:f.logo}:{}},void 0,!1,void 0,this),fz("main",{className:"flex-grow flex flex-col bg-theme",children:A},void 0,!1,void 0,this),fz("div",{className:"section-divider"},void 0,!1,void 0,this),fz($KA,{primaryNavigation:f.navigation.primary,secondaryNavigation:f.navigation.secondary,copyright:f.copyright,socialLinks:f.socialLinks,children:fz(CvA,{name:"footer-top",slots:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Hr2={layouts:{default:xs0},routes:Bs0,plugin:Qs0,entityDisplay:{post:{label:"Post"},deck:{label:"Deck"},project:{label:"Project"},series:{label:"Series",navigation:{slot:"secondary"}},topic:{label:"Topic",navigation:{slot:"secondary"}},link:{label:"Link",navigation:{slot:"secondary"}},base:{label:"Note",navigation:{show:!1}},"social-post":{label:"Social Post",pluralName:"social-posts",navigation:{slot:"secondary"}},newsletter:{label:"Newsletter",navigation:{slot:"secondary"}}}},FO=Hr2;var cs0=`/* Default font imports */
26566
26566
  @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&display=swap');
26567
26567
  @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap');
26568
26568
 
@@ -26866,7 +26866,7 @@ ${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,
26866
26866
  .btn-primary:hover { background-color: var(--color-brand-dark); }
26867
26867
  .btn-primary:disabled { opacity: 0.5; }
26868
26868
  }
26869
- `;var xs=cs0;import{join as Fr2}from"path";var Is0=["prompt","note","link","wishlist","topics","directory-sync","agents","mcp","discord","a2a"],$s0=[...Is0,"image","dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder","webserver"],Kr2=[...$s0,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],us0=yH({name:"rover",version:"0.1.0",model:"gpt-5.4-mini",site:FO,theme:xs,presets:{core:Is0,default:$s0,full:Kr2},evalDisable:["discord","webserver","mcp","analytics","dashboard"],capabilities:[["prompt",Vv,void 0],["image",Aq,void 0],["dashboard",QO,void 0],["blog",MvA,{}],["series",RvA,void 0],["decks",lM,void 0],["note",Lv,{}],["link",qv,{}],["portfolio",ZWA,{}],["topics",Ea,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",mWA,{generationSchedules:{newsletter:"0 9 * * 1","social-post":"0 10 * * *"},generationConditions:{newsletter:{skipIfDraftExists:!0,minSourceEntities:1,sourceEntityType:"post"},"social-post":{skipIfDraftExists:!0,maxUnpublishedDrafts:5}}}],["social-media",tM,{autoGenerateOnBlogPublish:!0}],["newsletter",Wa0,{doubleOptIn:!0}],["obsidian-vault",wkA,{autoSync:!0}],["wishlist",ya,{}],["stock-photo",YkA,{}],["agents",fs,void 0],["directory-sync",rZ,{seedContent:!0,seedContentPath:Fr2(import.meta.dir,"..","seed-content"),initialSync:!0}],["analytics",Ra,{}],["site-info",kv,void 0],["site-builder",Nv,{cms:{}}]],interfaces:[["mcp",QU,()=>({})],["discord",PU,()=>({})],["webserver",RU,()=>({})],["a2a",TJ,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"public"},{pattern:"discord:*",level:"public"}]},deployment:{cdn:{enabled:!0,provider:"bunny"},dns:{enabled:!0,provider:"bunny"}}});$3();B0();YA();YA();B0();var cs=X.object({routeId:X.string(),sectionId:X.string()}),KO=v2.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:cs});B0();class Ds0 extends _2{constructor(){super({entityType:"site-content",schema:KO,frontmatterSchema:cs})}toMarkdown(A){let f=this.extractBody(A.content);return this.buildMarkdown(f,A.metadata)}fromMarkdown(A){return{content:A,entityType:"site-content",metadata:this.parseFrontmatter(A)}}}var GkA=new Ds0;YA();var Is=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")}),KOw=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()});class JkA{context;constructor(A){this.context=A}createJobOptions(A,f){if(!A)return;return{source:A.operationType??f,rootJobId:A.rootJobId??`${f}-${Date.now()}`,metadata:{operationType:A.operationType??"content_operations",progressToken:A.progressToken,pluginId:A.pluginId??"site-content"}}}async fetchRoutes(){let A=await this.context.messaging.send("site-builder:routes:list",{});if("noop"in A)throw Error("No handler for site-builder:routes:list \u2014 is site-builder plugin loaded?");if(!A.success||!A.data)throw Error("Failed to fetch routes from site-builder");return A.data}async generate(A,f,w){let Q=this.context.logger.child("SiteContentOperations"),B=await this.fetchRoutes(),x=B;if(A.routeId){if(x=B.filter((Y)=>Y.id===A.routeId),x.length===0)throw Error(`Route not found: ${A.routeId}`)}let c=[];for(let Y of x)for(let F of Y.sections){if(A.sectionId&&F.id!==A.sectionId)continue;if(F.content){Q.debug("Section has static content, skipping",{routeId:Y.id,sectionId:F.id});continue}if(F.template){let K=this.context.templates.getCapabilities(F.template);if(!K){Q.warn("Template not found, skipping section",{routeId:Y.id,sectionId:F.id,templateName:F.template});continue}if(!K.canGenerate){Q.debug("Template doesn't support generation, skipping",{routeId:Y.id,sectionId:F.id,templateName:F.template,capabilities:K});continue}}else{Q.debug("Section has no template, skipping",{routeId:Y.id,sectionId:F.id});continue}if(!A.force&&!A.dryRun){let K=`${Y.id}:${F.id}`;if(await this.context.entityService.getEntity("site-content",K)){Q.debug("Content already exists, skipping",{routeId:Y.id,sectionId:F.id});continue}}c.push({route:Y,section:F})}let I=c.length;if(A.dryRun)return{jobs:[],totalSections:I,queuedSections:I,batchId:`dry-run-${Date.now()}`};let $=[],u=[];for(let{route:Y,section:F}of c){let K=`${Y.id}:${F.id}`,Z=F.template,k={routeId:Y.id,sectionId:F.id,entityId:K,entityType:"site-content",templateName:Z,context:{prompt:typeof F.content==="string"?F.content:void 0,data:{routeId:Y.id,sectionId:F.id,routeTitle:Y.title,routeDescription:Y.description,sectionContent:F.content},conversationId:"system"},siteConfig:f};u.push({type:"shell:content-generation",data:k})}if(u.length>0){let Y=this.createJobOptions(w,"site:content-generation"),F=await this.context.jobs.enqueueBatch(u,Y);for(let K=0;K<c.length;K++){let Z=c[K];if(Z)$.push({jobId:`${F}-${K}`,routeId:Z.route.id,sectionId:Z.section.id})}return{jobs:$,totalSections:I,queuedSections:$.length,batchId:F}}return{jobs:[],totalSections:I,queuedSections:0,batchId:`empty-${Date.now()}`}}}class bkA{siteConfig;operations;constructor(A,f){this.siteConfig=f;this.operations=new JkA(A)}async generateContent(A,f){let w=Is.parse(A);return this.operations.generate(w,this.siteConfig,f)}}B0();function Ys0(A,f){return[Tf(f,"generate","Generate content for all routes, a specific route, or a specific section",Is,async(w,Q)=>{let B=A();if(!B)return{success:!1,error:"Site content service not initialized"};if(w.sectionId&&!w.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let x={rootJobId:`generate-${Date.now()}`,progressToken:Q.progressToken,pluginId:f,operationType:"content_operations",interfaceType:Q.interfaceType,channelId:Q.channelId},c=await B.generateContent(w,x);return{success:!0,message:`Generated ${c.queuedSections} of ${c.totalSections} sections. ${c.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:c.batchId,jobsQueued:c.queuedSections,totalSections:c.totalSections,jobs:c.jobs}}})]}var Hs0={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.8",description:"Site content entity and generation orchestration",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class zkA extends yQ{siteContentService;constructor(){super("site-content",Hs0,{},X.object({}))}async onRegister(A){A.entities.register("site-content",KO,GkA),this.siteContentService=new bkA(A)}async getTools(){return Ys0(()=>this.siteContentService,this.id)}}function XO(){return new zkA}B0();YA();P2();YA();B0();var Us0=X.enum(["available","early access","coming soon","planned"]),Fs0=X.object({title:X.string(),description:X.string()}),BY=X.object({name:X.string(),availability:Us0,order:X.number()}),$s=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(Fs0).min(1).max(6),story:X.string()}),Zr2=BY.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),wz=v2.extend({entityType:X.literal("product"),metadata:Zr2}),us=wz.extend({frontmatter:BY,body:$s,labels:X.record(X.string(),X.string())}),Ds=us.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional()});B0();YA();YA();class Qz extends R1{constructor(){super($s,{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 NkA extends _2{constructor(){super({entityType:"product",schema:wz,frontmatterSchema:BY,bodyFormatter:new Qz})}toMarkdown(A){let f=this.extractBody(A.content);try{let w=this.parseFrontMatter(A.content,BY);return this.buildMarkdown(f,w)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,BY),w=x2(f.name);return{content:A,entityType:"product",metadata:{name:f.name,slug:w,availability:f.availability,order:f.order}}}}var Ys=new NkA;YA();B0();var Ks0=X.object({title:X.string(),description:X.string()}),Xs0=X.object({title:X.string(),description:X.string()}),vr2=X.object({title:X.string(),description:X.string()}),Zs0=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),xY=X.object({headline:X.string(),tagline:X.string()}),Wr2=X.object({title:X.string(),description:X.string()}),Hs=X.object({vision:X.string(),pillars:X.array(Ks0).min(1).max(6),approach:X.array(Wr2).min(1).max(6),productsIntro:X.string(),technologies:X.array(vr2).min(1).max(6),benefits:X.array(Xs0).min(1).max(6),cta:Zs0}),vs0=xY.pick({headline:!0}).extend({slug:X.string()}),Bz=v2.extend({entityType:X.literal("products-overview"),metadata:vs0}),ZO=Bz.extend({frontmatter:xY,body:Hs,labels:X.record(X.string(),X.string())});B0();YA();YA();class xz extends R1{constructor(){super(Hs,{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 CkA extends _2{constructor(){super({entityType:"products-overview",schema:Bz,frontmatterSchema:xY,bodyFormatter:new xz})}toMarkdown(A){let f=this.extractBody(A.content);try{let w=this.parseFrontMatter(A.content,xY);return this.buildMarkdown(f,w)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,xY),w=x2(f.headline);return{content:A,entityType:"products-overview",metadata:{headline:f.headline,slug:w}}}}var EkA=new CkA;B0();YA();var kr2=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function Ws0(A,f){let w=K2(A.content,BY),Q=f.parse(w.content),B=f.getLabels();return us.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}function ks0(A,f){let w=K2(A.content,xY),Q=f.parse(w.content),B=f.getLabels();return ZO.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}class Us{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new xz;productFormatter=new Qz;constructor(A){this.logger=A;this.logger.debug("ProductsDataSource initialized")}async fetch(A,f,w){let Q=kr2.parse(A),B=w.entityService;if(Q.entityType==="products-overview"){let u=(await B.listEntities("products-overview",{limit:1}))[0];if(!u)throw Error("Products overview entity not found");let Y=ks0(u,this.overviewFormatter);return f.parse(Y)}if(Q.query?.id){let u=(await B.listEntities("product",{filter:{metadata:{slug:Q.query.id}},limit:1}))[0];if(!u)throw Error(`Product not found: ${Q.query.id}`);return f.parse({product:Ws0(u,this.productFormatter)})}let[x,c]=await Promise.all([B.listEntities("products-overview",{limit:1}),B.listEntities("product",{sortFields:[{field:"order",direction:"asc"}]})]),I=x[0];if(!I)throw Error("Products overview entity not found");return f.parse({overview:ks0(I,this.overviewFormatter),products:c.map(($)=>Ws0($,this.productFormatter))})}}import{jsxDEV as y0,Fragment as Jr2}from"preact/jsx-dev-runtime";var hs0=({overview:A,products:f})=>{let{frontmatter:w,body:Q,labels:B}=A;return y0(Jr2,{children:[y0(o2,{title:w.headline,description:w.tagline},void 0,!1,void 0,this),y0("header",{className:"relative w-full min-h-[80vh] flex items-end px-6 md:px-12 bg-brand-dark overflow-hidden",children:[y0("style",{children:`
26869
+ `;var xs=cs0;import{join as Fr2}from"path";var Is0=["prompt","note","link","wishlist","topics","directory-sync","agents","mcp","discord","a2a"],$s0=[...Is0,"image","dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder","webserver"],Kr2=[...$s0,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],us0=yH({name:"rover",version:"0.1.0",model:"gpt-5.4-mini",site:FO,theme:xs,presets:{core:Is0,default:$s0,full:Kr2},evalDisable:["discord","webserver","mcp","analytics","dashboard"],capabilities:[["prompt",Vv,void 0],["image",Aq,void 0],["dashboard",QO,void 0],["blog",MvA,{}],["series",RvA,void 0],["decks",lM,void 0],["note",Lv,{}],["link",qv,{}],["portfolio",ZWA,{}],["topics",Ea,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",mWA,{generationSchedules:{newsletter:"0 9 * * 1","social-post":"0 10 * * *"},generationConditions:{newsletter:{skipIfDraftExists:!0,minSourceEntities:1,sourceEntityType:"post"},"social-post":{skipIfDraftExists:!0,maxUnpublishedDrafts:5}}}],["social-media",tM,{autoGenerateOnBlogPublish:!0}],["newsletter",Wa0,{doubleOptIn:!0}],["obsidian-vault",wkA,{autoSync:!0}],["wishlist",ya,{}],["stock-photo",YkA,{}],["agents",fs,void 0],["directory-sync",rZ,{seedContent:!0,seedContentPath:Fr2(import.meta.dir,"..","seed-content"),initialSync:!0}],["analytics",Ra,{}],["site-info",kv,void 0],["site-builder",Nv,{cms:{}}]],interfaces:[["mcp",QU,()=>({})],["discord",PU,()=>({})],["webserver",RU,()=>({})],["a2a",TJ,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"public"},{pattern:"discord:*",level:"public"}]},deployment:{cdn:{enabled:!0,provider:"bunny"},dns:{enabled:!0,provider:"bunny"}}});$3();B0();YA();YA();B0();var cs=X.object({routeId:X.string(),sectionId:X.string()}),KO=v2.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:cs});B0();class Ds0 extends _2{constructor(){super({entityType:"site-content",schema:KO,frontmatterSchema:cs})}toMarkdown(A){let f=this.extractBody(A.content);return this.buildMarkdown(f,A.metadata)}fromMarkdown(A){return{content:A,entityType:"site-content",metadata:this.parseFrontmatter(A)}}}var GkA=new Ds0;YA();var Is=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")}),KOw=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()});class JkA{context;constructor(A){this.context=A}createJobOptions(A,f){if(!A)return;return{source:A.operationType??f,rootJobId:A.rootJobId??`${f}-${Date.now()}`,metadata:{operationType:A.operationType??"content_operations",progressToken:A.progressToken,pluginId:A.pluginId??"site-content"}}}async fetchRoutes(){let A=await this.context.messaging.send("site-builder:routes:list",{});if("noop"in A)throw Error("No handler for site-builder:routes:list \u2014 is site-builder plugin loaded?");if(!A.success||!A.data)throw Error("Failed to fetch routes from site-builder");return A.data}async generate(A,f,w){let Q=this.context.logger.child("SiteContentOperations"),B=await this.fetchRoutes(),x=B;if(A.routeId){if(x=B.filter((Y)=>Y.id===A.routeId),x.length===0)throw Error(`Route not found: ${A.routeId}`)}let c=[];for(let Y of x)for(let F of Y.sections){if(A.sectionId&&F.id!==A.sectionId)continue;if(F.content){Q.debug("Section has static content, skipping",{routeId:Y.id,sectionId:F.id});continue}if(F.template){let K=this.context.templates.getCapabilities(F.template);if(!K){Q.warn("Template not found, skipping section",{routeId:Y.id,sectionId:F.id,templateName:F.template});continue}if(!K.canGenerate){Q.debug("Template doesn't support generation, skipping",{routeId:Y.id,sectionId:F.id,templateName:F.template,capabilities:K});continue}}else{Q.debug("Section has no template, skipping",{routeId:Y.id,sectionId:F.id});continue}if(!A.force&&!A.dryRun){let K=`${Y.id}:${F.id}`;if(await this.context.entityService.getEntity("site-content",K)){Q.debug("Content already exists, skipping",{routeId:Y.id,sectionId:F.id});continue}}c.push({route:Y,section:F})}let I=c.length;if(A.dryRun)return{jobs:[],totalSections:I,queuedSections:I,batchId:`dry-run-${Date.now()}`};let $=[],u=[];for(let{route:Y,section:F}of c){let K=`${Y.id}:${F.id}`,Z=F.template,k={routeId:Y.id,sectionId:F.id,entityId:K,entityType:"site-content",templateName:Z,context:{prompt:typeof F.content==="string"?F.content:void 0,data:{routeId:Y.id,sectionId:F.id,routeTitle:Y.title,routeDescription:Y.description,sectionContent:F.content},conversationId:"system"},siteConfig:f};u.push({type:"shell:content-generation",data:k})}if(u.length>0){let Y=this.createJobOptions(w,"site:content-generation"),F=await this.context.jobs.enqueueBatch(u,Y);for(let K=0;K<c.length;K++){let Z=c[K];if(Z)$.push({jobId:`${F}-${K}`,routeId:Z.route.id,sectionId:Z.section.id})}return{jobs:$,totalSections:I,queuedSections:$.length,batchId:F}}return{jobs:[],totalSections:I,queuedSections:0,batchId:`empty-${Date.now()}`}}}class bkA{siteConfig;operations;constructor(A,f){this.siteConfig=f;this.operations=new JkA(A)}async generateContent(A,f){let w=Is.parse(A);return this.operations.generate(w,this.siteConfig,f)}}B0();function Ys0(A,f){return[Tf(f,"generate","Generate content for all routes, a specific route, or a specific section",Is,async(w,Q)=>{let B=A();if(!B)return{success:!1,error:"Site content service not initialized"};if(w.sectionId&&!w.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let x={rootJobId:`generate-${Date.now()}`,progressToken:Q.progressToken,pluginId:f,operationType:"content_operations",interfaceType:Q.interfaceType,channelId:Q.channelId},c=await B.generateContent(w,x);return{success:!0,message:`Generated ${c.queuedSections} of ${c.totalSections} sections. ${c.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:c.batchId,jobsQueued:c.queuedSections,totalSections:c.totalSections,jobs:c.jobs}}})]}var Hs0={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.9",description:"Site content entity and generation orchestration",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class zkA extends yQ{siteContentService;constructor(){super("site-content",Hs0,{},X.object({}))}async onRegister(A){A.entities.register("site-content",KO,GkA),this.siteContentService=new bkA(A)}async getTools(){return Ys0(()=>this.siteContentService,this.id)}}function XO(){return new zkA}B0();YA();P2();YA();B0();var Us0=X.enum(["available","early access","coming soon","planned"]),Fs0=X.object({title:X.string(),description:X.string()}),BY=X.object({name:X.string(),availability:Us0,order:X.number()}),$s=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(Fs0).min(1).max(6),story:X.string()}),Zr2=BY.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),wz=v2.extend({entityType:X.literal("product"),metadata:Zr2}),us=wz.extend({frontmatter:BY,body:$s,labels:X.record(X.string(),X.string())}),Ds=us.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional()});B0();YA();YA();class Qz extends R1{constructor(){super($s,{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 NkA extends _2{constructor(){super({entityType:"product",schema:wz,frontmatterSchema:BY,bodyFormatter:new Qz})}toMarkdown(A){let f=this.extractBody(A.content);try{let w=this.parseFrontMatter(A.content,BY);return this.buildMarkdown(f,w)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,BY),w=x2(f.name);return{content:A,entityType:"product",metadata:{name:f.name,slug:w,availability:f.availability,order:f.order}}}}var Ys=new NkA;YA();B0();var Ks0=X.object({title:X.string(),description:X.string()}),Xs0=X.object({title:X.string(),description:X.string()}),vr2=X.object({title:X.string(),description:X.string()}),Zs0=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),xY=X.object({headline:X.string(),tagline:X.string()}),Wr2=X.object({title:X.string(),description:X.string()}),Hs=X.object({vision:X.string(),pillars:X.array(Ks0).min(1).max(6),approach:X.array(Wr2).min(1).max(6),productsIntro:X.string(),technologies:X.array(vr2).min(1).max(6),benefits:X.array(Xs0).min(1).max(6),cta:Zs0}),vs0=xY.pick({headline:!0}).extend({slug:X.string()}),Bz=v2.extend({entityType:X.literal("products-overview"),metadata:vs0}),ZO=Bz.extend({frontmatter:xY,body:Hs,labels:X.record(X.string(),X.string())});B0();YA();YA();class xz extends R1{constructor(){super(Hs,{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 CkA extends _2{constructor(){super({entityType:"products-overview",schema:Bz,frontmatterSchema:xY,bodyFormatter:new xz})}toMarkdown(A){let f=this.extractBody(A.content);try{let w=this.parseFrontMatter(A.content,xY);return this.buildMarkdown(f,w)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,xY),w=x2(f.headline);return{content:A,entityType:"products-overview",metadata:{headline:f.headline,slug:w}}}}var EkA=new CkA;B0();YA();var kr2=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function Ws0(A,f){let w=K2(A.content,BY),Q=f.parse(w.content),B=f.getLabels();return us.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}function ks0(A,f){let w=K2(A.content,xY),Q=f.parse(w.content),B=f.getLabels();return ZO.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}class Us{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new xz;productFormatter=new Qz;constructor(A){this.logger=A;this.logger.debug("ProductsDataSource initialized")}async fetch(A,f,w){let Q=kr2.parse(A),B=w.entityService;if(Q.entityType==="products-overview"){let u=(await B.listEntities("products-overview",{limit:1}))[0];if(!u)throw Error("Products overview entity not found");let Y=ks0(u,this.overviewFormatter);return f.parse(Y)}if(Q.query?.id){let u=(await B.listEntities("product",{filter:{metadata:{slug:Q.query.id}},limit:1}))[0];if(!u)throw Error(`Product not found: ${Q.query.id}`);return f.parse({product:Ws0(u,this.productFormatter)})}let[x,c]=await Promise.all([B.listEntities("products-overview",{limit:1}),B.listEntities("product",{sortFields:[{field:"order",direction:"asc"}]})]),I=x[0];if(!I)throw Error("Products overview entity not found");return f.parse({overview:ks0(I,this.overviewFormatter),products:c.map(($)=>Ws0($,this.productFormatter))})}}import{jsxDEV as y0,Fragment as Jr2}from"preact/jsx-dev-runtime";var hs0=({overview:A,products:f})=>{let{frontmatter:w,body:Q,labels:B}=A;return y0(Jr2,{children:[y0(o2,{title:w.headline,description:w.tagline},void 0,!1,void 0,this),y0("header",{className:"relative w-full min-h-[80vh] flex items-end px-6 md:px-12 bg-brand-dark overflow-hidden",children:[y0("style",{children:`
26870
26870
  @keyframes wave-drift {
26871
26871
  from { transform: translateX(0); }
26872
26872
  to { transform: translateX(-50%); }
@@ -26894,7 +26894,7 @@ ${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,
26894
26894
  @media (prefers-reduced-motion: reduce) {
26895
26895
  .detail-wave { animation: none; }
26896
26896
  }
26897
- `},void 0,!1,void 0,this),i1("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:i1("svg",{preserveAspectRatio:"none",width:"200%",height:"100%",viewBox:"0 0 1600 400",className:"block absolute inset-0 detail-wave",children:[i1("path",{d:"M0,200 C67,140 133,140 200,200 C267,260 333,260 400,200 C467,140 533,140 600,200 C667,260 733,260 800,200 C867,140 933,140 1000,200 C1067,260 1133,260 1200,200 C1267,140 1333,140 1400,200 C1467,260 1533,260 1600,200",className:"stroke-accent",strokeWidth:"2",strokeMiterlimit:"10",fill:"none",opacity:"0.15"},void 0,!1,void 0,this),i1("path",{d:"M0,230 C67,170 133,170 200,230 C267,290 333,290 400,230 C467,170 533,170 600,230 C667,290 733,290 800,230 C867,170 933,170 1000,230 C1067,290 1133,290 1200,230 C1267,170 1333,170 1400,230 C1467,290 1533,290 1600,230",className:"stroke-accent",strokeWidth:"1.5",strokeMiterlimit:"10",fill:"none",opacity:"0.06"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("div",{className:"absolute inset-0 cta-bg-pattern pointer-events-none"},void 0,!1,void 0,this),i1("div",{className:"relative z-10 max-w-5xl mx-auto w-full px-6 md:px-12 pt-12 md:pt-20 pb-16 md:pb-24",children:[i1("nav",{"aria-label":"Breadcrumb",className:"text-sm text-white/50 mb-8 hero-stagger-1",children:i1("ol",{className:"flex flex-wrap items-center gap-1",children:[i1("li",{className:"flex items-center gap-1",children:i1("a",{href:"/",className:"hover:text-white transition-colors",children:"Home"},void 0,!1,void 0,this)},void 0,!1,void 0,this),i1("li",{className:"flex items-center gap-1",children:[i1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),i1("a",{href:B,className:"hover:text-white transition-colors",children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("li",{className:"flex items-center gap-1",children:[i1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),i1("span",{className:"text-white font-medium",children:f.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("div",{className:"mb-6 hero-stagger-1",children:i1(Ec,{status:f.availability},void 0,!1,void 0,this)},void 0,!1,void 0,this),i1("h1",{className:"text-5xl md:text-6xl lg:text-[7rem] font-bold text-white tracking-tighter leading-[0.95] mb-6 md:mb-8 hero-stagger-1",children:f.name},void 0,!1,void 0,this),i1("div",{className:"w-20 h-1.5 bg-accent mb-6 md:mb-8 hero-stagger-2"},void 0,!1,void 0,this),i1("p",{className:"text-lg md:text-xl text-white/70 leading-relaxed max-w-xl hero-stagger-3",children:w.tagline},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),i1("section",{className:"bg-theme-subtle py-20 md:py-28 px-6 md:px-12",children:i1("div",{className:"max-w-4xl mx-auto space-y-16",children:[i1("div",{children:[i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:Q.promise},void 0,!1,void 0,this),i1("p",{className:"text-2xl md:text-3xl lg:text-4xl leading-relaxed text-heading font-light",children:w.promise},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-16",children:[i1("div",{children:[i1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.role},void 0,!1,void 0,this),i1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.role},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("div",{children:[i1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.purpose},void 0,!1,void 0,this),i1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.purpose},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("div",{children:[i1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.audience},void 0,!1,void 0,this),i1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.audience},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),i1("div",{className:"flex flex-col md:flex-row md:items-center gap-6 md:gap-12",children:[i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted whitespace-nowrap",children:Q.values},void 0,!1,void 0,this),i1(nx,{tags:w.values,variant:"accent",size:"md"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("section",{className:"cta-bg-pattern bg-brand py-20 md:py-32 px-6 md:px-12",children:i1("div",{className:"container mx-auto max-w-5xl",children:[i1("h2",{className:"text-sm tracking-widest uppercase text-white/50 mb-16",children:Q.features},void 0,!1,void 0,this),i1("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-16",children:w.features.map((I,$)=>i1("div",{children:i1("div",{className:"flex items-start gap-6",children:[i1("span",{className:"text-5xl md:text-6xl font-black text-white/10 leading-none shrink-0",children:String($+1).padStart(2,"0")},void 0,!1,void 0,this),i1("div",{className:"pt-2",children:[i1("div",{className:"w-8 h-1 bg-accent mb-4"},void 0,!1,void 0,this),i1("h3",{className:"text-xl font-bold text-white mb-3",children:I.title},void 0,!1,void 0,this),i1("p",{className:"text-white/70 leading-relaxed",children:I.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},I.title,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("section",{className:"py-20 md:py-32 px-6 md:px-12",children:i1("div",{className:"max-w-3xl mx-auto",children:[i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-12",children:Q.story},void 0,!1,void 0,this),i1("div",{className:"space-y-6",children:c.map((I,$)=>i1("p",{className:$===0?"text-2xl md:text-3xl leading-relaxed text-heading font-light":"text-lg leading-relaxed text-theme-muted",children:I},$,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("section",{className:"cta-bg-pattern bg-brand-dark pt-24 md:pt-32 pb-40 md:pb-48 -mb-[60px] px-6 md:px-12",children:i1("div",{className:"max-w-4xl mx-auto",children:[i1("p",{className:"text-sm tracking-widest uppercase text-white/60 mb-4",children:f.name},void 0,!1,void 0,this),i1("h2",{className:"text-3xl md:text-5xl font-bold text-white max-w-2xl mb-4",children:w.tagline},void 0,!1,void 0,this),i1("p",{className:"text-lg text-white/60 mb-10 max-w-xl",children:w.promise},void 0,!1,void 0,this),i1(_B,{href:B,variant:"outline-light",size:"lg",children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();var LkA=X.object({route:X.string().default("/products")});var Js0={name:"@brains/products",private:!0,version:"0.2.0-alpha.8",description:"Product entity management and overview page for marketing showcase",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Nr2=X.object({overview:ZO,products:X.array(Ds)}),Cr2=X.object({product:Ds});class qkA extends Nf{entityType=Ys.entityType;schema=wz;adapter=Ys;constructor(A={}){super("products",Js0,A,LkA)}getTemplates(){return{"product-list":i0({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:Nr2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:hs0}}),"product-detail":i0({name:"product-detail",description:"Individual product detail page",schema:Cr2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:Gs0}})}}getDataSources(){return[new Us(this.logger.child("ProductsDataSource"))]}async onRegister(A){A.entities.register("products-overview",Bz,EkA)}}function _kA(A={}){return new qkA(A)}import{join as vd2}from"path";var bs0=`/*
26897
+ `},void 0,!1,void 0,this),i1("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:i1("svg",{preserveAspectRatio:"none",width:"200%",height:"100%",viewBox:"0 0 1600 400",className:"block absolute inset-0 detail-wave",children:[i1("path",{d:"M0,200 C67,140 133,140 200,200 C267,260 333,260 400,200 C467,140 533,140 600,200 C667,260 733,260 800,200 C867,140 933,140 1000,200 C1067,260 1133,260 1200,200 C1267,140 1333,140 1400,200 C1467,260 1533,260 1600,200",className:"stroke-accent",strokeWidth:"2",strokeMiterlimit:"10",fill:"none",opacity:"0.15"},void 0,!1,void 0,this),i1("path",{d:"M0,230 C67,170 133,170 200,230 C267,290 333,290 400,230 C467,170 533,170 600,230 C667,290 733,290 800,230 C867,170 933,170 1000,230 C1067,290 1133,290 1200,230 C1267,170 1333,170 1400,230 C1467,290 1533,290 1600,230",className:"stroke-accent",strokeWidth:"1.5",strokeMiterlimit:"10",fill:"none",opacity:"0.06"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("div",{className:"absolute inset-0 cta-bg-pattern pointer-events-none"},void 0,!1,void 0,this),i1("div",{className:"relative z-10 max-w-5xl mx-auto w-full px-6 md:px-12 pt-12 md:pt-20 pb-16 md:pb-24",children:[i1("nav",{"aria-label":"Breadcrumb",className:"text-sm text-white/50 mb-8 hero-stagger-1",children:i1("ol",{className:"flex flex-wrap items-center gap-1",children:[i1("li",{className:"flex items-center gap-1",children:i1("a",{href:"/",className:"hover:text-white transition-colors",children:"Home"},void 0,!1,void 0,this)},void 0,!1,void 0,this),i1("li",{className:"flex items-center gap-1",children:[i1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),i1("a",{href:B,className:"hover:text-white transition-colors",children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("li",{className:"flex items-center gap-1",children:[i1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),i1("span",{className:"text-white font-medium",children:f.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("div",{className:"mb-6 hero-stagger-1",children:i1(Ec,{status:f.availability},void 0,!1,void 0,this)},void 0,!1,void 0,this),i1("h1",{className:"text-5xl md:text-6xl lg:text-[7rem] font-bold text-white tracking-tighter leading-[0.95] mb-6 md:mb-8 hero-stagger-1",children:f.name},void 0,!1,void 0,this),i1("div",{className:"w-20 h-1.5 bg-accent mb-6 md:mb-8 hero-stagger-2"},void 0,!1,void 0,this),i1("p",{className:"text-lg md:text-xl text-white/70 leading-relaxed max-w-xl hero-stagger-3",children:w.tagline},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),i1("section",{className:"bg-theme-subtle py-20 md:py-28 px-6 md:px-12",children:i1("div",{className:"max-w-4xl mx-auto space-y-16",children:[i1("div",{children:[i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:Q.promise},void 0,!1,void 0,this),i1("p",{className:"text-2xl md:text-3xl lg:text-4xl leading-relaxed text-heading font-light",children:w.promise},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-16",children:[i1("div",{children:[i1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.role},void 0,!1,void 0,this),i1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.role},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("div",{children:[i1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.purpose},void 0,!1,void 0,this),i1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.purpose},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i1("div",{children:[i1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.audience},void 0,!1,void 0,this),i1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.audience},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),i1("div",{className:"flex flex-col md:flex-row md:items-center gap-6 md:gap-12",children:[i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted whitespace-nowrap",children:Q.values},void 0,!1,void 0,this),i1(nx,{tags:w.values,variant:"accent",size:"md"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("section",{className:"cta-bg-pattern bg-brand py-20 md:py-32 px-6 md:px-12",children:i1("div",{className:"container mx-auto max-w-5xl",children:[i1("h2",{className:"text-sm tracking-widest uppercase text-white/50 mb-16",children:Q.features},void 0,!1,void 0,this),i1("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-16",children:w.features.map((I,$)=>i1("div",{children:i1("div",{className:"flex items-start gap-6",children:[i1("span",{className:"text-5xl md:text-6xl font-black text-white/10 leading-none shrink-0",children:String($+1).padStart(2,"0")},void 0,!1,void 0,this),i1("div",{className:"pt-2",children:[i1("div",{className:"w-8 h-1 bg-accent mb-4"},void 0,!1,void 0,this),i1("h3",{className:"text-xl font-bold text-white mb-3",children:I.title},void 0,!1,void 0,this),i1("p",{className:"text-white/70 leading-relaxed",children:I.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},I.title,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("section",{className:"py-20 md:py-32 px-6 md:px-12",children:i1("div",{className:"max-w-3xl mx-auto",children:[i1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-12",children:Q.story},void 0,!1,void 0,this),i1("div",{className:"space-y-6",children:c.map((I,$)=>i1("p",{className:$===0?"text-2xl md:text-3xl leading-relaxed text-heading font-light":"text-lg leading-relaxed text-theme-muted",children:I},$,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),i1("section",{className:"cta-bg-pattern bg-brand-dark pt-24 md:pt-32 pb-40 md:pb-48 -mb-[60px] px-6 md:px-12",children:i1("div",{className:"max-w-4xl mx-auto",children:[i1("p",{className:"text-sm tracking-widest uppercase text-white/60 mb-4",children:f.name},void 0,!1,void 0,this),i1("h2",{className:"text-3xl md:text-5xl font-bold text-white max-w-2xl mb-4",children:w.tagline},void 0,!1,void 0,this),i1("p",{className:"text-lg text-white/60 mb-10 max-w-xl",children:w.promise},void 0,!1,void 0,this),i1(_B,{href:B,variant:"outline-light",size:"lg",children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();var LkA=X.object({route:X.string().default("/products")});var Js0={name:"@brains/products",private:!0,version:"0.2.0-alpha.9",description:"Product entity management and overview page for marketing showcase",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Nr2=X.object({overview:ZO,products:X.array(Ds)}),Cr2=X.object({product:Ds});class qkA extends Nf{entityType=Ys.entityType;schema=wz;adapter=Ys;constructor(A={}){super("products",Js0,A,LkA)}getTemplates(){return{"product-list":i0({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:Nr2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:hs0}}),"product-detail":i0({name:"product-detail",description:"Individual product detail page",schema:Cr2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:Gs0}})}}getDataSources(){return[new Us(this.logger.child("ProductsDataSource"))]}async onRegister(A){A.entities.register("products-overview",Bz,EkA)}}function _kA(A={}){return new qkA(A)}import{join as vd2}from"path";var bs0=`/*
26898
26898
  * Shared globals + helpers used by tree / constellation / roots canvas
26899
26899
  * scripts. Concatenated in front of each variant canvas at site-package
26900
26900
  * load time (see sites/rizom/src/index.ts) so the variant canvases
@@ -29792,7 +29792,7 @@ Your task is to:
29792
29792
  2. Generate a clear, natural summary that captures key points, decisions, and action items
29793
29793
  3. Return structured data in the required JSON format
29794
29794
 
29795
- Be concise but comprehensive, focusing on the most important information.`});B0();YA();var bd2=X.object({entityType:X.literal("summary"),query:X.object({id:X.string().optional(),conversationId:X.string().optional(),limit:X.number().optional()}).optional()});class mkA{logger;id="summary:entities";name="Summary Entity DataSource";description="Fetches and transforms summary entities for rendering";adapter;constructor(A){this.logger=A;this.adapter=new mu,this.logger.debug("SummaryDataSource initialized")}async fetch(A,f,w){let Q=bd2.parse(A),B=w.entityService,x=Q.query?.conversationId??Q.query?.id;if(x){let u=await B.getEntity(Q.query?.conversationId?"summary":Q.entityType,x);if(!u)throw Error(`Summary not found: ${x}`);let Y;try{let K=K2(u.content,X.record(X.string(),X.unknown()));Y=this.adapter.parseEntriesFromContent(K.content)}catch{Y=this.adapter.parseEntriesFromContent(u.content)}let F={conversationId:u.metadata.conversationId,channelName:u.metadata.channelName,entries:Y,totalMessages:u.metadata.totalMessages,entryCount:Y.length,updated:u.updated};return f.parse(F)}let I=(await B.listEntities(Q.entityType,{limit:Q.query?.limit??100})).map((u)=>{let Y;try{let K=K2(u.content,X.record(X.string(),X.unknown()));Y=this.adapter.parseEntriesFromContent(K.content)}catch{Y=this.adapter.parseEntriesFromContent(u.content)}let F=Y[0];return{id:u.id,conversationId:u.metadata.conversationId,channelName:u.metadata.channelName,entryCount:Y.length,totalMessages:u.metadata.totalMessages,latestEntry:F?.title??"No entries",updated:u.updated,created:u.created}}),$={summaries:I,totalCount:I.length};return this.logger.debug("Creating list data",{summaryCount:I.length,firstSummary:I[0]?.id}),f.parse($)}}var Ae0={name:"@brains/summary",private:!0,version:"0.2.0-alpha.8",description:"Plugin for generating entity summaries and digests",type:"module",main:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint src test --ext .ts,.tsx","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};var Nd2=new mu;class lkA extends Nf{entityType="summary";schema=WO;adapter=Nd2;digestHandler=null;constructor(A){super("summary",Ae0,A??{},PkA)}getConfig(){return this.config}getTemplates(){return{"summary-list":st0,"summary-detail":tt0,"ai-response":et0}}getDataSources(){return[new mkA(this.logger)]}async onRegister(A){if(this.digestHandler=$Y.getInstance(A,this.logger),this.config.enableAutoSummary)A.messaging.subscribe("conversation:digest",async(f)=>{let w=lP.parse(f.payload);return await this.handleDigestMessage({...f,payload:w}),{success:!0}}),this.logger.debug("Summary plugin subscribed to digest events")}async derive(A,f,w){}async handleDigestMessage(A){if(!this.digestHandler){this.logger.error("Digest handler not initialized");return}try{await this.digestHandler.handleDigest(A.payload)}catch(f){this.logger.error("Failed to handle digest message",{messageId:A.id,error:h0(f)})}}}function TkA(A){return new lkA(A)}var fe0=["prompt","directory-sync","note","link","topics","agents","mcp","discord","a2a"],Ed2=[...fe0,"image","site-info","site-content","site-builder","webserver"],we0=yH({name:"relay",version:"0.1.0",model:"gpt-5.4-mini",site:uz,theme:Dz,presets:{core:fe0,default:Ed2},evalDisable:["webserver","discord"],capabilities:[["prompt",Vv,void 0],["note",Lv,{}],["link",qv,{}],["image",Aq,void 0],["topics",Ea,{}],["summary",TkA,{}],["decks",lM,void 0],["agents",fs,void 0],["directory-sync",rZ,{seedContent:!0,seedContentPath:Cd2(import.meta.dir,"..","seed-content"),initialSync:!0}],["site-content",XO,void 0],["site-info",kv,void 0],["site-builder",Nv,{}]],interfaces:[["mcp",QU,()=>({})],["discord",PU,()=>({captureUrls:!0})],["a2a",TJ,()=>({})],["webserver",RU,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"anchor"},{pattern:"discord:*",level:"public"}]},deployment:{cdn:{enabled:!0,provider:"bunny"}}});import{readFileSync as ms2}from"fs";import{join as ls2}from"path";import{execSync as Ts2}from"child_process";import{parseArgs as _d2}from"util";var Vd2={model:{type:"string"},domain:{type:"string"},"content-repo":{type:"string"},backend:{type:"string"},"push-to":{type:"string"},"ai-api-key":{type:"string"},"no-interactive":{type:"boolean"},preview:{type:"boolean"},deploy:{type:"boolean"},regen:{type:"boolean"},all:{type:"boolean"},only:{type:"string"},"dry-run":{type:"boolean"},remote:{type:"string"},token:{type:"string"},help:{type:"boolean",short:"h"},version:{type:"boolean",short:"v"}};function uY(A,f){let w=A[f];return typeof w==="string"?w:void 0}function Yz(A,f){let w=A[f];return typeof w==="boolean"?w:void 0}function Qe0(A){let{values:f,positionals:w}=_d2({args:A,options:Vd2,allowPositionals:!0,strict:!1});if(f.help)return{command:"help",args:[],flags:{help:!0}};if(f.version)return{command:"version",args:[],flags:{version:!0}};return{command:w[0]??"help",args:w.slice(1),flags:{model:uY(f,"model"),domain:uY(f,"domain"),"content-repo":uY(f,"content-repo"),backend:uY(f,"backend"),"push-to":uY(f,"push-to"),"ai-api-key":uY(f,"ai-api-key"),"no-interactive":Yz(f,"no-interactive"),preview:Yz(f,"preview"),deploy:Yz(f,"deploy"),regen:Yz(f,"regen"),all:Yz(f,"all"),only:uY(f,"only"),"dry-run":Yz(f,"dry-run"),remote:uY(f,"remote"),token:uY(f,"token")}}}import{mkdirSync as Ns2}from"fs";import{join as Cs2}from"path";import{spawn as Es2,execSync as Ls2}from"child_process";var Rs={name:"@rizom/brain",version:"0.2.0-alpha.8",description:"Brain runtime + CLI \u2014 scaffold, run, and manage AI brain instances",type:"module",bin:{brain:"./dist/brain.js"},exports:{"./cli":"./dist/brain.js","./site":{types:"./dist/site.d.ts",import:"./dist/site.js"},"./themes":{types:"./dist/themes.d.ts",import:"./dist/themes.js"},"./deploy":{types:"./dist/deploy.d.ts",import:"./dist/deploy.js"}},files:["dist","templates"],scripts:{build:"bun scripts/build.ts",prepublishOnly:"bun scripts/build.ts",typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts"},dependencies:{"@clack/prompts":"^0.11.0","@modelcontextprotocol/sdk":"^1.24.0","@tailwindcss/postcss":"^4.1.13","@tailwindcss/typography":"^0.5.19",postcss:"^8.5.6",preact:"^10.27.2","preact-render-to-string":"^6.3.1",tailwindcss:"^4.1.11"},optionalDependencies:{"@libsql/client":"^0.15.7","@tailwindcss/oxide":"^4.1.4","better-sqlite3":"^11.8.1",lightningcss:"^1.29.2","react-devtools-core":"^6.1.1",sharp:"^0.34.5"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/mcp-service":"workspace:*","@brains/plugins":"workspace:*","@brains/ranger":"workspace:*","@brains/relay":"workspace:*","@brains/rover":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-default":"workspace:*","@brains/site-personal":"workspace:*","@brains/site-professional":"workspace:*","@brains/site-rizom":"workspace:*","@brains/theme-default":"workspace:*","@brains/theme-rizom":"workspace:*","@brains/typescript-config":"workspace:*","@brains/utils":"workspace:*","@types/bun":"latest",typescript:"^5.3.3"},publishConfig:{access:"public"},repository:{type:"git",url:"https://github.com/rizom-ai/brains.git",directory:"packages/brain-cli"},license:"Apache-2.0",author:"Yeehaa <yeehaa@rizom.ai> (https://rizom.ai)",homepage:"https://github.com/rizom-ai/brains/tree/main/packages/brain-cli#readme",bugs:"https://github.com/rizom-ai/brains/issues",engines:{bun:">=1.3.3"},keywords:["brain","ai","cli","mcp","agent","personal-ai","knowledge-management"]};import{mkdirSync as Ie0,writeFileSync as ms,chmodSync as ls,existsSync as Ts,readFileSync as Hz}from"fs";import{basename as rkA,dirname as dkA,join as Bw,resolve as td2}from"path";import{fileURLToPath as ed2}from"url";GO();import{existsSync as Be0,readFileSync as Pd2}from"fs";import{dirname as Rd2,join as xe0}from"path";var ns={rover:`# This env file uses @env-spec - see https://varlock.dev/env-spec for more info
29795
+ Be concise but comprehensive, focusing on the most important information.`});B0();YA();var bd2=X.object({entityType:X.literal("summary"),query:X.object({id:X.string().optional(),conversationId:X.string().optional(),limit:X.number().optional()}).optional()});class mkA{logger;id="summary:entities";name="Summary Entity DataSource";description="Fetches and transforms summary entities for rendering";adapter;constructor(A){this.logger=A;this.adapter=new mu,this.logger.debug("SummaryDataSource initialized")}async fetch(A,f,w){let Q=bd2.parse(A),B=w.entityService,x=Q.query?.conversationId??Q.query?.id;if(x){let u=await B.getEntity(Q.query?.conversationId?"summary":Q.entityType,x);if(!u)throw Error(`Summary not found: ${x}`);let Y;try{let K=K2(u.content,X.record(X.string(),X.unknown()));Y=this.adapter.parseEntriesFromContent(K.content)}catch{Y=this.adapter.parseEntriesFromContent(u.content)}let F={conversationId:u.metadata.conversationId,channelName:u.metadata.channelName,entries:Y,totalMessages:u.metadata.totalMessages,entryCount:Y.length,updated:u.updated};return f.parse(F)}let I=(await B.listEntities(Q.entityType,{limit:Q.query?.limit??100})).map((u)=>{let Y;try{let K=K2(u.content,X.record(X.string(),X.unknown()));Y=this.adapter.parseEntriesFromContent(K.content)}catch{Y=this.adapter.parseEntriesFromContent(u.content)}let F=Y[0];return{id:u.id,conversationId:u.metadata.conversationId,channelName:u.metadata.channelName,entryCount:Y.length,totalMessages:u.metadata.totalMessages,latestEntry:F?.title??"No entries",updated:u.updated,created:u.created}}),$={summaries:I,totalCount:I.length};return this.logger.debug("Creating list data",{summaryCount:I.length,firstSummary:I[0]?.id}),f.parse($)}}var Ae0={name:"@brains/summary",private:!0,version:"0.2.0-alpha.9",description:"Plugin for generating entity summaries and digests",type:"module",main:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint src test --ext .ts,.tsx","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};var Nd2=new mu;class lkA extends Nf{entityType="summary";schema=WO;adapter=Nd2;digestHandler=null;constructor(A){super("summary",Ae0,A??{},PkA)}getConfig(){return this.config}getTemplates(){return{"summary-list":st0,"summary-detail":tt0,"ai-response":et0}}getDataSources(){return[new mkA(this.logger)]}async onRegister(A){if(this.digestHandler=$Y.getInstance(A,this.logger),this.config.enableAutoSummary)A.messaging.subscribe("conversation:digest",async(f)=>{let w=lP.parse(f.payload);return await this.handleDigestMessage({...f,payload:w}),{success:!0}}),this.logger.debug("Summary plugin subscribed to digest events")}async derive(A,f,w){}async handleDigestMessage(A){if(!this.digestHandler){this.logger.error("Digest handler not initialized");return}try{await this.digestHandler.handleDigest(A.payload)}catch(f){this.logger.error("Failed to handle digest message",{messageId:A.id,error:h0(f)})}}}function TkA(A){return new lkA(A)}var fe0=["prompt","directory-sync","note","link","topics","agents","mcp","discord","a2a"],Ed2=[...fe0,"image","site-info","site-content","site-builder","webserver"],we0=yH({name:"relay",version:"0.1.0",model:"gpt-5.4-mini",site:uz,theme:Dz,presets:{core:fe0,default:Ed2},evalDisable:["webserver","discord"],capabilities:[["prompt",Vv,void 0],["note",Lv,{}],["link",qv,{}],["image",Aq,void 0],["topics",Ea,{}],["summary",TkA,{}],["decks",lM,void 0],["agents",fs,void 0],["directory-sync",rZ,{seedContent:!0,seedContentPath:Cd2(import.meta.dir,"..","seed-content"),initialSync:!0}],["site-content",XO,void 0],["site-info",kv,void 0],["site-builder",Nv,{}]],interfaces:[["mcp",QU,()=>({})],["discord",PU,()=>({captureUrls:!0})],["a2a",TJ,()=>({})],["webserver",RU,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"anchor"},{pattern:"discord:*",level:"public"}]},deployment:{cdn:{enabled:!0,provider:"bunny"}}});import{readFileSync as ms2}from"fs";import{join as ls2}from"path";import{execSync as Ts2}from"child_process";import{parseArgs as _d2}from"util";var Vd2={model:{type:"string"},domain:{type:"string"},"content-repo":{type:"string"},backend:{type:"string"},"push-to":{type:"string"},"ai-api-key":{type:"string"},"no-interactive":{type:"boolean"},preview:{type:"boolean"},deploy:{type:"boolean"},regen:{type:"boolean"},all:{type:"boolean"},only:{type:"string"},"dry-run":{type:"boolean"},remote:{type:"string"},token:{type:"string"},help:{type:"boolean",short:"h"},version:{type:"boolean",short:"v"}};function uY(A,f){let w=A[f];return typeof w==="string"?w:void 0}function Yz(A,f){let w=A[f];return typeof w==="boolean"?w:void 0}function Qe0(A){let{values:f,positionals:w}=_d2({args:A,options:Vd2,allowPositionals:!0,strict:!1});if(f.help)return{command:"help",args:[],flags:{help:!0}};if(f.version)return{command:"version",args:[],flags:{version:!0}};return{command:w[0]??"help",args:w.slice(1),flags:{model:uY(f,"model"),domain:uY(f,"domain"),"content-repo":uY(f,"content-repo"),backend:uY(f,"backend"),"push-to":uY(f,"push-to"),"ai-api-key":uY(f,"ai-api-key"),"no-interactive":Yz(f,"no-interactive"),preview:Yz(f,"preview"),deploy:Yz(f,"deploy"),regen:Yz(f,"regen"),all:Yz(f,"all"),only:uY(f,"only"),"dry-run":Yz(f,"dry-run"),remote:uY(f,"remote"),token:uY(f,"token")}}}import{mkdirSync as Ns2}from"fs";import{join as Cs2}from"path";import{spawn as Es2,execSync as Ls2}from"child_process";var Rs={name:"@rizom/brain",version:"0.2.0-alpha.9",description:"Brain runtime + CLI \u2014 scaffold, run, and manage AI brain instances",type:"module",bin:{brain:"./dist/brain.js"},exports:{"./cli":"./dist/brain.js","./site":{types:"./dist/site.d.ts",import:"./dist/site.js"},"./themes":{types:"./dist/themes.d.ts",import:"./dist/themes.js"},"./deploy":{types:"./dist/deploy.d.ts",import:"./dist/deploy.js"}},files:["dist","templates"],scripts:{build:"bun scripts/build.ts",prepublishOnly:"bun scripts/build.ts",typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts"},dependencies:{"@clack/prompts":"^0.11.0","@modelcontextprotocol/sdk":"^1.24.0","@tailwindcss/postcss":"^4.1.13","@tailwindcss/typography":"^0.5.19",postcss:"^8.5.6",preact:"^10.27.2","preact-render-to-string":"^6.3.1",tailwindcss:"^4.1.11"},optionalDependencies:{"@libsql/client":"^0.15.7","@tailwindcss/oxide":"^4.1.4","better-sqlite3":"^11.8.1",lightningcss:"^1.29.2","react-devtools-core":"^6.1.1",sharp:"^0.34.5"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/mcp-service":"workspace:*","@brains/plugins":"workspace:*","@brains/ranger":"workspace:*","@brains/relay":"workspace:*","@brains/rover":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-default":"workspace:*","@brains/site-personal":"workspace:*","@brains/site-professional":"workspace:*","@brains/site-rizom":"workspace:*","@brains/theme-default":"workspace:*","@brains/theme-rizom":"workspace:*","@brains/typescript-config":"workspace:*","@brains/utils":"workspace:*","@types/bun":"latest",typescript:"^5.3.3"},publishConfig:{access:"public"},repository:{type:"git",url:"https://github.com/rizom-ai/brains.git",directory:"packages/brain-cli"},license:"Apache-2.0",author:"Yeehaa <yeehaa@rizom.ai> (https://rizom.ai)",homepage:"https://github.com/rizom-ai/brains/tree/main/packages/brain-cli#readme",bugs:"https://github.com/rizom-ai/brains/issues",engines:{bun:">=1.3.3"},keywords:["brain","ai","cli","mcp","agent","personal-ai","knowledge-management"]};import{mkdirSync as Ie0,writeFileSync as ms,chmodSync as ls,existsSync as Ts,readFileSync as Hz}from"fs";import{basename as rkA,dirname as dkA,join as Bw,resolve as td2}from"path";import{fileURLToPath as ed2}from"url";GO();import{existsSync as Be0,readFileSync as Pd2}from"fs";import{dirname as Rd2,join as xe0}from"path";var ns={rover:`# This env file uses @env-spec - see https://varlock.dev/env-spec for more info
29796
29796
  #
29797
29797
  # @defaultRequired=false @defaultSensitive=false
29798
29798
  # ----------