@rizom/brain 0.2.0-alpha.13 → 0.2.0-alpha.14
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 +25 -25
- package/dist/site.js +5 -5
- package/dist/site.js.map +1 -1
- package/package.json +1 -1
package/dist/brain.js
CHANGED
|
@@ -503,7 +503,7 @@ This will delete existing topics and regenerate them from scratch.`,args:{...x,c
|
|
|
503
503
|
hash text NOT NULL,
|
|
504
504
|
created_at numeric
|
|
505
505
|
)
|
|
506
|
-
`;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 fm=T(()=>{DoA();TB()});async function YoA(A,f){let w=f?.child("entity-migrate")??O2.getInstance().child("entity-migrate"),{db:Q,client:B,url:x}=OP(A);w.debug("Running entity database migrations...");try{await jP(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 gP(B),w.debug("Entity database migrations completed successfully")}catch(c){throw w.error("Entity database migration failed:",c),c}finally{B.close()}}var HoA=T(()=>{fm();Y2A();YA()});async function UoA(A,f){let w=f?.child("job-queue-migrate")??O2.getInstance().child("job-queue-migrate"),{db:Q,client:B,url:x}=MP(A);w.debug("Running job queue migrations...");try{await iP(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 FoA=T(()=>{fm();$2A();YA()});async function KoA(A,f){let w=f?.child("conversation-migrate")??O2.getInstance().child("conversation-migrate"),{db:Q,client:B,url:x}=TP(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 XoA=T(()=>{fm();R2A();YA()});class UL{logger;migrations;constructor(A,f){this.logger=A,this.migrations=f??{getStandardConfigWithDirectories:TC,migrateEntities:YoA,migrateJobQueue:UoA,migrateConversations:KoA}}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 J9A=T(()=>{en();HoA();FoA();XoA()});var wm;var b9A=T(()=>{YA();wm=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 WoA;var ZoA=T(()=>{WoA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.13",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((gb1,Qm)=>{(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 vA: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 i(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,i(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,"$&/")+"/"),i(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+=i(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+=i(n0,KA,dA,U1,m0);else if(U1==="object"){if(typeof fA.then==="function")return i(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 i(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
|
|
506
|
+
`;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 fm=T(()=>{DoA();TB()});async function YoA(A,f){let w=f?.child("entity-migrate")??O2.getInstance().child("entity-migrate"),{db:Q,client:B,url:x}=OP(A);w.debug("Running entity database migrations...");try{await jP(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 gP(B),w.debug("Entity database migrations completed successfully")}catch(c){throw w.error("Entity database migration failed:",c),c}finally{B.close()}}var HoA=T(()=>{fm();Y2A();YA()});async function UoA(A,f){let w=f?.child("job-queue-migrate")??O2.getInstance().child("job-queue-migrate"),{db:Q,client:B,url:x}=MP(A);w.debug("Running job queue migrations...");try{await iP(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 FoA=T(()=>{fm();$2A();YA()});async function KoA(A,f){let w=f?.child("conversation-migrate")??O2.getInstance().child("conversation-migrate"),{db:Q,client:B,url:x}=TP(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 XoA=T(()=>{fm();R2A();YA()});class UL{logger;migrations;constructor(A,f){this.logger=A,this.migrations=f??{getStandardConfigWithDirectories:TC,migrateEntities:YoA,migrateJobQueue:UoA,migrateConversations:KoA}}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 J9A=T(()=>{en();HoA();FoA();XoA()});var wm;var b9A=T(()=>{YA();wm=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 WoA;var ZoA=T(()=>{WoA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.14",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((gb1,Qm)=>{(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 vA: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 i(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,i(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,"$&/")+"/"),i(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+=i(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+=i(n0,KA,dA,U1,m0);else if(U1==="object"){if(typeof fA.then==="function")return i(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 i(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
|
|
507
507
|
|
|
508
508
|
Your code should look like:
|
|
509
509
|
const MyComponent = lazy(() => import('./MyComponent'))
|
|
@@ -1862,7 +1862,7 @@ Example bad output: "A dreamlike crystal formation glowing with ethereal light i
|
|
|
1862
1862
|
Title: "${A.entityTitle??I}"
|
|
1863
1863
|
|
|
1864
1864
|
Content:
|
|
1865
|
-
${A.entityContent}`,cq1);$=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=KA0(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=uk(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 XA0={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.13",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 uq1=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 _cA extends Nf{entityType=dH.entityType;schema=eL;adapter=dH;constructor(A={}){super("image",XA0,A,uq1)}getEntityTypeConfig(){return{embeddable:!1}}createGenerationHandler(A){return new Zl(A,this.logger)}async onRegister(A){let f=new Zl(A,this.logger);A.jobs.registerHandler("image-generate",f)}}function wq(A){return new _cA(A)}B0();import{StdioServerTransport as Dq1}from"@modelcontextprotocol/sdk/server/stdio.js";function ZA0(){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 VcA(){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 Wl(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 VcA()}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?Wl(this.config.logger):ZA0()}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 Dq1,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 y7A=o0(o80(),1),BB0=o0(AB0(),1),B_=o0(wB0(),1);import{randomUUID as QB0}from"crypto";import{StreamableHTTPServerTransport as Hl1}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?Wl(this.config.logger):VcA(),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=y7A.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(y7A.default.json()),this.app.use(BB0.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",B_.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 Hl1({sessionIdGenerator:()=>QB0(),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",B_.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",B_.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",B_.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??QB0();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 S7A=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 xB0(A,f){return[]}B0();function p7A(A,f){A.messaging.subscribe("job-progress",async(w)=>{let Q=_k.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 cB0={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.13",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",cB0,f,S7A)}async getTools(){return xB0(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`),p7A(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(zL0(),1);YA();B0();var EHA=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),...pP.shape,captureUrlEmoji:X.string().default("\uD83D\uDD16")});var NL0={name:"@brains/discord",private:!0,version:"0.2.0-alpha.13",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 LHA=2000,LF2=8000,qF2=100;function qp(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",NL0,A,EHA);this.fetchText=f.fetchText??wP}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(!qp(w))return;let Q=QC(f,LHA);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(!qp(w))return;let Q=QC(f,LHA),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(!qp(Q))return!1;try{return await(await Q.messages.fetch(f)).edit(w.slice(0,LHA)),!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+=`
|
|
1865
|
+
${A.entityContent}`,cq1);$=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=KA0(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=uk(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 XA0={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.14",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 uq1=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 _cA extends Nf{entityType=dH.entityType;schema=eL;adapter=dH;constructor(A={}){super("image",XA0,A,uq1)}getEntityTypeConfig(){return{embeddable:!1}}createGenerationHandler(A){return new Zl(A,this.logger)}async onRegister(A){let f=new Zl(A,this.logger);A.jobs.registerHandler("image-generate",f)}}function wq(A){return new _cA(A)}B0();import{StdioServerTransport as Dq1}from"@modelcontextprotocol/sdk/server/stdio.js";function ZA0(){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 VcA(){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 Wl(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 VcA()}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?Wl(this.config.logger):ZA0()}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 Dq1,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 y7A=o0(o80(),1),BB0=o0(AB0(),1),B_=o0(wB0(),1);import{randomUUID as QB0}from"crypto";import{StreamableHTTPServerTransport as Hl1}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?Wl(this.config.logger):VcA(),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=y7A.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(y7A.default.json()),this.app.use(BB0.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",B_.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 Hl1({sessionIdGenerator:()=>QB0(),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",B_.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",B_.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",B_.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??QB0();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 S7A=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 xB0(A,f){return[]}B0();function p7A(A,f){A.messaging.subscribe("job-progress",async(w)=>{let Q=_k.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 cB0={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.14",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",cB0,f,S7A)}async getTools(){return xB0(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`),p7A(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(zL0(),1);YA();B0();var EHA=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),...pP.shape,captureUrlEmoji:X.string().default("\uD83D\uDD16")});var NL0={name:"@brains/discord",private:!0,version:"0.2.0-alpha.14",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 LHA=2000,LF2=8000,qF2=100;function qp(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",NL0,A,EHA);this.fetchText=f.fetchText??wP}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(!qp(w))return;let Q=QC(f,LHA);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(!qp(w))return;let Q=QC(f,LHA),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(!qp(Q))return!1;try{return await(await Q.messages.fetch(f)).edit(w.slice(0,LHA)),!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+=`
|
|
1866
1866
|
|
|
1867
1867
|
`+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,qF2),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(qp($))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=jk(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}))},LF2);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 XK2}from"path";var qHA=(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 CL0=Symbol();var EL0=async(A,f=Object.create(null))=>{let{all:w=!1,dot:Q=!1}=f,x=(A instanceof _p?A.raw.headers:A.headers).get("Content-Type");if(x?.startsWith("multipart/form-data")||x?.startsWith("application/x-www-form-urlencoded"))return _F2(A,{all:w,dot:Q});return{}};async function _F2(A,f){let w=await A.formData();if(w)return VF2(w,f);return{}}function VF2(A,f){let w=Object.create(null);if(A.forEach((Q,B)=>{if(!(f.all||B.endsWith("[]")))w[B]=Q;else MF2(w,B,Q)}),f.dot)Object.entries(w).forEach(([Q,B])=>{if(Q.includes("."))iF2(w,Q,B),delete w[Q]});return w}var MF2=(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]},iF2=(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 VHA=(A)=>{let f=A.split("/");if(f[0]==="")f.shift();return f},LL0=(A)=>{let{groups:f,path:w}=OF2(A),Q=VHA(w);return jF2(Q,f)},OF2=(A)=>{let f=[];return A=A.replace(/\{[^}]+\}/g,(w,Q)=>{let B=`@${Q}`;return f.push([B,w]),B}),{groups:f,path:A}},jF2=(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},Vp={},qL0=(A,f)=>{if(A==="*")return"*";let w=A.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);if(w){let Q=`${A}#${f}`;if(!Vp[Q])if(w[2])Vp[Q]=f&&f[0]!==":"&&f[0]!=="*"?[Q,w[1],new RegExp(`^${w[2]}(?=/${f})`)]:[A,w[1],new RegExp(`^${w[2]}$`)];else Vp[Q]=[A,w[1],!0];return Vp[Q]}return null},Mp=(A,f)=>{try{return f(A)}catch{return A.replace(/(?:%[0-9A-Fa-f]{2})+/g,(w)=>{try{return f(w)}catch{return w}})}},MHA=(A)=>Mp(A,decodeURI),iHA=(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 MHA($.includes("%25")?$.replace(/%25/g,"%2525"):$)}else if(B===63||B===35)break}return f.slice(w,Q)};var _L0=(A)=>{let f=iHA(A);return f.length>1&&f.at(-1)==="/"?f.slice(0,-1):f},RZ=(A,f,...w)=>{if(w.length)f=RZ(f,...w);return`${A?.[0]==="/"?"":"/"}${A}${f==="/"?"":`${A?.at(-1)==="/"?"":"/"}${f?.[0]==="/"?f.slice(1):f}`}`},ip=(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)},_HA=(A)=>{if(!/[%+]/.test(A))return A;if(A.indexOf("+")!==-1)A=A.replace(/\+/g," ");return A.indexOf("%")!==-1?Mp(A,OHA):A},VL0=(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 _HA(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)$=_HA($);if(x=c,$==="")continue;let u;if(I===-1)u="";else if(u=A.slice(I+1,c===-1?void 0:c),Q)u=_HA(u);if(w){if(!(B[$]&&Array.isArray(B[$])))B[$]=[];B[$].push(u)}else B[$]??=u}return f?B[f]:B},ML0=VL0,iL0=(A,f)=>{return VL0(A,f,!0)},OHA=decodeURIComponent;var OL0=(A)=>Mp(A,OHA),_p=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)?OL0(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)?OL0(Q):Q}return A}#B(A){return this.#f[1]?this.#f[1][A]:A}query(A){return ML0(this.url,A)}queries(A){return iL0(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 EL0(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[CL0](){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 jL0={Stringify:1,BeforeStream:2,Stream:3},gL0=(A,f)=>{let w=new String(A);return w.isEscaped=!0,w.callbacks=f,w};var jHA=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(($)=>jHA($,f,!1,Q,B))).then(()=>B[0]));if(w)return gL0(await c,x);else return c};var gF2="text/plain; charset=UTF-8",gHA=(A,f)=>{return{"Content-Type":A,...f}},lV=(A,f)=>new Response(A,f),PL0=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 _p(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||=lV(null,{headers:this.#I??=new Headers})}set res(A){if(this.#Q&&A){A=lV(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=lV(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 lV(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,gHA(gF2,w))};json=(A,f,w)=>{return this.#c(JSON.stringify(A),f,gHA("application/json",w))};html=(A,f,w)=>{let Q=(B)=>this.#c(B,f,gHA("text/html; charset=UTF-8",w));return typeof A==="object"?jHA(A,jL0.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??=()=>lV(),this.#u(this)}};var aw="ALL",RL0="all",nL0=["get","post","put","delete","options","patch"],Op="Can not add a route since the matcher is already built.",jp=class extends Error{};var PHA="__COMPOSED_HANDLER";var PF2=(A)=>{return A.text("404 Not Found",404)},mL0=(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)},lL0=class A{get;post;put;delete;options;patch;all;on;use;router;getPath;_basePath="/";#A="/";routes=[];constructor(f={}){[...nL0,RL0].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??iHA:_L0}#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=PF2;errorHandler=mL0;route(f,w){let Q=this.basePath(f);return w.routes.map((B)=>{let x;if(w.errorHandler===mL0)x=B.handler;else x=async(c,I)=>(await qHA([],w.errorHandler)(c,()=>B.handler(c,I))).res,x[PHA]=B.handler;Q.#x(B.method,B.path,x)}),this}basePath(f){let w=this.#f();return w._basePath=RZ(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 $=RZ(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,RZ(f,"*"),I),this}#x(f,w,Q){f=f.toUpperCase(),w=RZ(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 PL0(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 $=qHA(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${RZ("/",f)}`,w),Q,B)};fire=()=>{addEventListener("fetch",(f)=>{f.respondWith(this.#Q(f.request,f,void 0,f.request.method))})}};var TV=[];function gp(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[[],TV];let u=$.indexOf("",1);return[c[1][u],$]};return this.match=Q,Q(A,f)}var Pp="[^/]+",yV=".*",SV="(?:|/.*)",nZ=Symbol(),RF2=new Set(".\\+*[^]$()");function nF2(A,f){if(A.length===1)return f.length===1?A<f?-1:1:-1;if(f.length===1)return 1;if(A===yV||A===SV)return 1;else if(f===yV||f===SV)return-1;if(A===Pp)return 1;else if(f===Pp)return-1;return A.length===f.length?A<f?-1:1:f.length-A.length}var TL0=class A{#A;#f;#w=Object.create(null);insert(f,w,Q,B,x){if(f.length===0){if(this.#A!==void 0)throw nZ;if(x)return;this.#A=w;return}let[c,...I]=f,$=c==="*"?I.length===0?["","",yV]:["","",Pp]:c==="/*"?["","",SV]:c.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/),u;if($){let Y=$[1],F=$[2]||Pp;if(Y&&$[2]){if(F===".*")throw nZ;if(F=F.replace(/^\((?!\?:)(?=[^)]+\)$)/,"(?:"),/\((?!\?:)/.test(F))throw nZ}if(u=this.#w[F],!u){if(Object.keys(this.#w).some((K)=>K!==yV&&K!==SV))throw nZ;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!==yV&&Y!==SV))throw nZ;if(x)return;u=this.#w[c]=new A}u.insert(I,w,Q,B,x)}buildRegExpStr(){let w=Object.keys(this.#w).sort(nF2).map((Q)=>{let B=this.#w[Q];return(typeof B.#f==="number"?`(${Q})@${B.#f}`:RF2.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 yL0=class{#A={varIndex:0};#f=new TL0;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 mF2=[/^$/,[],Object.create(null)],SL0=Object.create(null);function pL0(A){return SL0[A]??=new RegExp(A==="*"?"":`^${A.replace(/\/\*$|([.\\+*[^\]$()])/g,(f,w)=>w?`\\${w}`:"(?:|/.*)")}$`)}function lF2(){SL0=Object.create(null)}function TF2(A){let f=new yL0,w=[];if(A.length===0)return mF2;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)]),TV];else Y++;let h;try{h=f.insert(Z,Y,K)}catch(G){throw G===nZ?new jp(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(pL0(w).test(f))return[...A[w]];return}var Rp=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(Op);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=pL0(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=ip(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=gp;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,lF2(),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 TF2(f)}};var yF2=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(),TV];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=gp};var RHA=class{name="SmartRouter";#A=[];#f=[];constructor(A){this.#A=A.routers}add(A,f,w){if(!this.#f)throw Error(Op);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 jp)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 pV=Object.create(null),SF2=(A)=>{for(let f in A)return!0;return!1},rL0=class A{#A;#f;#w;#x=0;#B=pV;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=LL0(w),c=[];for(let I=0,$=x.length;I<$;I++){let u=x[I],Y=x[I+1],F=qL0(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!==pV||x&&x!==pV)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=pV;let x=[this],c=VHA(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===pV?{}:{...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[i,j,P]=r;if(!F&&!(P instanceof RegExp))continue;let t=E.#f[i];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),SF2(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 nHA=class{name="TrieRouter";#A;constructor(){this.#A=new rL0}add(A,f,w){let Q=ip(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 mZ=class extends lL0{constructor(A={}){super(A);this.router=A.router??new RHA({routers:[new Rp,new nHA]})}};import{stat as aF2}from"fs/promises";import{join as sF2}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 mHA=(A,f=rF2)=>{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 pF2={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"},rF2=pF2;var dL0=(...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 oL0={br:".br",zstd:".zst",gzip:".gz"},dF2=Object.keys(oL0),oF2="index.html",aL0=(A)=>{let f=A.root??"./",w=A.path,Q=A.join??dL0;return async(B,x)=>{if(B.finalized)return x();let c;if(A.path)c=A.path;else try{if(c=MHA(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,oF2);let $=A.getContent,u=await $(I,B);if(u instanceof Response)return B.newResponse(u.body,u);if(u){let Y=A.mimes&&mHA(I,A.mimes)||mHA(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 dF2){if(!F.has(K))continue;let Z=await $(I+oL0[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 lHA=(A)=>{return async function(w,Q){return aL0({...A,getContent:async(c)=>{let I=Bun.file(c);return await I.exists()?I:null},join:sF2,isDir:async(c)=>{let I;try{I=(await aF2(c)).isDirectory()}catch{}return I}})(w,Q)}};var THA="x-hono-disable-ssg",y8w=(()=>{try{return new Response("SSG is disabled",{status:404,headers:{[THA]:"true"}})}catch{return null}})();var{write:zBw}=Bun;var AK2=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 sL0=(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 np=(A)=>("server"in A.env)?A.env.server:A.env;var fK2=sL0((A,f)=>{let w=np(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 wK2=["gzip","deflate"],QK2=/(?:^|,)\s*?no-transform\s*?(?:,|$)/i,tL0=(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||!BK2(Q.res)||!xK2(Q.res))return;let c=Q.req.header("Accept-Encoding"),I=A?.encoding??wK2.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)}},BK2=(A)=>{let f=A.headers.get("Content-Type");return f&&mJ.test(f)},xK2=(A)=>{let f=A.headers.get("Cache-Control");return!f||!QK2.test(f)};import{Readable as eL0}from"stream";import{createDeflate as cK2,createGzip as IK2}from"zlib";var $K2=["gzip","deflate"],uK2=/(?:^|,)\s*?no-transform\s*?(?:,|$)/i,Aq0=(A)=>{if(typeof CompressionStream<"u")return tL0(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||!DK2(Q.res)||!YK2(Q.res))return;let c=Q.req.header("Accept-Encoding"),I=A?.encoding??$K2.find(($)=>c?.includes($));if(!I||!Q.res.body)return;try{let $=I==="gzip"?IK2():cK2(),u=Q.res.body,F=eL0.fromWeb(u).pipe($),K=eL0.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:",$)}}},DK2=(A)=>{let f=A.headers.get("Content-Type");return f&&mJ.test(f)},YK2=(A)=>{let f=A.headers.get("Cache-Control");return!f||!uK2.test(f)};var HK2=(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},fq0=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(HK2(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"],wq0=(A)=>A.replace(/^W\//,"");function FK2(A,f){return f!=null&&f.split(/,\s*/).some((w)=>wq0(w)===wq0(A))}function KK2(A){if(!A){if(crypto&&crypto.subtle)A=(f)=>crypto.subtle.digest({name:"SHA-1"},f)}return A}var Qq0=(A)=>{let f=A?.retainedHeaders??UK2,w=A?.weak??!1,Q=KK2(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 fq0($.clone().body,Q);if(Y===null)return;u=w?`W/"${Y}"`:`"${Y}"`}if(FK2(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 yHA(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 mp{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 mZ;for(let w of this.routes){let Q=yHA(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 Bq0="public, max-age=31536000, immutable";class lp{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 mZ;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("/*",Aq0());return f.use("/*",Qq0()),f.use("/*",async(w,Q)=>{if(await Q(),A.immutableExtensions.test(w.req.path))w.header("Cache-Control",Bq0);else w.header("Cache-Control",A.defaultCache)}),f.use("/*",this.createCleanUrlMiddleware(A.distDir)),f.use("/*",lHA({root:A.distDir})),f.notFound(async(w)=>{let Q=Bun.file(XK2(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":Bq0}})}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 cq0}from"fs";import{join as Iq0}from"path";YA();var SHA=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 pHA=`<!DOCTYPE html>
|
|
1868
1868
|
<html lang="en">
|
|
@@ -1931,7 +1931,7 @@ ${A.entityContent}`,cq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt
|
|
|
1931
1931
|
<p>Once built, this page will be replaced with your actual website.</p>
|
|
1932
1932
|
</div>
|
|
1933
1933
|
</body>
|
|
1934
|
-
</html>`;var xq0={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.
|
|
1934
|
+
</html>`;var xq0={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.14",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",xq0,A,SHA)}async onRegister(A){this.siteUrl=A.siteUrl,this.previewUrl=A.previewUrl,this.serverManager=new lp({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 mp({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&&!cq0(this.config.previewDistDir))await A(this.config.previewDistDir,{recursive:!0}),await f(Iq0(this.config.previewDistDir,"index.html"),pHA),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!cq0(this.config.productionDistDir))await A(this.config.productionDistDir,{recursive:!0}),await f(Iq0(this.config.productionDistDir,"index.html"),pHA),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}B0();YA();var $q0=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 WK2(A,f){return`${A.name} is ${f.name}'s ${A.role}. Its purpose is: ${A.purpose}.`}function uq0(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:dP,description:"Anchor (operator) identity for this brain",params:Y}];return{name:f.name,description:WK2(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 rHA=new Set(["completed","failed","canceled","rejected"]);class dHA{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(rHA.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 Dq0=X.array(X.object({kind:X.string(),text:X.string().optional(),data:X.record(X.unknown()).optional()})),vK2=X.object({message:X.object({kind:X.literal("message").optional(),messageId:X.string().optional(),role:X.enum(["user","agent"]).optional(),parts:Dq0,contextId:X.string().optional(),taskId:X.string().optional()}),configuration:X.object({historyLength:X.number().optional()}).optional()}),Yq0=X.object({id:X.string(),historyLength:X.number().optional()});function oHA(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 Hq0=X.object({jsonrpc:X.string(),id:X.union([X.string(),X.number()]),method:X.string(),params:X.record(X.unknown()).optional()});async function Uq0(A,f){let{id:w,method:Q,params:B}=A;switch(Q){case"message/send":return kK2(w,B??{},f);case"tasks/get":return GK2(w,B??{},f);case"tasks/cancel":return JK2(w,B??{},f);default:return Ku(w,-32601,`Method not found: ${Q}`)}}async function kK2(A,f,w){let Q=vK2.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(`
|
|
1935
1935
|
`),c=Q.data.message.contextId,I=w.taskManager.createTask(x,c),$=I.task.id;w.taskManager.updateState($,"working"),hK2($,x,I.conversationId,w);let u=w.taskManager.getTask($);if(!u)return Ku(A,-32603,"Internal error: task disappeared");return oHA(A,u.task)}function hK2(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 Fq0=X.object({message:X.object({kind:X.string(),parts:Dq0,contextId:X.string().optional()})});function Kq0(A,f,w){let B=f.parts.filter((u)=>u.kind==="text"&&typeof u.text==="string").map((u)=>u.text).join(`
|
|
1936
1936
|
`)||"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)}
|
|
1937
1937
|
|
|
@@ -1939,7 +1939,7 @@ ${A.entityContent}`,cq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt
|
|
|
1939
1939
|
|
|
1940
1940
|
`);Q=x.pop()??"";for(let c of x){let I=c.split(`
|
|
1941
1941
|
`).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(`
|
|
1942
|
-
`)||"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 Wq0(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:Xq0,visibility:"anchor",handler:async(w)=>{let Q=X.object(Xq0).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 bK2(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 zK2(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 aHA={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.13",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 dHA;agentService;permissionContext;constructor(A={}){super("a2a",aHA,A,$q0)}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)=>lk.safeParse(I.metadata)).filter((I)=>I.success).map((I)=>I.data)}catch{}this.agentCard=uq0({character:f,profile:w,version:aHA.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[Wq0({outboundTokens:this.config.outboundTokens,entityService:this.getContext().entityService,sendMessage:(A,f)=>this.getContext().messaging.send(A,f)})]}createDaemon(){let A=new mZ;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=Hq0.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=Fq0.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}=Kq0(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 Uq0(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 sHA{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 nk2,isAbsolute as mk2}from"path";import{mkdir as lk2}from"fs/promises";var PV0=o0(MV0(),1);R7();import{join as Xu,dirname as zk2,extname as ur}from"path";import{mkdir as aUA,readFile as $r,writeFile as iV0,readdir as Nk2,stat as OV0,utimes as Ck2,access as Ek2}from"fs/promises";var cM=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function jV0(A){let f=ur(A).toLowerCase();return cM.includes(f)}function Lk2(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 gV0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}async function aJ(A){try{return await Ek2(A),!0}catch{return!1}}class sUA{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 $=ur(I).toLowerCase(),u=$===".md"||cM.includes($)?I.slice(0,-$.length):I;x[x.length-1]=u}c=x.join(":")}else{let I=x[0]??"",$=ur(I).toLowerCase();c=$===".md"||cM.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 OV0(f),{entityType:Q,id:B}=this.parseEntityFromPath(A),x=w.birthtime.getTime()>0?w.birthtime:w.mtime,c=w.mtime,I;if(jV0(A)){let u=(await $r(f)).toString("base64"),Y=ur(A);I=`data:${Lk2(Y)};base64,${u}`}else I=await $r(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 $r(f):await $r(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 aUA(zk2(f),{recursive:!0});if(w)await iV0(f,Q);else await iV0(f,Q,"utf-8");let B=new Date(A.updated);await Ck2(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=gV0(w);else{let Q=A.content.match(/^data:image\/([a-z+]+);base64,/i);if(Q?.[1])f=gV0(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 Nk2(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&&jV0(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 aUA(this.syncPath,{recursive:!0});for(let f of A)if(f!=="base")await aUA(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 OV0(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 qk2(A,f){if(!A.replace(f+"/","").startsWith("image/"))return!1;return cM.some((Q)=>A.toLowerCase().endsWith(Q))}function _k2(A,f){if(A.replace(f+"/","").split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return qk2(A,f)}class tUA{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=PV0.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(!_k2(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 eUA{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 AFA{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 Dr(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 RV0=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.string().url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class fFA{entityService;fetcher;logger;constructor(A,f,w=B5){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=RV0.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=RV0.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 Dr({id:`${w}-cover`,title:x,alt:B??x,sourceUrl:Q},this.entityService,this.fetcher,this.logger)}}YA();class IM{entityService;fetcher;logger;constructor(A,f,w=B5){this.entityService=A;this.fetcher=w;this.logger=f.child("MarkdownImageConverter")}detectInlineImages(A,f){let w=[],Q=ng(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``;return``}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++),$=``;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 Dr({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 Vk2,appendFile as Mk2,readFile as ik2,writeFile as Ok2,access as jk2}from"fs/promises";import{join as nV0}from"path";class wFA{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 Vk2(B,x),w.quarantined++,w.quarantinedFiles.push(A);let c=nV0(this.syncPath,".import-errors.log"),I=new Date().toISOString(),$=h0(f),u=`${I} - ${A}: ${$}
|
|
1942
|
+
`)||"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 Wq0(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:Xq0,visibility:"anchor",handler:async(w)=>{let Q=X.object(Xq0).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 bK2(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 zK2(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 aHA={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.14",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 dHA;agentService;permissionContext;constructor(A={}){super("a2a",aHA,A,$q0)}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)=>lk.safeParse(I.metadata)).filter((I)=>I.success).map((I)=>I.data)}catch{}this.agentCard=uq0({character:f,profile:w,version:aHA.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[Wq0({outboundTokens:this.config.outboundTokens,entityService:this.getContext().entityService,sendMessage:(A,f)=>this.getContext().messaging.send(A,f)})]}createDaemon(){let A=new mZ;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=Hq0.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=Fq0.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}=Kq0(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 Uq0(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 sHA{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 nk2,isAbsolute as mk2}from"path";import{mkdir as lk2}from"fs/promises";var PV0=o0(MV0(),1);R7();import{join as Xu,dirname as zk2,extname as ur}from"path";import{mkdir as aUA,readFile as $r,writeFile as iV0,readdir as Nk2,stat as OV0,utimes as Ck2,access as Ek2}from"fs/promises";var cM=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function jV0(A){let f=ur(A).toLowerCase();return cM.includes(f)}function Lk2(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 gV0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}async function aJ(A){try{return await Ek2(A),!0}catch{return!1}}class sUA{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 $=ur(I).toLowerCase(),u=$===".md"||cM.includes($)?I.slice(0,-$.length):I;x[x.length-1]=u}c=x.join(":")}else{let I=x[0]??"",$=ur(I).toLowerCase();c=$===".md"||cM.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 OV0(f),{entityType:Q,id:B}=this.parseEntityFromPath(A),x=w.birthtime.getTime()>0?w.birthtime:w.mtime,c=w.mtime,I;if(jV0(A)){let u=(await $r(f)).toString("base64"),Y=ur(A);I=`data:${Lk2(Y)};base64,${u}`}else I=await $r(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 $r(f):await $r(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 aUA(zk2(f),{recursive:!0});if(w)await iV0(f,Q);else await iV0(f,Q,"utf-8");let B=new Date(A.updated);await Ck2(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=gV0(w);else{let Q=A.content.match(/^data:image\/([a-z+]+);base64,/i);if(Q?.[1])f=gV0(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 Nk2(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&&jV0(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 aUA(this.syncPath,{recursive:!0});for(let f of A)if(f!=="base")await aUA(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 OV0(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 qk2(A,f){if(!A.replace(f+"/","").startsWith("image/"))return!1;return cM.some((Q)=>A.toLowerCase().endsWith(Q))}function _k2(A,f){if(A.replace(f+"/","").split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return qk2(A,f)}class tUA{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=PV0.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(!_k2(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 eUA{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 AFA{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 Dr(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 RV0=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.string().url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class fFA{entityService;fetcher;logger;constructor(A,f,w=B5){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=RV0.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=RV0.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 Dr({id:`${w}-cover`,title:x,alt:B??x,sourceUrl:Q},this.entityService,this.fetcher,this.logger)}}YA();class IM{entityService;fetcher;logger;constructor(A,f,w=B5){this.entityService=A;this.fetcher=w;this.logger=f.child("MarkdownImageConverter")}detectInlineImages(A,f){let w=[],Q=ng(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``;return``}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++),$=``;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 Dr({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 Vk2,appendFile as Mk2,readFile as ik2,writeFile as Ok2,access as jk2}from"fs/promises";import{join as nV0}from"path";class wFA{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 Vk2(B,x),w.quarantined++,w.quarantinedFiles.push(A);let c=nV0(this.syncPath,".import-errors.log"),I=new Date().toISOString(),$=h0(f),u=`${I} - ${A}: ${$}
|
|
1943
1943
|
\u2192 ${A}.invalid
|
|
1944
1944
|
|
|
1945
1945
|
`;await Mk2(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=nV0(this.syncPath,".import-errors.log");try{await jk2(f)}catch{return}try{let w=await ik2(f,"utf-8");if(w.includes(A)){let B=`${new Date().toISOString()} - [RECOVERED] ${A}
|
|
@@ -1965,7 +1965,7 @@ ${A.entityContent}`,cq1);$=Q+E.imagePrompt}catch(E){this.logger.warn("AI prompt
|
|
|
1965
1965
|
*...and ${A.files.length-10} more files*`)}if(A.exists&&A.stats.totalFiles===0)f.push(`
|
|
1966
1966
|
## Getting Started
|
|
1967
1967
|
`),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(`
|
|
1968
|
-
`)}}B0();class ir extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:VO0,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 Or extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:_O0,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 jr extends Vw{directorySync;context;constructor(A,f,w){super(A,{schema:qO0,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 gr extends Vw{context;constructor(A,f,w){super(A,{schema:sFA,jobTypeName:"directory-delete"});this.context=f}async process(A,f,w){let Q=sFA.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 Wb2=X.object({});class Pr extends Vw{directorySync;constructor(A,f){super(A,{schema:Wb2,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 vb2,writeFile as kb2}from"fs/promises";var hb2=X.object({filePath:X.string(),sourceUrl:X.string().url(),postTitle:X.string(),postSlug:X.string(),customAlt:X.string().optional()});class Rr extends Vw{context;fetcher;constructor(A,f,w=B5){super(f,{schema:hb2,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 vb2(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 kb2(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 Gb2,writeFile as Jb2}from"fs/promises";class nr extends Vw{converter;constructor(A,f,w=B5){super(f,{schema:MO0,jobTypeName:"inline-image-convert"});this.converter=new IM(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 Gb2(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 Jb2(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 jO0(A,f,w){let Q=(B)=>w.child(B);A.jobs.registerHandler("directory-sync",new jr(Q("DirectorySyncJobHandler"),A,f)),A.jobs.registerHandler("directory-export",new ir(Q("DirectoryExportJobHandler"),A,f)),A.jobs.registerHandler("directory-import",new Or(Q("DirectoryImportJobHandler"),A,f)),A.jobs.registerHandler("directory-delete",new gr(Q("DirectoryDeleteJobHandler"),A,f)),A.jobs.registerHandler("directory-cleanup",new Pr(Q("DirectoryCleanupJobHandler"),f)),A.jobs.registerHandler("cover-image-convert",new Rr(A,Q("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new nr(A,Q("InlineImageConversionJobHandler"))),w.debug("Registered async job handlers")}B0();import{unlink as bb2,access as zb2}from"fs/promises";function gO0(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 zb2(u).then(()=>!0,()=>!1))await bb2(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 PO0(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 Nb2,readdir as RO0,mkdir as Cb2,copyFile as Eb2}from"fs/promises";import{exec as Lb2}from"child_process";import{promisify as qb2}from"util";import{join as eFA,resolve as tFA}from"path";var _b2=qb2(Lb2);async function mr(A){try{return await Nb2(A),!0}catch{return!1}}async function Vb2(A,f){if(!await mr(A))return!0;if((await RO0(A)).filter((B)=>!B.startsWith(".")&&!B.startsWith("_")).length>0)return!1;if(await Mb2(A))return f.debug("Git repository with remote detected - skipping seed content",{path:A}),!1;return!0}async function Mb2(A){let f=eFA(A,".git");if(!await mr(f))return!1;try{let{stdout:w}=await _b2("git remote",{cwd:A});return w.trim().length>0}catch{return!1}}async function nO0(A,f){let w=await RO0(A,{withFileTypes:!0});for(let Q of w){let B=eFA(A,Q.name),x=eFA(f,Q.name);if(Q.isDirectory()){if(!await mr(x))await Cb2(x,{recursive:!0});await nO0(B,x)}else await Eb2(B,x)}}async function mO0(A,f,w){let Q=tFA(process.cwd(),A);w=w?tFA(w):tFA(process.cwd(),"seed-content");let B=await Vb2(Q,f);if(B&&await mr(w))f.debug("Copying seed content to brain-data directory"),await nO0(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 ib2(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 lO0(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 mO0(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}),ib2(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 TO0(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 yO0(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 SO0(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 pO0(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 rO0(A,f,w,Q){let B=[Tf(w,"sync","Sync brain entities with the filesystem. Use this for refresh, pull, sync, or backup-to-git requests. 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. Use this for status questions, not for actually syncing or backing up.",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(pO0(w,Q));return B}var dO0={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.13",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 AKA extends yQ{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",dO0,A,LO0)}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:WM,basePrompt:"",formatter:new Mr,requiredPermission:"anchor"}});let Q=this.config.syncPath??A.dataDir;this.directorySync=new $M({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(gO0(A,B,this.logger,this.config.entityTypes),this.config.autoSync)PO0(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 aFA({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(TO0(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push(yO0(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)lO0(A,()=>this.requireDirectorySync(),this.config,this.id,this.logger,this.gitSync);SO0(A,()=>this.requireDirectorySync(),(c)=>this.configure(c),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return rO0(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 $M({...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){jO0(A,this.requireDirectorySync(),this.logger)}}function dZ(A={}){return new AKA(A)}B0();B0();YA();YA();var oO0=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()}),w4w=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 GS0}from"preact-render-to-string";import{h as kW}from"preact";class fKA{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(`
|
|
1968
|
+
`)}}B0();class ir extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:VO0,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 Or extends Vw{context;directorySync;constructor(A,f,w){super(A,{schema:_O0,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 jr extends Vw{directorySync;context;constructor(A,f,w){super(A,{schema:qO0,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 gr extends Vw{context;constructor(A,f,w){super(A,{schema:sFA,jobTypeName:"directory-delete"});this.context=f}async process(A,f,w){let Q=sFA.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 Wb2=X.object({});class Pr extends Vw{directorySync;constructor(A,f){super(A,{schema:Wb2,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 vb2,writeFile as kb2}from"fs/promises";var hb2=X.object({filePath:X.string(),sourceUrl:X.string().url(),postTitle:X.string(),postSlug:X.string(),customAlt:X.string().optional()});class Rr extends Vw{context;fetcher;constructor(A,f,w=B5){super(f,{schema:hb2,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 vb2(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 kb2(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 Gb2,writeFile as Jb2}from"fs/promises";class nr extends Vw{converter;constructor(A,f,w=B5){super(f,{schema:MO0,jobTypeName:"inline-image-convert"});this.converter=new IM(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 Gb2(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 Jb2(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 jO0(A,f,w){let Q=(B)=>w.child(B);A.jobs.registerHandler("directory-sync",new jr(Q("DirectorySyncJobHandler"),A,f)),A.jobs.registerHandler("directory-export",new ir(Q("DirectoryExportJobHandler"),A,f)),A.jobs.registerHandler("directory-import",new Or(Q("DirectoryImportJobHandler"),A,f)),A.jobs.registerHandler("directory-delete",new gr(Q("DirectoryDeleteJobHandler"),A,f)),A.jobs.registerHandler("directory-cleanup",new Pr(Q("DirectoryCleanupJobHandler"),f)),A.jobs.registerHandler("cover-image-convert",new Rr(A,Q("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new nr(A,Q("InlineImageConversionJobHandler"))),w.debug("Registered async job handlers")}B0();import{unlink as bb2,access as zb2}from"fs/promises";function gO0(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 zb2(u).then(()=>!0,()=>!1))await bb2(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 PO0(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 Nb2,readdir as RO0,mkdir as Cb2,copyFile as Eb2}from"fs/promises";import{exec as Lb2}from"child_process";import{promisify as qb2}from"util";import{join as eFA,resolve as tFA}from"path";var _b2=qb2(Lb2);async function mr(A){try{return await Nb2(A),!0}catch{return!1}}async function Vb2(A,f){if(!await mr(A))return!0;if((await RO0(A)).filter((B)=>!B.startsWith(".")&&!B.startsWith("_")).length>0)return!1;if(await Mb2(A))return f.debug("Git repository with remote detected - skipping seed content",{path:A}),!1;return!0}async function Mb2(A){let f=eFA(A,".git");if(!await mr(f))return!1;try{let{stdout:w}=await _b2("git remote",{cwd:A});return w.trim().length>0}catch{return!1}}async function nO0(A,f){let w=await RO0(A,{withFileTypes:!0});for(let Q of w){let B=eFA(A,Q.name),x=eFA(f,Q.name);if(Q.isDirectory()){if(!await mr(x))await Cb2(x,{recursive:!0});await nO0(B,x)}else await Eb2(B,x)}}async function mO0(A,f,w){let Q=tFA(process.cwd(),A);w=w?tFA(w):tFA(process.cwd(),"seed-content");let B=await Vb2(Q,f);if(B&&await mr(w))f.debug("Copying seed content to brain-data directory"),await nO0(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 ib2(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 lO0(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 mO0(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}),ib2(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 TO0(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 yO0(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 SO0(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 pO0(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 rO0(A,f,w,Q){let B=[Tf(w,"sync","Sync brain entities with the filesystem. Use this for refresh, pull, sync, or backup-to-git requests. 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. Use this for status questions, not for actually syncing or backing up.",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(pO0(w,Q));return B}var dO0={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.14",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 AKA extends yQ{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",dO0,A,LO0)}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:WM,basePrompt:"",formatter:new Mr,requiredPermission:"anchor"}});let Q=this.config.syncPath??A.dataDir;this.directorySync=new $M({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(gO0(A,B,this.logger,this.config.entityTypes),this.config.autoSync)PO0(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 aFA({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(TO0(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push(yO0(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)lO0(A,()=>this.requireDirectorySync(),this.config,this.id,this.logger,this.gitSync);SO0(A,()=>this.requireDirectorySync(),(c)=>this.configure(c),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return rO0(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 $M({...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){jO0(A,this.requireDirectorySync(),this.logger)}}function dZ(A={}){return new AKA(A)}B0();B0();YA();YA();var oO0=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()}),w4w=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 GS0}from"preact-render-to-string";import{h as kW}from"preact";class fKA{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(`
|
|
1969
1969
|
`);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(`
|
|
1970
1970
|
`)}escapeHtml(A){let f={"&":"&","<":"<",">":">",'"':""","'":"'"};return A.replace(/[&<>"']/g,(w)=>f[w]??w)}}function aO0(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=aO0(A[f]))&&(Q&&(Q+=" "),Q+=w)}else for(w in A)A[w]&&(Q&&(Q+=" "),Q+=w);return Q}function lr(){for(var A,f,w=0,Q="",B=arguments.length;w<B;w++)(A=arguments[w])&&(f=aO0(A))&&(Q&&(Q+=" "),Q+=f);return Q}var jb2=(A)=>{let f=Pb2(A),{conflictingClassGroups:w,conflictingClassGroupModifiers:Q}=A;return{getClassGroupId:(c)=>{let I=c.split("-");if(I[0]===""&&I.length!==1)I.shift();return fj0(I,f)||gb2(c)},getConflictingClassGroupIds:(c,I)=>{let $=w[c]||[];if(I&&Q[c])return[...$,...Q[c]];return $}}},fj0=(A,f)=>{if(A.length===0)return f.classGroupId;let w=A[0],Q=f.nextPart.get(w),B=Q?fj0(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},sO0=/^\[(.+)\]$/,gb2=(A)=>{if(sO0.test(A)){let f=sO0.exec(A)[1],w=f?.substring(0,f.indexOf(":"));if(w)return"arbitrary.."+w}},Pb2=(A)=>{let{theme:f,prefix:w}=A,Q={nextPart:new Map,validators:[]};return nb2(Object.entries(A.classGroups),w).forEach(([x,c])=>{QKA(c,Q,x,f)}),Q},QKA=(A,f,w,Q)=>{A.forEach((B)=>{if(typeof B==="string"){let x=B===""?f:tO0(f,B);x.classGroupId=w;return}if(typeof B==="function"){if(Rb2(B)){QKA(B(Q),f,w,Q);return}f.validators.push({validator:B,classGroupId:w});return}Object.entries(B).forEach(([x,c])=>{QKA(c,tO0(f,x),w,Q)})})},tO0=(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},Rb2=(A)=>A.isThemeGetter,nb2=(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]})},mb2=(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 lb2=(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},Tb2=(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},yb2=(A)=>({cache:mb2(A.cacheSize),parseClassName:lb2(A),...jb2(A)}),Sb2=/\s+/,pb2=(A,f)=>{let{parseClassName:w,getClassGroupId:Q,getConflictingClassGroupIds:B}=f,x=[],c=A.trim().split(Sb2),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=Tb2(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 rb2(){let A=0,f,w,Q="";while(A<arguments.length)if(f=arguments[A++]){if(w=wj0(f))Q&&(Q+=" "),Q+=w}return Q}var wj0=(A)=>{if(typeof A==="string")return A;let f,w="";for(let Q=0;Q<A.length;Q++)if(A[Q]){if(f=wj0(A[Q]))w&&(w+=" "),w+=f}return w};function eO0(A,...f){let w,Q,B,x=c;function c($){let u=f.reduce((Y,F)=>F(Y),A());return w=yb2(u),Q=w.cache.get,B=w.cache.set,x=I,I($)}function I($){let u=Q($);if(u)return u;let Y=pb2($,w);return B($,Y),Y}return function(){return x(rb2.apply(null,arguments))}}var VQ=(A)=>{let f=(w)=>w[A]||[];return f.isThemeGetter=!0,f},Qj0=/^\[(?:([a-z-]+):)?(.+)\]$/i,db2=/^\d+\/\d+$/,ob2=new Set(["px","full","screen"]),ab2=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,sb2=/\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$/,tb2=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,eb2=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,Az2=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,_3=(A)=>wb(A)||ob2.has(A)||db2.test(A),lU=(A)=>Qb(A,"length",$z2),wb=(A)=>Boolean(A)&&!Number.isNaN(Number(A)),wKA=(A)=>Qb(A,"number",wb),vM=(A)=>Boolean(A)&&Number.isInteger(Number(A)),fz2=(A)=>A.endsWith("%")&&wb(A.slice(0,-1)),If=(A)=>Qj0.test(A),TU=(A)=>ab2.test(A),wz2=new Set(["length","size","percentage"]),Qz2=(A)=>Qb(A,wz2,Bj0),Bz2=(A)=>Qb(A,"position",Bj0),xz2=new Set(["image","url"]),cz2=(A)=>Qb(A,xz2,Dz2),Iz2=(A)=>Qb(A,"",uz2),kM=()=>!0,Qb=(A,f,w)=>{let Q=Qj0.exec(A);if(Q){if(Q[1])return typeof f==="string"?Q[1]===f:f.has(Q[1]);return w(Q[2])}return!1},$z2=(A)=>sb2.test(A)&&!tb2.test(A),Bj0=()=>!1,uz2=(A)=>eb2.test(A),Dz2=(A)=>Az2.test(A);var Aj0=()=>{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"),i=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"],M=()=>["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:[kM],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:[fz2,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",vM,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",vM,If]}],"grid-cols":[{"grid-cols":[kM]}],"col-start-end":[{col:["auto",{span:["full",vM,If]},If]}],"col-start":[{"col-start":_()}],"col-end":[{"col-end":_()}],"grid-rows":[{"grid-rows":[kM]}],"row-start-end":[{row:["auto",{span:[vM,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":[i]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[i]}],"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",wKA]}],"font-family":[{font:[kM]}],"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,wKA]}],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:[...M(),"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(),Bz2]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",Qz2]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},cz2]}],"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:[...M(),"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:M()}],"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:["",...M()]}],"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,Iz2]}],"shadow-color":[{shadow:[kM]}],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:[vM,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,wKA]}],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"]}}},Yz2=(A,{cacheSize:f,prefix:w,separator:Q,experimentalParseClassName:B,extend:x={},override:c={}})=>{hM(A,"cacheSize",f),hM(A,"prefix",w),hM(A,"separator",Q),hM(A,"experimentalParseClassName",B);for(let I in c)Hz2(A[I],c[I]);for(let I in x)Uz2(A[I],x[I]);return A},hM=(A,f,w)=>{if(w!==void 0)A[f]=w},Hz2=(A,f)=>{if(f)for(let w in f)hM(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)}},xj0=(A,...f)=>typeof A==="function"?eO0(Aj0,A,...f):eO0(()=>Yz2(Aj0(),A),...f);var Fz2=xj0({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 Fz2(lr(A))}var cj0=(A)=>typeof A==="boolean"?`${A}`:A===0?"0":A,Ij0=lr,sw=(A,f)=>(w)=>{var Q;if((f===null||f===void 0?void 0:f.variants)==null)return Ij0(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=cj0(Y)||cj0(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 Ij0(A,c,$,w===null||w===void 0?void 0:w.class,w===null||w===void 0?void 0:w.className)};import{jsxDEV as BKA}from"preact/jsx-dev-runtime";var $j0=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 xKA({variant:A,title:f,children:w,className:Q}){return BKA("div",{className:C1($j0({variant:A}),Q),role:"alert",children:[f&&BKA("p",{className:"font-medium text-current opacity-90",children:f},void 0,!1,void 0,this),BKA("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 Kz2}from"preact/jsx-dev-runtime";var uj0=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 oZ({variant:A,size:f,className:w,children:Q,ssrOnClick:B,type:x="button",...c}){return Kz2("button",{type:x,className:C1(uj0({variant:A,size:f}),w),...c,...B&&{onclick:B},children:Q},void 0,!1,void 0,this)}import{jsxDEV as Xz2}from"preact/jsx-dev-runtime";var Dj0=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 Xz2("a",{href:A,className:C1(Dj0({variant:w,size:Q}),x),"aria-label":c,...I,children:f},void 0,!1,void 0,this)}import{jsxDEV as Tr}from"preact/jsx-dev-runtime";var Yj0=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"}}),Zz2={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=Zz2[f??"md"];return Tr("button",{onclick:"toggleTheme()",type:"button",className:C1(Yj0({variant:A,size:f}),w),"aria-label":"Toggle dark mode",children:Tr("svg",{className:C1(Q,"transition-colors"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:[Tr("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),Tr("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 cKA}from"preact/jsx-dev-runtime";var Hj0=sw("flex flex-wrap",{variants:{orientation:{horizontal:"justify-center gap-6 items-center",vertical:"flex-col gap-2.5"}},defaultVariants:{orientation:"horizontal"}});function yr({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 cKA("ul",{className:C1(Hj0({orientation:Q}),f),children:[x.map((c)=>cKA("li",{children:cKA("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 M4w}from"preact/jsx-dev-runtime";import{jsxDEV as j4w}from"preact/jsx-dev-runtime";YA();YA();import{createContext as Wz2,h as vz2}from"preact";import{useContext as kz2}from"preact/hooks";var Uj0=Wz2(null);function Sr({imageRenderer:A,children:f}){return vz2(Uj0.Provider,{value:A??null},f)}function Fj0(){return kz2(Uj0)}function aZ(){let A=Fj0();return(f)=>Pg(f,A?{imageRenderer:A}:void 0)}import{jsxDEV as V3}from"preact/jsx-dev-runtime";var IKA=({markdown:A})=>{let f=aZ(),Q=A.split(/^---$/gm).map((c)=>c.trim()).map((c)=>{let{attributes:I,markdown:$}=BP(c),u=xP($),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:`
|
|
1971
1971
|
window.addEventListener('DOMContentLoaded', () => {
|
|
@@ -2712,7 +2712,7 @@ ${f.join(`
|
|
|
2712
2712
|
`+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(`
|
|
2713
2713
|
`)+`
|
|
2714
2714
|
|
|
2715
|
-
`+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(oP2(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 yZA(A){return new JS0(A)}function aP2(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 JT2}from"path";YA();class SZA{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 bS0=X.object({}),Ni=W2.extend({id:X.literal("site-info"),entityType:X.literal("site-info"),metadata:bS0}),Ci=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:Ci.optional().describe("Call-to-action configuration")});B0();class iI extends _2{constructor(){super({entityType:"site-info",schema:Ni,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 iI;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 sP2=new iI;class no{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?sP2.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 zS0={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.13",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 eP2=new iI;class pZA extends Nf{entityType="site-info";schema=Ni;adapter=eP2;defaultSiteInfo;constructor(A){super("site-info",zS0);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new no(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 hW(A){return new pZA(A)}var AR2=new iI;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 AR2.parseSiteInfoBody(w.content)}YA();var fR2=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 NS0(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 ar0}from"fs";import{join as GT2}from"path";import{createHash as ZT2}from"crypto";import{promises as vWA}from"fs";import{join as pr0}from"path";var rr0=null;async function WT2(){return rr0??=Promise.resolve().then(() => o0(Sr0(),1)).then((A)=>A.default),rr0}var vT2=[480,960,1920],kT2=80,hT2="(max-width: 640px) 480px, (max-width: 1280px) 960px, 1920px";class kWA{imagesDir;logger;constructor(A,f){this.imagesDir=A;this.logger=f.child("ImageOptimizer")}async optimize(A,f){try{let w=await WT2(),Q=ZT2("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 vT2){if(F>x)continue;let K=`${Q}-${F}w.webp`,Z=pr0(this.imagesDir,K),k=`/images/${K}`;if(await vWA.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:kT2}).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:hT2,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 vWA.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=pr0(this.imagesDir,Q.name),x=`/images/${Q.name}`;try{let c=await vWA.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 dr0(A,f){if(A.format)return A.format;return f.match(/^data:image\/([^;]+);/)?.[1]??"png"}function or0(A){return A.match(/^data:image\/[^;]+;base64,(.+)$/)?.[1]??null}function gb(A){return A.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}class hWA{entityService;logger;imageMap={};imagesDir;optimizer;constructor(A,f,w){this.entityService=A;this.logger=f.child("ImageBuildService"),this.imagesDir=w,this.optimizer=new kWA(this.imagesDir,this.logger)}async resolveAll(A){let f=[...new Set(A)];if(f.length===0)return;await ar0.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=or0(f.content);if(!w){this.logger.warn("Could not extract base64 from image",{imageId:A});return}let Q=Buffer.from(w,"base64"),B=dr0(f.metadata,f.content),x=`${A}.${B}`,c=GT2(this.imagesDir,x);await ar0.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 bT2=W2.extend({metadata:X.object({slug:X.string()}).passthrough()});class Oc{static instance=null;static defaultStaticSiteBuilderFactory=yZA;logger;context;staticSiteBuilderFactory;routeRegistry;profileService;entityDisplay;imageBuildService=null;static setDefaultStaticSiteBuilderFactory(A){Oc.defaultStaticSiteBuilderFactory=A}static getInstance(A,f,w,Q,B){return Oc.instance??=new Oc(A,Oc.defaultStaticSiteBuilderFactory,f,w,Q,B),Oc.instance}static resetInstance(){Oc.instance=null}static createFresh(A,f,w,Q,B,x){return new Oc(A,B??Oc.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,Q5.getInstance().configure(x)}async getSiteInfo(){return NS0(this.context.entityService,this.profileService,this.routeRegistry)}async build(A,f){let w=oO0.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 SZA(this.context,this.routeRegistry,this.entityDisplay).generateEntityRoutes();let I=w.workingDir??JT2(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 hWA(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=Q5.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=bT2.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=Aq(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 fq(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=Aq(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 GWA{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=Pk.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 xa{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 JWA{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 zT2(A,f){return A.map((w)=>({...w,template:w.template.includes(":")?w.template:`${f}:${w.template}`}))}function ca(A,f,w){for(let Q of A)w.register({...Q,pluginId:f,sections:Q.sections?zT2(Q.sections,f):[]})}function sr0(A,f,w){A.messaging.subscribe("plugin:site-builder:route:register",async(Q)=>{try{let B=y2A.parse(Q.payload),{routes:x,pluginId:c}=B;return ca(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=S2A.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=p2A.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=r2A.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 ii}from"fs";import{join as Oi}from"path";function tr0(A,f){if(f==="preview")return`User-agent: *
|
|
2715
|
+
`+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(oP2(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 yZA(A){return new JS0(A)}function aP2(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 JT2}from"path";YA();class SZA{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 bS0=X.object({}),Ni=W2.extend({id:X.literal("site-info"),entityType:X.literal("site-info"),metadata:bS0}),Ci=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:Ci.optional().describe("Call-to-action configuration")});B0();class iI extends _2{constructor(){super({entityType:"site-info",schema:Ni,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 iI;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 sP2=new iI;class no{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?sP2.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 zS0={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.14",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 eP2=new iI;class pZA extends Nf{entityType="site-info";schema=Ni;adapter=eP2;defaultSiteInfo;constructor(A){super("site-info",zS0);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new no(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 hW(A){return new pZA(A)}var AR2=new iI;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 AR2.parseSiteInfoBody(w.content)}YA();var fR2=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 NS0(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 ar0}from"fs";import{join as GT2}from"path";import{createHash as ZT2}from"crypto";import{promises as vWA}from"fs";import{join as pr0}from"path";var rr0=null;async function WT2(){return rr0??=Promise.resolve().then(() => o0(Sr0(),1)).then((A)=>A.default),rr0}var vT2=[480,960,1920],kT2=80,hT2="(max-width: 640px) 480px, (max-width: 1280px) 960px, 1920px";class kWA{imagesDir;logger;constructor(A,f){this.imagesDir=A;this.logger=f.child("ImageOptimizer")}async optimize(A,f){try{let w=await WT2(),Q=ZT2("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 vT2){if(F>x)continue;let K=`${Q}-${F}w.webp`,Z=pr0(this.imagesDir,K),k=`/images/${K}`;if(await vWA.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:kT2}).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:hT2,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 vWA.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=pr0(this.imagesDir,Q.name),x=`/images/${Q.name}`;try{let c=await vWA.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 dr0(A,f){if(A.format)return A.format;return f.match(/^data:image\/([^;]+);/)?.[1]??"png"}function or0(A){return A.match(/^data:image\/[^;]+;base64,(.+)$/)?.[1]??null}function gb(A){return A.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}class hWA{entityService;logger;imageMap={};imagesDir;optimizer;constructor(A,f,w){this.entityService=A;this.logger=f.child("ImageBuildService"),this.imagesDir=w,this.optimizer=new kWA(this.imagesDir,this.logger)}async resolveAll(A){let f=[...new Set(A)];if(f.length===0)return;await ar0.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=or0(f.content);if(!w){this.logger.warn("Could not extract base64 from image",{imageId:A});return}let Q=Buffer.from(w,"base64"),B=dr0(f.metadata,f.content),x=`${A}.${B}`,c=GT2(this.imagesDir,x);await ar0.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 bT2=W2.extend({metadata:X.object({slug:X.string()}).passthrough()});class Oc{static instance=null;static defaultStaticSiteBuilderFactory=yZA;logger;context;staticSiteBuilderFactory;routeRegistry;profileService;entityDisplay;imageBuildService=null;static setDefaultStaticSiteBuilderFactory(A){Oc.defaultStaticSiteBuilderFactory=A}static getInstance(A,f,w,Q,B){return Oc.instance??=new Oc(A,Oc.defaultStaticSiteBuilderFactory,f,w,Q,B),Oc.instance}static resetInstance(){Oc.instance=null}static createFresh(A,f,w,Q,B,x){return new Oc(A,B??Oc.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,Q5.getInstance().configure(x)}async getSiteInfo(){return NS0(this.context.entityService,this.profileService,this.routeRegistry)}async build(A,f){let w=oO0.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 SZA(this.context,this.routeRegistry,this.entityDisplay).generateEntityRoutes();let I=w.workingDir??JT2(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 hWA(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=Q5.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=bT2.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=Aq(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 fq(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=Aq(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 GWA{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=Pk.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 xa{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 JWA{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 zT2(A,f){return A.map((w)=>({...w,template:w.template.includes(":")?w.template:`${f}:${w.template}`}))}function ca(A,f,w){for(let Q of A)w.register({...Q,pluginId:f,sections:Q.sections?zT2(Q.sections,f):[]})}function sr0(A,f,w){A.messaging.subscribe("plugin:site-builder:route:register",async(Q)=>{try{let B=y2A.parse(Q.payload),{routes:x,pluginId:c}=B;return ca(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=S2A.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=p2A.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=r2A.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 ii}from"fs";import{join as Oi}from"path";function tr0(A,f){if(f==="preview")return`User-agent: *
|
|
2716
2716
|
Disallow: /
|
|
2717
2717
|
|
|
2718
2718
|
Sitemap: ${A}/sitemap.xml
|
|
@@ -2741,7 +2741,7 @@ ${A.map((x)=>({url:`${f}${x.path}`,lastmod:w,changefreq:x.path==="/"?"daily":"we
|
|
|
2741
2741
|
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
|
|
2742
2742
|
</body>
|
|
2743
2743
|
</html>
|
|
2744
|
-
`;async function LT2(A,f,w){let Q=A.siteConfig.url??"https://example.com",B=f.list(),x=tr0(Q,A.environment);await ii.writeFile(Oi(A.outputDir,"robots.txt"),x,"utf-8"),w.info(`Generated robots.txt for ${A.environment} environment`);let c=er0(B,Q);await ii.writeFile(Oi(A.outputDir,"sitemap.xml"),c,"utf-8"),w.info(`Generated sitemap.xml with ${B.length} URLs`)}async function qT2(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=fd0({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=Oi(A.outputDir,"admin");await ii.mkdir(I,{recursive:!0}),await ii.writeFile(Oi(I,"config.yml"),k$(c),"utf-8"),await ii.writeFile(Oi(I,"index.html"),wd0,"utf-8"),Q.info("Generated CMS admin page and config.yml")}function Qd0(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 LT2(c,w,B),await qT2(c,f,Q,B),{success:!0}}catch(c){return B.error("Failed to generate SEO files",c),{success:!1}}})}B0();YA();var Bd0=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 CWA extends Vw{sendMessage;cfg;constructor(A,f,w){super(A,{schema:Bd0,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)=>Q5.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 _T2=X.object({slot:X.enum(gk).optional().default("primary"),limit:X.number().optional()});class EWA{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=_T2.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 VT2=X.object({environment:X.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function xd0(A,f){return[Tf(A,"build-site","Build a static site from registered routes",VT2,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 cd0=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(Pk).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(gk).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 Id0={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.13",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 LWA 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",Id0,{...A,layouts:f},cd0);this.layouts=f}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new GWA(A.logger),this._slotRegistry=new xa,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 EWA(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=u5.getInstance(A.entityService,A.logger),A.messaging.subscribe("sync:initial:completed",async()=>{return await this.profileService?.initialize(),this.logger.info("AnchorProfileService initialized"),{success:!0}}),sr0(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)ca(this.config.routes,this.id,this.routeRegistry);if(this.siteBuilder=Oc.getInstance(A.logger.child("SiteBuilder"),A,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new CWA(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 JWA(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}}),Qd0({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 xd0(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
|
|
2744
|
+
`;async function LT2(A,f,w){let Q=A.siteConfig.url??"https://example.com",B=f.list(),x=tr0(Q,A.environment);await ii.writeFile(Oi(A.outputDir,"robots.txt"),x,"utf-8"),w.info(`Generated robots.txt for ${A.environment} environment`);let c=er0(B,Q);await ii.writeFile(Oi(A.outputDir,"sitemap.xml"),c,"utf-8"),w.info(`Generated sitemap.xml with ${B.length} URLs`)}async function qT2(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=fd0({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=Oi(A.outputDir,"admin");await ii.mkdir(I,{recursive:!0}),await ii.writeFile(Oi(I,"config.yml"),k$(c),"utf-8"),await ii.writeFile(Oi(I,"index.html"),wd0,"utf-8"),Q.info("Generated CMS admin page and config.yml")}function Qd0(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 LT2(c,w,B),await qT2(c,f,Q,B),{success:!0}}catch(c){return B.error("Failed to generate SEO files",c),{success:!1}}})}B0();YA();var Bd0=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 CWA extends Vw{sendMessage;cfg;constructor(A,f,w){super(A,{schema:Bd0,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)=>Q5.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 _T2=X.object({slot:X.enum(gk).optional().default("primary"),limit:X.number().optional()});class EWA{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=_T2.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 VT2=X.object({environment:X.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function xd0(A,f){return[Tf(A,"build-site","Build a static site from registered routes",VT2,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 cd0=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(Pk).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(gk).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 Id0={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.14",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 LWA 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",Id0,{...A,layouts:f},cd0);this.layouts=f}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new GWA(A.logger),this._slotRegistry=new xa,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 EWA(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=u5.getInstance(A.entityService,A.logger),A.messaging.subscribe("sync:initial:completed",async()=>{return await this.profileService?.initialize(),this.logger.info("AnchorProfileService initialized"),{success:!0}}),sr0(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)ca(this.config.routes,this.id,this.routeRegistry);if(this.siteBuilder=Oc.getInstance(A.logger.child("SiteBuilder"),A,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new CWA(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 JWA(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}}),Qd0({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 xd0(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
|
|
2745
2745
|
${[`**Title:** ${f.title}`,`**Description:** ${f.description}`,A.domain&&`**Domain:** ${A.domain}`,A.siteUrl&&`**URL:** ${A.siteUrl}`].filter(Boolean).join(`
|
|
2746
2746
|
`)}`}catch{return}}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),this.rebuildManager?.dispose(),Oc.resetInstance(),this.logger.debug("Cleaned up all event subscriptions")}}function CW(A={}){return new LWA(A)}YA();var iT2=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 OT2,Fragment as jT2}from"preact";function qWA({name:A,slots:f}){if(!f?.hasSlot(A))return null;let Q=f.getSlot(A).map((B)=>B.render());return OT2(jT2,{},...Q)}B0();Mu();Pi();YA();var _WA=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 RT2=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()}),_Xw=x5.extend({title:X.string().optional(),slug:X.string().optional()});class VWA extends Cx{constructor(A,f){super(A,f,{schema:RT2,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
|
|
2747
2747
|
|
|
@@ -2788,7 +2788,7 @@ The excerpt should be clear, concise, and compelling.`});YA();P2();Mu();import{j
|
|
|
2788
2788
|
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=Ay2.parse(f);return A.ai.generate({prompt:`Title: ${w.title}
|
|
2789
2789
|
|
|
2790
2790
|
Content:
|
|
2791
|
-
${w.content}`,templateName:"blog:excerpt"})})}var Gd0={name:"@brains/blog",private:!0,version:"0.2.0-alpha.
|
|
2791
|
+
${w.content}`,templateName:"blog:excerpt"})})}var Gd0={name:"@brains/blog",private:!0,version:"0.2.0-alpha.14",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 jWA extends Nf{entityType=EW.entityType;schema=Pb;adapter=EW;constructor(A={}){super("blog",Gd0,A,_WA)}getEntityTypeConfig(){return{weight:2}}createGenerationHandler(A){return new VWA(this.logger.child("BlogGenerationJobHandler"),A)}getTemplates(){return Xd0()}getDataSources(){return[new iWA(this.logger.child("BlogDataSource"))]}async onRegister(A){let{RSSDataSource:f}=await Promise.resolve().then(() => (zd0(),bd0));A.entities.registerDataSource(new f(this.logger.child("RSSDataSource"))),await Zd0(A,this.logger),Wd0(A,this.logger),kd0(A,this.logger),hd0(A),this.logger.info("Blog plugin registered (routes auto-generated at /posts/)")}}function gWA(A={}){return new jWA(A)}Mu();Pi();B0();YA();H6();var y4=X.object({title:X.string(),slug:X.string(),coverImageId:X.string().optional()}),Nd0=y4.pick({title:!0,slug:!0}),mb=W2.extend({metadata:Nd0}),Da=mb.extend({frontmatter:y4}),Ya=Da.extend({description:X.string().optional(),postCount:X.number(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),Cd0=X.object({description:X.string().optional()});function LW(A){return new R1(Cd0,{title:A,mappings:[{key:"description",label:"Description",type:"string"}]})}H6();class PWA extends _2{constructor(){super({entityType:"series",schema:mb,frontmatterSchema:y4,supportsCoverImage:!0,bodyFormatter:LW("")})}toMarkdown(A){let f,w={};try{f=this.parseFrontMatter(A.content,y4).coverImageId,w=LW(A.metadata.title).parse(this.extractBody(A.content))}catch{}let Q={title:A.metadata.title,slug:A.metadata.slug,...f&&{coverImageId:f}},x=LW(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 LW(f.title).parse(this.extractBody(A))}catch{return{}}}generateFrontMatter(){return""}}var lb=new PWA;B0();YA();R7();class RWA{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 Qy2=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()}),By2=X.object({type:X.enum(["list","detail"]),seriesName:X.string().optional()});function xy2(A){let f=By2.safeParse(A);if(f.success)return{type:f.data.type,seriesName:f.data.seriesName};let w=Qy2.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 Ed0(A){let f=K2(A.content,y4);return Da.parse({...A,frontmatter:f.metadata})}class nWA{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=xy2(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=Ed0(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=Ed0(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 cy2=X.object({prompt:X.string().optional(),title:X.string().optional(),seriesId:X.string().optional()});class Ha{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}
|
|
2792
2792
|
|
|
2793
2793
|
Content in this series:
|
|
2794
2794
|
${Q.join(`
|
|
@@ -2800,7 +2800,7 @@ Your task is to write a series description (2-3 sentences) that:
|
|
|
2800
2800
|
3. Is engaging and makes readers want to explore the content
|
|
2801
2801
|
4. Works well as a series overview on a website
|
|
2802
2802
|
|
|
2803
|
-
Be concise and focus on what makes this series unique and valuable.`});var Od0={name:"@brains/series",private:!0,version:"0.2.0-alpha.
|
|
2803
|
+
Be concise and focus on what makes this series unique and valuable.`});var Od0={name:"@brains/series",private:!0,version:"0.2.0-alpha.14",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 mWA extends Nf{entityType="series";schema=mb;adapter=lb;manager;constructor(){super("series",Od0)}getEntityTypeConfig(){return{weight:0.5}}createGenerationHandler(A){return new Ha(this.logger.child("SeriesGenerationHandler"),A)}getTemplates(){return{...Md0(),description:id0}}getDataSources(){return[new nWA(this.logger.child("SeriesDataSource"))]}async onRegister(A){this.manager=new RWA(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 Ha(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 lWA(){return new mWA}B0();YA();B0();YA();YA();B0();var Yy2=X.enum(["draft","queued","published"]),DF=X.object({title:X.string(),slug:X.string().optional(),description:X.string().optional(),author:X.string().optional(),status:Yy2,publishedAt:X.string().datetime().optional(),event:X.string().optional(),coverImageId:X.string().optional()}),Hy2=DF.pick({title:!0,description:!0,status:!0,publishedAt:!0,coverImageId:!0}).extend({slug:X.string()}),Ua=W2.extend({entityType:X.literal("deck"),metadata:Hy2}),Fa=Ua.extend({frontmatter:DF,body:X.string()}),mi=Fa.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 TWA extends _2{constructor(){super({entityType:"deck",schema:Ua,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 li=new TWA;YA();P2();var Uy2=X.object({markdown:X.string().describe("Markdown content with slide separators (---)")}),yWA=M0({name:"deck-detail",description:"Render a presentation deck as Reveal.js slides",schema:Uy2,dataSourceId:"decks:entities",requiredPermission:"public",layout:{component:IKA,fullscreen:!0}});P2();YA();var SWA=X.object({decks:X.array(Fa)}),pWA=X.object({decks:X.array(mi),pageTitle:X.string().optional()});import{jsxDEV as rWA}from"preact/jsx-dev-runtime";var dWA=({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 rWA("div",{className:"deck-list bg-theme",children:rWA("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:rWA(i3,{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 Ka extends R1{constructor(){super(SWA,{title:"Deck List",mappings:[{key:"decks",label:"Decks",type:"array",itemType:"object"}]})}}var oWA=M0({name:"deck-list",description:"List view of all presentation decks",schema:pWA,dataSourceId:"decks:entities",requiredPermission:"public",formatter:new Ka,layout:{component:dWA}});YA();B0();var Fy2=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")}),jd0=M0({name:"decks:generation",description:"Template for AI to generate complete slide decks from prompts",schema:Fy2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are creating slide decks in a distinctive voice that blends philosophy, technology, and culture.
|
|
2804
2804
|
|
|
2805
2805
|
Your task is to generate a complete slide deck based on the user's prompt.
|
|
2806
2806
|
|
|
@@ -2868,7 +2868,7 @@ Add your conclusion here`,$=$??`Presentation: ${c}`,await this.reportProgress(f,
|
|
|
2868
2868
|
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}
|
|
2869
2869
|
|
|
2870
2870
|
Content:
|
|
2871
|
-
${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 Pd0={name:"@brains/decks",private:!0,version:"0.2.0-alpha.
|
|
2871
|
+
${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 Pd0={name:"@brains/decks",private:!0,version:"0.2.0-alpha.14",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 tWA extends Nf{entityType=li.entityType;schema=li.schema;adapter=li;constructor(){super("decks",Pd0)}createGenerationHandler(A){return new sWA(this.logger.child("DeckGenerationJobHandler"),A)}getTemplates(){return{"deck-detail":yWA,"deck-list":oWA,generation:jd0,description:gd0}}getDataSources(){return[new aWA(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?`
|
|
2872
2872
|
|
|
2873
2873
|
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}
|
|
2874
2874
|
|
|
@@ -2883,7 +2883,7 @@ Guidelines:
|
|
|
2883
2883
|
3. Depth: Provide enough detail to be useful as a reference, but stay focused on the topic.
|
|
2884
2884
|
4. Style: Informative and educational. Write as if explaining to yourself for future reference.
|
|
2885
2885
|
5. Length: Adjust based on topic complexity - concise for simple topics, more detailed for complex ones.
|
|
2886
|
-
6. No meta-commentary: Just provide the content directly without phrases like "Here is..." or "This note covers..."`});B0();YA();var md0=X.object({prompt:X.string(),title:X.string().optional()}),vy2=x5.extend({title:X.string().optional()});class Xa extends Cx{constructor(A,f){super(A,f,{schema:md0,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 ld0={name:"@brains/note",private:!0,version:"0.2.0-alpha.
|
|
2886
|
+
6. No meta-commentary: Just provide the content directly without phrases like "Here is..." or "This note covers..."`});B0();YA();var md0=X.object({prompt:X.string(),title:X.string().optional()}),vy2=x5.extend({title:X.string().optional()});class Xa extends Cx{constructor(A,f){super(A,f,{schema:md0,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 ld0={name:"@brains/note",private:!0,version:"0.2.0-alpha.14",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 wvA extends Nf{entityType=yb.entityType;schema=Tb;adapter=yb;constructor(A={}){super("note",ld0,A,AvA)}createGenerationHandler(A){return new Xa(this.logger.child("NoteGenerationJobHandler"),A)}getTemplates(){return{generation:fvA}}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 qW(A={}){return new wvA(A)}B0();YA();YA();B0();var Td0=X.object({ref:X.string(),label:X.string()}),yd0=X.enum(["pending","draft","published"]),fY=X.object({status:yd0,title:X.string(),url:X.string().url(),description:X.string().optional(),keywords:X.array(X.string()),domain:X.string(),capturedAt:X.string().datetime(),source:Td0}),Sd0=fY.pick({title:!0,status:!0}),Si=W2.extend({entityType:X.literal("link"),metadata:Sd0}),QvA=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:Si,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 BvA=new HF;B0();YA();var hy2=X.object({success:X.boolean().describe("Set to true if you can extract meaningful content. Set to false only if the provided content is empty, just an error message, or otherwise unusable."),error:X.string().describe("If success is false, explain why content could not be extracted. Use an empty string when success is true."),title:X.string().max(80).describe("The page title - extract from the content or create a descriptive one. Leave empty string if success is false."),description:X.string().describe("A one-sentence description of what the page is about. Leave empty string if success is false."),summary:X.string().describe("A 1-2 paragraph summary of the main content. Leave empty string if success is false."),keywords:X.array(X.string()).describe("3-5 relevant keywords that categorize this content. Leave empty array if success is false.")}),pd0=M0({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:hy2,basePrompt:`You are an expert at extracting key information from webpage content.
|
|
2887
2887
|
|
|
2888
2888
|
You will receive webpage content in markdown format. Your job is to extract structured information from it.
|
|
2889
2889
|
|
|
@@ -2901,7 +2901,7 @@ Focus only on information present in the provided content. Do not make up or hal
|
|
|
2901
2901
|
|
|
2902
2902
|
`))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 zy2}from"crypto";class ri{static URL_PATTERN=/https?:\/\/[^\s<>"{}|\\^`[\]]+?(?=[,;:\s]|$)/gi;static extractUrls(A){let f=A.match(ri.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=zy2("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 Ny2=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()}),ohw=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 DvA extends Vw{context;linkAdapter;urlFetcher;constructor(A,f,w){super(A,{schema:Ny2,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=ri.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:
|
|
2903
2903
|
|
|
2904
|
-
${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 od0={name:"@brains/link",private:!0,version:"0.2.0-alpha.
|
|
2904
|
+
${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 od0={name:"@brains/link",private:!0,version:"0.2.0-alpha.14",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 YvA extends Nf{entityType=BvA.entityType;schema=Si;adapter=BvA;constructor(A={}){super("link",od0,A,QvA)}createGenerationHandler(A){return new DvA(this.logger.child("LinkCaptureJobHandler"),A,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:pd0,"link-list":rd0,"link-detail":dd0}}getDataSources(){return[new uvA(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:
|
|
2905
2905
|
|
|
2906
2906
|
${B.content}`,data:{url:w,hasContent:!0},interfacePermissionGrant:"public"})})}}function ad0(A={}){return new YvA(A)}var _W=ad0;YA();var FGw=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 sd0=X.enum(["draft","published"]),S4=X.object({title:X.string(),slug:X.string().optional(),status:sd0,publishedAt:X.string().datetime().optional(),description:X.string(),year:X.number(),coverImageId:X.string().optional(),url:X.string().url().optional()}),td0=S4.pick({title:!0,status:!0,publishedAt:!0,year:!0}).extend({slug:X.string()}),pb=W2.extend({entityType:X.literal("project"),metadata:td0}),Wa=X.object({context:X.string(),problem:X.string(),solution:X.string(),outcome:X.string()}),di=pb.extend({frontmatter:S4,body:X.string(),structuredContent:Wa.optional(),coverImageUrl:X.string().optional()}),rb=di.extend({url:X.string().optional(),typeLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),Ey2=di.extend({url:X.string(),typeLabel:X.string(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});B0();YA();YA();class HvA extends R1{constructor(){super(Wa,{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 UvA=new HvA;class FvA extends _2{constructor(){super({entityType:"project",schema:pb,frontmatterSchema:S4,supportsCoverImage:!0,bodyFormatter:UvA})}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 UvA.parse(this.extractBody(A.content))}createProjectContent(A,f){let w=UvA.format(f);return this.buildMarkdown(w,A)}}var UF=new FvA;YA();var KvA=X.object({});import{jsxDEV as gc,Fragment as qy2}from"preact/jsx-dev-runtime";var Ly2=({project:A})=>{let{frontmatter:f,url:w,coverImageUrl:Q}=A;return gc(Gf,{href:w,children:[Q&&gc("img",{src:Q,alt:f.title,className:"w-full h-56 object-cover rounded-md mb-4"},void 0,!1,void 0,this),gc(Rx,{children:f.title},void 0,!1,void 0,this),gc("p",{className:"text-theme leading-relaxed",children:f.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},XvA=({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 gc(qy2,{children:[gc(o2,{title:B,description:c},void 0,!1,void 0,this),gc("div",{className:"project-list bg-theme",children:gc("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[gc("h1",{className:"text-4xl font-bold text-heading mb-12",children:B},void 0,!1,void 0,this),gc("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-8",children:A.map((I)=>gc(Ly2,{project:I},I.id,!1,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&gc("div",{className:"mt-12",children:gc(vI,{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 ed0}from"preact/jsx-dev-runtime";var _y2=({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)},va=({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(WI,{markdown:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},ZvA=({project:A,prevProject:f,nextProject:w})=>{let{frontmatter:Q,structuredContent:B,metadata:x,coverImageUrl:c}=A;return Fw(ed0,{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(M3,{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(ed0,{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(va,{title:"Context",content:B.context},void 0,!1,void 0,this),Fw(va,{title:"Problem",content:B.problem},void 0,!1,void 0,this),Fw(va,{title:"Solution",content:B.solution},void 0,!1,void 0,this),Fw(va,{title:"Outcome",content:B.outcome},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Fw(_y2,{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 Vy2=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)")}),WvA=M0({name:"portfolio:generation",description:"Template for AI to generate portfolio project case studies",schema:Vy2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are helping to create a professional portfolio case study based on REAL project information.
|
|
2907
2907
|
|
|
@@ -2920,7 +2920,7 @@ Guidelines:
|
|
|
2920
2920
|
CRITICAL: Only include information that can be derived from the provided content. If information is missing, keep that section brief rather than inventing details.
|
|
2921
2921
|
|
|
2922
2922
|
Tone: Professional but accessible. Write for someone evaluating real work.
|
|
2923
|
-
Structure: Use markdown formatting. Break long sections into paragraphs for readability.`});B0();YA();var My2=X.object({prompt:X.string(),year:X.number(),title:X.string().optional()}),rGw=x5.extend({title:X.string().optional()});class ka extends Cx{constructor(A,f){super(A,f,{schema:My2,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 iy2(A){let f=K2(A.content,S4),w=UF.parseStructuredContent(A);return di.parse({...A,frontmatter:f.metadata,body:f.content,structuredContent:w})}class ha 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 iy2(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 Ao0={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.
|
|
2923
|
+
Structure: Use markdown formatting. Break long sections into paragraphs for readability.`});B0();YA();var My2=X.object({prompt:X.string(),year:X.number(),title:X.string().optional()}),rGw=x5.extend({title:X.string().optional()});class ka extends Cx{constructor(A,f){super(A,f,{schema:My2,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 iy2(A){let f=K2(A.content,S4),w=UF.parseStructuredContent(A);return di.parse({...A,frontmatter:f.metadata,body:f.content,structuredContent:w})}class ha 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 iy2(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 Ao0={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.14",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 jy2=X.object({projects:X.array(rb),pageTitle:X.string().optional(),pagination:$5.nullable(),baseUrl:X.string().optional()});class vvA extends Nf{entityType=UF.entityType;schema=pb;adapter=UF;constructor(A={}){super("portfolio",Ao0,A,KvA)}createGenerationHandler(A){return new ka(this.logger.child("ProjectGenerationJobHandler"),A)}getTemplates(){return{"project-list":M0({name:"project-list",description:"Portfolio project list page template",schema:jy2,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:XvA}}),"project-detail":M0({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:ZvA}}),generation:WvA}}getDataSources(){return[new ha(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 kvA(A={}){return new vvA(A)}B0();YA();YA();var fo0=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 gy2=X.object({aliases:X.array(X.string()).optional()}),Ga=W2.extend({entityType:X.literal("topic"),metadata:gy2}),EJw=X.object({content:X.string(),keywords:X.array(X.string())}),wo0=X.object({title:X.string().describe("Topic title"),keywords:X.array(X.string()).optional().describe("Topic keywords")}),LJw=X.object({timeWindowHours:X.number().min(1),minRelevanceScore:X.number().min(0).max(1)}),qJw=X.object({topicIds:X.array(X.string()).min(2),similarityThreshold:X.number().min(0).max(1)});class Pc extends _2{constructor(){super({entityType:"topic",schema:Ga,frontmatterSchema:wo0})}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 Qo0=40,Py2=new Pc;async function Ja(A,f=Qo0){return(await A.listEntities("topic",{limit:f})).map((Q)=>Py2.parseTopicBody(Q.content).title).filter((Q)=>Q.trim().length>0)}function ba(A){let f=(A.existingTopicTitles??[]).slice(0,Qo0),w=f.length>0?`
|
|
2924
2924
|
|
|
2925
2925
|
Existing topic titles to reuse when they clearly fit:
|
|
2926
2926
|
${f.map((Q)=>`- ${Q}`).join(`
|
|
@@ -3028,13 +3028,13 @@ RULES:
|
|
|
3028
3028
|
Return JSON with:
|
|
3029
3029
|
- title
|
|
3030
3030
|
- content
|
|
3031
|
-
- keywords`,requiredPermission:"public"});P2();YA();var ty2=X.object({id:X.string(),title:X.string(),summary:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()}),ai=X.object({topics:X.array(ty2),totalCount:X.number()});import{jsxDEV as jI}from"preact/jsx-dev-runtime";var JvA=({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(_c,{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 La extends R1{constructor(){super(ai,{title:"Topic List",mappings:[{key:"topics",label:"Topics",type:"array",itemType:"object"},{key:"totalCount",label:"Total Count",type:"number"}]})}}var Xo0=M0({name:"topics:topic-list",description:"List view of all discovered topics",schema:ai,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new La,layout:{component:JvA}});P2();YA();var si=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 bvA=({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(eZ,{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(sZ,{href:"/topics",children:"Back to Topics"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();class qa extends R1{constructor(){super(si,{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 Zo0=M0({name:"topics:topic-detail",description:"Detailed view of a single topic",schema:si,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new qa,layout:{component:bvA}});B0();YA();class zvA 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 Pc;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 Wo0(){let A=new Pc;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 vo0={name:"@brains/topics",private:!0,version:"0.2.0-alpha.13",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 AS2=new Pc;class ko0 extends Nf{entityType="topic";schema=Ga;adapter=AS2;autoExtractionEnabled=!1;initialDerivationDone=!1;constructor(A={}){super("topics",vo0,A,fo0)}getEntityTypeConfig(){return{weight:0.5}}getTemplates(){return{extraction:Fo0,"merge-synthesis":Ko0,"topic-list":Xo0,"topic-detail":Zo0}}getDataSources(){return[new zvA(this.logger.child("TopicsDataSource"))]}async onRegister(A){let f=new Ea(A,this.logger);A.jobs.registerHandler("process-single",f);let w=new GvA(A,this.logger);if(A.jobs.registerHandler("extract",w),A.insights.register("topic-distribution",Wo0()),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 Ca(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 Ca(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 oi(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 Ea(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}`),i=await f.extractFromEntity(g,G);for(let j of i)await E.createTopic({title:j.title,content:j.content,keywords:j.keywords});V.push({extractedTitles:i.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 Ca(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 _a(A){return new ko0(A)}B0();YA();B0();var ho0=X.enum(["linkedin"]),Go0=X.enum(["draft","queued","published","failed"]),Jo0=X.enum(["post","deck"]),r4=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:ho0.describe("Target platform"),status:Go0,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:Jo0.optional().describe("Source entity type (post, deck)")}),bo0=r4.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}")}),db=W2.extend({entityType:X.literal("social-post"),metadata:bo0}),Va=db.extend({frontmatter:r4,body:X.string()}),Ma=Va.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 NvA 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 V5=new NvA;B0();B0();YA();var fS2=bH.extend({platform:X.enum(["linkedin"]).optional(),status:X.enum(["draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),wS2=zH.extend({query:fS2.optional()});function zo0(A){let f=K2(A.content,r4);return Va.parse({...A,frontmatter:f.metadata,body:f.content})}class ia 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=wS2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){return zo0(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?zo0(Q):null;return A.parse({post:B})}}YA();var No0=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional()}),CvA=X.object({linkedin:No0.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();LvA();import{jsxDEV as e8,Fragment as xS2}from"preact/jsx-dev-runtime";function QS2(A,f){if(A.length<=f)return A;return A.slice(0,f).trim()+"..."}function BS2(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var ja=({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(xS2,{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:BS2(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(E5,{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:QS2(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(vI,{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 cS2}from"preact/jsx-dev-runtime";function Co0(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var ga=({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(cS2,{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(E5,{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(M3,{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)," ",Co0(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)," ",Co0(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 ti(A){return`social-media:${A}`}var qvA=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")}),IS2=x5.extend({slug:X.string().optional()});class VW extends Cx{constructor(A,f){super(A,f,{schema:qvA,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:ti(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}:
|
|
3031
|
+
- keywords`,requiredPermission:"public"});P2();YA();var ty2=X.object({id:X.string(),title:X.string(),summary:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()}),ai=X.object({topics:X.array(ty2),totalCount:X.number()});import{jsxDEV as jI}from"preact/jsx-dev-runtime";var JvA=({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(_c,{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 La extends R1{constructor(){super(ai,{title:"Topic List",mappings:[{key:"topics",label:"Topics",type:"array",itemType:"object"},{key:"totalCount",label:"Total Count",type:"number"}]})}}var Xo0=M0({name:"topics:topic-list",description:"List view of all discovered topics",schema:ai,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new La,layout:{component:JvA}});P2();YA();var si=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 bvA=({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(eZ,{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(sZ,{href:"/topics",children:"Back to Topics"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};YA();class qa extends R1{constructor(){super(si,{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 Zo0=M0({name:"topics:topic-detail",description:"Detailed view of a single topic",schema:si,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new qa,layout:{component:bvA}});B0();YA();class zvA 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 Pc;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 Wo0(){let A=new Pc;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 vo0={name:"@brains/topics",private:!0,version:"0.2.0-alpha.14",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 AS2=new Pc;class ko0 extends Nf{entityType="topic";schema=Ga;adapter=AS2;autoExtractionEnabled=!1;initialDerivationDone=!1;constructor(A={}){super("topics",vo0,A,fo0)}getEntityTypeConfig(){return{weight:0.5}}getTemplates(){return{extraction:Fo0,"merge-synthesis":Ko0,"topic-list":Xo0,"topic-detail":Zo0}}getDataSources(){return[new zvA(this.logger.child("TopicsDataSource"))]}async onRegister(A){let f=new Ea(A,this.logger);A.jobs.registerHandler("process-single",f);let w=new GvA(A,this.logger);if(A.jobs.registerHandler("extract",w),A.insights.register("topic-distribution",Wo0()),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 Ca(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 Ca(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 oi(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 Ea(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}`),i=await f.extractFromEntity(g,G);for(let j of i)await E.createTopic({title:j.title,content:j.content,keywords:j.keywords});V.push({extractedTitles:i.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 Ca(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 _a(A){return new ko0(A)}B0();YA();B0();var ho0=X.enum(["linkedin"]),Go0=X.enum(["draft","queued","published","failed"]),Jo0=X.enum(["post","deck"]),r4=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:ho0.describe("Target platform"),status:Go0,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:Jo0.optional().describe("Source entity type (post, deck)")}),bo0=r4.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}")}),db=W2.extend({entityType:X.literal("social-post"),metadata:bo0}),Va=db.extend({frontmatter:r4,body:X.string()}),Ma=Va.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 NvA 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 V5=new NvA;B0();B0();YA();var fS2=bH.extend({platform:X.enum(["linkedin"]).optional(),status:X.enum(["draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),wS2=zH.extend({query:fS2.optional()});function zo0(A){let f=K2(A.content,r4);return Va.parse({...A,frontmatter:f.metadata,body:f.content})}class ia 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=wS2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){return zo0(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?zo0(Q):null;return A.parse({post:B})}}YA();var No0=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional()}),CvA=X.object({linkedin:No0.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();LvA();import{jsxDEV as e8,Fragment as xS2}from"preact/jsx-dev-runtime";function QS2(A,f){if(A.length<=f)return A;return A.slice(0,f).trim()+"..."}function BS2(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var ja=({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(xS2,{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:BS2(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(E5,{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:QS2(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(vI,{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 cS2}from"preact/jsx-dev-runtime";function Co0(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var ga=({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(cS2,{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(E5,{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(M3,{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)," ",Co0(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)," ",Co0(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 ti(A){return`social-media:${A}`}var qvA=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")}),IS2=x5.extend({slug:X.string().optional()});class VW extends Cx{constructor(A,f){super(A,f,{schema:qvA,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:ti(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}:
|
|
3032
3032
|
|
|
3033
3033
|
Source: ${x}/${q}
|
|
3034
3034
|
|
|
3035
3035
|
${G.content}`,templateName:ti(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:ti(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=V5.createPostContent(Y,I),Z=V5.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=V5.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 _vA{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 VvA(A,f){return new _vA(A,f)}B0();YA();P2();LvA();var $S2=X.object({posts:X.array(Ma),totalCount:X.number().optional(),pagination:$5.nullable(),baseUrl:X.string().optional()}),uS2=X.object({post:Ma});function Eo0(){return{linkedin:Oa,"social-post-list":M0({name:"social-post-list",description:"Social post list page template",schema:$S2,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:ja}}),"social-post-detail":M0({name:"social-post-detail",description:"Individual social post template",schema:uS2,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:ga}})}}YA();var DS2=X.object({prompt:X.string().optional(),content:X.string().optional(),platform:X.enum(["linkedin"]).default("linkedin")}),YS2=X.object({prompt:X.string().optional(),content:X.string().optional(),title:X.string().optional(),platform:X.enum(["linkedin"]).optional()});function Lo0(A){A.eval.registerHandler("generation",async(f)=>{let w=DS2.parse(f),Q=w.content?`Create an engaging LinkedIn post to share this content:
|
|
3036
3036
|
|
|
3037
|
-
${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=YS2.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 VW(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 ei{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=V5.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=V5.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 qo0(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 _o0(A,f,w){let Q=new ei({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 Vo0(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 Mo0(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(`${V5.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 io0(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(`${V5.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 Oo0={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.13",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 MvA extends Nf{entityType=V5.entityType;schema=db;adapter=V5;providers=new Map;constructor(A){super("social-media",Oo0,A,CvA)}createGenerationHandler(A){return new VW(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return Eo0()}getDataSources(){return[new ia(this.logger.child("SocialPostDataSource"))]}async onRegister(A){if(this.initializeProviders(),qo0(A,this.providers,this.logger),_o0(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)Vo0(A,this.logger),Mo0(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");io0(A,this.logger),Lo0(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=VvA(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function AO(A){return new MvA(A)}YA();var US2=X.enum(["draft","queued","published","failed"]),oNw=X.object({status:US2.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class ivA{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"},iu={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 FS2=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),jo0=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),FS2).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 ivA;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 go0(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 Po0(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 Ro0(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 no0(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 mo0(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(iu.SKIPPED,{entityType:A,reason:B.reason??"Conditions not met"},"content-pipeline");return}}let Q={entityType:A};if(f.messageBus)await f.messageBus.send(iu.EXECUTE,Q,"content-pipeline");f.onGenerate?.(Q)}function lo0(A,f,w){if(w)w.send(iu.COMPLETED,{entityType:A,entityId:f},"content-pipeline")}function To0(A,f,w){if(w)w.send(iu.FAILED,{entityType:A,error:f},"content-pipeline")}var KS2=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(KS2,()=>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 go0(A,this.publishDeps);else await Po0(A,this.publishDeps)}completePublish(A,f,w){Ro0(A,f,w,this.publishDeps)}failPublish(A,f,w){no0(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 mo0(A,this.generationDeps)}catch(f){this.config.logger.error(`Generation trigger error for ${A}:`,f)}}completeGeneration(A,f){lo0(A,f,this.config.messageBus)}failGeneration(A,f){To0(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 yo0={maxRetries:3,baseDelayMs:5000};class gu{static instance=null;retries=new Map;config;static getInstance(A){return gu.instance??=new gu(A??yo0),gu.instance}static resetInstance(){gu.instance=null}static createFresh(A){return new gu(A??yo0)}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(XS2(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=OvA(A.tz,w),B=new Date(w.getTime()-Q),x=OvA(A.tz,B);if(x-Q===0)return B;{let c=new Date(w.getTime()-x),I=OvA(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 OvA(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 XS2(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 jvA=32,wO=31|jvA,do0=[1,2,4,8,16],So0=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,wO),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]|jvA;else if(f===wO)this.dayOfWeek[A]=wO;else if(f<6&&f>0)this.dayOfWeek[A]=this.dayOfWeek[A]|do0[f-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${f}, Type: ${typeof f}`)}},po0=[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&wO&&do0[c-1]&B)return!0;if(B&jvA){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>po0[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=po0[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&wO)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 ZS2(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 fO(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function WS2(A){return fO(A)}function vS2(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var ro0=30000,Pa=[],gvA=class{name;options;_states;fn;constructor(A,f,w){let Q,B;if(fO(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(fO(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=ZS2(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 So0("* * * * *")},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 So0(A,this.options.timezone),this.name){if(Pa.find((x)=>x.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");Pa.push(this)}return B!==void 0&&WS2(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=Pa.indexOf(this);A>=0&&Pa.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>ro0&&(f=ro0),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(w),f),this._states.currentTimeout&&this.options.unref&&vS2(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){fO(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&&fO(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 Ra{scheduleCron(A,f){let w=new gvA(A,()=>{f()});return{stop:()=>w.stop()}}scheduleInterval(A,f){let w=setInterval(()=>{f()},A);return{stop:()=>clearInterval(w)}}validateCron(A){new gvA(A).stop()}}B0();YA();var PvA=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)")}),RvA=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),kS2=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array(RvA).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),hS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),nvA=X.union([kS2,hS2]);function na(A,f,w){return{...Tf(f,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",PvA,async(B)=>{let{action:x,entityType:c,entityId:I,position:$}=B;switch(x){case"list":return GS2(w,c);case"add":return JS2(w,c,I);case"remove":return bS2(w,c,I);case"reorder":return zS2(w,c,I,$);default:return{success:!1,error:`Unknown action: ${x}`}}}),outputSchema:nvA}}async function GS2(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 JS2(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 bS2(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 zS2(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 mvA=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")}),NS2=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()}),CS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),lvA=X.union([NS2,CS2]);function ma(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.)",mvA,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:lvA}}B0();YA();function oo0(A,f){let{logger:w}=f;A.messaging.subscribe(fB.REGISTER,async(Q)=>ES2(f,Q.payload)),A.messaging.subscribe(fB.QUEUE,async(Q)=>LS2(A,f,Q.payload)),A.messaging.subscribe(fB.DIRECT,async(Q)=>qS2(A,f,Q.payload)),A.messaging.subscribe(fB.REMOVE,async(Q)=>_S2(f,Q.payload)),A.messaging.subscribe(fB.REORDER,async(Q)=>VS2(f,Q.payload)),A.messaging.subscribe(fB.LIST,async(Q)=>MS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_SUCCESS,async(Q)=>iS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_FAILURE,async(Q)=>OS2(A,f,Q.payload)),w.debug("Subscribed to publish messages"),A.messaging.subscribe(iu.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(iu.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 ES2(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 LS2(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 qS2(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 _S2(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 VS2(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 MS2(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 iS2(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 OS2(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 ao0(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 so0(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 Ra,...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)=>ao0(f.entityService,c,$,u),onGenerate:($)=>{c.info(`Generation triggered for ${$.entityType}`),f.messaging.send(iu.EXECUTE,{entityType:$.entityType})}})}async function to0(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 eo0={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.13",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 TvA extends yQ{pluginContext;queueManager;providerRegistry;retryTracker;scheduler;constructor(A){super("content-pipeline",eo0,A??{},jo0)}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=so0({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,logger:this.logger}),oo0(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 to0(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[na(this.pluginContext,this.id,this.queueManager),ma(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 yvA(A){return new TvA(A)}B0();YA();var Aa0=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")}),SvA=X.object({cloudflare:Aa0.optional()});B0();YA();var gS2=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 PS2(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 fa0(A,f,w){let Q=[];if(!w)return Q;return Q.push(Tf(A,"query",`Query website analytics from Cloudflare.
|
|
3037
|
+
${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=YS2.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 VW(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 ei{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=V5.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=V5.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 qo0(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 _o0(A,f,w){let Q=new ei({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 Vo0(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 Mo0(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(`${V5.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 io0(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(`${V5.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 Oo0={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.14",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 MvA extends Nf{entityType=V5.entityType;schema=db;adapter=V5;providers=new Map;constructor(A){super("social-media",Oo0,A,CvA)}createGenerationHandler(A){return new VW(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return Eo0()}getDataSources(){return[new ia(this.logger.child("SocialPostDataSource"))]}async onRegister(A){if(this.initializeProviders(),qo0(A,this.providers,this.logger),_o0(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)Vo0(A,this.logger),Mo0(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");io0(A,this.logger),Lo0(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=VvA(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function AO(A){return new MvA(A)}YA();var US2=X.enum(["draft","queued","published","failed"]),oNw=X.object({status:US2.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class ivA{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"},iu={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 FS2=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),jo0=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),FS2).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 ivA;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 go0(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 Po0(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 Ro0(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 no0(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 mo0(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(iu.SKIPPED,{entityType:A,reason:B.reason??"Conditions not met"},"content-pipeline");return}}let Q={entityType:A};if(f.messageBus)await f.messageBus.send(iu.EXECUTE,Q,"content-pipeline");f.onGenerate?.(Q)}function lo0(A,f,w){if(w)w.send(iu.COMPLETED,{entityType:A,entityId:f},"content-pipeline")}function To0(A,f,w){if(w)w.send(iu.FAILED,{entityType:A,error:f},"content-pipeline")}var KS2=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(KS2,()=>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 go0(A,this.publishDeps);else await Po0(A,this.publishDeps)}completePublish(A,f,w){Ro0(A,f,w,this.publishDeps)}failPublish(A,f,w){no0(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 mo0(A,this.generationDeps)}catch(f){this.config.logger.error(`Generation trigger error for ${A}:`,f)}}completeGeneration(A,f){lo0(A,f,this.config.messageBus)}failGeneration(A,f){To0(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 yo0={maxRetries:3,baseDelayMs:5000};class gu{static instance=null;retries=new Map;config;static getInstance(A){return gu.instance??=new gu(A??yo0),gu.instance}static resetInstance(){gu.instance=null}static createFresh(A){return new gu(A??yo0)}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(XS2(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=OvA(A.tz,w),B=new Date(w.getTime()-Q),x=OvA(A.tz,B);if(x-Q===0)return B;{let c=new Date(w.getTime()-x),I=OvA(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 OvA(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 XS2(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 jvA=32,wO=31|jvA,do0=[1,2,4,8,16],So0=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,wO),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]|jvA;else if(f===wO)this.dayOfWeek[A]=wO;else if(f<6&&f>0)this.dayOfWeek[A]=this.dayOfWeek[A]|do0[f-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${f}, Type: ${typeof f}`)}},po0=[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&wO&&do0[c-1]&B)return!0;if(B&jvA){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>po0[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=po0[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&wO)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 ZS2(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 fO(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function WS2(A){return fO(A)}function vS2(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var ro0=30000,Pa=[],gvA=class{name;options;_states;fn;constructor(A,f,w){let Q,B;if(fO(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(fO(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=ZS2(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 So0("* * * * *")},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 So0(A,this.options.timezone),this.name){if(Pa.find((x)=>x.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");Pa.push(this)}return B!==void 0&&WS2(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=Pa.indexOf(this);A>=0&&Pa.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>ro0&&(f=ro0),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(w),f),this._states.currentTimeout&&this.options.unref&&vS2(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){fO(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&&fO(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 Ra{scheduleCron(A,f){let w=new gvA(A,()=>{f()});return{stop:()=>w.stop()}}scheduleInterval(A,f){let w=setInterval(()=>{f()},A);return{stop:()=>clearInterval(w)}}validateCron(A){new gvA(A).stop()}}B0();YA();var PvA=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)")}),RvA=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),kS2=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array(RvA).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),hS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),nvA=X.union([kS2,hS2]);function na(A,f,w){return{...Tf(f,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",PvA,async(B)=>{let{action:x,entityType:c,entityId:I,position:$}=B;switch(x){case"list":return GS2(w,c);case"add":return JS2(w,c,I);case"remove":return bS2(w,c,I);case"reorder":return zS2(w,c,I,$);default:return{success:!1,error:`Unknown action: ${x}`}}}),outputSchema:nvA}}async function GS2(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 JS2(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 bS2(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 zS2(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 mvA=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")}),NS2=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()}),CS2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),lvA=X.union([NS2,CS2]);function ma(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.)",mvA,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:lvA}}B0();YA();function oo0(A,f){let{logger:w}=f;A.messaging.subscribe(fB.REGISTER,async(Q)=>ES2(f,Q.payload)),A.messaging.subscribe(fB.QUEUE,async(Q)=>LS2(A,f,Q.payload)),A.messaging.subscribe(fB.DIRECT,async(Q)=>qS2(A,f,Q.payload)),A.messaging.subscribe(fB.REMOVE,async(Q)=>_S2(f,Q.payload)),A.messaging.subscribe(fB.REORDER,async(Q)=>VS2(f,Q.payload)),A.messaging.subscribe(fB.LIST,async(Q)=>MS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_SUCCESS,async(Q)=>iS2(A,f,Q.payload)),A.messaging.subscribe(fB.REPORT_FAILURE,async(Q)=>OS2(A,f,Q.payload)),w.debug("Subscribed to publish messages"),A.messaging.subscribe(iu.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(iu.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 ES2(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 LS2(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 qS2(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 _S2(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 VS2(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 MS2(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 iS2(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 OS2(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 ao0(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 so0(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 Ra,...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)=>ao0(f.entityService,c,$,u),onGenerate:($)=>{c.info(`Generation triggered for ${$.entityType}`),f.messaging.send(iu.EXECUTE,{entityType:$.entityType})}})}async function to0(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 eo0={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.14",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 TvA extends yQ{pluginContext;queueManager;providerRegistry;retryTracker;scheduler;constructor(A){super("content-pipeline",eo0,A??{},jo0)}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=so0({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,logger:this.logger}),oo0(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 to0(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[na(this.pluginContext,this.id,this.queueManager),ma(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 yvA(A){return new TvA(A)}B0();YA();var Aa0=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")}),SvA=X.object({cloudflare:Aa0.optional()});B0();YA();var gS2=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 PS2(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 fa0(A,f,w){let Q=[];if(!w)return Q;return Q.push(Tf(A,"query",`Query website analytics from Cloudflare.
|
|
3038
3038
|
|
|
3039
3039
|
Date range options (use only one):
|
|
3040
3040
|
- No params: yesterday only
|
|
@@ -3172,7 +3172,7 @@ Returns pageviews, visitors, top pages, referrers, devices, and countries.`,gS2,
|
|
|
3172
3172
|
}
|
|
3173
3173
|
}
|
|
3174
3174
|
}
|
|
3175
|
-
`,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 rvA=7,RS2=10;function Qa0(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let f=Gk(),w=fP(rvA),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:RS2})]);return{days:rvA,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:rvA}}}}var Ba0={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.
|
|
3175
|
+
`,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 rvA=7,RS2=10;function Qa0(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let f=Gk(),w=fP(rvA),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:RS2})]);return{days:rvA,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:rvA}}}}var Ba0={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.14",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 xa0 extends yQ{cloudflareClient;constructor(A={}){super("analytics",Ba0,A,SvA)}async onRegister(A){this.cloudflareClient=this.config.cloudflare?new pvA(this.config.cloudflare):void 0,A.insights.register("traffic-overview",Qa0(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:wa0(f)}),{success:!0}})}async getTools(){return fa0(this.id,this.getContext(),this.cloudflareClient)}}function mS2(A={}){return new xa0(A)}var la=mS2;B0();YA();YA();var QO=["StatsWidget","ListWidget","CustomWidget","PipelineWidget","IdentityWidget","ProfileWidget","SystemWidget"],lS2=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(QO)});class Ta{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 ya{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 BO}from"preact/jsx-dev-runtime";var TS2={StatsWidget:or,ListWidget:ar,CustomWidget:sr,PipelineWidget:tr,IdentityWidget:er,ProfileWidget:Ad,SystemWidget:fd};function yS2(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 dvA(A,f){let{widget:w,data:Q}=A,B=`${w.pluginId}:${w.id}`,x=TS2[w.rendererName];return BO("div",{className:f?"col-span-1 lg:col-span-2":"",children:BO(x,{title:w.title,description:w.description,data:Q},void 0,!1,void 0,this)},B,!1,void 0,this)}function SS2({widgets:A}){let f=yS2(A);return BO("div",{className:"dashboard w-full max-w-layout mx-auto px-6 py-8 bg-theme","data-component":"dashboard:dashboard",children:BO("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_280px] gap-4",children:[f.primary.map((w)=>dvA(w,!0)),f.sidebar.length>0&&BO("aside",{className:"row-span-3 lg:col-start-3 space-y-4",children:f.sidebar.map((w)=>dvA(w))},void 0,!1,void 0,this),f.secondary.map((w)=>dvA(w,!0))]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var ovA=(A)=>{return SS2(A)};YA();var pS2=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(QO)}),rS2=X.object({widget:pS2,data:X.unknown()}),Sa=X.object({widgets:X.record(rS2)});class pa{format(A){return JSON.stringify(A,null,2)}parse(A){return JSON.parse(A)}}P2();var ca0=`var { h, hydrate, useState, useMemo, useEffect, useCallback, useRef, useContext, createContext, jsx, jsxs } = window.preact;
|
|
3176
3176
|
var __require = function(mod) {
|
|
3177
3177
|
if (mod === "crypto") return { randomUUID: () => window.crypto.randomUUID() };
|
|
3178
3178
|
throw new Error("Cannot require " + mod + " in browser");
|
|
@@ -26460,7 +26460,7 @@ Please report this to https://github.com/markedjs/marked.\`;
|
|
|
26460
26460
|
}
|
|
26461
26461
|
})();
|
|
26462
26462
|
})();
|
|
26463
|
-
`;var Ia0=M0({name:"dashboard",description:"Extensible dashboard with plugin-contributed widgets",schema:Sa,requiredPermission:"public",formatter:new pa,dataSourceId:"dashboard:dashboard",layout:{component:ovA,interactive:ca0}});var $a0={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.
|
|
26463
|
+
`;var Ia0=M0({name:"dashboard",description:"Extensible dashboard with plugin-contributed widgets",schema:Sa,requiredPermission:"public",formatter:new pa,dataSourceId:"dashboard:dashboard",layout:{component:ovA,interactive:ca0}});var $a0={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.14",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 aS2=X.object({version:X.string().default("1.0.0")}),sS2=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(QO),dataProvider:X.function().returns(X.promise(X.unknown()))}),tS2=X.object({pluginId:X.string(),widgetId:X.string().optional()});class avA extends yQ{dependencies=["site-builder"];widgetRegistry=null;datasource=null;constructor(A){super("dashboard",$a0,A??{},aS2)}async onRegister(A){this.widgetRegistry=new Ta(this.logger),this.datasource=new ya(this.widgetRegistry,this.logger),A.entities.registerDataSource(this.datasource),A.templates.register({dashboard:Ia0}),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=sS2.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=tS2.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 xO(A){return new avA(A)}YA();B0();YA();import{h as Hp2}from"preact";YA();R7();B0();var ob=X.enum(["draft","queued","published","failed"]),cO=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()}),ua0=cO.pick({subject:!0,status:!0,entityIds:!0,scheduledFor:!0,sentAt:!0,buttondownId:!0,sourceEntityType:!0}),IO=W2.extend({entityType:X.literal("newsletter"),metadata:ua0});B0();class Da0 extends _2{constructor(){super({entityType:"newsletter",schema:IO,frontmatterSchema:cO})}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 Ya0=new Da0;B0();B0();YA();var eS2=bH.extend({status:X.enum(["draft","queued","published","failed"]).optional()}),Ap2=zH.extend({query:eS2.optional()});function Ha0(A){try{let{content:f}=K2(A.content,cO);return f}catch{return A.content}}class svA 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=Ap2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){let f=Ha0(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=Ha0(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 fp2=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 tvA extends Cx{constructor(A,f){super(A,f,{schema:fp2,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:
|
|
26464
26464
|
|
|
26465
26465
|
${k.map((q)=>`## ${q.metadata.title}
|
|
26466
26466
|
|
|
@@ -26529,16 +26529,16 @@ Newsletter-specific guidelines:
|
|
|
26529
26529
|
- "Reply and let me know..."
|
|
26530
26530
|
- "Until next time..."
|
|
26531
26531
|
|
|
26532
|
-
The goal is to build a relationship with readers through valuable, authentic content.`});YA();B0();import{jsxDEV as m9,Fragment as cp2}from"preact/jsx-dev-runtime";var Qp2=X.object({id:X.string(),subject:X.string(),status:ob,excerpt:X.string(),created:X.string(),sentAt:X.string().optional(),url:X.string()}),Bp2=X.object({newsletters:X.array(Qp2),totalCount:X.number(),pagination:$5.nullable()}),xp2=({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(cp2,{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(E5,{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(vI,{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)},Fa0=M0({name:"newsletter-list",description:"Newsletter list page template",schema:Bp2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:xp2}});YA();B0();import{jsxDEV as KQ,Fragment as Dp2}from"preact/jsx-dev-runtime";var Ip2=X.object({id:X.string(),title:X.string(),url:X.string()}),Ka0=X.object({id:X.string(),subject:X.string(),url:X.string()}),$p2=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(Ip2).optional(),prevNewsletter:Ka0.nullable().optional(),nextNewsletter:Ka0.nullable().optional()}),up2=({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(Dp2,{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(E5,{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(WI,{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)},Xa0=M0({name:"newsletter-detail",description:"Individual newsletter detail template",schema:$p2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:up2}});var Za0={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.
|
|
26532
|
+
The goal is to build a relationship with readers through valuable, authentic content.`});YA();B0();import{jsxDEV as m9,Fragment as cp2}from"preact/jsx-dev-runtime";var Qp2=X.object({id:X.string(),subject:X.string(),status:ob,excerpt:X.string(),created:X.string(),sentAt:X.string().optional(),url:X.string()}),Bp2=X.object({newsletters:X.array(Qp2),totalCount:X.number(),pagination:$5.nullable()}),xp2=({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(cp2,{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(E5,{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(vI,{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)},Fa0=M0({name:"newsletter-list",description:"Newsletter list page template",schema:Bp2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:xp2}});YA();B0();import{jsxDEV as KQ,Fragment as Dp2}from"preact/jsx-dev-runtime";var Ip2=X.object({id:X.string(),title:X.string(),url:X.string()}),Ka0=X.object({id:X.string(),subject:X.string(),url:X.string()}),$p2=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(Ip2).optional(),prevNewsletter:Ka0.nullable().optional(),nextNewsletter:Ka0.nullable().optional()}),up2=({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(Dp2,{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(E5,{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(WI,{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)},Xa0=M0({name:"newsletter-detail",description:"Individual newsletter detail template",schema:$p2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:up2}});var Za0={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.14",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 evA extends Nf{entityType="newsletter";schema=IO;adapter=Ya0;constructor(A={}){super("newsletter",Za0,A,Up2)}createGenerationHandler(A){return new tvA(this.logger,A)}getTemplates(){return{generation:Ua0,"newsletter-list":Fa0,"newsletter-detail":Xa0}}getDataSources(){return[new svA(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:()=>Hp2(CKA,{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:
|
|
26533
26533
|
|
|
26534
|
-
${Q.content}`:Q.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:B,templateName:"newsletter:generation"})})}}function AkA(A={}){return new evA(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 Fp2=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)")}),Kp2=X.object({email:X.string().email().describe("Email address to unsubscribe")}),Xp2=X.object({type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:X.number().optional().describe("Maximum number of results")});function Wa0(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.",Fp2,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.",Kp2,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.",Xp2,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 va0(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 ka0={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.
|
|
26534
|
+
${Q.content}`:Q.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:B,templateName:"newsletter:generation"})})}}function AkA(A={}){return new evA(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 Fp2=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)")}),Kp2=X.object({email:X.string().email().describe("Email address to unsubscribe")}),Xp2=X.object({type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:X.number().optional().describe("Maximum number of results")});function Wa0(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.",Fp2,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.",Kp2,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.",Xp2,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 va0(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 ka0={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.14",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 Wp2=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 fkA extends yQ{constructor(A={}){super("buttondown",ka0,A,Wp2)}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 va0(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 Wa0(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 wkA(A={}){return new fkA(A)}var vp2=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 ha0(A={}){let f=vp2.parse(A);return[AkA({}),wkA({...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 _p2,mkdirSync as Vp2,writeFileSync as Mp2}from"fs";import{join as QY}from"path";YA();var QkA=X.object({baseFolder:X.string().default("_obsidian")});YA();function kp2(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 hp2(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 Ga0(A){let f=A.shape,w=[];for(let[Q,B]of Object.entries(f)){let{inner:x,required:c,defaultValue:I}=kp2(B),$=hp2(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 Gp2(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 Ja0(A,f,w=""){let Q=["---"];for(let B of f){let x=Gp2(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(`
|
|
26535
26535
|
`)}YA();var Jp2={string:"Input",number:"Number",boolean:"Boolean",date:"Date",enum:"Select",array:"Multi",unknown:"Input"};function bp2(A){let f={name:A.name,id:A.name,type:Jp2[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 ba0(A,f){let w={filesPaths:A,fields:f.map(bp2)};return`---
|
|
26536
26536
|
${k$(w)}---
|
|
26537
|
-
`}YA();var zp2=new Set(["entityType"]),Np2={base:"Notes"},Cp2=new Set(["base"]);function Ep2(A){let f=["file.name"];for(let w of A)if(!zp2.has(w.name))f.push(w.name);return f}function Lp2(A){return A.some((f)=>f.name==="status"&&f.type==="enum")}function za0(A,f){let w=Np2[A]??eg(A),Q=Lp2(f),B=Ep2(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:[Cp2.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:x};return{filename:`${w}.base`,content:k$(I),hasStatus:Q}}function Na0(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 Ca0(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 Ea0={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.13",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 ip2={mkdir:Vp2,writeFile:Mp2,existsFile:_p2},Op2=X.object({entityTypes:X.array(X.string()).optional().describe("Entity types to generate templates for (default: all)")});class BkA extends yQ{deps;constructor(A={},f={}){super("obsidian-vault",Ea0,A,QkA);this.deps={...ip2,...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.",Op2,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=Ga0(E),q=A.entities.getAdapter(G),y=q?.isSingleton===!0,r=ba0(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()??"",i=Ja0(G,V,g);this.deps.writeFile(QY(x,`${G}.md`),i),$.push(G);let j=za0(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=Na0(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=Ca0(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 xkA(A,f){return new BkA(A,f)}B0();YA();B0();var ckA=X.enum(["new","planned","in-progress","done","declined"]),IkA=X.enum(["low","medium","high","critical"]),$O=X.object({title:X.string(),status:ckA,priority:IkA.default("medium"),requested:X.number().int().default(1),tags:X.array(X.string()).default([]),declinedReason:X.string().optional()}),La0=X.object({title:X.string(),status:ckA,priority:IkA,requested:X.number().int(),slug:X.string()}),uO=W2.extend({entityType:X.literal("wish"),metadata:La0}),$kA=X.object({});B0();YA();class DO extends _2{constructor(){super({entityType:"wish",schema:uO,frontmatterSchema:$O})}createWishContent(A,f){return this.buildMarkdown(f,A)}parseWishContent(A){let f=this.parseFrontMatter(A,$O);return{frontmatter:$O.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 ukA=new DO;YA();YA();async function qa0(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 DkA{logger;context;adapter=new DO;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 qa0({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 _a0={critical:0,high:1,medium:2,low:3};function Va0(A){A.sort((f,w)=>{let Q=w.metadata.requested-f.metadata.requested;if(Q!==0)return Q;return _a0[f.metadata.priority]-_a0[w.metadata.priority]})}var Ma0={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.13",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 ia0 extends Nf{entityType=ukA.entityType;schema=uO;adapter=ukA;constructor(A={}){super("wishlist",Ma0,A,$kA)}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 Va0(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 DkA(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 gp2(A={}){return new ia0(A)}var ra=gp2;B0();YA();B0();var YO=X.object({title:X.string(),target:X.string()}),Oa0=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),HO=W2.extend({entityType:X.literal("prompt"),metadata:Oa0});B0();YA();class YkA extends _2{constructor(){super({entityType:"prompt",schema:HO,frontmatterSchema:YO})}toMarkdown(A){let f=this.extractBody(A.content),w=this.parseFrontMatter(A.content,YO);return this.buildMarkdown(f,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,YO),w=x2(f.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:f.title,target:f.target,slug:w}}}}var da=new YkA;var ja0={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.13",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 HkA extends Nf{entityType=da.entityType;schema=HO;adapter=da;constructor(){super("prompt",ja0,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function MW(){return new HkA}B0();YA();class oa{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(Rp2),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 Rp2(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 ga0={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")},Pa0={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 na0(A,f){return[np2(A,f),mp2(A,f)]}function np2(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:ga0,handler:async(w)=>{let Q=X.object(ga0).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 mp2(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:Pa0,handler:async(w)=>{let Q=X.object(Pa0).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 Ra0(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 Ra0(f.entityService,K,Z,y),r.coverSet=!0;return{success:!0,data:r}}}}async function Ra0(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 ma0={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.13",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 Tp2=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class UkA extends yQ{deps;cachedTools=null;constructor(A={},f={}){super("stock-photo",ma0,A,Tp2);this.deps=f}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),f=new oa(this.config.apiKey,this.deps.fetch??globalThis.fetch);return this.cachedTools=na0(this.id,{provider:f,entityService:A.entityService,fetchImage:this.deps.fetchImage??B5}),this.cachedTools}}function FkA(A={},f={}){return new UkA(A,f)}YA();B0();YA();B0();var la0=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")}),Ta0=KF.pick({name:!0,url:!0,status:!0}).extend({slug:X.string()}),sb=W2.extend({entityType:X.literal("agent"),metadata:Ta0}),UO=sb.extend({frontmatter:KF,about:X.string(),skills:X.array(la0),notes:X.string()}),tb=UO.extend({url:X.string().optional(),typeLabel:X.string().optional()}),yp2=UO.extend({url:X.string(),typeLabel:X.string()});B0();YA();var Sp2=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 pp2(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(`
|
|
26537
|
+
`}YA();var zp2=new Set(["entityType"]),Np2={base:"Notes"},Cp2=new Set(["base"]);function Ep2(A){let f=["file.name"];for(let w of A)if(!zp2.has(w.name))f.push(w.name);return f}function Lp2(A){return A.some((f)=>f.name==="status"&&f.type==="enum")}function za0(A,f){let w=Np2[A]??eg(A),Q=Lp2(f),B=Ep2(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:[Cp2.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:x};return{filename:`${w}.base`,content:k$(I),hasStatus:Q}}function Na0(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 Ca0(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 Ea0={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.14",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 ip2={mkdir:Vp2,writeFile:Mp2,existsFile:_p2},Op2=X.object({entityTypes:X.array(X.string()).optional().describe("Entity types to generate templates for (default: all)")});class BkA extends yQ{deps;constructor(A={},f={}){super("obsidian-vault",Ea0,A,QkA);this.deps={...ip2,...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.",Op2,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=Ga0(E),q=A.entities.getAdapter(G),y=q?.isSingleton===!0,r=ba0(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()??"",i=Ja0(G,V,g);this.deps.writeFile(QY(x,`${G}.md`),i),$.push(G);let j=za0(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=Na0(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=Ca0(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 xkA(A,f){return new BkA(A,f)}B0();YA();B0();var ckA=X.enum(["new","planned","in-progress","done","declined"]),IkA=X.enum(["low","medium","high","critical"]),$O=X.object({title:X.string(),status:ckA,priority:IkA.default("medium"),requested:X.number().int().default(1),tags:X.array(X.string()).default([]),declinedReason:X.string().optional()}),La0=X.object({title:X.string(),status:ckA,priority:IkA,requested:X.number().int(),slug:X.string()}),uO=W2.extend({entityType:X.literal("wish"),metadata:La0}),$kA=X.object({});B0();YA();class DO extends _2{constructor(){super({entityType:"wish",schema:uO,frontmatterSchema:$O})}createWishContent(A,f){return this.buildMarkdown(f,A)}parseWishContent(A){let f=this.parseFrontMatter(A,$O);return{frontmatter:$O.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 ukA=new DO;YA();YA();async function qa0(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 DkA{logger;context;adapter=new DO;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 qa0({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 _a0={critical:0,high:1,medium:2,low:3};function Va0(A){A.sort((f,w)=>{let Q=w.metadata.requested-f.metadata.requested;if(Q!==0)return Q;return _a0[f.metadata.priority]-_a0[w.metadata.priority]})}var Ma0={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.14",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 ia0 extends Nf{entityType=ukA.entityType;schema=uO;adapter=ukA;constructor(A={}){super("wishlist",Ma0,A,$kA)}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 Va0(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 DkA(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 gp2(A={}){return new ia0(A)}var ra=gp2;B0();YA();B0();var YO=X.object({title:X.string(),target:X.string()}),Oa0=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),HO=W2.extend({entityType:X.literal("prompt"),metadata:Oa0});B0();YA();class YkA extends _2{constructor(){super({entityType:"prompt",schema:HO,frontmatterSchema:YO})}toMarkdown(A){let f=this.extractBody(A.content),w=this.parseFrontMatter(A.content,YO);return this.buildMarkdown(f,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,YO),w=x2(f.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:f.title,target:f.target,slug:w}}}}var da=new YkA;var ja0={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.14",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 HkA extends Nf{entityType=da.entityType;schema=HO;adapter=da;constructor(){super("prompt",ja0,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function MW(){return new HkA}B0();YA();class oa{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(Rp2),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 Rp2(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 ga0={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")},Pa0={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 na0(A,f){return[np2(A,f),mp2(A,f)]}function np2(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:ga0,handler:async(w)=>{let Q=X.object(ga0).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 mp2(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:Pa0,handler:async(w)=>{let Q=X.object(Pa0).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 Ra0(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 Ra0(f.entityService,K,Z,y),r.coverSet=!0;return{success:!0,data:r}}}}async function Ra0(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 ma0={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.14",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 Tp2=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class UkA extends yQ{deps;cachedTools=null;constructor(A={},f={}){super("stock-photo",ma0,A,Tp2);this.deps=f}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),f=new oa(this.config.apiKey,this.deps.fetch??globalThis.fetch);return this.cachedTools=na0(this.id,{provider:f,entityService:A.entityService,fetchImage:this.deps.fetchImage??B5}),this.cachedTools}}function FkA(A={},f={}){return new UkA(A,f)}YA();B0();YA();B0();var la0=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")}),Ta0=KF.pick({name:!0,url:!0,status:!0}).extend({slug:X.string()}),sb=W2.extend({entityType:X.literal("agent"),metadata:Ta0}),UO=sb.extend({frontmatter:KF,about:X.string(),skills:X.array(la0),notes:X.string()}),tb=UO.extend({url:X.string().optional(),typeLabel:X.string().optional()}),yp2=UO.extend({url:X.string(),typeLabel:X.string()});B0();YA();var Sp2=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 pp2(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(`
|
|
26538
26538
|
`)}function rp2(A){if(!A.trim())return[];let f=[];for(let w of A.split(`
|
|
26539
26539
|
`)){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 ya0=new R1(Sp2,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:pp2,parser:rp2},{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=hk(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=ya0.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=ya0.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 dp2=new XF;function op2(A){let f=K2(A.content,KF),w=dp2.parseAgentContent(A.content);return UO.parse({...A,frontmatter:f.metadata,about:w.about,skills:w.skills,notes:w.notes})}class aa 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 op2(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 sa(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 Sa0(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 ap2=new XF;function ta(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:ap2.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(`
|
|
26540
26540
|
|
|
26541
|
-
`),skills:A.skills.map((x)=>({name:x.name,description:x.description,tags:x.tags})),notes:""}),metadata:{name:f,url:A.url,status:"active",slug:hk(A.url)},anchorName:f}}var sp2=X.object({prompt:X.string().optional(),url:X.string().optional(),content:X.string().optional(),skipAi:X.boolean().optional()}),WVw=x5.extend({name:X.string().optional(),domain:X.string().optional()});class KkA extends Cx{constructor(A,f){super(A,f,{schema:sp2,jobTypeName:"agent-generation",entityType:"agent"})}async generate(A,f){let w=A.url??A.prompt??"",Q=Sa0(w);if(!Q)throw Error("No URL or domain provided. Use: system_create agent with a domain like yeehaa.io");let B=await sa(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}=ta(B);return{id:Q,content:x,metadata:c,title:I}}}B0();P2();YA();import{jsxDEV as pa0}from"preact/jsx-dev-runtime";function ea(A){try{return new URL(A).hostname}catch{return A}}var As=({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 pa0("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)},fs=({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 pa0("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 fr2}from"preact/jsx-dev-runtime";var tp2=({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 ep2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var Ar2=({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(As,{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(fs,{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(tp2,{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:ea(f.url)},void 0,!1,void 0,this),XQ("span",{className:"text-[11px] text-theme-muted opacity-60",children:x?"Archived":`Discovered ${ep2(f.discoveredAt)}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},ra0=({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(fr2,{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(Ar2,{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(vI,{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 Br2}from"preact/jsx-dev-runtime";function wr2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var FO=({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),Qr2=({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),da0=({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),oa0=({agent:A})=>{let{frontmatter:f,about:w,skills:Q,notes:B}=A,x=ea(f.url);return c2(Br2,{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(As,{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(fs,{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 ",wr2(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(FO,{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(FO,{children:"Skills"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col gap-2.5",children:Q.map((c)=>c2(Qr2,{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(FO,{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(FO,{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(FO,{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(da0,{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(da0,{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 xr2=X.object({agents:X.array(tb),pageTitle:X.string().optional(),pagination:$5.nullable(),baseUrl:X.string().optional()});function aa0(){return{"agent-list":M0({name:"agent-list",description:"Agent directory list page template",schema:xr2,dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:ra0}}),"agent-detail":M0({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:oa0}})}}function sa0(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 sa(w,globalThis.fetch);if(!B)return{success:!0};let{content:x,metadata:c}=ta(B);await A.entityService.createEntity({id:w,entityType:"agent",content:x,metadata:c})}catch{}return{success:!0}})}var ws={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.13",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 Ir2=new XF;class XkA extends Nf{entityType="agent";schema=sb;adapter=Ir2;constructor(){super("agent-discovery",ws)}createGenerationHandler(A){return new KkA(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return aa0()}getDataSources(){return[new aa(this.logger.child("AgentDataSource"))]}async onRegister(A){sa0(A)}}function ZkA(){return new XkA}B0();YA();YA();B0();var eb=lk,ta0=lk,KO=W2.extend({entityType:X.literal("skill"),metadata:ta0});B0();class Az extends _2{constructor(){super({entityType:"skill",schema:KO,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 $r2(A){let f=[];if(A.topicTitles.length>0)f.push(`The brain's knowledge domains (from content analysis):
|
|
26541
|
+
`),skills:A.skills.map((x)=>({name:x.name,description:x.description,tags:x.tags})),notes:""}),metadata:{name:f,url:A.url,status:"active",slug:hk(A.url)},anchorName:f}}var sp2=X.object({prompt:X.string().optional(),url:X.string().optional(),content:X.string().optional(),skipAi:X.boolean().optional()}),WVw=x5.extend({name:X.string().optional(),domain:X.string().optional()});class KkA extends Cx{constructor(A,f){super(A,f,{schema:sp2,jobTypeName:"agent-generation",entityType:"agent"})}async generate(A,f){let w=A.url??A.prompt??"",Q=Sa0(w);if(!Q)throw Error("No URL or domain provided. Use: system_create agent with a domain like yeehaa.io");let B=await sa(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}=ta(B);return{id:Q,content:x,metadata:c,title:I}}}B0();P2();YA();import{jsxDEV as pa0}from"preact/jsx-dev-runtime";function ea(A){try{return new URL(A).hostname}catch{return A}}var As=({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 pa0("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)},fs=({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 pa0("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 fr2}from"preact/jsx-dev-runtime";var tp2=({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 ep2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var Ar2=({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(As,{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(fs,{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(tp2,{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:ea(f.url)},void 0,!1,void 0,this),XQ("span",{className:"text-[11px] text-theme-muted opacity-60",children:x?"Archived":`Discovered ${ep2(f.discoveredAt)}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},ra0=({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(fr2,{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(Ar2,{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(vI,{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 Br2}from"preact/jsx-dev-runtime";function wr2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var FO=({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),Qr2=({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),da0=({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),oa0=({agent:A})=>{let{frontmatter:f,about:w,skills:Q,notes:B}=A,x=ea(f.url);return c2(Br2,{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(As,{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(fs,{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 ",wr2(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(FO,{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(FO,{children:"Skills"},void 0,!1,void 0,this),c2("div",{className:"flex flex-col gap-2.5",children:Q.map((c)=>c2(Qr2,{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(FO,{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(FO,{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(FO,{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(da0,{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(da0,{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 xr2=X.object({agents:X.array(tb),pageTitle:X.string().optional(),pagination:$5.nullable(),baseUrl:X.string().optional()});function aa0(){return{"agent-list":M0({name:"agent-list",description:"Agent directory list page template",schema:xr2,dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:ra0}}),"agent-detail":M0({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:oa0}})}}function sa0(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 sa(w,globalThis.fetch);if(!B)return{success:!0};let{content:x,metadata:c}=ta(B);await A.entityService.createEntity({id:w,entityType:"agent",content:x,metadata:c})}catch{}return{success:!0}})}var ws={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.14",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 Ir2=new XF;class XkA extends Nf{entityType="agent";schema=sb;adapter=Ir2;constructor(){super("agent-discovery",ws)}createGenerationHandler(A){return new KkA(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return aa0()}getDataSources(){return[new aa(this.logger.child("AgentDataSource"))]}async onRegister(A){sa0(A)}}function ZkA(){return new XkA}B0();YA();YA();B0();var eb=lk,ta0=lk,KO=W2.extend({entityType:X.literal("skill"),metadata:ta0});B0();class Az extends _2{constructor(){super({entityType:"skill",schema:KO,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 $r2(A){let f=[];if(A.topicTitles.length>0)f.push(`The brain's knowledge domains (from content analysis):
|
|
26542
26542
|
${A.topicTitles.map((w)=>`- ${w}`).join(`
|
|
26543
26543
|
`)}`);if(A.toolDescriptions.length>0)f.push(`The brain has these capabilities:
|
|
26544
26544
|
${A.toolDescriptions.map((w)=>`- ${w}`).join(`
|
|
@@ -26580,7 +26580,7 @@ Return 2-5 skills as a JSON object with a "skills" array.`,requiredPermission:"p
|
|
|
26580
26580
|
title: ${c}
|
|
26581
26581
|
keywords: []
|
|
26582
26582
|
---
|
|
26583
|
-
${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,metadata:{}})}catch{}}let B=await Qs(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 Qs(A,this.logger,{replaceAll:!0});this.logger.info("Skill derivation complete",f)}hasRunInitialDerivation(){return this.initialDerivationDone}}function vkA(){return new WkA}var Yr2=X.object({}).strict();function Bs(A={}){return Yr2.parse(A),[ZkA(),vkA()]}B0();YA();P2();YA();B0();var xs=rP.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(xs.shape);B0();NH();YA();var Hr2=new V$;class cs{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([mk(Q),Q.listEntities("post",{limit:20}),Q.listEntities("deck",{limit:20}),d3(Q)]),$=Hr2.parseProfileBody(B,ZF),u=x.sort(BC).slice(0,3).map(Ri),Y=c.sort(BC).slice(0,3).map(Ti);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 Is{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,f,w){let Q=await mk(w.entityService),x={profile:Ur2.parseProfileBody(Q,ZF)};return f.parse(x)}}import{jsxDEV as wB,Fragment as As0}from"preact/jsx-dev-runtime";var kkA=({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(As0,{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(As0,{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(i3,{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(i3,{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(i3,{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(uKA,{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 Fr2}from"preact/jsx-dev-runtime";var hkA=({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(Fr2,{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(WI,{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:GM({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 fs0}from"preact/jsx-dev-runtime";var GkA=()=>{return rx(fs0,{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)},JkA=()=>{return rx(fs0,{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 ws0=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')")}),Qs0=X.object({entityDisplay:X.object({post:ws0,deck:ws0}).describe("Display metadata for post and deck entity types (required for homepage)")});var Bs0={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.13",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 bkA extends yQ{dependencies=["blog","decks"];constructor(A){super("professional-site",Bs0,A,Qs0)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",xs);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 cs(Q,B);A.entities.registerDataSource(x);let c=new Is;A.entities.registerDataSource(c);let I=X.object({profile:ZF,posts:X.array(e3),decks:X.array(mi),postsListUrl:X.string(),decksListUrl:X.string(),cta:Ci}),$=X.object({profile:ZF}),u=X.object({});A.templates.register({"homepage-list":M0({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:I,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:kkA}}),about:M0({name:"about",description:"About page with full profile information",schema:$,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:hkA}}),"subscribe-thanks":M0({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:u,requiredPermission:"public",layout:{component:GkA}}),"subscribe-error":M0({name:"subscribe-error",description:"Newsletter subscription error page",schema:u,requiredPermission:"public",layout:{component:JkA}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function xs0(A){return new bkA(A??{})}var cs0=[{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 Is0({sections:A,siteInfo:f,slots:w}){return fz("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[fz(UKA,{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(YKA,{primaryNavigation:f.navigation.primary,secondaryNavigation:f.navigation.secondary,copyright:f.copyright,socialLinks:f.socialLinks,children:fz(qWA,{name:"footer-top",slots:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Xr2={layouts:{default:Is0},routes:cs0,plugin:xs0,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"}}}},XO=Xr2;var $s0=`/* Default font imports */
|
|
26583
|
+
${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,metadata:{}})}catch{}}let B=await Qs(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 Qs(A,this.logger,{replaceAll:!0});this.logger.info("Skill derivation complete",f)}hasRunInitialDerivation(){return this.initialDerivationDone}}function vkA(){return new WkA}var Yr2=X.object({}).strict();function Bs(A={}){return Yr2.parse(A),[ZkA(),vkA()]}B0();YA();P2();YA();B0();var xs=rP.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(xs.shape);B0();NH();YA();var Hr2=new V$;class cs{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([mk(Q),Q.listEntities("post",{limit:20}),Q.listEntities("deck",{limit:20}),d3(Q)]),$=Hr2.parseProfileBody(B,ZF),u=x.sort(BC).slice(0,3).map(Ri),Y=c.sort(BC).slice(0,3).map(Ti);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 Is{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,f,w){let Q=await mk(w.entityService),x={profile:Ur2.parseProfileBody(Q,ZF)};return f.parse(x)}}import{jsxDEV as wB,Fragment as As0}from"preact/jsx-dev-runtime";var kkA=({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(As0,{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(As0,{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(i3,{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(i3,{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(i3,{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(uKA,{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 Fr2}from"preact/jsx-dev-runtime";var hkA=({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(Fr2,{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(WI,{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:GM({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 fs0}from"preact/jsx-dev-runtime";var GkA=()=>{return rx(fs0,{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)},JkA=()=>{return rx(fs0,{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 ws0=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')")}),Qs0=X.object({entityDisplay:X.object({post:ws0,deck:ws0}).describe("Display metadata for post and deck entity types (required for homepage)")});var Bs0={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.14",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 bkA extends yQ{dependencies=["blog","decks"];constructor(A){super("professional-site",Bs0,A,Qs0)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",xs);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 cs(Q,B);A.entities.registerDataSource(x);let c=new Is;A.entities.registerDataSource(c);let I=X.object({profile:ZF,posts:X.array(e3),decks:X.array(mi),postsListUrl:X.string(),decksListUrl:X.string(),cta:Ci}),$=X.object({profile:ZF}),u=X.object({});A.templates.register({"homepage-list":M0({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:I,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:kkA}}),about:M0({name:"about",description:"About page with full profile information",schema:$,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:hkA}}),"subscribe-thanks":M0({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:u,requiredPermission:"public",layout:{component:GkA}}),"subscribe-error":M0({name:"subscribe-error",description:"Newsletter subscription error page",schema:u,requiredPermission:"public",layout:{component:JkA}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function xs0(A){return new bkA(A??{})}var cs0=[{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 Is0({sections:A,siteInfo:f,slots:w}){return fz("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[fz(UKA,{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(YKA,{primaryNavigation:f.navigation.primary,secondaryNavigation:f.navigation.secondary,copyright:f.copyright,socialLinks:f.socialLinks,children:fz(qWA,{name:"footer-top",slots:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Xr2={layouts:{default:Is0},routes:cs0,plugin:xs0,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"}}}},XO=Xr2;var $s0=`/* Default font imports */
|
|
26584
26584
|
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&display=swap');
|
|
26585
26585
|
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap');
|
|
26586
26586
|
|
|
@@ -26884,7 +26884,7 @@ ${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,
|
|
|
26884
26884
|
.btn-primary:hover { background-color: var(--color-brand-dark); }
|
|
26885
26885
|
.btn-primary:disabled { opacity: 0.5; }
|
|
26886
26886
|
}
|
|
26887
|
-
`;var $s=$s0;import{join as Wr2}from"path";var us0=["prompt","note","link","wishlist","topics","directory-sync","agents","mcp","discord","a2a"],Ds0=[...us0,"image","dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder","webserver"],vr2=[...Ds0,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],Ys0=yH({name:"rover",version:"0.1.0",model:"gpt-5.4-mini",site:XO,theme:$s,presets:{core:us0,default:Ds0,full:vr2},evalDisable:["discord","webserver","mcp","analytics","dashboard"],capabilities:[["prompt",MW,void 0],["image",wq,void 0],["dashboard",xO,void 0],["blog",gWA,{}],["series",lWA,void 0],["decks",yi,void 0],["note",qW,{}],["link",_W,{}],["portfolio",kvA,{}],["topics",_a,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",yvA,{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",AO,{autoGenerateOnBlogPublish:!0}],["newsletter",ha0,{doubleOptIn:!0}],["obsidian-vault",xkA,{autoSync:!0}],["wishlist",ra,{}],["stock-photo",FkA,{}],["agents",Bs,void 0],["directory-sync",dZ,{seedContent:!0,seedContentPath:Wr2(import.meta.dir,"..","seed-content"),initialSync:!0}],["analytics",la,{}],["site-info",hW,void 0],["site-builder",CW,{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 us=X.object({routeId:X.string(),sectionId:X.string()}),ZO=W2.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:us});B0();class Hs0 extends _2{constructor(){super({entityType:"site-content",schema:ZO,frontmatterSchema:us})}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 zkA=new Hs0;YA();var Ds=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 NkA{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 CkA{siteConfig;operations;constructor(A,f){this.siteConfig=f;this.operations=new NkA(A)}async generateContent(A,f){let w=Ds.parse(A);return this.operations.generate(w,this.siteConfig,f)}}B0();function Us0(A,f){return[Tf(f,"generate","Generate content for all routes, a specific route, or a specific section",Ds,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 Fs0={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.13",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 EkA extends yQ{siteContentService;constructor(){super("site-content",Fs0,{},X.object({}))}async onRegister(A){A.entities.register("site-content",ZO,zkA),this.siteContentService=new CkA(A)}async getTools(){return Us0(()=>this.siteContentService,this.id)}}function WO(){return new EkA}B0();YA();P2();YA();B0();var Ks0=X.enum(["available","early access","coming soon","planned"]),Xs0=X.object({title:X.string(),description:X.string()}),BY=X.object({name:X.string(),availability:Ks0,order:X.number()}),Ys=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(Xs0).min(1).max(6),story:X.string()}),hr2=BY.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),wz=W2.extend({entityType:X.literal("product"),metadata:hr2}),Hs=wz.extend({frontmatter:BY,body:Ys,labels:X.record(X.string(),X.string())}),Us=Hs.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(Ys,{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 LkA 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 Fs=new LkA;YA();B0();var Zs0=X.object({title:X.string(),description:X.string()}),Ws0=X.object({title:X.string(),description:X.string()}),Gr2=X.object({title:X.string(),description:X.string()}),vs0=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),xY=X.object({headline:X.string(),tagline:X.string()}),Jr2=X.object({title:X.string(),description:X.string()}),Ks=X.object({vision:X.string(),pillars:X.array(Zs0).min(1).max(6),approach:X.array(Jr2).min(1).max(6),productsIntro:X.string(),technologies:X.array(Gr2).min(1).max(6),benefits:X.array(Ws0).min(1).max(6),cta:vs0}),ks0=xY.pick({headline:!0}).extend({slug:X.string()}),Bz=W2.extend({entityType:X.literal("products-overview"),metadata:ks0}),vO=Bz.extend({frontmatter:xY,body:Ks,labels:X.record(X.string(),X.string())});B0();YA();YA();class xz extends R1{constructor(){super(Ks,{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 qkA 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 _kA=new qkA;B0();YA();var br2=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function hs0(A,f){let w=K2(A.content,BY),Q=f.parse(w.content),B=f.getLabels();return Hs.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}function Gs0(A,f){let w=K2(A.content,xY),Q=f.parse(w.content),B=f.getLabels();return vO.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}class Xs{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=br2.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=Gs0(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:hs0(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:Gs0(I,this.overviewFormatter),products:c.map(($)=>hs0($,this.productFormatter))})}}import{jsxDEV as y0,Fragment as Cr2}from"preact/jsx-dev-runtime";var Js0=({overview:A,products:f})=>{let{frontmatter:w,body:Q,labels:B}=A;return y0(Cr2,{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:`
|
|
26887
|
+
`;var $s=$s0;import{join as Wr2}from"path";var us0=["prompt","note","link","wishlist","topics","directory-sync","agents","mcp","discord","a2a"],Ds0=[...us0,"image","dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder","webserver"],vr2=[...Ds0,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],Ys0=yH({name:"rover",version:"0.1.0",model:"gpt-5.4-mini",site:XO,theme:$s,presets:{core:us0,default:Ds0,full:vr2},evalDisable:["discord","webserver","mcp","analytics","dashboard"],capabilities:[["prompt",MW,void 0],["image",wq,void 0],["dashboard",xO,void 0],["blog",gWA,{}],["series",lWA,void 0],["decks",yi,void 0],["note",qW,{}],["link",_W,{}],["portfolio",kvA,{}],["topics",_a,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",yvA,{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",AO,{autoGenerateOnBlogPublish:!0}],["newsletter",ha0,{doubleOptIn:!0}],["obsidian-vault",xkA,{autoSync:!0}],["wishlist",ra,{}],["stock-photo",FkA,{}],["agents",Bs,void 0],["directory-sync",dZ,{seedContent:!0,seedContentPath:Wr2(import.meta.dir,"..","seed-content"),initialSync:!0}],["analytics",la,{}],["site-info",hW,void 0],["site-builder",CW,{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 us=X.object({routeId:X.string(),sectionId:X.string()}),ZO=W2.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:us});B0();class Hs0 extends _2{constructor(){super({entityType:"site-content",schema:ZO,frontmatterSchema:us})}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 zkA=new Hs0;YA();var Ds=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 NkA{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 CkA{siteConfig;operations;constructor(A,f){this.siteConfig=f;this.operations=new NkA(A)}async generateContent(A,f){let w=Ds.parse(A);return this.operations.generate(w,this.siteConfig,f)}}B0();function Us0(A,f){return[Tf(f,"generate","Generate content for all routes, a specific route, or a specific section",Ds,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 Fs0={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.14",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 EkA extends yQ{siteContentService;constructor(){super("site-content",Fs0,{},X.object({}))}async onRegister(A){A.entities.register("site-content",ZO,zkA),this.siteContentService=new CkA(A)}async getTools(){return Us0(()=>this.siteContentService,this.id)}}function WO(){return new EkA}B0();YA();P2();YA();B0();var Ks0=X.enum(["available","early access","coming soon","planned"]),Xs0=X.object({title:X.string(),description:X.string()}),BY=X.object({name:X.string(),availability:Ks0,order:X.number()}),Ys=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(Xs0).min(1).max(6),story:X.string()}),hr2=BY.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),wz=W2.extend({entityType:X.literal("product"),metadata:hr2}),Hs=wz.extend({frontmatter:BY,body:Ys,labels:X.record(X.string(),X.string())}),Us=Hs.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(Ys,{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 LkA 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 Fs=new LkA;YA();B0();var Zs0=X.object({title:X.string(),description:X.string()}),Ws0=X.object({title:X.string(),description:X.string()}),Gr2=X.object({title:X.string(),description:X.string()}),vs0=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),xY=X.object({headline:X.string(),tagline:X.string()}),Jr2=X.object({title:X.string(),description:X.string()}),Ks=X.object({vision:X.string(),pillars:X.array(Zs0).min(1).max(6),approach:X.array(Jr2).min(1).max(6),productsIntro:X.string(),technologies:X.array(Gr2).min(1).max(6),benefits:X.array(Ws0).min(1).max(6),cta:vs0}),ks0=xY.pick({headline:!0}).extend({slug:X.string()}),Bz=W2.extend({entityType:X.literal("products-overview"),metadata:ks0}),vO=Bz.extend({frontmatter:xY,body:Ks,labels:X.record(X.string(),X.string())});B0();YA();YA();class xz extends R1{constructor(){super(Ks,{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 qkA 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 _kA=new qkA;B0();YA();var br2=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function hs0(A,f){let w=K2(A.content,BY),Q=f.parse(w.content),B=f.getLabels();return Hs.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}function Gs0(A,f){let w=K2(A.content,xY),Q=f.parse(w.content),B=f.getLabels();return vO.parse({...A,frontmatter:w.metadata,body:Q,labels:B})}class Xs{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=br2.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=Gs0(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:hs0(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:Gs0(I,this.overviewFormatter),products:c.map(($)=>hs0($,this.productFormatter))})}}import{jsxDEV as y0,Fragment as Cr2}from"preact/jsx-dev-runtime";var Js0=({overview:A,products:f})=>{let{frontmatter:w,body:Q,labels:B}=A;return y0(Cr2,{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:`
|
|
26888
26888
|
@keyframes wave-drift {
|
|
26889
26889
|
from { transform: translateX(0); }
|
|
26890
26890
|
to { transform: translateX(-50%); }
|
|
@@ -26912,7 +26912,7 @@ ${c}`;try{await A.entityService.createEntity({id:I,entityType:"topic",content:$,
|
|
|
26912
26912
|
@media (prefers-reduced-motion: reduce) {
|
|
26913
26913
|
.detail-wave { animation: none; }
|
|
26914
26914
|
}
|
|
26915
|
-
`},void 0,!1,void 0,this),M1("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:M1("svg",{preserveAspectRatio:"none",width:"200%",height:"100%",viewBox:"0 0 1600 400",className:"block absolute inset-0 detail-wave",children:[M1("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),M1("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),M1("div",{className:"absolute inset-0 cta-bg-pattern pointer-events-none"},void 0,!1,void 0,this),M1("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:[M1("nav",{"aria-label":"Breadcrumb",className:"text-sm text-white/50 mb-8 hero-stagger-1",children:M1("ol",{className:"flex flex-wrap items-center gap-1",children:[M1("li",{className:"flex items-center gap-1",children:M1("a",{href:"/",className:"hover:text-white transition-colors",children:"Home"},void 0,!1,void 0,this)},void 0,!1,void 0,this),M1("li",{className:"flex items-center gap-1",children:[M1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),M1("a",{href:B,className:"hover:text-white transition-colors",children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this),M1("li",{className:"flex items-center gap-1",children:[M1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),M1("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),M1("div",{className:"mb-6 hero-stagger-1",children:M1(E5,{status:f.availability},void 0,!1,void 0,this)},void 0,!1,void 0,this),M1("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),M1("div",{className:"w-20 h-1.5 bg-accent mb-6 md:mb-8 hero-stagger-2"},void 0,!1,void 0,this),M1("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),M1("section",{className:"bg-theme-subtle py-20 md:py-28 px-6 md:px-12",children:M1("div",{className:"max-w-4xl mx-auto space-y-16",children:[M1("div",{children:[M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:Q.promise},void 0,!1,void 0,this),M1("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),M1("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-16",children:[M1("div",{children:[M1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.role},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.role},void 0,!1,void 0,this)]},void 0,!0,void 0,this),M1("div",{children:[M1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.purpose},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.purpose},void 0,!1,void 0,this)]},void 0,!0,void 0,this),M1("div",{children:[M1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.audience},void 0,!1,void 0,this),M1("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),M1("div",{className:"flex flex-col md:flex-row md:items-center gap-6 md:gap-12",children:[M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted whitespace-nowrap",children:Q.values},void 0,!1,void 0,this),M1(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),M1("section",{className:"cta-bg-pattern bg-brand py-20 md:py-32 px-6 md:px-12",children:M1("div",{className:"container mx-auto max-w-5xl",children:[M1("h2",{className:"text-sm tracking-widest uppercase text-white/50 mb-16",children:Q.features},void 0,!1,void 0,this),M1("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-16",children:w.features.map((I,$)=>M1("div",{children:M1("div",{className:"flex items-start gap-6",children:[M1("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),M1("div",{className:"pt-2",children:[M1("div",{className:"w-8 h-1 bg-accent mb-4"},void 0,!1,void 0,this),M1("h3",{className:"text-xl font-bold text-white mb-3",children:I.title},void 0,!1,void 0,this),M1("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),M1("section",{className:"py-20 md:py-32 px-6 md:px-12",children:M1("div",{className:"max-w-3xl mx-auto",children:[M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-12",children:Q.story},void 0,!1,void 0,this),M1("div",{className:"space-y-6",children:c.map((I,$)=>M1("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),M1("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:M1("div",{className:"max-w-4xl mx-auto",children:[M1("p",{className:"text-sm tracking-widest uppercase text-white/60 mb-4",children:f.name},void 0,!1,void 0,this),M1("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),M1("p",{className:"text-lg text-white/60 mb-10 max-w-xl",children:w.promise},void 0,!1,void 0,this),M1(_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 VkA=X.object({route:X.string().default("/products")});var zs0={name:"@brains/products",private:!0,version:"0.2.0-alpha.
|
|
26915
|
+
`},void 0,!1,void 0,this),M1("div",{className:"absolute inset-0 overflow-hidden pointer-events-none",children:M1("svg",{preserveAspectRatio:"none",width:"200%",height:"100%",viewBox:"0 0 1600 400",className:"block absolute inset-0 detail-wave",children:[M1("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),M1("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),M1("div",{className:"absolute inset-0 cta-bg-pattern pointer-events-none"},void 0,!1,void 0,this),M1("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:[M1("nav",{"aria-label":"Breadcrumb",className:"text-sm text-white/50 mb-8 hero-stagger-1",children:M1("ol",{className:"flex flex-wrap items-center gap-1",children:[M1("li",{className:"flex items-center gap-1",children:M1("a",{href:"/",className:"hover:text-white transition-colors",children:"Home"},void 0,!1,void 0,this)},void 0,!1,void 0,this),M1("li",{className:"flex items-center gap-1",children:[M1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),M1("a",{href:B,className:"hover:text-white transition-colors",children:x},void 0,!1,void 0,this)]},void 0,!0,void 0,this),M1("li",{className:"flex items-center gap-1",children:[M1("span",{className:"mx-1","aria-hidden":"true",children:"/"},void 0,!1,void 0,this),M1("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),M1("div",{className:"mb-6 hero-stagger-1",children:M1(E5,{status:f.availability},void 0,!1,void 0,this)},void 0,!1,void 0,this),M1("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),M1("div",{className:"w-20 h-1.5 bg-accent mb-6 md:mb-8 hero-stagger-2"},void 0,!1,void 0,this),M1("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),M1("section",{className:"bg-theme-subtle py-20 md:py-28 px-6 md:px-12",children:M1("div",{className:"max-w-4xl mx-auto space-y-16",children:[M1("div",{children:[M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:Q.promise},void 0,!1,void 0,this),M1("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),M1("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-16",children:[M1("div",{children:[M1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.role},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.role},void 0,!1,void 0,this)]},void 0,!0,void 0,this),M1("div",{children:[M1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.purpose},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:w.purpose},void 0,!1,void 0,this)]},void 0,!0,void 0,this),M1("div",{children:[M1("div",{className:"w-8 h-1 bg-accent mb-6"},void 0,!1,void 0,this),M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-4",children:Q.audience},void 0,!1,void 0,this),M1("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),M1("div",{className:"flex flex-col md:flex-row md:items-center gap-6 md:gap-12",children:[M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted whitespace-nowrap",children:Q.values},void 0,!1,void 0,this),M1(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),M1("section",{className:"cta-bg-pattern bg-brand py-20 md:py-32 px-6 md:px-12",children:M1("div",{className:"container mx-auto max-w-5xl",children:[M1("h2",{className:"text-sm tracking-widest uppercase text-white/50 mb-16",children:Q.features},void 0,!1,void 0,this),M1("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-16",children:w.features.map((I,$)=>M1("div",{children:M1("div",{className:"flex items-start gap-6",children:[M1("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),M1("div",{className:"pt-2",children:[M1("div",{className:"w-8 h-1 bg-accent mb-4"},void 0,!1,void 0,this),M1("h3",{className:"text-xl font-bold text-white mb-3",children:I.title},void 0,!1,void 0,this),M1("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),M1("section",{className:"py-20 md:py-32 px-6 md:px-12",children:M1("div",{className:"max-w-3xl mx-auto",children:[M1("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-12",children:Q.story},void 0,!1,void 0,this),M1("div",{className:"space-y-6",children:c.map((I,$)=>M1("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),M1("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:M1("div",{className:"max-w-4xl mx-auto",children:[M1("p",{className:"text-sm tracking-widest uppercase text-white/60 mb-4",children:f.name},void 0,!1,void 0,this),M1("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),M1("p",{className:"text-lg text-white/60 mb-10 max-w-xl",children:w.promise},void 0,!1,void 0,this),M1(_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 VkA=X.object({route:X.string().default("/products")});var zs0={name:"@brains/products",private:!0,version:"0.2.0-alpha.14",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 qr2=X.object({overview:vO,products:X.array(Us)}),_r2=X.object({product:Us});class MkA extends Nf{entityType=Fs.entityType;schema=wz;adapter=Fs;constructor(A={}){super("products",zs0,A,VkA)}getTemplates(){return{"product-list":M0({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:qr2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:Js0}}),"product-detail":M0({name:"product-detail",description:"Individual product detail page",schema:_r2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:bs0}})}}getDataSources(){return[new Xs(this.logger.child("ProductsDataSource"))]}async onRegister(A){A.entities.register("products-overview",Bz,_kA)}}function ikA(A={}){return new MkA(A)}import{join as Gd2}from"path";var Ns0=`/*
|
|
26916
26916
|
* Shared globals + helpers used by tree / constellation / roots canvas
|
|
26917
26917
|
* scripts. Concatenated in front of each variant canvas at site-package
|
|
26918
26918
|
* load time (see sites/rizom/src/index.ts) so the variant canvases
|
|
@@ -29810,7 +29810,7 @@ Your task is to:
|
|
|
29810
29810
|
2. Generate a clear, natural summary that captures key points, decisions, and action items
|
|
29811
29811
|
3. Return structured data in the required JSON format
|
|
29812
29812
|
|
|
29813
|
-
Be concise but comprehensive, focusing on the most important information.`});B0();YA();var Ed2=X.object({entityType:X.literal("summary"),query:X.object({id:X.string().optional(),conversationId:X.string().optional(),limit:X.number().optional()}).optional()});class ykA{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=Ed2.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 we0={name:"@brains/summary",private:!0,version:"0.2.0-alpha.
|
|
29813
|
+
Be concise but comprehensive, focusing on the most important information.`});B0();YA();var Ed2=X.object({entityType:X.literal("summary"),query:X.object({id:X.string().optional(),conversationId:X.string().optional(),limit:X.number().optional()}).optional()});class ykA{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=Ed2.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 we0={name:"@brains/summary",private:!0,version:"0.2.0-alpha.14",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 qd2=new mu;class SkA extends Nf{entityType="summary";schema=hO;adapter=qd2;digestHandler=null;constructor(A){super("summary",we0,A??{},mkA)}getConfig(){return this.config}getTemplates(){return{"summary-list":et0,"summary-detail":Ae0,"ai-response":fe0}}getDataSources(){return[new ykA(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=yP.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 pkA(A){return new SkA(A)}var Qe0=["prompt","directory-sync","note","link","topics","agents","mcp","discord","a2a"],Vd2=[...Qe0,"image","site-info","site-content","site-builder","webserver"],Be0=yH({name:"relay",version:"0.1.0",model:"gpt-5.4-mini",site:uz,theme:Dz,presets:{core:Qe0,default:Vd2},evalDisable:["webserver","discord"],capabilities:[["prompt",MW,void 0],["note",qW,{}],["link",_W,{}],["image",wq,void 0],["topics",_a,{}],["summary",pkA,{}],["decks",yi,void 0],["agents",Bs,void 0],["directory-sync",dZ,{seedContent:!0,seedContentPath:_d2(import.meta.dir,"..","seed-content"),initialSync:!0}],["site-content",WO,void 0],["site-info",hW,void 0],["site-builder",CW,{}]],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 Ss2}from"fs";import{join as ps2}from"path";import{execSync as rs2}from"child_process";import{parseArgs as Od2}from"util";var jd2={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 xe0(A){let{values:f,positionals:w}=Od2({args:A,options:jd2,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 qs2}from"fs";import{join as _s2}from"path";import{spawn as Vs2,execSync as Ms2}from"child_process";var ls={name:"@rizom/brain",version:"0.2.0-alpha.14",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 ue0,writeFileSync as ys,chmodSync as Ss,existsSync as ps,readFileSync as Hz}from"fs";import{basename as akA,dirname as skA,join as Bw,resolve as wo2}from"path";import{fileURLToPath as Qo2}from"url";bO();import{existsSync as ce0,readFileSync as ld2}from"fs";import{dirname as Td2,join as Ie0}from"path";var Ts={rover:`# This env file uses @env-spec - see https://varlock.dev/env-spec for more info
|
|
29814
29814
|
#
|
|
29815
29815
|
# @defaultRequired=false @defaultSensitive=false
|
|
29816
29816
|
# ----------
|