@rizom/brain 0.2.0-alpha.0 → 0.2.0-alpha.1
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
|
@@ -488,7 +488,7 @@ This will delete existing topics and regenerate them from scratch.`,args:{...x,c
|
|
|
488
488
|
hash text NOT NULL,
|
|
489
489
|
created_at numeric
|
|
490
490
|
)
|
|
491
|
-
`;await A.session.run(B);let I=(await A.values(VA`SELECT id, hash, created_at FROM ${VA.identifier(w)} ORDER BY created_at DESC LIMIT 1`))[0]??void 0,$=[];for(let c of Q)if(!I||Number(I[2])<c.folderMillis){for(let D of c.sql)$.push(A.run(VA.raw(D)));$.push(A.run(VA`INSERT INTO ${VA.identifier(w)} ("hash", "created_at") VALUES(${c.hash}, ${c.folderMillis})`))}await A.session.migrate($)}var jT=y(()=>{bdA();g8()});async function LdA(A,f){let Q=f?.child("entity-migrate")??M2.getInstance().child("entity-migrate"),{db:w,client:B,url:x}=Zg(A);Q.debug("Running entity database migrations...");try{await Wg(B,x);let $=import.meta.url.includes("/dist/")?new URL("./migrations/entity-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Gv(w,{migrationsFolder:$}),await Gg(B),Q.debug("Entity database migrations completed successfully")}catch(I){throw Q.error("Entity database migration failed:",I),I}finally{B.close()}}var qdA=y(()=>{jT();M1A();HA()});async function CdA(A,f){let Q=f?.child("job-queue-migrate")??M2.getInstance().child("job-queue-migrate"),{db:w,client:B,url:x}=Fg(A);Q.debug("Running job queue migrations...");try{await Xg(B,x);let $=import.meta.url.includes("/dist/")?new URL("./migrations/job-queue",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Gv(w,{migrationsFolder:$}),Q.debug("Job queue migrations completed successfully")}catch(I){throw Q.error("Job queue migration failed:",I),I}finally{B.close()}}var _dA=y(()=>{jT();C1A();HA()});async function VdA(A,f){let Q=f?.child("conversation-migrate")??M2.getInstance().child("conversation-migrate"),{db:w,client:B,url:x}=Eg(A);Q.debug("Running conversation database migrations...");try{if(x.startsWith("file:"))await B.execute("PRAGMA journal_mode = WAL");let $=import.meta.url.includes("/dist/")?new URL("./migrations/conversation-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Gv(w,{migrationsFolder:$}),Q.debug("Conversation database migrations completed successfully")}catch(I){throw Q.error("Conversation database migration failed:",I),I}finally{B.close()}}var MdA=y(()=>{jT();$2A();HA()});class aL{logger;migrations;constructor(A,f){this.logger=A,this.migrations=f??{getStandardConfigWithDirectories:Lb,migrateEntities:LdA,migrateJobQueue:CdA,migrateConversations:VdA}}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 n9A=y(()=>{MT();qdA();_dA();MdA()});var RT;var p9A=y(()=>{HA();RT=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 jdA;var OdA=y(()=>{jdA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.0",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 Hf=b((Yz1,PT)=>{(function(){function A(fA,FA){Object.defineProperty(w.prototype,fA,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",FA[0],FA[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 Q(fA,FA){fA=(fA=fA.constructor)&&(fA.displayName||fA.name)||"ReactClass";var dA=fA+"."+FA;KA[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.",FA,fA),KA[dA]=!0)}function w(fA,FA,dA){this.props=fA,this.context=FA,this.refs=RA,this.updater=dA||kA}function B(){}function x(fA,FA,dA){this.props=fA,this.context=FA,this.refs=RA,this.updater=dA||kA}function I(){}function $(fA){return""+fA}function c(fA){try{$(fA);var FA=!1}catch(T0){FA=!0}if(FA){FA=console;var dA=FA.error,i0=typeof Symbol==="function"&&Symbol.toStringTag&&fA[Symbol.toStringTag]||fA.constructor.name||"Object";return dA.call(FA,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",i0),$(fA)}}function D(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 uA:return"Profiler";case d:return"StrictMode";case P0:return"Suspense";case GA:return"SuspenseList";case JA: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 DA:return fA.displayName||"Context";case gA:return(fA._context.displayName||"Context")+".Consumer";case $0:var FA=fA.render;return fA=fA.displayName,fA||(fA=FA.displayName||FA.name||"",fA=fA!==""?"ForwardRef("+fA+")":"ForwardRef"),fA;case _0:return FA=fA.displayName||null,FA!==null?FA:D(fA.type)||"Memo";case c0:FA=fA._payload,fA=fA._init;try{return D(fA(FA))}catch(dA){}}return null}function u(fA){if(fA===e)return"<>";if(typeof fA==="object"&&fA!==null&&fA.$$typeof===c0)return"<...>";try{var FA=D(fA);return FA?"<"+FA+">":"<...>"}catch(dA){return"<...>"}}function K(){var fA=rA.A;return fA===null?null:fA.getOwner()}function F(){return Error("react-stack-top-frame")}function Z(fA){if(EA.call(fA,"key")){var FA=Object.getOwnPropertyDescriptor(fA,"key").get;if(FA&&FA.isReactWarning)return!1}return fA.key!==void 0}function J(fA,FA){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)",FA))}dA.isReactWarning=!0,Object.defineProperty(fA,"key",{get:dA,configurable:!0})}function v(){var fA=D(this.type);return S0[fA]||(S0[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 k(fA,FA,dA,i0,T0,H1){var z0=dA.ref;return fA={$$typeof:a,type:fA,key:FA,props:dA,_owner:i0},(z0!==void 0?z0:null)!==null?Object.defineProperty(fA,"ref",{enumerable:!1,get:v}):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:T0}),Object.defineProperty(fA,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:H1}),Object.freeze&&(Object.freeze(fA.props),Object.freeze(fA)),fA}function q(fA,FA){return FA=k(fA.type,FA,fA.props,fA._owner,fA._debugStack,fA._debugTask),fA._store&&(FA._store.validated=fA._store.validated),FA}function V(fA){C(fA)?fA._store&&(fA._store.validated=1):typeof fA==="object"&&fA!==null&&fA.$$typeof===c0&&(fA._payload.status==="fulfilled"?C(fA._payload.value)&&fA._payload.value._store&&(fA._payload.value._store.validated=1):fA._store&&(fA._store.validated=1))}function C(fA){return typeof fA==="object"&&fA!==null&&fA.$$typeof===a}function l(fA){var FA={"=":"=0",":":"=2"};return"$"+fA.replace(/[=:]/g,function(dA){return FA[dA]})}function r(fA,FA){return typeof fA==="object"&&fA!==null&&fA.key!=null?(c(fA.key),l(""+fA.key)):FA.toString(36)}function P(fA){switch(fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason;default:switch(typeof fA.status==="string"?fA.then(I,I):(fA.status="pending",fA.then(function(FA){fA.status==="pending"&&(fA.status="fulfilled",fA.value=FA)},function(FA){fA.status==="pending"&&(fA.status="rejected",fA.reason=FA)})),fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason}}throw fA}function O(fA,FA,dA,i0,T0){var H1=typeof fA;if(H1==="undefined"||H1==="boolean")fA=null;var z0=!1;if(fA===null)z0=!0;else switch(H1){case"bigint":case"string":case"number":z0=!0;break;case"object":switch(fA.$$typeof){case a:case p:z0=!0;break;case c0:return z0=fA._init,O(z0(fA._payload),FA,dA,i0,T0)}}if(z0){z0=fA,T0=T0(z0);var z1=i0===""?"."+r(z0,0):i0;return x0(T0)?(dA="",z1!=null&&(dA=z1.replace(_A,"$&/")+"/"),O(T0,FA,dA,"",function(N2){return N2})):T0!=null&&(C(T0)&&(T0.key!=null&&(z0&&z0.key===T0.key||c(T0.key)),dA=q(T0,dA+(T0.key==null||z0&&z0.key===T0.key?"":(""+T0.key).replace(_A,"$&/")+"/")+z1),i0!==""&&z0!=null&&C(z0)&&z0.key==null&&z0._store&&!z0._store.validated&&(dA._store.validated=2),T0=dA),FA.push(T0)),1}if(z0=0,z1=i0===""?".":i0+":",x0(fA))for(var v1=0;v1<fA.length;v1++)i0=fA[v1],H1=z1+r(i0,v1),z0+=O(i0,FA,dA,H1,T0);else if(v1=f(fA),typeof v1==="function")for(v1===fA.entries&&(jA||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),jA=!0),fA=v1.call(fA),v1=0;!(i0=fA.next()).done;)i0=i0.value,H1=z1+r(i0,v1++),z0+=O(i0,FA,dA,H1,T0);else if(H1==="object"){if(typeof fA.then==="function")return O(P(fA),FA,dA,i0,T0);throw FA=String(fA),Error("Objects are not valid as a React child (found: "+(FA==="[object Object]"?"object with keys {"+Object.keys(fA).join(", ")+"}":FA)+"). If you meant to render a collection of children, use an array instead.")}return z0}function R(fA,FA,dA){if(fA==null)return fA;var i0=[],T0=0;return O(fA,i0,"","",function(H1){return FA.call(dA,H1,T0++)}),i0}function g(fA){if(fA._status===-1){var FA=fA._ioInfo;FA!=null&&(FA.start=FA.end=performance.now()),FA=fA._result;var dA=FA();if(dA.then(function(T0){if(fA._status===0||fA._status===-1){fA._status=1,fA._result=T0;var H1=fA._ioInfo;H1!=null&&(H1.end=performance.now()),dA.status===void 0&&(dA.status="fulfilled",dA.value=T0)}},function(T0){if(fA._status===0||fA._status===-1){fA._status=2,fA._result=T0;var H1=fA._ioInfo;H1!=null&&(H1.end=performance.now()),dA.status===void 0&&(dA.status="rejected",dA.reason=T0)}}),FA=fA._ioInfo,FA!=null){FA.value=dA;var i0=dA.displayName;typeof i0==="string"&&(FA.name=i0)}fA._status===-1&&(fA._status=0,fA._result=dA)}if(fA._status===1)return FA=fA._result,FA===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
491
|
+
`;await A.session.run(B);let I=(await A.values(VA`SELECT id, hash, created_at FROM ${VA.identifier(w)} ORDER BY created_at DESC LIMIT 1`))[0]??void 0,$=[];for(let c of Q)if(!I||Number(I[2])<c.folderMillis){for(let D of c.sql)$.push(A.run(VA.raw(D)));$.push(A.run(VA`INSERT INTO ${VA.identifier(w)} ("hash", "created_at") VALUES(${c.hash}, ${c.folderMillis})`))}await A.session.migrate($)}var jT=y(()=>{bdA();g8()});async function LdA(A,f){let Q=f?.child("entity-migrate")??M2.getInstance().child("entity-migrate"),{db:w,client:B,url:x}=Zg(A);Q.debug("Running entity database migrations...");try{await Wg(B,x);let $=import.meta.url.includes("/dist/")?new URL("./migrations/entity-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Gv(w,{migrationsFolder:$}),await Gg(B),Q.debug("Entity database migrations completed successfully")}catch(I){throw Q.error("Entity database migration failed:",I),I}finally{B.close()}}var qdA=y(()=>{jT();M1A();HA()});async function CdA(A,f){let Q=f?.child("job-queue-migrate")??M2.getInstance().child("job-queue-migrate"),{db:w,client:B,url:x}=Fg(A);Q.debug("Running job queue migrations...");try{await Xg(B,x);let $=import.meta.url.includes("/dist/")?new URL("./migrations/job-queue",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Gv(w,{migrationsFolder:$}),Q.debug("Job queue migrations completed successfully")}catch(I){throw Q.error("Job queue migration failed:",I),I}finally{B.close()}}var _dA=y(()=>{jT();C1A();HA()});async function VdA(A,f){let Q=f?.child("conversation-migrate")??M2.getInstance().child("conversation-migrate"),{db:w,client:B,url:x}=Eg(A);Q.debug("Running conversation database migrations...");try{if(x.startsWith("file:"))await B.execute("PRAGMA journal_mode = WAL");let $=import.meta.url.includes("/dist/")?new URL("./migrations/conversation-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await Gv(w,{migrationsFolder:$}),Q.debug("Conversation database migrations completed successfully")}catch(I){throw Q.error("Conversation database migration failed:",I),I}finally{B.close()}}var MdA=y(()=>{jT();$2A();HA()});class aL{logger;migrations;constructor(A,f){this.logger=A,this.migrations=f??{getStandardConfigWithDirectories:Lb,migrateEntities:LdA,migrateJobQueue:CdA,migrateConversations:VdA}}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 n9A=y(()=>{MT();qdA();_dA();MdA()});var RT;var p9A=y(()=>{HA();RT=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 jdA;var OdA=y(()=>{jdA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.1",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 Hf=b((Yz1,PT)=>{(function(){function A(fA,FA){Object.defineProperty(w.prototype,fA,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",FA[0],FA[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 Q(fA,FA){fA=(fA=fA.constructor)&&(fA.displayName||fA.name)||"ReactClass";var dA=fA+"."+FA;KA[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.",FA,fA),KA[dA]=!0)}function w(fA,FA,dA){this.props=fA,this.context=FA,this.refs=RA,this.updater=dA||kA}function B(){}function x(fA,FA,dA){this.props=fA,this.context=FA,this.refs=RA,this.updater=dA||kA}function I(){}function $(fA){return""+fA}function c(fA){try{$(fA);var FA=!1}catch(T0){FA=!0}if(FA){FA=console;var dA=FA.error,i0=typeof Symbol==="function"&&Symbol.toStringTag&&fA[Symbol.toStringTag]||fA.constructor.name||"Object";return dA.call(FA,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",i0),$(fA)}}function D(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 uA:return"Profiler";case d:return"StrictMode";case P0:return"Suspense";case GA:return"SuspenseList";case JA: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 DA:return fA.displayName||"Context";case gA:return(fA._context.displayName||"Context")+".Consumer";case $0:var FA=fA.render;return fA=fA.displayName,fA||(fA=FA.displayName||FA.name||"",fA=fA!==""?"ForwardRef("+fA+")":"ForwardRef"),fA;case _0:return FA=fA.displayName||null,FA!==null?FA:D(fA.type)||"Memo";case c0:FA=fA._payload,fA=fA._init;try{return D(fA(FA))}catch(dA){}}return null}function u(fA){if(fA===e)return"<>";if(typeof fA==="object"&&fA!==null&&fA.$$typeof===c0)return"<...>";try{var FA=D(fA);return FA?"<"+FA+">":"<...>"}catch(dA){return"<...>"}}function K(){var fA=rA.A;return fA===null?null:fA.getOwner()}function F(){return Error("react-stack-top-frame")}function Z(fA){if(EA.call(fA,"key")){var FA=Object.getOwnPropertyDescriptor(fA,"key").get;if(FA&&FA.isReactWarning)return!1}return fA.key!==void 0}function J(fA,FA){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)",FA))}dA.isReactWarning=!0,Object.defineProperty(fA,"key",{get:dA,configurable:!0})}function v(){var fA=D(this.type);return S0[fA]||(S0[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 k(fA,FA,dA,i0,T0,H1){var z0=dA.ref;return fA={$$typeof:a,type:fA,key:FA,props:dA,_owner:i0},(z0!==void 0?z0:null)!==null?Object.defineProperty(fA,"ref",{enumerable:!1,get:v}):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:T0}),Object.defineProperty(fA,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:H1}),Object.freeze&&(Object.freeze(fA.props),Object.freeze(fA)),fA}function q(fA,FA){return FA=k(fA.type,FA,fA.props,fA._owner,fA._debugStack,fA._debugTask),fA._store&&(FA._store.validated=fA._store.validated),FA}function V(fA){C(fA)?fA._store&&(fA._store.validated=1):typeof fA==="object"&&fA!==null&&fA.$$typeof===c0&&(fA._payload.status==="fulfilled"?C(fA._payload.value)&&fA._payload.value._store&&(fA._payload.value._store.validated=1):fA._store&&(fA._store.validated=1))}function C(fA){return typeof fA==="object"&&fA!==null&&fA.$$typeof===a}function l(fA){var FA={"=":"=0",":":"=2"};return"$"+fA.replace(/[=:]/g,function(dA){return FA[dA]})}function r(fA,FA){return typeof fA==="object"&&fA!==null&&fA.key!=null?(c(fA.key),l(""+fA.key)):FA.toString(36)}function P(fA){switch(fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason;default:switch(typeof fA.status==="string"?fA.then(I,I):(fA.status="pending",fA.then(function(FA){fA.status==="pending"&&(fA.status="fulfilled",fA.value=FA)},function(FA){fA.status==="pending"&&(fA.status="rejected",fA.reason=FA)})),fA.status){case"fulfilled":return fA.value;case"rejected":throw fA.reason}}throw fA}function O(fA,FA,dA,i0,T0){var H1=typeof fA;if(H1==="undefined"||H1==="boolean")fA=null;var z0=!1;if(fA===null)z0=!0;else switch(H1){case"bigint":case"string":case"number":z0=!0;break;case"object":switch(fA.$$typeof){case a:case p:z0=!0;break;case c0:return z0=fA._init,O(z0(fA._payload),FA,dA,i0,T0)}}if(z0){z0=fA,T0=T0(z0);var z1=i0===""?"."+r(z0,0):i0;return x0(T0)?(dA="",z1!=null&&(dA=z1.replace(_A,"$&/")+"/"),O(T0,FA,dA,"",function(N2){return N2})):T0!=null&&(C(T0)&&(T0.key!=null&&(z0&&z0.key===T0.key||c(T0.key)),dA=q(T0,dA+(T0.key==null||z0&&z0.key===T0.key?"":(""+T0.key).replace(_A,"$&/")+"/")+z1),i0!==""&&z0!=null&&C(z0)&&z0.key==null&&z0._store&&!z0._store.validated&&(dA._store.validated=2),T0=dA),FA.push(T0)),1}if(z0=0,z1=i0===""?".":i0+":",x0(fA))for(var v1=0;v1<fA.length;v1++)i0=fA[v1],H1=z1+r(i0,v1),z0+=O(i0,FA,dA,H1,T0);else if(v1=f(fA),typeof v1==="function")for(v1===fA.entries&&(jA||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),jA=!0),fA=v1.call(fA),v1=0;!(i0=fA.next()).done;)i0=i0.value,H1=z1+r(i0,v1++),z0+=O(i0,FA,dA,H1,T0);else if(H1==="object"){if(typeof fA.then==="function")return O(P(fA),FA,dA,i0,T0);throw FA=String(fA),Error("Objects are not valid as a React child (found: "+(FA==="[object Object]"?"object with keys {"+Object.keys(fA).join(", ")+"}":FA)+"). If you meant to render a collection of children, use an array instead.")}return z0}function R(fA,FA,dA){if(fA==null)return fA;var i0=[],T0=0;return O(fA,i0,"","",function(H1){return FA.call(dA,H1,T0++)}),i0}function g(fA){if(fA._status===-1){var FA=fA._ioInfo;FA!=null&&(FA.start=FA.end=performance.now()),FA=fA._result;var dA=FA();if(dA.then(function(T0){if(fA._status===0||fA._status===-1){fA._status=1,fA._result=T0;var H1=fA._ioInfo;H1!=null&&(H1.end=performance.now()),dA.status===void 0&&(dA.status="fulfilled",dA.value=T0)}},function(T0){if(fA._status===0||fA._status===-1){fA._status=2,fA._result=T0;var H1=fA._ioInfo;H1!=null&&(H1.end=performance.now()),dA.status===void 0&&(dA.status="rejected",dA.reason=T0)}}),FA=fA._ioInfo,FA!=null){FA.value=dA;var i0=dA.displayName;typeof i0==="string"&&(FA.name=i0)}fA._status===-1&&(fA._status=0,fA._result=dA)}if(fA._status===1)return FA=fA._result,FA===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
492
492
|
|
|
493
493
|
Your code should look like:
|
|
494
494
|
const MyComponent = lazy(() => import('./MyComponent'))
|
|
@@ -1847,7 +1847,7 @@ Example bad output: "A dreamlike crystal formation glowing with ethereal light i
|
|
|
1847
1847
|
Title: "${A.entityTitle??$}"
|
|
1848
1848
|
|
|
1849
1849
|
Content:
|
|
1850
|
-
${A.entityContent}`,ML1);c=w+q.imagePrompt}catch(q){this.logger.warn("AI prompt distillation failed, using fallback",{error:v0(q)})}}await this.reportProgress(Q,{progress:U2.PROCESS,message:"Generating image"});let D=this.context.identity.get(),u=this.context.identity.getProfile(),F=VeA(D,u)+c,Z;try{Z=await this.context.ai.generateImage(F,{...B&&{aspectRatio:B}})}catch(q){return this.logger.error("Image generation failed",{jobId:f,error:v0(q)}),GB.failure(q)}await this.reportProgress(Q,{progress:U2.GENERATE,message:"Creating image entity"});let J=w2($),v=gU.createImageEntity({dataUrl:Z.dataUrl,title:$});if(await this.context.entityService.getEntity("image",J))this.logger.debug("Deleting existing image for regeneration",{imageId:J}),await this.context.entityService.deleteEntity("image",J);if(await this.context.entityService.createEntity({...v,id:J}),this.logger.debug("Created image entity",{imageId:J}),x&&I){await this.reportProgress(Q,{progress:U2.SAVE,message:`Updating ${x} with cover image`});let q=await this.context.entityService.getEntity(x,I);if(!q)return GB.failure(Error(`Target entity not found: ${x}/${I}`));let V=dG(q,J);await this.context.entities.update(V),this.logger.debug("Updated target entity with cover image",{targetEntityType:x,targetEntityId:I,imageId:J})}return await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:f,imageId:J,targetEntityType:x,targetEntityId:I}),{success:!0,imageId:J}}catch(c){return this.logger.error("Image generation job failed",{jobId:f,error:v0(c)}),GB.failure(c)}}summarizeDataForLog(A){return{title:A.title,promptLength:A.prompt.length,aspectRatio:A.aspectRatio,targetEntityType:A.targetEntityType,targetEntityId:A.targetEntityId}}}var MeA={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.0",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 RL1=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 exA extends zf{entityType=gU.entityType;schema=Rq;adapter=gU;constructor(A={}){super("image",MeA,A,RL1)}getEntityTypeConfig(){return{embeddable:!1}}createGenerationHandler(A){return new sm(A,this.logger)}async onRegister(A){let f=new sm(A,this.logger);A.jobs.registerHandler("image-generate",f)}}function iq(A){return new exA(A)}B0();import{StdioServerTransport as PL1}from"@modelcontextprotocol/sdk/server/stdio.js";function OeA(){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 A7A(){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 tm(A){if(A&&typeof A==="object"&&"info"in A&&"debug"in A&&"error"in A&&"warn"in A){let f=A;return{info:(Q,...w)=>f.info(Q,...w),debug:(Q,...w)=>f.debug(Q,...w),error:(Q,...w)=>f.error(Q,...w),warn:(Q,...w)=>f.warn(Q,...w)}}return A7A()}class dI{static instance=null;mcpServer=null;transport=null;config;logger;static getInstance(A){return dI.instance??=new dI(A),dI.instance}static resetInstance(){if(dI.instance)dI.instance.stop(),dI.instance=null}static createFresh(A){return new dI(A)}constructor(A={}){this.config=A,this.logger=this.config.logger?tm(this.config.logger):OeA()}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 PL1,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 UIA=d0(UB0(),1),vB0=d0(ZB0(),1),mC=d0(GB0(),1);import{randomUUID as JB0}from"crypto";import{StreamableHTTPServerTransport as iT1}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as TT1}from"@modelcontextprotocol/sdk/types.js";class QY{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?tm(this.config.logger):A7A(),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=UIA.default(),this.setupMiddleware(),this.setupRoutes()}static getInstance(A){return QY.instance??=new QY(A),QY.instance}static resetInstance(){QY.instance=null}static createFresh(A){return new QY(A)}authMiddleware=(A,f,Q)=>{if(A.path==="/health"||A.path==="/status")return Q();if(this.authConfig.disabled||!this.authConfig.token)return Q();let w=A.headers.authorization;if(!w?.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(w.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}`),Q()};setupMiddleware(){this.app.use(UIA.default.json()),this.app.use(vB0.default()),this.app.use((A,f,Q)=>{this.logger.debug(`${A.method} ${A.path}`),Q()}),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",mC.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 Q=this.mcpServer;this.logger.debug(`POST /mcp - Session: ${A.headers["mcp-session-id"]??"new"}`);try{let w=A.headers["mcp-session-id"],B;if(w&&this.transports[w])B=this.transports[w];else if(!w&&TT1(A.body)){B=new iT1({sessionIdGenerator:()=>JB0(),onsessioninitialized:(I)=>{this.logger.info(`Session initialized: ${I}`),this.transports[I]=B},onsessionclosed:(I)=>{this.logger.info(`Session closed: ${I}`),delete this.transports[I]}}),await(this.mcpTransport?this.mcpTransport.createMcpServer():Q).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(w){if(this.logger.error("MCP transport error:",w),!f.headersSent)f.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}})}})),this.app.get("/mcp",mC.default(async(A,f)=>{let Q=A.headers["mcp-session-id"];if(!Q||!this.transports[Q]){f.status(400).send("Invalid or missing session ID");return}this.logger.debug(`GET /mcp - SSE stream for session ${Q}`),await this.transports[Q].handleRequest(A,f)})),this.app.delete("/mcp",mC.default(async(A,f)=>{let Q=A.headers["mcp-session-id"];if(!Q||!this.transports[Q]){f.status(400).send("Invalid or missing session ID");return}this.logger.info(`DELETE /mcp - Terminating session ${Q}`),await this.transports[Q].handleRequest(A,f)})),this.app.post("/api/chat",mC.default(async(A,f)=>{if(!this.agentService){f.status(503).json({error:"Agent service not connected"});return}let{message:Q,conversationId:w}=A.body;if(!Q||typeof Q!=="string"){f.status(400).json({error:"Missing or invalid 'message' field"});return}let B=w??JB0();this.logger.debug(`POST /api/chat - conversation: ${B}`);try{let x=await this.agentService.chat(Q,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((Q,w)=>{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`),Q()}).on("error",(B)=>{if(B.code==="EADDRINUSE")this.logger.error(`Port ${A} is already in use`);w(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}}HA();var HIA=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 kB0(A,f){return[]}B0();function KIA(A,f){A.messaging.subscribe("job-progress",async(Q)=>{let w=ZJ.safeParse(Q.payload);if(!w.success)return f.warn("Received invalid job-progress message",{error:w.error.message}),{success:!1};let B=w.data,x=B.type,I=B.status,$=B.id;if(f.debug(`${x} ${$} - ${I}:`,{id:B.id,message:B.message,progress:B.progress,metadata:B.metadata}),B.batchDetails)f.debug(`Batch details for ${$}:`,{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 ${$}:`,{jobType:B.jobDetails.jobType,priority:B.jobDetails.priority,retryCount:B.jobDetails.retryCount});return{success:!0}}),f.debug("Subscribed to job progress events")}var zB0={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.0",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 rU extends vc{mcpTransport;stdioServer;httpServer;domain;constructor(A={}){let f={...A,authToken:A.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",zB0,f,HIA)}async getTools(){return kB0(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`),KIA(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=dI.createFresh();let Q=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(Q),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=QY.createFresh({port:this.config.httpPort,logger:this.logger,auth:{token:this.config.authToken}});let Q=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(Q,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(){dI.resetInstance(),QY.resetInstance()}}B0();HA();var q4=d0(SL0(),1);HA();B0();var auA=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),...Lg.shape,captureUrlEmoji:X.string().default("\uD83D\uDD16")});var yL0={name:"@brains/discord",private:!0,version:"0.2.0-alpha.0",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 suA=2000,QH2=8000,wH2=100;function up(A){return!!A&&typeof A==="object"&&"send"in A&&"sendTyping"in A}class LH extends VI{client=null;fetchText;pendingConfirmations=new Map;typingIntervals=new Map;constructor(A,f={}){super("discord",yL0,A,auA);this.fetchText=f.fetchText??gP}async onRegister(A){await super.onRegister(A),this.client=new q4.Client({intents:[q4.GatewayIntentBits.Guilds,q4.GatewayIntentBits.GuildMessages,q4.GatewayIntentBits.MessageContent,q4.GatewayIntentBits.DirectMessages],partials:[q4.Partials.Channel]}),this.client.on(q4.Events.MessageCreate,(f)=>{this.handleMessage(f)}),this.client.once(q4.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 Q=this.client.channels.cache.get(A);if(!up(Q))return;let w=yh(f,suA);for(let B of w)Q.send(B).catch((x)=>this.logger.error("Failed to send message",{error:x}))}async sendMessageWithId(A,f){if(!A||!this.client)return;let Q=this.client.channels.cache.get(A);if(!up(Q))return;let w=yh(f,suA),B;for(let x of w)B=(await Q.send(x)).id;return B}async editMessage(A,f,Q){if(!A||!this.client)return!1;let w=this.client.channels.cache.get(A);if(!up(w))return!1;try{return await(await w.messages.fetch(f)).edit(Q.slice(0,suA)),!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,Q=A.channel.isThread();if(f&&!this.config.allowDMs)return;let w=!!this.client?.user&&A.mentions.has(this.client.user,{ignoreEveryone:!0});if(A.author.bot&&!w)return;let B=Q&&"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&&!w){if(this.config.captureUrls){let $=this.extractCaptureableUrls(A.content,this.config.blockedUrlDomains);if($.length>0){await A.react(this.config.captureUrlEmoji).catch((c)=>this.logger.debug("React failed",{error:c}));for(let c of $)await this.captureUrlViaAgent(c,A.channel.id,A.author.id,"discord").catch((D)=>this.logger.error("URL capture failed",{error:D,url:c}))}}return}let x=this.stripMention(A.content);if(A.attachments.size>0){let $=this.context.permissions.getUserLevel("discord",A.author.id);if($==="anchor"||$==="trusted")for(let D of A.attachments.values()){let u=D.name,K=D.contentType??void 0,F=D.size;if(!this.isUploadableTextFile(u,K))continue;if(!this.isFileSizeAllowed(F))continue;try{let Z=await this.fetchText(D.url);x+=`
|
|
1850
|
+
${A.entityContent}`,ML1);c=w+q.imagePrompt}catch(q){this.logger.warn("AI prompt distillation failed, using fallback",{error:v0(q)})}}await this.reportProgress(Q,{progress:U2.PROCESS,message:"Generating image"});let D=this.context.identity.get(),u=this.context.identity.getProfile(),F=VeA(D,u)+c,Z;try{Z=await this.context.ai.generateImage(F,{...B&&{aspectRatio:B}})}catch(q){return this.logger.error("Image generation failed",{jobId:f,error:v0(q)}),GB.failure(q)}await this.reportProgress(Q,{progress:U2.GENERATE,message:"Creating image entity"});let J=w2($),v=gU.createImageEntity({dataUrl:Z.dataUrl,title:$});if(await this.context.entityService.getEntity("image",J))this.logger.debug("Deleting existing image for regeneration",{imageId:J}),await this.context.entityService.deleteEntity("image",J);if(await this.context.entityService.createEntity({...v,id:J}),this.logger.debug("Created image entity",{imageId:J}),x&&I){await this.reportProgress(Q,{progress:U2.SAVE,message:`Updating ${x} with cover image`});let q=await this.context.entityService.getEntity(x,I);if(!q)return GB.failure(Error(`Target entity not found: ${x}/${I}`));let V=dG(q,J);await this.context.entities.update(V),this.logger.debug("Updated target entity with cover image",{targetEntityType:x,targetEntityId:I,imageId:J})}return await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:f,imageId:J,targetEntityType:x,targetEntityId:I}),{success:!0,imageId:J}}catch(c){return this.logger.error("Image generation job failed",{jobId:f,error:v0(c)}),GB.failure(c)}}summarizeDataForLog(A){return{title:A.title,promptLength:A.prompt.length,aspectRatio:A.aspectRatio,targetEntityType:A.targetEntityType,targetEntityId:A.targetEntityId}}}var MeA={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.1",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 RL1=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 exA extends zf{entityType=gU.entityType;schema=Rq;adapter=gU;constructor(A={}){super("image",MeA,A,RL1)}getEntityTypeConfig(){return{embeddable:!1}}createGenerationHandler(A){return new sm(A,this.logger)}async onRegister(A){let f=new sm(A,this.logger);A.jobs.registerHandler("image-generate",f)}}function iq(A){return new exA(A)}B0();import{StdioServerTransport as PL1}from"@modelcontextprotocol/sdk/server/stdio.js";function OeA(){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 A7A(){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 tm(A){if(A&&typeof A==="object"&&"info"in A&&"debug"in A&&"error"in A&&"warn"in A){let f=A;return{info:(Q,...w)=>f.info(Q,...w),debug:(Q,...w)=>f.debug(Q,...w),error:(Q,...w)=>f.error(Q,...w),warn:(Q,...w)=>f.warn(Q,...w)}}return A7A()}class dI{static instance=null;mcpServer=null;transport=null;config;logger;static getInstance(A){return dI.instance??=new dI(A),dI.instance}static resetInstance(){if(dI.instance)dI.instance.stop(),dI.instance=null}static createFresh(A){return new dI(A)}constructor(A={}){this.config=A,this.logger=this.config.logger?tm(this.config.logger):OeA()}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 PL1,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 UIA=d0(UB0(),1),vB0=d0(ZB0(),1),mC=d0(GB0(),1);import{randomUUID as JB0}from"crypto";import{StreamableHTTPServerTransport as iT1}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as TT1}from"@modelcontextprotocol/sdk/types.js";class QY{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?tm(this.config.logger):A7A(),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=UIA.default(),this.setupMiddleware(),this.setupRoutes()}static getInstance(A){return QY.instance??=new QY(A),QY.instance}static resetInstance(){QY.instance=null}static createFresh(A){return new QY(A)}authMiddleware=(A,f,Q)=>{if(A.path==="/health"||A.path==="/status")return Q();if(this.authConfig.disabled||!this.authConfig.token)return Q();let w=A.headers.authorization;if(!w?.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(w.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}`),Q()};setupMiddleware(){this.app.use(UIA.default.json()),this.app.use(vB0.default()),this.app.use((A,f,Q)=>{this.logger.debug(`${A.method} ${A.path}`),Q()}),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",mC.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 Q=this.mcpServer;this.logger.debug(`POST /mcp - Session: ${A.headers["mcp-session-id"]??"new"}`);try{let w=A.headers["mcp-session-id"],B;if(w&&this.transports[w])B=this.transports[w];else if(!w&&TT1(A.body)){B=new iT1({sessionIdGenerator:()=>JB0(),onsessioninitialized:(I)=>{this.logger.info(`Session initialized: ${I}`),this.transports[I]=B},onsessionclosed:(I)=>{this.logger.info(`Session closed: ${I}`),delete this.transports[I]}}),await(this.mcpTransport?this.mcpTransport.createMcpServer():Q).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(w){if(this.logger.error("MCP transport error:",w),!f.headersSent)f.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}})}})),this.app.get("/mcp",mC.default(async(A,f)=>{let Q=A.headers["mcp-session-id"];if(!Q||!this.transports[Q]){f.status(400).send("Invalid or missing session ID");return}this.logger.debug(`GET /mcp - SSE stream for session ${Q}`),await this.transports[Q].handleRequest(A,f)})),this.app.delete("/mcp",mC.default(async(A,f)=>{let Q=A.headers["mcp-session-id"];if(!Q||!this.transports[Q]){f.status(400).send("Invalid or missing session ID");return}this.logger.info(`DELETE /mcp - Terminating session ${Q}`),await this.transports[Q].handleRequest(A,f)})),this.app.post("/api/chat",mC.default(async(A,f)=>{if(!this.agentService){f.status(503).json({error:"Agent service not connected"});return}let{message:Q,conversationId:w}=A.body;if(!Q||typeof Q!=="string"){f.status(400).json({error:"Missing or invalid 'message' field"});return}let B=w??JB0();this.logger.debug(`POST /api/chat - conversation: ${B}`);try{let x=await this.agentService.chat(Q,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((Q,w)=>{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`),Q()}).on("error",(B)=>{if(B.code==="EADDRINUSE")this.logger.error(`Port ${A} is already in use`);w(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}}HA();var HIA=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 kB0(A,f){return[]}B0();function KIA(A,f){A.messaging.subscribe("job-progress",async(Q)=>{let w=ZJ.safeParse(Q.payload);if(!w.success)return f.warn("Received invalid job-progress message",{error:w.error.message}),{success:!1};let B=w.data,x=B.type,I=B.status,$=B.id;if(f.debug(`${x} ${$} - ${I}:`,{id:B.id,message:B.message,progress:B.progress,metadata:B.metadata}),B.batchDetails)f.debug(`Batch details for ${$}:`,{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 ${$}:`,{jobType:B.jobDetails.jobType,priority:B.jobDetails.priority,retryCount:B.jobDetails.retryCount});return{success:!0}}),f.debug("Subscribed to job progress events")}var zB0={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.1",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 rU extends vc{mcpTransport;stdioServer;httpServer;domain;constructor(A={}){let f={...A,authToken:A.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",zB0,f,HIA)}async getTools(){return kB0(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`),KIA(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=dI.createFresh();let Q=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(Q),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=QY.createFresh({port:this.config.httpPort,logger:this.logger,auth:{token:this.config.authToken}});let Q=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(Q,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(){dI.resetInstance(),QY.resetInstance()}}B0();HA();var q4=d0(SL0(),1);HA();B0();var auA=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),...Lg.shape,captureUrlEmoji:X.string().default("\uD83D\uDD16")});var yL0={name:"@brains/discord",private:!0,version:"0.2.0-alpha.1",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 suA=2000,QH2=8000,wH2=100;function up(A){return!!A&&typeof A==="object"&&"send"in A&&"sendTyping"in A}class LH extends VI{client=null;fetchText;pendingConfirmations=new Map;typingIntervals=new Map;constructor(A,f={}){super("discord",yL0,A,auA);this.fetchText=f.fetchText??gP}async onRegister(A){await super.onRegister(A),this.client=new q4.Client({intents:[q4.GatewayIntentBits.Guilds,q4.GatewayIntentBits.GuildMessages,q4.GatewayIntentBits.MessageContent,q4.GatewayIntentBits.DirectMessages],partials:[q4.Partials.Channel]}),this.client.on(q4.Events.MessageCreate,(f)=>{this.handleMessage(f)}),this.client.once(q4.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 Q=this.client.channels.cache.get(A);if(!up(Q))return;let w=yh(f,suA);for(let B of w)Q.send(B).catch((x)=>this.logger.error("Failed to send message",{error:x}))}async sendMessageWithId(A,f){if(!A||!this.client)return;let Q=this.client.channels.cache.get(A);if(!up(Q))return;let w=yh(f,suA),B;for(let x of w)B=(await Q.send(x)).id;return B}async editMessage(A,f,Q){if(!A||!this.client)return!1;let w=this.client.channels.cache.get(A);if(!up(w))return!1;try{return await(await w.messages.fetch(f)).edit(Q.slice(0,suA)),!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,Q=A.channel.isThread();if(f&&!this.config.allowDMs)return;let w=!!this.client?.user&&A.mentions.has(this.client.user,{ignoreEveryone:!0});if(A.author.bot&&!w)return;let B=Q&&"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&&!w){if(this.config.captureUrls){let $=this.extractCaptureableUrls(A.content,this.config.blockedUrlDomains);if($.length>0){await A.react(this.config.captureUrlEmoji).catch((c)=>this.logger.debug("React failed",{error:c}));for(let c of $)await this.captureUrlViaAgent(c,A.channel.id,A.author.id,"discord").catch((D)=>this.logger.error("URL capture failed",{error:D,url:c}))}}return}let x=this.stripMention(A.content);if(A.attachments.size>0){let $=this.context.permissions.getUserLevel("discord",A.author.id);if($==="anchor"||$==="trusted")for(let D of A.attachments.values()){let u=D.name,K=D.contentType??void 0,F=D.size;if(!this.isUploadableTextFile(u,K))continue;if(!this.isFileSizeAllowed(F))continue;try{let Z=await this.fetchText(D.url);x+=`
|
|
1851
1851
|
|
|
1852
1852
|
`+this.formatFileUploadMessage(u,Z)}catch(Z){this.logger.error("Failed to download attachment",{error:Z,filename:u})}}}if(x=x.trim(),!x)return;let I=A.channel.id;await this.routeToAgent(x,I,A)}async routeToAgent(A,f,Q){if(!this.context)return;let w=this.context.agentService,B=f;if(this.config.useThreads&&Q.guild&&!Q.channel.isThread())try{B=(await Q.startThread({name:IU(A,wH2),autoArchiveDuration:this.config.threadAutoArchive})).id}catch(c){this.logger.error("Failed to create thread",{error:c})}let x=`discord-${B}`,I=this.context.permissions.getUserLevel("discord",Q.author.id),$=Q.guild?.name??"DM";this.startProcessingInput(B);try{let c=this.client?.channels.cache.get(B);if(up(c))this.startTypingIndicator(c);if(this.pendingConfirmations.has(x)){await this.handleConfirmationResponse(A,x,B);return}let D=await w.chat(A,x,{userPermissionLevel:I,interfaceType:"discord",channelId:B,channelName:$});if(D.pendingConfirmation)this.pendingConfirmations.set(x,!0);let u=await this.sendMessageWithId(B,D.text);if(u&&D.toolResults){for(let K of D.toolResults)if(K.jobId)this.trackAgentResponseForJob(K.jobId,u,B)}}catch(c){this.logger.error("Error handling message",{error:c,channelId:B}),this.sendMessageToChannel(B,`**Error:** ${c instanceof Error?c.message:"Unknown error"}`)}finally{this.endProcessingInput(),this.stopTypingIndicator(B)}}async handleConfirmationResponse(A,f,Q){let w=kJ(A);if(!w){this.sendMessageToChannel(Q,"_Please reply with **yes** to confirm or **no/cancel** to abort._");return}this.pendingConfirmations.delete(f);let B=await this.context?.agentService.confirmPendingAction(f,w.confirmed);if(B)await this.sendMessageWithId(Q,B.text)}startTypingIndicator(A){if(!this.config.showTypingIndicator)return;A.sendTyping().catch((Q)=>this.logger.debug("Typing indicator failed",{error:Q}));let f=setInterval(()=>{A.sendTyping().catch((Q)=>this.logger.debug("Typing indicator failed",{error:Q}))},QH2);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 qz,join as yH2}from"path";var tuA=(A,f,Q)=>{return(w,B)=>{let x=-1;return I(0);async function I($){if($<=x)throw Error("next() called multiple times");x=$;let c,D=!1,u;if(A[$])u=A[$][0][0],w.req.routeIndex=$;else u=$===A.length&&B||void 0;if(u)try{c=await u(w,()=>I($+1))}catch(K){if(K instanceof Error&&f)w.error=K,c=await f(K,w),D=!0;else throw K}else if(w.finalized===!1&&Q)c=await Q(w);if(c&&(w.finalized===!1||D))w.res=c;return w}}};var lL0=Symbol();var nL0=async(A,f=Object.create(null))=>{let{all:Q=!1,dot:w=!1}=f,x=(A instanceof Up?A.raw.headers:A.headers).get("Content-Type");if(x?.startsWith("multipart/form-data")||x?.startsWith("application/x-www-form-urlencoded"))return BH2(A,{all:Q,dot:w});return{}};async function BH2(A,f){let Q=await A.formData();if(Q)return xH2(Q,f);return{}}function xH2(A,f){let Q=Object.create(null);if(A.forEach((w,B)=>{if(!(f.all||B.endsWith("[]")))Q[B]=w;else IH2(Q,B,w)}),f.dot)Object.entries(Q).forEach(([w,B])=>{if(w.includes("."))$H2(Q,w,B),delete Q[w]});return Q}var IH2=(A,f,Q)=>{if(A[f]!==void 0)if(Array.isArray(A[f]))A[f].push(Q);else A[f]=[A[f],Q];else if(!f.endsWith("[]"))A[f]=Q;else A[f]=[Q]},$H2=(A,f,Q)=>{let w=A,B=f.split(".");B.forEach((x,I)=>{if(I===B.length-1)w[x]=Q;else{if(!w[x]||typeof w[x]!=="object"||Array.isArray(w[x])||w[x]instanceof File)w[x]=Object.create(null);w=w[x]}})};var AUA=(A)=>{let f=A.split("/");if(f[0]==="")f.shift();return f},pL0=(A)=>{let{groups:f,path:Q}=cH2(A),w=AUA(Q);return DH2(w,f)},cH2=(A)=>{let f=[];return A=A.replace(/\{[^}]+\}/g,(Q,w)=>{let B=`@${w}`;return f.push([B,Q]),B}),{groups:f,path:A}},DH2=(A,f)=>{for(let Q=f.length-1;Q>=0;Q--){let[w]=f[Q];for(let B=A.length-1;B>=0;B--)if(A[B].includes(w)){A[B]=A[B].replace(w,f[Q][1]);break}}return A},Hp={},rL0=(A,f)=>{if(A==="*")return"*";let Q=A.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);if(Q){let w=`${A}#${f}`;if(!Hp[w])if(Q[2])Hp[w]=f&&f[0]!==":"&&f[0]!=="*"?[w,Q[1],new RegExp(`^${Q[2]}(?=/${f})`)]:[A,Q[1],new RegExp(`^${Q[2]}$`)];else Hp[w]=[A,Q[1],!0];return Hp[w]}return null},Kp=(A,f)=>{try{return f(A)}catch{return A.replace(/(?:%[0-9A-Fa-f]{2})+/g,(Q)=>{try{return f(Q)}catch{return Q}})}},fUA=(A)=>Kp(A,decodeURI),QUA=(A)=>{let f=A.url,Q=f.indexOf("/",f.indexOf(":")+4),w=Q;for(;w<f.length;w++){let B=f.charCodeAt(w);if(B===37){let x=f.indexOf("?",w),I=f.indexOf("#",w),$=x===-1?I===-1?void 0:I:I===-1?x:Math.min(x,I),c=f.slice(Q,$);return fUA(c.includes("%25")?c.replace(/%25/g,"%2525"):c)}else if(B===63||B===35)break}return f.slice(Q,w)};var dL0=(A)=>{let f=QUA(A);return f.length>1&&f.at(-1)==="/"?f.slice(0,-1):f},zZ=(A,f,...Q)=>{if(Q.length)f=zZ(f,...Q);return`${A?.[0]==="/"?"":"/"}${A}${f==="/"?"":`${A?.at(-1)==="/"?"":"/"}${f?.[0]==="/"?f.slice(1):f}`}`},Fp=(A)=>{if(A.charCodeAt(A.length-1)!==63||!A.includes(":"))return null;let f=A.split("/"),Q=[],w="";return f.forEach((B)=>{if(B!==""&&!/\:/.test(B))w+="/"+B;else if(/\:/.test(B))if(/\?/.test(B)){if(Q.length===0&&w==="")Q.push("/");else Q.push(w);let x=B.replace("?","");w+="/"+x,Q.push(w)}else w+="/"+B}),Q.filter((B,x,I)=>I.indexOf(B)===x)},euA=(A)=>{if(!/[%+]/.test(A))return A;if(A.indexOf("+")!==-1)A=A.replace(/\+/g," ");return A.indexOf("%")!==-1?Kp(A,wUA):A},oL0=(A,f,Q)=>{let w;if(!Q&&f&&!/[%+]/.test(f)){let I=A.indexOf("?",8);if(I===-1)return;if(!A.startsWith(f,I+1))I=A.indexOf(`&${f}`,I+1);while(I!==-1){let $=A.charCodeAt(I+f.length+1);if($===61){let c=I+f.length+2,D=A.indexOf("&",c);return euA(A.slice(c,D===-1?void 0:D))}else if($==38||isNaN($))return"";I=A.indexOf(`&${f}`,I+1)}if(w=/[%+]/.test(A),!w)return}let B={};w??=/[%+]/.test(A);let x=A.indexOf("?",8);while(x!==-1){let I=A.indexOf("&",x+1),$=A.indexOf("=",x);if($>I&&I!==-1)$=-1;let c=A.slice(x+1,$===-1?I===-1?void 0:I:$);if(w)c=euA(c);if(x=I,c==="")continue;let D;if($===-1)D="";else if(D=A.slice($+1,I===-1?void 0:I),w)D=euA(D);if(Q){if(!(B[c]&&Array.isArray(B[c])))B[c]=[];B[c].push(D)}else B[c]??=D}return f?B[f]:B},aL0=oL0,sL0=(A,f)=>{return oL0(A,f,!0)},wUA=decodeURIComponent;var tL0=(A)=>Kp(A,wUA),Up=class{raw;#A;#f;routeIndex=0;path;bodyCache={};constructor(A,f="/",Q=[[]]){this.raw=A,this.path=f,this.#f=Q,this.#A={}}param(A){return A?this.#Q(A):this.#x()}#Q(A){let f=this.#f[0][this.routeIndex][1][A],Q=this.#B(f);return Q&&/\%/.test(Q)?tL0(Q):Q}#x(){let A={},f=Object.keys(this.#f[0][this.routeIndex][1]);for(let Q of f){let w=this.#B(this.#f[0][this.routeIndex][1][Q]);if(w!==void 0)A[Q]=/\%/.test(w)?tL0(w):w}return A}#B(A){return this.#f[1]?this.#f[1][A]:A}query(A){return aL0(this.url,A)}queries(A){return sL0(this.url,A)}header(A){if(A)return this.raw.headers.get(A)??void 0;let f={};return this.raw.headers.forEach((Q,w)=>{f[w]=Q}),f}async parseBody(A){return this.bodyCache.parsedBody??=await nL0(this,A)}#w=(A)=>{let{bodyCache:f,raw:Q}=this,w=f[A];if(w)return w;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]=Q[A]()};json(){return this.#w("text").then((A)=>JSON.parse(A))}text(){return this.#w("text")}arrayBuffer(){return this.#w("arrayBuffer")}blob(){return this.#w("blob")}formData(){return this.#w("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[lL0](){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 eL0={Stringify:1,BeforeStream:2,Stream:3},Aq0=(A,f)=>{let Q=new String(A);return Q.isEscaped=!0,Q.callbacks=f,Q};var BUA=async(A,f,Q,w,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 I=Promise.all(x.map(($)=>$({phase:f,buffer:B,context:w}))).then(($)=>Promise.all($.filter(Boolean).map((c)=>BUA(c,f,!1,w,B))).then(()=>B[0]));if(Q)return Aq0(await I,x);else return I};var YH2="text/plain; charset=UTF-8",xUA=(A,f)=>{return{"Content-Type":A,...f}},EV=(A,f)=>new Response(A,f),fq0=class{#A;#f;env={};#Q;finalized=!1;error;#x;#B;#w;#Y;#c;#D;#$;#u;#U;constructor(A,f){if(this.#A=A,f)this.#B=f.executionCtx,this.env=f.env,this.#D=f.notFoundHandler,this.#U=f.path,this.#u=f.matchResult}get req(){return this.#f??=new Up(this.#A,this.#U,this.#u),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.#w||=EV(null,{headers:this.#$??=new Headers})}set res(A){if(this.#w&&A){A=EV(A.body,A);for(let[f,Q]of this.#w.headers.entries()){if(f==="content-type")continue;if(f==="set-cookie"){let w=this.#w.headers.getSetCookie();A.headers.delete("set-cookie");for(let B of w)A.headers.append("set-cookie",B)}else A.headers.set(f,Q)}}this.#w=A,this.finalized=!0}render=(...A)=>{return this.#c??=(f)=>this.html(f),this.#c(...A)};setLayout=(A)=>this.#Y=A;getLayout=()=>this.#Y;setRenderer=(A)=>{this.#c=A};header=(A,f,Q)=>{if(this.finalized)this.#w=EV(this.#w.body,this.#w);let w=this.#w?this.#w.headers:this.#$??=new Headers;if(f===void 0)w.delete(A);else if(Q?.append)w.append(A,f);else w.set(A,f)};status=(A)=>{this.#x=A};set=(A,f)=>{this.#Q??=new Map,this.#Q.set(A,f)};get=(A)=>{return this.#Q?this.#Q.get(A):void 0};get var(){if(!this.#Q)return{};return Object.fromEntries(this.#Q)}#I(A,f,Q){let w=this.#w?new Headers(this.#w.headers):this.#$??new Headers;if(typeof f==="object"&&"headers"in f){let x=f.headers instanceof Headers?f.headers:new Headers(f.headers);for(let[I,$]of x)if(I.toLowerCase()==="set-cookie")w.append(I,$);else w.set(I,$)}if(Q)for(let[x,I]of Object.entries(Q))if(typeof I==="string")w.set(x,I);else{w.delete(x);for(let $ of I)w.append(x,$)}let B=typeof f==="number"?f:f?.status??this.#x;return EV(A,{status:B,headers:w})}newResponse=(...A)=>this.#I(...A);body=(A,f,Q)=>this.#I(A,f,Q);text=(A,f,Q)=>{return!this.#$&&!this.#x&&!f&&!Q&&!this.finalized?new Response(A):this.#I(A,f,xUA(YH2,Q))};json=(A,f,Q)=>{return this.#I(JSON.stringify(A),f,xUA("application/json",Q))};html=(A,f,Q)=>{let w=(B)=>this.#I(B,f,xUA("text/html; charset=UTF-8",Q));return typeof A==="object"?BUA(A,eL0.Stringify,!1,{}).then(w):w(A)};redirect=(A,f)=>{let Q=String(A);return this.header("Location",!/[^\x00-\xFF]/.test(Q)?Q:encodeURI(Q)),this.newResponse(null,f??302)};notFound=()=>{return this.#D??=()=>EV(),this.#D(this)}};var rQ="ALL",Qq0="all",wq0=["get","post","put","delete","options","patch"],Xp="Can not add a route since the matcher is already built.",Zp=class extends Error{};var IUA="__COMPOSED_HANDLER";var uH2=(A)=>{return A.text("404 Not Found",404)},Bq0=(A,f)=>{if("getResponse"in A){let Q=A.getResponse();return f.newResponse(Q.body,Q)}return console.error(A),f.text("Internal Server Error",500)},xq0=class A{get;post;put;delete;options;patch;all;on;use;router;getPath;_basePath="/";#A="/";routes=[];constructor(f={}){[...wq0,Qq0].forEach((x)=>{this[x]=(I,...$)=>{if(typeof I==="string")this.#A=I;else this.#x(x,this.#A,I);return $.forEach((c)=>{this.#x(x,this.#A,c)}),this}}),this.on=(x,I,...$)=>{for(let c of[I].flat()){this.#A=c;for(let D of[x].flat())$.map((u)=>{this.#x(D.toUpperCase(),this.#A,u)})}return this},this.use=(x,...I)=>{if(typeof x==="string")this.#A=x;else this.#A="*",I.unshift(x);return I.forEach(($)=>{this.#x(rQ,this.#A,$)}),this};let{strict:w,...B}=f;Object.assign(this,B),this.getPath=w??!0?f.getPath??QUA:dL0}#f(){let f=new A({router:this.router,getPath:this.getPath});return f.errorHandler=this.errorHandler,f.#Q=this.#Q,f.routes=this.routes,f}#Q=uH2;errorHandler=Bq0;route(f,Q){let w=this.basePath(f);return Q.routes.map((B)=>{let x;if(Q.errorHandler===Bq0)x=B.handler;else x=async(I,$)=>(await tuA([],Q.errorHandler)(I,()=>B.handler(I,$))).res,x[IUA]=B.handler;w.#x(B.method,B.path,x)}),this}basePath(f){let Q=this.#f();return Q._basePath=zZ(this._basePath,f),Q}onError=(f)=>{return this.errorHandler=f,this};notFound=(f)=>{return this.#Q=f,this};mount(f,Q,w){let B,x;if(w)if(typeof w==="function")x=w;else if(x=w.optionHandler,w.replaceRequest===!1)B=(c)=>c;else B=w.replaceRequest;let I=x?(c)=>{let D=x(c);return Array.isArray(D)?D:[D]}:(c)=>{let D=void 0;try{D=c.executionCtx}catch{}return[c.env,D]};B||=(()=>{let c=zZ(this._basePath,f),D=c==="/"?0:c.length;return(u)=>{let K=new URL(u.url);return K.pathname=K.pathname.slice(D)||"/",new Request(K,u)}})();let $=async(c,D)=>{let u=await Q(B(c.req.raw),...I(c));if(u)return u;await D()};return this.#x(rQ,zZ(f,"*"),$),this}#x(f,Q,w){f=f.toUpperCase(),Q=zZ(this._basePath,Q);let B={basePath:this._basePath,path:Q,method:f,handler:w};this.router.add(f,Q,[w,B]),this.routes.push(B)}#B(f,Q){if(f instanceof Error)return this.errorHandler(f,Q);throw f}#w(f,Q,w,B){if(B==="HEAD")return(async()=>new Response(null,await this.#w(f,Q,w,"GET")))();let x=this.getPath(f,{env:w}),I=this.router.match(B,x),$=new fq0(f,{path:x,matchResult:I,env:w,executionCtx:Q,notFoundHandler:this.#Q});if(I[0].length===1){let D;try{D=I[0][0][0][0]($,async()=>{$.res=await this.#Q($)})}catch(u){return this.#B(u,$)}return D instanceof Promise?D.then((u)=>u||($.finalized?$.res:this.#Q($))).catch((u)=>this.#B(u,$)):D??this.#Q($)}let c=tuA(I[0],this.errorHandler,this.#Q);return(async()=>{try{let D=await c($);if(!D.finalized)throw Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");return D.res}catch(D){return this.#B(D,$)}})()}fetch=(f,...Q)=>{return this.#w(f,Q[1],Q[0],f.method)};request=(f,Q,w,B)=>{if(f instanceof Request)return this.fetch(Q?new Request(f,Q):f,w,B);return f=f.toString(),this.fetch(new Request(/^https?:\/\//.test(f)?f:`http://localhost${zZ("/",f)}`,Q),w,B)};fire=()=>{addEventListener("fetch",(f)=>{f.respondWith(this.#w(f.request,f,void 0,f.request.method))})}};var hV=[];function Wp(A,f){let Q=this.buildAllMatchers(),w=(B,x)=>{let I=Q[B]||Q[rQ],$=I[2][x];if($)return $;let c=x.match(I[0]);if(!c)return[[],hV];let D=c.indexOf("",1);return[I[1][D],c]};return this.match=w,w(A,f)}var Gp="[^/]+",bV=".*",LV="(?:|/.*)",NZ=Symbol(),UH2=new Set(".\\+*[^]$()");function HH2(A,f){if(A.length===1)return f.length===1?A<f?-1:1:-1;if(f.length===1)return 1;if(A===bV||A===LV)return 1;else if(f===bV||f===LV)return-1;if(A===Gp)return 1;else if(f===Gp)return-1;return A.length===f.length?A<f?-1:1:f.length-A.length}var Iq0=class A{#A;#f;#Q=Object.create(null);insert(f,Q,w,B,x){if(f.length===0){if(this.#A!==void 0)throw NZ;if(x)return;this.#A=Q;return}let[I,...$]=f,c=I==="*"?$.length===0?["","",bV]:["","",Gp]:I==="/*"?["","",LV]:I.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/),D;if(c){let u=c[1],K=c[2]||Gp;if(u&&c[2]){if(K===".*")throw NZ;if(K=K.replace(/^\((?!\?:)(?=[^)]+\)$)/,"(?:"),/\((?!\?:)/.test(K))throw NZ}if(D=this.#Q[K],!D){if(Object.keys(this.#Q).some((F)=>F!==bV&&F!==LV))throw NZ;if(x)return;if(D=this.#Q[K]=new A,u!=="")D.#f=B.varIndex++}if(!x&&u!=="")w.push([u,D.#f])}else if(D=this.#Q[I],!D){if(Object.keys(this.#Q).some((u)=>u.length>1&&u!==bV&&u!==LV))throw NZ;if(x)return;D=this.#Q[I]=new A}D.insert($,Q,w,B,x)}buildRegExpStr(){let Q=Object.keys(this.#Q).sort(HH2).map((w)=>{let B=this.#Q[w];return(typeof B.#f==="number"?`(${w})@${B.#f}`:UH2.has(w)?`\\${w}`:w)+B.buildRegExpStr()});if(typeof this.#A==="number")Q.unshift(`#${this.#A}`);if(Q.length===0)return"";if(Q.length===1)return Q[0];return"(?:"+Q.join("|")+")"}};var $q0=class{#A={varIndex:0};#f=new Iq0;insert(A,f,Q){let w=[],B=[];for(let I=0;;){let $=!1;if(A=A.replace(/\{[^}]+\}/g,(c)=>{let D=`@\\${I}`;return B[I]=[D,c],I++,$=!0,D}),!$)break}let x=A.match(/(?::[^\/]+)|(?:\/\*$)|./g)||[];for(let I=B.length-1;I>=0;I--){let[$]=B[I];for(let c=x.length-1;c>=0;c--)if(x[c].indexOf($)!==-1){x[c]=x[c].replace($,B[I][1]);break}}return this.#f.insert(x,f,w,this.#A,Q),w}buildRegExp(){let A=this.#f.buildRegExpStr();if(A==="")return[/^$/,[],[]];let f=0,Q=[],w=[];return A=A.replace(/#(\d+)|@(\d+)|\.\*\$/g,(B,x,I)=>{if(x!==void 0)return Q[++f]=Number(x),"$()";if(I!==void 0)return w[Number(I)]=++f,"";return""}),[new RegExp(`^${A}`),Q,w]}};var KH2=[/^$/,[],Object.create(null)],cq0=Object.create(null);function Dq0(A){return cq0[A]??=new RegExp(A==="*"?"":`^${A.replace(/\/\*$|([.\\+*[^\]$()])/g,(f,Q)=>Q?`\\${Q}`:"(?:|/.*)")}$`)}function FH2(){cq0=Object.create(null)}function XH2(A){let f=new $q0,Q=[];if(A.length===0)return KH2;let w=A.map((D)=>[!/\*|\/:/.test(D[0]),...D]).sort(([D,u],[K,F])=>D?1:K?-1:u.length-F.length),B=Object.create(null);for(let D=0,u=-1,K=w.length;D<K;D++){let[F,Z,J]=w[D];if(F)B[Z]=[J.map(([k])=>[k,Object.create(null)]),hV];else u++;let v;try{v=f.insert(Z,u,F)}catch(k){throw k===NZ?new Zp(Z):k}if(F)continue;Q[u]=J.map(([k,q])=>{let V=Object.create(null);q-=1;for(;q>=0;q--){let[C,l]=v[q];V[C]=l}return[k,V]})}let[x,I,$]=f.buildRegExp();for(let D=0,u=Q.length;D<u;D++)for(let K=0,F=Q[D].length;K<F;K++){let Z=Q[D][K]?.[1];if(!Z)continue;let J=Object.keys(Z);for(let v=0,k=J.length;v<k;v++)Z[J[v]]=$[Z[J[v]]]}let c=[];for(let D in I)c[D]=Q[I[D]];return[x,c,B]}function bz(A,f){if(!A)return;for(let Q of Object.keys(A).sort((w,B)=>B.length-w.length))if(Dq0(Q).test(f))return[...A[Q]];return}var Jp=class{name="RegExpRouter";#A;#f;constructor(){this.#A={[rQ]:Object.create(null)},this.#f={[rQ]:Object.create(null)}}add(A,f,Q){let w=this.#A,B=this.#f;if(!w||!B)throw Error(Xp);if(!w[A])[w,B].forEach(($)=>{$[A]=Object.create(null),Object.keys($[rQ]).forEach((c)=>{$[A][c]=[...$[rQ][c]]})});if(f==="/*")f="*";let x=(f.match(/\/:/g)||[]).length;if(/\*$/.test(f)){let $=Dq0(f);if(A===rQ)Object.keys(w).forEach((c)=>{w[c][f]||=bz(w[c],f)||bz(w[rQ],f)||[]});else w[A][f]||=bz(w[A],f)||bz(w[rQ],f)||[];Object.keys(w).forEach((c)=>{if(A===rQ||A===c)Object.keys(w[c]).forEach((D)=>{$.test(D)&&w[c][D].push([Q,x])})}),Object.keys(B).forEach((c)=>{if(A===rQ||A===c)Object.keys(B[c]).forEach((D)=>$.test(D)&&B[c][D].push([Q,x]))});return}let I=Fp(f)||[f];for(let $=0,c=I.length;$<c;$++){let D=I[$];Object.keys(B).forEach((u)=>{if(A===rQ||A===u)B[u][D]||=[...bz(w[u],D)||bz(w[rQ],D)||[]],B[u][D].push([Q,x-c+$+1])})}}match=Wp;buildAllMatchers(){let A=Object.create(null);return Object.keys(this.#f).concat(Object.keys(this.#A)).forEach((f)=>{A[f]||=this.#Q(f)}),this.#A=this.#f=void 0,FH2(),A}#Q(A){let f=[],Q=A===rQ;if([this.#A,this.#f].forEach((w)=>{let B=w[A]?Object.keys(w[A]).map((x)=>[x,w[A][x]]):[];if(B.length!==0)Q||=!0,f.push(...B);else if(A!==rQ)f.push(...Object.keys(w[rQ]).map((x)=>[x,w[rQ][x]]))}),!Q)return null;else return XH2(f)}};var ZH2=class{name="PreparedRegExpRouter";#A;#f;constructor(A,f){this.#A=A,this.#f=f}#Q(A,f){let Q=this.#A[A];Q[1].forEach((w)=>w&&w.push(f)),Object.values(Q[2]).forEach((w)=>w[0].push(f))}#x(A,f,Q,w,B){let x=this.#A[A];if(!B)x[2][f][0].push([Q,{}]);else w.forEach((I)=>{if(typeof I==="number")x[1][I].push([Q,B]);else x[2][I||f][0].push([Q,B])})}add(A,f,Q){if(!this.#A[A]){let B=this.#A[rQ],x={};for(let I in B[2])x[I]=[B[2][I][0].slice(),hV];this.#A[A]=[B[0],B[1].map((I)=>Array.isArray(I)?I.slice():0),x]}if(f==="/*"||f==="*"){let B=[Q,{}];if(A===rQ)for(let x in this.#A)this.#Q(x,B);else this.#Q(A,B);return}let w=this.#f[f];if(!w)throw Error(`Path ${f} is not registered`);for(let[B,x]of w)if(A===rQ)for(let I in this.#A)this.#x(I,f,Q,B,x);else this.#x(A,f,Q,B,x)}buildAllMatchers(){return this.#A}match=Wp};var $UA=class{name="SmartRouter";#A=[];#f=[];constructor(A){this.#A=A.routers}add(A,f,Q){if(!this.#f)throw Error(Xp);this.#f.push([A,f,Q])}match(A,f){if(!this.#f)throw Error("Fatal error");let Q=this.#A,w=this.#f,B=Q.length,x=0,I;for(;x<B;x++){let $=Q[x];try{for(let c=0,D=w.length;c<D;c++)$.add(...w[c]);I=$.match(A,f)}catch(c){if(c instanceof Zp)continue;throw c}this.match=$.match.bind($),this.#A=[$],this.#f=void 0;break}if(x===B)throw Error("Fatal error");return this.name=`SmartRouter + ${this.activeRouter.name}`,I}get activeRouter(){if(this.#f||this.#A.length!==1)throw Error("No active router has been determined yet.");return this.#A[0]}};var qV=Object.create(null),WH2=(A)=>{for(let f in A)return!0;return!1},Yq0=class A{#A;#f;#Q;#x=0;#B=qV;constructor(f,Q,w){if(this.#f=w||Object.create(null),this.#A=[],f&&Q){let B=Object.create(null);B[f]={handler:Q,possibleKeys:[],score:0},this.#A=[B]}this.#Q=[]}insert(f,Q,w){this.#x=++this.#x;let B=this,x=pL0(Q),I=[];for(let $=0,c=x.length;$<c;$++){let D=x[$],u=x[$+1],K=rL0(D,u),F=Array.isArray(K)?K[0]:D;if(F in B.#f){if(B=B.#f[F],K)I.push(K[1]);continue}if(B.#f[F]=new A,K)B.#Q.push(K),I.push(K[1]);B=B.#f[F]}return B.#A.push({[f]:{handler:w,possibleKeys:I.filter(($,c,D)=>D.indexOf($)===c),score:this.#x}}),B}#w(f,Q,w,B,x){for(let I=0,$=Q.#A.length;I<$;I++){let c=Q.#A[I],D=c[w]||c[rQ],u={};if(D!==void 0){if(D.params=Object.create(null),f.push(D),B!==qV||x&&x!==qV)for(let K=0,F=D.possibleKeys.length;K<F;K++){let Z=D.possibleKeys[K],J=u[D.score];D.params[Z]=x?.[Z]&&!J?x[Z]:B[Z]??x?.[Z],u[D.score]=!0}}}}search(f,Q){let w=[];this.#B=qV;let x=[this],I=AUA(Q),$=[],c=I.length,D=null;for(let u=0;u<c;u++){let K=I[u],F=u===c-1,Z=[];for(let v=0,k=x.length;v<k;v++){let q=x[v],V=q.#f[K];if(V)if(V.#B=q.#B,F){if(V.#f["*"])this.#w(w,V.#f["*"],f,q.#B);this.#w(w,V,f,q.#B)}else Z.push(V);for(let C=0,l=q.#Q.length;C<l;C++){let r=q.#Q[C],P=q.#B===qV?{}:{...q.#B};if(r==="*"){let S=q.#f["*"];if(S)this.#w(w,S,f,q.#B),S.#B=P,Z.push(S);continue}let[O,R,g]=r;if(!K&&!(g instanceof RegExp))continue;let t=q.#f[O];if(g instanceof RegExp){if(D===null){D=Array(c);let IA=Q[0]==="/"?1:0;for(let _=0;_<c;_++)D[_]=IA,IA+=I[_].length+1}let S=Q.substring(D[u]),YA=g.exec(S);if(YA){if(P[R]=YA[0],this.#w(w,t,f,q.#B,P),WH2(t.#f)){t.#B=P;let IA=YA[0].match(/\//)?.length??0;($[IA]||=[]).push(t)}continue}}if(g===!0||g.test(K))if(P[R]=K,F){if(this.#w(w,t,f,P,q.#B),t.#f["*"])this.#w(w,t.#f["*"],f,P,q.#B)}else t.#B=P,Z.push(t)}}let J=$.shift();x=J?Z.concat(J):Z}if(w.length>1)w.sort((u,K)=>{return u.score-K.score});return[w.map(({handler:u,params:K})=>[u,K])]}};var cUA=class{name="TrieRouter";#A;constructor(){this.#A=new Yq0}add(A,f,Q){let w=Fp(f);if(w){for(let B=0,x=w.length;B<x;B++)this.#A.insert(A,w[B],Q);return}this.#A.insert(A,f,Q)}match(A,f){return this.#A.search(A,f)}};var EZ=class extends xq0{constructor(A={}){super(A);this.router=A.router??new $UA({routers:[new Jp,new cUA]})}};import{stat as zH2}from"fs/promises";import{join as NH2}from"path";var Lz=/^\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 DUA=(A,f=JH2)=>{let Q=/\.([a-zA-Z0-9]+?)$/,w=A.match(Q);if(!w)return;let B=f[w[1]];if(B&&B.startsWith("text"))B+="; charset=utf-8";return B};var GH2={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"},JH2=GH2;var uq0=(...A)=>{let f=A.filter((B)=>B!=="").join("/");f=f.replace(/(?<=\/)\/+/g,"");let Q=f.split("/"),w=[];for(let B of Q)if(B===".."&&w.length>0&&w.at(-1)!=="..")w.pop();else if(B!==".")w.push(B);return w.join("/")||"."};var Uq0={br:".br",zstd:".zst",gzip:".gz"},vH2=Object.keys(Uq0),kH2="index.html",Hq0=(A)=>{let f=A.root??"./",Q=A.path,w=A.join??uq0;return async(B,x)=>{if(B.finalized)return x();let I;if(A.path)I=A.path;else try{if(I=fUA(B.req.path),/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(I))throw Error()}catch{return await A.onNotFound?.(B.req.path,B),x()}let $=w(f,!Q&&A.rewriteRequestPath?A.rewriteRequestPath(I):I);if(A.isDir&&await A.isDir($))$=w($,kH2);let c=A.getContent,D=await c($,B);if(D instanceof Response)return B.newResponse(D.body,D);if(D){let u=A.mimes&&DUA($,A.mimes)||DUA($);if(B.header("Content-Type",u||"application/octet-stream"),A.precompressed&&(!u||Lz.test(u))){let K=new Set(B.req.header("Accept-Encoding")?.split(",").map((F)=>F.trim()));for(let F of vH2){if(!K.has(F))continue;let Z=await c($+Uq0[F],B);if(Z){D=Z,B.header("Content-Encoding",F),B.header("Vary","Accept-Encoding",{append:!0});break}}}return await A.onFound?.($,B),B.body(D)}await A.onNotFound?.($,B),await x();return}};var YUA=(A)=>{return async function(Q,w){return Hq0({...A,getContent:async(I)=>{let $=Bun.file(I);return await $.exists()?$:null},join:NH2,isDir:async(I)=>{let $;try{$=(await zH2(I)).isDirectory()}catch{}return $}})(Q,w)}};var uUA="x-hono-disable-ssg",cwQ=(()=>{try{return new Response("SSG is disabled",{status:404,headers:{[uUA]:"true"}})}catch{return null}})();var{write:ywQ}=Bun;var bH2=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 Kq0=(A)=>{return(...f)=>{if(typeof f[0]==="function"){let[Q,w]=f;return async function(x,I){let $=await Q(x),c=await A(x,$,w);if(c)return c;await I()}}else{let[Q,w,B]=f;return(async()=>{let x=await A(Q,w,B);if(!x)throw Error("Failed to upgrade WebSocket");return x})()}}};var vp=(A)=>("server"in A.env)?A.env.server:A.env;var LH2=Kq0((A,f)=>{let Q=vp(A);if(!Q)throw TypeError("env has to include the 2nd argument of fetch.");if(Q.upgrade(A.req.raw,{data:{events:f,url:new URL(A.req.url),protocol:A.req.url}}))return new Response(null);return});var qH2=["gzip","deflate"],CH2=/(?:^|,)\s*?no-transform\s*?(?:,|$)/i,Fq0=(A)=>{let f=A?.threshold??1024;return async function(w,B){await B();let x=w.res.headers.get("Content-Length");if(w.res.headers.has("Content-Encoding")||w.res.headers.has("Transfer-Encoding")||w.req.method==="HEAD"||x&&Number(x)<f||!_H2(w.res)||!VH2(w.res))return;let I=w.req.header("Accept-Encoding"),$=A?.encoding??qH2.find((D)=>I?.includes(D));if(!$||!w.res.body)return;let c=new CompressionStream($);w.res=new Response(w.res.body.pipeThrough(c),w.res),w.res.headers.delete("Content-Length"),w.res.headers.set("Content-Encoding",$)}},_H2=(A)=>{let f=A.headers.get("Content-Type");return f&&Lz.test(f)},VH2=(A)=>{let f=A.headers.get("Cache-Control");return!f||!CH2.test(f)};import{Readable as Xq0}from"stream";import{createDeflate as MH2,createGzip as OH2}from"zlib";var jH2=["gzip","deflate"],RH2=/(?:^|,)\s*?no-transform\s*?(?:,|$)/i,Zq0=(A)=>{if(typeof CompressionStream<"u")return Fq0(A);let f=A?.threshold??1024;return async function(w,B){await B();let x=w.res.headers.get("Content-Length");if(w.res.headers.has("Content-Encoding")||w.res.headers.has("Transfer-Encoding")||w.req.method==="HEAD"||x&&Number(x)<f||!PH2(w.res)||!gH2(w.res))return;let I=w.req.header("Accept-Encoding"),$=A?.encoding??jH2.find((c)=>I?.includes(c));if(!$||!w.res.body)return;try{let c=$==="gzip"?OH2():MH2(),D=w.res.body,K=Xq0.fromWeb(D).pipe(c),F=Xq0.toWeb(K);w.res=new Response(F,w.res),w.res.headers.delete("Content-Length"),w.res.headers.set("Content-Encoding",$)}catch(c){console.error("Compression error:",c)}}},PH2=(A)=>{let f=A.headers.get("Content-Type");return f&&Lz.test(f)},gH2=(A)=>{let f=A.headers.get("Cache-Control");return!f||!RH2.test(f)};var iH2=(A,f)=>{if(!A)return f;let Q=new Uint8Array(new ArrayBuffer(A.byteLength+f.byteLength));return Q.set(new Uint8Array(A),0),Q.set(f,A.byteLength),Q},Wq0=async(A,f)=>{if(!A)return null;let Q=void 0,w=A.getReader();for(;;){let{value:B,done:x}=await w.read();if(x)break;Q=await f(iH2(Q,B))}if(!Q)return null;return Array.prototype.map.call(new Uint8Array(Q),(B)=>B.toString(16).padStart(2,"0")).join("")};var TH2=["cache-control","content-location","date","etag","expires","vary"],Gq0=(A)=>A.replace(/^W\//,"");function mH2(A,f){return f!=null&&f.split(/,\s*/).some((Q)=>Gq0(Q)===Gq0(A))}function SH2(A){if(!A){if(crypto&&crypto.subtle)A=(f)=>crypto.subtle.digest({name:"SHA-1"},f)}return A}var Jq0=(A)=>{let f=A?.retainedHeaders??TH2,Q=A?.weak??!1,w=SH2(A?.generateDigest);return async function(x,I){let $=x.req.header("If-None-Match")??null;await I();let c=x.res,D=c.headers.get("ETag");if(!D){if(!w)return;let u=await Wq0(c.clone().body,w);if(u===null)return;D=Q?`W/"${u}"`:`"${u}"`}if(mH2(D,$))x.res=new Response(null,{status:304,statusText:"Not Modified",headers:{ETag:D}}),x.res.headers.forEach((u,K)=>{if(f.indexOf(K.toLowerCase())===-1)x.res.headers.delete(K)});else x.res.headers.set("ETag",D)}};B0();function UUA(A,f){return async(Q)=>{let w=Q.req.raw,B=w.headers.get("content-type")??"",x=w.headers.get("accept")?.includes("application/json"),I={};if(B.includes("application/json"))I=await w.json();else if(B.includes("form")){let Z=await w.formData();for(let[J,v]of Z.entries())I[J]=v}let $=`${A.pluginId}_${A.definition.tool}`,c=await f.send(`plugin:${A.pluginId}:tool:execute`,{toolName:$,args:I,interfaceType:"webserver",userId:"anonymous"},"webserver"),D=typeof c==="object"&&"data"in c?c.data:c,u=ah.safeParse(D),K=u.success?u.data:D,F=u.success&&u.data.success===!0;if(x)return Q.json(K,F?200:400);if(F&&A.definition.successRedirect)return Q.redirect(A.definition.successRedirect);if(!F&&A.definition.errorRedirect)return Q.redirect(A.definition.errorRedirect);return Q.json(K,F?200:400)}}class kp{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 EZ;for(let Q of this.routes){let w=UUA(Q,this.messageBus),B=Q.definition.method.toLowerCase();A[B](Q.fullPath,w),this.logger.debug(`Mounted API route: ${Q.definition.method} ${Q.fullPath} -> ${Q.pluginId}_${Q.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 vq0="public, max-age=31536000, immutable";class zp{logger;options;productionServer=null;previewServer=null;constructor(A){this.logger=A.logger,this.options={...A,productionDistDir:qz(process.cwd(),A.productionDistDir),sharedImagesDir:qz(process.cwd(),A.sharedImagesDir),...A.previewDistDir&&{previewDistDir:qz(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 Q=await this.serveImageFastPath(f);if(Q)return Q;return A.fetch(f)}})}catch(f){let Q=String(f);if(Q.includes("EADDRINUSE")||Q.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(Q)=>{let w=await this.serveImageFastPath(Q);if(w)return w;return f.fetch(Q)}}),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 EZ;if(A.healthEndpoint)f.get("/health",async(Q)=>{if(this.options.getHealthData){let w=await this.options.getHealthData();return Q.json({status:"healthy",...w},200)}return Q.json({status:"healthy"},200)});if(A.compress)f.use("/*",Zq0());return f.use("/*",Jq0()),f.use("/*",async(Q,w)=>{if(await w(),A.immutableExtensions.test(Q.req.path))Q.header("Cache-Control",vq0);else Q.header("Cache-Control",A.defaultCache)}),f.use("/*",this.createCleanUrlMiddleware(A.distDir)),f.use("/*",YUA({root:A.distDir})),f.notFound(async(Q)=>{let w=Bun.file(yH2(A.distDir,"404.html"));if(await w.exists())return Q.html(await w.text(),404);return Q.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 Q=f.pathname.slice(8),w=qz(this.options.sharedImagesDir,Q);if(!w.startsWith(this.options.sharedImagesDir))return null;let B=Bun.file(w);if(!await B.exists())return null;return new Response(B,{headers:{"Cache-Control":vq0}})}createCleanUrlMiddleware(A){return async(f,Q)=>{let w=f.req.path;if(w.includes(".")||w==="/"){await Q();return}let B=qz(A,`.${w}`,"index.html");if(!B.startsWith(A)){await Q();return}let x=Bun.file(B);if(await x.exists())return f.html(await x.text());let I=qz(A,`.${w}.html`);if(I.startsWith(A)){let $=Bun.file(I);if(await $.exists())return f.html(await $.text())}await Q()}}}import{existsSync as zq0}from"fs";import{join as Nq0}from"path";HA();var HUA=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 KUA=`<!DOCTYPE html>
|
|
1853
1853
|
<html lang="en">
|
|
@@ -1916,7 +1916,7 @@ ${A.entityContent}`,ML1);c=w+q.imagePrompt}catch(q){this.logger.warn("AI prompt
|
|
|
1916
1916
|
<p>Once built, this page will be replaced with your actual website.</p>
|
|
1917
1917
|
</div>
|
|
1918
1918
|
</body>
|
|
1919
|
-
</html>`;var kq0={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.
|
|
1919
|
+
</html>`;var kq0={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.1",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 qH extends vc{serverManager;apiServer;siteUrl;previewUrl;constructor(A={}){super("webserver",kq0,A,HUA)}async onRegister(A){this.siteUrl=A.siteUrl,this.previewUrl=A.previewUrl,this.serverManager=new zp({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 Q=A.apiRoutes.getMessageBus();this.apiServer=new kp({logger:A.logger,port:this.config.apiPort,routes:f,messageBus:Q}),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,Q=this.siteUrl??A?.productionUrl??`http://localhost:${this.config.productionPort}`,w=this.previewUrl??A?.previewUrl??`http://localhost:${this.config.previewPort}`,B=[];if(f){if(B.push(`Production: ${Q}`),A?.previewUrl)B.push(`Preview: ${w}`)}return{status:f?"healthy":"error",message:f?B.join(", "):"Webserver not running",lastCheck:new Date,details:{preview:!!A?.previewUrl,production:f,previewUrl:A?.previewUrl?w:void 0,productionUrl:f?Q:void 0}}}}}async handleProgressEvent(A,f){}async ensureDistDirectories(){let{mkdir:A,writeFile:f}=await import("fs/promises");if(this.config.previewDistDir&&!zq0(this.config.previewDistDir))await A(this.config.previewDistDir,{recursive:!0}),await f(Nq0(this.config.previewDistDir,"index.html"),KUA),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!zq0(this.config.productionDistDir))await A(this.config.productionDistDir,{recursive:!0}),await f(Nq0(this.config.productionDistDir,"index.html"),KUA),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}B0();HA();var Eq0=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 nH2(A,f){return`${A.name} is ${f.name}'s ${A.role}. Its purpose is: ${A.purpose}.`}function hq0(A){let{character:f,profile:Q,version:w,domain:B,organization:x,tools:I}=A,c=`${B?`https://${B}`:"http://localhost:3334"}/a2a`,D=A.skills&&A.skills.length>0?A.skills.map((F)=>({id:F.name.toLowerCase().replace(/\s+/g,"-"),name:F.name,description:F.description,tags:F.tags,examples:F.examples})):I.map((F)=>({id:F.name,name:F.name,description:F.description,tags:[],examples:[]})),u={name:Q.name};if(A.kind)u.kind=A.kind;if(Q.description)u.description=Q.description;if(x)u.organization=x;let K=[{uri:Cg,description:"Anchor (operator) identity for this brain",params:u}];return{name:f.name,description:nH2(f,Q),url:c,version:w,protocolVersion:"0.2.2",capabilities:{streaming:!0,pushNotifications:!1,extensions:K},skills:D,defaultInputModes:["text/plain"],defaultOutputModes:["text/plain"],...x&&{provider:{organization:x,url:c}},...A.authEnabled&&{securitySchemes:{bearerAuth:{type:"http",scheme:"bearer"}},security:[{bearerAuth:[]}]}}}B0();var FUA=new Set(["completed","failed","canceled","rejected"]);class XUA{tasks=new Map;ttlMs;processingTimeoutMs;constructor(A=3600000,f=300000){this.ttlMs=A,this.processingTimeoutMs=f}evictExpired(){let A=Date.now();for(let[f,Q]of this.tasks)if(FUA.has(Q.task.status.state)&&A-new Date(Q.updatedAt).getTime()>=this.ttlMs)this.tasks.delete(f)}createTask(A,f){this.evictExpired();let Q=crypto.randomUUID(),w=f??crypto.randomUUID(),B=new Date().toISOString(),x={kind:"message",messageId:crypto.randomUUID(),role:"user",parts:[{kind:"text",text:A}],contextId:w,taskId:Q},$={task:{id:Q,contextId:w,kind:"task",status:{state:"submitted",timestamp:B},history:[x]},conversationId:`a2a:${Q}`,createdAt:B,updatedAt:B};return this.tasks.set(Q,$),$}getTask(A){return this.tasks.get(A)}updateState(A,f,Q){let w=this.tasks.get(A);if(!w)return;let B=new Date().toISOString();if(w.task.status={state:f,timestamp:B},w.updatedAt=B,f==="working")w.workingStartedAt=B;if(Q){let x={kind:"message",messageId:crypto.randomUUID(),role:"agent",parts:[{kind:"text",text:Q}],contextId:w.task.contextId,taskId:A};w.task.status.message=x,w.task.history??=[],w.task.history.push(x)}return w}addArtifact(A,f,Q){let w=this.tasks.get(A);if(!w)return;return w.task.artifacts??=[],w.task.artifacts.push({artifactId:crypto.randomUUID(),name:f,parts:Q}),w.updatedAt=new Date().toISOString(),w}getTaskWithHistory(A,f){let Q=this.tasks.get(A);if(!Q)return;if(Q.task.status.state==="working"&&Q.workingStartedAt&&Date.now()-new Date(Q.workingStartedAt).getTime()>=this.processingTimeoutMs)this.updateState(A,"failed","Processing timed out");if(f===void 0||!Q.task.history)return Q.task;return{...Q.task,history:Q.task.history.slice(-f)}}deleteTask(A){return this.tasks.delete(A)}get size(){return this.tasks.size}}HA();var bq0=X.array(X.object({kind:X.string(),text:X.string().optional(),data:X.record(X.unknown()).optional()})),pH2=X.object({message:X.object({kind:X.literal("message").optional(),messageId:X.string().optional(),role:X.enum(["user","agent"]).optional(),parts:bq0,contextId:X.string().optional(),taskId:X.string().optional()}),configuration:X.object({historyLength:X.number().optional()}).optional()}),Lq0=X.object({id:X.string(),historyLength:X.number().optional()});function ZUA(A,f){return{jsonrpc:"2.0",id:A,result:f}}function xD(A,f,Q){return{jsonrpc:"2.0",id:A,error:{code:f,message:Q}}}var qq0=X.object({jsonrpc:X.string(),id:X.union([X.string(),X.number()]),method:X.string(),params:X.record(X.unknown()).optional()});async function Cq0(A,f){let{id:Q,method:w,params:B}=A;switch(w){case"message/send":return rH2(Q,B??{},f);case"tasks/get":return oH2(Q,B??{},f);case"tasks/cancel":return aH2(Q,B??{},f);default:return xD(Q,-32601,`Method not found: ${w}`)}}async function rH2(A,f,Q){let w=pH2.safeParse(f);if(!w.success)return xD(A,-32602,`Invalid params: ${w.error.message}`);let B=w.data.message.parts.filter((u)=>u.kind==="text"&&typeof u.text==="string");if(B.length===0)return xD(A,-32602,"Message must contain at least one text part");let x=B.map((u)=>u.text).join(`
|
|
1920
1920
|
`),I=w.data.message.contextId,$=Q.taskManager.createTask(x,I),c=$.task.id;Q.taskManager.updateState(c,"working"),dH2(c,x,$.conversationId,Q);let D=Q.taskManager.getTask(c);if(!D)return xD(A,-32603,"Internal error: task disappeared");return ZUA(A,D.task)}function dH2(A,f,Q,w){w.agentService.chat(f,Q,{userPermissionLevel:w.callerPermissionLevel,interfaceType:"a2a"}).then((B)=>{w.taskManager.updateState(A,"completed",B.text)}).catch((B)=>{let x=B instanceof Error?B.message:"Unknown error";w.taskManager.updateState(A,"failed",`Error: ${x}`)})}var _q0=X.object({message:X.object({kind:X.string(),parts:bq0,contextId:X.string().optional()})});function Vq0(A,f,Q){let B=f.parts.filter((D)=>D.kind==="text"&&typeof D.text==="string").map((D)=>D.text).join(`
|
|
1921
1921
|
`)||"No message text",x=Q.taskManager.createTask(B,f.contextId),I=x.task.id;Q.taskManager.updateState(I,"working");let $=new TextEncoder,c=new ReadableStream({start(D){let u=!1;function K(v){if(u)return;try{D.enqueue($.encode(`data: ${JSON.stringify(v)}
|
|
1922
1922
|
|
|
@@ -1924,7 +1924,7 @@ ${A.entityContent}`,ML1);c=w+q.imagePrompt}catch(q){this.logger.warn("AI prompt
|
|
|
1924
1924
|
|
|
1925
1925
|
`);w=x.pop()??"";for(let I of x){let $=I.split(`
|
|
1926
1926
|
`).find((v)=>v.startsWith("data: "));if(!$)continue;let D=JSON.parse($.slice(6)).result;if(!D)continue;if(D.final!==!0)continue;f.cancel().catch(()=>{});let K=D.status,F=K?.state??"unknown",J=(K?.message?.parts??[]).filter((v)=>v.kind==="text"&&typeof v.text==="string").map((v)=>v.text).join(`
|
|
1927
|
-
`)||"No response text";return{success:!0,data:{state:F,response:J}}}B=await f.read()}return{success:!1,error:"Stream ended without a terminal event"}}function jq0(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:Mq0,visibility:"anchor",handler:async(Q)=>{let w=X.object(Mq0).safeParse(Q);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};let{agent:B,message:x}=w.data,I=B,$=B.startsWith("http://")||B.startsWith("https://");if(!$&&A.entityService){let F=await A.entityService.getEntity("agent",B);if(F){if(F.metadata.status==="archived")return{success:!1,error:`Agent ${B} is archived. Use agent_add to re-activate.`};let Z=F.metadata.url;if(typeof Z==="string")I=Z}}if(!I.startsWith("http"))I=`https://${I}`;let c=await sH2(I,f);if(!c)return{success:!1,error:`Could not fetch Agent Card from ${I}`};let D=c.url,u;if(A.outboundTokens)try{let F=new URL(D).hostname;u=A.outboundTokens[F]}catch{}let K=await tH2(D,x,f,u);if("success"in K&&K.success&&$&&A.sendMessage){let F=new URL(D).hostname;A.sendMessage("a2a:call:completed",{domain:F}).catch(()=>{})}return K}}}var WUA={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.0",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 Cz extends vc{agentCard;server;unsubscribeReady;unsubscribeSyncCompleted;taskManager=new XUA;agentService;permissionContext;constructor(A={}){super("a2a",WUA,A,Eq0)}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(),Q=A.identity.getProfile(),w=A.tools.listForPermissionLevel("public"),B=this.config.trustedTokens&&Object.keys(this.config.trustedTokens).length>0,x;if(A.entityService.hasEntityType("skill"))try{let I=await A.entityService.listEntities("skill");if(I.length>0)x=I.map(($)=>LJ.safeParse($.metadata)).filter(($)=>$.success).map(($)=>$.data)}catch{}this.agentCard=hq0({character:f,profile:Q,version:WUA.version,domain:A.domain,organization:this.config.organization,tools:w,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),Q=this.config.trustedTokens[f];if(!Q||!this.permissionContext)return"public";return this.permissionContext.getUserLevel("a2a",Q)}async getTools(){return[jq0({outboundTokens:this.config.outboundTokens,entityService:this.getContext().entityService,sendMessage:(A,f)=>this.getContext().messaging.send(A,f)})]}createDaemon(){let A=new EZ;return A.get("/.well-known/agent-card.json",(f)=>{if(!this.agentCard)return f.json({error:"Agent Card not ready"},503);return f.json(this.agentCard)}),A.post("/a2a",async(f)=>{if(!this.agentService)return f.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503);let Q;try{Q=await f.req.json()}catch{return f.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null})}let w=qq0.safeParse(Q);if(!w.success)return f.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null});let B=this.resolveCallerPermission(f.req.header("Authorization"));if(w.data.method==="message/stream"){let I=_q0.safeParse(w.data.params??{});if(!I.success)return f.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${I.error.message}`},id:w.data.id});let{stream:$}=Vq0(w.data.id,I.data.message,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:B});return new Response($,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}let x=await Cq0(w.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 GUA{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 Q=[],w=this.createImportOperations(A);Q.push(...w);let B=w.length;if(f?.includeCleanup)Q.push({type:"directory-cleanup",data:{}});let x=A.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:B,totalFiles:x}),{operations:Q,exportOperationsCount:0,importOperationsCount:B,totalFiles:x}}async queueSyncBatch(A,f,Q,w,B){let x=this.prepareBatchOperations(Q,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:w?.rootJobId??iB(),metadata:{progressToken:w?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:w?.pluginId??"directory-sync",interfaceType:w?.interfaceType,channelId:w?.channelId}}),operationCount:x.operations.length,exportOperationsCount:x.exportOperationsCount,importOperationsCount:x.importOperationsCount,totalFiles:x.totalFiles}}createImportOperations(A){if(A.length===0)return[];let f=50,Q=[];for(let w=0;w<A.length;w+=f){let B=A.slice(w,w+f);Q.push({type:"directory-import",data:{batchIndex:Math.floor(w/f),paths:B,batchSize:B.length}})}return Q}}HA();import{resolve as HG2,isAbsolute as KG2}from"path";import{mkdir as FG2}from"fs/promises";var fV0=d0(a_0(),1);_I();import{join as ID,dirname as tW2,extname as lp}from"path";import{mkdir as WHA,readFile as yp,writeFile as s_0,readdir as eW2,stat as t_0,utimes as AG2,access as fG2}from"fs/promises";var yV=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function e_0(A){let f=lp(A).toLowerCase();return yV.includes(f)}function QG2(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 AV0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}async function Pz(A){try{return await fG2(A),!0}catch{return!1}}class GHA{syncPath;entityService;constructor(A,f){this.syncPath=A,this.entityService=f}parseEntityFromPath(A){let w=(A.startsWith(this.syncPath)?A:ID(this.syncPath,A)).replace(this.syncPath+"/","").split("/"),B,x;if(w.length===1)B="base",x=w;else if(w.length>1&&w[0])B=w[0],x=w.slice(1);else B="base",x=w;let I;if(x.length>1){let $=x[x.length-1];if($){let c=lp($).toLowerCase(),D=c===".md"||yV.includes(c)?$.slice(0,-c.length):$;x[x.length-1]=D}I=x.join(":")}else{let $=x[0]??"",c=lp($).toLowerCase();I=c===".md"||yV.includes(c)?$.slice(0,-c.length):$}return{entityType:B,id:I}}async readEntity(A){let f=A.startsWith(this.syncPath)?A:ID(this.syncPath,A),Q=await t_0(f),{entityType:w,id:B}=this.parseEntityFromPath(A),x=Q.birthtime.getTime()>0?Q.birthtime:Q.mtime,I=Q.mtime,$;if(e_0(A)){let D=(await yp(f)).toString("base64"),u=lp(A);$=`data:${QG2(u)};base64,${D}`}else $=await yp(f,"utf-8");return{entityType:w,id:B,content:$,created:x,updated:I}}async writeEntity(A){let f=this.getEntityFilePath(A),Q=A.entityType==="image",w;if(Q){let x=A.content.match(/^data:image\/[a-z+]+;base64,(.+)$/i);w=x?.[1]?Buffer.from(x[1],"base64"):Buffer.from(A.content,"base64")}else w=this.entityService.serializeEntity(A);if(await Pz(f)){let x=Q?await yp(f):await yp(f,"utf-8"),I=Bw(Q?x.toString("base64"):x),$=Bw(Q?w.toString("base64"):w);if(I===$)return}if(A.entityType!=="base")await WHA(tW2(f),{recursive:!0});if(Q)await s_0(f,w);else await s_0(f,w,"utf-8");let B=new Date(A.updated);await AG2(f,B,B)}getFilePath(A,f,Q=".md"){let w=A.split(":").filter((c)=>c.length>0),B=f==="base";if(w.length===1)return B?ID(this.syncPath,`${w[0]}${Q}`):ID(this.syncPath,f,`${w[0]}${Q}`);let x=w;if(w[0]===f)x=w.slice(1);let I=x[x.length-1],$=x.slice(0,-1);if(B)return ID(this.syncPath,...$,`${I}${Q}`);else return ID(this.syncPath,f,...$,`${I}${Q}`)}getEntityFilePath(A){let f=".md";if(A.entityType==="image"){let Q=A.metadata.format;if(Q)f=AV0(Q);else{let w=A.content.match(/^data:image\/([a-z+]+);base64,/i);if(w?.[1])f=AV0(w[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 Pz(this.syncPath))return f;let Q=async(w,B="",x=!1)=>{let I=await eW2(w,{withFileTypes:!0});for(let $ of I){let c=B?ID(B,$.name):$.name;if($.isFile()&&!$.name.endsWith(".invalid")){if($.name.endsWith(".md"))f.push(c);else if(A.includeImages&&x&&e_0($.name))f.push(c)}else if($.isDirectory()&&!$.name.startsWith(".")){if(B===""&&!this.entityService.hasEntityType($.name))continue;let D=ID(w,$.name),u=$.name==="image"&&B==="";await Q(D,c,x||u)}}};return await Q(this.syncPath),f}async ensureDirectoryStructure(A){if(!await Pz(this.syncPath))await WHA(this.syncPath,{recursive:!0});for(let f of A)if(f!=="base")await WHA(ID(this.syncPath,f),{recursive:!0})}shouldUpdateEntity(A,f){let Q=Bw(f.content);return A.contentHash!==Q}async gatherFileStatus(){let A=[],f={totalFiles:0,byEntityType:{}};if(!await Pz(this.syncPath))return{files:A,stats:f};let Q=await this.getAllMarkdownFiles();for(let w of Q)try{let B=ID(this.syncPath,w),x=await t_0(B),{entityType:I}=this.parseEntityFromPath(w);A.push({path:w,entityType:I,modified:x.mtime}),f.totalFiles++,f.byEntityType[I]=(f.byEntityType[I]??0)+1}catch{continue}return{files:A,stats:f}}async syncDirectoryExists(){return Pz(this.syncPath)}async fileExists(A){return Pz(A)}}function wG2(A,f){if(!A.replace(f+"/","").startsWith("image/"))return!1;return yV.some((w)=>A.toLowerCase().endsWith(w))}function BG2(A,f){if(A.replace(f+"/","").split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return wG2(A,f)}class JHA{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=fV0.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(!BG2(f,this.syncPath))return;this.logger.debug("File change detected",{event:A,path:f});let Q=f.replace(this.syncPath+"/","");if(this.pendingChanges.set(Q,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,Q]of A){let w=`${this.syncPath}/${f}`;try{if(this.onFileChange)await this.onFileChange(Q,w)}catch(B){this.logger.error("Error processing file change",{path:f,event:Q,error:B})}}}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}class vHA{logger;entityService;fileOperations;constructor(A,f,Q){this.logger=A,this.entityService=f,this.fileOperations=Q}async importEntitiesWithProgress(A,f,Q,w){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(),I=x.length;await f.report({progress:0,message:`Starting import of ${I} files`});for(let $=0;$<I;$+=Q){let c=x.slice($,$+Q),D=await w(c);B.imported+=D.imported,B.skipped+=D.skipped,B.failed+=D.failed,B.errors.push(...D.errors),B.jobIds.push(...D.jobIds);let u=Math.min($+Q,I),K=Math.round(u/I*40);await f.report({progress:K,message:`Imported ${u}/${I} files`})}return B}async exportEntitiesWithProgress(A,f,Q){this.logger.debug("Exporting entities with progress reporting");let w=A??this.entityService.getEntityTypes(),B={exported:0,failed:0,errors:[]},x=w.length;await f.report({progress:50,message:`Starting export of ${x} entity types`});for(let I=0;I<x;I++){let $=w[I];if(!$)continue;let c=await this.entityService.listEntities($,{limit:1000});for(let D=0;D<c.length;D+=Q){let u=c.slice(D,D+Q);for(let Z of u)try{await this.fileOperations.writeEntity(Z),B.exported++,this.logger.debug("Exported entity",{entityType:$,id:Z.id})}catch(J){let v=J instanceof Error?J:Error(`Failed to export entity ${Z.id||"unknown"}`);B.failed++,B.errors.push({entityId:Z.id||"unknown",entityType:$,error:v.message}),this.logger.error("Failed to export entity",{entityType:$,id:Z.id||"unknown",error:v})}let K=(I+1)/x,F=50+Math.round(K*50);await f.report({progress:F,message:`Exported ${B.exported} entities`})}}return this.logger.debug("Export completed",B),B}}class kHA{logger;handleImport;handleDelete;deleteOnFileRemoval;fileOperations;constructor(A,f,Q,w,B=!0){if(this.logger=A,this.fileOperations=w,this.deleteOnFileRemoval=B,Q)this.handleImport=async(x)=>{let I=await Q({type:"directory-import",data:{paths:[x]}});this.logger.debug("Queued import job for file change",{jobId:I,path:x})},this.handleDelete=async(x)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:x});return}try{let{entityType:I,id:$}=this.fileOperations.parseEntityFromPath(x),c=await Q({type:"directory-delete",data:{entityId:$,entityType:I,filePath:x}});this.logger.info("Queued delete job for removed file",{jobId:c,path:x,entityId:$,entityType:I})}catch(I){this.logger.warn("Could not extract entity info from deleted file",{path:x,error:I})}};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(Q){this.logger.error("Failed to handle file change",{event:A,path:f,error:Q})}}}HA();async function np(A,f,Q,w){let{sourceUrl:B}=A,x=await f.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1});if(x[0])return w.debug("Reusing existing image entity",{sourceUrl:B,imageId:x[0].id}),x[0].id;let I=await Q(B),{base64:$}=RU(I),c=WX($),D=PU($);if(!c||!D)throw Error("Could not detect image format or dimensions");let u=await f.createEntity({id:A.id,entityType:"image",content:I,metadata:{title:A.title,alt:A.alt,format:c,width:D.width,height:D.height,sourceUrl:B}});return w.debug("Created image entity from URL",{sourceUrl:B,imageId:u.entityId}),u.entityId}var QV0=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.string().url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class zHA{entityService;fetcher;logger;constructor(A,f,Q=t5){this.entityService=A;this.fetcher=Q;this.logger=f.child("FrontmatterImageConverter")}detectCoverImageUrl(A){let f;try{f=JI(A)}catch{return null}let{frontmatter:Q}=f,w=QV0.safeParse(Q);if(!w.success)return null;if(w.data.coverImageId)return null;let{title:B,slug:x,coverImageUrl:I,coverImageAlt:$}=w.data;if(!b3(I))return null;return{sourceUrl:I,postTitle:B,postSlug:x??w2(B),customAlt:$}}async convert(A){let f;try{f=JI(A)}catch(D){return this.logger.debug("Parse failed",{error:D}),{content:A,converted:!1}}let{frontmatter:Q}=f,w=QV0.safeParse(Q);if(!w.success)return{content:A,converted:!1};if(w.data.coverImageId)return{content:A,converted:!1};let{title:B,slug:x,coverImageUrl:I,coverImageAlt:$}=w.data;if(!b3(I))return{content:A,converted:!1};let c={postTitle:B,postSlug:x??w2(B),sourceUrl:I,customAlt:$};try{let D=await this.createImageEntity(c),u={...Q};return delete u.coverImageUrl,delete u.coverImageAlt,u.coverImageId=D,{content:GF(u,f.content),converted:!0,imageId:D}}catch(D){return this.logger.warn("Failed to convert coverImageUrl",{url:I,error:v0(D)}),{content:A,converted:!1}}}async createImageEntity(A){let{postTitle:f,postSlug:Q,sourceUrl:w,customAlt:B}=A,x=`Cover image for ${f}`;return np({id:`${Q}-cover`,title:x,alt:B??x,sourceUrl:w},this.entityService,this.fetcher,this.logger)}}HA();class lV{entityService;fetcher;logger;constructor(A,f,Q=t5){this.entityService=A;this.fetcher=Q;this.logger=f.child("MarkdownImageConverter")}detectInlineImages(A,f){let Q=[],w=kP(A);for(let B of w){if(!b3(B.url))continue;if(B.url.startsWith("entity://"))continue;let x=this.reconstructMarkdown(B);Q.push({sourceUrl:B.url,alt:B.alt,originalMarkdown:x,postSlug:f})}return Q}reconstructMarkdown(A){if(A.title)return``;return``}async convert(A,f){let Q=this.detectInlineImages(A,f);if(Q.length===0)return{content:A,converted:!1,convertedCount:0};let w=A,B=0,x=0;for(let I of Q)try{let $=await this.createImageEntity(I,x++),c=``;w=w.replace(I.originalMarkdown,c),B++,this.logger.debug("Converted inline image",{sourceUrl:I.sourceUrl,imageId:$})}catch($){this.logger.warn("Failed to convert inline image",{sourceUrl:I.sourceUrl,error:v0($)})}return{content:w,converted:B>0,convertedCount:B}}async createImageEntity(A,f){let{sourceUrl:Q,alt:w,postSlug:B}=A;return np({id:`${B}-inline-${f}`,title:w||`Inline image ${f+1} for ${B}`,alt:w||"",sourceUrl:Q},this.entityService,this.fetcher,this.logger)}}HA();import{rename as xG2,appendFile as IG2,readFile as $G2,writeFile as cG2,access as DG2}from"fs/promises";import{join as wV0}from"path";class NHA{logger;syncPath;constructor(A,f){this.logger=A;this.syncPath=f}isValidationError(A){if(A instanceof X.ZodError)return!0;let f=v0(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,Q,w){let B=w(A),x=`${B}.invalid`;try{await xG2(B,x),Q.quarantined++,Q.quarantinedFiles.push(A);let I=wV0(this.syncPath,".import-errors.log"),$=new Date().toISOString(),c=v0(f),D=`${$} - ${A}: ${c}
|
|
1927
|
+
`)||"No response text";return{success:!0,data:{state:F,response:J}}}B=await f.read()}return{success:!1,error:"Stream ended without a terminal event"}}function jq0(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:Mq0,visibility:"anchor",handler:async(Q)=>{let w=X.object(Mq0).safeParse(Q);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};let{agent:B,message:x}=w.data,I=B,$=B.startsWith("http://")||B.startsWith("https://");if(!$&&A.entityService){let F=await A.entityService.getEntity("agent",B);if(F){if(F.metadata.status==="archived")return{success:!1,error:`Agent ${B} is archived. Use agent_add to re-activate.`};let Z=F.metadata.url;if(typeof Z==="string")I=Z}}if(!I.startsWith("http"))I=`https://${I}`;let c=await sH2(I,f);if(!c)return{success:!1,error:`Could not fetch Agent Card from ${I}`};let D=c.url,u;if(A.outboundTokens)try{let F=new URL(D).hostname;u=A.outboundTokens[F]}catch{}let K=await tH2(D,x,f,u);if("success"in K&&K.success&&$&&A.sendMessage){let F=new URL(D).hostname;A.sendMessage("a2a:call:completed",{domain:F}).catch(()=>{})}return K}}}var WUA={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.1",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 Cz extends vc{agentCard;server;unsubscribeReady;unsubscribeSyncCompleted;taskManager=new XUA;agentService;permissionContext;constructor(A={}){super("a2a",WUA,A,Eq0)}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(),Q=A.identity.getProfile(),w=A.tools.listForPermissionLevel("public"),B=this.config.trustedTokens&&Object.keys(this.config.trustedTokens).length>0,x;if(A.entityService.hasEntityType("skill"))try{let I=await A.entityService.listEntities("skill");if(I.length>0)x=I.map(($)=>LJ.safeParse($.metadata)).filter(($)=>$.success).map(($)=>$.data)}catch{}this.agentCard=hq0({character:f,profile:Q,version:WUA.version,domain:A.domain,organization:this.config.organization,tools:w,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),Q=this.config.trustedTokens[f];if(!Q||!this.permissionContext)return"public";return this.permissionContext.getUserLevel("a2a",Q)}async getTools(){return[jq0({outboundTokens:this.config.outboundTokens,entityService:this.getContext().entityService,sendMessage:(A,f)=>this.getContext().messaging.send(A,f)})]}createDaemon(){let A=new EZ;return A.get("/.well-known/agent-card.json",(f)=>{if(!this.agentCard)return f.json({error:"Agent Card not ready"},503);return f.json(this.agentCard)}),A.post("/a2a",async(f)=>{if(!this.agentService)return f.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503);let Q;try{Q=await f.req.json()}catch{return f.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null})}let w=qq0.safeParse(Q);if(!w.success)return f.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null});let B=this.resolveCallerPermission(f.req.header("Authorization"));if(w.data.method==="message/stream"){let I=_q0.safeParse(w.data.params??{});if(!I.success)return f.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${I.error.message}`},id:w.data.id});let{stream:$}=Vq0(w.data.id,I.data.message,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:B});return new Response($,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}let x=await Cq0(w.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 GUA{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 Q=[],w=this.createImportOperations(A);Q.push(...w);let B=w.length;if(f?.includeCleanup)Q.push({type:"directory-cleanup",data:{}});let x=A.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:B,totalFiles:x}),{operations:Q,exportOperationsCount:0,importOperationsCount:B,totalFiles:x}}async queueSyncBatch(A,f,Q,w,B){let x=this.prepareBatchOperations(Q,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:w?.rootJobId??iB(),metadata:{progressToken:w?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:w?.pluginId??"directory-sync",interfaceType:w?.interfaceType,channelId:w?.channelId}}),operationCount:x.operations.length,exportOperationsCount:x.exportOperationsCount,importOperationsCount:x.importOperationsCount,totalFiles:x.totalFiles}}createImportOperations(A){if(A.length===0)return[];let f=50,Q=[];for(let w=0;w<A.length;w+=f){let B=A.slice(w,w+f);Q.push({type:"directory-import",data:{batchIndex:Math.floor(w/f),paths:B,batchSize:B.length}})}return Q}}HA();import{resolve as HG2,isAbsolute as KG2}from"path";import{mkdir as FG2}from"fs/promises";var fV0=d0(a_0(),1);_I();import{join as ID,dirname as tW2,extname as lp}from"path";import{mkdir as WHA,readFile as yp,writeFile as s_0,readdir as eW2,stat as t_0,utimes as AG2,access as fG2}from"fs/promises";var yV=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function e_0(A){let f=lp(A).toLowerCase();return yV.includes(f)}function QG2(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 AV0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}async function Pz(A){try{return await fG2(A),!0}catch{return!1}}class GHA{syncPath;entityService;constructor(A,f){this.syncPath=A,this.entityService=f}parseEntityFromPath(A){let w=(A.startsWith(this.syncPath)?A:ID(this.syncPath,A)).replace(this.syncPath+"/","").split("/"),B,x;if(w.length===1)B="base",x=w;else if(w.length>1&&w[0])B=w[0],x=w.slice(1);else B="base",x=w;let I;if(x.length>1){let $=x[x.length-1];if($){let c=lp($).toLowerCase(),D=c===".md"||yV.includes(c)?$.slice(0,-c.length):$;x[x.length-1]=D}I=x.join(":")}else{let $=x[0]??"",c=lp($).toLowerCase();I=c===".md"||yV.includes(c)?$.slice(0,-c.length):$}return{entityType:B,id:I}}async readEntity(A){let f=A.startsWith(this.syncPath)?A:ID(this.syncPath,A),Q=await t_0(f),{entityType:w,id:B}=this.parseEntityFromPath(A),x=Q.birthtime.getTime()>0?Q.birthtime:Q.mtime,I=Q.mtime,$;if(e_0(A)){let D=(await yp(f)).toString("base64"),u=lp(A);$=`data:${QG2(u)};base64,${D}`}else $=await yp(f,"utf-8");return{entityType:w,id:B,content:$,created:x,updated:I}}async writeEntity(A){let f=this.getEntityFilePath(A),Q=A.entityType==="image",w;if(Q){let x=A.content.match(/^data:image\/[a-z+]+;base64,(.+)$/i);w=x?.[1]?Buffer.from(x[1],"base64"):Buffer.from(A.content,"base64")}else w=this.entityService.serializeEntity(A);if(await Pz(f)){let x=Q?await yp(f):await yp(f,"utf-8"),I=Bw(Q?x.toString("base64"):x),$=Bw(Q?w.toString("base64"):w);if(I===$)return}if(A.entityType!=="base")await WHA(tW2(f),{recursive:!0});if(Q)await s_0(f,w);else await s_0(f,w,"utf-8");let B=new Date(A.updated);await AG2(f,B,B)}getFilePath(A,f,Q=".md"){let w=A.split(":").filter((c)=>c.length>0),B=f==="base";if(w.length===1)return B?ID(this.syncPath,`${w[0]}${Q}`):ID(this.syncPath,f,`${w[0]}${Q}`);let x=w;if(w[0]===f)x=w.slice(1);let I=x[x.length-1],$=x.slice(0,-1);if(B)return ID(this.syncPath,...$,`${I}${Q}`);else return ID(this.syncPath,f,...$,`${I}${Q}`)}getEntityFilePath(A){let f=".md";if(A.entityType==="image"){let Q=A.metadata.format;if(Q)f=AV0(Q);else{let w=A.content.match(/^data:image\/([a-z+]+);base64,/i);if(w?.[1])f=AV0(w[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 Pz(this.syncPath))return f;let Q=async(w,B="",x=!1)=>{let I=await eW2(w,{withFileTypes:!0});for(let $ of I){let c=B?ID(B,$.name):$.name;if($.isFile()&&!$.name.endsWith(".invalid")){if($.name.endsWith(".md"))f.push(c);else if(A.includeImages&&x&&e_0($.name))f.push(c)}else if($.isDirectory()&&!$.name.startsWith(".")){if(B===""&&!this.entityService.hasEntityType($.name))continue;let D=ID(w,$.name),u=$.name==="image"&&B==="";await Q(D,c,x||u)}}};return await Q(this.syncPath),f}async ensureDirectoryStructure(A){if(!await Pz(this.syncPath))await WHA(this.syncPath,{recursive:!0});for(let f of A)if(f!=="base")await WHA(ID(this.syncPath,f),{recursive:!0})}shouldUpdateEntity(A,f){let Q=Bw(f.content);return A.contentHash!==Q}async gatherFileStatus(){let A=[],f={totalFiles:0,byEntityType:{}};if(!await Pz(this.syncPath))return{files:A,stats:f};let Q=await this.getAllMarkdownFiles();for(let w of Q)try{let B=ID(this.syncPath,w),x=await t_0(B),{entityType:I}=this.parseEntityFromPath(w);A.push({path:w,entityType:I,modified:x.mtime}),f.totalFiles++,f.byEntityType[I]=(f.byEntityType[I]??0)+1}catch{continue}return{files:A,stats:f}}async syncDirectoryExists(){return Pz(this.syncPath)}async fileExists(A){return Pz(A)}}function wG2(A,f){if(!A.replace(f+"/","").startsWith("image/"))return!1;return yV.some((w)=>A.toLowerCase().endsWith(w))}function BG2(A,f){if(A.replace(f+"/","").split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return wG2(A,f)}class JHA{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=fV0.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(!BG2(f,this.syncPath))return;this.logger.debug("File change detected",{event:A,path:f});let Q=f.replace(this.syncPath+"/","");if(this.pendingChanges.set(Q,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,Q]of A){let w=`${this.syncPath}/${f}`;try{if(this.onFileChange)await this.onFileChange(Q,w)}catch(B){this.logger.error("Error processing file change",{path:f,event:Q,error:B})}}}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}class vHA{logger;entityService;fileOperations;constructor(A,f,Q){this.logger=A,this.entityService=f,this.fileOperations=Q}async importEntitiesWithProgress(A,f,Q,w){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(),I=x.length;await f.report({progress:0,message:`Starting import of ${I} files`});for(let $=0;$<I;$+=Q){let c=x.slice($,$+Q),D=await w(c);B.imported+=D.imported,B.skipped+=D.skipped,B.failed+=D.failed,B.errors.push(...D.errors),B.jobIds.push(...D.jobIds);let u=Math.min($+Q,I),K=Math.round(u/I*40);await f.report({progress:K,message:`Imported ${u}/${I} files`})}return B}async exportEntitiesWithProgress(A,f,Q){this.logger.debug("Exporting entities with progress reporting");let w=A??this.entityService.getEntityTypes(),B={exported:0,failed:0,errors:[]},x=w.length;await f.report({progress:50,message:`Starting export of ${x} entity types`});for(let I=0;I<x;I++){let $=w[I];if(!$)continue;let c=await this.entityService.listEntities($,{limit:1000});for(let D=0;D<c.length;D+=Q){let u=c.slice(D,D+Q);for(let Z of u)try{await this.fileOperations.writeEntity(Z),B.exported++,this.logger.debug("Exported entity",{entityType:$,id:Z.id})}catch(J){let v=J instanceof Error?J:Error(`Failed to export entity ${Z.id||"unknown"}`);B.failed++,B.errors.push({entityId:Z.id||"unknown",entityType:$,error:v.message}),this.logger.error("Failed to export entity",{entityType:$,id:Z.id||"unknown",error:v})}let K=(I+1)/x,F=50+Math.round(K*50);await f.report({progress:F,message:`Exported ${B.exported} entities`})}}return this.logger.debug("Export completed",B),B}}class kHA{logger;handleImport;handleDelete;deleteOnFileRemoval;fileOperations;constructor(A,f,Q,w,B=!0){if(this.logger=A,this.fileOperations=w,this.deleteOnFileRemoval=B,Q)this.handleImport=async(x)=>{let I=await Q({type:"directory-import",data:{paths:[x]}});this.logger.debug("Queued import job for file change",{jobId:I,path:x})},this.handleDelete=async(x)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:x});return}try{let{entityType:I,id:$}=this.fileOperations.parseEntityFromPath(x),c=await Q({type:"directory-delete",data:{entityId:$,entityType:I,filePath:x}});this.logger.info("Queued delete job for removed file",{jobId:c,path:x,entityId:$,entityType:I})}catch(I){this.logger.warn("Could not extract entity info from deleted file",{path:x,error:I})}};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(Q){this.logger.error("Failed to handle file change",{event:A,path:f,error:Q})}}}HA();async function np(A,f,Q,w){let{sourceUrl:B}=A,x=await f.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1});if(x[0])return w.debug("Reusing existing image entity",{sourceUrl:B,imageId:x[0].id}),x[0].id;let I=await Q(B),{base64:$}=RU(I),c=WX($),D=PU($);if(!c||!D)throw Error("Could not detect image format or dimensions");let u=await f.createEntity({id:A.id,entityType:"image",content:I,metadata:{title:A.title,alt:A.alt,format:c,width:D.width,height:D.height,sourceUrl:B}});return w.debug("Created image entity from URL",{sourceUrl:B,imageId:u.entityId}),u.entityId}var QV0=X.object({title:X.string(),slug:X.string().optional(),coverImageUrl:X.string().url(),coverImageId:X.string().optional(),coverImageAlt:X.string().optional()});class zHA{entityService;fetcher;logger;constructor(A,f,Q=t5){this.entityService=A;this.fetcher=Q;this.logger=f.child("FrontmatterImageConverter")}detectCoverImageUrl(A){let f;try{f=JI(A)}catch{return null}let{frontmatter:Q}=f,w=QV0.safeParse(Q);if(!w.success)return null;if(w.data.coverImageId)return null;let{title:B,slug:x,coverImageUrl:I,coverImageAlt:$}=w.data;if(!b3(I))return null;return{sourceUrl:I,postTitle:B,postSlug:x??w2(B),customAlt:$}}async convert(A){let f;try{f=JI(A)}catch(D){return this.logger.debug("Parse failed",{error:D}),{content:A,converted:!1}}let{frontmatter:Q}=f,w=QV0.safeParse(Q);if(!w.success)return{content:A,converted:!1};if(w.data.coverImageId)return{content:A,converted:!1};let{title:B,slug:x,coverImageUrl:I,coverImageAlt:$}=w.data;if(!b3(I))return{content:A,converted:!1};let c={postTitle:B,postSlug:x??w2(B),sourceUrl:I,customAlt:$};try{let D=await this.createImageEntity(c),u={...Q};return delete u.coverImageUrl,delete u.coverImageAlt,u.coverImageId=D,{content:GF(u,f.content),converted:!0,imageId:D}}catch(D){return this.logger.warn("Failed to convert coverImageUrl",{url:I,error:v0(D)}),{content:A,converted:!1}}}async createImageEntity(A){let{postTitle:f,postSlug:Q,sourceUrl:w,customAlt:B}=A,x=`Cover image for ${f}`;return np({id:`${Q}-cover`,title:x,alt:B??x,sourceUrl:w},this.entityService,this.fetcher,this.logger)}}HA();class lV{entityService;fetcher;logger;constructor(A,f,Q=t5){this.entityService=A;this.fetcher=Q;this.logger=f.child("MarkdownImageConverter")}detectInlineImages(A,f){let Q=[],w=kP(A);for(let B of w){if(!b3(B.url))continue;if(B.url.startsWith("entity://"))continue;let x=this.reconstructMarkdown(B);Q.push({sourceUrl:B.url,alt:B.alt,originalMarkdown:x,postSlug:f})}return Q}reconstructMarkdown(A){if(A.title)return``;return``}async convert(A,f){let Q=this.detectInlineImages(A,f);if(Q.length===0)return{content:A,converted:!1,convertedCount:0};let w=A,B=0,x=0;for(let I of Q)try{let $=await this.createImageEntity(I,x++),c=``;w=w.replace(I.originalMarkdown,c),B++,this.logger.debug("Converted inline image",{sourceUrl:I.sourceUrl,imageId:$})}catch($){this.logger.warn("Failed to convert inline image",{sourceUrl:I.sourceUrl,error:v0($)})}return{content:w,converted:B>0,convertedCount:B}}async createImageEntity(A,f){let{sourceUrl:Q,alt:w,postSlug:B}=A;return np({id:`${B}-inline-${f}`,title:w||`Inline image ${f+1} for ${B}`,alt:w||"",sourceUrl:Q},this.entityService,this.fetcher,this.logger)}}HA();import{rename as xG2,appendFile as IG2,readFile as $G2,writeFile as cG2,access as DG2}from"fs/promises";import{join as wV0}from"path";class NHA{logger;syncPath;constructor(A,f){this.logger=A;this.syncPath=f}isValidationError(A){if(A instanceof X.ZodError)return!0;let f=v0(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,Q,w){let B=w(A),x=`${B}.invalid`;try{await xG2(B,x),Q.quarantined++,Q.quarantinedFiles.push(A);let I=wV0(this.syncPath,".import-errors.log"),$=new Date().toISOString(),c=v0(f),D=`${$} - ${A}: ${c}
|
|
1928
1928
|
\u2192 ${A}.invalid
|
|
1929
1929
|
|
|
1930
1930
|
`;await IG2(I,D),this.logger.warn("Quarantined invalid entity file",{originalPath:A,quarantinePath:`${A}.invalid`,error:c})}catch(I){this.logger.error("Failed to quarantine invalid file",{path:A,error:I}),Q.failed++,Q.errors.push({path:A,error:"Failed to quarantine invalid file"})}}async markAsRecoveredIfNeeded(A){let f=wV0(this.syncPath,".import-errors.log");try{await DG2(f)}catch{return}try{let Q=await $G2(f,"utf-8");if(Q.includes(A)){let B=`${new Date().toISOString()} - [RECOVERED] ${A}
|
|
@@ -1950,7 +1950,7 @@ ${A.entityContent}`,ML1);c=w+q.imagePrompt}catch(q){this.logger.warn("AI prompt
|
|
|
1950
1950
|
*...and ${A.files.length-10} more files*`)}if(A.exists&&A.stats.totalFiles===0)f.push(`
|
|
1951
1951
|
## Getting Started
|
|
1952
1952
|
`),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(`
|
|
1953
|
-
`)}}B0();class Fr extends qQ{context;directorySync;constructor(A,f,Q){super(A,{schema:oO0,jobTypeName:"directory-export"});this.context=f,this.directorySync=Q}async process(A,f,Q){this.logger.debug("Processing directory export job",{jobId:f,data:A});let w=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 Q.report({message:`Starting export of ${x.length} entity types`,progress:0,total:x.length});for(let[I,$]of x.entries())await this.exportEntityType($,A.batchSize??100,f,B),await Q.report({message:`Exported ${I+1}/${x.length} entity types (${B.exported} entities)`,progress:I+1,total:x.length});return this.logger.debug("Directory export job completed",{jobId:f,exported:B.exported,failed:B.failed,duration:Date.now()-w}),B}catch(x){throw this.logger.error("Directory export job failed",{jobId:f,error:x}),x}}async exportEntityType(A,f,Q,w){let B=0,x=!0;while(x){let I=await this.context.entityService.listEntities(A,{limit:f,offset:B});if(I.length===0){x=!1;break}let $=I.map(async(c)=>{let D=await this.directorySync.processEntityExport(c);if(D.success)w.exported++;else w.failed++,w.errors.push({entityId:c.id,entityType:A,error:D.error??"Unknown error"});return D});await Promise.all($),this.logger.debug("Export progress",{jobId:Q,entityType:A,processed:B+I.length,exported:w.exported,failed:w.failed}),B+=f,x=I.length===f}}summarizeDataForLog(A){return{entityTypes:A.entityTypes??"all",batchSize:A.batchSize}}}B0();HA();_I();class Xr extends qQ{context;directorySync;constructor(A,f,Q){super(A,{schema:dO0,jobTypeName:"directory-import"});this.context=f,this.directorySync=Q}async process(A,f,Q){this.logger.debug("Processing directory import job",{jobId:f,data:A});let w=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 Q.report({message:`Starting import of ${x.length} files`,progress:0,total:x.length});let I=A.batchSize??100;for(let $=0;$<x.length;$+=I){let c=x.slice($,$+I);await this.importBatch(c,f,B,$,x.length);let D=Math.min($+I,x.length);await Q.report({message:`Imported ${D}/${x.length} files (${B.imported} successful, ${B.failed} failed)`,progress:D,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()-w}),B}catch(x){throw this.logger.error("Directory import job failed",{jobId:f,error:x}),x}}async importBatch(A,f,Q,w,B){let x=A.map(async(I)=>{try{let $=await this.directorySync.fileOps.readEntity(I);if(!this.context.entityService.getEntityTypes().includes($.entityType))return Q.skipped++,{success:!1,skipped:!0};try{let D=this.context.entityService.deserializeEntity($.content,$.entityType),u=await this.context.entityService.getEntity($.entityType,$.id);if(u){let K=new Date(u.updated).getTime(),F=$.updated.getTime(),Z=Bw($.content),J=u.contentHash!==Z;if(K<F||J){let v={...u,content:$.content,...D,id:$.id,entityType:$.entityType,updated:$.updated.toISOString()};await this.context.entityService.updateEntity(v),Q.imported++}else Q.skipped++}else{let K={id:$.id,entityType:$.entityType,content:$.content,...D,metadata:D.metadata??{},created:$.created.toISOString(),updated:$.updated.toISOString()};await this.context.entityService.createEntity(K),Q.imported++}return{success:!0}}catch{return Q.skipped++,{success:!1,skipped:!0}}}catch($){return Q.failed++,Q.errors.push({path:I,error:v0($)}),{success:!1,error:$}}});await Promise.all(x),this.logger.debug("Import progress",{jobId:f,processed:w+A.length,total:B,imported:Q.imported,skipped:Q.skipped,failed:Q.failed})}summarizeDataForLog(A){return{pathCount:A.paths?.length??"all",batchSize:A.batchSize}}}B0();class Zr extends qQ{directorySync;context;constructor(A,f,Q){super(A,{schema:rO0,jobTypeName:"directory-sync"});this.context=f,this.directorySync=Q}async process(A,f,Q){let w=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:[]},I={exported:0,failed:0,errors:[]};if(B!=="export")if(await Q.report({progress:10,message:"Scanning directory for changes"}),x=await this.importWithProgress(A.paths,Q),B==="import")await this.waitForImportJobs(x.jobIds,Q),await Q.report({progress:100,message:`Import complete: ${x.imported} imported`});else await Q.report({progress:50,message:`Imported ${x.imported} entities`}),await this.waitForImportJobs(x.jobIds,Q),await Q.report({progress:56,message:"Processing complete, starting export"});if(B!=="import"){let c=B==="export"?10:60;await Q.report({progress:c,message:"Exporting entities to directory"}),I=await this.exportWithProgress(A.entityTypes,Q),await Q.report({progress:100,message:B==="export"?`Export complete: ${I.exported} exported`:`Sync complete: ${x.imported} imported, ${I.exported} exported`})}let $=Date.now()-w;return this.logger.info("Directory sync job completed",{jobId:f,duration:$,imported:x.imported,exported:I.exported}),{import:x,export:I,duration:$}}async importWithProgress(A,f){try{return await this.directorySync.importEntitiesWithProgress(A,f,10)}catch(Q){throw this.logger.error("Import phase failed",{error:Q}),Q}}async exportWithProgress(A,f){try{return await this.directorySync.exportEntitiesWithProgress(A,f,10)}catch(Q){throw this.logger.error("Export phase failed",{error:Q}),Q}}async waitForImportJobs(A,f){if(A.length===0)return;this.logger.debug(`Waiting for ${A.length} import jobs to complete`);let{entityService:Q}=this.context,w=300000,B=500,x=Date.now(),I=async()=>{let c=(await Promise.all(A.map((u)=>Q.getAsyncJobStatus(u)))).filter((u)=>u&&(u.status==="completed"||u.status==="failed")).length;if(c===A.length){this.logger.debug("All import jobs completed");return}if(Date.now()-x>w){this.logger.warn(`Timeout waiting for import jobs (${c}/${A.length} completed)`);return}let D=Math.round(c/A.length*100);return await f.report({progress:50+Math.round(D*0.05),message:`Processing ${c}/${A.length} entities`}),await new Promise((u)=>setTimeout(u,B)),I()};return I()}summarizeDataForLog(A){return{operation:A.operation,syncDirection:A.syncDirection}}}B0();class Wr extends qQ{context;constructor(A,f,Q){super(A,{schema:GKA,jobTypeName:"directory-delete"});this.context=f}async process(A,f,Q){let w=GKA.parse(A);this.logger.info("Processing entity deletion for removed file",{entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}),await Q.report({progress:0,total:1,message:`Deleting ${w.entityType}:${w.entityId}`});try{let B=await this.context.entityService.deleteEntity(w.entityType,w.entityId);if(B)this.logger.info("Successfully deleted entity for removed file",{entityId:w.entityId,entityType:w.entityType});else this.logger.warn("Entity not found in database",{entityId:w.entityId,entityType:w.entityType});return await Q.report({progress:1,total:1,message:`Deleted ${w.entityType}:${w.entityId}`}),{deleted:B,entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}}catch(B){throw this.logger.error("Failed to delete entity",{entityId:w.entityId,entityType:w.entityType,error:B}),B}}summarizeDataForLog(A){return{entityId:A.entityId,entityType:A.entityType,filePath:A.filePath}}}B0();HA();var nk2=X.object({});class Gr extends qQ{directorySync;constructor(A,f){super(A,{schema:nk2,jobTypeName:"directory-cleanup"});this.directorySync=f}async process(A,f,Q){await Q.report({progress:0,message:"Removing orphaned entities"});let w=await this.directorySync.removeOrphanedEntities();return await Q.report({progress:100,message:`Cleanup complete: ${w.deleted} orphans removed`}),w}}B0();HA();import{readFile as pk2,writeFile as rk2}from"fs/promises";var dk2=X.object({filePath:X.string(),sourceUrl:X.string().url(),postTitle:X.string(),postSlug:X.string(),customAlt:X.string().optional()});class Jr extends qQ{context;fetcher;constructor(A,f,Q=t5){super(f,{schema:dk2,jobTypeName:"cover-image-convert"});this.context=A,this.fetcher=Q}async process(A,f,Q){let{filePath:w,sourceUrl:B,postTitle:x,postSlug:I,customAlt:$}=A;this.logger.debug("Starting image conversion job",{jobId:f,filePath:w,sourceUrl:B,postSlug:I});try{await this.reportProgress(Q,{progress:U2.INIT,message:`Reading file: ${w}`});let c;try{c=await pk2(w,"utf-8")}catch(v){return this.logger.error("Failed to read file",{filePath:w,error:v0(v)}),GB.failure(v)}let D;try{D=JI(c)}catch(v){return this.logger.warn("Failed to parse markdown",{filePath:w,error:v0(v)}),GB.failure(v)}let u=D.frontmatter;if(u.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:w}),await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(Q,{progress:U2.FETCH,message:"Checking for existing image"});let K=await this.context.entityService.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1}),F;if(K[0])F=K[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:B,imageId:F}),await this.reportProgress(Q,{progress:U2.EXTRACT,message:`Reusing existing image: ${F}`});else{await this.reportProgress(Q,{progress:U2.PROCESS,message:`Fetching image from ${B}`});let v;try{v=await this.fetcher(B)}catch(r){return this.logger.error("Failed to fetch image",{sourceUrl:B,error:v0(r)}),GB.failure(r)}await this.reportProgress(Q,{progress:U2.GENERATE,message:"Creating image entity"});let{base64:k}=RU(v),q=WX(k),V=PU(k);if(!q||!V)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:B}),GB.failure(Error("Could not detect image format or dimensions"));F=`${I}-cover`;let C=`Cover image for ${x}`,l=$??C;await this.context.entityService.createEntity({id:F,entityType:"image",content:v,metadata:{title:C,alt:l,format:q,width:V.width,height:V.height,sourceUrl:B}}),this.logger.debug("Created image entity",{imageId:F,sourceUrl:B}),await this.reportProgress(Q,{progress:U2.EXTRACT,message:`Created image: ${F}`})}await this.reportProgress(Q,{progress:U2.SAVE,message:"Updating file"});let Z={...u};delete Z.coverImageUrl,delete Z.coverImageAlt,Z.coverImageId=F;let J=GF(Z,D.content);try{await rk2(w,J,"utf-8")}catch(v){return this.logger.error("Failed to write file",{filePath:w,error:v0(v)}),GB.failure(v)}return await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:w,imageId:F,sourceUrl:B}),{success:!0,imageId:F}}catch(c){return this.logger.error("Image conversion job failed",{jobId:f,filePath:w,error:v0(c)}),GB.failure(c)}}summarizeDataForLog(A){return{filePath:A.filePath,sourceUrl:A.sourceUrl,postSlug:A.postSlug}}}B0();HA();import{readFile as ok2,writeFile as ak2}from"fs/promises";class vr extends qQ{converter;constructor(A,f,Q=t5){super(f,{schema:aO0,jobTypeName:"inline-image-convert"});this.converter=new lV(A.entityService,f,Q)}async process(A,f,Q){let{filePath:w,postSlug:B}=A;this.logger.debug("Starting inline image conversion job",{jobId:f,filePath:w,postSlug:B});try{await this.reportProgress(Q,{progress:U2.INIT,message:`Reading file: ${w}`});let x;try{x=await ok2(w,"utf-8")}catch(c){let D=v0(c);return this.logger.error("Failed to read file",{filePath:w,error:D}),{success:!1,error:D}}await this.reportProgress(Q,{progress:U2.FETCH,message:"Detecting inline images"});let I=this.converter.detectInlineImages(x,B);if(I.length===0)return this.logger.debug("No inline images to convert",{filePath:w}),await this.reportProgress(Q,{progress:U2.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:w,count:I.length}),await this.reportProgress(Q,{progress:U2.PROCESS,message:`Converting ${I.length} images`});let $=await this.converter.convert(x,B);if(!$.converted)return this.logger.debug("No images were converted",{filePath:w}),await this.reportProgress(Q,{progress:U2.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(Q,{progress:U2.SAVE,message:"Writing updated file"});try{await ak2(w,$.content,"utf-8")}catch(c){let D=v0(c);return this.logger.error("Failed to write file",{filePath:w,error:D}),{success:!1,error:D}}return await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:w,convertedCount:$.convertedCount}),{success:!0,convertedCount:$.convertedCount}}catch(x){let I=v0(x);return this.logger.error("Inline image conversion job failed",{jobId:f,filePath:w,error:I}),{success:!1,error:I}}}summarizeDataForLog(A){return{filePath:A.filePath,postSlug:A.postSlug}}}function eO0(A,f,Q){let w=(B)=>Q.child(B);A.jobs.registerHandler("directory-sync",new Zr(w("DirectorySyncJobHandler"),A,f)),A.jobs.registerHandler("directory-export",new Fr(w("DirectoryExportJobHandler"),A,f)),A.jobs.registerHandler("directory-import",new Xr(w("DirectoryImportJobHandler"),A,f)),A.jobs.registerHandler("directory-delete",new Wr(w("DirectoryDeleteJobHandler"),A,f)),A.jobs.registerHandler("directory-cleanup",new Gr(w("DirectoryCleanupJobHandler"),f)),A.jobs.registerHandler("cover-image-convert",new Jr(A,w("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new vr(A,w("InlineImageConversionJobHandler"))),Q.debug("Registered async job handlers")}B0();import{unlink as sk2,access as tk2}from"fs/promises";function Aj0(A,f,Q,w){let{subscribe:B}=A.messaging,{entityService:x}=A;B("entity:created",async(I)=>{let{entity:$}=I.payload;try{await f.fileOps.writeEntity($),Q.debug("Auto-exported created entity",{id:$.id,entityType:$.entityType})}catch(c){Q.error("Auto-export FAILED for created entity",{id:$.id,entityType:$.entityType,error:c instanceof Error?c.message:String(c),stack:c instanceof Error?c.stack:void 0})}return{success:!0}}),B("entity:updated",async(I)=>{let{entityType:$,entityId:c}=I.payload;try{let D=await x.getEntity($,c);if(!D)return Q.debug("Entity not found in DB, skipping export",{entityType:$,entityId:c}),{success:!1};await f.fileOps.writeEntity(D),Q.debug("Auto-exported updated entity",{id:D.id,entityType:D.entityType})}catch(D){Q.error("Auto-export FAILED for updated entity",{entityType:$,entityId:c,error:D instanceof Error?D.message:String(D),stack:D instanceof Error?D.stack:void 0})}return{success:!0}}),B("entity:deleted",async(I)=>{let{entityId:$,entityType:c}=I.payload,D=f.fileOps.getFilePath($,c);if(await tk2(D).then(()=>!0,()=>!1))await sk2(D),Q.debug("Auto-deleted entity file",{id:$,entityType:c,path:D});return{success:!0}}),Q.debug("Setup auto-sync for entity events",{entityTypes:w})}function fj0(A,f,Q){f.setJobQueueCallback(async(w)=>{let B=[{type:w.type,data:w.data}];return A.jobs.enqueueBatch(B,{priority:5,source:"directory-sync-watcher",rootJobId:iB(),metadata:{operationType:"file_operations",operationTarget:Q,pluginId:"directory-sync"}})})}HA();import{access as ek2,readdir as Qj0,mkdir as Az2,copyFile as fz2}from"fs/promises";import{exec as Qz2}from"child_process";import{promisify as wz2}from"util";import{join as vKA,resolve as JKA}from"path";var Bz2=wz2(Qz2);async function kr(A){try{return await ek2(A),!0}catch{return!1}}async function xz2(A,f){if(!await kr(A))return!0;if((await Qj0(A)).filter((B)=>!B.startsWith(".")&&!B.startsWith("_")).length>0)return!1;if(await Iz2(A))return f.debug("Git repository with remote detected - skipping seed content",{path:A}),!1;return!0}async function Iz2(A){let f=vKA(A,".git");if(!await kr(f))return!1;try{let{stdout:Q}=await Bz2("git remote",{cwd:A});return Q.trim().length>0}catch{return!1}}async function wj0(A,f){let Q=await Qj0(A,{withFileTypes:!0});for(let w of Q){let B=vKA(A,w.name),x=vKA(f,w.name);if(w.isDirectory()){if(!await kr(x))await Az2(x,{recursive:!0});await wj0(B,x)}else await fz2(B,x)}}async function Bj0(A,f,Q){let w=JKA(process.cwd(),A);Q=Q?JKA(Q):JKA(process.cwd(),"seed-content");let B=await xz2(w,f);if(B&&await kr(Q))f.debug("Copying seed content to brain-data directory"),await wj0(Q,w),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 $z2(A,f,Q,w=300000){let x=Date.now();while(Date.now()-x<w){let I=await A.jobs.getBatchStatus(f);if(I&&(I.status==="completed"||I.status==="failed")){Q.debug("Batch completed",{batchId:f,status:I.status,completed:I.completedOperations,failed:I.failedOperations});return}await new Promise(($)=>setTimeout($,500))}Q.warn(`Timeout waiting for batch ${f} after ${w}ms`)}function xj0(A,f,Q,w,B,x){let I=!1,$=async()=>{if(I)return;I=!0;let c=f();if(Q.seedContent){let D=Q.syncPath??A.dataDir;await Bj0(D,B,Q.seedContentPath)}try{if(x){B.debug("Git enabled \u2014 pulling before import");let u=await x.pull();if(u.files.length>0)B.info("Pulled changes from remote",{filesChanged:u.files.length})}B.debug("Starting initial sync");let D=await c.queueSyncBatch(A,"initial-sync",void 0,{includeCleanup:!0});if(!D){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:D.importOperationsCount,totalFiles:D.totalFiles}),$z2(A,D.batchId,B).then(()=>A.messaging.send("sync:initial:completed",{success:!0},{broadcast:!0}),(u)=>{B.error("Initial sync batch failed",u),A.messaging.send("sync:initial:completed",{success:!1,error:v0(u)},{broadcast:!0})})}catch(D){B.error("Initial sync failed",D),await A.messaging.send("sync:initial:completed",{success:!1,error:v0(D)},{broadcast:!0})}};A.messaging.subscribe("system:plugins:ready",async()=>{return B.debug("system:plugins:ready received, starting initial sync"),await $(),{success:!0}})}HA();function Ij0(A,f,Q,w){let B=new zF(()=>{f.withLock(async()=>{try{await f.commit(),await f.push()}catch($){w.error("Git auto-commit failed",{error:$})}})},Q),x=["entity:created","entity:updated","entity:deleted"],I=[];for(let $ of x){let c=A.subscribe($,async()=>{return B.trigger(),{success:!0}});I.push(c)}return()=>{B.dispose();for(let $ of I)$()}}function $j0(A,f,Q,w,B){if(w<=0)return()=>{};let x=w*60*1000,I=!1,$=async()=>{if(I)return;I=!0;try{let{files:D}=await A.withLock(()=>A.pull());if(D.length>0)B.info("Periodic sync: pulled changes",{filesChanged:D.length});let u=await f.queueSyncBatch(Q,"periodic-sync");if(u)B.debug("Periodic sync: queued imports",{importOperations:u.importOperationsCount,totalFiles:u.totalFiles})}catch(D){B.error("Periodic git sync failed",{error:D})}finally{I=!1}},c=setInterval(()=>{$()},x);return B.info("Started periodic git sync",{intervalMinutes:w}),()=>{clearInterval(c)}}function cj0(A,f,Q,w,B){let{subscribe:x}=A.messaging;x("entity:export:request",async(I)=>{try{return{success:!0,data:await f().exportEntities(I.payload.entityTypes)}}catch($){return{success:!1,error:$ instanceof Error?$.message:"Export failed"}}}),x("entity:import:request",async(I)=>{try{let $=f(),c=I.payload.paths,D=await $.importEntities(c);if(c&&c.length>0)await $.removeOrphanedEntities();return{success:!0,data:D}}catch($){return{success:!1,error:$ instanceof Error?$.message:"Import failed"}}}),x("sync:status:request",async()=>{try{let $=await f().getStatus();return{success:!0,data:{syncPath:$.syncPath,isInitialized:$.exists,watchEnabled:$.watching}}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Status check failed"}}}),x("sync:configure:request",async(I)=>{try{return await Q({syncPath:I.payload.syncPath}),{success:!0,data:{syncPath:I.payload.syncPath,configured:!0}}}catch($){return{success:!1,error:$ instanceof Error?$.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"}}}),w.debug("Registered message handlers")}B0();HA();B0();HA();function Dj0(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(Q)=>{let w=`${Q.entityType}/${Q.id}.md`;try{if(Q.sha){let x=await f.show(Q.sha,w);return R8({sha:Q.sha,entityType:Q.entityType,id:Q.id,content:x},`Content at ${Q.sha.slice(0,7)}`)}let B=await f.log(w,Q.limit);if(B.length===0)return R8({commits:[]},`No history found for ${Q.entityType}/${Q.id}`);return R8({commits:B,entityType:Q.entityType,id:Q.id},`${B.length} version${B.length===1?"":"s"} found`)}catch(B){return T6(B instanceof Error?B.message:"History lookup failed")}})}function Yj0(A,f,Q,w){let B=[Tf(Q,"sync","Sync brain entities with the filesystem. Pulls from git if configured, then imports files. Git commit and push happen automatically after imports complete.",X.object({}),async(x,I)=>{try{let $=I.channelId?`${I.interfaceType}:${I.channelId}`:`plugin:${Q}`,c={interfaceType:I.interfaceType,channelId:I.channelId},D=!1;if(w)await w.withLock(()=>w.pull()),D=!0;let u=await A.queueSyncBatch(f,$,c);if(!u)return R8({gitPulled:D},"No files to sync");return R8({batchId:u.batchId,importOperations:u.importOperationsCount,totalFiles:u.totalFiles,gitPulled:D},`Sync started: ${u.importOperationsCount} import jobs queued for ${u.totalFiles} files${D?" (pulled from git)":""}`)}catch($){return T6($ instanceof Error?$.message:"Sync failed")}},{cli:{name:"sync"}}),Tf(Q,"status","Get sync and git repository status \u2014 last sync time, watching state, pending git changes.",X.object({}),async()=>{try{let x=await A.getStatus(),I={syncPath:x.syncPath,lastSync:x.lastSync?.toISOString(),watching:x.watching};if(w){let $=await w.getStatus();I.git={isRepo:$.isRepo,branch:$.branch,hasChanges:$.hasChanges,ahead:$.ahead,behind:$.behind,remote:$.remote}}return R8(I)}catch(x){return T6(x instanceof Error?x.message:"Status check failed")}},{visibility:"public"})];if(w)B.push(Dj0(Q,w));return B}var uj0={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.0",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 kKA extends mw{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",uj0,A,pO0)}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:Q}=A;A.templates.register({status:{name:"status",description:"Directory synchronization status",schema:fM,basePrompt:"",formatter:new Kr,requiredPermission:"anchor"}});let w=this.config.syncPath??A.dataDir;this.directorySync=new nV({syncPath:w,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:Q,logger:f});try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:w})}catch(I){throw this.logger.error("Failed to initialize directory",I),I}await this.registerJobHandlers(A);let B=this.requireDirectorySync();if(Aj0(A,B,this.logger,this.config.entityTypes),this.config.autoSync)fj0(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 I=this.config.syncPath??A.dataDir;if(this.gitSync=new WKA({logger:this.logger.child("GitSync"),dataDir:I,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(Ij0(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push($j0(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)xj0(A,()=>this.requireDirectorySync(),this.config,this.id,this.logger,this.gitSync);cj0(A,()=>this.requireDirectorySync(),(I)=>this.configure(I),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return Yj0(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 nV({...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){eO0(A,this.requireDirectorySync(),this.logger)}}function VZ(A={}){return new kKA(A)}B0();B0();HA();HA();var Uj0=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()}),JxQ=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 il0}from"preact-render-to-string";import{h as BW}from"preact";class zKA{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(`
|
|
1953
|
+
`)}}B0();class Fr extends qQ{context;directorySync;constructor(A,f,Q){super(A,{schema:oO0,jobTypeName:"directory-export"});this.context=f,this.directorySync=Q}async process(A,f,Q){this.logger.debug("Processing directory export job",{jobId:f,data:A});let w=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 Q.report({message:`Starting export of ${x.length} entity types`,progress:0,total:x.length});for(let[I,$]of x.entries())await this.exportEntityType($,A.batchSize??100,f,B),await Q.report({message:`Exported ${I+1}/${x.length} entity types (${B.exported} entities)`,progress:I+1,total:x.length});return this.logger.debug("Directory export job completed",{jobId:f,exported:B.exported,failed:B.failed,duration:Date.now()-w}),B}catch(x){throw this.logger.error("Directory export job failed",{jobId:f,error:x}),x}}async exportEntityType(A,f,Q,w){let B=0,x=!0;while(x){let I=await this.context.entityService.listEntities(A,{limit:f,offset:B});if(I.length===0){x=!1;break}let $=I.map(async(c)=>{let D=await this.directorySync.processEntityExport(c);if(D.success)w.exported++;else w.failed++,w.errors.push({entityId:c.id,entityType:A,error:D.error??"Unknown error"});return D});await Promise.all($),this.logger.debug("Export progress",{jobId:Q,entityType:A,processed:B+I.length,exported:w.exported,failed:w.failed}),B+=f,x=I.length===f}}summarizeDataForLog(A){return{entityTypes:A.entityTypes??"all",batchSize:A.batchSize}}}B0();HA();_I();class Xr extends qQ{context;directorySync;constructor(A,f,Q){super(A,{schema:dO0,jobTypeName:"directory-import"});this.context=f,this.directorySync=Q}async process(A,f,Q){this.logger.debug("Processing directory import job",{jobId:f,data:A});let w=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 Q.report({message:`Starting import of ${x.length} files`,progress:0,total:x.length});let I=A.batchSize??100;for(let $=0;$<x.length;$+=I){let c=x.slice($,$+I);await this.importBatch(c,f,B,$,x.length);let D=Math.min($+I,x.length);await Q.report({message:`Imported ${D}/${x.length} files (${B.imported} successful, ${B.failed} failed)`,progress:D,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()-w}),B}catch(x){throw this.logger.error("Directory import job failed",{jobId:f,error:x}),x}}async importBatch(A,f,Q,w,B){let x=A.map(async(I)=>{try{let $=await this.directorySync.fileOps.readEntity(I);if(!this.context.entityService.getEntityTypes().includes($.entityType))return Q.skipped++,{success:!1,skipped:!0};try{let D=this.context.entityService.deserializeEntity($.content,$.entityType),u=await this.context.entityService.getEntity($.entityType,$.id);if(u){let K=new Date(u.updated).getTime(),F=$.updated.getTime(),Z=Bw($.content),J=u.contentHash!==Z;if(K<F||J){let v={...u,content:$.content,...D,id:$.id,entityType:$.entityType,updated:$.updated.toISOString()};await this.context.entityService.updateEntity(v),Q.imported++}else Q.skipped++}else{let K={id:$.id,entityType:$.entityType,content:$.content,...D,metadata:D.metadata??{},created:$.created.toISOString(),updated:$.updated.toISOString()};await this.context.entityService.createEntity(K),Q.imported++}return{success:!0}}catch{return Q.skipped++,{success:!1,skipped:!0}}}catch($){return Q.failed++,Q.errors.push({path:I,error:v0($)}),{success:!1,error:$}}});await Promise.all(x),this.logger.debug("Import progress",{jobId:f,processed:w+A.length,total:B,imported:Q.imported,skipped:Q.skipped,failed:Q.failed})}summarizeDataForLog(A){return{pathCount:A.paths?.length??"all",batchSize:A.batchSize}}}B0();class Zr extends qQ{directorySync;context;constructor(A,f,Q){super(A,{schema:rO0,jobTypeName:"directory-sync"});this.context=f,this.directorySync=Q}async process(A,f,Q){let w=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:[]},I={exported:0,failed:0,errors:[]};if(B!=="export")if(await Q.report({progress:10,message:"Scanning directory for changes"}),x=await this.importWithProgress(A.paths,Q),B==="import")await this.waitForImportJobs(x.jobIds,Q),await Q.report({progress:100,message:`Import complete: ${x.imported} imported`});else await Q.report({progress:50,message:`Imported ${x.imported} entities`}),await this.waitForImportJobs(x.jobIds,Q),await Q.report({progress:56,message:"Processing complete, starting export"});if(B!=="import"){let c=B==="export"?10:60;await Q.report({progress:c,message:"Exporting entities to directory"}),I=await this.exportWithProgress(A.entityTypes,Q),await Q.report({progress:100,message:B==="export"?`Export complete: ${I.exported} exported`:`Sync complete: ${x.imported} imported, ${I.exported} exported`})}let $=Date.now()-w;return this.logger.info("Directory sync job completed",{jobId:f,duration:$,imported:x.imported,exported:I.exported}),{import:x,export:I,duration:$}}async importWithProgress(A,f){try{return await this.directorySync.importEntitiesWithProgress(A,f,10)}catch(Q){throw this.logger.error("Import phase failed",{error:Q}),Q}}async exportWithProgress(A,f){try{return await this.directorySync.exportEntitiesWithProgress(A,f,10)}catch(Q){throw this.logger.error("Export phase failed",{error:Q}),Q}}async waitForImportJobs(A,f){if(A.length===0)return;this.logger.debug(`Waiting for ${A.length} import jobs to complete`);let{entityService:Q}=this.context,w=300000,B=500,x=Date.now(),I=async()=>{let c=(await Promise.all(A.map((u)=>Q.getAsyncJobStatus(u)))).filter((u)=>u&&(u.status==="completed"||u.status==="failed")).length;if(c===A.length){this.logger.debug("All import jobs completed");return}if(Date.now()-x>w){this.logger.warn(`Timeout waiting for import jobs (${c}/${A.length} completed)`);return}let D=Math.round(c/A.length*100);return await f.report({progress:50+Math.round(D*0.05),message:`Processing ${c}/${A.length} entities`}),await new Promise((u)=>setTimeout(u,B)),I()};return I()}summarizeDataForLog(A){return{operation:A.operation,syncDirection:A.syncDirection}}}B0();class Wr extends qQ{context;constructor(A,f,Q){super(A,{schema:GKA,jobTypeName:"directory-delete"});this.context=f}async process(A,f,Q){let w=GKA.parse(A);this.logger.info("Processing entity deletion for removed file",{entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}),await Q.report({progress:0,total:1,message:`Deleting ${w.entityType}:${w.entityId}`});try{let B=await this.context.entityService.deleteEntity(w.entityType,w.entityId);if(B)this.logger.info("Successfully deleted entity for removed file",{entityId:w.entityId,entityType:w.entityType});else this.logger.warn("Entity not found in database",{entityId:w.entityId,entityType:w.entityType});return await Q.report({progress:1,total:1,message:`Deleted ${w.entityType}:${w.entityId}`}),{deleted:B,entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}}catch(B){throw this.logger.error("Failed to delete entity",{entityId:w.entityId,entityType:w.entityType,error:B}),B}}summarizeDataForLog(A){return{entityId:A.entityId,entityType:A.entityType,filePath:A.filePath}}}B0();HA();var nk2=X.object({});class Gr extends qQ{directorySync;constructor(A,f){super(A,{schema:nk2,jobTypeName:"directory-cleanup"});this.directorySync=f}async process(A,f,Q){await Q.report({progress:0,message:"Removing orphaned entities"});let w=await this.directorySync.removeOrphanedEntities();return await Q.report({progress:100,message:`Cleanup complete: ${w.deleted} orphans removed`}),w}}B0();HA();import{readFile as pk2,writeFile as rk2}from"fs/promises";var dk2=X.object({filePath:X.string(),sourceUrl:X.string().url(),postTitle:X.string(),postSlug:X.string(),customAlt:X.string().optional()});class Jr extends qQ{context;fetcher;constructor(A,f,Q=t5){super(f,{schema:dk2,jobTypeName:"cover-image-convert"});this.context=A,this.fetcher=Q}async process(A,f,Q){let{filePath:w,sourceUrl:B,postTitle:x,postSlug:I,customAlt:$}=A;this.logger.debug("Starting image conversion job",{jobId:f,filePath:w,sourceUrl:B,postSlug:I});try{await this.reportProgress(Q,{progress:U2.INIT,message:`Reading file: ${w}`});let c;try{c=await pk2(w,"utf-8")}catch(v){return this.logger.error("Failed to read file",{filePath:w,error:v0(v)}),GB.failure(v)}let D;try{D=JI(c)}catch(v){return this.logger.warn("Failed to parse markdown",{filePath:w,error:v0(v)}),GB.failure(v)}let u=D.frontmatter;if(u.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:w}),await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(Q,{progress:U2.FETCH,message:"Checking for existing image"});let K=await this.context.entityService.listEntities("image",{filter:{metadata:{sourceUrl:B}},limit:1}),F;if(K[0])F=K[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:B,imageId:F}),await this.reportProgress(Q,{progress:U2.EXTRACT,message:`Reusing existing image: ${F}`});else{await this.reportProgress(Q,{progress:U2.PROCESS,message:`Fetching image from ${B}`});let v;try{v=await this.fetcher(B)}catch(r){return this.logger.error("Failed to fetch image",{sourceUrl:B,error:v0(r)}),GB.failure(r)}await this.reportProgress(Q,{progress:U2.GENERATE,message:"Creating image entity"});let{base64:k}=RU(v),q=WX(k),V=PU(k);if(!q||!V)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:B}),GB.failure(Error("Could not detect image format or dimensions"));F=`${I}-cover`;let C=`Cover image for ${x}`,l=$??C;await this.context.entityService.createEntity({id:F,entityType:"image",content:v,metadata:{title:C,alt:l,format:q,width:V.width,height:V.height,sourceUrl:B}}),this.logger.debug("Created image entity",{imageId:F,sourceUrl:B}),await this.reportProgress(Q,{progress:U2.EXTRACT,message:`Created image: ${F}`})}await this.reportProgress(Q,{progress:U2.SAVE,message:"Updating file"});let Z={...u};delete Z.coverImageUrl,delete Z.coverImageAlt,Z.coverImageId=F;let J=GF(Z,D.content);try{await rk2(w,J,"utf-8")}catch(v){return this.logger.error("Failed to write file",{filePath:w,error:v0(v)}),GB.failure(v)}return await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:w,imageId:F,sourceUrl:B}),{success:!0,imageId:F}}catch(c){return this.logger.error("Image conversion job failed",{jobId:f,filePath:w,error:v0(c)}),GB.failure(c)}}summarizeDataForLog(A){return{filePath:A.filePath,sourceUrl:A.sourceUrl,postSlug:A.postSlug}}}B0();HA();import{readFile as ok2,writeFile as ak2}from"fs/promises";class vr extends qQ{converter;constructor(A,f,Q=t5){super(f,{schema:aO0,jobTypeName:"inline-image-convert"});this.converter=new lV(A.entityService,f,Q)}async process(A,f,Q){let{filePath:w,postSlug:B}=A;this.logger.debug("Starting inline image conversion job",{jobId:f,filePath:w,postSlug:B});try{await this.reportProgress(Q,{progress:U2.INIT,message:`Reading file: ${w}`});let x;try{x=await ok2(w,"utf-8")}catch(c){let D=v0(c);return this.logger.error("Failed to read file",{filePath:w,error:D}),{success:!1,error:D}}await this.reportProgress(Q,{progress:U2.FETCH,message:"Detecting inline images"});let I=this.converter.detectInlineImages(x,B);if(I.length===0)return this.logger.debug("No inline images to convert",{filePath:w}),await this.reportProgress(Q,{progress:U2.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:w,count:I.length}),await this.reportProgress(Q,{progress:U2.PROCESS,message:`Converting ${I.length} images`});let $=await this.converter.convert(x,B);if(!$.converted)return this.logger.debug("No images were converted",{filePath:w}),await this.reportProgress(Q,{progress:U2.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(Q,{progress:U2.SAVE,message:"Writing updated file"});try{await ak2(w,$.content,"utf-8")}catch(c){let D=v0(c);return this.logger.error("Failed to write file",{filePath:w,error:D}),{success:!1,error:D}}return await this.reportProgress(Q,{progress:U2.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:w,convertedCount:$.convertedCount}),{success:!0,convertedCount:$.convertedCount}}catch(x){let I=v0(x);return this.logger.error("Inline image conversion job failed",{jobId:f,filePath:w,error:I}),{success:!1,error:I}}}summarizeDataForLog(A){return{filePath:A.filePath,postSlug:A.postSlug}}}function eO0(A,f,Q){let w=(B)=>Q.child(B);A.jobs.registerHandler("directory-sync",new Zr(w("DirectorySyncJobHandler"),A,f)),A.jobs.registerHandler("directory-export",new Fr(w("DirectoryExportJobHandler"),A,f)),A.jobs.registerHandler("directory-import",new Xr(w("DirectoryImportJobHandler"),A,f)),A.jobs.registerHandler("directory-delete",new Wr(w("DirectoryDeleteJobHandler"),A,f)),A.jobs.registerHandler("directory-cleanup",new Gr(w("DirectoryCleanupJobHandler"),f)),A.jobs.registerHandler("cover-image-convert",new Jr(A,w("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new vr(A,w("InlineImageConversionJobHandler"))),Q.debug("Registered async job handlers")}B0();import{unlink as sk2,access as tk2}from"fs/promises";function Aj0(A,f,Q,w){let{subscribe:B}=A.messaging,{entityService:x}=A;B("entity:created",async(I)=>{let{entity:$}=I.payload;try{await f.fileOps.writeEntity($),Q.debug("Auto-exported created entity",{id:$.id,entityType:$.entityType})}catch(c){Q.error("Auto-export FAILED for created entity",{id:$.id,entityType:$.entityType,error:c instanceof Error?c.message:String(c),stack:c instanceof Error?c.stack:void 0})}return{success:!0}}),B("entity:updated",async(I)=>{let{entityType:$,entityId:c}=I.payload;try{let D=await x.getEntity($,c);if(!D)return Q.debug("Entity not found in DB, skipping export",{entityType:$,entityId:c}),{success:!1};await f.fileOps.writeEntity(D),Q.debug("Auto-exported updated entity",{id:D.id,entityType:D.entityType})}catch(D){Q.error("Auto-export FAILED for updated entity",{entityType:$,entityId:c,error:D instanceof Error?D.message:String(D),stack:D instanceof Error?D.stack:void 0})}return{success:!0}}),B("entity:deleted",async(I)=>{let{entityId:$,entityType:c}=I.payload,D=f.fileOps.getFilePath($,c);if(await tk2(D).then(()=>!0,()=>!1))await sk2(D),Q.debug("Auto-deleted entity file",{id:$,entityType:c,path:D});return{success:!0}}),Q.debug("Setup auto-sync for entity events",{entityTypes:w})}function fj0(A,f,Q){f.setJobQueueCallback(async(w)=>{let B=[{type:w.type,data:w.data}];return A.jobs.enqueueBatch(B,{priority:5,source:"directory-sync-watcher",rootJobId:iB(),metadata:{operationType:"file_operations",operationTarget:Q,pluginId:"directory-sync"}})})}HA();import{access as ek2,readdir as Qj0,mkdir as Az2,copyFile as fz2}from"fs/promises";import{exec as Qz2}from"child_process";import{promisify as wz2}from"util";import{join as vKA,resolve as JKA}from"path";var Bz2=wz2(Qz2);async function kr(A){try{return await ek2(A),!0}catch{return!1}}async function xz2(A,f){if(!await kr(A))return!0;if((await Qj0(A)).filter((B)=>!B.startsWith(".")&&!B.startsWith("_")).length>0)return!1;if(await Iz2(A))return f.debug("Git repository with remote detected - skipping seed content",{path:A}),!1;return!0}async function Iz2(A){let f=vKA(A,".git");if(!await kr(f))return!1;try{let{stdout:Q}=await Bz2("git remote",{cwd:A});return Q.trim().length>0}catch{return!1}}async function wj0(A,f){let Q=await Qj0(A,{withFileTypes:!0});for(let w of Q){let B=vKA(A,w.name),x=vKA(f,w.name);if(w.isDirectory()){if(!await kr(x))await Az2(x,{recursive:!0});await wj0(B,x)}else await fz2(B,x)}}async function Bj0(A,f,Q){let w=JKA(process.cwd(),A);Q=Q?JKA(Q):JKA(process.cwd(),"seed-content");let B=await xz2(w,f);if(B&&await kr(Q))f.debug("Copying seed content to brain-data directory"),await wj0(Q,w),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 $z2(A,f,Q,w=300000){let x=Date.now();while(Date.now()-x<w){let I=await A.jobs.getBatchStatus(f);if(I&&(I.status==="completed"||I.status==="failed")){Q.debug("Batch completed",{batchId:f,status:I.status,completed:I.completedOperations,failed:I.failedOperations});return}await new Promise(($)=>setTimeout($,500))}Q.warn(`Timeout waiting for batch ${f} after ${w}ms`)}function xj0(A,f,Q,w,B,x){let I=!1,$=async()=>{if(I)return;I=!0;let c=f();if(Q.seedContent){let D=Q.syncPath??A.dataDir;await Bj0(D,B,Q.seedContentPath)}try{if(x){B.debug("Git enabled \u2014 pulling before import");let u=await x.pull();if(u.files.length>0)B.info("Pulled changes from remote",{filesChanged:u.files.length})}B.debug("Starting initial sync");let D=await c.queueSyncBatch(A,"initial-sync",void 0,{includeCleanup:!0});if(!D){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:D.importOperationsCount,totalFiles:D.totalFiles}),$z2(A,D.batchId,B).then(()=>A.messaging.send("sync:initial:completed",{success:!0},{broadcast:!0}),(u)=>{B.error("Initial sync batch failed",u),A.messaging.send("sync:initial:completed",{success:!1,error:v0(u)},{broadcast:!0})})}catch(D){B.error("Initial sync failed",D),await A.messaging.send("sync:initial:completed",{success:!1,error:v0(D)},{broadcast:!0})}};A.messaging.subscribe("system:plugins:ready",async()=>{return B.debug("system:plugins:ready received, starting initial sync"),await $(),{success:!0}})}HA();function Ij0(A,f,Q,w){let B=new zF(()=>{f.withLock(async()=>{try{await f.commit(),await f.push()}catch($){w.error("Git auto-commit failed",{error:$})}})},Q),x=["entity:created","entity:updated","entity:deleted"],I=[];for(let $ of x){let c=A.subscribe($,async()=>{return B.trigger(),{success:!0}});I.push(c)}return()=>{B.dispose();for(let $ of I)$()}}function $j0(A,f,Q,w,B){if(w<=0)return()=>{};let x=w*60*1000,I=!1,$=async()=>{if(I)return;I=!0;try{let{files:D}=await A.withLock(()=>A.pull());if(D.length>0)B.info("Periodic sync: pulled changes",{filesChanged:D.length});let u=await f.queueSyncBatch(Q,"periodic-sync");if(u)B.debug("Periodic sync: queued imports",{importOperations:u.importOperationsCount,totalFiles:u.totalFiles})}catch(D){B.error("Periodic git sync failed",{error:D})}finally{I=!1}},c=setInterval(()=>{$()},x);return B.info("Started periodic git sync",{intervalMinutes:w}),()=>{clearInterval(c)}}function cj0(A,f,Q,w,B){let{subscribe:x}=A.messaging;x("entity:export:request",async(I)=>{try{return{success:!0,data:await f().exportEntities(I.payload.entityTypes)}}catch($){return{success:!1,error:$ instanceof Error?$.message:"Export failed"}}}),x("entity:import:request",async(I)=>{try{let $=f(),c=I.payload.paths,D=await $.importEntities(c);if(c&&c.length>0)await $.removeOrphanedEntities();return{success:!0,data:D}}catch($){return{success:!1,error:$ instanceof Error?$.message:"Import failed"}}}),x("sync:status:request",async()=>{try{let $=await f().getStatus();return{success:!0,data:{syncPath:$.syncPath,isInitialized:$.exists,watchEnabled:$.watching}}}catch(I){return{success:!1,error:I instanceof Error?I.message:"Status check failed"}}}),x("sync:configure:request",async(I)=>{try{return await Q({syncPath:I.payload.syncPath}),{success:!0,data:{syncPath:I.payload.syncPath,configured:!0}}}catch($){return{success:!1,error:$ instanceof Error?$.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"}}}),w.debug("Registered message handlers")}B0();HA();B0();HA();function Dj0(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(Q)=>{let w=`${Q.entityType}/${Q.id}.md`;try{if(Q.sha){let x=await f.show(Q.sha,w);return R8({sha:Q.sha,entityType:Q.entityType,id:Q.id,content:x},`Content at ${Q.sha.slice(0,7)}`)}let B=await f.log(w,Q.limit);if(B.length===0)return R8({commits:[]},`No history found for ${Q.entityType}/${Q.id}`);return R8({commits:B,entityType:Q.entityType,id:Q.id},`${B.length} version${B.length===1?"":"s"} found`)}catch(B){return T6(B instanceof Error?B.message:"History lookup failed")}})}function Yj0(A,f,Q,w){let B=[Tf(Q,"sync","Sync brain entities with the filesystem. Pulls from git if configured, then imports files. Git commit and push happen automatically after imports complete.",X.object({}),async(x,I)=>{try{let $=I.channelId?`${I.interfaceType}:${I.channelId}`:`plugin:${Q}`,c={interfaceType:I.interfaceType,channelId:I.channelId},D=!1;if(w)await w.withLock(()=>w.pull()),D=!0;let u=await A.queueSyncBatch(f,$,c);if(!u)return R8({gitPulled:D},"No files to sync");return R8({batchId:u.batchId,importOperations:u.importOperationsCount,totalFiles:u.totalFiles,gitPulled:D},`Sync started: ${u.importOperationsCount} import jobs queued for ${u.totalFiles} files${D?" (pulled from git)":""}`)}catch($){return T6($ instanceof Error?$.message:"Sync failed")}},{cli:{name:"sync"}}),Tf(Q,"status","Get sync and git repository status \u2014 last sync time, watching state, pending git changes.",X.object({}),async()=>{try{let x=await A.getStatus(),I={syncPath:x.syncPath,lastSync:x.lastSync?.toISOString(),watching:x.watching};if(w){let $=await w.getStatus();I.git={isRepo:$.isRepo,branch:$.branch,hasChanges:$.hasChanges,ahead:$.ahead,behind:$.behind,remote:$.remote}}return R8(I)}catch(x){return T6(x instanceof Error?x.message:"Status check failed")}},{visibility:"public"})];if(w)B.push(Dj0(Q,w));return B}var uj0={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.1",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 kKA extends mw{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",uj0,A,pO0)}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:Q}=A;A.templates.register({status:{name:"status",description:"Directory synchronization status",schema:fM,basePrompt:"",formatter:new Kr,requiredPermission:"anchor"}});let w=this.config.syncPath??A.dataDir;this.directorySync=new nV({syncPath:w,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:Q,logger:f});try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:w})}catch(I){throw this.logger.error("Failed to initialize directory",I),I}await this.registerJobHandlers(A);let B=this.requireDirectorySync();if(Aj0(A,B,this.logger,this.config.entityTypes),this.config.autoSync)fj0(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 I=this.config.syncPath??A.dataDir;if(this.gitSync=new WKA({logger:this.logger.child("GitSync"),dataDir:I,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(Ij0(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push($j0(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)xj0(A,()=>this.requireDirectorySync(),this.config,this.id,this.logger,this.gitSync);cj0(A,()=>this.requireDirectorySync(),(I)=>this.configure(I),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return Yj0(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 nV({...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){eO0(A,this.requireDirectorySync(),this.logger)}}function VZ(A={}){return new kKA(A)}B0();B0();HA();HA();var Uj0=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()}),JxQ=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 il0}from"preact-render-to-string";import{h as BW}from"preact";class zKA{headProps=null;defaultTitle;constructor(A){this.defaultTitle=A}setHeadProps(A){this.headProps??=A}getHeadProps(){return this.headProps}reset(){this.headProps=null}generateHeadHTML(){let A=[];if(A.push('<meta charset="UTF-8">'),A.push('<meta name="viewport" content="width=device-width, initial-scale=1.0">'),A.push('<meta http-equiv="X-UA-Compatible" content="IE=edge">'),A.push('<link rel="icon" type="image/svg+xml" href="/favicon.svg">'),A.push('<link rel="icon" type="image/png" href="/favicon.png">'),A.push('<link rel="stylesheet" href="/styles/main.css">'),!this.headProps)return A.push(`<title>${this.escapeHtml(this.defaultTitle)}</title>`),A.join(`
|
|
1954
1954
|
`);let{title:f,description:Q,ogImage:w,ogType:B,twitterCard:x,canonicalUrl:I}=this.headProps;if(A.push(`<title>${this.escapeHtml(f)}</title>`),Q)A.push(`<meta name="description" content="${this.escapeHtml(Q)}">`);if(A.push(`<meta property="og:title" content="${this.escapeHtml(f)}">`),Q)A.push(`<meta property="og:description" content="${this.escapeHtml(Q)}">`);if(A.push(`<meta property="og:type" content="${B??"website"}">`),w)A.push(`<meta property="og:image" content="${this.escapeHtml(w)}">`);if(A.push(`<meta name="twitter:card" content="${x??"summary_large_image"}">`),A.push(`<meta name="twitter:title" content="${this.escapeHtml(f)}">`),Q)A.push(`<meta name="twitter:description" content="${this.escapeHtml(Q)}">`);if(w)A.push(`<meta name="twitter:image" content="${this.escapeHtml(w)}">`);if(I)A.push(`<link rel="canonical" href="${this.escapeHtml(I)}">`);return A.join(`
|
|
1955
1955
|
`)}escapeHtml(A){let f={"&":"&","<":"<",">":">",'"':""","'":"'"};return A.replace(/[&<>"']/g,(Q)=>f[Q]??Q)}}function Hj0(A){var f,Q,w="";if(typeof A=="string"||typeof A=="number")w+=A;else if(typeof A=="object")if(Array.isArray(A)){var B=A.length;for(f=0;f<B;f++)A[f]&&(Q=Hj0(A[f]))&&(w&&(w+=" "),w+=Q)}else for(Q in A)A[Q]&&(w&&(w+=" "),w+=Q);return w}function zr(){for(var A,f,Q=0,w="",B=arguments.length;Q<B;Q++)(A=arguments[Q])&&(f=Hj0(A))&&(w&&(w+=" "),w+=f);return w}var Dz2=(A)=>{let f=uz2(A),{conflictingClassGroups:Q,conflictingClassGroupModifiers:w}=A;return{getClassGroupId:(I)=>{let $=I.split("-");if($[0]===""&&$.length!==1)$.shift();return Wj0($,f)||Yz2(I)},getConflictingClassGroupIds:(I,$)=>{let c=Q[I]||[];if($&&w[I])return[...c,...w[I]];return c}}},Wj0=(A,f)=>{if(A.length===0)return f.classGroupId;let Q=A[0],w=f.nextPart.get(Q),B=w?Wj0(A.slice(1),w):void 0;if(B)return B;if(f.validators.length===0)return;let x=A.join("-");return f.validators.find(({validator:I})=>I(x))?.classGroupId},Kj0=/^\[(.+)\]$/,Yz2=(A)=>{if(Kj0.test(A)){let f=Kj0.exec(A)[1],Q=f?.substring(0,f.indexOf(":"));if(Q)return"arbitrary.."+Q}},uz2=(A)=>{let{theme:f,prefix:Q}=A,w={nextPart:new Map,validators:[]};return Hz2(Object.entries(A.classGroups),Q).forEach(([x,I])=>{EKA(I,w,x,f)}),w},EKA=(A,f,Q,w)=>{A.forEach((B)=>{if(typeof B==="string"){let x=B===""?f:Fj0(f,B);x.classGroupId=Q;return}if(typeof B==="function"){if(Uz2(B)){EKA(B(w),f,Q,w);return}f.validators.push({validator:B,classGroupId:Q});return}Object.entries(B).forEach(([x,I])=>{EKA(I,Fj0(f,x),Q,w)})})},Fj0=(A,f)=>{let Q=A;return f.split("-").forEach((w)=>{if(!Q.nextPart.has(w))Q.nextPart.set(w,{nextPart:new Map,validators:[]});Q=Q.nextPart.get(w)}),Q},Uz2=(A)=>A.isThemeGetter,Hz2=(A,f)=>{if(!f)return A;return A.map(([Q,w])=>{let B=w.map((x)=>{if(typeof x==="string")return f+x;if(typeof x==="object")return Object.fromEntries(Object.entries(x).map(([I,$])=>[f+I,$]));return x});return[Q,B]})},Kz2=(A)=>{if(A<1)return{get:()=>{return},set:()=>{}};let f=0,Q=new Map,w=new Map,B=(x,I)=>{if(Q.set(x,I),f++,f>A)f=0,w=Q,Q=new Map};return{get(x){let I=Q.get(x);if(I!==void 0)return I;if((I=w.get(x))!==void 0)return B(x,I),I},set(x,I){if(Q.has(x))Q.set(x,I);else B(x,I)}}};var Fz2=(A)=>{let{separator:f,experimentalParseClassName:Q}=A,w=f.length===1,B=f[0],x=f.length,I=($)=>{let c=[],D=0,u=0,K;for(let k=0;k<$.length;k++){let q=$[k];if(D===0){if(q===B&&(w||$.slice(k,k+x)===f)){c.push($.slice(u,k)),u=k+x;continue}if(q==="/"){K=k;continue}}if(q==="[")D++;else if(q==="]")D--}let F=c.length===0?$:$.substring(u),Z=F.startsWith("!"),J=Z?F.substring(1):F,v=K&&K>u?K-u:void 0;return{modifiers:c,hasImportantModifier:Z,baseClassName:J,maybePostfixModifierPosition:v}};if(Q)return($)=>Q({className:$,parseClassName:I});return I},Xz2=(A)=>{if(A.length<=1)return A;let f=[],Q=[];return A.forEach((w)=>{if(w[0]==="[")f.push(...Q.sort(),w),Q=[];else Q.push(w)}),f.push(...Q.sort()),f},Zz2=(A)=>({cache:Kz2(A.cacheSize),parseClassName:Fz2(A),...Dz2(A)}),Wz2=/\s+/,Gz2=(A,f)=>{let{parseClassName:Q,getClassGroupId:w,getConflictingClassGroupIds:B}=f,x=[],I=A.trim().split(Wz2),$="";for(let c=I.length-1;c>=0;c-=1){let D=I[c],{modifiers:u,hasImportantModifier:K,baseClassName:F,maybePostfixModifierPosition:Z}=Q(D),J=Boolean(Z),v=w(J?F.substring(0,Z):F);if(!v){if(!J){$=D+($.length>0?" "+$:$);continue}if(v=w(F),!v){$=D+($.length>0?" "+$:$);continue}J=!1}let k=Xz2(u).join(":"),q=K?k+"!":k,V=q+v;if(x.includes(V))continue;x.push(V);let C=B(v,J);for(let l=0;l<C.length;++l){let r=C[l];x.push(q+r)}$=D+($.length>0?" "+$:$)}return $};function Jz2(){let A=0,f,Q,w="";while(A<arguments.length)if(f=arguments[A++]){if(Q=Gj0(f))w&&(w+=" "),w+=Q}return w}var Gj0=(A)=>{if(typeof A==="string")return A;let f,Q="";for(let w=0;w<A.length;w++)if(A[w]){if(f=Gj0(A[w]))Q&&(Q+=" "),Q+=f}return Q};function Xj0(A,...f){let Q,w,B,x=I;function I(c){let D=f.reduce((u,K)=>K(u),A());return Q=Zz2(D),w=Q.cache.get,B=Q.cache.set,x=$,$(c)}function $(c){let D=w(c);if(D)return D;let u=Gz2(c,Q);return B(c,u),u}return function(){return x(Jz2.apply(null,arguments))}}var qw=(A)=>{let f=(Q)=>Q[A]||[];return f.isThemeGetter=!0,f},Jj0=/^\[(?:([a-z-]+):)?(.+)\]$/i,vz2=/^\d+\/\d+$/,kz2=new Set(["px","full","screen"]),zz2=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,Nz2=/\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$/,Ez2=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,hz2=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,bz2=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,kY=(A)=>yz(A)||kz2.has(A)||vz2.test(A),VH=(A)=>lz(A,"length",jz2),yz=(A)=>Boolean(A)&&!Number.isNaN(Number(A)),NKA=(A)=>lz(A,"number",yz),QM=(A)=>Boolean(A)&&Number.isInteger(Number(A)),Lz2=(A)=>A.endsWith("%")&&yz(A.slice(0,-1)),xf=(A)=>Jj0.test(A),MH=(A)=>zz2.test(A),qz2=new Set(["length","size","percentage"]),Cz2=(A)=>lz(A,qz2,vj0),_z2=(A)=>lz(A,"position",vj0),Vz2=new Set(["image","url"]),Mz2=(A)=>lz(A,Vz2,Pz2),Oz2=(A)=>lz(A,"",Rz2),wM=()=>!0,lz=(A,f,Q)=>{let w=Jj0.exec(A);if(w){if(w[1])return typeof f==="string"?w[1]===f:f.has(w[1]);return Q(w[2])}return!1},jz2=(A)=>Nz2.test(A)&&!Ez2.test(A),vj0=()=>!1,Rz2=(A)=>hz2.test(A),Pz2=(A)=>bz2.test(A);var Zj0=()=>{let A=qw("colors"),f=qw("spacing"),Q=qw("blur"),w=qw("brightness"),B=qw("borderColor"),x=qw("borderRadius"),I=qw("borderSpacing"),$=qw("borderWidth"),c=qw("contrast"),D=qw("grayscale"),u=qw("hueRotate"),K=qw("invert"),F=qw("gap"),Z=qw("gradientColorStops"),J=qw("gradientColorStopPositions"),v=qw("inset"),k=qw("margin"),q=qw("opacity"),V=qw("padding"),C=qw("saturate"),l=qw("scale"),r=qw("sepia"),P=qw("skew"),O=qw("space"),R=qw("translate"),g=()=>["auto","contain","none"],t=()=>["auto","hidden","clip","visible","scroll"],S=()=>["auto",xf,f],YA=()=>[xf,f],IA=()=>["",kY,VH],_=()=>["auto",yz,xf],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",xf],d=()=>["auto","avoid","all","avoid-page","page","left","right","column"],uA=()=>[yz,xf];return{cacheSize:500,separator:":",theme:{colors:[wM],spacing:[kY,VH],blur:["none","",MH,xf],brightness:uA(),borderColor:[A],borderRadius:["none","","full",MH,xf],borderSpacing:YA(),borderWidth:IA(),contrast:uA(),grayscale:e(),hueRotate:uA(),invert:e(),gap:YA(),gradientColorStops:[A],gradientColorStopPositions:[Lz2,VH],inset:S(),margin:S(),opacity:uA(),padding:YA(),saturate:uA(),scale:uA(),sepia:e(),skew:uA(),space:YA(),translate:YA()},classGroups:{aspect:[{aspect:["auto","square","video",xf]}],container:["container"],columns:[{columns:[MH]}],"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(),xf]}],overflow:[{overflow:t()}],"overflow-x":[{"overflow-x":t()}],"overflow-y":[{"overflow-y":t()}],overscroll:[{overscroll:g()}],"overscroll-x":[{"overscroll-x":g()}],"overscroll-y":[{"overscroll-y":g()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[v]}],"inset-x":[{"inset-x":[v]}],"inset-y":[{"inset-y":[v]}],start:[{start:[v]}],end:[{end:[v]}],top:[{top:[v]}],right:[{right:[v]}],bottom:[{bottom:[v]}],left:[{left:[v]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",QM,xf]}],basis:[{basis:S()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",xf]}],grow:[{grow:e()}],shrink:[{shrink:e()}],order:[{order:["first","last","none",QM,xf]}],"grid-cols":[{"grid-cols":[wM]}],"col-start-end":[{col:["auto",{span:["full",QM,xf]},xf]}],"col-start":[{"col-start":_()}],"col-end":[{"col-end":_()}],"grid-rows":[{"grid-rows":[wM]}],"row-start-end":[{row:["auto",{span:[QM,xf]},xf]}],"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",xf]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",xf]}],gap:[{gap:[F]}],"gap-x":[{"gap-x":[F]}],"gap-y":[{"gap-y":[F]}],"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:[k]}],mx:[{mx:[k]}],my:[{my:[k]}],ms:[{ms:[k]}],me:[{me:[k]}],mt:[{mt:[k]}],mr:[{mr:[k]}],mb:[{mb:[k]}],ml:[{ml:[k]}],"space-x":[{"space-x":[O]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[O]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",xf,f]}],"min-w":[{"min-w":[xf,f,"min","max","fit"]}],"max-w":[{"max-w":[xf,f,"none","full","min","max","fit","prose",{screen:[MH]},MH]}],h:[{h:[xf,f,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[xf,f,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[xf,f,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[xf,f,"auto","min","max","fit"]}],"font-size":[{text:["base",MH,VH]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",NKA]}],"font-family":[{font:[wM]}],"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",xf]}],"line-clamp":[{"line-clamp":["none",yz,NKA]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",kY,xf]}],"list-image":[{"list-image":["none",xf]}],"list-style-type":[{list:["none","disc","decimal",xf]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[A]}],"placeholder-opacity":[{"placeholder-opacity":[q]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[A]}],"text-opacity":[{"text-opacity":[q]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...M(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",kY,VH]}],"underline-offset":[{"underline-offset":["auto",kY,xf]}],"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:YA()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",xf]}],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",xf]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[q]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...L(),_z2]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",Cz2]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},Mz2]}],"bg-color":[{bg:[A]}],"gradient-from-pos":[{from:[J]}],"gradient-via-pos":[{via:[J]}],"gradient-to-pos":[{to:[J]}],"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:[$]}],"border-w-x":[{"border-x":[$]}],"border-w-y":[{"border-y":[$]}],"border-w-s":[{"border-s":[$]}],"border-w-e":[{"border-e":[$]}],"border-w-t":[{"border-t":[$]}],"border-w-r":[{"border-r":[$]}],"border-w-b":[{"border-b":[$]}],"border-w-l":[{"border-l":[$]}],"border-opacity":[{"border-opacity":[q]}],"border-style":[{border:[...M(),"hidden"]}],"divide-x":[{"divide-x":[$]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[$]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[q]}],"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":[kY,xf]}],"outline-w":[{outline:[kY,VH]}],"outline-color":[{outline:[A]}],"ring-w":[{ring:IA()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[A]}],"ring-opacity":[{"ring-opacity":[q]}],"ring-offset-w":[{"ring-offset":[kY,VH]}],"ring-offset-color":[{"ring-offset":[A]}],shadow:[{shadow:["","inner","none",MH,Oz2]}],"shadow-color":[{shadow:[wM]}],opacity:[{opacity:[q]}],"mix-blend":[{"mix-blend":[...a(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":a()}],filter:[{filter:["","none"]}],blur:[{blur:[Q]}],brightness:[{brightness:[w]}],contrast:[{contrast:[c]}],"drop-shadow":[{"drop-shadow":["","none",MH,xf]}],grayscale:[{grayscale:[D]}],"hue-rotate":[{"hue-rotate":[u]}],invert:[{invert:[K]}],saturate:[{saturate:[C]}],sepia:[{sepia:[r]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[Q]}],"backdrop-brightness":[{"backdrop-brightness":[w]}],"backdrop-contrast":[{"backdrop-contrast":[c]}],"backdrop-grayscale":[{"backdrop-grayscale":[D]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[u]}],"backdrop-invert":[{"backdrop-invert":[K]}],"backdrop-opacity":[{"backdrop-opacity":[q]}],"backdrop-saturate":[{"backdrop-saturate":[C]}],"backdrop-sepia":[{"backdrop-sepia":[r]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[I]}],"border-spacing-x":[{"border-spacing-x":[I]}],"border-spacing-y":[{"border-spacing-y":[I]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",xf]}],duration:[{duration:uA()}],ease:[{ease:["linear","in","out","in-out",xf]}],delay:[{delay:uA()}],animate:[{animate:["none","spin","ping","pulse","bounce",xf]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[l]}],"scale-x":[{"scale-x":[l]}],"scale-y":[{"scale-y":[l]}],rotate:[{rotate:[QM,xf]}],"translate-x":[{"translate-x":[R]}],"translate-y":[{"translate-y":[R]}],"skew-x":[{"skew-x":[P]}],"skew-y":[{"skew-y":[P]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",xf]}],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",xf]}],"caret-color":[{caret:[A]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":YA()}],"scroll-mx":[{"scroll-mx":YA()}],"scroll-my":[{"scroll-my":YA()}],"scroll-ms":[{"scroll-ms":YA()}],"scroll-me":[{"scroll-me":YA()}],"scroll-mt":[{"scroll-mt":YA()}],"scroll-mr":[{"scroll-mr":YA()}],"scroll-mb":[{"scroll-mb":YA()}],"scroll-ml":[{"scroll-ml":YA()}],"scroll-p":[{"scroll-p":YA()}],"scroll-px":[{"scroll-px":YA()}],"scroll-py":[{"scroll-py":YA()}],"scroll-ps":[{"scroll-ps":YA()}],"scroll-pe":[{"scroll-pe":YA()}],"scroll-pt":[{"scroll-pt":YA()}],"scroll-pr":[{"scroll-pr":YA()}],"scroll-pb":[{"scroll-pb":YA()}],"scroll-pl":[{"scroll-pl":YA()}],"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",xf]}],fill:[{fill:[A,"none"]}],"stroke-w":[{stroke:[kY,VH,NKA]}],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"]}}},gz2=(A,{cacheSize:f,prefix:Q,separator:w,experimentalParseClassName:B,extend:x={},override:I={}})=>{BM(A,"cacheSize",f),BM(A,"prefix",Q),BM(A,"separator",w),BM(A,"experimentalParseClassName",B);for(let $ in I)iz2(A[$],I[$]);for(let $ in x)Tz2(A[$],x[$]);return A},BM=(A,f,Q)=>{if(Q!==void 0)A[f]=Q},iz2=(A,f)=>{if(f)for(let Q in f)BM(A,Q,f[Q])},Tz2=(A,f)=>{if(f)for(let Q in f){let w=f[Q];if(w!==void 0)A[Q]=(A[Q]||[]).concat(w)}},kj0=(A,...f)=>typeof A==="function"?Xj0(Zj0,A,...f):Xj0(()=>gz2(Zj0(),A),...f);var mz2=kj0({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 b1(...A){return mz2(zr(A))}var zj0=(A)=>typeof A==="boolean"?`${A}`:A===0?"0":A,Nj0=zr,dQ=(A,f)=>(Q)=>{var w;if((f===null||f===void 0?void 0:f.variants)==null)return Nj0(A,Q===null||Q===void 0?void 0:Q.class,Q===null||Q===void 0?void 0:Q.className);let{variants:B,defaultVariants:x}=f,I=Object.keys(B).map((D)=>{let u=Q===null||Q===void 0?void 0:Q[D],K=x===null||x===void 0?void 0:x[D];if(u===null)return null;let F=zj0(u)||zj0(K);return B[D][F]}),$=Q&&Object.entries(Q).reduce((D,u)=>{let[K,F]=u;if(F===void 0)return D;return D[K]=F,D},{}),c=f===null||f===void 0?void 0:(w=f.compoundVariants)===null||w===void 0?void 0:w.reduce((D,u)=>{let{class:K,className:F,...Z}=u;return Object.entries(Z).every((J)=>{let[v,k]=J;return Array.isArray(k)?k.includes({...x,...$}[v]):{...x,...$}[v]===k})?[...D,K,F]:D},[]);return Nj0(A,I,c,Q===null||Q===void 0?void 0:Q.class,Q===null||Q===void 0?void 0:Q.className)};import{jsxDEV as hKA}from"preact/jsx-dev-runtime";var Ej0=dQ("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 bKA({variant:A,title:f,children:Q,className:w}){return hKA("div",{className:b1(Ej0({variant:A}),w),role:"alert",children:[f&&hKA("p",{className:"font-medium text-current opacity-90",children:f},void 0,!1,void 0,this),hKA("div",{className:b1(f&&"mt-1","text-sm text-current opacity-75"),children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as Sz2}from"preact/jsx-dev-runtime";var hj0=dQ("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 MZ({variant:A,size:f,className:Q,children:w,ssrOnClick:B,type:x="button",...I}){return Sz2("button",{type:x,className:b1(hj0({variant:A,size:f}),Q),...I,...B&&{onclick:B},children:w},void 0,!1,void 0,this)}import{jsxDEV as yz2}from"preact/jsx-dev-runtime";var bj0=dQ("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 h8({href:A,children:f,variant:Q,size:w,external:B=!1,className:x,"aria-label":I}){let $=B?{target:"_blank",rel:"noopener noreferrer"}:{};return yz2("a",{href:A,className:b1(bj0({variant:Q,size:w}),x),"aria-label":I,...$,children:f},void 0,!1,void 0,this)}import{jsxDEV as Nr}from"preact/jsx-dev-runtime";var Lj0=dQ("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"}}),lz2={sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6"};function nz({variant:A,size:f,className:Q}){let w=lz2[f??"md"];return Nr("button",{onclick:"toggleTheme()",type:"button",className:b1(Lj0({variant:A,size:f}),Q),"aria-label":"Toggle dark mode",children:Nr("svg",{className:b1(w,"transition-colors"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:[Nr("path",{className:"sun-icon",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"},void 0,!1,void 0,this),Nr("path",{className:"moon-icon",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z",transform:"rotate(45 12 12)"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}import{jsxDEV as LKA}from"preact/jsx-dev-runtime";var qj0=dQ("flex flex-wrap",{variants:{orientation:{horizontal:"justify-center gap-6 items-center",vertical:"flex-col gap-2.5"}},defaultVariants:{orientation:"horizontal"}});function Er({items:A,className:f,linkClassName:Q="hover:text-accent transition-colors",orientation:w,children:B}){if(A.length===0&&!B)return null;let x=[...A].sort((I,$)=>I.priority-$.priority);return LKA("ul",{className:b1(qj0({orientation:w}),f),children:[x.map((I)=>LKA("li",{children:LKA("a",{href:I.href,className:Q,children:I.label},void 0,!1,void 0,this)},I.href,!1,void 0,this)),B]},void 0,!0,void 0,this)}import{jsxDEV as sxQ}from"preact/jsx-dev-runtime";import{jsxDEV as A7Q}from"preact/jsx-dev-runtime";HA();HA();import{createContext as nz2,h as pz2}from"preact";import{useContext as rz2}from"preact/hooks";var Cj0=nz2(null);function hr({imageRenderer:A,children:f}){return pz2(Cj0.Provider,{value:A??null},f)}function _j0(){return rz2(Cj0)}function OZ(){let A=_j0();return(f)=>JP(f,A?{imageRenderer:A}:void 0)}import{jsxDEV as zY}from"preact/jsx-dev-runtime";var qKA=({markdown:A})=>{let f=OZ(),w=A.split(/^---$/gm).map((I)=>I.trim()).map((I)=>{let{attributes:$,markdown:c}=TP(I),D=mP(c),u;if(D)u=`<div class="slide-columns">${D.map((F)=>`<div class="slide-column">${nh(f(F.trim()))}</div>`).join("")}</div>`;else u=nh(f(c));return{attributes:$,htmlContent:u}}),B=w.some((I)=>I.htmlContent.includes('class="mermaid"')),x=w.map(({attributes:I,htmlContent:$},c)=>zY("section",{...I,dangerouslySetInnerHTML:{__html:$}},c,!1,void 0,this));return zY("section",{className:"presentation-section",children:[zY("link",{rel:"stylesheet",href:"https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.min.css"},void 0,!1,void 0,this),zY("div",{className:"reveal",children:zY("div",{className:"slides",children:x},void 0,!1,void 0,this)},void 0,!1,void 0,this),zY("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&&zY("script",{src:"https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js",defer:!0},void 0,!1,void 0,this),zY("script",{dangerouslySetInnerHTML:{__html:`
|
|
1956
1956
|
window.addEventListener('DOMContentLoaded', () => {
|
|
@@ -2697,7 +2697,7 @@ ${f.join(`
|
|
|
2697
2697
|
`+B:Q,I=HD(this.outputDir,"styles","main.css");await this.cssProcessor.process(x,I,this.workingDir,this.outputDir,this.logger);let $=await Q9.readFile(I,"utf-8"),c=w.length>0?w:f;if(c.length>0){let D=c.join(`
|
|
2698
2698
|
`)+`
|
|
2699
2699
|
|
|
2700
|
-
`+$;await Q9.writeFile(I,D,"utf-8")}this.logger.debug("CSS processed successfully with font imports")}async copyStaticAssets(){this.logger.debug("Copying static assets from public/ directory");let A=HD(process.cwd(),"public");try{await Q9.access(A)}catch{this.logger.debug("No public/ directory found, skipping static assets");return}let f=await Q9.readdir(A,{withFileTypes:!0});for(let Q of f){let w=HD(A,Q.name),B=HD(this.outputDir,Q.name);if(Q.isDirectory())await this.copyDirectory(w,B);else await Q9.copyFile(w,B),this.logger.debug(`Copied static asset: ${Q.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([Q,w])=>{let B=Q.startsWith("/")?Q.slice(1):Q,x=HD(this.outputDir,B);await Q9.mkdir(kP2(x),{recursive:!0}),await Q9.writeFile(x,w,"utf-8"),this.logger.debug(`Wrote inline static asset: ${B}`)}))}async copyDirectory(A,f){await Q9.mkdir(f,{recursive:!0});let Q=await Q9.readdir(A,{withFileTypes:!0});for(let w of Q){let B=HD(A,w.name),x=HD(f,w.name);if(w.isDirectory())await this.copyDirectory(B,x);else await Q9.copyFile(B,x)}}}function UZA(A){return new Tl0(A)}function zP2(A,f){let Q=new Map;for(let w of A.sections){let B=f.getViewTemplate(w.template);if(!B?.runtimeScripts)continue;for(let x of B.runtimeScripts)if(!Q.has(x.src))Q.set(x.src,x)}return[...Q.values()].map((w)=>{let B=[`src="${w.src}"`];if(w.defer)B.push("defer");if(w.module)B.push('type="module"');return`<script ${B.join(" ")}></script>`})}import{join as am2}from"path";HA();class HZA{context;routeRegistry;entityDisplay;constructor(A,f,Q){this.context=A;this.routeRegistry=f;this.entityDisplay=Q}async generateEntityRoutes(){let A=this.context.logger.child("DynamicRouteGenerator"),f=this.routeRegistry.list(),Q=0;for(let B of f)if(B.sourceEntityType)this.routeRegistry.unregister(B.path),Q++;if(Q>0)A.debug(`Cleared ${Q} dynamic routes before regeneration`);let w=this.context.entityService.getEntityTypes();A.debug(`Found ${w.length} entity types`,{entityTypes:w});for(let B of w)await this.generateRoutesForEntityType(B)}async generateRoutesForEntityType(A){let f=this.context.logger.child("DynamicRouteGenerator"),{listTemplateName:Q,detailTemplateName:w}=this.findTemplatesForEntityType(A);if(!Q&&!w){f.debug(`No matching templates found for entity type: ${A}`);return}if(f.debug(`Generating routes for entity type: ${A}`,{listTemplate:Q,detailTemplate:w}),Q){let{pluralName:B,label:x,layout:I,paginate:$,pageSize:c,navigation:D}=this.getEntityDisplayConfig(A);if($)await this.generatePaginatedRoutes(A,Q,B,x,I,c,D,f);else{let u={id:`${A}-index`,path:`/${B}`,title:x,description:`Browse all ${B}`,...I&&{layout:I},navigation:{show:D.show,label:x,slot:D.slot,priority:D.priority},sections:[{id:"list",template:Q,dataQuery:{entityType:A,query:{limit:100}}}],sourceEntityType:A};try{this.routeRegistry.register(u),f.debug(`Registered index route for ${A}`,{path:u.path})}catch(K){f.warn(`Failed to register index route for ${A}`,{error:K})}}}if(w)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:I}=this.getEntityDisplayConfig(A);for(let c of B){let D="slug"in c.metadata?c.metadata.slug:c.id,u={id:`${A}-${c.id}`,path:`/${x}/${D}`,title:`${this.capitalize(A)}: ${D}`,description:`View ${A} details`,...I&&{layout:I},sections:[{id:"detail",template:w,dataQuery:{entityType:A,query:{id:D}}}],sourceEntityType:A};try{this.routeRegistry.register(u)}catch(K){f.warn(`Failed to register detail route for ${A}/${c.id}`,{error:K})}}let $=Q?B.length+1:B.length;f.debug(`Successfully registered ${$} routes for ${A}`)}catch(B){f.error(`Failed to list entities for type: ${A}`,{error:B})}}async generatePaginatedRoutes(A,f,Q,w,B,x,I,$){let D=(await this.context.entityService.listEntities(A,{limit:1000})).length,u=Math.max(1,Math.ceil(D/x));$.debug(`Generating ${u} paginated routes for ${A}`,{totalItems:D,pageSize:x});for(let K=1;K<=u;K++){let F=K===1,Z=F?`/${Q}`:`/${Q}/page/${K}`,J={id:`${A}-index${F?"":`-page-${K}`}`,path:Z,title:F?w:`${w} - Page ${K}`,description:`Browse all ${Q}${F?"":` - Page ${K}`}`,...B&&{layout:B},navigation:F?{show:I.show,label:w,slot:I.slot,priority:I.priority}:void 0,sections:[{id:"list",template:f,dataQuery:{entityType:A,query:{page:K,pageSize:x,baseUrl:`/${Q}`}}}],sourceEntityType:A};try{this.routeRegistry.register(J),$.debug(`Registered paginated route for ${A}`,{path:J.path,page:K})}catch(v){$.warn(`Failed to register paginated route for ${A} page ${K}`,{error:v})}}}findTemplatesForEntityType(A){let f=this.context.views.list(),Q,w,B=`${A}-list`,x=`${A}-detail`;for(let $ of f){let c=$.name;if(c.endsWith(B)){let D=c.slice(0,-B.length);if(D===""||D.endsWith(":"))Q=c}if(c.endsWith(x)){let D=c.slice(0,-x.length);if(D===""||D.endsWith(":"))w=c}}let I={};if(Q)I.listTemplateName=Q;if(w)I.detailTemplateName=w;return I}getEntityDisplayConfig(A){let f=this.entityDisplay?.[A],Q=10,w=!0,B=!0,x="primary",I=40;if(f){let c=f.pluralName??kI(f.label.toLowerCase()),D=this.capitalize(kI(f.label.toLowerCase()));return{pluralName:c,label:D,...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 $=kI(A);return{pluralName:$,label:this.capitalize($),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();HA();B0();var ml0=X.object({}),DO=X2.extend({id:X.literal("site-info"),entityType:X.literal("site-info"),metadata:ml0}),YO=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")}),KD=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:YO.optional().describe("Call-to-action configuration")});B0();class h$ extends q2{constructor(){super({entityType:"site-info",schema:DO,frontmatterSchema:KD,isSingleton:!0,hasBody:!1})}createSiteInfoContent(A){let f=KD.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 FD{static instance=null;logger;entityService;adapter;defaultSiteInfo;static getDefaultSiteInfo(){return{title:"Brain",description:"A knowledge management system"}}static getInstance(A,f,Q){return FD.instance??=new FD(A,f,Q),FD.instance}static resetInstance(){FD.instance=null}static createFresh(A,f,Q){return new FD(A,f,Q)}constructor(A,f,Q){this.entityService=A,this.logger=f.child("SiteInfoService"),this.adapter=new h$;let w=FD.getDefaultSiteInfo();this.defaultSiteInfo={...w,...Q}}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 NP2=new h$;class vo{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,Q){let{entityService:w}=Q,B;try{let $=await w.getEntity("site-info","site-info");B=$?NP2.parseSiteInfoBody($.content):{title:"Brain",description:"A knowledge management system"}}catch{B={title:"Brain",description:"A knowledge management system"}}let x;try{let $=await w.getEntity("anchor-profile","anchor-profile");if($)x=$.metadata.socialLinks}catch{}let I={...B,socialLinks:x,copyright:B.copyright??"Powered by Rizom"};return this.logger.debug("SiteInfoDataSource returning",{title:I.title,hasSocialLinks:!!I.socialLinks}),f.parse(I)}}var Sl0={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.0",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 hP2=new h$;class KZA extends zf{entityType="site-info";schema=DO;adapter=hP2;defaultSiteInfo;constructor(A){super("site-info",Sl0);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new vo(this.logger.child("SiteInfoDataSource"))]}async onRegister(A){let f=FD.createFresh(A.entityService,this.logger,this.defaultSiteInfo);A.messaging.subscribe("sync:initial:completed",async()=>{return await f.initialize(),{success:!0}})}}function xW(A){return new KZA(A)}var bP2=new h$;async function iY(A){let Q=(await A.listEntities("site-info",{limit:1}))[0];if(!Q)throw Error("Site info not found \u2014 create a site-info entity");return bP2.parseSiteInfoBody(Q.content)}HA();var LP2=KD.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 yl0(A,f,Q){let w;try{w=await iY(A)}catch{w={title:"Brain",description:"A knowledge management system"}}let B=f.getProfile(),x=Q.getNavigationItems("primary"),I=Q.getNavigationItems("secondary");return{...w,socialLinks:B.socialLinks,navigation:{primary:x,secondary:I},copyright:w.copyright??"Powered by Rizom"}}HA();HA();import{promises as Hr0}from"fs";import{join as om2}from"path";import{createHash as lm2}from"crypto";import{promises as mZA}from"fs";import{join as Dr0}from"path";var Yr0=null;async function nm2(){return Yr0??=Promise.resolve().then(() => d0(cr0(),1)).then((A)=>A.default),Yr0}var pm2=[480,960,1920],rm2=80,dm2="(max-width: 640px) 480px, (max-width: 1280px) 960px, 1920px";class SZA{imagesDir;logger;constructor(A,f){this.imagesDir=A;this.logger=f.child("ImageOptimizer")}async optimize(A,f){try{let Q=await nm2(),w=lm2("sha256").update(A).digest("hex").slice(0,16),B=await Q(A).metadata();if(!B.width||!B.height)return this.logger.warn("Could not determine image dimensions",{originalUrl:f}),null;let{width:x,height:I}=B,$=[];for(let K of pm2){if(K>x)continue;let F=`${w}-${K}w.webp`,Z=Dr0(this.imagesDir,F),J=`/images/${F}`;if(await mZA.access(Z).then(()=>!0).catch(()=>!1)){this.logger.debug("Cache hit, skipping optimization",{fileName:F}),$.push({width:K,url:J});continue}await Q(A).resize(K,null,{withoutEnlargement:!0}).webp({quality:rm2}).toFile(Z),$.push({width:K,url:J}),this.logger.debug("Created WebP variant",{fileName:F,width:K})}if($.length===0)return null;let c=$[$.length-1];if(!c)return null;let D=$.find((K)=>K.width===960)??c,u=Math.round(I*(D.width/x));return{src:D.url,srcset:$.map((K)=>`${K.url} ${K.width}w`).join(", "),sizes:dm2,width:D.width,height:u}}catch(Q){return this.logger.warn("Image optimization failed, using original",{originalUrl:f,error:Q instanceof Error?Q.message:String(Q)}),null}}async optimizeAll(){let A={},f;try{f=await mZA.readdir(this.imagesDir,{withFileTypes:!0})}catch{return this.logger.debug("Images directory does not exist, nothing to optimize"),A}let Q=f.filter((w)=>w.isFile()&&/\.(png|jpe?g)$/i.test(w.name));if(Q.length===0)return this.logger.debug("No PNG/JPEG images found to optimize"),A;this.logger.debug(`Optimizing ${Q.length} images`);for(let w of Q){let B=Dr0(this.imagesDir,w.name),x=`/images/${w.name}`;try{let I=await mZA.readFile(B),$=await this.optimize(I,x);if($)A[x]=$}catch(I){this.logger.warn("Failed to optimize image",{file:w.name,error:I instanceof Error?I.message:String(I)})}}return this.logger.debug(`Optimized ${Object.keys(A).length}/${Q.length} images`),A}}function ur0(A,f){if(A.format)return A.format;return f.match(/^data:image\/([^;]+);/)?.[1]??"png"}function Ur0(A){return A.match(/^data:image\/[^;]+;base64,(.+)$/)?.[1]??null}function NN(A){return A.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}class yZA{entityService;logger;imageMap={};imagesDir;optimizer;constructor(A,f,Q){this.entityService=A;this.logger=f.child("ImageBuildService"),this.imagesDir=Q,this.optimizer=new SZA(this.imagesDir,this.logger)}async resolveAll(A){let f=[...new Set(A)];if(f.length===0)return;await Hr0.mkdir(this.imagesDir,{recursive:!0});let Q=JF(4);await Promise.all(f.map((w)=>Q(async()=>{try{await this.resolveImage(w)}catch(B){this.logger.warn("Failed to resolve image",{imageId:w,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 Q=Ur0(f.content);if(!Q){this.logger.warn("Could not extract base64 from image",{imageId:A});return}let w=Buffer.from(Q,"base64"),B=ur0(f.metadata,f.content),x=`${A}.${B}`,I=om2(this.imagesDir,x);await Hr0.writeFile(I,w);let $=`/images/${x}`,c=await this.optimizer.optimize(w,$);if(c)this.imageMap[A]={src:c.src,srcset:c.srcset,sizes:c.sizes,width:c.width,height:c.height};else this.imageMap[A]={src:$,width:f.metadata.width??0,height:f.metadata.height??0};this.logger.debug("Resolved image",{imageId:A,optimized:Boolean(c)})}get(A){return this.imageMap[A]}getMap(){return this.imageMap}createImageRenderer(){let A=this.imageMap;return(f,Q,w)=>{let B=/^entity:\/\/image\/(.+)$/.exec(f);if(!B?.[1])return;let x=A[B[1]];if(!x)return;let I=[`src="${NN(x.src)}"`,`alt="${NN(w)}"`];if(x.srcset)I.push(`srcset="${NN(x.srcset)}"`);if(x.sizes)I.push(`sizes="${NN(x.sizes)}"`);if(x.width)I.push(`width="${x.width}"`);if(x.height)I.push(`height="${x.height}"`);if(Q)I.push(`title="${NN(Q)}"`);return I.push('loading="lazy"'),I.push('decoding="async"'),`<img ${I.join(" ")}>`}}}var sm2=X2.extend({metadata:X.object({slug:X.string()}).passthrough()});class q7{static instance=null;static defaultStaticSiteBuilderFactory=UZA;logger;context;staticSiteBuilderFactory;routeRegistry;profileService;entityDisplay;imageBuildService=null;static setDefaultStaticSiteBuilderFactory(A){q7.defaultStaticSiteBuilderFactory=A}static getInstance(A,f,Q,w,B){return q7.instance??=new q7(A,q7.defaultStaticSiteBuilderFactory,f,Q,w,B),q7.instance}static resetInstance(){q7.instance=null}static createFresh(A,f,Q,w,B,x){return new q7(A,B??q7.defaultStaticSiteBuilderFactory,f,Q,w,x)}constructor(A,f,Q,w,B,x){this.logger=A,this.context=Q,this.staticSiteBuilderFactory=f,this.routeRegistry=w,this.profileService=B,this.entityDisplay=x,s5.getInstance().configure(x)}async getSiteInfo(){return yl0(this.context.entityService,this.profileService,this.routeRegistry)}async build(A,f){let Q=Uj0.parse(A),w=Z9.from(f),B=[],x=[];try{await w?.report({message:"Starting site build",progress:0,total:100}),await w?.report({message:"Generating dynamic routes",progress:10,total:100}),await new HZA(this.context,this.routeRegistry,this.entityDisplay).generateEntityRoutes();let $=Q.workingDir??am2(Q.outputDir,".preact-work"),c=this.staticSiteBuilderFactory({logger:this.logger.child("StaticSiteBuilder"),workingDir:$,outputDir:Q.outputDir});if(Q.cleanBeforeBuild)await c.clean();let D=this.routeRegistry.list();if(D.length===0)x.push("No routes registered for site build");await w?.report({message:`Building ${D.length} routes`,progress:20,total:100}),await w?.report({message:"Resolving images",progress:25,total:100}),this.imageBuildService=new yZA(this.context.entityService,this.logger,Q.sharedImagesDir);let u=await this.collectAllImageIds();if(u.length>0)await this.imageBuildService.resolveAll(u);let K=Q.siteConfig,F={routes:D,pluginContext:this.context,siteConfig:{title:K.title,description:K.description,...K.url&&{url:K.url},...K.copyright&&{copyright:K.copyright},...K.themeMode&&{themeMode:K.themeMode},...K.analyticsScript&&{analyticsScript:K.analyticsScript}},headScripts:A.headScripts,...A.staticAssets&&{staticAssets:A.staticAssets},getContent:async(q,V)=>{let C=Q.environment==="production";return this.getContentForSection(V,q,C)},getViewTemplate:(q)=>{return this.context.views.get(q)},layouts:Q.layouts,getSiteInfo:async()=>{return this.getSiteInfo()},...Q.themeCSS!==void 0&&{themeCSS:Q.themeCSS},...A.slots&&{slots:A.slots},imageBuildService:this.imageBuildService},Z=0,J=D.length+4;await c.build(F,(q)=>{Z++;let V=85+Math.round(Z/J*10);w?.report({message:q,progress:V,total:100}).catch(()=>{})}),await w?.report({message:"Site build complete",progress:100,total:100});let v=D.length+1,k={success:B.length===0,outputDir:Q.outputDir,filesGenerated:v,routesBuilt:D.length};if(B.length>0)k.errors=B;if(x.length>0)k.warnings=x;return k}catch(I){let $=Error("Site build process failed");return this.logger.error("Site build failed",{error:$,originalError:I}),B.push($.message),{success:!1,outputDir:Q.outputDir,filesGenerated:0,routesBuilt:0,errors:B}}}async getContentForSection(A,f,Q){if(!A.template)return A.content??null;let w=A.template,B=s5.getInstance();if(A.dataQuery){let I={dataParams:A.dataQuery,fallback:A.content,publishedOnly:Q},$=await this.context.templates.resolve(w,I);if($)return this.enrichWithUrls($,B);return null}let x=await this.context.templates.resolve(w,{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((C)=>this.enrichWithUrls(C,f)));if(typeof A!=="object")return A;let Q=A,w={},B=Object.entries(Q),x=await Promise.all(B.map(([,C])=>this.enrichWithUrls(C,f)));for(let C=0;C<B.length;C++){let l=B[C];if(l)w[l[0]]=x[C]}let I=sm2.safeParse(Q);if(!I.success)return w;let $=I.data,c=$.entityType,D=$.metadata.slug,u=this.entityDisplay?.[c],K=u?u.label:c.charAt(0).toUpperCase()+c.slice(1),F=u?u.pluralName??u.label.toLowerCase()+"s":kI(c),Z=`/${F}`,J=F.charAt(0).toUpperCase()+F.slice(1),v=Pq($),k=v?this.imageBuildService?.get(v):void 0,q={};if(k)q={coverImageUrl:k.src,coverImageWidth:k.width,coverImageHeight:k.height,...k.srcset&&{coverImageSrcset:k.srcset,coverImageSizes:k.sizes}};else{let C=await gq($,this.context.entityService);if(C)q={coverImageUrl:C.url,coverImageWidth:C.width,coverImageHeight:C.height}}return{...w,...$,url:f.generateUrl(c,D),typeLabel:K,listUrl:Z,listLabel:J,...q}}async collectAllImageIds(){let A=new Set;try{let f=this.context.entityService.getEntityTypes();for(let Q of f){if(Q==="image")continue;let w=await this.context.entityService.listEntities(Q);for(let B of w){let x=Pq(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 lZA{logger;routes=new Map;constructor(A){this.logger=A}register(A){let f=Array.isArray(A)?A:[A];for(let Q of f){let w=NJ.parse(Q);if(this.routes.has(w.path)){let B=this.routes.get(w.path);this.logger.debug(`Overriding route "${w.path}" (was registered by plugin "${B?.pluginId}")`)}this.routes.set(w.path,w)}}unregister(A){(Array.isArray(A)?A:[A]).forEach((Q)=>this.routes.delete(Q))}unregisterByPlugin(A){for(let[f,Q]of this.routes.entries())if(Q.pluginId===A)this.routes.delete(f)}get(A){return this.routes.get(A)}list(A){let f=Array.from(this.routes.values()).filter((Q)=>!Q.external);if(A?.pluginId)f=f.filter((Q)=>Q.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[Q,w]of this.routes.entries())if(w.navigation?.show&&w.navigation.slot===A)f.push({label:w.navigation.label??w.title,href:Q,priority:w.navigation.priority});return f.sort((Q,w)=>Q.priority-w.priority)}}class io{slots=new Map;register(A,f){let Q={...f,priority:f.priority??50},w=this.slots.get(A)??[];w.push(Q),this.slots.set(A,w)}getSlot(A){return[...this.slots.get(A)??[]].sort((Q,w)=>w.priority-Q.priority)}hasSlot(A){let f=this.slots.get(A);return f!==void 0&&f.length>0}unregister(A,f){let Q=this.slots.get(A);if(!Q)return;let w=Q.filter((B)=>B.pluginId!==f);if(w.length>0)this.slots.set(A,w);else this.slots.delete(A)}unregisterAll(A){for(let[f,Q]of this.slots){let w=Q.filter((B)=>B.pluginId!==A);if(w.length>0)this.slots.set(f,w);else this.slots.delete(f)}}getSlotNames(){return Array.from(this.slots.keys())}clear(){this.slots.clear()}}HA();class nZA{config;context;pluginId;logger;debounces=new Map;unsubscribeFunctions=[];constructor(A,f,Q,w){this.config=A;this.context=f;this.pluginId=Q;this.logger=w}requestBuild(A){let f=A??(this.config.previewOutputDir?"preview":"production"),Q=this.debounces.get(f);if(!Q)Q=new zF(()=>{this.enqueueBuild(f)},this.config.rebuildDebounce),this.debounces.set(f,Q);Q.trigger()}setupAutoRebuild(){let A=new Set(["base"]),f=async(w)=>{let{entityType:B}=w.payload;if(!A.has(B))this.logger.debug(`Entity type ${B} will trigger rebuild`),this.requestBuild();return{success:!0}},Q=["entity:created","entity:updated","entity:deleted"];for(let w of Q)this.unsubscribeFunctions.push(this.context.messaging.subscribe(w,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(Q){this.logger.error("Failed to enqueue site rebuild",{error:Q})}}}B0();function tm2(A,f){return A.map((Q)=>({...Q,template:Q.template.includes(":")?Q.template:`${f}:${Q.template}`}))}function To(A,f,Q){for(let w of A)Q.register({...w,pluginId:f,sections:w.sections?tm2(w.sections,f):[]})}function Kr0(A,f,Q){A.messaging.subscribe("plugin:site-builder:route:register",async(w)=>{try{let B=U2A.parse(w.payload),{routes:x,pluginId:I}=B;return To(x,I,f),{success:!0}}catch(B){return Q.error("Failed to register routes",{error:B}),{success:!1,error:"Failed to register routes"}}}),A.messaging.subscribe("plugin:site-builder:route:unregister",async(w)=>{try{let B=H2A.parse(w.payload),{paths:x,pluginId:I}=B;if(x)for(let $ of x)f.unregister($);else if(I)f.unregisterByPlugin(I);return{success:!0}}catch(B){return Q.error("Failed to unregister routes",{error:B}),{success:!1,error:"Failed to unregister routes"}}}),A.messaging.subscribe("plugin:site-builder:route:list",async(w)=>{try{let B=K2A.parse(w.payload);return{success:!0,data:{routes:f.list(B.pluginId?B:void 0)}}}catch(B){return Q.error("Failed to list routes",{error:B}),{success:!1,error:"Failed to list routes"}}}),A.messaging.subscribe("plugin:site-builder:route:get",async(w)=>{try{let B=F2A.parse(w.payload);return{success:!0,data:{route:f.get(B.path)}}}catch(B){return Q.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()}})}HA();import{promises as ZO}from"fs";import{join as WO}from"path";function Fr0(A,f){if(f==="preview")return`User-agent: *
|
|
2700
|
+
`+$;await Q9.writeFile(I,D,"utf-8")}this.logger.debug("CSS processed successfully with font imports")}async copyStaticAssets(){this.logger.debug("Copying static assets from public/ directory");let A=HD(process.cwd(),"public");try{await Q9.access(A)}catch{this.logger.debug("No public/ directory found, skipping static assets");return}let f=await Q9.readdir(A,{withFileTypes:!0});for(let Q of f){let w=HD(A,Q.name),B=HD(this.outputDir,Q.name);if(Q.isDirectory())await this.copyDirectory(w,B);else await Q9.copyFile(w,B),this.logger.debug(`Copied static asset: ${Q.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([Q,w])=>{let B=Q.startsWith("/")?Q.slice(1):Q,x=HD(this.outputDir,B);await Q9.mkdir(kP2(x),{recursive:!0}),await Q9.writeFile(x,w,"utf-8"),this.logger.debug(`Wrote inline static asset: ${B}`)}))}async copyDirectory(A,f){await Q9.mkdir(f,{recursive:!0});let Q=await Q9.readdir(A,{withFileTypes:!0});for(let w of Q){let B=HD(A,w.name),x=HD(f,w.name);if(w.isDirectory())await this.copyDirectory(B,x);else await Q9.copyFile(B,x)}}}function UZA(A){return new Tl0(A)}function zP2(A,f){let Q=new Map;for(let w of A.sections){let B=f.getViewTemplate(w.template);if(!B?.runtimeScripts)continue;for(let x of B.runtimeScripts)if(!Q.has(x.src))Q.set(x.src,x)}return[...Q.values()].map((w)=>{let B=[`src="${w.src}"`];if(w.defer)B.push("defer");if(w.module)B.push('type="module"');return`<script ${B.join(" ")}></script>`})}import{join as am2}from"path";HA();class HZA{context;routeRegistry;entityDisplay;constructor(A,f,Q){this.context=A;this.routeRegistry=f;this.entityDisplay=Q}async generateEntityRoutes(){let A=this.context.logger.child("DynamicRouteGenerator"),f=this.routeRegistry.list(),Q=0;for(let B of f)if(B.sourceEntityType)this.routeRegistry.unregister(B.path),Q++;if(Q>0)A.debug(`Cleared ${Q} dynamic routes before regeneration`);let w=this.context.entityService.getEntityTypes();A.debug(`Found ${w.length} entity types`,{entityTypes:w});for(let B of w)await this.generateRoutesForEntityType(B)}async generateRoutesForEntityType(A){let f=this.context.logger.child("DynamicRouteGenerator"),{listTemplateName:Q,detailTemplateName:w}=this.findTemplatesForEntityType(A);if(!Q&&!w){f.debug(`No matching templates found for entity type: ${A}`);return}if(f.debug(`Generating routes for entity type: ${A}`,{listTemplate:Q,detailTemplate:w}),Q){let{pluralName:B,label:x,layout:I,paginate:$,pageSize:c,navigation:D}=this.getEntityDisplayConfig(A);if($)await this.generatePaginatedRoutes(A,Q,B,x,I,c,D,f);else{let u={id:`${A}-index`,path:`/${B}`,title:x,description:`Browse all ${B}`,...I&&{layout:I},navigation:{show:D.show,label:x,slot:D.slot,priority:D.priority},sections:[{id:"list",template:Q,dataQuery:{entityType:A,query:{limit:100}}}],sourceEntityType:A};try{this.routeRegistry.register(u),f.debug(`Registered index route for ${A}`,{path:u.path})}catch(K){f.warn(`Failed to register index route for ${A}`,{error:K})}}}if(w)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:I}=this.getEntityDisplayConfig(A);for(let c of B){let D="slug"in c.metadata?c.metadata.slug:c.id,u={id:`${A}-${c.id}`,path:`/${x}/${D}`,title:`${this.capitalize(A)}: ${D}`,description:`View ${A} details`,...I&&{layout:I},sections:[{id:"detail",template:w,dataQuery:{entityType:A,query:{id:D}}}],sourceEntityType:A};try{this.routeRegistry.register(u)}catch(K){f.warn(`Failed to register detail route for ${A}/${c.id}`,{error:K})}}let $=Q?B.length+1:B.length;f.debug(`Successfully registered ${$} routes for ${A}`)}catch(B){f.error(`Failed to list entities for type: ${A}`,{error:B})}}async generatePaginatedRoutes(A,f,Q,w,B,x,I,$){let D=(await this.context.entityService.listEntities(A,{limit:1000})).length,u=Math.max(1,Math.ceil(D/x));$.debug(`Generating ${u} paginated routes for ${A}`,{totalItems:D,pageSize:x});for(let K=1;K<=u;K++){let F=K===1,Z=F?`/${Q}`:`/${Q}/page/${K}`,J={id:`${A}-index${F?"":`-page-${K}`}`,path:Z,title:F?w:`${w} - Page ${K}`,description:`Browse all ${Q}${F?"":` - Page ${K}`}`,...B&&{layout:B},navigation:F?{show:I.show,label:w,slot:I.slot,priority:I.priority}:void 0,sections:[{id:"list",template:f,dataQuery:{entityType:A,query:{page:K,pageSize:x,baseUrl:`/${Q}`}}}],sourceEntityType:A};try{this.routeRegistry.register(J),$.debug(`Registered paginated route for ${A}`,{path:J.path,page:K})}catch(v){$.warn(`Failed to register paginated route for ${A} page ${K}`,{error:v})}}}findTemplatesForEntityType(A){let f=this.context.views.list(),Q,w,B=`${A}-list`,x=`${A}-detail`;for(let $ of f){let c=$.name;if(c.endsWith(B)){let D=c.slice(0,-B.length);if(D===""||D.endsWith(":"))Q=c}if(c.endsWith(x)){let D=c.slice(0,-x.length);if(D===""||D.endsWith(":"))w=c}}let I={};if(Q)I.listTemplateName=Q;if(w)I.detailTemplateName=w;return I}getEntityDisplayConfig(A){let f=this.entityDisplay?.[A],Q=10,w=!0,B=!0,x="primary",I=40;if(f){let c=f.pluralName??kI(f.label.toLowerCase()),D=this.capitalize(kI(f.label.toLowerCase()));return{pluralName:c,label:D,...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 $=kI(A);return{pluralName:$,label:this.capitalize($),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();HA();B0();var ml0=X.object({}),DO=X2.extend({id:X.literal("site-info"),entityType:X.literal("site-info"),metadata:ml0}),YO=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")}),KD=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:YO.optional().describe("Call-to-action configuration")});B0();class h$ extends q2{constructor(){super({entityType:"site-info",schema:DO,frontmatterSchema:KD,isSingleton:!0,hasBody:!1})}createSiteInfoContent(A){let f=KD.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 FD{static instance=null;logger;entityService;adapter;defaultSiteInfo;static getDefaultSiteInfo(){return{title:"Brain",description:"A knowledge management system"}}static getInstance(A,f,Q){return FD.instance??=new FD(A,f,Q),FD.instance}static resetInstance(){FD.instance=null}static createFresh(A,f,Q){return new FD(A,f,Q)}constructor(A,f,Q){this.entityService=A,this.logger=f.child("SiteInfoService"),this.adapter=new h$;let w=FD.getDefaultSiteInfo();this.defaultSiteInfo={...w,...Q}}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 NP2=new h$;class vo{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,Q){let{entityService:w}=Q,B;try{let $=await w.getEntity("site-info","site-info");B=$?NP2.parseSiteInfoBody($.content):{title:"Brain",description:"A knowledge management system"}}catch{B={title:"Brain",description:"A knowledge management system"}}let x;try{let $=await w.getEntity("anchor-profile","anchor-profile");if($)x=$.metadata.socialLinks}catch{}let I={...B,socialLinks:x,copyright:B.copyright??"Powered by Rizom"};return this.logger.debug("SiteInfoDataSource returning",{title:I.title,hasSocialLinks:!!I.socialLinks}),f.parse(I)}}var Sl0={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.1",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 hP2=new h$;class KZA extends zf{entityType="site-info";schema=DO;adapter=hP2;defaultSiteInfo;constructor(A){super("site-info",Sl0);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new vo(this.logger.child("SiteInfoDataSource"))]}async onRegister(A){let f=FD.createFresh(A.entityService,this.logger,this.defaultSiteInfo);A.messaging.subscribe("sync:initial:completed",async()=>{return await f.initialize(),{success:!0}})}}function xW(A){return new KZA(A)}var bP2=new h$;async function iY(A){let Q=(await A.listEntities("site-info",{limit:1}))[0];if(!Q)throw Error("Site info not found \u2014 create a site-info entity");return bP2.parseSiteInfoBody(Q.content)}HA();var LP2=KD.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 yl0(A,f,Q){let w;try{w=await iY(A)}catch{w={title:"Brain",description:"A knowledge management system"}}let B=f.getProfile(),x=Q.getNavigationItems("primary"),I=Q.getNavigationItems("secondary");return{...w,socialLinks:B.socialLinks,navigation:{primary:x,secondary:I},copyright:w.copyright??"Powered by Rizom"}}HA();HA();import{promises as Hr0}from"fs";import{join as om2}from"path";import{createHash as lm2}from"crypto";import{promises as mZA}from"fs";import{join as Dr0}from"path";var Yr0=null;async function nm2(){return Yr0??=Promise.resolve().then(() => d0(cr0(),1)).then((A)=>A.default),Yr0}var pm2=[480,960,1920],rm2=80,dm2="(max-width: 640px) 480px, (max-width: 1280px) 960px, 1920px";class SZA{imagesDir;logger;constructor(A,f){this.imagesDir=A;this.logger=f.child("ImageOptimizer")}async optimize(A,f){try{let Q=await nm2(),w=lm2("sha256").update(A).digest("hex").slice(0,16),B=await Q(A).metadata();if(!B.width||!B.height)return this.logger.warn("Could not determine image dimensions",{originalUrl:f}),null;let{width:x,height:I}=B,$=[];for(let K of pm2){if(K>x)continue;let F=`${w}-${K}w.webp`,Z=Dr0(this.imagesDir,F),J=`/images/${F}`;if(await mZA.access(Z).then(()=>!0).catch(()=>!1)){this.logger.debug("Cache hit, skipping optimization",{fileName:F}),$.push({width:K,url:J});continue}await Q(A).resize(K,null,{withoutEnlargement:!0}).webp({quality:rm2}).toFile(Z),$.push({width:K,url:J}),this.logger.debug("Created WebP variant",{fileName:F,width:K})}if($.length===0)return null;let c=$[$.length-1];if(!c)return null;let D=$.find((K)=>K.width===960)??c,u=Math.round(I*(D.width/x));return{src:D.url,srcset:$.map((K)=>`${K.url} ${K.width}w`).join(", "),sizes:dm2,width:D.width,height:u}}catch(Q){return this.logger.warn("Image optimization failed, using original",{originalUrl:f,error:Q instanceof Error?Q.message:String(Q)}),null}}async optimizeAll(){let A={},f;try{f=await mZA.readdir(this.imagesDir,{withFileTypes:!0})}catch{return this.logger.debug("Images directory does not exist, nothing to optimize"),A}let Q=f.filter((w)=>w.isFile()&&/\.(png|jpe?g)$/i.test(w.name));if(Q.length===0)return this.logger.debug("No PNG/JPEG images found to optimize"),A;this.logger.debug(`Optimizing ${Q.length} images`);for(let w of Q){let B=Dr0(this.imagesDir,w.name),x=`/images/${w.name}`;try{let I=await mZA.readFile(B),$=await this.optimize(I,x);if($)A[x]=$}catch(I){this.logger.warn("Failed to optimize image",{file:w.name,error:I instanceof Error?I.message:String(I)})}}return this.logger.debug(`Optimized ${Object.keys(A).length}/${Q.length} images`),A}}function ur0(A,f){if(A.format)return A.format;return f.match(/^data:image\/([^;]+);/)?.[1]??"png"}function Ur0(A){return A.match(/^data:image\/[^;]+;base64,(.+)$/)?.[1]??null}function NN(A){return A.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}class yZA{entityService;logger;imageMap={};imagesDir;optimizer;constructor(A,f,Q){this.entityService=A;this.logger=f.child("ImageBuildService"),this.imagesDir=Q,this.optimizer=new SZA(this.imagesDir,this.logger)}async resolveAll(A){let f=[...new Set(A)];if(f.length===0)return;await Hr0.mkdir(this.imagesDir,{recursive:!0});let Q=JF(4);await Promise.all(f.map((w)=>Q(async()=>{try{await this.resolveImage(w)}catch(B){this.logger.warn("Failed to resolve image",{imageId:w,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 Q=Ur0(f.content);if(!Q){this.logger.warn("Could not extract base64 from image",{imageId:A});return}let w=Buffer.from(Q,"base64"),B=ur0(f.metadata,f.content),x=`${A}.${B}`,I=om2(this.imagesDir,x);await Hr0.writeFile(I,w);let $=`/images/${x}`,c=await this.optimizer.optimize(w,$);if(c)this.imageMap[A]={src:c.src,srcset:c.srcset,sizes:c.sizes,width:c.width,height:c.height};else this.imageMap[A]={src:$,width:f.metadata.width??0,height:f.metadata.height??0};this.logger.debug("Resolved image",{imageId:A,optimized:Boolean(c)})}get(A){return this.imageMap[A]}getMap(){return this.imageMap}createImageRenderer(){let A=this.imageMap;return(f,Q,w)=>{let B=/^entity:\/\/image\/(.+)$/.exec(f);if(!B?.[1])return;let x=A[B[1]];if(!x)return;let I=[`src="${NN(x.src)}"`,`alt="${NN(w)}"`];if(x.srcset)I.push(`srcset="${NN(x.srcset)}"`);if(x.sizes)I.push(`sizes="${NN(x.sizes)}"`);if(x.width)I.push(`width="${x.width}"`);if(x.height)I.push(`height="${x.height}"`);if(Q)I.push(`title="${NN(Q)}"`);return I.push('loading="lazy"'),I.push('decoding="async"'),`<img ${I.join(" ")}>`}}}var sm2=X2.extend({metadata:X.object({slug:X.string()}).passthrough()});class q7{static instance=null;static defaultStaticSiteBuilderFactory=UZA;logger;context;staticSiteBuilderFactory;routeRegistry;profileService;entityDisplay;imageBuildService=null;static setDefaultStaticSiteBuilderFactory(A){q7.defaultStaticSiteBuilderFactory=A}static getInstance(A,f,Q,w,B){return q7.instance??=new q7(A,q7.defaultStaticSiteBuilderFactory,f,Q,w,B),q7.instance}static resetInstance(){q7.instance=null}static createFresh(A,f,Q,w,B,x){return new q7(A,B??q7.defaultStaticSiteBuilderFactory,f,Q,w,x)}constructor(A,f,Q,w,B,x){this.logger=A,this.context=Q,this.staticSiteBuilderFactory=f,this.routeRegistry=w,this.profileService=B,this.entityDisplay=x,s5.getInstance().configure(x)}async getSiteInfo(){return yl0(this.context.entityService,this.profileService,this.routeRegistry)}async build(A,f){let Q=Uj0.parse(A),w=Z9.from(f),B=[],x=[];try{await w?.report({message:"Starting site build",progress:0,total:100}),await w?.report({message:"Generating dynamic routes",progress:10,total:100}),await new HZA(this.context,this.routeRegistry,this.entityDisplay).generateEntityRoutes();let $=Q.workingDir??am2(Q.outputDir,".preact-work"),c=this.staticSiteBuilderFactory({logger:this.logger.child("StaticSiteBuilder"),workingDir:$,outputDir:Q.outputDir});if(Q.cleanBeforeBuild)await c.clean();let D=this.routeRegistry.list();if(D.length===0)x.push("No routes registered for site build");await w?.report({message:`Building ${D.length} routes`,progress:20,total:100}),await w?.report({message:"Resolving images",progress:25,total:100}),this.imageBuildService=new yZA(this.context.entityService,this.logger,Q.sharedImagesDir);let u=await this.collectAllImageIds();if(u.length>0)await this.imageBuildService.resolveAll(u);let K=Q.siteConfig,F={routes:D,pluginContext:this.context,siteConfig:{title:K.title,description:K.description,...K.url&&{url:K.url},...K.copyright&&{copyright:K.copyright},...K.themeMode&&{themeMode:K.themeMode},...K.analyticsScript&&{analyticsScript:K.analyticsScript}},headScripts:A.headScripts,...A.staticAssets&&{staticAssets:A.staticAssets},getContent:async(q,V)=>{let C=Q.environment==="production";return this.getContentForSection(V,q,C)},getViewTemplate:(q)=>{return this.context.views.get(q)},layouts:Q.layouts,getSiteInfo:async()=>{return this.getSiteInfo()},...Q.themeCSS!==void 0&&{themeCSS:Q.themeCSS},...A.slots&&{slots:A.slots},imageBuildService:this.imageBuildService},Z=0,J=D.length+4;await c.build(F,(q)=>{Z++;let V=85+Math.round(Z/J*10);w?.report({message:q,progress:V,total:100}).catch(()=>{})}),await w?.report({message:"Site build complete",progress:100,total:100});let v=D.length+1,k={success:B.length===0,outputDir:Q.outputDir,filesGenerated:v,routesBuilt:D.length};if(B.length>0)k.errors=B;if(x.length>0)k.warnings=x;return k}catch(I){let $=Error("Site build process failed");return this.logger.error("Site build failed",{error:$,originalError:I}),B.push($.message),{success:!1,outputDir:Q.outputDir,filesGenerated:0,routesBuilt:0,errors:B}}}async getContentForSection(A,f,Q){if(!A.template)return A.content??null;let w=A.template,B=s5.getInstance();if(A.dataQuery){let I={dataParams:A.dataQuery,fallback:A.content,publishedOnly:Q},$=await this.context.templates.resolve(w,I);if($)return this.enrichWithUrls($,B);return null}let x=await this.context.templates.resolve(w,{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((C)=>this.enrichWithUrls(C,f)));if(typeof A!=="object")return A;let Q=A,w={},B=Object.entries(Q),x=await Promise.all(B.map(([,C])=>this.enrichWithUrls(C,f)));for(let C=0;C<B.length;C++){let l=B[C];if(l)w[l[0]]=x[C]}let I=sm2.safeParse(Q);if(!I.success)return w;let $=I.data,c=$.entityType,D=$.metadata.slug,u=this.entityDisplay?.[c],K=u?u.label:c.charAt(0).toUpperCase()+c.slice(1),F=u?u.pluralName??u.label.toLowerCase()+"s":kI(c),Z=`/${F}`,J=F.charAt(0).toUpperCase()+F.slice(1),v=Pq($),k=v?this.imageBuildService?.get(v):void 0,q={};if(k)q={coverImageUrl:k.src,coverImageWidth:k.width,coverImageHeight:k.height,...k.srcset&&{coverImageSrcset:k.srcset,coverImageSizes:k.sizes}};else{let C=await gq($,this.context.entityService);if(C)q={coverImageUrl:C.url,coverImageWidth:C.width,coverImageHeight:C.height}}return{...w,...$,url:f.generateUrl(c,D),typeLabel:K,listUrl:Z,listLabel:J,...q}}async collectAllImageIds(){let A=new Set;try{let f=this.context.entityService.getEntityTypes();for(let Q of f){if(Q==="image")continue;let w=await this.context.entityService.listEntities(Q);for(let B of w){let x=Pq(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 lZA{logger;routes=new Map;constructor(A){this.logger=A}register(A){let f=Array.isArray(A)?A:[A];for(let Q of f){let w=NJ.parse(Q);if(this.routes.has(w.path)){let B=this.routes.get(w.path);this.logger.debug(`Overriding route "${w.path}" (was registered by plugin "${B?.pluginId}")`)}this.routes.set(w.path,w)}}unregister(A){(Array.isArray(A)?A:[A]).forEach((Q)=>this.routes.delete(Q))}unregisterByPlugin(A){for(let[f,Q]of this.routes.entries())if(Q.pluginId===A)this.routes.delete(f)}get(A){return this.routes.get(A)}list(A){let f=Array.from(this.routes.values()).filter((Q)=>!Q.external);if(A?.pluginId)f=f.filter((Q)=>Q.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[Q,w]of this.routes.entries())if(w.navigation?.show&&w.navigation.slot===A)f.push({label:w.navigation.label??w.title,href:Q,priority:w.navigation.priority});return f.sort((Q,w)=>Q.priority-w.priority)}}class io{slots=new Map;register(A,f){let Q={...f,priority:f.priority??50},w=this.slots.get(A)??[];w.push(Q),this.slots.set(A,w)}getSlot(A){return[...this.slots.get(A)??[]].sort((Q,w)=>w.priority-Q.priority)}hasSlot(A){let f=this.slots.get(A);return f!==void 0&&f.length>0}unregister(A,f){let Q=this.slots.get(A);if(!Q)return;let w=Q.filter((B)=>B.pluginId!==f);if(w.length>0)this.slots.set(A,w);else this.slots.delete(A)}unregisterAll(A){for(let[f,Q]of this.slots){let w=Q.filter((B)=>B.pluginId!==A);if(w.length>0)this.slots.set(f,w);else this.slots.delete(f)}}getSlotNames(){return Array.from(this.slots.keys())}clear(){this.slots.clear()}}HA();class nZA{config;context;pluginId;logger;debounces=new Map;unsubscribeFunctions=[];constructor(A,f,Q,w){this.config=A;this.context=f;this.pluginId=Q;this.logger=w}requestBuild(A){let f=A??(this.config.previewOutputDir?"preview":"production"),Q=this.debounces.get(f);if(!Q)Q=new zF(()=>{this.enqueueBuild(f)},this.config.rebuildDebounce),this.debounces.set(f,Q);Q.trigger()}setupAutoRebuild(){let A=new Set(["base"]),f=async(w)=>{let{entityType:B}=w.payload;if(!A.has(B))this.logger.debug(`Entity type ${B} will trigger rebuild`),this.requestBuild();return{success:!0}},Q=["entity:created","entity:updated","entity:deleted"];for(let w of Q)this.unsubscribeFunctions.push(this.context.messaging.subscribe(w,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(Q){this.logger.error("Failed to enqueue site rebuild",{error:Q})}}}B0();function tm2(A,f){return A.map((Q)=>({...Q,template:Q.template.includes(":")?Q.template:`${f}:${Q.template}`}))}function To(A,f,Q){for(let w of A)Q.register({...w,pluginId:f,sections:w.sections?tm2(w.sections,f):[]})}function Kr0(A,f,Q){A.messaging.subscribe("plugin:site-builder:route:register",async(w)=>{try{let B=U2A.parse(w.payload),{routes:x,pluginId:I}=B;return To(x,I,f),{success:!0}}catch(B){return Q.error("Failed to register routes",{error:B}),{success:!1,error:"Failed to register routes"}}}),A.messaging.subscribe("plugin:site-builder:route:unregister",async(w)=>{try{let B=H2A.parse(w.payload),{paths:x,pluginId:I}=B;if(x)for(let $ of x)f.unregister($);else if(I)f.unregisterByPlugin(I);return{success:!0}}catch(B){return Q.error("Failed to unregister routes",{error:B}),{success:!1,error:"Failed to unregister routes"}}}),A.messaging.subscribe("plugin:site-builder:route:list",async(w)=>{try{let B=K2A.parse(w.payload);return{success:!0,data:{routes:f.list(B.pluginId?B:void 0)}}}catch(B){return Q.error("Failed to list routes",{error:B}),{success:!1,error:"Failed to list routes"}}}),A.messaging.subscribe("plugin:site-builder:route:get",async(w)=>{try{let B=F2A.parse(w.payload);return{success:!0,data:{route:f.get(B.path)}}}catch(B){return Q.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()}})}HA();import{promises as ZO}from"fs";import{join as WO}from"path";function Fr0(A,f){if(f==="preview")return`User-agent: *
|
|
2701
2701
|
Disallow: /
|
|
2702
2702
|
|
|
2703
2703
|
Sitemap: ${A}/sitemap.xml
|
|
@@ -2726,7 +2726,7 @@ ${A.map((x)=>({url:`${f}${x.path}`,lastmod:Q,changefreq:x.path==="/"?"daily":"we
|
|
|
2726
2726
|
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
|
|
2727
2727
|
</body>
|
|
2728
2728
|
</html>
|
|
2729
|
-
`;async function QS2(A,f,Q){let w=A.siteConfig.url??"https://example.com",B=f.list(),x=Fr0(w,A.environment);await ZO.writeFile(WO(A.outputDir,"robots.txt"),x,"utf-8"),Q.info(`Generated robots.txt for ${A.environment} environment`);let I=Xr0(B,w);await ZO.writeFile(WO(A.outputDir,"sitemap.xml"),I,"utf-8"),Q.info(`Generated sitemap.xml with ${B.length} URLs`)}async function wS2(A,f,Q,w){if(!Q.cms)return;let B=await f.messaging.send("git-sync:get-repo-info",{});if("noop"in B||!B.success||!B.data?.repo){w.warn("CMS enabled but git-sync repo info unavailable \u2014 skipping CMS generation");return}let x=f.entityService.getEntityTypes(),I=Wr0({repo:B.data.repo,branch:B.data.branch,...f.siteUrl&&{baseUrl:f.siteUrl},entityTypes:x,getFrontmatterSchema:(c)=>f.entities.getEffectiveFrontmatterSchema(c),getAdapter:(c)=>f.entities.getAdapter(c),...Q.entityDisplay&&{entityDisplay:Q.entityDisplay}}),$=WO(A.outputDir,"admin");await ZO.mkdir($,{recursive:!0}),await ZO.writeFile(WO($,"config.yml"),uc(I),"utf-8"),await ZO.writeFile(WO($,"index.html"),Gr0,"utf-8"),w.info("Generated CMS admin page and config.yml")}function Jr0(A){let{context:f,routeRegistry:Q,config:w,logger:B}=A;f.messaging.subscribe("site:build:completed",async(x)=>{try{let I=x.payload;return B.info(`Received site:build:completed event for ${I.environment} environment - generating SEO files`),await QS2(I,Q,B),await wS2(I,f,w,B),{success:!0}}catch(I){return B.error("Failed to generate SEO files",I),{success:!1}}})}B0();HA();var vr0=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()});HA();class oZA extends qQ{sendMessage;cfg;constructor(A,f,Q){super(A,{schema:vr0,jobTypeName:"site-build"});this.sendMessage=f;this.cfg=Q}async process(A,f,Q){let w=A.environment??"preview",B=A.enableContentGeneration??!1;try{this.logger.debug("Starting site build job",{jobId:f,environment:w,outputDir:A.outputDir}),await Q.report({progress:0,total:100,message:`Starting site build for ${w} environment`});let x=Q.createSub({scale:{start:10,end:90}}),I=await this.cfg.siteBuilder.build({outputDir:A.outputDir,workingDir:A.workingDir,sharedImagesDir:this.cfg.sharedImagesDir,enableContentGeneration:B,environment:w,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 Q.report({progress:100,total:100,message:`Site build completed: ${I.routesBuilt} routes built`}),this.logger.debug("Site build job completed",{jobId:f,environment:w,routesBuilt:I.routesBuilt,success:I.success}),I.success){this.logger.info(`Emitting site:build:completed event for ${w} environment`);let $=w==="preview"?this.cfg.previewUrl??this.cfg.siteUrl:this.cfg.siteUrl;await this.sendMessage("site:build:completed",{outputDir:A.outputDir,environment:w,routesBuilt:I.routesBuilt,siteConfig:{...A.siteConfig??this.cfg.defaultSiteConfig,url:$},generateEntityUrl:(c,D)=>s5.getInstance().generateUrl(c,D)},{broadcast:!0})}return{success:I.success,routesBuilt:I.routesBuilt,outputDir:A.outputDir,environment:w,...I.errors&&{errors:I.errors},...I.warnings&&{warnings:I.warnings}}}catch(x){throw this.logger.error("Site build job failed",x),x}}summarizeDataForLog(A){return{environment:A.environment,outputDir:A.outputDir}}}HA();B0();var BS2=X.object({slot:X.enum(zJ).optional().default("primary"),limit:X.number().optional()});class aZA{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,Q){let w=BS2.parse(A??{});this.logger.debug("NavigationDataSource fetch called",{params:w});let B=this.routeRegistry.getNavigationItems(w.slot),x=w.limit?B.slice(0,w.limit):B,I=x.map((c)=>({label:c.label,href:c.href}));this.logger.debug("NavigationDataSource returning",{slot:w.slot,itemCount:x.length,items:I});let $={navigation:I};return f.parse($)}}B0();HA();var xS2=X.object({environment:X.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function kr0(A,f){return[Tf(A,"build-site","Build a static site from registered routes",xS2,async(Q)=>{return f(Q.environment),{success:!0,message:`Site build requested${Q.environment?` for ${Q.environment}`:""} (debounced)`,data:{}}},{cli:{name:"build"}})]}HA();B0();var zr0=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:KD.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(NJ).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(zJ).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 Nr0={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.0",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 sZA extends mw{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",Nr0,{...A,layouts:f},zr0);this.layouts=f}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new lZA(A.logger),this._slotRegistry=new io,A.messaging.subscribe("plugin:site-builder:slot:register",async(f)=>{let{slotName:Q,pluginId:w,render:B,priority:x}=f.payload;return this._slotRegistry?.register(Q,{pluginId:w,render:B,...x!==void 0&&{priority:x}}),{success:!0}}),A.messaging.subscribe("plugin:site-builder:head-script:register",async(f)=>{let{pluginId:Q,script:w}=f.payload;return this.headScripts.set(Q,w),{success:!0}}),A.entities.registerDataSource(new aZA(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=wx.getInstance(A.entityService,A.logger),A.messaging.subscribe("sync:initial:completed",async()=>{return await this.profileService?.initialize(),this.logger.info("AnchorProfileService initialized"),{success:!0}}),Kr0(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)To(this.config.routes,this.id,this.routeRegistry);if(this.siteBuilder=q7.getInstance(A.logger.child("SiteBuilder"),A,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new oZA(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 nZA(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 w=await this.getInstructions();if(w)A.registerInstructions(w)}return{success:!0}}),Jr0({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 kr0(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 iY(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((Q)=>({id:Q.id,path:Q.path,title:Q.title,description:Q.description,sections:Q.sections.map((w)=>({id:w.id,template:w.template}))})),null,2)}]}}},{uri:"site://templates",name:"View Templates",description:"All registered view templates",mimeType:"application/json",handler:async()=>{let f=A.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(f.map((Q)=>({name:Q.name,description:Q.description,hasWebRenderer:!!Q.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let A=this.getContext();try{let f=await iY(A.entityService);return`## Your Site
|
|
2729
|
+
`;async function QS2(A,f,Q){let w=A.siteConfig.url??"https://example.com",B=f.list(),x=Fr0(w,A.environment);await ZO.writeFile(WO(A.outputDir,"robots.txt"),x,"utf-8"),Q.info(`Generated robots.txt for ${A.environment} environment`);let I=Xr0(B,w);await ZO.writeFile(WO(A.outputDir,"sitemap.xml"),I,"utf-8"),Q.info(`Generated sitemap.xml with ${B.length} URLs`)}async function wS2(A,f,Q,w){if(!Q.cms)return;let B=await f.messaging.send("git-sync:get-repo-info",{});if("noop"in B||!B.success||!B.data?.repo){w.warn("CMS enabled but git-sync repo info unavailable \u2014 skipping CMS generation");return}let x=f.entityService.getEntityTypes(),I=Wr0({repo:B.data.repo,branch:B.data.branch,...f.siteUrl&&{baseUrl:f.siteUrl},entityTypes:x,getFrontmatterSchema:(c)=>f.entities.getEffectiveFrontmatterSchema(c),getAdapter:(c)=>f.entities.getAdapter(c),...Q.entityDisplay&&{entityDisplay:Q.entityDisplay}}),$=WO(A.outputDir,"admin");await ZO.mkdir($,{recursive:!0}),await ZO.writeFile(WO($,"config.yml"),uc(I),"utf-8"),await ZO.writeFile(WO($,"index.html"),Gr0,"utf-8"),w.info("Generated CMS admin page and config.yml")}function Jr0(A){let{context:f,routeRegistry:Q,config:w,logger:B}=A;f.messaging.subscribe("site:build:completed",async(x)=>{try{let I=x.payload;return B.info(`Received site:build:completed event for ${I.environment} environment - generating SEO files`),await QS2(I,Q,B),await wS2(I,f,w,B),{success:!0}}catch(I){return B.error("Failed to generate SEO files",I),{success:!1}}})}B0();HA();var vr0=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()});HA();class oZA extends qQ{sendMessage;cfg;constructor(A,f,Q){super(A,{schema:vr0,jobTypeName:"site-build"});this.sendMessage=f;this.cfg=Q}async process(A,f,Q){let w=A.environment??"preview",B=A.enableContentGeneration??!1;try{this.logger.debug("Starting site build job",{jobId:f,environment:w,outputDir:A.outputDir}),await Q.report({progress:0,total:100,message:`Starting site build for ${w} environment`});let x=Q.createSub({scale:{start:10,end:90}}),I=await this.cfg.siteBuilder.build({outputDir:A.outputDir,workingDir:A.workingDir,sharedImagesDir:this.cfg.sharedImagesDir,enableContentGeneration:B,environment:w,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 Q.report({progress:100,total:100,message:`Site build completed: ${I.routesBuilt} routes built`}),this.logger.debug("Site build job completed",{jobId:f,environment:w,routesBuilt:I.routesBuilt,success:I.success}),I.success){this.logger.info(`Emitting site:build:completed event for ${w} environment`);let $=w==="preview"?this.cfg.previewUrl??this.cfg.siteUrl:this.cfg.siteUrl;await this.sendMessage("site:build:completed",{outputDir:A.outputDir,environment:w,routesBuilt:I.routesBuilt,siteConfig:{...A.siteConfig??this.cfg.defaultSiteConfig,url:$},generateEntityUrl:(c,D)=>s5.getInstance().generateUrl(c,D)},{broadcast:!0})}return{success:I.success,routesBuilt:I.routesBuilt,outputDir:A.outputDir,environment:w,...I.errors&&{errors:I.errors},...I.warnings&&{warnings:I.warnings}}}catch(x){throw this.logger.error("Site build job failed",x),x}}summarizeDataForLog(A){return{environment:A.environment,outputDir:A.outputDir}}}HA();B0();var BS2=X.object({slot:X.enum(zJ).optional().default("primary"),limit:X.number().optional()});class aZA{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,Q){let w=BS2.parse(A??{});this.logger.debug("NavigationDataSource fetch called",{params:w});let B=this.routeRegistry.getNavigationItems(w.slot),x=w.limit?B.slice(0,w.limit):B,I=x.map((c)=>({label:c.label,href:c.href}));this.logger.debug("NavigationDataSource returning",{slot:w.slot,itemCount:x.length,items:I});let $={navigation:I};return f.parse($)}}B0();HA();var xS2=X.object({environment:X.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function kr0(A,f){return[Tf(A,"build-site","Build a static site from registered routes",xS2,async(Q)=>{return f(Q.environment),{success:!0,message:`Site build requested${Q.environment?` for ${Q.environment}`:""} (debounced)`,data:{}}},{cli:{name:"build"}})]}HA();B0();var zr0=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:KD.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(NJ).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(zJ).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 Nr0={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.1",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 sZA extends mw{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",Nr0,{...A,layouts:f},zr0);this.layouts=f}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new lZA(A.logger),this._slotRegistry=new io,A.messaging.subscribe("plugin:site-builder:slot:register",async(f)=>{let{slotName:Q,pluginId:w,render:B,priority:x}=f.payload;return this._slotRegistry?.register(Q,{pluginId:w,render:B,...x!==void 0&&{priority:x}}),{success:!0}}),A.messaging.subscribe("plugin:site-builder:head-script:register",async(f)=>{let{pluginId:Q,script:w}=f.payload;return this.headScripts.set(Q,w),{success:!0}}),A.entities.registerDataSource(new aZA(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=wx.getInstance(A.entityService,A.logger),A.messaging.subscribe("sync:initial:completed",async()=>{return await this.profileService?.initialize(),this.logger.info("AnchorProfileService initialized"),{success:!0}}),Kr0(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)To(this.config.routes,this.id,this.routeRegistry);if(this.siteBuilder=q7.getInstance(A.logger.child("SiteBuilder"),A,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new oZA(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 nZA(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 w=await this.getInstructions();if(w)A.registerInstructions(w)}return{success:!0}}),Jr0({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 kr0(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 iY(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((Q)=>({id:Q.id,path:Q.path,title:Q.title,description:Q.description,sections:Q.sections.map((w)=>({id:w.id,template:w.template}))})),null,2)}]}}},{uri:"site://templates",name:"View Templates",description:"All registered view templates",mimeType:"application/json",handler:async()=>{let f=A.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(f.map((Q)=>({name:Q.name,description:Q.description,hasWebRenderer:!!Q.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let A=this.getContext();try{let f=await iY(A.entityService);return`## Your Site
|
|
2730
2730
|
${[`**Title:** ${f.title}`,`**Description:** ${f.description}`,A.domain&&`**Domain:** ${A.domain}`,A.siteUrl&&`**URL:** ${A.siteUrl}`].filter(Boolean).join(`
|
|
2731
2731
|
`)}`}catch{return}}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),this.rebuildManager?.dispose(),q7.resetInstance(),this.logger.debug("Cleaned up all event subscriptions")}}function uW(A={}){return new sZA(A)}HA();var $S2=KD.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 cS2,Fragment as DS2}from"preact";function tZA({name:A,slots:f}){if(!f?.hasSlot(A))return null;let w=f.getSlot(A).map((B)=>B.render());return cS2(DS2,{},...w)}B0();zD();vO();HA();var eZA=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();HA();var US2=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()}),oKQ=e5.extend({title:X.string().optional(),slug:X.string().optional()});class AWA extends J9{constructor(A,f){super(A,f,{schema:US2,jobTypeName:"blog-generation",entityType:"post"})}async generate(A,f){let{prompt:Q,coverImageId:w,seriesName:B,seriesIndex:x,skipAi:I}=A,{title:$,content:c,excerpt:D}=A;if(I){if(!$)this.failEarly("Title is required when skipAi is true");c=c??`## Introduction
|
|
2732
2732
|
|
|
@@ -2771,7 +2771,7 @@ The excerpt should be clear, concise, and compelling.`});HA();tf();zD();import{j
|
|
|
2771
2771
|
Note: This is part of a series called "${Q.seriesName}".`:""}`;return A.ai.generate({prompt:w,templateName:"blog:generation"})}),A.eval.registerHandler("generateExcerpt",async(f)=>{let Q=bS2.parse(f);return A.ai.generate({prompt:`Title: ${Q.title}
|
|
2772
2772
|
|
|
2773
2773
|
Content:
|
|
2774
|
-
${Q.content}`,templateName:"blog:excerpt"})})}var ir0={name:"@brains/blog",private:!0,version:"0.2.0-alpha.
|
|
2774
|
+
${Q.content}`,templateName:"blog:excerpt"})})}var ir0={name:"@brains/blog",private:!0,version:"0.2.0-alpha.1",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 BWA extends zf{entityType=UW.entityType;schema=EN;adapter=UW;constructor(A={}){super("blog",ir0,A,eZA)}getEntityTypeConfig(){return{weight:2}}createGenerationHandler(A){return new AWA(this.logger.child("BlogGenerationJobHandler"),A)}getTemplates(){return Mr0()}getDataSources(){return[new QWA(this.logger.child("BlogDataSource"))]}async onRegister(A){let{RSSDataSource:f}=await Promise.resolve().then(() => (Sr0(),mr0));A.entities.registerDataSource(new f(this.logger.child("RSSDataSource"))),await Or0(A,this.logger),jr0(A,this.logger),Pr0(A,this.logger),gr0(A),this.logger.info("Blog plugin registered (routes auto-generated at /posts/)")}}function xWA(A={}){return new BWA(A)}zD();vO();B0();HA();$6();var R4=X.object({title:X.string(),slug:X.string(),coverImageId:X.string().optional()}),yr0=R4.pick({title:!0,slug:!0}),LN=X2.extend({metadata:yr0}),lo=LN.extend({frontmatter:R4}),no=lo.extend({description:X.string().optional(),postCount:X.number(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),lr0=X.object({description:X.string().optional()});function HW(A){return new ff(lr0,{title:A,mappings:[{key:"description",label:"Description",type:"string"}]})}$6();class IWA extends q2{constructor(){super({entityType:"series",schema:LN,frontmatterSchema:R4,supportsCoverImage:!0,bodyFormatter:HW("")})}toMarkdown(A){let f,Q={};try{f=this.parseFrontMatter(A.content,R4).coverImageId,Q=HW(A.metadata.title).parse(this.extractBody(A.content))}catch{}let w={title:A.metadata.title,slug:A.metadata.slug,...f&&{coverImageId:f}},x=HW(A.metadata.title).format(Q);return this.buildMarkdown(x,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,R4);return{content:A,entityType:"series",metadata:{title:f.title,slug:f.slug}}}parseBody(A){try{let f=this.parseFrontMatter(A,R4);return HW(f.title).parse(this.extractBody(A))}catch{return{}}}generateFrontMatter(){return""}}var qN=new IWA;B0();HA();_I();class $WA{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}),Q=new Map(f.map((B)=>[B.id,B])),w=new Set;for(let B of A){let x=w2(B);w.add(x);let I=Q.get(x),$=I?.content??this.createSeriesContent(B),c=Bw($);if(I?.contentHash===c)continue;let D={id:x,entityType:"series",content:$,contentHash:c,created:I?.created??new Date().toISOString(),updated:new Date().toISOString(),metadata:{title:B,slug:w2(B)}};await this.entityService.upsertEntity(D),this.logger.debug(`Upserted series: ${B}`)}for(let B of f)if(!w.has(B.id))await this.entityService.deleteEntity("series",B.id),this.logger.debug(`Deleted orphaned series: ${B.id}`)}async handleEntityChange(A,f){let Q=this.getSeriesName(A);if(Q)await this.ensureSeriesExists(Q);if(f&&f!==Q)await this.cleanupOrphanedSeries(f)}async handleEntityDeleted(){await this.syncAllSeries()}getSeriesName(A){let Q=A.metadata.seriesName;return typeof Q==="string"?Q:void 0}async ensureSeriesExists(A){let f=w2(A);if(await this.entityService.getEntity("series",f))return;let w=this.createSeriesContent(A),B={id:f,entityType:"series",content:w,contentHash:Bw(w),created:new Date().toISOString(),updated:new Date().toISOString(),metadata:{title:A,slug:w2(A)}};await this.entityService.upsertEntity(B),this.logger.debug(`Created series: ${A}`)}async cleanupOrphanedSeries(A){let f=w2(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 Q of f){if(Q==="series")continue;if((await this.entityService.listEntities(Q,{filter:{metadata:{seriesName:A}},limit:1})).length>0)return!0}return!1}async collectSeriesNames(){let A=new Set,f=this.entityService.getEntityTypes();for(let Q of f){if(Q==="series")continue;let w=await this.entityService.listEntities(Q,{limit:1000});for(let B of w){let x=this.getSeriesName(B);if(x)A.add(x)}}return A}createSeriesContent(A){let f={title:A,slug:w2(A)};return I6("",f)}}B0();HA();var CS2=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()}),_S2=X.object({type:X.enum(["list","detail"]),seriesName:X.string().optional()});function VS2(A){let f=_S2.safeParse(A);if(f.success)return{type:f.data.type,seriesName:f.data.seriesName};let Q=CS2.safeParse(A);if(Q.success){let{query:w}=Q.data;if(w.id)return{type:"detail",seriesSlug:w.id};return{type:"list"}}throw Error('Invalid series query format. Expected { type: "list"|"detail" } or { entityType: "series", query: { id?: string } }')}function nr0(A){let f=H2(A.content,R4);return lo.parse({...A,frontmatter:f.metadata})}class cWA{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(A){this.logger=A}async fetch(A,f,Q){let w=VS2(A),B=Q.entityService;if(w.type==="list")return this.fetchSeriesList(f,B);if(w.seriesName)return this.fetchSeriesDetail(w.seriesName,f,B);if(w.seriesSlug)return this.fetchSeriesDetailBySlug(w.seriesSlug,f,B);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(A,f){let Q=await f.listEntities("series",{limit:1000}),w=await this.countEntitiesPerSeries(f),B=Q.map((x)=>{let I=nr0(x),$=qN.parseBody(x.content);return{...I,description:$.description,postCount:w.get(x.metadata.title)??0}});return this.logger.debug(`Found ${B.length} series entities`),A.parse({series:B})}async fetchSeriesDetail(A,f,Q,w){if(!w)w=(await Q.listEntities("series",{filter:{metadata:{title:A}}}))[0];if(!w)throw Error(`Series not found: ${A}`);let B=nr0(w),x=qN.parseBody(w.content),I=await this.getSeriesMembers(A,Q);return this.logger.debug(`Found ${I.length} entities in series "${A}"`),f.parse({seriesName:A,posts:I,series:{...B,description:x.description,postCount:I.length},description:x.description})}async fetchSeriesDetailBySlug(A,f,Q){let B=(await Q.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,Q,B)}async countEntitiesPerSeries(A){let f=new Map,Q=A.getEntityTypes();for(let w of Q){if(w==="series")continue;let B=await A.listEntities(w,{limit:1000});for(let x of B){let I=this.getSeriesName(x);if(I)f.set(I,(f.get(I)??0)+1)}}return f}async getSeriesMembers(A,f){let Q=[],w=f.getEntityTypes();for(let B of w){if(B==="series")continue;let x=await f.listEntities(B,{filter:{metadata:{seriesName:A}}});Q.push(...x)}return Q.sort((B,x)=>{let I=B.metadata.seriesIndex,$=x.metadata.seriesIndex;return(typeof I==="number"?I:999)-(typeof $==="number"?$:999)}),Q}getSeriesName(A){let Q=A.metadata.seriesName;return typeof Q==="string"?Q:void 0}}B0();HA();_I();var MS2=X.object({prompt:X.string().optional(),title:X.string().optional(),seriesId:X.string().optional()});class po{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 Q=await this.context.entityService.getEntity("series",f);if(!Q)return{success:!1,error:`Series not found: ${f}`};let w=await this.gatherMemberSummaries(Q.metadata.title);if(w.length===0)return{success:!1,error:`No members found in series: ${Q.metadata.title}`};let B=A.prompt??`Series name: ${Q.metadata.title}
|
|
2775
2775
|
|
|
2776
2776
|
Content in this series:
|
|
2777
2777
|
${w.join(`
|
|
@@ -2783,7 +2783,7 @@ Your task is to write a series description (2-3 sentences) that:
|
|
|
2783
2783
|
3. Is engaging and makes readers want to explore the content
|
|
2784
2784
|
4. Works well as a series overview on a website
|
|
2785
2785
|
|
|
2786
|
-
Be concise and focus on what makes this series unique and valuable.`});var tr0={name:"@brains/series",private:!0,version:"0.2.0-alpha.
|
|
2786
|
+
Be concise and focus on what makes this series unique and valuable.`});var tr0={name:"@brains/series",private:!0,version:"0.2.0-alpha.1",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 DWA extends zf{entityType="series";schema=LN;adapter=qN;manager;constructor(){super("series",tr0)}getEntityTypeConfig(){return{weight:0.5}}createGenerationHandler(A){return new po(this.logger.child("SeriesGenerationHandler"),A)}getTemplates(){return{...ar0(),description:sr0}}getDataSources(){return[new cWA(this.logger.child("SeriesDataSource"))]}async onRegister(A){this.manager=new $WA(A.entityService,this.logger.child("SeriesManager"));let f=this.manager;for(let Q of["entity:created","entity:updated"])A.messaging.subscribe(Q,async(w)=>{try{let B=w.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(Q)=>{try{if(Q.payload.entityType==="series")return{success:!0};return await f.handleEntityDeleted(),{success:!0}}catch(w){return this.logger.error("Failed to handle entity deletion for series",{error:w}),{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(Q){return this.logger.error("Failed to sync series after initial sync",{error:Q}),{success:!1,error:"Series sync failed"}}})}requireManager(){if(!this.manager)throw Error("SeriesPlugin not registered");return this.manager}async derive(A,f,Q){await this.requireManager().handleEntityChange(A)}async deriveAll(A){await this.requireManager().syncAllSeries();let f=new po(this.logger.child("SeriesGenerationHandler"),A),Q=await A.entityService.listEntities("series",{limit:1000});for(let w of Q)try{if(!this.adapter.parseBody(w.content).description)this.logger.info(`Generating description for series: ${w.metadata.title}`),await f.process({seriesId:w.id})}catch(B){this.logger.error(`Failed to generate description for series: ${w.id}`,{error:B})}}}function YWA(){return new DWA}B0();HA();B0();HA();HA();B0();var gS2=X.enum(["draft","queued","published"]),AK=X.object({title:X.string(),slug:X.string().optional(),description:X.string().optional(),author:X.string().optional(),status:gS2,publishedAt:X.string().datetime().optional(),event:X.string().optional(),coverImageId:X.string().optional()}),iS2=AK.pick({title:!0,description:!0,status:!0,publishedAt:!0,coverImageId:!0}).extend({slug:X.string()}),ro=X2.extend({entityType:X.literal("deck"),metadata:iS2}),oo=ro.extend({frontmatter:AK,body:X.string()}),NO=oo.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 uWA extends q2{constructor(){super({entityType:"deck",schema:ro,frontmatterSchema:AK,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 Q=this.parseFrontMatter(A.content,AK),w={...Q,slug:Q.slug??A.metadata.slug};return this.buildMarkdown(f,w)}catch{return f}}fromMarkdown(A){let f=this.parseFrontmatter(A),Q=this.extractBody(A);this.validateSlideStructure(Q);let w=f.slug??w2(f.title),B=f.status;return{entityType:"deck",content:A,metadata:{slug:w,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 EO=new uWA;HA();tf();var TS2=X.object({markdown:X.string().describe("Markdown content with slide separators (---)")}),UWA=a0({name:"deck-detail",description:"Render a presentation deck as Reveal.js slides",schema:TS2,dataSourceId:"decks:entities",requiredPermission:"public",layout:{component:qKA,fullscreen:!0}});tf();HA();var HWA=X.object({decks:X.array(oo)}),KWA=X.object({decks:X.array(NO),pageTitle:X.string().optional()});import{jsxDEV as FWA}from"preact/jsx-dev-runtime";var XWA=({decks:A,pageTitle:f})=>{let Q=A.map((w)=>({id:w.id,url:w.url,title:w.frontmatter.title,date:w.frontmatter.publishedAt??w.created,description:w.frontmatter.description}));return FWA("div",{className:"deck-list bg-theme",children:FWA("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:FWA(EY,{title:f??"Presentations",items:Q},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)};HA();class ao extends ff{constructor(){super(HWA,{title:"Deck List",mappings:[{key:"decks",label:"Decks",type:"array",itemType:"object"}]})}}var ZWA=a0({name:"deck-list",description:"List view of all presentation decks",schema:KWA,dataSourceId:"decks:entities",requiredPermission:"public",formatter:new ao,layout:{component:XWA}});HA();B0();var mS2=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")}),er0=a0({name:"decks:generation",description:"Template for AI to generate complete slide decks from prompts",schema:mS2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are creating slide decks in a distinctive voice that blends philosophy, technology, and culture.
|
|
2787
2787
|
|
|
2788
2788
|
Your task is to generate a complete slide deck based on the user's prompt.
|
|
2789
2789
|
|
|
@@ -2851,7 +2851,7 @@ Add your conclusion here`,c=c??`Presentation: ${I}`,await this.reportProgress(f,
|
|
|
2851
2851
|
Note: This presentation is for "${B}".`:""}`,q=await this.context.ai.generate({prompt:k,templateName:"decks:generation"});I=I??q.title,$=$??q.content,c=c??q.description,await this.reportProgress(f,{progress:50,message:`Generated deck: "${I}"`})}else if(!c)await this.reportProgress(f,{progress:30,message:"Generating description with AI"}),c=(await this.context.ai.generate({prompt:`Title: ${I}
|
|
2852
2852
|
|
|
2853
2853
|
Content:
|
|
2854
|
-
${$}`,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(!I||!$)this.failEarly("Title and content are required");let u={slug:w2(I),title:I,status:"draft"},K=await j3({entityType:"deck",title:I,deriveId:(J)=>J,regeneratePrompt:"Generate a different presentation deck title on the same topic.",context:this.context});if(K!==I)u.title=K,u.slug=w2(K);let F={title:u.title,status:u.status,slug:u.slug,description:c,author:w,event:B},Z=I6($,F);return{id:K,content:Z,metadata:u,title:K,resultExtras:{title:K,slug:u.slug},createOptions:{deduplicateId:!0}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var fd0={name:"@brains/decks",private:!0,version:"0.2.0-alpha.
|
|
2854
|
+
${$}`,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(!I||!$)this.failEarly("Title and content are required");let u={slug:w2(I),title:I,status:"draft"},K=await j3({entityType:"deck",title:I,deriveId:(J)=>J,regeneratePrompt:"Generate a different presentation deck title on the same topic.",context:this.context});if(K!==I)u.title=K,u.slug=w2(K);let F={title:u.title,status:u.status,slug:u.slug,description:c,author:w,event:B},Z=I6($,F);return{id:K,content:Z,metadata:u,title:K,resultExtras:{title:K,slug:u.slug},createOptions:{deduplicateId:!0}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var fd0={name:"@brains/decks",private:!0,version:"0.2.0-alpha.1",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 JWA extends zf{entityType=EO.entityType;schema=EO.schema;adapter=EO;constructor(){super("decks",fd0)}createGenerationHandler(A){return new GWA(this.logger.child("DeckGenerationJobHandler"),A)}getTemplates(){return{"deck-detail":UWA,"deck-list":ZWA,generation:er0,description:Ad0}}getDataSources(){return[new WWA(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:Q,entityId:w}=f.payload;if(Q!=="deck")return{success:!0};try{let B=await A.entityService.getEntity("deck",w);if(!B)return await A.messaging.send("publish:report:failure",{entityType:Q,entityId:w,error:`Deck not found: ${w}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=new Date().toISOString(),I={...B,metadata:{...B.metadata,status:"published",publishedAt:x}};await A.entityService.updateEntity({...I,content:this.adapter.toMarkdown(I)}),await A.messaging.send("publish:report:success",{entityType:Q,entityId:w,result:{id:w}})}catch(B){await A.messaging.send("publish:report:failure",{entityType:Q,entityId:w,error:v0(B)})}return{success:!0}})}registerEvalHandlers(A){A.eval.registerHandler("generateDeck",async(f)=>{let Q=X.object({prompt:X.string(),event:X.string().optional()}).parse(f);return A.ai.generate({prompt:`${Q.prompt}${Q.event?`
|
|
2855
2855
|
|
|
2856
2856
|
Note: This presentation is for "${Q.event}".`:""}`,templateName:"decks:generation"})}),A.eval.registerHandler("generateDescription",async(f)=>{let Q=X.object({title:X.string(),content:X.string()}).parse(f);return A.ai.generate({prompt:`Title: ${Q.title}
|
|
2857
2857
|
|
|
@@ -2866,7 +2866,7 @@ Guidelines:
|
|
|
2866
2866
|
3. Depth: Provide enough detail to be useful as a reference, but stay focused on the topic.
|
|
2867
2867
|
4. Style: Informative and educational. Write as if explaining to yourself for future reference.
|
|
2868
2868
|
5. Length: Adjust based on topic complexity - concise for simple topics, more detailed for complex ones.
|
|
2869
|
-
6. No meta-commentary: Just provide the content directly without phrases like "Here is..." or "This note covers..."`});B0();HA();var Bd0=X.object({prompt:X.string(),title:X.string().optional()}),pS2=e5.extend({title:X.string().optional()});class so extends J9{constructor(A,f){super(A,f,{schema:Bd0,jobTypeName:"note-generation",entityType:"base"})}async generate(A,f){await this.reportProgress(f,{progress:10,message:"Generating note content with AI"});let Q=await this.context.ai.generate({prompt:A.prompt,templateName:"note:generation"}),w=A.title??Q.title;return await this.reportProgress(f,{progress:50,message:`Generated note: "${w}"`}),{id:w,content:_N.createNoteContent(w,Q.body),metadata:{title:w},title:w,resultExtras:{title:w}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var xd0={name:"@brains/note",private:!0,version:"0.2.0-alpha.
|
|
2869
|
+
6. No meta-commentary: Just provide the content directly without phrases like "Here is..." or "This note covers..."`});B0();HA();var Bd0=X.object({prompt:X.string(),title:X.string().optional()}),pS2=e5.extend({title:X.string().optional()});class so extends J9{constructor(A,f){super(A,f,{schema:Bd0,jobTypeName:"note-generation",entityType:"base"})}async generate(A,f){await this.reportProgress(f,{progress:10,message:"Generating note content with AI"});let Q=await this.context.ai.generate({prompt:A.prompt,templateName:"note:generation"}),w=A.title??Q.title;return await this.reportProgress(f,{progress:50,message:`Generated note: "${w}"`}),{id:w,content:_N.createNoteContent(w,Q.body),metadata:{title:w},title:w,resultExtras:{title:w}}}summarizeDataForLog(A){return{prompt:A.prompt,title:A.title}}}var xd0={name:"@brains/note",private:!0,version:"0.2.0-alpha.1",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 NWA extends zf{entityType=_N.entityType;schema=CN;adapter=_N;constructor(A={}){super("note",xd0,A,kWA)}createGenerationHandler(A){return new so(this.logger.child("NoteGenerationJobHandler"),A)}getTemplates(){return{generation:zWA}}async onRegister(A){A.eval.registerHandler("generateNote",async(f)=>{let Q=X.object({prompt:X.string()}).parse(f);return A.ai.generate({prompt:Q.prompt,templateName:"note:generation"})})}}function KW(A={}){return new NWA(A)}B0();HA();HA();B0();var Id0=X.object({ref:X.string(),label:X.string()}),$d0=X.enum(["pending","draft","published"]),pY=X.object({status:$d0,title:X.string(),url:X.string().url(),description:X.string().optional(),keywords:X.array(X.string()),domain:X.string(),capturedAt:X.string().datetime(),source:Id0}),cd0=pY.pick({title:!0,status:!0}),LO=X2.extend({entityType:X.literal("link"),metadata:cd0}),EWA=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 QK extends q2{constructor(){super({entityType:"link",schema:LO,frontmatterSchema:pY})}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},Q=A.summary??"";return this.buildMarkdown(Q,f)}parseLinkContent(A){return{frontmatter:this.parseFrontMatter(A,pY),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 hWA=new QK;B0();HA();var dS2=X.object({success:X.boolean().describe("Set to true if you can extract meaningful content. Set to false only if the provided content is empty, just an error message, or otherwise unusable."),error:X.string().optional().describe("If success is false, explain why content could not be extracted"),title:X.string().max(80).describe("The page title - extract from the content or create a descriptive one. Leave empty string if success is false."),description:X.string().describe("A one-sentence description of what the page is about. Leave empty string if success is false."),summary:X.string().describe("A 1-2 paragraph summary of the main content. Leave empty string if success is false."),keywords:X.array(X.string()).describe("3-5 relevant keywords that categorize this content. Leave empty array if success is false.")}),Dd0=a0({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:dS2,basePrompt:`You are an expert at extracting key information from webpage content.
|
|
2870
2870
|
|
|
2871
2871
|
You will receive webpage content in markdown format. Your job is to extract structured information from it.
|
|
2872
2872
|
|
|
@@ -2882,7 +2882,7 @@ Focus only on information present in the provided content. Do not make up or hal
|
|
|
2882
2882
|
|
|
2883
2883
|
`))return{success:!1,error:I.trim(),errorType:"fetch_failed"};return{success:!0,content:I}}catch(Q){return this.handleFetchError(Q,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();HA();import{createHash as tS2}from"crypto";class CO{static URL_PATTERN=/https?:\/\/[^\s<>"{}|\\^`[\]]+?(?=[,;:\s]|$)/gi;static extractUrls(A){let f=A.match(CO.URL_PATTERN)??[];return[...new Set(f)]}static normalizeUrl(A){try{let f=new URL(A),Q=f.pathname.replace(/\/$/,"")||"/";return`${f.protocol}//${f.host}${Q}`}catch{return A}}static generateEntityId(A){let f=this.normalizeUrl(A),Q=tS2("sha256").update(f).digest("hex");try{return`${new URL(f).hostname.replace(/\./g,"-")}-${Q.substring(0,6)}`}catch{return Q.substring(0,12)}}static isValidUrl(A){try{let f=new URL(A);return["http:","https:"].includes(f.protocol)}catch{return!1}}}var eS2=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()}),HJQ=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 VWA extends qQ{context;linkAdapter;urlFetcher;constructor(A,f,Q){super(A,{schema:eS2,jobTypeName:"link-capture"});this.context=f,this.linkAdapter=new QK,this.urlFetcher=new VN(Q?.jinaApiKey?{jinaApiKey:Q.jinaApiKey}:void 0)}async process(A,f,Q){let{url:w,metadata:B}=A;try{await Q.report({progress:U2.START,total:100,message:"Starting link capture"});let x=CO.generateEntityId(w);await Q.report({progress:U2.INIT,total:100,message:"Checking for existing link"});let I=await this.context.entityService.getEntity("link",x);if(I){this.logger.info("Link already captured, returning existing",{url:w,entityId:x});let{frontmatter:Z}=this.linkAdapter.parseLinkContent(I.content);return{success:!0,entityId:I.id,title:Z.title,url:w,status:I.metadata.status}}await Q.report({progress:U2.FETCH,total:100,message:"Fetching webpage content"});let $=await this.urlFetcher.fetch(w);if(!$.success){if($.errorType==="url_not_found"||$.errorType==="url_unreachable")return this.logger.warn("Link URL not accessible",{url:w,errorType:$.errorType,error:$.error}),{success:!1,error:`Could not capture link: ${$.error}`}}await Q.report({progress:U2.PROCESS,total:100,message:"Extracting content with AI"});let c=await this.context.ai.generate({templateName:"link:extraction",prompt:$.success?`Extract structured information from this webpage content:
|
|
2884
2884
|
|
|
2885
|
-
${$.content}`:`The URL ${w} could not be fetched. Return success: false with error: "${$.error}"`,data:{url:w,hasContent:$.success},interfacePermissionGrant:"public"});this.logger.debug("AI extraction result",{result:c}),await Q.report({progress:U2.EXTRACT,total:100,message:"Processing extraction results"});let D=this.resolveSource(B),u=new Date().toISOString();if(c.success===!1||!c.title||!c.description||!c.summary){let Z=c.title||new URL(w).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:w}),await Q.report({progress:U2.SAVE,total:100,message:"Saving link as pending"});let J=this.linkAdapter.createLinkContent({status:"pending",title:Z,url:w,description:c.description,summary:c.summary,keywords:c.keywords,domain:new URL(w).hostname,capturedAt:u,source:D}),v=await this.context.entityService.createEntity({id:x,entityType:"link",content:J,metadata:{status:"pending",title:Z}});return await Q.report({progress:U2.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:v.entityId,title:Z,url:w,status:"pending"}}await Q.report({progress:U2.SAVE,total:100,message:`Saving link: "${c.title}"`});let K=this.linkAdapter.createLinkContent({status:"draft",title:c.title,url:w,description:c.description,summary:c.summary,keywords:c.keywords,domain:new URL(w).hostname,capturedAt:u,source:D}),F=await this.context.entityService.createEntity({id:x,entityType:"link",content:K,metadata:{status:"draft",title:c.title}});return await Q.report({progress:U2.COMPLETE,total:100,message:`Link captured: "${c.title}"`}),{success:!0,entityId:F.entityId,title:c.title,url:w,status:"draft"}}catch(x){return this.logger.error("Link capture job failed",{error:x,jobId:f,data:A}),GB.failure(x)}}resolveSource(A){let f=A?.channelId,Q=A?.channelName;if(f)return{ref:`matrix:${f}`,label:Q??f};let w=A?.interfaceId??"cli";return{ref:`${w}:local`,label:w.toUpperCase()}}summarizeDataForLog(A){return{url:A.url,interfaceId:A.metadata?.interfaceId}}}var Ud0={name:"@brains/link",private:!0,version:"0.2.0-alpha.
|
|
2885
|
+
${$.content}`:`The URL ${w} could not be fetched. Return success: false with error: "${$.error}"`,data:{url:w,hasContent:$.success},interfacePermissionGrant:"public"});this.logger.debug("AI extraction result",{result:c}),await Q.report({progress:U2.EXTRACT,total:100,message:"Processing extraction results"});let D=this.resolveSource(B),u=new Date().toISOString();if(c.success===!1||!c.title||!c.description||!c.summary){let Z=c.title||new URL(w).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:w}),await Q.report({progress:U2.SAVE,total:100,message:"Saving link as pending"});let J=this.linkAdapter.createLinkContent({status:"pending",title:Z,url:w,description:c.description,summary:c.summary,keywords:c.keywords,domain:new URL(w).hostname,capturedAt:u,source:D}),v=await this.context.entityService.createEntity({id:x,entityType:"link",content:J,metadata:{status:"pending",title:Z}});return await Q.report({progress:U2.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:v.entityId,title:Z,url:w,status:"pending"}}await Q.report({progress:U2.SAVE,total:100,message:`Saving link: "${c.title}"`});let K=this.linkAdapter.createLinkContent({status:"draft",title:c.title,url:w,description:c.description,summary:c.summary,keywords:c.keywords,domain:new URL(w).hostname,capturedAt:u,source:D}),F=await this.context.entityService.createEntity({id:x,entityType:"link",content:K,metadata:{status:"draft",title:c.title}});return await Q.report({progress:U2.COMPLETE,total:100,message:`Link captured: "${c.title}"`}),{success:!0,entityId:F.entityId,title:c.title,url:w,status:"draft"}}catch(x){return this.logger.error("Link capture job failed",{error:x,jobId:f,data:A}),GB.failure(x)}}resolveSource(A){let f=A?.channelId,Q=A?.channelName;if(f)return{ref:`matrix:${f}`,label:Q??f};let w=A?.interfaceId??"cli";return{ref:`${w}:local`,label:w.toUpperCase()}}summarizeDataForLog(A){return{url:A.url,interfaceId:A.metadata?.interfaceId}}}var Ud0={name:"@brains/link",private:!0,version:"0.2.0-alpha.1",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 MWA extends zf{entityType=hWA.entityType;schema=LO;adapter=hWA;constructor(A={}){super("link",Ud0,A,EWA)}createGenerationHandler(A){return new VWA(this.logger.child("LinkCaptureJobHandler"),A,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:Dd0,"link-list":Yd0,"link-detail":ud0}}getDataSources(){return[new _WA(this.logger.child("LinksDataSource"))]}async onRegister(A){A.eval.registerHandler("extractContent",async(f)=>{let{url:Q}=X.object({url:X.string().url()}).parse(f),B=await new VN(this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0).fetch(Q);if(!B.success)return{success:!1,error:B.error,errorType:B.errorType};return A.ai.generate({templateName:"link:extraction",prompt:`Extract structured information from this webpage content:
|
|
2886
2886
|
|
|
2887
2887
|
${B.content}`,data:{url:Q,hasContent:!0},interfacePermissionGrant:"public"})})}}function Hd0(A={}){return new MWA(A)}var FW=Hd0;HA();var VJQ=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();HA();tf();HA();B0();var Kd0=X.enum(["draft","published"]),P4=X.object({title:X.string(),slug:X.string().optional(),status:Kd0,publishedAt:X.string().datetime().optional(),description:X.string(),year:X.number(),coverImageId:X.string().optional(),url:X.string().url().optional()}),Fd0=P4.pick({title:!0,status:!0,publishedAt:!0,year:!0}).extend({slug:X.string()}),MN=X2.extend({entityType:X.literal("project"),metadata:Fd0}),eo=X.object({context:X.string(),problem:X.string(),solution:X.string(),outcome:X.string()}),_O=MN.extend({frontmatter:P4,body:X.string(),structuredContent:eo.optional(),coverImageUrl:X.string().optional()}),ON=_O.extend({url:X.string().optional(),typeLabel:X.string().optional(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()}),fy2=_O.extend({url:X.string(),typeLabel:X.string(),coverImageUrl:X.string().optional(),coverImageWidth:X.number().optional(),coverImageHeight:X.number().optional()});B0();HA();HA();class OWA extends ff{constructor(){super(eo,{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 jWA=new OWA;class RWA extends q2{constructor(){super({entityType:"project",schema:MN,frontmatterSchema:P4,supportsCoverImage:!0,bodyFormatter:jWA})}toMarkdown(A){let f=this.extractBody(A.content);try{let Q=this.parseFrontMatter(A.content,P4),w={...Q,slug:Q.slug??A.metadata.slug};return this.buildMarkdown(f,w)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,P4),Q=f.slug??w2(f.title);return{content:A,entityType:"project",metadata:{title:f.title,slug:Q,status:f.status,publishedAt:f.publishedAt,year:f.year}}}parseProjectFrontmatter(A){return this.parseFrontMatter(A.content,P4)}parseStructuredContent(A){return jWA.parse(this.extractBody(A.content))}createProjectContent(A,f){let Q=jWA.format(f);return this.buildMarkdown(Q,A)}}var wK=new RWA;HA();var PWA=X.object({});import{jsxDEV as _7,Fragment as wy2}from"preact/jsx-dev-runtime";var Qy2=({project:A})=>{let{frontmatter:f,url:Q,coverImageUrl:w}=A;return _7(Gf,{href:Q,children:[w&&_7("img",{src:w,alt:f.title,className:"w-full h-56 object-cover rounded-md mb-4"},void 0,!1,void 0,this),_7(V9,{children:f.title},void 0,!1,void 0,this),_7("p",{className:"text-theme leading-relaxed",children:f.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},gWA=({projects:A,pageTitle:f,pagination:Q,baseUrl:w="/projects"})=>{let B=f??"Projects",x=Q?.totalItems??A.length,I=`Browse all ${x} ${x===1?"project":"projects"}`;return _7(wy2,{children:[_7(p2,{title:B,description:I},void 0,!1,void 0,this),_7("div",{className:"project-list bg-theme",children:_7("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[_7("h1",{className:"text-4xl font-bold text-heading mb-12",children:B},void 0,!1,void 0,this),_7("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-8",children:A.map(($)=>_7(Qy2,{project:$},$.id,!1,void 0,this))},void 0,!1,void 0,this),Q&&Q.totalPages>1&&_7("div",{className:"mt-12",children:_7(u$,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:w},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 uQ,Fragment as Xd0}from"preact/jsx-dev-runtime";var By2=({prevProject:A,nextProject:f})=>{if(!A&&!f)return null;return uQ("nav",{className:"pt-12 mt-12 border-t border-theme-muted",children:uQ("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[A?uQ(Gf,{href:A.url,variant:"compact",children:[uQ("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Previous"},void 0,!1,void 0,this),uQ("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):uQ("div",{},void 0,!1,void 0,this),f&&uQ(Gf,{href:f.url,variant:"compact",className:"md:text-right",children:[uQ("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Next"},void 0,!1,void 0,this),uQ("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)},Aa=({title:A,content:f})=>{if(!f)return null;return uQ("section",{className:"mb-12",children:[uQ("h2",{className:"text-2xl font-bold text-heading mb-4",children:A},void 0,!1,void 0,this),uQ(Y$,{markdown:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},iWA=({project:A,prevProject:f,nextProject:Q})=>{let{frontmatter:w,structuredContent:B,metadata:x,coverImageUrl:I}=A;return uQ(Xd0,{children:[uQ(p2,{title:w.title,description:w.description,...I&&{ogImage:I},ogType:"article"},void 0,!1,void 0,this),uQ("article",{className:"project-detail",children:uQ("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:uQ("div",{className:"max-w-3xl mx-auto",children:[I&&A.coverImageWidth&&A.coverImageHeight&&uQ(NY,{src:I,alt:w.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8 shadow-lg"},void 0,!1,void 0,this),uQ("h1",{className:"text-4xl md:text-5xl font-bold text-heading leading-tight tracking-tight mb-4",children:w.title},void 0,!1,void 0,this),uQ("div",{className:"flex flex-wrap items-center gap-4 text-theme-muted mb-8",children:[uQ("span",{className:"text-sm",children:x.year},void 0,!1,void 0,this),w.url&&uQ(Xd0,{children:[uQ("span",{className:"text-theme-muted",children:"|"},void 0,!1,void 0,this),uQ("a",{href:w.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),uQ("p",{className:"text-lg text-theme mb-12 leading-relaxed",children:w.description},void 0,!1,void 0,this),B&&uQ("div",{className:"case-study",children:[uQ(Aa,{title:"Context",content:B.context},void 0,!1,void 0,this),uQ(Aa,{title:"Problem",content:B.problem},void 0,!1,void 0,this),uQ(Aa,{title:"Solution",content:B.solution},void 0,!1,void 0,this),uQ(Aa,{title:"Outcome",content:B.outcome},void 0,!1,void 0,this)]},void 0,!0,void 0,this),uQ(By2,{prevProject:f,nextProject:Q},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)};HA();B0();var xy2=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)")}),TWA=a0({name:"portfolio:generation",description:"Template for AI to generate portfolio project case studies",schema:xy2,dataSourceId:"shell:ai-content",requiredPermission:"public",basePrompt:`You are helping to create a professional portfolio case study based on REAL project information.
|
|
2888
2888
|
|
|
@@ -2901,7 +2901,7 @@ Guidelines:
|
|
|
2901
2901
|
CRITICAL: Only include information that can be derived from the provided content. If information is missing, keep that section brief rather than inventing details.
|
|
2902
2902
|
|
|
2903
2903
|
Tone: Professional but accessible. Write for someone evaluating real work.
|
|
2904
|
-
Structure: Use markdown formatting. Break long sections into paragraphs for readability.`});B0();HA();var Iy2=X.object({prompt:X.string(),year:X.number(),title:X.string().optional()}),uvQ=e5.extend({title:X.string().optional()});class fa extends J9{constructor(A,f){super(A,f,{schema:Iy2,jobTypeName:"project-generation",entityType:"project"})}async generate(A,f){let{prompt:Q,year:w}=A;await this.reportProgress(f,{progress:10,message:"Generating project content with AI"});let B=await this.context.ai.generate({prompt:Q,templateName:"portfolio:generation"}),x=A.title??B.title,I=w2(x);await this.reportProgress(f,{progress:50,message:`Generated project: "${x}"`});let $={title:x,slug:I,status:"draft",description:B.description,year:w},c={context:B.context,problem:B.problem,solution:B.solution,outcome:B.outcome};return{id:I,content:wK.createProjectContent($,c),metadata:{title:x,slug:I,status:"draft",year:w},title:x,resultExtras:{title:x}}}summarizeDataForLog(A){return{prompt:A.prompt.substring(0,100),year:A.year,title:A.title}}}B0();B0();function $y2(A){let f=H2(A.content,P4),Q=wK.parseStructuredContent(A);return _O.parse({...A,frontmatter:f.metadata,body:f.content,structuredContent:Q})}class Qa extends c6{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 $y2(A)}buildDetailResult(A,f){return{project:A,prevProject:f?.prev??null,nextProject:f?.next??null}}buildListResult(A,f,Q){return{projects:A,pagination:f,baseUrl:Q.baseUrl}}}var Zd0={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.
|
|
2904
|
+
Structure: Use markdown formatting. Break long sections into paragraphs for readability.`});B0();HA();var Iy2=X.object({prompt:X.string(),year:X.number(),title:X.string().optional()}),uvQ=e5.extend({title:X.string().optional()});class fa extends J9{constructor(A,f){super(A,f,{schema:Iy2,jobTypeName:"project-generation",entityType:"project"})}async generate(A,f){let{prompt:Q,year:w}=A;await this.reportProgress(f,{progress:10,message:"Generating project content with AI"});let B=await this.context.ai.generate({prompt:Q,templateName:"portfolio:generation"}),x=A.title??B.title,I=w2(x);await this.reportProgress(f,{progress:50,message:`Generated project: "${x}"`});let $={title:x,slug:I,status:"draft",description:B.description,year:w},c={context:B.context,problem:B.problem,solution:B.solution,outcome:B.outcome};return{id:I,content:wK.createProjectContent($,c),metadata:{title:x,slug:I,status:"draft",year:w},title:x,resultExtras:{title:x}}}summarizeDataForLog(A){return{prompt:A.prompt.substring(0,100),year:A.year,title:A.title}}}B0();B0();function $y2(A){let f=H2(A.content,P4),Q=wK.parseStructuredContent(A);return _O.parse({...A,frontmatter:f.metadata,body:f.content,structuredContent:Q})}class Qa extends c6{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 $y2(A)}buildDetailResult(A,f){return{project:A,prevProject:f?.prev??null,nextProject:f?.next??null}}buildListResult(A,f,Q){return{projects:A,pagination:f,baseUrl:Q.baseUrl}}}var Zd0={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.1",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 Dy2=X.object({projects:X.array(ON),pageTitle:X.string().optional(),pagination:Qx.nullable(),baseUrl:X.string().optional()});class mWA extends zf{entityType=wK.entityType;schema=MN;adapter=wK;constructor(A={}){super("portfolio",Zd0,A,PWA)}createGenerationHandler(A){return new fa(this.logger.child("ProjectGenerationJobHandler"),A)}getTemplates(){return{"project-list":a0({name:"project-list",description:"Portfolio project list page template",schema:Dy2,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:gWA}}),"project-detail":a0({name:"project-detail",description:"Individual project case study template",schema:X.object({project:ON,prevProject:ON.nullable(),nextProject:ON.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:iWA}}),generation:TWA}}getDataSources(){return[new Qa(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 Q=X.object({prompt:X.string(),year:X.number()}).parse(f);return A.ai.generate({prompt:Q.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:Q,entityId:w}=f.payload;if(Q!=="project")return{success:!0};try{let B=await A.entityService.getEntity("project",w);if(!B)return await A.messaging.send("publish:report:failure",{entityType:Q,entityId:w,error:`Project not found: ${w}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=H2(B.content,P4),I=new Date().toISOString(),$=I6(x.content,{...x.metadata,status:"published",publishedAt:I});await A.entityService.updateEntity({...B,content:$,metadata:{...B.metadata,status:"published",publishedAt:I}}),await A.messaging.send("publish:report:success",{entityType:Q,entityId:w,publishedAt:I})}catch(B){await A.messaging.send("publish:report:failure",{entityType:Q,entityId:w,error:v0(B)})}return{success:!0}})}}function SWA(A={}){return new mWA(A)}B0();HA();HA();var Wd0=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();HA();B0();var Yy2=X.object({aliases:X.array(X.string()).optional()}),wa=X2.extend({entityType:X.literal("topic"),metadata:Yy2}),pvQ=X.object({content:X.string(),keywords:X.array(X.string())}),Gd0=X.object({title:X.string().describe("Topic title"),keywords:X.array(X.string()).optional().describe("Topic keywords")}),rvQ=X.object({timeWindowHours:X.number().min(1),minRelevanceScore:X.number().min(0).max(1)}),dvQ=X.object({topicIds:X.array(X.string()).min(2),similarityThreshold:X.number().min(0).max(1)});class V7 extends q2{constructor(){super({entityType:"topic",schema:wa,frontmatterSchema:Gd0})}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),w=this.buildMarkdown("",this.buildFrontmatter(f.title,f.keywords)).match(/^---\n[\s\S]*?\n---/);return w?w[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))}}HA();var Jd0=40,uy2=new V7;async function Ba(A,f=Jd0){return(await A.listEntities("topic",{limit:f})).map((w)=>uy2.parseTopicBody(w.content).title).filter((w)=>w.trim().length>0)}function xa(A){let f=(A.existingTopicTitles??[]).slice(0,Jd0),Q=f.length>0?`
|
|
2905
2905
|
|
|
2906
2906
|
Existing topic titles to reuse when they clearly fit:
|
|
2907
2907
|
${f.map((w)=>`- ${w}`).join(`
|
|
@@ -3009,13 +3009,13 @@ RULES:
|
|
|
3009
3009
|
Return JSON with:
|
|
3010
3010
|
- title
|
|
3011
3011
|
- content
|
|
3012
|
-
- keywords`,requiredPermission:"public"});tf();HA();var Ey2=X.object({id:X.string(),title:X.string(),summary:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()}),MO=X.object({topics:X.array(Ey2),totalCount:X.number()});import{jsxDEV as L$}from"preact/jsx-dev-runtime";var nWA=({topics:A,totalCount:f})=>{return L$("div",{className:"topic-list-container w-full max-w-4xl mx-auto p-6 bg-theme",children:[L$(D$,{title:"Topics",count:f,singularLabel:"topic",description:"discovered from your knowledge base"},void 0,!1,void 0,this),L$("div",{className:"space-y-6",children:A.map((Q)=>L$(Gf,{variant:"vertical",children:[L$(V9,{href:`/topics/${Q.id}`,className:"text-xl",children:Q.title},void 0,!1,void 0,this),L$("p",{className:"text-theme-muted mb-4",children:Q.summary},void 0,!1,void 0,this),L$(M9,{tags:Q.keywords,maxVisible:5,variant:"muted",className:"mb-3"},void 0,!1,void 0,this),L$(q5,{children:L$("div",{className:"flex justify-between text-sm text-theme-muted",children:L$("time",{dateTime:Q.updated,children:["Updated ",dw(Q.updated)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},Q.id,!0,void 0,this))},void 0,!1,void 0,this),A.length===0&&L$(E7,{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)};HA();class Ya extends ff{constructor(){super(MO,{title:"Topic List",mappings:[{key:"topics",label:"Topics",type:"array",itemType:"object"},{key:"totalCount",label:"Total Count",type:"number"}]})}}var Md0=a0({name:"topics:topic-list",description:"List view of all discovered topics",schema:MO,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new Ya,layout:{component:nWA}});tf();HA();var OO=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 BK}from"preact/jsx-dev-runtime";var pWA=({title:A,content:f,keywords:Q,created:w,updated:B})=>{return BK("article",{className:"topic-detail-container max-w-4xl mx-auto p-6 bg-theme",children:[BK(PZ,{title:A,created:w,updated:B},void 0,!1,void 0,this),BK("div",{className:"prose prose-lg max-w-none mb-8 text-theme-muted",children:BK("div",{dangerouslySetInnerHTML:{__html:f}},void 0,!1,void 0,this)},void 0,!1,void 0,this),Q.length>0&&BK("section",{className:"mb-8",children:[BK("h2",{className:"text-xl font-semibold mb-3 text-theme",children:"Keywords"},void 0,!1,void 0,this),BK(M9,{tags:Q,maxVisible:Q.length,size:"sm"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),BK(jZ,{href:"/topics",children:"Back to Topics"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};HA();class ua extends ff{constructor(){super(OO,{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 Od0=a0({name:"topics:topic-detail",description:"Detailed view of a single topic",schema:OO,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new ua,layout:{component:pWA}});B0();HA();class rWA extends c6{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 V7;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:IU(f.content,200),keywords:f.keywords,created:A.created,updated:A.updated}}buildListResult(A,f,Q){return{topics:A,totalCount:A.length}}async fetch(A,f,Q){let{query:w}=this.parseQuery(A);if(w.id){let x=await Q.entityService.getEntity(this.config.entityType,w.id);if(!x)throw Error(`Entity not found: ${w.id}`);let I=this.adapter.parseTopicBody(x.content);return f.parse({id:x.id,title:I.title,content:I.content,keywords:I.keywords,created:x.created,updated:x.updated})}return super.fetch(A,f,Q)}}_I();function jd0(){let A=new V7;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 Rd0={name:"@brains/topics",private:!0,version:"0.2.0-alpha.0",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 by2=new V7;class Pd0 extends zf{entityType="topic";schema=wa;adapter=by2;autoExtractionEnabled=!1;initialDerivationDone=!1;constructor(A={}){super("topics",Rd0,A,Wd0)}getEntityTypeConfig(){return{weight:0.5}}getTemplates(){return{extraction:_d0,"merge-synthesis":Vd0,"topic-list":Md0,"topic-detail":Od0}}getDataSources(){return[new rWA(this.logger.child("TopicsDataSource"))]}async onRegister(A){let f=new Da(A,this.logger);A.jobs.registerHandler("process-single",f);let Q=new lWA(A,this.logger);if(A.jobs.registerHandler("extract",Q),A.insights.register("topic-distribution",jd0()),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 w=async(B)=>{if(!this.autoExtractionEnabled)return{success:!0};let{entityType:x,entity:I}=B.payload;if(!this.shouldProcessEntityType(x))return{success:!0};if(!I)return{success:!0};return await this.handleEntityChanged(A,I),{success:!0}};A.messaging.subscribe("entity:created",w),A.messaging.subscribe("entity:updated",w)}}async derive(A,f,Q){if(!this.shouldProcessEntityType(A.entityType))return;if(!this.isEntityPublished(A))return;await this.handleEntityChanged(Q,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 Q=await ca(f,A,this.logger);this.logger.info("Batch topic extraction complete",Q)}async rebuildAll(A){let f=await this.getEntitiesToExtract(A),Q=await this.replaceAllTopics(f,A);this.logger.info("Topic rebuild complete",Q)}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 Q=A.metadata.status;return Q==="published"||Q===void 0||Q===null}async replaceAllTopics(A,f){let Q=new g4(f.entityService,this.logger),w=await Q.listTopics();for(let x of w)await Q.deleteTopic(x.id);if(A.length===0)return{deleted:w.length,created:0,skipped:0,batches:0};let B=await ca(A,f,this.logger);return{deleted:w.length,...B}}async getEntitiesToExtract(A){let f=this.getExtractableEntityTypes(A),Q=[];for(let w of f){let B=await A.entityService.listEntities(w);for(let x of B){if(!this.isEntityPublished(x))continue;Q.push(x)}}return Q}getExtractableEntityTypes(A){return A.entityService.getEntityTypes().filter((Q)=>this.shouldProcessEntityType(Q))}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(Q){this.logger.error("Failed to queue topic extraction job",{error:v0(Q),entityId:f.id,entityType:f.entityType})}}registerEvalHandler(A){let f=new VO(A,this.logger),Q=X.object({entityType:X.string(),content:X.string(),metadata:X.record(X.unknown()).optional()}),w=(J,v="")=>({id:`eval${v}-${Date.now()}`,entityType:J.entityType,content:J.content,contentHash:Bw(J.content),metadata:J.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}),B=async(J,v,k="")=>{let q=w(J,k);return f.extractFromEntity(q,v)},x=Q.extend({minRelevanceScore:X.number().optional()});A.eval.registerHandler("extractFromEntity",async(J)=>{let v=x.parse(J),k=v.minRelevanceScore??this.config.minRelevanceScore;return B(v,k)});let I=X.object({contentA:Q,contentB:Q,minRelevanceScore:X.number().optional()});A.eval.registerHandler("checkMergeSimilarity",async(J)=>{let v=I.parse(J),k=v.minRelevanceScore??this.config.minRelevanceScore,[q,V]=await Promise.all([B(v.contentA,k,"-a"),B(v.contentB,k,"-b")]),C=q.map((P)=>P.title.toLowerCase()),l=V.map((P)=>P.title.toLowerCase()),r=C.filter((P)=>l.includes(P));return{topicsA:q.map((P)=>({title:P.title,relevanceScore:P.relevanceScore})),topicsB:V.map((P)=>({title:P.title,relevanceScore:P.relevanceScore})),matchingTitles:r,wouldMerge:r.length>0}});let $=X.object({title:X.string(),content:X.string(),keywords:X.array(X.string())}),c=X.object({existingTopics:X.array($),incomingTopic:$,threshold:X.number().optional()});A.eval.registerHandler("detectMergeCandidate",async(J)=>{let v=c.parse(J),k=v.threshold??this.config.mergeSimilarityThreshold,q=new g4(A.entityService,this.logger);for(let C of v.existingTopics)await q.createTopic(C);let V=await q.findMergeCandidate({title:v.incomingTopic.title,keywords:v.incomingTopic.keywords},k);return{found:V!==null,candidateTitle:V?.title,candidateScore:V?.score}});let D=X.object({existingAliases:X.array(X.string()).optional(),canonicalTitle:X.string(),candidateAliases:X.array(X.string())});A.eval.registerHandler("mergeAliases",async(J)=>{let v=D.parse(J);return{aliases:new g4(A.entityService,this.logger).mergeAliases(v.existingAliases,v.canonicalTitle,v.candidateAliases)}});let u=X.object({existingTopics:X.array($.extend({aliases:X.array(X.string()).optional()})).default([]),incomingTopic:$.extend({relevanceScore:X.number().min(0).max(1).optional()}),threshold:X.number().optional()});A.eval.registerHandler("processTopicWithAutoMerge",async(J)=>{let v=u.parse(J),k=new g4(A.entityService,this.logger);for(let r of v.existingTopics)await k.createTopic({title:r.title,content:r.content,keywords:r.keywords,metadata:{aliases:r.aliases??[]}});let q=new Da(A,this.logger),V=Z9.from(async()=>{});if(!V)throw Error("Failed to create progress reporter");let C=await q.process({topic:{title:v.incomingTopic.title,content:v.incomingTopic.content,keywords:v.incomingTopic.keywords,relevanceScore:v.incomingTopic.relevanceScore??0.9},sourceEntityId:"eval-source",sourceEntityType:"post",autoMerge:!0,mergeSimilarityThreshold:v.threshold??this.config.mergeSimilarityThreshold},`eval-job-${Date.now()}`,V),l=await A.entityService.listEntities("topic");return{...C,topicCount:l.length,topics:l.map((r)=>{let P=this.adapter.parseTopicBody(r.content);return{id:r.id,title:P.title,content:P.content,keywords:P.keywords,metadata:r.metadata}})}});let K=X.object({entities:X.array(Q).min(1),minRelevanceScore:X.number().optional()}),F=X.object({existingTopics:X.array($).optional(),entities:X.array(Q)});A.eval.registerHandler("rebuildTopics",async(J)=>{let v=F.parse(J),k=new g4(A.entityService,this.logger);for(let l of v.existingTopics??[])await k.createTopic(l);let q=v.entities.map((l,r)=>w(l,`-rebuild-${r}`)),V=await this.replaceAllTopics(q,A),C=await A.entityService.listEntities("topic");return{...V,topicCount:C.length,topics:C.map((l)=>{let r=this.adapter.parseTopicBody(l.content);return{id:l.id,title:r.title,content:r.content,keywords:r.keywords,metadata:l.metadata}})}}),A.eval.registerHandler("extractSequentially",async(J)=>{let v=K.parse(J),k=v.minRelevanceScore??this.config.minRelevanceScore,q=new g4(A.entityService,this.logger),V=[];for(let[l,r]of v.entities.entries()){let P=w(r,`-sequential-${l}`),O=await f.extractFromEntity(P,k);for(let R of O)await q.createTopic({title:R.title,content:R.content,keywords:R.keywords});V.push({extractedTitles:O.map((R)=>R.title)})}let C=await A.entityService.listEntities("topic");return{totalTopics:C.length,perEntity:V,topics:C.map((l)=>{let r=this.adapter.parseTopicBody(l.content);return{id:l.id,title:r.title,content:r.content,keywords:r.keywords}})}});let Z=X.object({entities:X.array(Q)});A.eval.registerHandler("batchExtract",async(J)=>{let k=Z.parse(J).entities.map((C,l)=>w(C,`-batch-${l}`)),q=await ca(k,A,this.logger),V=await A.entityService.listEntities("topic");return{...q,topics:V.map((C)=>{let l=this.adapter.parseTopicBody(C.content);return{id:C.id,title:l.title,content:l.content,keywords:l.keywords}})}})}}function Ua(A){return new Pd0(A)}B0();HA();B0();var gd0=X.enum(["linkedin"]),id0=X.enum(["draft","queued","published","failed"]),Td0=X.enum(["post","deck"]),i4=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:gd0.describe("Target platform"),status:id0,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:Td0.optional().describe("Source entity type (post, deck)")}),md0=i4.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}")}),jN=X2.extend({entityType:X.literal("social-post"),metadata:md0}),Ha=jN.extend({frontmatter:i4,body:X.string()}),Ka=Ha.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();HA();class dWA extends q2{constructor(){super({entityType:"social-post",schema:jN,frontmatterSchema:i4,supportsCoverImage:!0})}toMarkdown(A){let f="",Q={};try{Q=this.parseFrontMatter(A.content,i4),f=this.extractBody(A.content)}catch{f=A.content}let w={...Q,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,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,i4),Q=`${f.platform}-${w2(f.title)}`;return{content:A,entityType:"social-post",metadata:{title:f.title,slug:Q,platform:f.platform,status:f.status,publishedAt:f.publishedAt,platformPostId:f.platformPostId}}}parsePostFrontmatter(A){return this.parseFrontMatter(A.content,i4)}getPostContent(A){return this.extractBody(A.content)}createPostContent(A,f){return this.buildMarkdown(f,A)}}var hx=new dWA;B0();B0();HA();var Ly2=KU.extend({platform:X.enum(["linkedin"]).optional(),status:X.enum(["draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),qy2=FU.extend({query:Ly2.optional()});function Sd0(A){let f=H2(A.content,i4);return Ha.parse({...A,frontmatter:f.metadata,body:f.content})}class Fa extends c6{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=qy2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){return Sd0(A)}buildDetailResult(A,f){return{post:A}}buildListResult(A,f,Q){return{posts:A,totalCount:f?.totalItems??A.length,pagination:f,baseUrl:Q.baseUrl}}async fetch(A,f,Q){let{query:w}=this.parseQuery(A),B=Q.entityService;if(w.nextInQueue)return this.fetchNextInQueue(f,B);if(w.id){let{item:u}=await this.fetchDetail(w.id,B);return f.parse(this.buildDetailResult(u,null))}let x={};if(w.platform)x.platform=w.platform;if(w.status)x.status=w.status;let I=Object.keys(x).length>0,$=w.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:c,pagination:D}=await this.fetchList(w,B,{...I&&{filter:{metadata:x}},sortFields:$});return f.parse(this.buildListResult(c,D,w))}async fetchNextInQueue(A,f){let w=(await f.listEntities(this.config.entityType,{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}))[0],B=w?Sd0(w):null;return A.parse({post:B})}}HA();var yd0=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional()}),oWA=X.object({linkedin:yd0.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();HA();sWA();import{jsxDEV as aB,Fragment as Vy2}from"preact/jsx-dev-runtime";function Cy2(A,f){if(A.length<=f)return A;return A.slice(0,f).trim()+"..."}function _y2(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var Za=({posts:A,pageTitle:f,pagination:Q,baseUrl:w="/social-posts"})=>{let B=f??"Social Posts",x=Q?.totalItems??A.length,I=`Browse all ${x} social ${x===1?"post":"posts"}`;return aB(Vy2,{children:[aB(p2,{title:B,description:I},void 0,!1,void 0,this),aB("div",{className:"social-post-list bg-theme",children:aB("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[aB("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:B},void 0,!1,void 0,this),A.length===0?aB("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):aB("ul",{className:"space-y-6",children:A.map(($)=>aB("li",{children:aB(Gf,{href:$.url,variant:"horizontal",children:aB("div",{className:"flex flex-col sm:flex-row gap-4",children:[$.coverImageUrl&&aB("img",{src:$.coverImageUrl,alt:$.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),aB("div",{className:"flex-1 min-w-0",children:[aB("div",{className:"flex items-start justify-between gap-4 mb-2",children:[aB("h2",{className:"text-lg font-semibold text-heading",children:$.frontmatter.title},void 0,!1,void 0,this),aB("time",{className:"text-sm text-theme-muted shrink-0",children:_y2($.frontmatter.publishedAt??$.created)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),aB("div",{className:"flex items-center gap-2 mb-3",children:[aB(kx,{status:$.frontmatter.status},void 0,!1,void 0,this),aB("span",{className:"text-xs text-theme-muted uppercase",children:$.frontmatter.platform},void 0,!1,void 0,this),aB("span",{className:"text-xs text-theme-muted font-mono",children:$.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),aB("p",{className:"text-theme leading-relaxed",children:Cy2($.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)},$.id,!1,void 0,this))},void 0,!1,void 0,this),Q&&Q.totalPages>1&&aB(u$,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:w},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 sB,Fragment as My2}from"preact/jsx-dev-runtime";function ld0(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var Wa=({post:A})=>{let f=`Social Post - ${A.frontmatter.platform}`,Q=A.body.slice(0,160),w=[{label:"Home",href:"/"},{label:A.listLabel??"Social Posts",href:A.listUrl??"/social-posts"},{label:A.frontmatter.platform}];return sB(My2,{children:[sB(p2,{title:f,description:Q},void 0,!1,void 0,this),sB("section",{className:"social-post-detail",children:sB("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:sB("div",{className:"max-w-3xl mx-auto",children:[sB(V4,{items:w},void 0,!1,void 0,this),sB("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:A.frontmatter.title},void 0,!1,void 0,this),sB("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[sB(kx,{status:A.frontmatter.status},void 0,!1,void 0,this),sB("span",{className:"text-sm text-theme-muted uppercase",children:A.frontmatter.platform},void 0,!1,void 0,this),sB("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&&sB(NY,{src:A.coverImageUrl,alt:A.frontmatter.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),sB(Gf,{className:"p-8 mb-8",children:sB("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),sB("div",{className:"space-y-4 text-sm text-theme-muted",children:[sB("div",{children:[sB("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",ld0(A.created)]},void 0,!0,void 0,this),A.frontmatter.publishedAt&&sB("div",{children:[sB("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",ld0(A.frontmatter.publishedAt)]},void 0,!0,void 0,this),A.frontmatter.platformPostId&&sB("div",{children:sB("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 jO(A){return`social-media:${A}`}var tWA=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")}),Oy2=e5.extend({slug:X.string().optional()});class XW extends J9{constructor(A,f){super(A,f,{schema:tWA,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(A,f){let Q=A.platform??"linkedin",w=A.addToQueue??!1,{prompt:B,sourceEntityType:x,sourceEntityId:I}=A,{content:$,title:c}=A;if($&&c)await this.reportProgress(f,{progress:50,message:"Using provided content"});else if($&&!c){await this.reportProgress(f,{progress:10,message:"Shaping content with AI"});let k=await this.context.ai.generate({prompt:$,templateName:jO(Q)});c=k.title,$=k.content,await this.reportProgress(f,{progress:50,message:"Social post shaped from content"})}else if(I&&x){await this.reportProgress(f,{progress:10,message:`Fetching source ${x}`});let k=await this.context.entityService.getEntity(x,I);if(!k)this.failEarly(`Source entity not found: ${x}/${I}`);await this.reportProgress(f,{progress:30,message:"Generating social post from source content"});let V=X.object({slug:X.string()}).safeParse(k.metadata),C=V.success?V.data.slug:I,l=await this.context.ai.generate({prompt:`Create an engaging ${Q} post to promote this ${x}:
|
|
3012
|
+
- keywords`,requiredPermission:"public"});tf();HA();var Ey2=X.object({id:X.string(),title:X.string(),summary:X.string(),keywords:X.array(X.string()),created:X.string(),updated:X.string()}),MO=X.object({topics:X.array(Ey2),totalCount:X.number()});import{jsxDEV as L$}from"preact/jsx-dev-runtime";var nWA=({topics:A,totalCount:f})=>{return L$("div",{className:"topic-list-container w-full max-w-4xl mx-auto p-6 bg-theme",children:[L$(D$,{title:"Topics",count:f,singularLabel:"topic",description:"discovered from your knowledge base"},void 0,!1,void 0,this),L$("div",{className:"space-y-6",children:A.map((Q)=>L$(Gf,{variant:"vertical",children:[L$(V9,{href:`/topics/${Q.id}`,className:"text-xl",children:Q.title},void 0,!1,void 0,this),L$("p",{className:"text-theme-muted mb-4",children:Q.summary},void 0,!1,void 0,this),L$(M9,{tags:Q.keywords,maxVisible:5,variant:"muted",className:"mb-3"},void 0,!1,void 0,this),L$(q5,{children:L$("div",{className:"flex justify-between text-sm text-theme-muted",children:L$("time",{dateTime:Q.updated,children:["Updated ",dw(Q.updated)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},Q.id,!0,void 0,this))},void 0,!1,void 0,this),A.length===0&&L$(E7,{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)};HA();class Ya extends ff{constructor(){super(MO,{title:"Topic List",mappings:[{key:"topics",label:"Topics",type:"array",itemType:"object"},{key:"totalCount",label:"Total Count",type:"number"}]})}}var Md0=a0({name:"topics:topic-list",description:"List view of all discovered topics",schema:MO,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new Ya,layout:{component:nWA}});tf();HA();var OO=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 BK}from"preact/jsx-dev-runtime";var pWA=({title:A,content:f,keywords:Q,created:w,updated:B})=>{return BK("article",{className:"topic-detail-container max-w-4xl mx-auto p-6 bg-theme",children:[BK(PZ,{title:A,created:w,updated:B},void 0,!1,void 0,this),BK("div",{className:"prose prose-lg max-w-none mb-8 text-theme-muted",children:BK("div",{dangerouslySetInnerHTML:{__html:f}},void 0,!1,void 0,this)},void 0,!1,void 0,this),Q.length>0&&BK("section",{className:"mb-8",children:[BK("h2",{className:"text-xl font-semibold mb-3 text-theme",children:"Keywords"},void 0,!1,void 0,this),BK(M9,{tags:Q,maxVisible:Q.length,size:"sm"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),BK(jZ,{href:"/topics",children:"Back to Topics"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};HA();class ua extends ff{constructor(){super(OO,{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 Od0=a0({name:"topics:topic-detail",description:"Detailed view of a single topic",schema:OO,dataSourceId:"topics:entities",requiredPermission:"public",formatter:new ua,layout:{component:pWA}});B0();HA();class rWA extends c6{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 V7;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:IU(f.content,200),keywords:f.keywords,created:A.created,updated:A.updated}}buildListResult(A,f,Q){return{topics:A,totalCount:A.length}}async fetch(A,f,Q){let{query:w}=this.parseQuery(A);if(w.id){let x=await Q.entityService.getEntity(this.config.entityType,w.id);if(!x)throw Error(`Entity not found: ${w.id}`);let I=this.adapter.parseTopicBody(x.content);return f.parse({id:x.id,title:I.title,content:I.content,keywords:I.keywords,created:x.created,updated:x.updated})}return super.fetch(A,f,Q)}}_I();function jd0(){let A=new V7;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 Rd0={name:"@brains/topics",private:!0,version:"0.2.0-alpha.1",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 by2=new V7;class Pd0 extends zf{entityType="topic";schema=wa;adapter=by2;autoExtractionEnabled=!1;initialDerivationDone=!1;constructor(A={}){super("topics",Rd0,A,Wd0)}getEntityTypeConfig(){return{weight:0.5}}getTemplates(){return{extraction:_d0,"merge-synthesis":Vd0,"topic-list":Md0,"topic-detail":Od0}}getDataSources(){return[new rWA(this.logger.child("TopicsDataSource"))]}async onRegister(A){let f=new Da(A,this.logger);A.jobs.registerHandler("process-single",f);let Q=new lWA(A,this.logger);if(A.jobs.registerHandler("extract",Q),A.insights.register("topic-distribution",jd0()),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 w=async(B)=>{if(!this.autoExtractionEnabled)return{success:!0};let{entityType:x,entity:I}=B.payload;if(!this.shouldProcessEntityType(x))return{success:!0};if(!I)return{success:!0};return await this.handleEntityChanged(A,I),{success:!0}};A.messaging.subscribe("entity:created",w),A.messaging.subscribe("entity:updated",w)}}async derive(A,f,Q){if(!this.shouldProcessEntityType(A.entityType))return;if(!this.isEntityPublished(A))return;await this.handleEntityChanged(Q,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 Q=await ca(f,A,this.logger);this.logger.info("Batch topic extraction complete",Q)}async rebuildAll(A){let f=await this.getEntitiesToExtract(A),Q=await this.replaceAllTopics(f,A);this.logger.info("Topic rebuild complete",Q)}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 Q=A.metadata.status;return Q==="published"||Q===void 0||Q===null}async replaceAllTopics(A,f){let Q=new g4(f.entityService,this.logger),w=await Q.listTopics();for(let x of w)await Q.deleteTopic(x.id);if(A.length===0)return{deleted:w.length,created:0,skipped:0,batches:0};let B=await ca(A,f,this.logger);return{deleted:w.length,...B}}async getEntitiesToExtract(A){let f=this.getExtractableEntityTypes(A),Q=[];for(let w of f){let B=await A.entityService.listEntities(w);for(let x of B){if(!this.isEntityPublished(x))continue;Q.push(x)}}return Q}getExtractableEntityTypes(A){return A.entityService.getEntityTypes().filter((Q)=>this.shouldProcessEntityType(Q))}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(Q){this.logger.error("Failed to queue topic extraction job",{error:v0(Q),entityId:f.id,entityType:f.entityType})}}registerEvalHandler(A){let f=new VO(A,this.logger),Q=X.object({entityType:X.string(),content:X.string(),metadata:X.record(X.unknown()).optional()}),w=(J,v="")=>({id:`eval${v}-${Date.now()}`,entityType:J.entityType,content:J.content,contentHash:Bw(J.content),metadata:J.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}),B=async(J,v,k="")=>{let q=w(J,k);return f.extractFromEntity(q,v)},x=Q.extend({minRelevanceScore:X.number().optional()});A.eval.registerHandler("extractFromEntity",async(J)=>{let v=x.parse(J),k=v.minRelevanceScore??this.config.minRelevanceScore;return B(v,k)});let I=X.object({contentA:Q,contentB:Q,minRelevanceScore:X.number().optional()});A.eval.registerHandler("checkMergeSimilarity",async(J)=>{let v=I.parse(J),k=v.minRelevanceScore??this.config.minRelevanceScore,[q,V]=await Promise.all([B(v.contentA,k,"-a"),B(v.contentB,k,"-b")]),C=q.map((P)=>P.title.toLowerCase()),l=V.map((P)=>P.title.toLowerCase()),r=C.filter((P)=>l.includes(P));return{topicsA:q.map((P)=>({title:P.title,relevanceScore:P.relevanceScore})),topicsB:V.map((P)=>({title:P.title,relevanceScore:P.relevanceScore})),matchingTitles:r,wouldMerge:r.length>0}});let $=X.object({title:X.string(),content:X.string(),keywords:X.array(X.string())}),c=X.object({existingTopics:X.array($),incomingTopic:$,threshold:X.number().optional()});A.eval.registerHandler("detectMergeCandidate",async(J)=>{let v=c.parse(J),k=v.threshold??this.config.mergeSimilarityThreshold,q=new g4(A.entityService,this.logger);for(let C of v.existingTopics)await q.createTopic(C);let V=await q.findMergeCandidate({title:v.incomingTopic.title,keywords:v.incomingTopic.keywords},k);return{found:V!==null,candidateTitle:V?.title,candidateScore:V?.score}});let D=X.object({existingAliases:X.array(X.string()).optional(),canonicalTitle:X.string(),candidateAliases:X.array(X.string())});A.eval.registerHandler("mergeAliases",async(J)=>{let v=D.parse(J);return{aliases:new g4(A.entityService,this.logger).mergeAliases(v.existingAliases,v.canonicalTitle,v.candidateAliases)}});let u=X.object({existingTopics:X.array($.extend({aliases:X.array(X.string()).optional()})).default([]),incomingTopic:$.extend({relevanceScore:X.number().min(0).max(1).optional()}),threshold:X.number().optional()});A.eval.registerHandler("processTopicWithAutoMerge",async(J)=>{let v=u.parse(J),k=new g4(A.entityService,this.logger);for(let r of v.existingTopics)await k.createTopic({title:r.title,content:r.content,keywords:r.keywords,metadata:{aliases:r.aliases??[]}});let q=new Da(A,this.logger),V=Z9.from(async()=>{});if(!V)throw Error("Failed to create progress reporter");let C=await q.process({topic:{title:v.incomingTopic.title,content:v.incomingTopic.content,keywords:v.incomingTopic.keywords,relevanceScore:v.incomingTopic.relevanceScore??0.9},sourceEntityId:"eval-source",sourceEntityType:"post",autoMerge:!0,mergeSimilarityThreshold:v.threshold??this.config.mergeSimilarityThreshold},`eval-job-${Date.now()}`,V),l=await A.entityService.listEntities("topic");return{...C,topicCount:l.length,topics:l.map((r)=>{let P=this.adapter.parseTopicBody(r.content);return{id:r.id,title:P.title,content:P.content,keywords:P.keywords,metadata:r.metadata}})}});let K=X.object({entities:X.array(Q).min(1),minRelevanceScore:X.number().optional()}),F=X.object({existingTopics:X.array($).optional(),entities:X.array(Q)});A.eval.registerHandler("rebuildTopics",async(J)=>{let v=F.parse(J),k=new g4(A.entityService,this.logger);for(let l of v.existingTopics??[])await k.createTopic(l);let q=v.entities.map((l,r)=>w(l,`-rebuild-${r}`)),V=await this.replaceAllTopics(q,A),C=await A.entityService.listEntities("topic");return{...V,topicCount:C.length,topics:C.map((l)=>{let r=this.adapter.parseTopicBody(l.content);return{id:l.id,title:r.title,content:r.content,keywords:r.keywords,metadata:l.metadata}})}}),A.eval.registerHandler("extractSequentially",async(J)=>{let v=K.parse(J),k=v.minRelevanceScore??this.config.minRelevanceScore,q=new g4(A.entityService,this.logger),V=[];for(let[l,r]of v.entities.entries()){let P=w(r,`-sequential-${l}`),O=await f.extractFromEntity(P,k);for(let R of O)await q.createTopic({title:R.title,content:R.content,keywords:R.keywords});V.push({extractedTitles:O.map((R)=>R.title)})}let C=await A.entityService.listEntities("topic");return{totalTopics:C.length,perEntity:V,topics:C.map((l)=>{let r=this.adapter.parseTopicBody(l.content);return{id:l.id,title:r.title,content:r.content,keywords:r.keywords}})}});let Z=X.object({entities:X.array(Q)});A.eval.registerHandler("batchExtract",async(J)=>{let k=Z.parse(J).entities.map((C,l)=>w(C,`-batch-${l}`)),q=await ca(k,A,this.logger),V=await A.entityService.listEntities("topic");return{...q,topics:V.map((C)=>{let l=this.adapter.parseTopicBody(C.content);return{id:C.id,title:l.title,content:l.content,keywords:l.keywords}})}})}}function Ua(A){return new Pd0(A)}B0();HA();B0();var gd0=X.enum(["linkedin"]),id0=X.enum(["draft","queued","published","failed"]),Td0=X.enum(["post","deck"]),i4=X.object({title:X.string().describe("Short descriptive title (3-6 words) for file naming"),platform:gd0.describe("Target platform"),status:id0,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:Td0.optional().describe("Source entity type (post, deck)")}),md0=i4.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:X.string().describe("URL-friendly identifier: {platform}-{title}")}),jN=X2.extend({entityType:X.literal("social-post"),metadata:md0}),Ha=jN.extend({frontmatter:i4,body:X.string()}),Ka=Ha.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();HA();class dWA extends q2{constructor(){super({entityType:"social-post",schema:jN,frontmatterSchema:i4,supportsCoverImage:!0})}toMarkdown(A){let f="",Q={};try{Q=this.parseFrontMatter(A.content,i4),f=this.extractBody(A.content)}catch{f=A.content}let w={...Q,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,w)}fromMarkdown(A){let f=this.parseFrontMatter(A,i4),Q=`${f.platform}-${w2(f.title)}`;return{content:A,entityType:"social-post",metadata:{title:f.title,slug:Q,platform:f.platform,status:f.status,publishedAt:f.publishedAt,platformPostId:f.platformPostId}}}parsePostFrontmatter(A){return this.parseFrontMatter(A.content,i4)}getPostContent(A){return this.extractBody(A.content)}createPostContent(A,f){return this.buildMarkdown(f,A)}}var hx=new dWA;B0();B0();HA();var Ly2=KU.extend({platform:X.enum(["linkedin"]).optional(),status:X.enum(["draft","queued","published","failed"]).optional(),sortByQueue:X.boolean().optional(),nextInQueue:X.boolean().optional()}),qy2=FU.extend({query:Ly2.optional()});function Sd0(A){let f=H2(A.content,i4);return Ha.parse({...A,frontmatter:f.metadata,body:f.content})}class Fa extends c6{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=qy2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){return Sd0(A)}buildDetailResult(A,f){return{post:A}}buildListResult(A,f,Q){return{posts:A,totalCount:f?.totalItems??A.length,pagination:f,baseUrl:Q.baseUrl}}async fetch(A,f,Q){let{query:w}=this.parseQuery(A),B=Q.entityService;if(w.nextInQueue)return this.fetchNextInQueue(f,B);if(w.id){let{item:u}=await this.fetchDetail(w.id,B);return f.parse(this.buildDetailResult(u,null))}let x={};if(w.platform)x.platform=w.platform;if(w.status)x.status=w.status;let I=Object.keys(x).length>0,$=w.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:c,pagination:D}=await this.fetchList(w,B,{...I&&{filter:{metadata:x}},sortFields:$});return f.parse(this.buildListResult(c,D,w))}async fetchNextInQueue(A,f){let w=(await f.listEntities(this.config.entityType,{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}))[0],B=w?Sd0(w):null;return A.parse({post:B})}}HA();var yd0=X.object({accessToken:X.string().optional(),refreshToken:X.string().optional(),organizationId:X.string().optional()}),oWA=X.object({linkedin:yd0.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();HA();sWA();import{jsxDEV as aB,Fragment as Vy2}from"preact/jsx-dev-runtime";function Cy2(A,f){if(A.length<=f)return A;return A.slice(0,f).trim()+"..."}function _y2(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var Za=({posts:A,pageTitle:f,pagination:Q,baseUrl:w="/social-posts"})=>{let B=f??"Social Posts",x=Q?.totalItems??A.length,I=`Browse all ${x} social ${x===1?"post":"posts"}`;return aB(Vy2,{children:[aB(p2,{title:B,description:I},void 0,!1,void 0,this),aB("div",{className:"social-post-list bg-theme",children:aB("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[aB("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:B},void 0,!1,void 0,this),A.length===0?aB("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):aB("ul",{className:"space-y-6",children:A.map(($)=>aB("li",{children:aB(Gf,{href:$.url,variant:"horizontal",children:aB("div",{className:"flex flex-col sm:flex-row gap-4",children:[$.coverImageUrl&&aB("img",{src:$.coverImageUrl,alt:$.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),aB("div",{className:"flex-1 min-w-0",children:[aB("div",{className:"flex items-start justify-between gap-4 mb-2",children:[aB("h2",{className:"text-lg font-semibold text-heading",children:$.frontmatter.title},void 0,!1,void 0,this),aB("time",{className:"text-sm text-theme-muted shrink-0",children:_y2($.frontmatter.publishedAt??$.created)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),aB("div",{className:"flex items-center gap-2 mb-3",children:[aB(kx,{status:$.frontmatter.status},void 0,!1,void 0,this),aB("span",{className:"text-xs text-theme-muted uppercase",children:$.frontmatter.platform},void 0,!1,void 0,this),aB("span",{className:"text-xs text-theme-muted font-mono",children:$.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),aB("p",{className:"text-theme leading-relaxed",children:Cy2($.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)},$.id,!1,void 0,this))},void 0,!1,void 0,this),Q&&Q.totalPages>1&&aB(u$,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:w},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 sB,Fragment as My2}from"preact/jsx-dev-runtime";function ld0(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var Wa=({post:A})=>{let f=`Social Post - ${A.frontmatter.platform}`,Q=A.body.slice(0,160),w=[{label:"Home",href:"/"},{label:A.listLabel??"Social Posts",href:A.listUrl??"/social-posts"},{label:A.frontmatter.platform}];return sB(My2,{children:[sB(p2,{title:f,description:Q},void 0,!1,void 0,this),sB("section",{className:"social-post-detail",children:sB("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:sB("div",{className:"max-w-3xl mx-auto",children:[sB(V4,{items:w},void 0,!1,void 0,this),sB("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:A.frontmatter.title},void 0,!1,void 0,this),sB("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[sB(kx,{status:A.frontmatter.status},void 0,!1,void 0,this),sB("span",{className:"text-sm text-theme-muted uppercase",children:A.frontmatter.platform},void 0,!1,void 0,this),sB("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&&sB(NY,{src:A.coverImageUrl,alt:A.frontmatter.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),sB(Gf,{className:"p-8 mb-8",children:sB("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),sB("div",{className:"space-y-4 text-sm text-theme-muted",children:[sB("div",{children:[sB("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",ld0(A.created)]},void 0,!0,void 0,this),A.frontmatter.publishedAt&&sB("div",{children:[sB("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",ld0(A.frontmatter.publishedAt)]},void 0,!0,void 0,this),A.frontmatter.platformPostId&&sB("div",{children:sB("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 jO(A){return`social-media:${A}`}var tWA=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")}),Oy2=e5.extend({slug:X.string().optional()});class XW extends J9{constructor(A,f){super(A,f,{schema:tWA,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(A,f){let Q=A.platform??"linkedin",w=A.addToQueue??!1,{prompt:B,sourceEntityType:x,sourceEntityId:I}=A,{content:$,title:c}=A;if($&&c)await this.reportProgress(f,{progress:50,message:"Using provided content"});else if($&&!c){await this.reportProgress(f,{progress:10,message:"Shaping content with AI"});let k=await this.context.ai.generate({prompt:$,templateName:jO(Q)});c=k.title,$=k.content,await this.reportProgress(f,{progress:50,message:"Social post shaped from content"})}else if(I&&x){await this.reportProgress(f,{progress:10,message:`Fetching source ${x}`});let k=await this.context.entityService.getEntity(x,I);if(!k)this.failEarly(`Source entity not found: ${x}/${I}`);await this.reportProgress(f,{progress:30,message:"Generating social post from source content"});let V=X.object({slug:X.string()}).safeParse(k.metadata),C=V.success?V.data.slug:I,l=await this.context.ai.generate({prompt:`Create an engaging ${Q} post to promote this ${x}:
|
|
3013
3013
|
|
|
3014
3014
|
Source: ${x}/${C}
|
|
3015
3015
|
|
|
3016
3016
|
${k.content}`,templateName:jO(Q)});c=l.title,$=l.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 k=await this.context.ai.generate({prompt:B,templateName:jO(Q)});c=k.title,$=k.content,await this.reportProgress(f,{progress:50,message:"Social post generated"})}else this.failEarly("No content source provided (prompt, sourceEntityId, or content)");if(!$||!c)this.failEarly("Content or title was not generated");let u={title:c,platform:Q,status:w?"queued":"draft",...I&&{sourceEntityId:I},...x&&{sourceEntityType:x}},K=hx.createPostContent(u,$),Z=hx.fromMarkdown(K).metadata;if(!Z)this.failEarly("Failed to parse social post metadata");let J=await j3({entityType:"social-post",title:c,deriveId:(k)=>`${Q}-${w2(k)}`,regeneratePrompt:"Generate a different social media post title on the same topic.",context:this.context}),v=K;if(J!==c){Z.title=J,Z.slug=`${Q}-${w2(J)}`;let k={...u,title:J};v=hx.createPostContent(k,$)}return{id:Z.slug,content:v,metadata:Z,title:J,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,Q,w){if(A.generateImage){await this.reportProgress(Q,{progress:90,message:"Queueing image generation"});let B=w.title??"Social Post";await this.context.jobs.enqueue("image:image-generate",{prompt:`Social media graphic for: ${B}`,title:`${B} Image`,aspectRatio:"16:9",targetEntityType:"social-post",targetEntityId:f},{interfaceType:"job",userId:"system"})}await this.context.messaging.send("generate:report:success",{entityType:"social-post",entityId:f})}summarizeDataForLog(A){return{platform:A.platform??"linkedin",hasPrompt:!!A.prompt,sourceEntityType:A.sourceEntityType,addToQueue:A.addToQueue??!1,generateImage:A.generateImage??!1}}}class eWA{config;logger;name="linkedin";apiBaseUrl="https://api.linkedin.com/v2";cachedUserId=null;constructor(A,f){this.config=A;this.logger=f}async publish(A,f,Q){if(!this.config.accessToken)throw Error("LinkedIn access token not configured");let w=await this.getAuthor(),B=null;if(Q)B=await this.uploadImage(w,Q);let x={shareCommentary:{text:A},shareMediaCategory:B?"IMAGE":"NONE",...B&&{media:[{status:"READY",media:B}]}},I=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:w,lifecycleState:"PUBLISHED",specificContent:{"com.linkedin.ugc.ShareContent":x},visibility:{"com.linkedin.ugc.MemberNetworkVisibility":"PUBLIC"}})});if(!I.ok){let D=await I.text();throw this.logger.error("LinkedIn API error",{status:I.status,error:D}),Error(`LinkedIn API error: ${I.status} - ${D}`)}let $=I.headers.get("X-RestLi-Id")??"";this.logger.info("LinkedIn post created",{postId:$,hasImage:!!B});let c={id:$};if($)c.url=`https://www.linkedin.com/feed/update/${$}`;return c}async uploadImage(A,f){try{let Q=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(!Q.ok){let $=await Q.text();return this.logger.warn("LinkedIn image upload registration failed",{status:Q.status,error:$}),null}let w=await Q.json(),B=w.value.uploadMechanism["com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest"].uploadUrl,x=w.value.asset,I=await fetch(B,{method:"PUT",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":f.mimeType},body:new Uint8Array(f.data)});if(!I.ok)return this.logger.warn("LinkedIn image binary upload failed",{status:I.status}),null;return this.logger.info("LinkedIn image uploaded",{assetUrn:x}),x}catch(Q){return this.logger.warn("LinkedIn image upload error",{error:Q}),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 Q=await fetch("https://api.linkedin.com/v2/userinfo",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(Q.ok){let w=await Q.json();return this.cachedUserId=`urn:li:person:${w.sub}`,this.cachedUserId}}catch{}let A=await fetch("https://api.linkedin.com/v2/me",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(!A.ok){let Q=await A.text();throw Error(`Failed to get LinkedIn user ID: ${A.status} - ${Q}`)}let f=await A.json();return this.cachedUserId=`urn:li:person:${f.id}`,this.cachedUserId}}function AGA(A,f){return new eWA(A,f)}B0();HA();tf();sWA();var jy2=X.object({posts:X.array(Ka),totalCount:X.number().optional(),pagination:Qx.nullable(),baseUrl:X.string().optional()}),Ry2=X.object({post:Ka});function nd0(){return{linkedin:Xa,"social-post-list":a0({name:"social-post-list",description:"Social post list page template",schema:jy2,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:Za}}),"social-post-detail":a0({name:"social-post-detail",description:"Individual social post template",schema:Ry2,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:Wa}})}}HA();var Py2=X.object({prompt:X.string().optional(),content:X.string().optional(),platform:X.enum(["linkedin"]).default("linkedin")}),gy2=X.object({prompt:X.string().optional(),content:X.string().optional(),title:X.string().optional(),platform:X.enum(["linkedin"]).optional()});function pd0(A){A.eval.registerHandler("generation",async(f)=>{let Q=Py2.parse(f),w=Q.content?`Create an engaging LinkedIn post to share this content:
|
|
3017
3017
|
|
|
3018
|
-
${Q.content}`:Q.prompt??"Write an engaging LinkedIn post";return A.ai.generate({prompt:w,templateName:`social-media:${Q.platform}`})}),A.eval.registerHandler("create",async(f)=>{let Q=gy2.parse(f),w=[],B=Z9.from(async(D)=>{let u={progress:D.progress};if(D.message!==void 0)u.message=D.message;w.push(u)});if(!B)throw Error("Failed to create progress reporter");let I=await new XW(A.logger,A).process(Q,`eval-${Date.now()}`,B),$=!1,c;if(I.success&&I.entityId){let D=await A.entityService.getEntity("social-post",I.entityId);$=!!D,c=D?.content.slice(0,300)}return{...I,entityExists:$,entityPreview:c,progressSteps:w}})}HA();B0();class RO{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:Q}=A;if(f!=="social-post")return;this.logger.debug("Handling publish:execute",{entityId:Q});try{let w=await this.entityService.getEntity("social-post",Q);if(!w){await this.reportFailure(f,Q,`Post not found: ${Q}`);return}if(w.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:Q});return}let B=w.metadata.platform,x=this.providers.get(B);if(!x){await this.reportFailure(f,Q,`No provider configured for platform: ${B}`);return}let I=H2(w.content,i4),$;if(I.metadata.coverImageId)$=await this.fetchImageData(I.metadata.coverImageId);try{let c=await x.publish(I.content,w.metadata,$),D=new Date().toISOString(),u=c.id||void 0,K={...I.metadata,status:"published",publishedAt:D,...u&&{platformPostId:u}},F=hx.createPostContent(K,I.content);await this.entityService.updateEntity({...w,content:F,metadata:{...w.metadata,status:"published",publishedAt:D,platformPostId:u}}),await this.reportSuccess(f,Q,c.id),this.logger.info(`Post published successfully: ${Q}`,{platform:B,platformPostId:u})}catch(c){let D=c instanceof Error?c.message:String(c),u={...I.metadata,status:"failed"},K=hx.createPostContent(u,I.content);await this.entityService.updateEntity({...w,content:K,metadata:{...w.metadata,status:"failed"}}),await this.reportFailure(f,Q,D),this.logger.error(`Post publish failed: ${Q}`,{platform:B,error:D})}}catch(w){let B=v0(w);this.logger.error("Unexpected error in publish handler",{entityId:Q,error:B}),await this.reportFailure(f,Q,B)}}async reportSuccess(A,f,Q){await this.sendMessage("publish:report:success",{entityType:A,entityId:f,result:{id:Q}})}async reportFailure(A,f,Q){await this.sendMessage("publish:report:failure",{entityType:A,entityId:f,error:Q})}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 w=f.content.match(/^data:([^;]+);base64,(.+)$/);if(!w?.[1]||!w[2]){this.logger.warn("Invalid image data URL format",{imageId:A});return}let B=w[1],x=w[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 rd0(A,f,Q){if(f.size===0){Q.debug("No providers configured, skipping publish-pipeline registration");return}A.messaging.subscribe("system:plugins:ready",async()=>{let w=f.values().next().value;return await A.messaging.send("publish:register",{entityType:"social-post",provider:w}),Q.info("Registered social-post with publish-pipeline"),{success:!0}})}function dd0(A,f,Q){let w=new RO({sendMessage:A.messaging.send,logger:Q.child("PublishExecuteHandler"),entityService:A.entityService,providers:f});A.messaging.subscribe("publish:execute",async(B)=>{return await w.handle(B.payload),{success:!0}}),Q.debug("Subscribed to publish:execute messages")}HA();function od0(A,f){A.messaging.subscribe("entity:updated",async(Q)=>{let{entityType:w,entityId:B,entity:x}=Q.payload;if(w!=="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:w,sourceEntityId:B,platform:"linkedin"}),f.info(`Auto-generate social post triggered for queued post ${B}`),{success:!0}}catch($){let c=v0($);return f.error(`Failed to trigger auto-generate for ${B}:`,{error:c}),{success:!0}}}),f.debug("Subscribed to entity:updated for auto-generation")}function ad0(A,f){A.messaging.subscribe("social:auto-generate",async(Q)=>{let{sourceEntityType:w,sourceEntityId:B,platform:x}=Q.payload;try{let I=await A.jobs.enqueue(`${hx.entityType}:generation`,{sourceEntityType:w,sourceEntityId:B,platform:x,addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info(`Social post generation job enqueued for ${w}/${B}`,{jobId:I}),{success:!0,jobId:I}}catch(I){let $=v0(I);return f.error(`Failed to enqueue social post generation for ${B}:`,{error:$}),{success:!1}}}),f.debug("Subscribed to social:auto-generate messages")}function sd0(A,f){A.messaging.subscribe("generate:execute",async(Q)=>{let{entityType:w}=Q.payload;if(w!=="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 $ of B)if((await A.entityService.listEntities("social-post",{filter:{metadata:{sourceEntityType:"post",sourceEntityId:$.id}},limit:1})).length===0){x=$;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 I=await A.jobs.enqueue(`${hx.entityType}:generation`,{sourceEntityType:"post",sourceEntityId:x.id,platform:"linkedin",addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info("Social post generation job queued",{jobId:I,sourcePostId:x.id}),{success:!0}}catch(B){let x=v0(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 td0={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.0",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 fGA extends zf{entityType=hx.entityType;schema=jN;adapter=hx;providers=new Map;constructor(A){super("social-media",td0,A,oWA)}createGenerationHandler(A){return new XW(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return nd0()}getDataSources(){return[new Fa(this.logger.child("SocialPostDataSource"))]}async onRegister(A){if(this.initializeProviders(),rd0(A,this.providers,this.logger),dd0(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)od0(A,this.logger),ad0(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");sd0(A,this.logger),pd0(A),this.logger.info("Social media plugin registered successfully")}async derive(A,f,Q){if(A.metadata.status!=="published")return;await Q.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=AGA(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function PO(A){return new fGA(A)}HA();var Ty2=X.enum(["draft","queued","published","failed"]),HEQ=X.object({status:Ty2.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class QGA{name="internal";async publish(A,f){return{id:"internal"}}}var tB={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"},ND={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"};HA();var my2=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),ed0=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),my2).optional(),maxRetries:X.number().optional().default(3),retryBaseDelayMs:X.number().optional().default(5000)});class ED{static instance=null;queues=new Map;static getInstance(){return ED.instance??=new ED,ED.instance}static resetInstance(){ED.instance=null}static createFresh(){return new ED}constructor(){}async add(A,f){let Q=this.getOrCreateQueue(A),w=Q.find((I)=>I.entityId===f);if(w)return{position:w.position};let B=Q.length+1,x={entityId:f,entityType:A,position:B,queuedAt:new Date().toISOString()};return Q.push(x),{position:B}}async remove(A,f){let Q=this.queues.get(A);if(!Q)return;let w=Q.findIndex((B)=>B.entityId===f);if(w===-1)return;Q.splice(w,1),this.recalculatePositions(Q)}async reorder(A,f,Q){let w=this.queues.get(A);if(!w)return;let B=w.findIndex(($)=>$.entityId===f);if(B===-1)return;let[x]=w.splice(B,1);if(!x)return;let I=Math.max(0,Math.min(Q-1,w.length));w.splice(I,0,x),this.recalculatePositions(w)}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 Q=f[0];if(!Q)continue;if(!A||Q.queuedAt<A.queuedAt)A=Q}return A}async popNext(A){let f=this.queues.get(A);if(!f||f.length===0)return null;let Q=f.shift()??null;if(Q)this.recalculatePositions(f);return Q}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let A=[];for(let[f,Q]of this.queues.entries())if(Q.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,Q)=>{f.position=Q+1})}}class hD{static instance=null;providers=new Map;defaultProvider=new QGA;static getInstance(){return hD.instance??=new hD,hD.instance}static resetInstance(){hD.instance=null}static createFresh(){return new hD}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())}}HA();HA();async function Ao0(A,f){let Q={entityType:A.entityType,entityId:A.entityId};if(f.messageBus)await f.messageBus.send(tB.EXECUTE,Q,"publish-service");f.onExecute?.(Q)}async function fo0(A,f){let Q=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 w=await f.entityService.getEntity(A.entityType,A.entityId);if(!w){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 Q.publish(w.content,w.metadata);f.retryTracker.clearRetries(A.entityId),f.onPublish?.({entityType:A.entityType,entityId:A.entityId,result:B})}catch(B){let x=v0(B);f.retryTracker.recordFailure(A.entityId,x);let I=f.retryTracker.getRetryInfo(A.entityId);f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:x,retryCount:I?.retryCount??1,willRetry:I?.willRetry??!1})}}function Qo0(A,f,Q,w){if(w.retryTracker.clearRetries(f),w.messageBus)w.messageBus.send(tB.COMPLETED,{entityType:A,entityId:f,result:Q},"publish-service");w.onPublish?.({entityType:A,entityId:f,result:Q})}function wo0(A,f,Q,w){w.retryTracker.recordFailure(f,Q);let B=w.retryTracker.getRetryInfo(f),x={entityType:A,entityId:f,error:Q,retryCount:B?.retryCount??1,willRetry:B?.willRetry??!1};if(w.messageBus)w.messageBus.send(tB.FAILED,x,"publish-service");w.onFailed?.(x)}async function Bo0(A,f){let Q=f.generationConditions[A];if(Q&&f.onCheckGenerationConditions){let B=await f.onCheckGenerationConditions(A,Q);if(!B.shouldGenerate){if(f.messageBus)f.messageBus.send(ND.SKIPPED,{entityType:A,reason:B.reason??"Conditions not met"},"content-pipeline");return}}let w={entityType:A};if(f.messageBus)await f.messageBus.send(ND.EXECUTE,w,"content-pipeline");f.onGenerate?.(w)}function xo0(A,f,Q){if(Q)Q.send(ND.COMPLETED,{entityType:A,entityId:f},"content-pipeline")}function Io0(A,f,Q){if(Q)Q.send(ND.FAILED,{entityType:A,error:f},"content-pipeline")}var Sy2=1000;class q${static instance=null;config;publishJobs=new Map;generationJobs=new Map;immediateIntervalJob=null;running=!1;static getInstance(A){return q$.instance??=new q$(A),q$.instance}static resetInstance(){if(q$.instance)q$.instance.stop();q$.instance=null}static createFresh(A){return new q$(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 Q=this.config.backend.scheduleCron(f,()=>this.processEntityType(A));this.publishJobs.set(A,Q)}for(let[A,f]of Object.entries(this.generationSchedules)){let Q=this.config.backend.scheduleCron(f,()=>this.handleTriggerGeneration(A));this.generationJobs.set(A,Q)}this.immediateIntervalJob=this.config.backend.scheduleInterval(Sy2,()=>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 Q=await this.config.queueManager.getNext(f);if(Q){await this.processEntry(Q);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 Ao0(A,this.publishDeps);else await fo0(A,this.publishDeps)}completePublish(A,f,Q){Qo0(A,f,Q,this.publishDeps)}failPublish(A,f,Q){wo0(A,f,Q,this.publishDeps)}async publishDirect(A,f,Q,w){return this.config.providerRegistry.get(A).publish(Q,w)}async handleTriggerGeneration(A){if(!this.running)return;try{await Bo0(A,this.generationDeps)}catch(f){this.config.logger.error(`Generation trigger error for ${A}:`,f)}}completeGeneration(A,f){xo0(A,f,this.config.messageBus)}failGeneration(A,f){Io0(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,Q){try{this.config.backend.validateCron(f)}catch(w){throw Error(`Invalid ${Q} cron expression for ${A}: "${f}" - ${v0(w)}`)}}}var $o0={maxRetries:3,baseDelayMs:5000};class bD{static instance=null;retries=new Map;config;static getInstance(A){return bD.instance??=new bD(A??$o0),bD.instance}static resetInstance(){bD.instance=null}static createFresh(A){return new bD(A??$o0)}constructor(A){this.config=A}recordFailure(A,f){let w=(this.retries.get(A)?.retryCount??0)+1,B=this.config.baseDelayMs*Math.pow(2,w-1),x=Date.now()+B;this.retries.set(A,{entityId:A,retryCount:w,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 i9(A,f,Q,w,B,x,I,$){return i9.fromTZ(i9.tp(A,f,Q,w,B,x,I),$)}i9.fromTZISO=(A,f,Q)=>i9.fromTZ(yy2(A,f),Q);i9.fromTZ=function(A,f){let Q=new Date(Date.UTC(A.y,A.m-1,A.d,A.h,A.i,A.s)),w=wGA(A.tz,Q),B=new Date(Q.getTime()-w),x=wGA(A.tz,B);if(x-w===0)return B;{let I=new Date(Q.getTime()-x),$=wGA(A.tz,I);if($-x===0)return I;if(!f&&$-x>0)return I;if(f)throw Error("Invalid date passed to fromTZ()");return B}};i9.toTZ=function(A,f){let Q=A.toLocaleString("en-US",{timeZone:f}).replace(/[\u202f]/," "),w=new Date(Q);return{y:w.getFullYear(),m:w.getMonth()+1,d:w.getDate(),h:w.getHours(),i:w.getMinutes(),s:w.getSeconds(),tz:f}};i9.tp=(A,f,Q,w,B,x,I)=>({y:A,m:f,d:Q,h:w,i:B,s:x,tz:I});function wGA(A,f=new Date){let Q=f.toLocaleString("en-US",{timeZone:A,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],w=f.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${w} GMT`)-Date.parse(`${w} ${Q}`)}function yy2(A,f){let Q=new Date(Date.parse(A));if(isNaN(Q))throw Error("minitz: Invalid ISO8601 passed to parser.");let w=A.substring(9);return A.includes("Z")||w.includes("-")||w.includes("+")?i9.tp(Q.getUTCFullYear(),Q.getUTCMonth()+1,Q.getUTCDate(),Q.getUTCHours(),Q.getUTCMinutes(),Q.getUTCSeconds(),"Etc/UTC"):i9.tp(Q.getFullYear(),Q.getMonth()+1,Q.getDate(),Q.getHours(),Q.getMinutes(),Q.getSeconds(),f)}i9.minitz=i9;var BGA=32,iO=31|BGA,uo0=[1,2,4,8,16],co0=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 T4(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,iO),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(A,f,Q,w){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(w);let I=f.split(",");if(I.length>1)for(let $=0;$<I.length;$++)this.partToArray(A,I[$],Q,w);else f.indexOf("-")!==-1&&f.indexOf("/")!==-1?this.handleRangeWithStepping(f,A,Q,w):f.indexOf("-")!==-1?this.handleRange(f,A,Q,w):f.indexOf("/")!==-1?this.handleStepping(f,A,Q,w):f!==""&&this.handleNumber(f,A,Q,w)}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,Q,w){let B=this.extractNth(A,f),x=parseInt(B[0],10)+Q;if(isNaN(x))throw TypeError("CronPattern: "+f+" is not a number: '"+A+"'");this.setPart(f,x,B[1]||w)}setPart(A,f,Q){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,Q);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]=Q}handleRangeWithStepping(A,f,Q,w){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[,I,$,c]=x,D=parseInt(I,10)+Q,u=parseInt($,10)+Q,K=parseInt(c,10);if(isNaN(D))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(u))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(K))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(K===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(K>this[f].length)throw TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[f].length+")");if(D>u)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let F=D;F<=u;F+=K)this.setPart(f,F,B[1]||w)}extractNth(A,f){let Q=A,w;if(Q.includes("#")){if(f!=="dayOfWeek")throw Error("CronPattern: nth (#) only allowed in day-of-week field");w=Q.split("#")[1],Q=Q.split("#")[0]}return[Q,w]}handleRange(A,f,Q,w){let B=this.extractNth(A,f),x=B[0].split("-");if(x.length!==2)throw TypeError("CronPattern: Syntax error, illegal range: '"+A+"'");let I=parseInt(x[0],10)+Q,$=parseInt(x[1],10)+Q;if(isNaN(I))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN($))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(I>$)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let c=I;c<=$;c++)this.setPart(f,c,B[1]||w)}handleStepping(A,f,Q,w){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 I=0;x[0]!=="*"&&(I=parseInt(x[0],10)+Q);let $=parseInt(x[1],10);if(isNaN($))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if($===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if($>this[f].length)throw TypeError("CronPattern: Syntax error, max steps for part is ("+this[f].length+")");for(let c=I;c<this[f].length;c+=$)this.setPart(f,c,B[1]||w)}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]|BGA;else if(f===iO)this.dayOfWeek[A]=iO;else if(f<6&&f>0)this.dayOfWeek[A]=this.dayOfWeek[A]|uo0[f-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${f}, Type: ${typeof f}`)}},Do0=[31,28,31,30,31,30,31,31,30,31,30,31],rY=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],T4=class A{tz;ms;second;minute;hour;day;month;year;constructor(f,Q){if(this.tz=Q,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,Q,w,B){let x=new Date(Date.UTC(f,Q,w)).getUTCDay(),I=0;for(let $=1;$<=w;$++)new Date(Date.UTC(f,Q,$)).getUTCDay()===x&&I++;if(B&iO&&uo0[I-1]&B)return!0;if(B&BGA){let $=new Date(Date.UTC(f,Q+1,0)).getUTCDate();for(let c=w+1;c<=$;c++)if(new Date(Date.UTC(f,Q,c)).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 Q=i9.toTZ(f,this.tz);this.ms=f.getMilliseconds(),this.second=Q.s,this.minute=Q.i,this.hour=Q.h,this.day=Q.d,this.month=Q.m-1,this.year=Q.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>Do0[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 Q=i9.fromTZISO(f);this.ms=Q.getUTCMilliseconds(),this.second=Q.getUTCSeconds(),this.minute=Q.getUTCMinutes(),this.hour=Q.getUTCHours(),this.day=Q.getUTCDate(),this.month=Q.getUTCMonth(),this.year=Q.getUTCFullYear(),this.apply()}else return this.fromDate(i9.fromTZISO(f,this.tz))}findNext(f,Q,w,B){let x=this[Q],I;w.lastDayOfMonth&&(this.month!==1?I=Do0[this.month]:I=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let $=!w.starDOW&&Q=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let c=this[Q]+B;c<w[Q].length;c++){let D=w[Q][c];if(Q==="day"&&w.lastDayOfMonth&&c-B==I&&(D=1),Q==="day"&&!w.starDOW){let u=w.dayOfWeek[($+(c-B-1))%7];if(u&&u&iO)u=this.isNthWeekdayOfMonth(this.year,this.month,c-B,u)?1:0;else if(u)throw Error(`CronDate: Invalid value for dayOfWeek encountered. ${u}`);f.legacyMode&&!w.starDOM?D=D||u:D=D&&u}if(D)return this[Q]=c-B,x!==this[Q]?2:1}return 3}recurse(f,Q,w){let B=this.findNext(Q,rY[w][0],f,rY[w][2]);if(B>1){let x=w+1;for(;x<rY.length;)this[rY[x][0]]=-rY[x][2],x++;if(B===3)return this[rY[w][1]]++,this[rY[w][0]]=-rY[w][2],this.apply(),this.recurse(f,Q,0);if(this.apply())return this.recurse(f,Q,w-1)}return w+=1,w>=rY.length?this:this.year>=3000?null:this.recurse(f,Q,w)}increment(f,Q,w){return this.second+=Q.interval!==void 0&&Q.interval>1&&w?Q.interval:1,this.ms=0,this.apply(),this.recurse(f,Q,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)):i9.fromTZ(i9.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function ly2(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 T4(A.startAt,A.timezone)),A.stopAt&&(A.stopAt=new T4(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 gO(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function ny2(A){return gO(A)}function py2(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var Yo0=30000,Ga=[],xGA=class{name;options;_states;fn;constructor(A,f,Q){let w,B;if(gO(f))B=f;else if(typeof f=="object")w=f;else if(f!==void 0)throw Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(gO(Q))B=Q;else if(typeof Q=="object")w=Q;else if(Q!==void 0)throw Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=w?.name,this.options=ly2(w),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:w?w.maxRuns:void 0,paused:w?w.paused:!1,pattern:new co0("* * * * *")},A&&(A instanceof Date||typeof A=="string"&&A.indexOf(":")>0)?this._states.once=new T4(A,this.options.timezone||this.options.utcOffset):this._states.pattern=new co0(A,this.options.timezone),this.name){if(Ga.find((x)=>x.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");Ga.push(this)}return B!==void 0&&ny2(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 Q=[],w=f||this._states.currentRun||void 0;for(;A--&&(w=this.nextRun(w));)Q.push(w);return Q}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let A=this.nextRun(this._states.currentRun),f=!this._states.paused,Q=this.fn!==void 0,w=!this._states.kill;return f&&Q&&w&&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 T4||A instanceof Date?f.getTime()-A.getTime():f.getTime()-new T4(A).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let A=Ga.indexOf(this);A>=0&&Ga.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(),Q=this.nextRun(this._states.currentRun);return f==null||isNaN(f)||Q===null?this:(f>Yo0&&(f=Yo0),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(Q),f),this._states.currentTimeout&&this.options.unref&&py2(this._states.currentTimeout),this)}async _trigger(A){if(this._states.blocking=!0,this._states.currentRun=new T4(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){gO(this.options.catch)&&this.options.catch(f,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new T4(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,Q=!this._states.paused&&f.getTime()>=A.getTime(),w=this._states.blocking&&this.options.protect;Q&&!w?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):Q&&w&&gO(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(A){let f=!!(A||this._states.currentRun),Q=!1;!A&&this.options.startAt&&this.options.interval&&([A,f]=this._calculatePreviousRun(A,f),Q=!A),A=new T4(A,this.options.timezone||this.options.utcOffset),this.options.startAt&&A&&A.getTime()<this.options.startAt.getTime()&&(A=this.options.startAt);let w=this._states.once||new T4(A,this.options.timezone||this.options.utcOffset);return!Q&&w!==this._states.once&&(w=w.increment(this._states.pattern,this.options,f)),this._states.once&&this._states.once.getTime()<=A.getTime()||w===null||this._states.maxRuns!==void 0&&this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&w.getTime()>=this.options.stopAt.getTime()?null:w}_calculatePreviousRun(A,f){let Q=new T4(void 0,this.options.timezone||this.options.utcOffset),w=A;if(this.options.startAt.getTime()<=Q.getTime()){w=this.options.startAt;let B=w.getTime()+this.options.interval*1000;for(;B<=Q.getTime();)w=new T4(w,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),B=w.getTime()+this.options.interval*1000;f=!0}return w===null&&(w=void 0),[w,f]}};class Ja{scheduleCron(A,f){let Q=new xGA(A,()=>{f()});return{stop:()=>Q.stop()}}scheduleInterval(A,f){let Q=setInterval(()=>{f()},A);return{stop:()=>clearInterval(Q)}}validateCron(A){new xGA(A).stop()}}B0();HA();var IGA=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)")}),$GA=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),ry2=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array($GA).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),dy2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),cGA=X.union([ry2,dy2]);function va(A,f,Q){return{...Tf(f,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",IGA,async(B)=>{let{action:x,entityType:I,entityId:$,position:c}=B;switch(x){case"list":return oy2(Q,I);case"add":return ay2(Q,I,$);case"remove":return sy2(Q,I,$);case"reorder":return ty2(Q,I,$,c);default:return{success:!1,error:`Unknown action: ${x}`}}}),outputSchema:cGA}}async function oy2(A,f){let Q=[];if(f)Q=await A.list(f);else{let B=A.getRegisteredTypes();for(let x of B){let I=await A.list(x);Q.push(...I)}Q.sort((x,I)=>new Date(x.queuedAt).getTime()-new Date(I.queuedAt).getTime())}if(Q.length===0)return{success:!0,data:{queue:[]},message:"No items in queue"};return{success:!0,data:{queue:Q.map((B,x)=>({position:x+1,entityType:B.entityType,entityId:B.entityId,queuedAt:B.queuedAt}))},message:`${Q.length} items in queue`}}async function ay2(A,f,Q){if(!f)return{success:!1,error:"entityType is required for add action"};if(!Q)return{success:!1,error:"entityId is required for add action"};let w=await A.add(f,Q);return{success:!0,data:{entityType:f,entityId:Q,position:w.position},message:`Added to queue at position ${w.position}`}}async function sy2(A,f,Q){if(!f)return{success:!1,error:"entityType is required for remove action"};if(!Q)return{success:!1,error:"entityId is required for remove action"};return await A.remove(f,Q),{success:!0,data:{entityType:f,entityId:Q},message:"Removed from queue"}}async function ty2(A,f,Q,w){if(!f)return{success:!1,error:"entityType is required for reorder action"};if(!Q)return{success:!1,error:"entityId is required for reorder action"};if(w===void 0)return{success:!1,error:"position is required for reorder action"};if(w<1)return{success:!1,error:"position must be a positive number"};return await A.reorder(f,Q,w),{success:!0,data:{entityType:f,entityId:Q,position:w},message:`Moved to position ${w}`}}B0();HA();var DGA=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")}),ey2=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()}),Al2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),YGA=X.union([ey2,Al2]);function ka(A,f,Q){return{...Tf(f,"publish","Publish an entity directly to its platform. Works with any registered entity type (social-post, post, deck, etc.)",DGA,async(B)=>{let{entityType:x,id:I,slug:$}=B;if(!I&&!$)return{success:!1,error:"Either 'id' or 'slug' must be provided"};let c=null;if(I)c=await A.entityService.getEntity(x,I);else if($)c=(await A.entityService.listEntities(x,{filter:{metadata:{slug:$}},limit:1}))[0]??null;if(!c)return{success:!1,error:`Entity not found: ${x}:${I??$}`};if(c.metadata.status==="published")return{success:!1,error:"Entity is already published"};if(!Q.has(x))return{success:!1,error:`No publish provider registered for ${x}. Check that the required credentials are configured.`};let D=Q.get(x),u=c.content,K;try{let J=H2(c.content,X.record(X.unknown()));u=J.content;let v=J.metadata.coverImageId;K=typeof v==="string"?v:void 0}catch{}let F;if(K){let J=await A.entityService.getEntity("image",K);if(J?.content){let v=J.content.match(/^data:([^;]+);base64,(.+)$/);if(v?.[1]&&v[2])F={data:Buffer.from(v[2],"base64"),mimeType:v[1]}}}let Z=await D.publish(u,c.metadata,F);return await A.entityService.updateEntity({...c,metadata:{...c.metadata,status:"published",publishedAt:new Date().toISOString(),platformId:Z.id}}),{success:!0,data:{entityType:x,entityId:c.id,platformId:Z.id,url:Z.url},message:`Published ${x}:${c.id}`}}),outputSchema:YGA}}B0();HA();function Uo0(A,f){let{logger:Q}=f;A.messaging.subscribe(tB.REGISTER,async(w)=>fl2(f,w.payload)),A.messaging.subscribe(tB.QUEUE,async(w)=>Ql2(A,f,w.payload)),A.messaging.subscribe(tB.DIRECT,async(w)=>wl2(A,f,w.payload)),A.messaging.subscribe(tB.REMOVE,async(w)=>Bl2(f,w.payload)),A.messaging.subscribe(tB.REORDER,async(w)=>xl2(f,w.payload)),A.messaging.subscribe(tB.LIST,async(w)=>Il2(A,f,w.payload)),A.messaging.subscribe(tB.REPORT_SUCCESS,async(w)=>$l2(A,f,w.payload)),A.messaging.subscribe(tB.REPORT_FAILURE,async(w)=>cl2(A,f,w.payload)),Q.debug("Subscribed to publish messages"),A.messaging.subscribe(ND.REPORT_SUCCESS,async(w)=>{let{entityType:B,entityId:x}=w.payload;return f.scheduler.completeGeneration(B,x),Q.info("Generation completed",{entityType:B,entityId:x}),{success:!0}}),A.messaging.subscribe(ND.REPORT_FAILURE,async(w)=>{let{entityType:B,error:x}=w.payload;return f.scheduler.failGeneration(B,x),Q.warn("Generation failed",{entityType:B,error:x}),{success:!0}}),Q.debug("Subscribed to generation messages")}async function fl2(A,f){let{entityType:Q,provider:w}=f;try{if(w)A.providerRegistry.register(Q,w),A.logger.info(`Registered provider for entity type: ${Q}`,{providerName:w.name});return{success:!0}}catch(B){let x=v0(B);return A.logger.error(`Failed to register provider: ${x}`),{success:!1}}}async function Ql2(A,f,Q){let{entityType:w,entityId:B}=Q;try{let x=await f.queueManager.add(w,B);return await A.messaging.send(tB.QUEUED,{entityType:w,entityId:B,position:x.position}),f.logger.debug(`Entity queued: ${B}`,{entityType:w,position:x.position}),{success:!0}}catch(x){let I=v0(x);return f.logger.error(`Failed to queue entity: ${I}`),{success:!1}}}async function wl2(A,f,Q){let{entityType:w,entityId:B}=Q;return await A.messaging.send(tB.EXECUTE,{entityType:w,entityId:B}),f.logger.debug(`Direct publish requested: ${B}`,{entityType:w}),{success:!0}}async function Bl2(A,f){let{entityType:Q,entityId:w}=f;try{return await A.queueManager.remove(Q,w),A.logger.debug(`Entity removed from queue: ${w}`,{entityType:Q}),{success:!0}}catch(B){let x=v0(B);return A.logger.error(`Failed to remove entity: ${x}`),{success:!1}}}async function xl2(A,f){let{entityType:Q,entityId:w,position:B}=f;try{return await A.queueManager.reorder(Q,w,B),A.logger.debug(`Entity reordered: ${w}`,{entityType:Q,newPosition:B}),{success:!0}}catch(x){let I=v0(x);return A.logger.error(`Failed to reorder entity: ${I}`),{success:!1}}}async function Il2(A,f,Q){let{entityType:w}=Q;try{let B=await f.queueManager.list(w);return await A.messaging.send(tB.LIST_RESPONSE,{entityType:w,queue:B.map((x)=>({entityId:x.entityId,position:x.position,queuedAt:x.queuedAt}))}),{success:!0}}catch(B){let x=v0(B);return f.logger.error(`Failed to list queue: ${x}`),{success:!1}}}async function $l2(A,f,Q){let{entityType:w,entityId:B,result:x}=Q;return f.retryTracker.clearRetries(B),await A.messaging.send(tB.COMPLETED,{entityType:w,entityId:B,result:x}),f.logger.info(`Publish reported success: ${B}`,{entityType:w}),{success:!0}}async function cl2(A,f,Q){let{entityType:w,entityId:B,error:x}=Q;f.retryTracker.recordFailure(B,x);let I=f.retryTracker.getRetryInfo(B);return await A.messaging.send(tB.FAILED,{entityType:w,entityId:B,error:x,retryCount:I?.retryCount??1,willRetry:I?.willRetry??!1}),f.logger.info(`Publish reported failure: ${B}`,{entityType:w,error:x,retryCount:I?.retryCount,willRetry:I?.willRetry}),{success:!0}}HA();async function Ho0(A,f,Q,w){try{if(w.skipIfDraftExists!==!1){if((await A.listEntities(Q,{filter:{metadata:{status:"draft"}},limit:1})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(w.maxUnpublishedDrafts!==void 0){let B=await A.listEntities(Q,{filter:{metadata:{status:"draft"}},limit:w.maxUnpublishedDrafts+1});if(B.length>=w.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${B.length}/${w.maxUnpublishedDrafts})`}}if(w.minSourceEntities!==void 0&&w.sourceEntityType){let B=await A.listEntities(w.sourceEntityType,{publishedOnly:!0,limit:w.minSourceEntities});if(B.length<w.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${B.length}/${w.minSourceEntities} ${w.sourceEntityType})`}}return{shouldGenerate:!0}}catch(B){return f.error("Failed to check generation conditions",{entityType:Q,error:v0(B)}),{shouldGenerate:!1,reason:`Condition check failed: ${v0(B)}`}}}function Ko0(A){let{context:f,config:Q,queueManager:w,providerRegistry:B,retryTracker:x,logger:I}=A,$={send:async(c,D)=>{return f.messaging.send(c,D)},subscribe:()=>()=>{}};return q$.createFresh({queueManager:w,providerRegistry:B,retryTracker:x,logger:I,backend:new Ja,...Q.entitySchedules&&{entitySchedules:Q.entitySchedules},...Q.generationSchedules&&{generationSchedules:Q.generationSchedules},...Q.generationConditions&&{generationConditions:Q.generationConditions},messageBus:$,entityService:f.entityService,onPublish:(c)=>{f.messaging.send(tB.COMPLETED,{entityType:c.entityType,entityId:c.entityId,result:c.result})},onFailed:(c)=>{f.messaging.send(tB.FAILED,{entityType:c.entityType,entityId:c.entityId,error:c.error,retryCount:c.retryCount,willRetry:c.willRetry})},onCheckGenerationConditions:(c,D)=>Ho0(f.entityService,I,c,D),onGenerate:(c)=>{I.info(`Generation triggered for ${c.entityType}`),f.messaging.send(ND.EXECUTE,{entityType:c.entityType})}})}async function Fo0(A,f,Q){let w=A.getEntityTypes();for(let x of w){let I=await A.listEntities(x,{filter:{metadata:{status:"queued"}}});for(let $ of I)await f.add($.entityType,$.id)}let B=0;for(let x of w){let I=await f.list(x);B+=I.length}if(B>0)Q.info(`Rebuilt queue with ${B} queued entities`)}var Xo0={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.0",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 uGA extends mw{pluginContext;queueManager;providerRegistry;retryTracker;scheduler;constructor(A){super("content-pipeline",Xo0,A??{},ed0)}async onRegister(A){this.pluginContext=A,this.queueManager=ED.createFresh(),this.providerRegistry=hD.createFresh(),this.retryTracker=bD.createFresh({maxRetries:this.config.maxRetries,baseDelayMs:this.config.retryBaseDelayMs}),this.scheduler=Ko0({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,logger:this.logger}),Uo0(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 Fo0(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(),Q=[],w={draft:0,queued:0,published:0,failed:0};for(let B of f){let x=await A.entityService.listEntities(B);for(let I of x){let $=I.metadata.status;if($!=="draft"&&$!=="queued"&&$!=="published"&&$!=="failed")continue;w[$]++;let c=I.metadata.title;Q.push({id:I.id,title:typeof c==="string"?c:I.id,type:B,status:$})}}return{summary:w,items:Q}}}),{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[va(this.pluginContext,this.id,this.queueManager),ka(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(){ED.resetInstance(),hD.resetInstance(),bD.resetInstance()}}function UGA(A){return new uGA(A)}B0();HA();var Zo0=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")}),HGA=X.object({cloudflare:Zo0.optional()});B0();HA();var Yl2=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 ul2(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 Wo0(A,f,Q){let w=[];if(!Q)return w;return w.push(Tf(A,"query",`Query website analytics from Cloudflare.
|
|
3018
|
+
${Q.content}`:Q.prompt??"Write an engaging LinkedIn post";return A.ai.generate({prompt:w,templateName:`social-media:${Q.platform}`})}),A.eval.registerHandler("create",async(f)=>{let Q=gy2.parse(f),w=[],B=Z9.from(async(D)=>{let u={progress:D.progress};if(D.message!==void 0)u.message=D.message;w.push(u)});if(!B)throw Error("Failed to create progress reporter");let I=await new XW(A.logger,A).process(Q,`eval-${Date.now()}`,B),$=!1,c;if(I.success&&I.entityId){let D=await A.entityService.getEntity("social-post",I.entityId);$=!!D,c=D?.content.slice(0,300)}return{...I,entityExists:$,entityPreview:c,progressSteps:w}})}HA();B0();class RO{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:Q}=A;if(f!=="social-post")return;this.logger.debug("Handling publish:execute",{entityId:Q});try{let w=await this.entityService.getEntity("social-post",Q);if(!w){await this.reportFailure(f,Q,`Post not found: ${Q}`);return}if(w.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:Q});return}let B=w.metadata.platform,x=this.providers.get(B);if(!x){await this.reportFailure(f,Q,`No provider configured for platform: ${B}`);return}let I=H2(w.content,i4),$;if(I.metadata.coverImageId)$=await this.fetchImageData(I.metadata.coverImageId);try{let c=await x.publish(I.content,w.metadata,$),D=new Date().toISOString(),u=c.id||void 0,K={...I.metadata,status:"published",publishedAt:D,...u&&{platformPostId:u}},F=hx.createPostContent(K,I.content);await this.entityService.updateEntity({...w,content:F,metadata:{...w.metadata,status:"published",publishedAt:D,platformPostId:u}}),await this.reportSuccess(f,Q,c.id),this.logger.info(`Post published successfully: ${Q}`,{platform:B,platformPostId:u})}catch(c){let D=c instanceof Error?c.message:String(c),u={...I.metadata,status:"failed"},K=hx.createPostContent(u,I.content);await this.entityService.updateEntity({...w,content:K,metadata:{...w.metadata,status:"failed"}}),await this.reportFailure(f,Q,D),this.logger.error(`Post publish failed: ${Q}`,{platform:B,error:D})}}catch(w){let B=v0(w);this.logger.error("Unexpected error in publish handler",{entityId:Q,error:B}),await this.reportFailure(f,Q,B)}}async reportSuccess(A,f,Q){await this.sendMessage("publish:report:success",{entityType:A,entityId:f,result:{id:Q}})}async reportFailure(A,f,Q){await this.sendMessage("publish:report:failure",{entityType:A,entityId:f,error:Q})}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 w=f.content.match(/^data:([^;]+);base64,(.+)$/);if(!w?.[1]||!w[2]){this.logger.warn("Invalid image data URL format",{imageId:A});return}let B=w[1],x=w[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 rd0(A,f,Q){if(f.size===0){Q.debug("No providers configured, skipping publish-pipeline registration");return}A.messaging.subscribe("system:plugins:ready",async()=>{let w=f.values().next().value;return await A.messaging.send("publish:register",{entityType:"social-post",provider:w}),Q.info("Registered social-post with publish-pipeline"),{success:!0}})}function dd0(A,f,Q){let w=new RO({sendMessage:A.messaging.send,logger:Q.child("PublishExecuteHandler"),entityService:A.entityService,providers:f});A.messaging.subscribe("publish:execute",async(B)=>{return await w.handle(B.payload),{success:!0}}),Q.debug("Subscribed to publish:execute messages")}HA();function od0(A,f){A.messaging.subscribe("entity:updated",async(Q)=>{let{entityType:w,entityId:B,entity:x}=Q.payload;if(w!=="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:w,sourceEntityId:B,platform:"linkedin"}),f.info(`Auto-generate social post triggered for queued post ${B}`),{success:!0}}catch($){let c=v0($);return f.error(`Failed to trigger auto-generate for ${B}:`,{error:c}),{success:!0}}}),f.debug("Subscribed to entity:updated for auto-generation")}function ad0(A,f){A.messaging.subscribe("social:auto-generate",async(Q)=>{let{sourceEntityType:w,sourceEntityId:B,platform:x}=Q.payload;try{let I=await A.jobs.enqueue(`${hx.entityType}:generation`,{sourceEntityType:w,sourceEntityId:B,platform:x,addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info(`Social post generation job enqueued for ${w}/${B}`,{jobId:I}),{success:!0,jobId:I}}catch(I){let $=v0(I);return f.error(`Failed to enqueue social post generation for ${B}:`,{error:$}),{success:!1}}}),f.debug("Subscribed to social:auto-generate messages")}function sd0(A,f){A.messaging.subscribe("generate:execute",async(Q)=>{let{entityType:w}=Q.payload;if(w!=="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 $ of B)if((await A.entityService.listEntities("social-post",{filter:{metadata:{sourceEntityType:"post",sourceEntityId:$.id}},limit:1})).length===0){x=$;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 I=await A.jobs.enqueue(`${hx.entityType}:generation`,{sourceEntityType:"post",sourceEntityId:x.id,platform:"linkedin",addToQueue:!1},{interfaceType:"job",userId:"system"});return f.info("Social post generation job queued",{jobId:I,sourcePostId:x.id}),{success:!0}}catch(B){let x=v0(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 td0={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.1",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 fGA extends zf{entityType=hx.entityType;schema=jN;adapter=hx;providers=new Map;constructor(A){super("social-media",td0,A,oWA)}createGenerationHandler(A){return new XW(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return nd0()}getDataSources(){return[new Fa(this.logger.child("SocialPostDataSource"))]}async onRegister(A){if(this.initializeProviders(),rd0(A,this.providers,this.logger),dd0(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)od0(A,this.logger),ad0(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");sd0(A,this.logger),pd0(A),this.logger.info("Social media plugin registered successfully")}async derive(A,f,Q){if(A.metadata.status!=="published")return;await Q.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=AGA(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function PO(A){return new fGA(A)}HA();var Ty2=X.enum(["draft","queued","published","failed"]),HEQ=X.object({status:Ty2.default("draft"),queueOrder:X.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:X.string().datetime().optional()});class QGA{name="internal";async publish(A,f){return{id:"internal"}}}var tB={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"},ND={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"};HA();var my2=X.object({skipIfDraftExists:X.boolean().optional(),minSourceEntities:X.number().optional(),maxUnpublishedDrafts:X.number().optional(),sourceEntityType:X.string().optional()}),ed0=X.object({entitySchedules:X.record(X.string(),X.string()).optional(),generationSchedules:X.record(X.string(),X.string()).optional(),generationConditions:X.record(X.string(),my2).optional(),maxRetries:X.number().optional().default(3),retryBaseDelayMs:X.number().optional().default(5000)});class ED{static instance=null;queues=new Map;static getInstance(){return ED.instance??=new ED,ED.instance}static resetInstance(){ED.instance=null}static createFresh(){return new ED}constructor(){}async add(A,f){let Q=this.getOrCreateQueue(A),w=Q.find((I)=>I.entityId===f);if(w)return{position:w.position};let B=Q.length+1,x={entityId:f,entityType:A,position:B,queuedAt:new Date().toISOString()};return Q.push(x),{position:B}}async remove(A,f){let Q=this.queues.get(A);if(!Q)return;let w=Q.findIndex((B)=>B.entityId===f);if(w===-1)return;Q.splice(w,1),this.recalculatePositions(Q)}async reorder(A,f,Q){let w=this.queues.get(A);if(!w)return;let B=w.findIndex(($)=>$.entityId===f);if(B===-1)return;let[x]=w.splice(B,1);if(!x)return;let I=Math.max(0,Math.min(Q-1,w.length));w.splice(I,0,x),this.recalculatePositions(w)}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 Q=f[0];if(!Q)continue;if(!A||Q.queuedAt<A.queuedAt)A=Q}return A}async popNext(A){let f=this.queues.get(A);if(!f||f.length===0)return null;let Q=f.shift()??null;if(Q)this.recalculatePositions(f);return Q}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let A=[];for(let[f,Q]of this.queues.entries())if(Q.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,Q)=>{f.position=Q+1})}}class hD{static instance=null;providers=new Map;defaultProvider=new QGA;static getInstance(){return hD.instance??=new hD,hD.instance}static resetInstance(){hD.instance=null}static createFresh(){return new hD}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())}}HA();HA();async function Ao0(A,f){let Q={entityType:A.entityType,entityId:A.entityId};if(f.messageBus)await f.messageBus.send(tB.EXECUTE,Q,"publish-service");f.onExecute?.(Q)}async function fo0(A,f){let Q=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 w=await f.entityService.getEntity(A.entityType,A.entityId);if(!w){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 Q.publish(w.content,w.metadata);f.retryTracker.clearRetries(A.entityId),f.onPublish?.({entityType:A.entityType,entityId:A.entityId,result:B})}catch(B){let x=v0(B);f.retryTracker.recordFailure(A.entityId,x);let I=f.retryTracker.getRetryInfo(A.entityId);f.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:x,retryCount:I?.retryCount??1,willRetry:I?.willRetry??!1})}}function Qo0(A,f,Q,w){if(w.retryTracker.clearRetries(f),w.messageBus)w.messageBus.send(tB.COMPLETED,{entityType:A,entityId:f,result:Q},"publish-service");w.onPublish?.({entityType:A,entityId:f,result:Q})}function wo0(A,f,Q,w){w.retryTracker.recordFailure(f,Q);let B=w.retryTracker.getRetryInfo(f),x={entityType:A,entityId:f,error:Q,retryCount:B?.retryCount??1,willRetry:B?.willRetry??!1};if(w.messageBus)w.messageBus.send(tB.FAILED,x,"publish-service");w.onFailed?.(x)}async function Bo0(A,f){let Q=f.generationConditions[A];if(Q&&f.onCheckGenerationConditions){let B=await f.onCheckGenerationConditions(A,Q);if(!B.shouldGenerate){if(f.messageBus)f.messageBus.send(ND.SKIPPED,{entityType:A,reason:B.reason??"Conditions not met"},"content-pipeline");return}}let w={entityType:A};if(f.messageBus)await f.messageBus.send(ND.EXECUTE,w,"content-pipeline");f.onGenerate?.(w)}function xo0(A,f,Q){if(Q)Q.send(ND.COMPLETED,{entityType:A,entityId:f},"content-pipeline")}function Io0(A,f,Q){if(Q)Q.send(ND.FAILED,{entityType:A,error:f},"content-pipeline")}var Sy2=1000;class q${static instance=null;config;publishJobs=new Map;generationJobs=new Map;immediateIntervalJob=null;running=!1;static getInstance(A){return q$.instance??=new q$(A),q$.instance}static resetInstance(){if(q$.instance)q$.instance.stop();q$.instance=null}static createFresh(A){return new q$(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 Q=this.config.backend.scheduleCron(f,()=>this.processEntityType(A));this.publishJobs.set(A,Q)}for(let[A,f]of Object.entries(this.generationSchedules)){let Q=this.config.backend.scheduleCron(f,()=>this.handleTriggerGeneration(A));this.generationJobs.set(A,Q)}this.immediateIntervalJob=this.config.backend.scheduleInterval(Sy2,()=>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 Q=await this.config.queueManager.getNext(f);if(Q){await this.processEntry(Q);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 Ao0(A,this.publishDeps);else await fo0(A,this.publishDeps)}completePublish(A,f,Q){Qo0(A,f,Q,this.publishDeps)}failPublish(A,f,Q){wo0(A,f,Q,this.publishDeps)}async publishDirect(A,f,Q,w){return this.config.providerRegistry.get(A).publish(Q,w)}async handleTriggerGeneration(A){if(!this.running)return;try{await Bo0(A,this.generationDeps)}catch(f){this.config.logger.error(`Generation trigger error for ${A}:`,f)}}completeGeneration(A,f){xo0(A,f,this.config.messageBus)}failGeneration(A,f){Io0(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,Q){try{this.config.backend.validateCron(f)}catch(w){throw Error(`Invalid ${Q} cron expression for ${A}: "${f}" - ${v0(w)}`)}}}var $o0={maxRetries:3,baseDelayMs:5000};class bD{static instance=null;retries=new Map;config;static getInstance(A){return bD.instance??=new bD(A??$o0),bD.instance}static resetInstance(){bD.instance=null}static createFresh(A){return new bD(A??$o0)}constructor(A){this.config=A}recordFailure(A,f){let w=(this.retries.get(A)?.retryCount??0)+1,B=this.config.baseDelayMs*Math.pow(2,w-1),x=Date.now()+B;this.retries.set(A,{entityId:A,retryCount:w,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 i9(A,f,Q,w,B,x,I,$){return i9.fromTZ(i9.tp(A,f,Q,w,B,x,I),$)}i9.fromTZISO=(A,f,Q)=>i9.fromTZ(yy2(A,f),Q);i9.fromTZ=function(A,f){let Q=new Date(Date.UTC(A.y,A.m-1,A.d,A.h,A.i,A.s)),w=wGA(A.tz,Q),B=new Date(Q.getTime()-w),x=wGA(A.tz,B);if(x-w===0)return B;{let I=new Date(Q.getTime()-x),$=wGA(A.tz,I);if($-x===0)return I;if(!f&&$-x>0)return I;if(f)throw Error("Invalid date passed to fromTZ()");return B}};i9.toTZ=function(A,f){let Q=A.toLocaleString("en-US",{timeZone:f}).replace(/[\u202f]/," "),w=new Date(Q);return{y:w.getFullYear(),m:w.getMonth()+1,d:w.getDate(),h:w.getHours(),i:w.getMinutes(),s:w.getSeconds(),tz:f}};i9.tp=(A,f,Q,w,B,x,I)=>({y:A,m:f,d:Q,h:w,i:B,s:x,tz:I});function wGA(A,f=new Date){let Q=f.toLocaleString("en-US",{timeZone:A,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],w=f.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${w} GMT`)-Date.parse(`${w} ${Q}`)}function yy2(A,f){let Q=new Date(Date.parse(A));if(isNaN(Q))throw Error("minitz: Invalid ISO8601 passed to parser.");let w=A.substring(9);return A.includes("Z")||w.includes("-")||w.includes("+")?i9.tp(Q.getUTCFullYear(),Q.getUTCMonth()+1,Q.getUTCDate(),Q.getUTCHours(),Q.getUTCMinutes(),Q.getUTCSeconds(),"Etc/UTC"):i9.tp(Q.getFullYear(),Q.getMonth()+1,Q.getDate(),Q.getHours(),Q.getMinutes(),Q.getSeconds(),f)}i9.minitz=i9;var BGA=32,iO=31|BGA,uo0=[1,2,4,8,16],co0=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 T4(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,iO),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(A,f,Q,w){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(w);let I=f.split(",");if(I.length>1)for(let $=0;$<I.length;$++)this.partToArray(A,I[$],Q,w);else f.indexOf("-")!==-1&&f.indexOf("/")!==-1?this.handleRangeWithStepping(f,A,Q,w):f.indexOf("-")!==-1?this.handleRange(f,A,Q,w):f.indexOf("/")!==-1?this.handleStepping(f,A,Q,w):f!==""&&this.handleNumber(f,A,Q,w)}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,Q,w){let B=this.extractNth(A,f),x=parseInt(B[0],10)+Q;if(isNaN(x))throw TypeError("CronPattern: "+f+" is not a number: '"+A+"'");this.setPart(f,x,B[1]||w)}setPart(A,f,Q){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,Q);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]=Q}handleRangeWithStepping(A,f,Q,w){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[,I,$,c]=x,D=parseInt(I,10)+Q,u=parseInt($,10)+Q,K=parseInt(c,10);if(isNaN(D))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(u))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(K))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(K===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(K>this[f].length)throw TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[f].length+")");if(D>u)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let F=D;F<=u;F+=K)this.setPart(f,F,B[1]||w)}extractNth(A,f){let Q=A,w;if(Q.includes("#")){if(f!=="dayOfWeek")throw Error("CronPattern: nth (#) only allowed in day-of-week field");w=Q.split("#")[1],Q=Q.split("#")[0]}return[Q,w]}handleRange(A,f,Q,w){let B=this.extractNth(A,f),x=B[0].split("-");if(x.length!==2)throw TypeError("CronPattern: Syntax error, illegal range: '"+A+"'");let I=parseInt(x[0],10)+Q,$=parseInt(x[1],10)+Q;if(isNaN(I))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN($))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(I>$)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let c=I;c<=$;c++)this.setPart(f,c,B[1]||w)}handleStepping(A,f,Q,w){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 I=0;x[0]!=="*"&&(I=parseInt(x[0],10)+Q);let $=parseInt(x[1],10);if(isNaN($))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if($===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if($>this[f].length)throw TypeError("CronPattern: Syntax error, max steps for part is ("+this[f].length+")");for(let c=I;c<this[f].length;c+=$)this.setPart(f,c,B[1]||w)}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]|BGA;else if(f===iO)this.dayOfWeek[A]=iO;else if(f<6&&f>0)this.dayOfWeek[A]=this.dayOfWeek[A]|uo0[f-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${f}, Type: ${typeof f}`)}},Do0=[31,28,31,30,31,30,31,31,30,31,30,31],rY=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],T4=class A{tz;ms;second;minute;hour;day;month;year;constructor(f,Q){if(this.tz=Q,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,Q,w,B){let x=new Date(Date.UTC(f,Q,w)).getUTCDay(),I=0;for(let $=1;$<=w;$++)new Date(Date.UTC(f,Q,$)).getUTCDay()===x&&I++;if(B&iO&&uo0[I-1]&B)return!0;if(B&BGA){let $=new Date(Date.UTC(f,Q+1,0)).getUTCDate();for(let c=w+1;c<=$;c++)if(new Date(Date.UTC(f,Q,c)).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 Q=i9.toTZ(f,this.tz);this.ms=f.getMilliseconds(),this.second=Q.s,this.minute=Q.i,this.hour=Q.h,this.day=Q.d,this.month=Q.m-1,this.year=Q.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>Do0[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 Q=i9.fromTZISO(f);this.ms=Q.getUTCMilliseconds(),this.second=Q.getUTCSeconds(),this.minute=Q.getUTCMinutes(),this.hour=Q.getUTCHours(),this.day=Q.getUTCDate(),this.month=Q.getUTCMonth(),this.year=Q.getUTCFullYear(),this.apply()}else return this.fromDate(i9.fromTZISO(f,this.tz))}findNext(f,Q,w,B){let x=this[Q],I;w.lastDayOfMonth&&(this.month!==1?I=Do0[this.month]:I=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let $=!w.starDOW&&Q=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let c=this[Q]+B;c<w[Q].length;c++){let D=w[Q][c];if(Q==="day"&&w.lastDayOfMonth&&c-B==I&&(D=1),Q==="day"&&!w.starDOW){let u=w.dayOfWeek[($+(c-B-1))%7];if(u&&u&iO)u=this.isNthWeekdayOfMonth(this.year,this.month,c-B,u)?1:0;else if(u)throw Error(`CronDate: Invalid value for dayOfWeek encountered. ${u}`);f.legacyMode&&!w.starDOM?D=D||u:D=D&&u}if(D)return this[Q]=c-B,x!==this[Q]?2:1}return 3}recurse(f,Q,w){let B=this.findNext(Q,rY[w][0],f,rY[w][2]);if(B>1){let x=w+1;for(;x<rY.length;)this[rY[x][0]]=-rY[x][2],x++;if(B===3)return this[rY[w][1]]++,this[rY[w][0]]=-rY[w][2],this.apply(),this.recurse(f,Q,0);if(this.apply())return this.recurse(f,Q,w-1)}return w+=1,w>=rY.length?this:this.year>=3000?null:this.recurse(f,Q,w)}increment(f,Q,w){return this.second+=Q.interval!==void 0&&Q.interval>1&&w?Q.interval:1,this.ms=0,this.apply(),this.recurse(f,Q,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)):i9.fromTZ(i9.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function ly2(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 T4(A.startAt,A.timezone)),A.stopAt&&(A.stopAt=new T4(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 gO(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function ny2(A){return gO(A)}function py2(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var Yo0=30000,Ga=[],xGA=class{name;options;_states;fn;constructor(A,f,Q){let w,B;if(gO(f))B=f;else if(typeof f=="object")w=f;else if(f!==void 0)throw Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(gO(Q))B=Q;else if(typeof Q=="object")w=Q;else if(Q!==void 0)throw Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=w?.name,this.options=ly2(w),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:w?w.maxRuns:void 0,paused:w?w.paused:!1,pattern:new co0("* * * * *")},A&&(A instanceof Date||typeof A=="string"&&A.indexOf(":")>0)?this._states.once=new T4(A,this.options.timezone||this.options.utcOffset):this._states.pattern=new co0(A,this.options.timezone),this.name){if(Ga.find((x)=>x.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");Ga.push(this)}return B!==void 0&&ny2(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 Q=[],w=f||this._states.currentRun||void 0;for(;A--&&(w=this.nextRun(w));)Q.push(w);return Q}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let A=this.nextRun(this._states.currentRun),f=!this._states.paused,Q=this.fn!==void 0,w=!this._states.kill;return f&&Q&&w&&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 T4||A instanceof Date?f.getTime()-A.getTime():f.getTime()-new T4(A).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let A=Ga.indexOf(this);A>=0&&Ga.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(),Q=this.nextRun(this._states.currentRun);return f==null||isNaN(f)||Q===null?this:(f>Yo0&&(f=Yo0),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(Q),f),this._states.currentTimeout&&this.options.unref&&py2(this._states.currentTimeout),this)}async _trigger(A){if(this._states.blocking=!0,this._states.currentRun=new T4(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){gO(this.options.catch)&&this.options.catch(f,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new T4(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,Q=!this._states.paused&&f.getTime()>=A.getTime(),w=this._states.blocking&&this.options.protect;Q&&!w?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):Q&&w&&gO(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(A){let f=!!(A||this._states.currentRun),Q=!1;!A&&this.options.startAt&&this.options.interval&&([A,f]=this._calculatePreviousRun(A,f),Q=!A),A=new T4(A,this.options.timezone||this.options.utcOffset),this.options.startAt&&A&&A.getTime()<this.options.startAt.getTime()&&(A=this.options.startAt);let w=this._states.once||new T4(A,this.options.timezone||this.options.utcOffset);return!Q&&w!==this._states.once&&(w=w.increment(this._states.pattern,this.options,f)),this._states.once&&this._states.once.getTime()<=A.getTime()||w===null||this._states.maxRuns!==void 0&&this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&w.getTime()>=this.options.stopAt.getTime()?null:w}_calculatePreviousRun(A,f){let Q=new T4(void 0,this.options.timezone||this.options.utcOffset),w=A;if(this.options.startAt.getTime()<=Q.getTime()){w=this.options.startAt;let B=w.getTime()+this.options.interval*1000;for(;B<=Q.getTime();)w=new T4(w,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),B=w.getTime()+this.options.interval*1000;f=!0}return w===null&&(w=void 0),[w,f]}};class Ja{scheduleCron(A,f){let Q=new xGA(A,()=>{f()});return{stop:()=>Q.stop()}}scheduleInterval(A,f){let Q=setInterval(()=>{f()},A);return{stop:()=>clearInterval(Q)}}validateCron(A){new xGA(A).stop()}}B0();HA();var IGA=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)")}),$GA=X.object({position:X.number(),entityType:X.string(),entityId:X.string(),queuedAt:X.string()}),ry2=X.object({success:X.literal(!0),message:X.string().optional(),data:X.object({queue:X.array($GA).optional(),entityType:X.string().optional(),entityId:X.string().optional(),position:X.number().optional()}).optional()}),dy2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),cGA=X.union([ry2,dy2]);function va(A,f,Q){return{...Tf(f,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",IGA,async(B)=>{let{action:x,entityType:I,entityId:$,position:c}=B;switch(x){case"list":return oy2(Q,I);case"add":return ay2(Q,I,$);case"remove":return sy2(Q,I,$);case"reorder":return ty2(Q,I,$,c);default:return{success:!1,error:`Unknown action: ${x}`}}}),outputSchema:cGA}}async function oy2(A,f){let Q=[];if(f)Q=await A.list(f);else{let B=A.getRegisteredTypes();for(let x of B){let I=await A.list(x);Q.push(...I)}Q.sort((x,I)=>new Date(x.queuedAt).getTime()-new Date(I.queuedAt).getTime())}if(Q.length===0)return{success:!0,data:{queue:[]},message:"No items in queue"};return{success:!0,data:{queue:Q.map((B,x)=>({position:x+1,entityType:B.entityType,entityId:B.entityId,queuedAt:B.queuedAt}))},message:`${Q.length} items in queue`}}async function ay2(A,f,Q){if(!f)return{success:!1,error:"entityType is required for add action"};if(!Q)return{success:!1,error:"entityId is required for add action"};let w=await A.add(f,Q);return{success:!0,data:{entityType:f,entityId:Q,position:w.position},message:`Added to queue at position ${w.position}`}}async function sy2(A,f,Q){if(!f)return{success:!1,error:"entityType is required for remove action"};if(!Q)return{success:!1,error:"entityId is required for remove action"};return await A.remove(f,Q),{success:!0,data:{entityType:f,entityId:Q},message:"Removed from queue"}}async function ty2(A,f,Q,w){if(!f)return{success:!1,error:"entityType is required for reorder action"};if(!Q)return{success:!1,error:"entityId is required for reorder action"};if(w===void 0)return{success:!1,error:"position is required for reorder action"};if(w<1)return{success:!1,error:"position must be a positive number"};return await A.reorder(f,Q,w),{success:!0,data:{entityType:f,entityId:Q,position:w},message:`Moved to position ${w}`}}B0();HA();var DGA=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")}),ey2=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()}),Al2=X.object({success:X.literal(!1),error:X.string(),code:X.string().optional()}),YGA=X.union([ey2,Al2]);function ka(A,f,Q){return{...Tf(f,"publish","Publish an entity directly to its platform. Works with any registered entity type (social-post, post, deck, etc.)",DGA,async(B)=>{let{entityType:x,id:I,slug:$}=B;if(!I&&!$)return{success:!1,error:"Either 'id' or 'slug' must be provided"};let c=null;if(I)c=await A.entityService.getEntity(x,I);else if($)c=(await A.entityService.listEntities(x,{filter:{metadata:{slug:$}},limit:1}))[0]??null;if(!c)return{success:!1,error:`Entity not found: ${x}:${I??$}`};if(c.metadata.status==="published")return{success:!1,error:"Entity is already published"};if(!Q.has(x))return{success:!1,error:`No publish provider registered for ${x}. Check that the required credentials are configured.`};let D=Q.get(x),u=c.content,K;try{let J=H2(c.content,X.record(X.unknown()));u=J.content;let v=J.metadata.coverImageId;K=typeof v==="string"?v:void 0}catch{}let F;if(K){let J=await A.entityService.getEntity("image",K);if(J?.content){let v=J.content.match(/^data:([^;]+);base64,(.+)$/);if(v?.[1]&&v[2])F={data:Buffer.from(v[2],"base64"),mimeType:v[1]}}}let Z=await D.publish(u,c.metadata,F);return await A.entityService.updateEntity({...c,metadata:{...c.metadata,status:"published",publishedAt:new Date().toISOString(),platformId:Z.id}}),{success:!0,data:{entityType:x,entityId:c.id,platformId:Z.id,url:Z.url},message:`Published ${x}:${c.id}`}}),outputSchema:YGA}}B0();HA();function Uo0(A,f){let{logger:Q}=f;A.messaging.subscribe(tB.REGISTER,async(w)=>fl2(f,w.payload)),A.messaging.subscribe(tB.QUEUE,async(w)=>Ql2(A,f,w.payload)),A.messaging.subscribe(tB.DIRECT,async(w)=>wl2(A,f,w.payload)),A.messaging.subscribe(tB.REMOVE,async(w)=>Bl2(f,w.payload)),A.messaging.subscribe(tB.REORDER,async(w)=>xl2(f,w.payload)),A.messaging.subscribe(tB.LIST,async(w)=>Il2(A,f,w.payload)),A.messaging.subscribe(tB.REPORT_SUCCESS,async(w)=>$l2(A,f,w.payload)),A.messaging.subscribe(tB.REPORT_FAILURE,async(w)=>cl2(A,f,w.payload)),Q.debug("Subscribed to publish messages"),A.messaging.subscribe(ND.REPORT_SUCCESS,async(w)=>{let{entityType:B,entityId:x}=w.payload;return f.scheduler.completeGeneration(B,x),Q.info("Generation completed",{entityType:B,entityId:x}),{success:!0}}),A.messaging.subscribe(ND.REPORT_FAILURE,async(w)=>{let{entityType:B,error:x}=w.payload;return f.scheduler.failGeneration(B,x),Q.warn("Generation failed",{entityType:B,error:x}),{success:!0}}),Q.debug("Subscribed to generation messages")}async function fl2(A,f){let{entityType:Q,provider:w}=f;try{if(w)A.providerRegistry.register(Q,w),A.logger.info(`Registered provider for entity type: ${Q}`,{providerName:w.name});return{success:!0}}catch(B){let x=v0(B);return A.logger.error(`Failed to register provider: ${x}`),{success:!1}}}async function Ql2(A,f,Q){let{entityType:w,entityId:B}=Q;try{let x=await f.queueManager.add(w,B);return await A.messaging.send(tB.QUEUED,{entityType:w,entityId:B,position:x.position}),f.logger.debug(`Entity queued: ${B}`,{entityType:w,position:x.position}),{success:!0}}catch(x){let I=v0(x);return f.logger.error(`Failed to queue entity: ${I}`),{success:!1}}}async function wl2(A,f,Q){let{entityType:w,entityId:B}=Q;return await A.messaging.send(tB.EXECUTE,{entityType:w,entityId:B}),f.logger.debug(`Direct publish requested: ${B}`,{entityType:w}),{success:!0}}async function Bl2(A,f){let{entityType:Q,entityId:w}=f;try{return await A.queueManager.remove(Q,w),A.logger.debug(`Entity removed from queue: ${w}`,{entityType:Q}),{success:!0}}catch(B){let x=v0(B);return A.logger.error(`Failed to remove entity: ${x}`),{success:!1}}}async function xl2(A,f){let{entityType:Q,entityId:w,position:B}=f;try{return await A.queueManager.reorder(Q,w,B),A.logger.debug(`Entity reordered: ${w}`,{entityType:Q,newPosition:B}),{success:!0}}catch(x){let I=v0(x);return A.logger.error(`Failed to reorder entity: ${I}`),{success:!1}}}async function Il2(A,f,Q){let{entityType:w}=Q;try{let B=await f.queueManager.list(w);return await A.messaging.send(tB.LIST_RESPONSE,{entityType:w,queue:B.map((x)=>({entityId:x.entityId,position:x.position,queuedAt:x.queuedAt}))}),{success:!0}}catch(B){let x=v0(B);return f.logger.error(`Failed to list queue: ${x}`),{success:!1}}}async function $l2(A,f,Q){let{entityType:w,entityId:B,result:x}=Q;return f.retryTracker.clearRetries(B),await A.messaging.send(tB.COMPLETED,{entityType:w,entityId:B,result:x}),f.logger.info(`Publish reported success: ${B}`,{entityType:w}),{success:!0}}async function cl2(A,f,Q){let{entityType:w,entityId:B,error:x}=Q;f.retryTracker.recordFailure(B,x);let I=f.retryTracker.getRetryInfo(B);return await A.messaging.send(tB.FAILED,{entityType:w,entityId:B,error:x,retryCount:I?.retryCount??1,willRetry:I?.willRetry??!1}),f.logger.info(`Publish reported failure: ${B}`,{entityType:w,error:x,retryCount:I?.retryCount,willRetry:I?.willRetry}),{success:!0}}HA();async function Ho0(A,f,Q,w){try{if(w.skipIfDraftExists!==!1){if((await A.listEntities(Q,{filter:{metadata:{status:"draft"}},limit:1})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(w.maxUnpublishedDrafts!==void 0){let B=await A.listEntities(Q,{filter:{metadata:{status:"draft"}},limit:w.maxUnpublishedDrafts+1});if(B.length>=w.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${B.length}/${w.maxUnpublishedDrafts})`}}if(w.minSourceEntities!==void 0&&w.sourceEntityType){let B=await A.listEntities(w.sourceEntityType,{publishedOnly:!0,limit:w.minSourceEntities});if(B.length<w.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${B.length}/${w.minSourceEntities} ${w.sourceEntityType})`}}return{shouldGenerate:!0}}catch(B){return f.error("Failed to check generation conditions",{entityType:Q,error:v0(B)}),{shouldGenerate:!1,reason:`Condition check failed: ${v0(B)}`}}}function Ko0(A){let{context:f,config:Q,queueManager:w,providerRegistry:B,retryTracker:x,logger:I}=A,$={send:async(c,D)=>{return f.messaging.send(c,D)},subscribe:()=>()=>{}};return q$.createFresh({queueManager:w,providerRegistry:B,retryTracker:x,logger:I,backend:new Ja,...Q.entitySchedules&&{entitySchedules:Q.entitySchedules},...Q.generationSchedules&&{generationSchedules:Q.generationSchedules},...Q.generationConditions&&{generationConditions:Q.generationConditions},messageBus:$,entityService:f.entityService,onPublish:(c)=>{f.messaging.send(tB.COMPLETED,{entityType:c.entityType,entityId:c.entityId,result:c.result})},onFailed:(c)=>{f.messaging.send(tB.FAILED,{entityType:c.entityType,entityId:c.entityId,error:c.error,retryCount:c.retryCount,willRetry:c.willRetry})},onCheckGenerationConditions:(c,D)=>Ho0(f.entityService,I,c,D),onGenerate:(c)=>{I.info(`Generation triggered for ${c.entityType}`),f.messaging.send(ND.EXECUTE,{entityType:c.entityType})}})}async function Fo0(A,f,Q){let w=A.getEntityTypes();for(let x of w){let I=await A.listEntities(x,{filter:{metadata:{status:"queued"}}});for(let $ of I)await f.add($.entityType,$.id)}let B=0;for(let x of w){let I=await f.list(x);B+=I.length}if(B>0)Q.info(`Rebuilt queue with ${B} queued entities`)}var Xo0={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.1",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 uGA extends mw{pluginContext;queueManager;providerRegistry;retryTracker;scheduler;constructor(A){super("content-pipeline",Xo0,A??{},ed0)}async onRegister(A){this.pluginContext=A,this.queueManager=ED.createFresh(),this.providerRegistry=hD.createFresh(),this.retryTracker=bD.createFresh({maxRetries:this.config.maxRetries,baseDelayMs:this.config.retryBaseDelayMs}),this.scheduler=Ko0({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,logger:this.logger}),Uo0(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 Fo0(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(),Q=[],w={draft:0,queued:0,published:0,failed:0};for(let B of f){let x=await A.entityService.listEntities(B);for(let I of x){let $=I.metadata.status;if($!=="draft"&&$!=="queued"&&$!=="published"&&$!=="failed")continue;w[$]++;let c=I.metadata.title;Q.push({id:I.id,title:typeof c==="string"?c:I.id,type:B,status:$})}}return{summary:w,items:Q}}}),{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[va(this.pluginContext,this.id,this.queueManager),ka(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(){ED.resetInstance(),hD.resetInstance(),bD.resetInstance()}}function UGA(A){return new uGA(A)}B0();HA();var Zo0=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")}),HGA=X.object({cloudflare:Zo0.optional()});B0();HA();var Yl2=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 ul2(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 Wo0(A,f,Q){let w=[];if(!Q)return w;return w.push(Tf(A,"query",`Query website analytics from Cloudflare.
|
|
3019
3019
|
|
|
3020
3020
|
Date range options (use only one):
|
|
3021
3021
|
- No params: yesterday only
|
|
@@ -3153,7 +3153,7 @@ Returns pageviews, visitors, top pages, referrers, devices, and countries.`,Yl2,
|
|
|
3153
3153
|
}
|
|
3154
3154
|
}
|
|
3155
3155
|
}
|
|
3156
|
-
`,variables:Q})});if(!w.ok){let I=await w.text();throw Error(`Cloudflare API error: ${w.status} - ${I}`)}let B=await w.json();if(B.errors&&B.errors.length>0)throw Error(`Cloudflare GraphQL error: ${B.errors.map((I)=>I.message).join(", ")}`);return(B.data.viewer.accounts[0]?.rumPageloadEventsAdaptiveGroups??[]).map((I)=>({country:I.dimensions.countryName,visits:I.sum.visits}))}}HA();var FGA=7,Ul2=10;function Jo0(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let f=cJ(),Q=PP(FGA),w=$U(Q),B=$U(f);try{let[x,I]=await Promise.all([A.getWebsiteStats({startDate:w,endDate:B}),A.getTopPages({startDate:w,endDate:B,limit:Ul2})]);return{days:FGA,startDate:w,endDate:B,pageviews:x.pageviews,visitors:x.visitors,topPages:I}}catch(x){return{error:x instanceof Error?x.message:"Failed to fetch analytics",days:FGA}}}}var vo0={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.
|
|
3156
|
+
`,variables:Q})});if(!w.ok){let I=await w.text();throw Error(`Cloudflare API error: ${w.status} - ${I}`)}let B=await w.json();if(B.errors&&B.errors.length>0)throw Error(`Cloudflare GraphQL error: ${B.errors.map((I)=>I.message).join(", ")}`);return(B.data.viewer.accounts[0]?.rumPageloadEventsAdaptiveGroups??[]).map((I)=>({country:I.dimensions.countryName,visits:I.sum.visits}))}}HA();var FGA=7,Ul2=10;function Jo0(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let f=cJ(),Q=PP(FGA),w=$U(Q),B=$U(f);try{let[x,I]=await Promise.all([A.getWebsiteStats({startDate:w,endDate:B}),A.getTopPages({startDate:w,endDate:B,limit:Ul2})]);return{days:FGA,startDate:w,endDate:B,pageviews:x.pageviews,visitors:x.visitors,topPages:I}}catch(x){return{error:x instanceof Error?x.message:"Failed to fetch analytics",days:FGA}}}}var vo0={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.1",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 ko0 extends mw{cloudflareClient;constructor(A={}){super("analytics",vo0,A,HGA)}async onRegister(A){this.cloudflareClient=this.config.cloudflare?new KGA(this.config.cloudflare):void 0,A.insights.register("traffic-overview",Jo0(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:Go0(f)}),{success:!0}})}async getTools(){return Wo0(this.id,this.getContext(),this.cloudflareClient)}}function Kl2(A={}){return new ko0(A)}var za=Kl2;B0();HA();HA();var TO=["StatsWidget","ListWidget","CustomWidget","PipelineWidget","IdentityWidget","ProfileWidget","SystemWidget"],Fl2=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(TO)});class Na{widgets=new Map;logger;constructor(A){this.logger=A.child("DashboardWidgetRegistry")}register(A){let f=`${A.pluginId}:${A.id}`;this.widgets.set(f,A),this.logger.debug("Dashboard widget registered",{key:f,title:A.title})}unregister(A,f){if(f)this.widgets.delete(`${A}:${f}`);else for(let Q of this.widgets.keys())if(Q.startsWith(`${A}:`))this.widgets.delete(Q)}list(A){return Array.from(this.widgets.values()).filter((f)=>!A||f.section===A).sort((f,Q)=>f.priority-Q.priority)}get size(){return this.widgets.size}}HA();class Ea{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,Q){let w={},B=this.registry.list(),x=await Promise.allSettled(B.map(async($)=>{let c=await $.dataProvider(),{dataProvider:D,...u}=$;return{key:`${$.pluginId}:${$.id}`,widget:u,data:c}}));for(let $=0;$<x.length;$++){let c=x[$],D=B[$];if(!c||!D)continue;if(c.status==="fulfilled")w[c.value.key]={widget:c.value.widget,data:c.value.data};else this.logger.error("Widget data provider failed",{widgetId:D.id,pluginId:D.pluginId,error:v0(c.reason)})}return{widgets:w}}}import{jsxDEV as mO}from"preact/jsx-dev-runtime";var Xl2={StatsWidget:Cr,ListWidget:_r,CustomWidget:Vr,PipelineWidget:Mr,IdentityWidget:Or,ProfileWidget:jr,SystemWidget:Rr};function Zl2(A){let f={primary:[],secondary:[],sidebar:[]};for(let w of Object.values(A)){let B=w.widget.section;f[B].push(w)}let Q=(w,B)=>w.widget.priority-B.widget.priority;for(let w of Object.keys(f))f[w].sort(Q);return f}function XGA(A,f){let{widget:Q,data:w}=A,B=`${Q.pluginId}:${Q.id}`,x=Xl2[Q.rendererName];return mO("div",{className:f?"col-span-1 lg:col-span-2":"",children:mO(x,{title:Q.title,description:Q.description,data:w},void 0,!1,void 0,this)},B,!1,void 0,this)}function Wl2({widgets:A}){let f=Zl2(A);return mO("div",{className:"dashboard w-full max-w-layout mx-auto px-6 py-8 bg-theme","data-component":"dashboard:dashboard",children:mO("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_280px] gap-4",children:[f.primary.map((Q)=>XGA(Q,!0)),f.sidebar.length>0&&mO("aside",{className:"row-span-3 lg:col-start-3 space-y-4",children:f.sidebar.map((Q)=>XGA(Q))},void 0,!1,void 0,this),f.secondary.map((Q)=>XGA(Q,!0))]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var ZGA=(A)=>{return Wl2(A)};HA();var Gl2=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(TO)}),Jl2=X.object({widget:Gl2,data:X.unknown()}),ha=X.object({widgets:X.record(Jl2)});class ba{format(A){return JSON.stringify(A,null,2)}parse(A){return JSON.parse(A)}}tf();var zo0=`var { h, hydrate, useState, useMemo, useEffect, useCallback, useRef, useContext, createContext, jsx, jsxs } = window.preact;
|
|
3157
3157
|
var __require = function(mod) {
|
|
3158
3158
|
if (mod === "crypto") return { randomUUID: () => window.crypto.randomUUID() };
|
|
3159
3159
|
throw new Error("Cannot require " + mod + " in browser");
|
|
@@ -26119,7 +26119,7 @@ Please report this to https://github.com/markedjs/marked.\`;
|
|
|
26119
26119
|
}
|
|
26120
26120
|
})();
|
|
26121
26121
|
})();
|
|
26122
|
-
`;var No0=a0({name:"dashboard",description:"Extensible dashboard with plugin-contributed widgets",schema:ha,requiredPermission:"public",formatter:new ba,dataSourceId:"dashboard:dashboard",layout:{component:ZGA,interactive:zo0}});var Eo0={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.
|
|
26122
|
+
`;var No0=a0({name:"dashboard",description:"Extensible dashboard with plugin-contributed widgets",schema:ha,requiredPermission:"public",formatter:new ba,dataSourceId:"dashboard:dashboard",layout:{component:ZGA,interactive:zo0}});var Eo0={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.1",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 zl2=X.object({version:X.string().default("1.0.0")}),Nl2=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(TO),dataProvider:X.function().returns(X.promise(X.unknown()))}),El2=X.object({pluginId:X.string(),widgetId:X.string().optional()});class WGA extends mw{dependencies=["site-builder"];widgetRegistry=null;datasource=null;constructor(A){super("dashboard",Eo0,A??{},zl2)}async onRegister(A){this.widgetRegistry=new Na(this.logger),this.datasource=new Ea(this.widgetRegistry,this.logger),A.entities.registerDataSource(this.datasource),A.templates.register({dashboard:No0}),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 Q=Nl2.parse(f.payload),w={id:Q.id,pluginId:Q.pluginId,title:Q.title,description:Q.description,priority:Q.priority,section:Q.section,rendererName:Q.rendererName,dataProvider:Q.dataProvider};return this.widgetRegistry?.register(w),this.logger.debug("Widget registered via messaging",{widgetId:Q.id,pluginId:Q.pluginId}),{success:!0}}catch(Q){return this.logger.error("Failed to register widget",{error:v0(Q),payload:f.payload}),{success:!1,error:"Widget registration failed"}}}),A.messaging.subscribe("dashboard:unregister-widget",async(f)=>{let Q=El2.parse(f.payload);return this.widgetRegistry?.unregister(Q.pluginId,Q.widgetId),this.logger.debug("Widget unregistered via messaging",{pluginId:Q.pluginId,widgetId:Q.widgetId}),{success:!0}}),this.logger.info("Dashboard plugin registered")}async getTools(){return[]}getWidgetRegistry(){return this.widgetRegistry}}function SO(A){return new WGA(A)}HA();B0();HA();import{h as il2}from"preact";HA();_I();B0();var RN=X.enum(["draft","queued","published","failed"]),yO=X.object({subject:X.string(),status:RN,entityIds:X.array(X.string()).optional(),scheduledFor:X.string().datetime().optional(),sentAt:X.string().datetime().optional(),buttondownId:X.string().optional(),sourceEntityType:X.string().optional()}),ho0=yO.pick({subject:!0,status:!0,entityIds:!0,scheduledFor:!0,sentAt:!0,buttondownId:!0,sourceEntityType:!0}),lO=X2.extend({entityType:X.literal("newsletter"),metadata:ho0});B0();class bo0 extends q2{constructor(){super({entityType:"newsletter",schema:lO,frontmatterSchema:yO})}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 Lo0=new bo0;B0();B0();HA();var hl2=KU.extend({status:X.enum(["draft","queued","published","failed"]).optional()}),bl2=FU.extend({query:hl2.optional()});function qo0(A){try{let{content:f}=H2(A.content,yO);return f}catch{return A.content}}class GGA extends c6{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=bl2.parse(A);return{entityType:f.entityType??this.config.entityType,query:f.query??{}}}transformEntity(A){let f=qo0(A),Q={id:A.id,subject:A.metadata.subject,status:A.metadata.status,excerpt:IU(f,150),created:A.created,url:`/newsletters/${A.id}`};if(A.metadata.sentAt)Q.sentAt=A.metadata.sentAt;return Q}buildListResult(A,f,Q){return{newsletters:A,totalCount:f?.totalItems??A.length,pagination:f}}async fetch(A,f,Q){let{query:w}=this.parseQuery(A),B=Q.entityService;if(w.id)return this.fetchSingleNewsletter(w.id,f,B);let x=w.status,I=x?{filter:{metadata:{status:x}}}:void 0,{items:$,pagination:c}=await this.fetchList(w,B,I);return f.parse(this.buildListResult($,c,w))}async fetchSingleNewsletter(A,f,Q){let w=await Q.getEntity(this.config.entityType,A);if(!w)throw Error(`Newsletter not found: ${A}`);let B=await this.resolveNavigation(w,Q),x=[];if(w.metadata.entityIds?.length){let c=w.metadata.sourceEntityType??"post";x=(await Promise.all(w.metadata.entityIds.map(async(u)=>{let K=await Q.getEntity(c,u);if(K){let F=K.metadata;return{id:u,title:F.title??u,url:`/${c}s/${F.slug??u}`}}return null}))).filter((u)=>u!==null)}let I=qo0(w),$={id:w.id,subject:w.metadata.subject,status:w.metadata.status,content:I,created:w.created,updated:w.updated,sentAt:w.metadata.sentAt,scheduledFor:w.metadata.scheduledFor,newsletter:w,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($)}}B0();HA();var Ll2=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 JGA extends J9{constructor(A,f){super(A,f,{schema:Ll2,jobTypeName:"newsletter:generation",entityType:"newsletter"})}async generate(A,f){let Q=A.addToQueue??!1,{prompt:w,sourceEntityIds:B,sourceEntityType:x}=A,{content:I,subject:$}=A;if(I){if(!$)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 F=x??"post";await this.reportProgress(f,{progress:10,message:`Fetching ${B.length} source entities`});let J=(await Promise.all(B.map((C)=>this.context.entityService.getEntity(F,C)))).filter((C)=>C!=null);if(J.length===0)this.failEarly(`No source entities found for IDs: ${B.join(", ")}`);await this.reportProgress(f,{progress:30,message:`Generating newsletter from ${J.length} posts`});let k=`Create an engaging newsletter that highlights these blog posts:
|
|
26123
26123
|
|
|
26124
26124
|
${J.map((C)=>`## ${C.metadata.title}
|
|
26125
26125
|
|
|
@@ -26188,16 +26188,16 @@ Newsletter-specific guidelines:
|
|
|
26188
26188
|
- "Reply and let me know..."
|
|
26189
26189
|
- "Until next time..."
|
|
26190
26190
|
|
|
26191
|
-
The goal is to build a relationship with readers through valuable, authentic content.`});HA();B0();import{jsxDEV as j5,Fragment as Ml2}from"preact/jsx-dev-runtime";var Cl2=X.object({id:X.string(),subject:X.string(),status:RN,excerpt:X.string(),created:X.string(),sentAt:X.string().optional(),url:X.string()}),_l2=X.object({newsletters:X.array(Cl2),totalCount:X.number(),pagination:Qx.nullable()}),Vl2=({newsletters:A,totalCount:f,pageTitle:Q,pagination:w,baseUrl:B="/newsletters"})=>{let x=Q??"Newsletters",I=`Browse all ${f} ${f===1?"newsletter":"newsletters"}`;return j5(Ml2,{children:[j5(p2,{title:x,description:I},void 0,!1,void 0,this),j5("div",{className:"newsletter-list bg-theme",children:j5("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[j5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:x},void 0,!1,void 0,this),A.length===0?j5("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):j5("div",{className:"space-y-4",children:A.map(($)=>j5(Gf,{href:$.url,children:[j5(V9,{className:"text-lg",children:$.subject},void 0,!1,void 0,this),j5(q5,{children:j5("div",{className:"flex items-center gap-3",children:[j5(kx,{status:$.status},void 0,!1,void 0,this),j5("span",{className:"text-sm text-theme-muted",children:dw($.sentAt??$.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),$.excerpt&&j5("p",{className:"text-theme-muted line-clamp-2",children:$.excerpt},void 0,!1,void 0,this)]},$.id,!0,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&j5(u$,{currentPage:w.currentPage,totalPages:w.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)},_o0=a0({name:"newsletter-list",description:"Newsletter list page template",schema:_l2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:Vl2}});HA();B0();import{jsxDEV as Uw,Fragment as Pl2}from"preact/jsx-dev-runtime";var Ol2=X.object({id:X.string(),title:X.string(),url:X.string()}),Vo0=X.object({id:X.string(),subject:X.string(),url:X.string()}),jl2=X.object({id:X.string(),subject:X.string(),status:RN,content:X.string(),created:X.string(),updated:X.string(),sentAt:X.string().optional(),scheduledFor:X.string().optional(),sourceEntities:X.array(Ol2).optional(),prevNewsletter:Vo0.nullable().optional(),nextNewsletter:Vo0.nullable().optional()}),Rl2=({subject:A,status:f,content:Q,created:w,sentAt:B,scheduledFor:x,sourceEntities:I,prevNewsletter:$,nextNewsletter:c})=>{let D=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:A}],u=B??w,K=B?"Sent":"Created";return Uw(Pl2,{children:[Uw(p2,{title:A,description:`Newsletter: ${A}`},void 0,!1,void 0,this),Uw("section",{className:"newsletter-detail-section",children:Uw("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:Uw("div",{className:"max-w-3xl mx-auto",children:[Uw(V4,{items:D},void 0,!1,void 0,this),Uw("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),Uw("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[Uw(kx,{status:f},void 0,!1,void 0,this),Uw("span",{children:[K,": ",dw(u,{style:"long"})]},void 0,!0,void 0,this),x&&f==="queued"&&Uw("span",{children:["Scheduled for: ",dw(x,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),I&&I.length>0&&Uw(Gf,{variant:"compact",className:"mb-8",children:[Uw("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),Uw("ul",{className:"space-y-1",children:I.map((F)=>Uw("li",{children:Uw("a",{href:F.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:F.title},void 0,!1,void 0,this)},F.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Uw(Y$,{markdown:Q},void 0,!1,void 0,this),($??c)&&Uw("nav",{className:"mt-12 pt-8 border-t border-theme",children:Uw("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[$?Uw(Gf,{href:$.url,variant:"compact",children:[Uw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),Uw("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):Uw("div",{},void 0,!1,void 0,this),c&&Uw(Gf,{href:c.url,variant:"compact",className:"md:text-right",children:[Uw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),Uw("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:c.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)},Mo0=a0({name:"newsletter-detail",description:"Individual newsletter detail template",schema:jl2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:Rl2}});var Oo0={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.
|
|
26191
|
+
The goal is to build a relationship with readers through valuable, authentic content.`});HA();B0();import{jsxDEV as j5,Fragment as Ml2}from"preact/jsx-dev-runtime";var Cl2=X.object({id:X.string(),subject:X.string(),status:RN,excerpt:X.string(),created:X.string(),sentAt:X.string().optional(),url:X.string()}),_l2=X.object({newsletters:X.array(Cl2),totalCount:X.number(),pagination:Qx.nullable()}),Vl2=({newsletters:A,totalCount:f,pageTitle:Q,pagination:w,baseUrl:B="/newsletters"})=>{let x=Q??"Newsletters",I=`Browse all ${f} ${f===1?"newsletter":"newsletters"}`;return j5(Ml2,{children:[j5(p2,{title:x,description:I},void 0,!1,void 0,this),j5("div",{className:"newsletter-list bg-theme",children:j5("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[j5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:x},void 0,!1,void 0,this),A.length===0?j5("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):j5("div",{className:"space-y-4",children:A.map(($)=>j5(Gf,{href:$.url,children:[j5(V9,{className:"text-lg",children:$.subject},void 0,!1,void 0,this),j5(q5,{children:j5("div",{className:"flex items-center gap-3",children:[j5(kx,{status:$.status},void 0,!1,void 0,this),j5("span",{className:"text-sm text-theme-muted",children:dw($.sentAt??$.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),$.excerpt&&j5("p",{className:"text-theme-muted line-clamp-2",children:$.excerpt},void 0,!1,void 0,this)]},$.id,!0,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&j5(u$,{currentPage:w.currentPage,totalPages:w.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)},_o0=a0({name:"newsletter-list",description:"Newsletter list page template",schema:_l2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:Vl2}});HA();B0();import{jsxDEV as Uw,Fragment as Pl2}from"preact/jsx-dev-runtime";var Ol2=X.object({id:X.string(),title:X.string(),url:X.string()}),Vo0=X.object({id:X.string(),subject:X.string(),url:X.string()}),jl2=X.object({id:X.string(),subject:X.string(),status:RN,content:X.string(),created:X.string(),updated:X.string(),sentAt:X.string().optional(),scheduledFor:X.string().optional(),sourceEntities:X.array(Ol2).optional(),prevNewsletter:Vo0.nullable().optional(),nextNewsletter:Vo0.nullable().optional()}),Rl2=({subject:A,status:f,content:Q,created:w,sentAt:B,scheduledFor:x,sourceEntities:I,prevNewsletter:$,nextNewsletter:c})=>{let D=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:A}],u=B??w,K=B?"Sent":"Created";return Uw(Pl2,{children:[Uw(p2,{title:A,description:`Newsletter: ${A}`},void 0,!1,void 0,this),Uw("section",{className:"newsletter-detail-section",children:Uw("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:Uw("div",{className:"max-w-3xl mx-auto",children:[Uw(V4,{items:D},void 0,!1,void 0,this),Uw("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),Uw("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[Uw(kx,{status:f},void 0,!1,void 0,this),Uw("span",{children:[K,": ",dw(u,{style:"long"})]},void 0,!0,void 0,this),x&&f==="queued"&&Uw("span",{children:["Scheduled for: ",dw(x,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),I&&I.length>0&&Uw(Gf,{variant:"compact",className:"mb-8",children:[Uw("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),Uw("ul",{className:"space-y-1",children:I.map((F)=>Uw("li",{children:Uw("a",{href:F.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:F.title},void 0,!1,void 0,this)},F.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Uw(Y$,{markdown:Q},void 0,!1,void 0,this),($??c)&&Uw("nav",{className:"mt-12 pt-8 border-t border-theme",children:Uw("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[$?Uw(Gf,{href:$.url,variant:"compact",children:[Uw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),Uw("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):Uw("div",{},void 0,!1,void 0,this),c&&Uw(Gf,{href:c.url,variant:"compact",className:"md:text-right",children:[Uw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),Uw("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:c.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)},Mo0=a0({name:"newsletter-detail",description:"Individual newsletter detail template",schema:jl2,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:Rl2}});var Oo0={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.1",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 Tl2=X.object({});class vGA extends zf{entityType="newsletter";schema=lO;adapter=Lo0;constructor(A={}){super("newsletter",Oo0,A,Tl2)}createGenerationHandler(A){return new JGA(this.logger,A)}getTemplates(){return{generation:Co0,"newsletter-list":_o0,"newsletter-detail":Mo0}}getDataSources(){return[new GGA(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:()=>il2(oKA,{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:Q,entityId:w}=f.payload;if(Q!=="newsletter")return{success:!0};try{let B=await A.entityService.getEntity("newsletter",w);if(!B)return await A.messaging.send("publish:report:failure",{entityType:Q,entityId:w,error:`Newsletter not found: ${w}`}),{success:!0};if(B.metadata.status==="published")return{success:!0};let x=await A.messaging.send("buttondown:send",{entityId:w,subject:B.metadata.subject,content:B.content}),I=new Date().toISOString(),$=!("noop"in x)&&x.data?x.data.emailId:void 0;return await A.entityService.updateEntity({...B,metadata:{...B.metadata,status:"published",sentAt:I,buttondownId:$}}),await A.messaging.send("publish:report:success",{entityType:Q,entityId:w,sentAt:I}),this.logger.info(`Published newsletter: ${w}`),{success:!0}}catch(B){let x=v0(B);return await A.messaging.send("publish:report:failure",{entityType:Q,entityId:w,error:x}),{success:!0}}})}subscribeToGenerateExecute(A){A.messaging.subscribe("generate:execute",async(f)=>{if(f.payload.entityType!=="newsletter")return{success:!0};try{let Q=await A.entityService.listEntities("post",{filter:{metadata:{status:"published"}},limit:10});if(Q.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:Q.map((w)=>w.id),sourceEntityType:"post",addToQueue:!1},{interfaceType:"job",userId:"system"}),{success:!0}}catch(Q){return await A.messaging.send("generate:report:failure",{entityType:"newsletter",error:v0(Q)}),{success:!0}}})}registerEvalHandlers(A){let f=X.object({prompt:X.string().optional(),content:X.string().optional()});A.eval.registerHandler("generation",async(Q)=>{let w=f.parse(Q),B=w.content?`Create an engaging newsletter based on this content:
|
|
26192
26192
|
|
|
26193
|
-
${w.content}`:w.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:B,templateName:"newsletter:generation"})})}}function kGA(A={}){return new vGA(A)}B0();HA();class PN{config;logger;constructor(A,f){this.config=A;this.logger=f}async request(A,f={}){let Q=`https://api.buttondown.email/v1${A}`;this.logger.debug("Buttondown API request",{endpoint:A,method:f.method??"GET"});let w=await fetch(Q,{...f,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...f.headers}});if(!w.ok){let B=await w.json().catch(()=>({})),x=B.detail??B.message??`HTTP ${w.status}`;throw this.logger.error("Buttondown API error",{endpoint:A,status:w.status,error:x}),Error(`Buttondown API error: ${x}`)}return w.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(Q){if(Q instanceof Error&&Q.message.includes("already subscribed")){let w=Q.message.match(/id=([a-f0-9-]+)/);return this.logger.info("Subscriber already exists",{email:A.email}),{id:w?.[1]??"existing",email:A.email,subscriber_type:"already_subscribed"}}throw Q}}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 Q=f.toString(),w=Q?`/subscribers?${Q}`:"/subscribers";return this.request(w)}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();HA();var ml2=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)")}),Sl2=X.object({email:X.string().email().describe("Email address to unsubscribe")}),yl2=X.object({type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:X.number().optional().describe("Maximum number of results")});function jo0(A,f,Q){let w=new PN(f,Q);return[Tf(A,"subscribe","Subscribe an email address to the newsletter. Uses double opt-in by default.",ml2,async(B)=>{try{let x=await w.createSubscriber({email:B.email,...B.name&&{name:B.name},...B.tags&&{tags:B.tags}}),I=x.subscriber_type==="already_subscribed";return R8({subscriberId:x.id,email:x.email,status:x.subscriber_type,message:I?"already_subscribed":"subscribed"},I?`${B.email} is already subscribed`:`Subscribed ${B.email} successfully`)}catch(x){return T6(v0(x))}}),Tf(A,"unsubscribe","Unsubscribe an email address from the newsletter.",Sl2,async(B)=>{try{return await w.unsubscribe(B.email),R8({email:B.email},`Unsubscribed ${B.email} successfully`)}catch(x){return T6(v0(x))}}),Tf(A,"list_subscribers","List newsletter subscribers with optional filtering by status.",yl2,async(B)=>{try{let x=await w.listSubscribers({...B.type&&{type:B.type},...B.limit&&{limit:B.limit}});return R8({subscribers:x.results.map((I)=>({id:I.id,email:I.email,status:I.subscriber_type})),count:x.count},`Found ${x.count} subscribers`)}catch(x){return T6(v0(x))}})]}HA();async function Ro0(A,f,Q,w){if(A.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let B=await Q.getEntity("post",A.entityId);if(!B)return{success:!1,error:`Post ${A.entityId} not found`};w.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 w.info("Newsletter sent for post",{postId:B.id,emailId:x.id}),{success:!0,emailId:x.id}}catch(x){let I=v0(x);return w.error("Failed to send newsletter for post",{postId:B.id,error:I}),{success:!1,error:I}}}var Po0={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.
|
|
26193
|
+
${w.content}`:w.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:B,templateName:"newsletter:generation"})})}}function kGA(A={}){return new vGA(A)}B0();HA();class PN{config;logger;constructor(A,f){this.config=A;this.logger=f}async request(A,f={}){let Q=`https://api.buttondown.email/v1${A}`;this.logger.debug("Buttondown API request",{endpoint:A,method:f.method??"GET"});let w=await fetch(Q,{...f,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...f.headers}});if(!w.ok){let B=await w.json().catch(()=>({})),x=B.detail??B.message??`HTTP ${w.status}`;throw this.logger.error("Buttondown API error",{endpoint:A,status:w.status,error:x}),Error(`Buttondown API error: ${x}`)}return w.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(Q){if(Q instanceof Error&&Q.message.includes("already subscribed")){let w=Q.message.match(/id=([a-f0-9-]+)/);return this.logger.info("Subscriber already exists",{email:A.email}),{id:w?.[1]??"existing",email:A.email,subscriber_type:"already_subscribed"}}throw Q}}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 Q=f.toString(),w=Q?`/subscribers?${Q}`:"/subscribers";return this.request(w)}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();HA();var ml2=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)")}),Sl2=X.object({email:X.string().email().describe("Email address to unsubscribe")}),yl2=X.object({type:X.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:X.number().optional().describe("Maximum number of results")});function jo0(A,f,Q){let w=new PN(f,Q);return[Tf(A,"subscribe","Subscribe an email address to the newsletter. Uses double opt-in by default.",ml2,async(B)=>{try{let x=await w.createSubscriber({email:B.email,...B.name&&{name:B.name},...B.tags&&{tags:B.tags}}),I=x.subscriber_type==="already_subscribed";return R8({subscriberId:x.id,email:x.email,status:x.subscriber_type,message:I?"already_subscribed":"subscribed"},I?`${B.email} is already subscribed`:`Subscribed ${B.email} successfully`)}catch(x){return T6(v0(x))}}),Tf(A,"unsubscribe","Unsubscribe an email address from the newsletter.",Sl2,async(B)=>{try{return await w.unsubscribe(B.email),R8({email:B.email},`Unsubscribed ${B.email} successfully`)}catch(x){return T6(v0(x))}}),Tf(A,"list_subscribers","List newsletter subscribers with optional filtering by status.",yl2,async(B)=>{try{let x=await w.listSubscribers({...B.type&&{type:B.type},...B.limit&&{limit:B.limit}});return R8({subscribers:x.results.map((I)=>({id:I.id,email:I.email,status:I.subscriber_type})),count:x.count},`Found ${x.count} subscribers`)}catch(x){return T6(v0(x))}})]}HA();async function Ro0(A,f,Q,w){if(A.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let B=await Q.getEntity("post",A.entityId);if(!B)return{success:!1,error:`Post ${A.entityId} not found`};w.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 w.info("Newsletter sent for post",{postId:B.id,emailId:x.id}),{success:!0,emailId:x.id}}catch(x){let I=v0(x);return w.error("Failed to send newsletter for post",{postId:B.id,error:I}),{success:!1,error:I}}}var Po0={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.1",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 nl2=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 zGA extends mw{constructor(A={}){super("buttondown",Po0,A,nl2)}async onRegister(A){if(A.messaging.subscribe("buttondown:is-configured",async()=>{return{success:!!this.config.apiKey}}),this.config.apiKey){let f=new PN({apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger);if(A.messaging.subscribe("buttondown:send",async(Q)=>{try{return{success:!0,data:{emailId:(await f.createEmail({subject:Q.payload.subject,body:Q.payload.content,status:"about_to_send"})).id}}}catch(w){return this.logger.error("Buttondown send failed",{error:v0(w)}),{success:!1}}}),this.config.autoSendOnPublish)A.messaging.subscribe("publish:completed",async(Q)=>{return await Ro0(Q.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 jo0(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 NGA(A={}){return new zGA(A)}var pl2=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 go0(A={}){let f=pl2.parse(A);return[kGA({}),NGA({...f.apiKey!==void 0&&{apiKey:f.apiKey},...f.doubleOptIn!==void 0&&{doubleOptIn:f.doubleOptIn},...f.autoSendOnPublish!==void 0&&{autoSendOnPublish:f.autoSendOnPublish}})]}B0();HA();import{existsSync as Bn2,mkdirSync as xn2,writeFileSync as In2}from"fs";import{join as dY}from"path";HA();var EGA=X.object({baseFolder:X.string().default("_obsidian")});HA();function rl2(A){let f=A,Q=!0,w=void 0,B=!1,x=!0;while(x){if(x=!1,f instanceof X.ZodOptional)Q=!1,f=f._def.innerType,x=!0;if(f instanceof X.ZodDefault)Q=!1,B=!0,w=f._def.defaultValue(),f=f._def.innerType,x=!0;if(f instanceof X.ZodNullable)Q=!1,f=f._def.innerType,x=!0}let I={inner:f,required:Q};if(B)I.defaultValue=w;return I}function dl2(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 io0(A){let f=A.shape,Q=[];for(let[w,B]of Object.entries(f)){let{inner:x,required:I,defaultValue:$}=rl2(B),c=dl2(x),D={name:w,type:c.type,required:I},u=$!==void 0?$:c.defaultValue;if(u!==void 0)D.defaultValue=u;if(c.enumValues)D.enumValues=c.enumValues;Q.push(D)}return Q}function ol2(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 To0(A,f,Q=""){let w=["---"];for(let B of f){let x=ol2(B,A);if(x==="")w.push(`${B.name}:`);else w.push(`${B.name}: ${x}`)}if(w.push("---"),w.push(""),Q)w.push(Q);else w.push("<!-- Write your content here -->"),w.push("");return w.join(`
|
|
26194
26194
|
`)}HA();var al2={string:"Input",number:"Number",boolean:"Boolean",date:"Date",enum:"Select",array:"Multi",unknown:"Input"};function sl2(A){let f={name:A.name,id:A.name,type:al2[A.type]};if(A.type==="enum"&&A.enumValues){let Q={};A.enumValues.forEach((w,B)=>{Q[String(B)]=w}),f.options=Q}return f}function mo0(A,f){let Q={filesPaths:A,fields:f.map(sl2)};return`---
|
|
26195
26195
|
${uc(Q)}---
|
|
26196
|
-
`}HA();var tl2=new Set(["entityType"]),el2={base:"Notes"},An2=new Set(["base"]);function fn2(A){let f=["file.name"];for(let Q of A)if(!tl2.has(Q.name))f.push(Q.name);return f}function Qn2(A){return A.some((f)=>f.name==="status"&&f.type==="enum")}function So0(A,f){let Q=el2[A]??jP(A),w=Qn2(f),B=fn2(f),x=[{type:"table",name:`All ${Q}`,order:B}];if(w)x.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:B});let $={filters:{and:[An2.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:x};return{filename:`${Q}.base`,content:uc($),hasStatus:w}}function yo0(A){if(A.length===0)return null;let f=A.map((w)=>`file.inFolder("${w}")`),Q={filters:{and:[f.length===1?f[0]:{or:f}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return uc(Q)}function lo0(A){if(A.length===0)return null;let f=A.map((w)=>`file.inFolder("${w.entityType}")`),Q={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 uc(Q)}var no0={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.0",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 $n2={mkdir:xn2,writeFile:In2,existsFile:Bn2},cn2=X.object({entityTypes:X.array(X.string()).optional().describe("Entity types to generate templates for (default: all)")});class hGA extends mw{deps;constructor(A={},f={}){super("obsidian-vault",no0,A,EGA);this.deps={...$n2,...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.",cn2,async(f)=>{return this.sync(A,f.entityTypes)})]}async sync(A,f){try{let Q=A.entityService.getEntityTypes(),w=f?Q.filter((k)=>f.includes(k)):Q,B=dY(A.dataDir,this.config.baseFolder),x=dY(B,"templates"),I=dY(B,"fileClasses"),$=dY(B,"bases");this.deps.mkdir(x,{recursive:!0}),this.deps.mkdir(I,{recursive:!0}),this.deps.mkdir($,{recursive:!0});let c=[],D=[],u=[],K=[],F=[],Z=[];for(let k of w){let q=A.entities.getEffectiveFrontmatterSchema(k);if(!q){this.logger.debug(`Skipping ${k}: no frontmatter schema`),D.push(k);continue}let V=io0(q),C=A.entities.getAdapter(k),l=C?.isSingleton===!0,r=mo0(k,V);if(this.deps.writeFile(dY(I,`${k}.md`),r),u.push(k),l){F.push(k),this.logger.debug(`Generated fileClass (singleton): ${k}`);continue}let P=C?.getBodyTemplate()??"",O=To0(k,V,P);this.deps.writeFile(dY(x,`${k}.md`),O),c.push(k);let R=So0(k,V),g=dY($,R.filename);if(!this.deps.existsFile(g))this.deps.writeFile(g,R.content),K.push(k),this.logger.debug(`Generated base: ${R.filename}`);if(R.hasStatus)Z.push({entityType:k,fields:V});this.logger.debug(`Generated template + fileClass: ${k}`)}let J=yo0(F);if(J){let k=dY($,"Settings.base");if(!this.deps.existsFile(k))this.deps.writeFile(k,J),K.push("Settings"),this.logger.debug("Generated Settings.base")}let v=lo0(Z);if(v){let k=dY($,"Pipeline.base");if(!this.deps.existsFile(k))this.deps.writeFile(k,v),K.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${c.length} templates, ${u.length} fileClasses, ${K.length} bases (${D.length} skipped)`),R8({generated:c,skipped:D,fileClasses:u,bases:K})}catch(Q){return this.logger.error("Failed to sync",{error:Q}),T6(Q instanceof Error?Q.message:"Unknown error")}}}function bGA(A,f){return new hGA(A,f)}B0();HA();B0();var LGA=X.enum(["new","planned","in-progress","done","declined"]),qGA=X.enum(["low","medium","high","critical"]),nO=X.object({title:X.string(),status:LGA,priority:qGA.default("medium"),requested:X.number().int().default(1),tags:X.array(X.string()).default([]),declinedReason:X.string().optional()}),po0=X.object({title:X.string(),status:LGA,priority:qGA,requested:X.number().int(),slug:X.string()}),pO=X2.extend({entityType:X.literal("wish"),metadata:po0}),CGA=X.object({});B0();HA();class rO extends q2{constructor(){super({entityType:"wish",schema:pO,frontmatterSchema:nO})}createWishContent(A,f){return this.buildMarkdown(f,A)}parseWishContent(A){let f=this.parseFrontMatter(A,nO);return{frontmatter:nO.parse(f),description:this.extractBody(A).trim()}}toMarkdown(A){return A.content}fromMarkdown(A){let{frontmatter:f}=this.parseWishContent(A),Q=w2(f.title);return{content:A,entityType:"wish",metadata:{title:f.title,status:f.status,priority:f.priority,requested:f.requested,slug:Q}}}}var _GA=new rO;HA();HA();async function ro0(A,f){let Q=`${f.title}: ${f.description}`,B=(await A.search(Q,{types:["wish"],limit:1}))[0];if(B&&B.score>=A.similarityThreshold)return B.entity;let x=w2(f.title);return A.getEntity("wish",x)}class VGA{logger;context;adapter=new rO;constructor(A,f){this.logger=A;this.context=f}async process(A,f,Q){let w=A.title??A.prompt??"Untitled wish",B=A.content??A.prompt??"",x=await ro0({search:(D,u)=>this.context.entityService.search(D,u),getEntity:(D,u)=>this.context.entityService.getEntity(D,u),similarityThreshold:0.85},{title:w,description:B});if(x){let{frontmatter:D,description:u}=this.adapter.parseWishContent(x.content),K=D.requested+1,F=this.adapter.createWishContent({...D,requested:K},u);return await this.context.entityService.updateEntity({...x,content:F,metadata:{...x.metadata,requested:K}}),this.logger.info("Incremented wish request count",{id:x.id,requested:K}),{success:!0,entityId:x.id,existed:!0,requested:K}}let I=w2(w),$=A.options?.priority??"medium",c=this.adapter.createWishContent({title:w,status:"new",priority:$,requested:1,tags:A.options?.tags??[]},B);return await this.context.entityService.createEntity({id:I,entityType:"wish",content:c,metadata:{title:w,status:"new",priority:$,requested:1,slug:I}}),this.logger.info("Created new wish",{id:I,title:w}),{success:!0,entityId:I,existed:!1,requested:1}}}var do0={critical:0,high:1,medium:2,low:3};function oo0(A){A.sort((f,Q)=>{let w=Q.metadata.requested-f.metadata.requested;if(w!==0)return w;return do0[f.metadata.priority]-do0[Q.metadata.priority]})}var ao0={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.0",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 so0 extends zf{entityType=_GA.entityType;schema=pO;adapter=_GA;constructor(A={}){super("wishlist",ao0,A,CGA)}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 Q=await A.entityService.listEntities("wish",{limit:10});return oo0(Q),{items:Q.map((w)=>({id:w.id,name:w.metadata.title,count:w.metadata.requested,priority:w.metadata.priority,status:w.metadata.status}))}}}),{success:!0}});let f=new VGA(this.logger,A);A.jobs.registerHandler("wish:create",{process:f.process.bind(f),validateAndParse:(Q)=>Q})}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 Yn2(A={}){return new so0(A)}var La=Yn2;B0();HA();B0();var dO=X.object({title:X.string(),target:X.string()}),to0=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),oO=X2.extend({entityType:X.literal("prompt"),metadata:to0});B0();HA();class MGA extends q2{constructor(){super({entityType:"prompt",schema:oO,frontmatterSchema:dO})}toMarkdown(A){let f=this.extractBody(A.content),Q=this.parseFrontMatter(A.content,dO);return this.buildMarkdown(f,Q)}fromMarkdown(A){let f=this.parseFrontMatter(A,dO),Q=w2(f.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:f.title,target:f.target,slug:Q}}}}var qa=new MGA;var eo0={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.0",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 OGA extends zf{entityType=qa.entityType;schema=oO;adapter=qa;constructor(){super("prompt",eo0,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function ZW(){return new OGA}B0();HA();class Ca{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(A,f){this.apiKey=A,this.fetchFn=f}async searchPhotos(A,f){let Q=new URL(`${this.baseUrl}/search/photos`);Q.searchParams.set("query",A),Q.searchParams.set("page",String(f.page)),Q.searchParams.set("per_page",String(f.perPage));let w=await this.fetchFn(Q.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!w.ok)throw Error(`Unsplash API error: ${w.status} ${w.statusText}`);let B=await w.json();return{photos:B.results.map(Un2),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 Un2(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}}HA();var Aa0={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")},fa0={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 wa0(A,f){return[Hn2(A,f),Kn2(A,f)]}function Hn2(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:Aa0,handler:async(Q)=>{let w=X.object(Aa0).safeParse(Q);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};try{return{success:!0,data:await f.provider.searchPhotos(w.data.query,{page:w.data.page,perPage:w.data.perPage})}}catch(B){return{success:!1,error:B instanceof Error?B.message:"Search failed"}}}}}function Kn2(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:fa0,handler:async(Q)=>{let w=X.object(fa0).safeParse(Q);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};let{photoId:B,downloadLocation:x,photographerName:I,photographerUrl:$,sourceUrl:c,imageUrl:D,title:u,alt:K,targetEntityType:F,targetEntityId:Z}=w.data,J={photographerName:I,photographerUrl:$,sourceUrl:c},v=await f.entityService.listEntities("image",{limit:1,filter:{metadata:{sourceUrl:D}}});if(v[0]){let P={imageEntityId:v[0].id,alreadyExisted:!0,attribution:J};if(F&&Z)await Qa0(f.entityService,F,Z,v[0].id),P.coverSet=!0;return{success:!0,data:P}}f.provider.triggerDownload(x).catch(()=>{});let k;try{k=await f.fetchImage(D)}catch(P){return{success:!1,error:P instanceof Error?P.message:"Image download failed"}}let q=u??`Stock photo ${B}`,V=gU.createImageEntity({dataUrl:k,title:q,alt:K??q}),C={id:B,...V,metadata:{...V.metadata,sourceUrl:D}},{entityId:l}=await f.entityService.createEntity(C),r={imageEntityId:l,alreadyExisted:!1,attribution:J};if(F&&Z)await Qa0(f.entityService,F,Z,l),r.coverSet=!0;return{success:!0,data:r}}}}async function Qa0(A,f,Q,w){let B=await A.getEntity(f,Q);if(!B)return;await A.updateEntity({...B,metadata:{...B.metadata,coverImageId:w}})}HA();var Ba0={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.0",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 Xn2=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class jGA extends mw{deps;cachedTools=null;constructor(A={},f={}){super("stock-photo",Ba0,A,Xn2);this.deps=f}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),f=new Ca(this.config.apiKey,this.deps.fetch??globalThis.fetch);return this.cachedTools=wa0(this.id,{provider:f,entityService:A.entityService,fetchImage:this.deps.fetchImage??t5}),this.cachedTools}}function RGA(A={},f={}){return new jGA(A,f)}HA();B0();HA();B0();var xa0=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),xK=OI.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")}),Ia0=xK.pick({name:!0,url:!0,status:!0}).extend({slug:X.string()}),gN=X2.extend({entityType:X.literal("agent"),metadata:Ia0}),aO=gN.extend({frontmatter:xK,about:X.string(),skills:X.array(xa0),notes:X.string()}),iN=aO.extend({url:X.string().optional(),typeLabel:X.string().optional()}),Zn2=aO.extend({url:X.string(),typeLabel:X.string()});B0();HA();var Wn2=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 Gn2(A){if(!Array.isArray(A)||A.length===0)return"";return A.map((Q)=>{let w=Q.tags.length>0?` [${Q.tags.join(", ")}]`:"";return`- ${Q.name}: ${Q.description}${w}`}).join(`
|
|
26196
|
+
`}HA();var tl2=new Set(["entityType"]),el2={base:"Notes"},An2=new Set(["base"]);function fn2(A){let f=["file.name"];for(let Q of A)if(!tl2.has(Q.name))f.push(Q.name);return f}function Qn2(A){return A.some((f)=>f.name==="status"&&f.type==="enum")}function So0(A,f){let Q=el2[A]??jP(A),w=Qn2(f),B=fn2(f),x=[{type:"table",name:`All ${Q}`,order:B}];if(w)x.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:B});let $={filters:{and:[An2.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:x};return{filename:`${Q}.base`,content:uc($),hasStatus:w}}function yo0(A){if(A.length===0)return null;let f=A.map((w)=>`file.inFolder("${w}")`),Q={filters:{and:[f.length===1?f[0]:{or:f}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return uc(Q)}function lo0(A){if(A.length===0)return null;let f=A.map((w)=>`file.inFolder("${w.entityType}")`),Q={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 uc(Q)}var no0={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.1",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 $n2={mkdir:xn2,writeFile:In2,existsFile:Bn2},cn2=X.object({entityTypes:X.array(X.string()).optional().describe("Entity types to generate templates for (default: all)")});class hGA extends mw{deps;constructor(A={},f={}){super("obsidian-vault",no0,A,EGA);this.deps={...$n2,...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.",cn2,async(f)=>{return this.sync(A,f.entityTypes)})]}async sync(A,f){try{let Q=A.entityService.getEntityTypes(),w=f?Q.filter((k)=>f.includes(k)):Q,B=dY(A.dataDir,this.config.baseFolder),x=dY(B,"templates"),I=dY(B,"fileClasses"),$=dY(B,"bases");this.deps.mkdir(x,{recursive:!0}),this.deps.mkdir(I,{recursive:!0}),this.deps.mkdir($,{recursive:!0});let c=[],D=[],u=[],K=[],F=[],Z=[];for(let k of w){let q=A.entities.getEffectiveFrontmatterSchema(k);if(!q){this.logger.debug(`Skipping ${k}: no frontmatter schema`),D.push(k);continue}let V=io0(q),C=A.entities.getAdapter(k),l=C?.isSingleton===!0,r=mo0(k,V);if(this.deps.writeFile(dY(I,`${k}.md`),r),u.push(k),l){F.push(k),this.logger.debug(`Generated fileClass (singleton): ${k}`);continue}let P=C?.getBodyTemplate()??"",O=To0(k,V,P);this.deps.writeFile(dY(x,`${k}.md`),O),c.push(k);let R=So0(k,V),g=dY($,R.filename);if(!this.deps.existsFile(g))this.deps.writeFile(g,R.content),K.push(k),this.logger.debug(`Generated base: ${R.filename}`);if(R.hasStatus)Z.push({entityType:k,fields:V});this.logger.debug(`Generated template + fileClass: ${k}`)}let J=yo0(F);if(J){let k=dY($,"Settings.base");if(!this.deps.existsFile(k))this.deps.writeFile(k,J),K.push("Settings"),this.logger.debug("Generated Settings.base")}let v=lo0(Z);if(v){let k=dY($,"Pipeline.base");if(!this.deps.existsFile(k))this.deps.writeFile(k,v),K.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${c.length} templates, ${u.length} fileClasses, ${K.length} bases (${D.length} skipped)`),R8({generated:c,skipped:D,fileClasses:u,bases:K})}catch(Q){return this.logger.error("Failed to sync",{error:Q}),T6(Q instanceof Error?Q.message:"Unknown error")}}}function bGA(A,f){return new hGA(A,f)}B0();HA();B0();var LGA=X.enum(["new","planned","in-progress","done","declined"]),qGA=X.enum(["low","medium","high","critical"]),nO=X.object({title:X.string(),status:LGA,priority:qGA.default("medium"),requested:X.number().int().default(1),tags:X.array(X.string()).default([]),declinedReason:X.string().optional()}),po0=X.object({title:X.string(),status:LGA,priority:qGA,requested:X.number().int(),slug:X.string()}),pO=X2.extend({entityType:X.literal("wish"),metadata:po0}),CGA=X.object({});B0();HA();class rO extends q2{constructor(){super({entityType:"wish",schema:pO,frontmatterSchema:nO})}createWishContent(A,f){return this.buildMarkdown(f,A)}parseWishContent(A){let f=this.parseFrontMatter(A,nO);return{frontmatter:nO.parse(f),description:this.extractBody(A).trim()}}toMarkdown(A){return A.content}fromMarkdown(A){let{frontmatter:f}=this.parseWishContent(A),Q=w2(f.title);return{content:A,entityType:"wish",metadata:{title:f.title,status:f.status,priority:f.priority,requested:f.requested,slug:Q}}}}var _GA=new rO;HA();HA();async function ro0(A,f){let Q=`${f.title}: ${f.description}`,B=(await A.search(Q,{types:["wish"],limit:1}))[0];if(B&&B.score>=A.similarityThreshold)return B.entity;let x=w2(f.title);return A.getEntity("wish",x)}class VGA{logger;context;adapter=new rO;constructor(A,f){this.logger=A;this.context=f}async process(A,f,Q){let w=A.title??A.prompt??"Untitled wish",B=A.content??A.prompt??"",x=await ro0({search:(D,u)=>this.context.entityService.search(D,u),getEntity:(D,u)=>this.context.entityService.getEntity(D,u),similarityThreshold:0.85},{title:w,description:B});if(x){let{frontmatter:D,description:u}=this.adapter.parseWishContent(x.content),K=D.requested+1,F=this.adapter.createWishContent({...D,requested:K},u);return await this.context.entityService.updateEntity({...x,content:F,metadata:{...x.metadata,requested:K}}),this.logger.info("Incremented wish request count",{id:x.id,requested:K}),{success:!0,entityId:x.id,existed:!0,requested:K}}let I=w2(w),$=A.options?.priority??"medium",c=this.adapter.createWishContent({title:w,status:"new",priority:$,requested:1,tags:A.options?.tags??[]},B);return await this.context.entityService.createEntity({id:I,entityType:"wish",content:c,metadata:{title:w,status:"new",priority:$,requested:1,slug:I}}),this.logger.info("Created new wish",{id:I,title:w}),{success:!0,entityId:I,existed:!1,requested:1}}}var do0={critical:0,high:1,medium:2,low:3};function oo0(A){A.sort((f,Q)=>{let w=Q.metadata.requested-f.metadata.requested;if(w!==0)return w;return do0[f.metadata.priority]-do0[Q.metadata.priority]})}var ao0={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.1",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 so0 extends zf{entityType=_GA.entityType;schema=pO;adapter=_GA;constructor(A={}){super("wishlist",ao0,A,CGA)}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 Q=await A.entityService.listEntities("wish",{limit:10});return oo0(Q),{items:Q.map((w)=>({id:w.id,name:w.metadata.title,count:w.metadata.requested,priority:w.metadata.priority,status:w.metadata.status}))}}}),{success:!0}});let f=new VGA(this.logger,A);A.jobs.registerHandler("wish:create",{process:f.process.bind(f),validateAndParse:(Q)=>Q})}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 Yn2(A={}){return new so0(A)}var La=Yn2;B0();HA();B0();var dO=X.object({title:X.string(),target:X.string()}),to0=X.object({title:X.string(),target:X.string(),slug:X.string().optional()}),oO=X2.extend({entityType:X.literal("prompt"),metadata:to0});B0();HA();class MGA extends q2{constructor(){super({entityType:"prompt",schema:oO,frontmatterSchema:dO})}toMarkdown(A){let f=this.extractBody(A.content),Q=this.parseFrontMatter(A.content,dO);return this.buildMarkdown(f,Q)}fromMarkdown(A){let f=this.parseFrontMatter(A,dO),Q=w2(f.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:f.title,target:f.target,slug:Q}}}}var qa=new MGA;var eo0={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.1",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 OGA extends zf{entityType=qa.entityType;schema=oO;adapter=qa;constructor(){super("prompt",eo0,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function ZW(){return new OGA}B0();HA();class Ca{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(A,f){this.apiKey=A,this.fetchFn=f}async searchPhotos(A,f){let Q=new URL(`${this.baseUrl}/search/photos`);Q.searchParams.set("query",A),Q.searchParams.set("page",String(f.page)),Q.searchParams.set("per_page",String(f.perPage));let w=await this.fetchFn(Q.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!w.ok)throw Error(`Unsplash API error: ${w.status} ${w.statusText}`);let B=await w.json();return{photos:B.results.map(Un2),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 Un2(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}}HA();var Aa0={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")},fa0={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 wa0(A,f){return[Hn2(A,f),Kn2(A,f)]}function Hn2(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:Aa0,handler:async(Q)=>{let w=X.object(Aa0).safeParse(Q);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};try{return{success:!0,data:await f.provider.searchPhotos(w.data.query,{page:w.data.page,perPage:w.data.perPage})}}catch(B){return{success:!1,error:B instanceof Error?B.message:"Search failed"}}}}}function Kn2(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:fa0,handler:async(Q)=>{let w=X.object(fa0).safeParse(Q);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};let{photoId:B,downloadLocation:x,photographerName:I,photographerUrl:$,sourceUrl:c,imageUrl:D,title:u,alt:K,targetEntityType:F,targetEntityId:Z}=w.data,J={photographerName:I,photographerUrl:$,sourceUrl:c},v=await f.entityService.listEntities("image",{limit:1,filter:{metadata:{sourceUrl:D}}});if(v[0]){let P={imageEntityId:v[0].id,alreadyExisted:!0,attribution:J};if(F&&Z)await Qa0(f.entityService,F,Z,v[0].id),P.coverSet=!0;return{success:!0,data:P}}f.provider.triggerDownload(x).catch(()=>{});let k;try{k=await f.fetchImage(D)}catch(P){return{success:!1,error:P instanceof Error?P.message:"Image download failed"}}let q=u??`Stock photo ${B}`,V=gU.createImageEntity({dataUrl:k,title:q,alt:K??q}),C={id:B,...V,metadata:{...V.metadata,sourceUrl:D}},{entityId:l}=await f.entityService.createEntity(C),r={imageEntityId:l,alreadyExisted:!1,attribution:J};if(F&&Z)await Qa0(f.entityService,F,Z,l),r.coverSet=!0;return{success:!0,data:r}}}}async function Qa0(A,f,Q,w){let B=await A.getEntity(f,Q);if(!B)return;await A.updateEntity({...B,metadata:{...B.metadata,coverImageId:w}})}HA();var Ba0={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.1",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 Xn2=X.object({provider:X.enum(["unsplash"]).default("unsplash"),apiKey:X.string().optional().describe("Stock photo provider API key")});class jGA extends mw{deps;cachedTools=null;constructor(A={},f={}){super("stock-photo",Ba0,A,Xn2);this.deps=f}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),f=new Ca(this.config.apiKey,this.deps.fetch??globalThis.fetch);return this.cachedTools=wa0(this.id,{provider:f,entityService:A.entityService,fetchImage:this.deps.fetchImage??t5}),this.cachedTools}}function RGA(A={},f={}){return new jGA(A,f)}HA();B0();HA();B0();var xa0=X.object({name:X.string(),description:X.string(),tags:X.array(X.string())}),xK=OI.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")}),Ia0=xK.pick({name:!0,url:!0,status:!0}).extend({slug:X.string()}),gN=X2.extend({entityType:X.literal("agent"),metadata:Ia0}),aO=gN.extend({frontmatter:xK,about:X.string(),skills:X.array(xa0),notes:X.string()}),iN=aO.extend({url:X.string().optional(),typeLabel:X.string().optional()}),Zn2=aO.extend({url:X.string(),typeLabel:X.string()});B0();HA();var Wn2=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 Gn2(A){if(!Array.isArray(A)||A.length===0)return"";return A.map((Q)=>{let w=Q.tags.length>0?` [${Q.tags.join(", ")}]`:"";return`- ${Q.name}: ${Q.description}${w}`}).join(`
|
|
26197
26197
|
`)}function Jn2(A){if(!A.trim())return[];let f=[];for(let Q of A.split(`
|
|
26198
26198
|
`)){let w=Q.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/);if(w){let B=w[1]??"",x=w[2]??"",I=w[3],$=I?I.split(",").map((c)=>c.trim()).filter(Boolean):[];f.push({name:B,description:x,tags:$})}}return f}var $a0=new ff(Wn2,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:Gn2,parser:Jn2},{key:"notes",label:"Notes",type:"string"}]});class IK extends q2{constructor(){super({entityType:"agent",schema:gN,frontmatterSchema:xK})}toMarkdown(A){return A.content}fromMarkdown(A){let f=this.parseFrontMatter(A,xK),Q=$J(f.url);return{content:A,entityType:"agent",metadata:{name:f.name,url:f.url,status:f.status,slug:Q}}}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},Q=$a0.format({about:A.about,skills:A.skills,notes:A.notes});return this.buildMarkdown(Q,f)}parseAgentContent(A){let f=this.stripFrontmatter(A);if(!f.trim())return{about:"",skills:[],notes:""};try{let Q=$a0.parse(f);return{about:Q.about,skills:Q.skills,notes:Q.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 vn2=new IK;function kn2(A){let f=H2(A.content,xK),Q=vn2.parseAgentContent(A.content);return aO.parse({...A,frontmatter:f.metadata,about:Q.about,skills:Q.skills,notes:Q.notes})}class _a extends c6{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 kn2(A)}buildDetailResult(A,f){return{agent:A,prevAgent:f?.prev??null,nextAgent:f?.next??null}}buildListResult(A,f,Q){return{agents:A,pagination:f,baseUrl:Q.baseUrl}}}B0();HA();B0();async function Va(A,f){let w=`${(A.startsWith("http")?A:`https://${A}`).replace(/\/$/,"")}/.well-known/agent-card.json`;try{let B=await f(w);if(!B.ok)return null;let x=await B.json();return Nb(x)}catch{return null}}function ca0(A){let f=A.trim();if(f.startsWith("http://")||f.startsWith("https://"))try{return new URL(f).hostname}catch{return f}let Q=f.match(/https?:\/\/[^\s]+?(?=[.,;:!?)]*(?:\s|$))/);if(Q)try{return new URL(Q[0]).hostname}catch{return Q[0]}if(/^[^\s]+\.[^\s]+$/.test(f))return f;return""}HA();var zn2=new IK;function Ma(A){let f=A.anchor?.name??A.brainName,Q=A.anchor?.kind??"professional",w=[];if(A.anchor?.description)w.push(A.anchor.description);if(A.description)w.push(A.description);return{content:zn2.createAgentContent({name:f,kind:Q,...A.anchor?.organization&&{organization:A.anchor.organization},brainName:A.brainName,url:A.url,status:"active",discoveredAt:new Date().toISOString(),discoveredVia:"manual",about:w.join(`
|
|
26199
26199
|
|
|
26200
|
-
`),skills:A.skills.map((x)=>({name:x.name,description:x.description,tags:x.tags})),notes:""}),metadata:{name:f,url:A.url,status:"active",slug:$J(A.url)},anchorName:f}}var Nn2=X.object({prompt:X.string().optional(),url:X.string().optional(),content:X.string().optional(),skipAi:X.boolean().optional()}),RCQ=e5.extend({name:X.string().optional(),domain:X.string().optional()});class PGA extends J9{constructor(A,f){super(A,f,{schema:Nn2,jobTypeName:"agent-generation",entityType:"agent"})}async generate(A,f){let Q=A.url??A.prompt??"",w=ca0(Q);if(!w)throw Error("No URL or domain provided. Use: system_create agent with a domain like yeehaa.io");let B=await Va(w,globalThis.fetch);if(!B)throw Error(`Could not fetch Agent Card from ${w}. Make sure the agent is running and accessible.`);let{content:x,metadata:I,anchorName:$}=Ma(B);return{id:w,content:x,metadata:I,title:$}}}B0();tf();HA();import{jsxDEV as Da0}from"preact/jsx-dev-runtime";function Oa(A){try{return new URL(A).hostname}catch{return A}}var ja=({name:A,className:f=""})=>{let Q=A.charAt(0).toUpperCase(),w=0;for(let x=0;x<A.length;x++)w=A.charCodeAt(x)+((w<<5)-w);let B=Math.abs(w)%360;return Da0("div",{className:`flex items-center justify-center rounded-full text-white font-bold flex-shrink-0 ${f}`,style:{backgroundColor:`hsl(${B}, 55%, 45%)`},children:Q},void 0,!1,void 0,this)},Ra=({kind:A,size:f="md"})=>{let w={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 Da0("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]"} ${w}`,children:A},void 0,!1,void 0,this)};import{jsxDEV as Hw,Fragment as Ln2}from"preact/jsx-dev-runtime";var En2=({skills:A})=>{if(A.length===0)return null;return Hw("div",{className:"flex gap-1.5 flex-wrap mt-2",children:A.map((f)=>Hw("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 hn2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var bn2=({agent:A})=>{let{frontmatter:f,about:Q,skills:w,url:B}=A,x=f.status==="archived";return Hw("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:[Hw(ja,{name:f.name,className:"w-12 h-12 text-lg"},void 0,!1,void 0,this),Hw("div",{className:"flex-1 min-w-0",children:[Hw("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[Hw("span",{className:"text-lg font-semibold text-heading",children:f.name},void 0,!1,void 0,this),Hw(Ra,{kind:x?"archived":f.kind,size:"sm"},void 0,!1,void 0,this),f.organization&&Hw("span",{className:"text-xs text-theme-muted",children:["\xB7 ",f.organization]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q&&Hw("p",{className:"text-sm text-theme-muted line-clamp-2 mb-0",children:Q},void 0,!1,void 0,this),!x&&Hw(En2,{skills:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Hw("div",{className:"flex flex-col items-end gap-1 flex-shrink-0 text-right",children:[Hw("span",{className:"text-xs text-theme-muted",children:Oa(f.url)},void 0,!1,void 0,this),Hw("span",{className:"text-[11px] text-theme-muted opacity-60",children:x?"Archived":`Discovered ${hn2(f.discoveredAt)}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},Ya0=({agents:A,pageTitle:f,pagination:Q,baseUrl:w="/agents"})=>{let B=f??"Agent Directory",x=Q?.totalItems??A.length,I=`Your network of ${x} ${x===1?"brain":"brains"} and their anchors`;return Hw(Ln2,{children:[Hw(p2,{title:B,description:I},void 0,!1,void 0,this),Hw("div",{className:"agent-list bg-theme",children:Hw("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[Hw("div",{className:"mb-8 pb-6 border-b border-theme",children:[Hw("h1",{className:"text-4xl font-bold text-heading mb-2",children:B},void 0,!1,void 0,this),Hw("p",{className:"text-theme-muted",children:I},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Hw("div",{className:"flex flex-col gap-4",children:A.map(($)=>Hw(bn2,{agent:$},$.id,!1,void 0,this))},void 0,!1,void 0,this),A.length===0&&Hw("p",{className:"text-center text-theme-muted py-16",children:"No agents in your directory yet."},void 0,!1,void 0,this),Q&&Q.totalPages>1&&Hw("div",{className:"mt-12",children:Hw(u$,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:w},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 B2,Fragment as _n2}from"preact/jsx-dev-runtime";function qn2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var sO=({children:A})=>B2("h2",{className:"text-sm font-semibold text-theme-muted uppercase tracking-wide mb-3",children:A},void 0,!1,void 0,this),Cn2=({skill:A})=>B2("div",{className:"flex items-start gap-3 px-4 py-3 bg-theme-subtle rounded-lg",children:[B2("div",{className:"flex-1",children:[B2("div",{className:"text-sm font-semibold text-heading",children:A.name},void 0,!1,void 0,this),B2("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&&B2("div",{className:"flex gap-1 flex-shrink-0",children:A.tags.map((f)=>B2("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),ua0=({label:A,value:f,valueClassName:Q})=>B2("div",{className:"flex justify-between text-[13px]",children:[B2("span",{className:"text-theme-muted",children:A},void 0,!1,void 0,this),B2("span",{className:Q??"text-heading",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ua0=({agent:A})=>{let{frontmatter:f,about:Q,skills:w,notes:B}=A,x=Oa(f.url);return B2(_n2,{children:[B2(p2,{title:f.name,description:Q||`Agent profile for ${f.name}`},void 0,!1,void 0,this),B2("article",{className:"agent-detail",children:B2("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:[B2("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),B2("div",{className:"flex items-start gap-6 mb-8",children:[B2(ja,{name:f.name,className:"w-[72px] h-[72px] text-3xl"},void 0,!1,void 0,this),B2("div",{children:[B2("div",{className:"flex items-center gap-3 mb-1",children:[B2("h1",{className:"text-3xl md:text-4xl font-bold text-heading",children:f.name},void 0,!1,void 0,this),B2(Ra,{kind:f.kind},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B2("div",{className:"flex items-center gap-3 text-theme-muted",children:[f.organization&&B2("span",{className:"text-[15px]",children:f.organization},void 0,!1,void 0,this),f.organization&&B2("span",{className:"text-theme-muted opacity-40",children:"\xB7"},void 0,!1,void 0,this),B2("span",{className:"text-sm",children:["Discovered ",qn2(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),B2("div",{className:"border-b border-theme mb-8"},void 0,!1,void 0,this),B2("div",{className:"flex flex-col md:flex-row gap-12",children:[B2("div",{className:"flex-[2] min-w-0",children:[Q&&B2("section",{className:"mb-8",children:[B2(sO,{children:"About"},void 0,!1,void 0,this),B2("p",{className:"text-[15px] text-theme leading-relaxed",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w.length>0&&B2("section",{className:"mb-8",children:[B2(sO,{children:"Skills"},void 0,!1,void 0,this),B2("div",{className:"flex flex-col gap-2.5",children:w.map((I)=>B2(Cn2,{skill:I},I.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B&&B2("section",{className:"mb-8",children:[B2(sO,{children:"Notes"},void 0,!1,void 0,this),B2("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),B2("aside",{className:"flex-1 md:pl-8 md:border-l border-theme-muted/20",children:[B2("section",{className:"mb-8",children:[B2(sO,{children:"Brain"},void 0,!1,void 0,this),B2("div",{className:"p-4 bg-theme-subtle rounded-xl",children:[B2("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&&B2("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),B2("section",{className:"mb-8",children:[B2(sO,{children:"Connection"},void 0,!1,void 0,this),B2("div",{className:"flex flex-col gap-3",children:[B2("div",{children:[B2("div",{className:"text-[13px] text-theme-muted mb-0.5",children:"Endpoint"},void 0,!1,void 0,this),B2("div",{className:"text-xs text-heading font-mono",children:f.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B2(ua0,{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),B2(ua0,{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),B2("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 Vn2=X.object({agents:X.array(iN),pageTitle:X.string().optional(),pagination:Qx.nullable(),baseUrl:X.string().optional()});function Ha0(){return{"agent-list":a0({name:"agent-list",description:"Agent directory list page template",schema:Vn2,dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:Ya0}}),"agent-detail":a0({name:"agent-detail",description:"Individual agent profile template",schema:X.object({agent:iN,prevAgent:iN.nullable(),nextAgent:iN.nullable()}),dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:Ua0}})}}function Ka0(A){A.messaging.subscribe("a2a:call:completed",async(f)=>{try{let{domain:Q}=f.payload;if(await A.entityService.getEntity("agent",Q))return{success:!0};let B=await Va(Q,globalThis.fetch);if(!B)return{success:!0};let{content:x,metadata:I}=Ma(B);await A.entityService.createEntity({id:Q,entityType:"agent",content:x,metadata:I})}catch{}return{success:!0}})}var Pa={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.0",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 On2=new IK;class gGA extends zf{entityType="agent";schema=gN;adapter=On2;constructor(){super("agent-discovery",Pa)}createGenerationHandler(A){return new PGA(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return Ha0()}getDataSources(){return[new _a(this.logger.child("AgentDataSource"))]}async onRegister(A){Ka0(A)}}function iGA(){return new gGA}B0();HA();HA();B0();var TN=LJ,Fa0=LJ,tO=X2.extend({entityType:X.literal("skill"),metadata:Fa0});B0();class mN extends q2{constructor(){super({entityType:"skill",schema:tO,frontmatterSchema:TN})}toMarkdown(A){return A.content}fromMarkdown(A){let f=this.parseFrontMatter(A,TN);return{content:A,entityType:"skill",metadata:f}}createSkillContent(A){return this.buildMarkdown("",A)}}HA();function jn2(A){let f=[];if(A.topicTitles.length>0)f.push(`The brain's knowledge domains (from content analysis):
|
|
26200
|
+
`),skills:A.skills.map((x)=>({name:x.name,description:x.description,tags:x.tags})),notes:""}),metadata:{name:f,url:A.url,status:"active",slug:$J(A.url)},anchorName:f}}var Nn2=X.object({prompt:X.string().optional(),url:X.string().optional(),content:X.string().optional(),skipAi:X.boolean().optional()}),RCQ=e5.extend({name:X.string().optional(),domain:X.string().optional()});class PGA extends J9{constructor(A,f){super(A,f,{schema:Nn2,jobTypeName:"agent-generation",entityType:"agent"})}async generate(A,f){let Q=A.url??A.prompt??"",w=ca0(Q);if(!w)throw Error("No URL or domain provided. Use: system_create agent with a domain like yeehaa.io");let B=await Va(w,globalThis.fetch);if(!B)throw Error(`Could not fetch Agent Card from ${w}. Make sure the agent is running and accessible.`);let{content:x,metadata:I,anchorName:$}=Ma(B);return{id:w,content:x,metadata:I,title:$}}}B0();tf();HA();import{jsxDEV as Da0}from"preact/jsx-dev-runtime";function Oa(A){try{return new URL(A).hostname}catch{return A}}var ja=({name:A,className:f=""})=>{let Q=A.charAt(0).toUpperCase(),w=0;for(let x=0;x<A.length;x++)w=A.charCodeAt(x)+((w<<5)-w);let B=Math.abs(w)%360;return Da0("div",{className:`flex items-center justify-center rounded-full text-white font-bold flex-shrink-0 ${f}`,style:{backgroundColor:`hsl(${B}, 55%, 45%)`},children:Q},void 0,!1,void 0,this)},Ra=({kind:A,size:f="md"})=>{let w={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 Da0("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]"} ${w}`,children:A},void 0,!1,void 0,this)};import{jsxDEV as Hw,Fragment as Ln2}from"preact/jsx-dev-runtime";var En2=({skills:A})=>{if(A.length===0)return null;return Hw("div",{className:"flex gap-1.5 flex-wrap mt-2",children:A.map((f)=>Hw("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 hn2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var bn2=({agent:A})=>{let{frontmatter:f,about:Q,skills:w,url:B}=A,x=f.status==="archived";return Hw("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:[Hw(ja,{name:f.name,className:"w-12 h-12 text-lg"},void 0,!1,void 0,this),Hw("div",{className:"flex-1 min-w-0",children:[Hw("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[Hw("span",{className:"text-lg font-semibold text-heading",children:f.name},void 0,!1,void 0,this),Hw(Ra,{kind:x?"archived":f.kind,size:"sm"},void 0,!1,void 0,this),f.organization&&Hw("span",{className:"text-xs text-theme-muted",children:["\xB7 ",f.organization]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q&&Hw("p",{className:"text-sm text-theme-muted line-clamp-2 mb-0",children:Q},void 0,!1,void 0,this),!x&&Hw(En2,{skills:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Hw("div",{className:"flex flex-col items-end gap-1 flex-shrink-0 text-right",children:[Hw("span",{className:"text-xs text-theme-muted",children:Oa(f.url)},void 0,!1,void 0,this),Hw("span",{className:"text-[11px] text-theme-muted opacity-60",children:x?"Archived":`Discovered ${hn2(f.discoveredAt)}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},Ya0=({agents:A,pageTitle:f,pagination:Q,baseUrl:w="/agents"})=>{let B=f??"Agent Directory",x=Q?.totalItems??A.length,I=`Your network of ${x} ${x===1?"brain":"brains"} and their anchors`;return Hw(Ln2,{children:[Hw(p2,{title:B,description:I},void 0,!1,void 0,this),Hw("div",{className:"agent-list bg-theme",children:Hw("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[Hw("div",{className:"mb-8 pb-6 border-b border-theme",children:[Hw("h1",{className:"text-4xl font-bold text-heading mb-2",children:B},void 0,!1,void 0,this),Hw("p",{className:"text-theme-muted",children:I},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Hw("div",{className:"flex flex-col gap-4",children:A.map(($)=>Hw(bn2,{agent:$},$.id,!1,void 0,this))},void 0,!1,void 0,this),A.length===0&&Hw("p",{className:"text-center text-theme-muted py-16",children:"No agents in your directory yet."},void 0,!1,void 0,this),Q&&Q.totalPages>1&&Hw("div",{className:"mt-12",children:Hw(u$,{currentPage:Q.currentPage,totalPages:Q.totalPages,baseUrl:w},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 B2,Fragment as _n2}from"preact/jsx-dev-runtime";function qn2(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var sO=({children:A})=>B2("h2",{className:"text-sm font-semibold text-theme-muted uppercase tracking-wide mb-3",children:A},void 0,!1,void 0,this),Cn2=({skill:A})=>B2("div",{className:"flex items-start gap-3 px-4 py-3 bg-theme-subtle rounded-lg",children:[B2("div",{className:"flex-1",children:[B2("div",{className:"text-sm font-semibold text-heading",children:A.name},void 0,!1,void 0,this),B2("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&&B2("div",{className:"flex gap-1 flex-shrink-0",children:A.tags.map((f)=>B2("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),ua0=({label:A,value:f,valueClassName:Q})=>B2("div",{className:"flex justify-between text-[13px]",children:[B2("span",{className:"text-theme-muted",children:A},void 0,!1,void 0,this),B2("span",{className:Q??"text-heading",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ua0=({agent:A})=>{let{frontmatter:f,about:Q,skills:w,notes:B}=A,x=Oa(f.url);return B2(_n2,{children:[B2(p2,{title:f.name,description:Q||`Agent profile for ${f.name}`},void 0,!1,void 0,this),B2("article",{className:"agent-detail",children:B2("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:[B2("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),B2("div",{className:"flex items-start gap-6 mb-8",children:[B2(ja,{name:f.name,className:"w-[72px] h-[72px] text-3xl"},void 0,!1,void 0,this),B2("div",{children:[B2("div",{className:"flex items-center gap-3 mb-1",children:[B2("h1",{className:"text-3xl md:text-4xl font-bold text-heading",children:f.name},void 0,!1,void 0,this),B2(Ra,{kind:f.kind},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B2("div",{className:"flex items-center gap-3 text-theme-muted",children:[f.organization&&B2("span",{className:"text-[15px]",children:f.organization},void 0,!1,void 0,this),f.organization&&B2("span",{className:"text-theme-muted opacity-40",children:"\xB7"},void 0,!1,void 0,this),B2("span",{className:"text-sm",children:["Discovered ",qn2(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),B2("div",{className:"border-b border-theme mb-8"},void 0,!1,void 0,this),B2("div",{className:"flex flex-col md:flex-row gap-12",children:[B2("div",{className:"flex-[2] min-w-0",children:[Q&&B2("section",{className:"mb-8",children:[B2(sO,{children:"About"},void 0,!1,void 0,this),B2("p",{className:"text-[15px] text-theme leading-relaxed",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w.length>0&&B2("section",{className:"mb-8",children:[B2(sO,{children:"Skills"},void 0,!1,void 0,this),B2("div",{className:"flex flex-col gap-2.5",children:w.map((I)=>B2(Cn2,{skill:I},I.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B&&B2("section",{className:"mb-8",children:[B2(sO,{children:"Notes"},void 0,!1,void 0,this),B2("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),B2("aside",{className:"flex-1 md:pl-8 md:border-l border-theme-muted/20",children:[B2("section",{className:"mb-8",children:[B2(sO,{children:"Brain"},void 0,!1,void 0,this),B2("div",{className:"p-4 bg-theme-subtle rounded-xl",children:[B2("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&&B2("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),B2("section",{className:"mb-8",children:[B2(sO,{children:"Connection"},void 0,!1,void 0,this),B2("div",{className:"flex flex-col gap-3",children:[B2("div",{children:[B2("div",{className:"text-[13px] text-theme-muted mb-0.5",children:"Endpoint"},void 0,!1,void 0,this),B2("div",{className:"text-xs text-heading font-mono",children:f.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B2(ua0,{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),B2(ua0,{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),B2("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 Vn2=X.object({agents:X.array(iN),pageTitle:X.string().optional(),pagination:Qx.nullable(),baseUrl:X.string().optional()});function Ha0(){return{"agent-list":a0({name:"agent-list",description:"Agent directory list page template",schema:Vn2,dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:Ya0}}),"agent-detail":a0({name:"agent-detail",description:"Individual agent profile template",schema:X.object({agent:iN,prevAgent:iN.nullable(),nextAgent:iN.nullable()}),dataSourceId:"agent-discovery:entities",requiredPermission:"public",layout:{component:Ua0}})}}function Ka0(A){A.messaging.subscribe("a2a:call:completed",async(f)=>{try{let{domain:Q}=f.payload;if(await A.entityService.getEntity("agent",Q))return{success:!0};let B=await Va(Q,globalThis.fetch);if(!B)return{success:!0};let{content:x,metadata:I}=Ma(B);await A.entityService.createEntity({id:Q,entityType:"agent",content:x,metadata:I})}catch{}return{success:!0}})}var Pa={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.1",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 On2=new IK;class gGA extends zf{entityType="agent";schema=gN;adapter=On2;constructor(){super("agent-discovery",Pa)}createGenerationHandler(A){return new PGA(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return Ha0()}getDataSources(){return[new _a(this.logger.child("AgentDataSource"))]}async onRegister(A){Ka0(A)}}function iGA(){return new gGA}B0();HA();HA();B0();var TN=LJ,Fa0=LJ,tO=X2.extend({entityType:X.literal("skill"),metadata:Fa0});B0();class mN extends q2{constructor(){super({entityType:"skill",schema:tO,frontmatterSchema:TN})}toMarkdown(A){return A.content}fromMarkdown(A){let f=this.parseFrontMatter(A,TN);return{content:A,entityType:"skill",metadata:f}}createSkillContent(A){return this.buildMarkdown("",A)}}HA();function jn2(A){let f=[];if(A.topicTitles.length>0)f.push(`The brain's knowledge domains (from content analysis):
|
|
26201
26201
|
${A.topicTitles.map((Q)=>`- ${Q}`).join(`
|
|
26202
26202
|
`)}`);if(A.toolDescriptions.length>0)f.push(`The brain has these capabilities:
|
|
26203
26203
|
${A.toolDescriptions.map((Q)=>`- ${Q}`).join(`
|
|
@@ -26239,7 +26239,7 @@ Return 2-5 skills as a JSON object with a "skills" array.`,requiredPermission:"p
|
|
|
26239
26239
|
title: ${I}
|
|
26240
26240
|
keywords: []
|
|
26241
26241
|
---
|
|
26242
|
-
${I}`;try{await A.entityService.createEntity({id:$,entityType:"topic",content:c,metadata:{}})}catch{}}let B=await ga(A,this.logger),x=await A.entityService.listEntities("skill");return{...B,skills:x.map((I)=>I.metadata)}})}async deriveAll(A){this.logger.info("Deriving skills from topics (replace-all)");let f=await ga(A,this.logger,{replaceAll:!0});this.logger.info("Skill derivation complete",f)}hasRunInitialDerivation(){return this.initialDerivationDone}}function mGA(){return new TGA}var gn2=X.object({}).strict();function ia(A={}){return gn2.parse(A),[iGA(),mGA()]}B0();HA();tf();HA();B0();var Ta=qg.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.)")}),$K=OI.extend(Ta.shape);B0();XU();HA();var in2=new kc;class ma{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,Q){let w=Q.entityService,[B,x,I,$]=await Promise.all([bJ(w),w.listEntities("post",{limit:20}),w.listEntities("deck",{limit:20}),iY(w)]),c=in2.parseProfileBody(B,$K),D=x.sort(lh).slice(0,3).map(kO),u=I.sort(lh).slice(0,3).map(hO);if(!$.cta)throw Error("CTA not configured in site-info");let K={profile:c,posts:D,decks:u,postsListUrl:this.postsListUrl,decksListUrl:this.decksListUrl,cta:$.cta};return f.parse(K)}}B0();XU();var Tn2=new kc;class Sa{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,f,Q){let w=await bJ(Q.entityService),x={profile:Tn2.parseProfileBody(w,$K)};return f.parse(x)}}import{jsxDEV as eB,Fragment as Za0}from"preact/jsx-dev-runtime";var SGA=({profile:A,posts:f,decks:Q,postsListUrl:w,decksListUrl:B,cta:x})=>{let I=A.tagline||A.description,$=f.map((K)=>({id:K.id,url:K.url,title:K.metadata.title,date:K.metadata.publishedAt||K.created,description:K.frontmatter.excerpt,series:K.frontmatter.seriesName&&K.frontmatter.seriesIndex?{name:K.frontmatter.seriesName,index:K.frontmatter.seriesIndex}:void 0})),c=Q.map((K)=>({id:K.id,url:K.url,title:K.frontmatter.title||K.id,date:K.frontmatter.publishedAt??K.created,description:K.frontmatter.description})),D=A.name||"Home",u=A.intro||A.description||I||"Professional site";return eB(Za0,{children:[eB(p2,{title:D,description:u,ogType:"website"},void 0,!1,void 0,this),eB("div",{className:"homepage-list bg-theme",children:[eB("header",{className:"hero-bg-pattern relative w-full min-h-[70vh] flex items-end px-6 md:px-12 bg-theme overflow-hidden",children:eB("div",{className:"relative z-10 max-w-6xl mx-auto w-full pb-16 md:pb-24",children:[I&&eB("h1",{className:"text-5xl md:text-6xl lg:text-7xl font-semibold text-heading leading-[1.08] tracking-tight",children:I},void 0,!1,void 0,this),A.intro&&eB(Za0,{children:[eB("div",{className:"w-12 border-t border-theme mt-8 mb-6 md:mt-10 md:mb-8"},void 0,!1,void 0,this),eB("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),eB("div",{className:"section-divider"},void 0,!1,void 0,this),eB("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[eB("div",{className:"content-section-reveal mb-20 md:mb-32",children:eB(EY,{title:"Essays",items:$,viewAllUrl:w},void 0,!1,void 0,this)},void 0,!1,void 0,this),c.length>0&&eB("div",{className:"content-section-reveal mb-20 md:mb-32",children:eB(EY,{title:"Presentations",items:c,viewAllUrl:B},void 0,!1,void 0,this)},void 0,!1,void 0,this),(A.description||A.expertise&&A.expertise.length>0)&&eB("div",{className:"content-section-reveal mb-20 md:mb-32",children:eB(EY,{title:"About",viewAllUrl:"/about",variant:"stacked",children:eB("div",{className:"space-y-6",children:[A.description&&eB("p",{className:"text-lg text-theme leading-relaxed",children:A.description},void 0,!1,void 0,this),A.expertise&&A.expertise.length>0&&eB(M9,{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),eB(_KA,{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 zQ,Fragment as mn2}from"preact/jsx-dev-runtime";var yGA=({profile:A})=>{let f=`About ${A.name||"Me"}`,Q=A.description||A.intro||"About page",w=A.expertise&&A.expertise.length>0||A.currentFocus||A.availability||A.email||A.website||A.socialLinks&&A.socialLinks.length>0;return zQ(mn2,{children:[zQ(p2,{title:f,description:Q,ogType:"profile"},void 0,!1,void 0,this),zQ("div",{className:"about-page bg-theme",children:[zQ("header",{className:"hero-bg-pattern relative w-full py-16 md:py-24 px-6 md:px-12 bg-theme overflow-hidden",children:zQ("div",{className:"relative z-10 max-w-4xl mx-auto",children:[zQ("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&&zQ("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),zQ("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-12 md:py-16",children:[A.story&&zQ("section",{className:"content-section-reveal mb-20 md:mb-28",children:zQ(Y$,{markdown:A.story},void 0,!1,void 0,this)},void 0,!1,void 0,this),w&&zQ("div",{className:"content-section-reveal grid md:grid-cols-2 gap-x-16 gap-y-12",children:[A.expertise&&A.expertise.length>0&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Expertise"},void 0,!1,void 0,this),zQ("ul",{className:"flex flex-wrap gap-3",children:A.expertise.map((B,x)=>zQ("li",{className:xM({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&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Current Focus"},void 0,!1,void 0,this),zQ("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&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Availability"},void 0,!1,void 0,this),zQ("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)&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Contact"},void 0,!1,void 0,this),zQ("div",{className:"space-y-4",children:[A.email&&zQ("p",{className:"text-lg",children:zQ("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&&zQ("p",{className:"text-lg",children:zQ("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&&zQ("div",{className:"flex flex-wrap gap-4 mt-4",children:A.socialLinks.map((B,x)=>zQ(h8,{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 T9,Fragment as Wa0}from"preact/jsx-dev-runtime";var lGA=()=>{return T9(Wa0,{children:[T9(p2,{title:"Thanks for subscribing!",description:"You've successfully subscribed to the newsletter."},void 0,!1,void 0,this),T9("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:T9("div",{className:"text-center max-w-md",children:[T9("div",{className:"text-6xl mb-6",children:"\uD83C\uDF89"},void 0,!1,void 0,this),T9("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Thanks for subscribing!"},void 0,!1,void 0,this),T9("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),T9(h8,{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)},nGA=()=>{return T9(Wa0,{children:[T9(p2,{title:"Subscription failed",description:"There was a problem with your subscription."},void 0,!1,void 0,this),T9("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:T9("div",{className:"text-center max-w-md",children:[T9("div",{className:"text-6xl mb-6",children:"\uD83D\uDE22"},void 0,!1,void 0,this),T9("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Something went wrong"},void 0,!1,void 0,this),T9("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),T9(h8,{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)};HA();var Ga0=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')")}),Ja0=X.object({entityDisplay:X.object({post:Ga0,deck:Ga0}).describe("Display metadata for post and deck entity types (required for homepage)")});var va0={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.0",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 pGA extends mw{dependencies=["blog","decks"];constructor(A){super("professional-site",va0,A,Ja0)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",Ta);let f=this.config.entityDisplay.post,Q=this.config.entityDisplay.deck,w=`/${f.pluralName??f.label.toLowerCase()+"s"}`,B=`/${Q.pluralName??Q.label.toLowerCase()+"s"}`,x=new ma(w,B);A.entities.registerDataSource(x);let I=new Sa;A.entities.registerDataSource(I);let $=X.object({profile:$K,posts:X.array(lY),decks:X.array(NO),postsListUrl:X.string(),decksListUrl:X.string(),cta:YO}),c=X.object({profile:$K}),D=X.object({});A.templates.register({"homepage-list":a0({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:$,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:SGA}}),about:a0({name:"about",description:"About page with full profile information",schema:c,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:yGA}}),"subscribe-thanks":a0({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:D,requiredPermission:"public",layout:{component:lGA}}),"subscribe-error":a0({name:"subscribe-error",description:"Newsletter subscription error page",schema:D,requiredPermission:"public",layout:{component:nGA}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function ka0(A){return new pGA(A??{})}var za0=[{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 SN}from"preact/jsx-dev-runtime";function Na0({sections:A,siteInfo:f,slots:Q}){return SN("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[SN(jKA,{title:f.title,navigation:f.navigation.primary,...f.logo!==void 0?{logo:f.logo}:{}},void 0,!1,void 0,this),SN("main",{className:"flex-grow flex flex-col bg-theme",children:A},void 0,!1,void 0,this),SN("div",{className:"section-divider"},void 0,!1,void 0,this),SN(MKA,{primaryNavigation:f.navigation.primary,secondaryNavigation:f.navigation.secondary,copyright:f.copyright,socialLinks:f.socialLinks,children:SN(tZA,{name:"footer-top",slots:Q},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var yn2={layouts:{default:Na0},routes:za0,plugin:ka0,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"}}}},eO=yn2;var Ea0=`/* Default font imports */
|
|
26242
|
+
${I}`;try{await A.entityService.createEntity({id:$,entityType:"topic",content:c,metadata:{}})}catch{}}let B=await ga(A,this.logger),x=await A.entityService.listEntities("skill");return{...B,skills:x.map((I)=>I.metadata)}})}async deriveAll(A){this.logger.info("Deriving skills from topics (replace-all)");let f=await ga(A,this.logger,{replaceAll:!0});this.logger.info("Skill derivation complete",f)}hasRunInitialDerivation(){return this.initialDerivationDone}}function mGA(){return new TGA}var gn2=X.object({}).strict();function ia(A={}){return gn2.parse(A),[iGA(),mGA()]}B0();HA();tf();HA();B0();var Ta=qg.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.)")}),$K=OI.extend(Ta.shape);B0();XU();HA();var in2=new kc;class ma{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,Q){let w=Q.entityService,[B,x,I,$]=await Promise.all([bJ(w),w.listEntities("post",{limit:20}),w.listEntities("deck",{limit:20}),iY(w)]),c=in2.parseProfileBody(B,$K),D=x.sort(lh).slice(0,3).map(kO),u=I.sort(lh).slice(0,3).map(hO);if(!$.cta)throw Error("CTA not configured in site-info");let K={profile:c,posts:D,decks:u,postsListUrl:this.postsListUrl,decksListUrl:this.decksListUrl,cta:$.cta};return f.parse(K)}}B0();XU();var Tn2=new kc;class Sa{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,f,Q){let w=await bJ(Q.entityService),x={profile:Tn2.parseProfileBody(w,$K)};return f.parse(x)}}import{jsxDEV as eB,Fragment as Za0}from"preact/jsx-dev-runtime";var SGA=({profile:A,posts:f,decks:Q,postsListUrl:w,decksListUrl:B,cta:x})=>{let I=A.tagline||A.description,$=f.map((K)=>({id:K.id,url:K.url,title:K.metadata.title,date:K.metadata.publishedAt||K.created,description:K.frontmatter.excerpt,series:K.frontmatter.seriesName&&K.frontmatter.seriesIndex?{name:K.frontmatter.seriesName,index:K.frontmatter.seriesIndex}:void 0})),c=Q.map((K)=>({id:K.id,url:K.url,title:K.frontmatter.title||K.id,date:K.frontmatter.publishedAt??K.created,description:K.frontmatter.description})),D=A.name||"Home",u=A.intro||A.description||I||"Professional site";return eB(Za0,{children:[eB(p2,{title:D,description:u,ogType:"website"},void 0,!1,void 0,this),eB("div",{className:"homepage-list bg-theme",children:[eB("header",{className:"hero-bg-pattern relative w-full min-h-[70vh] flex items-end px-6 md:px-12 bg-theme overflow-hidden",children:eB("div",{className:"relative z-10 max-w-6xl mx-auto w-full pb-16 md:pb-24",children:[I&&eB("h1",{className:"text-5xl md:text-6xl lg:text-7xl font-semibold text-heading leading-[1.08] tracking-tight",children:I},void 0,!1,void 0,this),A.intro&&eB(Za0,{children:[eB("div",{className:"w-12 border-t border-theme mt-8 mb-6 md:mt-10 md:mb-8"},void 0,!1,void 0,this),eB("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),eB("div",{className:"section-divider"},void 0,!1,void 0,this),eB("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[eB("div",{className:"content-section-reveal mb-20 md:mb-32",children:eB(EY,{title:"Essays",items:$,viewAllUrl:w},void 0,!1,void 0,this)},void 0,!1,void 0,this),c.length>0&&eB("div",{className:"content-section-reveal mb-20 md:mb-32",children:eB(EY,{title:"Presentations",items:c,viewAllUrl:B},void 0,!1,void 0,this)},void 0,!1,void 0,this),(A.description||A.expertise&&A.expertise.length>0)&&eB("div",{className:"content-section-reveal mb-20 md:mb-32",children:eB(EY,{title:"About",viewAllUrl:"/about",variant:"stacked",children:eB("div",{className:"space-y-6",children:[A.description&&eB("p",{className:"text-lg text-theme leading-relaxed",children:A.description},void 0,!1,void 0,this),A.expertise&&A.expertise.length>0&&eB(M9,{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),eB(_KA,{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 zQ,Fragment as mn2}from"preact/jsx-dev-runtime";var yGA=({profile:A})=>{let f=`About ${A.name||"Me"}`,Q=A.description||A.intro||"About page",w=A.expertise&&A.expertise.length>0||A.currentFocus||A.availability||A.email||A.website||A.socialLinks&&A.socialLinks.length>0;return zQ(mn2,{children:[zQ(p2,{title:f,description:Q,ogType:"profile"},void 0,!1,void 0,this),zQ("div",{className:"about-page bg-theme",children:[zQ("header",{className:"hero-bg-pattern relative w-full py-16 md:py-24 px-6 md:px-12 bg-theme overflow-hidden",children:zQ("div",{className:"relative z-10 max-w-4xl mx-auto",children:[zQ("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&&zQ("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),zQ("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-12 md:py-16",children:[A.story&&zQ("section",{className:"content-section-reveal mb-20 md:mb-28",children:zQ(Y$,{markdown:A.story},void 0,!1,void 0,this)},void 0,!1,void 0,this),w&&zQ("div",{className:"content-section-reveal grid md:grid-cols-2 gap-x-16 gap-y-12",children:[A.expertise&&A.expertise.length>0&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Expertise"},void 0,!1,void 0,this),zQ("ul",{className:"flex flex-wrap gap-3",children:A.expertise.map((B,x)=>zQ("li",{className:xM({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&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Current Focus"},void 0,!1,void 0,this),zQ("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&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Availability"},void 0,!1,void 0,this),zQ("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)&&zQ("section",{children:[zQ("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Contact"},void 0,!1,void 0,this),zQ("div",{className:"space-y-4",children:[A.email&&zQ("p",{className:"text-lg",children:zQ("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&&zQ("p",{className:"text-lg",children:zQ("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&&zQ("div",{className:"flex flex-wrap gap-4 mt-4",children:A.socialLinks.map((B,x)=>zQ(h8,{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 T9,Fragment as Wa0}from"preact/jsx-dev-runtime";var lGA=()=>{return T9(Wa0,{children:[T9(p2,{title:"Thanks for subscribing!",description:"You've successfully subscribed to the newsletter."},void 0,!1,void 0,this),T9("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:T9("div",{className:"text-center max-w-md",children:[T9("div",{className:"text-6xl mb-6",children:"\uD83C\uDF89"},void 0,!1,void 0,this),T9("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Thanks for subscribing!"},void 0,!1,void 0,this),T9("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),T9(h8,{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)},nGA=()=>{return T9(Wa0,{children:[T9(p2,{title:"Subscription failed",description:"There was a problem with your subscription."},void 0,!1,void 0,this),T9("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:T9("div",{className:"text-center max-w-md",children:[T9("div",{className:"text-6xl mb-6",children:"\uD83D\uDE22"},void 0,!1,void 0,this),T9("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Something went wrong"},void 0,!1,void 0,this),T9("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),T9(h8,{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)};HA();var Ga0=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')")}),Ja0=X.object({entityDisplay:X.object({post:Ga0,deck:Ga0}).describe("Display metadata for post and deck entity types (required for homepage)")});var va0={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.1",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 pGA extends mw{dependencies=["blog","decks"];constructor(A){super("professional-site",va0,A,Ja0)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",Ta);let f=this.config.entityDisplay.post,Q=this.config.entityDisplay.deck,w=`/${f.pluralName??f.label.toLowerCase()+"s"}`,B=`/${Q.pluralName??Q.label.toLowerCase()+"s"}`,x=new ma(w,B);A.entities.registerDataSource(x);let I=new Sa;A.entities.registerDataSource(I);let $=X.object({profile:$K,posts:X.array(lY),decks:X.array(NO),postsListUrl:X.string(),decksListUrl:X.string(),cta:YO}),c=X.object({profile:$K}),D=X.object({});A.templates.register({"homepage-list":a0({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:$,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:SGA}}),about:a0({name:"about",description:"About page with full profile information",schema:c,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:yGA}}),"subscribe-thanks":a0({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:D,requiredPermission:"public",layout:{component:lGA}}),"subscribe-error":a0({name:"subscribe-error",description:"Newsletter subscription error page",schema:D,requiredPermission:"public",layout:{component:nGA}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function ka0(A){return new pGA(A??{})}var za0=[{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 SN}from"preact/jsx-dev-runtime";function Na0({sections:A,siteInfo:f,slots:Q}){return SN("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[SN(jKA,{title:f.title,navigation:f.navigation.primary,...f.logo!==void 0?{logo:f.logo}:{}},void 0,!1,void 0,this),SN("main",{className:"flex-grow flex flex-col bg-theme",children:A},void 0,!1,void 0,this),SN("div",{className:"section-divider"},void 0,!1,void 0,this),SN(MKA,{primaryNavigation:f.navigation.primary,secondaryNavigation:f.navigation.secondary,copyright:f.copyright,socialLinks:f.socialLinks,children:SN(tZA,{name:"footer-top",slots:Q},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var yn2={layouts:{default:Na0},routes:za0,plugin:ka0,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"}}}},eO=yn2;var Ea0=`/* Default font imports */
|
|
26243
26243
|
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&display=swap');
|
|
26244
26244
|
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap');
|
|
26245
26245
|
|
|
@@ -26543,7 +26543,7 @@ ${I}`;try{await A.entityService.createEntity({id:$,entityType:"topic",content:c,
|
|
|
26543
26543
|
.btn-primary:hover { background-color: var(--color-brand-dark); }
|
|
26544
26544
|
.btn-primary:disabled { opacity: 0.5; }
|
|
26545
26545
|
}
|
|
26546
|
-
`;var ya=Ea0;import{join as nn2}from"path";var ha0=["prompt","note","link","wishlist","topics","directory-sync","agents","mcp","discord","a2a"],ba0=[...ha0,"image","dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder","webserver"],pn2=[...ba0,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],La0=OU({name:"rover",version:"0.1.0",model:"gpt-5.4-mini",site:eO,theme:ya,presets:{core:ha0,default:ba0,full:pn2},evalDisable:["discord","webserver","mcp","analytics","dashboard"],capabilities:[["prompt",ZW,void 0],["image",iq,void 0],["dashboard",SO,void 0],["blog",xWA,{}],["series",YWA,void 0],["decks",bO,void 0],["note",KW,{}],["link",FW,{}],["portfolio",SWA,{}],["topics",Ua,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",UGA,{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",PO,{autoGenerateOnBlogPublish:!0}],["newsletter",go0,{doubleOptIn:!0}],["obsidian-vault",bGA,{autoSync:!0}],["wishlist",La,{}],["stock-photo",RGA,{}],["agents",ia,void 0],["directory-sync",VZ,{seedContent:!0,seedContentPath:nn2(import.meta.dir,"..","seed-content"),initialSync:!0}],["analytics",za,{}],["site-info",xW,void 0],["site-builder",uW,{cms:{}}]],interfaces:[["mcp",rU,()=>({})],["discord",LH,()=>({})],["webserver",qH,()=>({})],["a2a",Cz,()=>({})]],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"}}});e3();B0();HA();HA();B0();var la=X.object({routeId:X.string(),sectionId:X.string()}),Aj=X2.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:la});B0();class qa0 extends q2{constructor(){super({entityType:"site-content",schema:Aj,frontmatterSchema:la})}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 rGA=new qa0;HA();var na=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")}),gMQ=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 dGA{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,Q){let w=this.context.logger.child("SiteContentOperations"),B=await this.fetchRoutes(),x=B;if(A.routeId){if(x=B.filter((u)=>u.id===A.routeId),x.length===0)throw Error(`Route not found: ${A.routeId}`)}let I=[];for(let u of x)for(let K of u.sections){if(A.sectionId&&K.id!==A.sectionId)continue;if(K.content){w.debug("Section has static content, skipping",{routeId:u.id,sectionId:K.id});continue}if(K.template){let F=this.context.templates.getCapabilities(K.template);if(!F){w.warn("Template not found, skipping section",{routeId:u.id,sectionId:K.id,templateName:K.template});continue}if(!F.canGenerate){w.debug("Template doesn't support generation, skipping",{routeId:u.id,sectionId:K.id,templateName:K.template,capabilities:F});continue}}else{w.debug("Section has no template, skipping",{routeId:u.id,sectionId:K.id});continue}if(!A.force&&!A.dryRun){let F=`${u.id}:${K.id}`;if(await this.context.entityService.getEntity("site-content",F)){w.debug("Content already exists, skipping",{routeId:u.id,sectionId:K.id});continue}}I.push({route:u,section:K})}let $=I.length;if(A.dryRun)return{jobs:[],totalSections:$,queuedSections:$,batchId:`dry-run-${Date.now()}`};let c=[],D=[];for(let{route:u,section:K}of I){let F=`${u.id}:${K.id}`,Z=K.template,J={routeId:u.id,sectionId:K.id,entityId:F,entityType:"site-content",templateName:Z,context:{prompt:typeof K.content==="string"?K.content:void 0,data:{routeId:u.id,sectionId:K.id,routeTitle:u.title,routeDescription:u.description,sectionContent:K.content},conversationId:"system"},siteConfig:f};D.push({type:"shell:content-generation",data:J})}if(D.length>0){let u=this.createJobOptions(Q,"site:content-generation"),K=await this.context.jobs.enqueueBatch(D,u);for(let F=0;F<I.length;F++){let Z=I[F];if(Z)c.push({jobId:`${K}-${F}`,routeId:Z.route.id,sectionId:Z.section.id})}return{jobs:c,totalSections:$,queuedSections:c.length,batchId:K}}return{jobs:[],totalSections:$,queuedSections:0,batchId:`empty-${Date.now()}`}}}class oGA{siteConfig;operations;constructor(A,f){this.siteConfig=f;this.operations=new dGA(A)}async generateContent(A,f){let Q=na.parse(A);return this.operations.generate(Q,this.siteConfig,f)}}B0();function Ca0(A,f){return[Tf(f,"generate","Generate content for all routes, a specific route, or a specific section",na,async(Q,w)=>{let B=A();if(!B)return{success:!1,error:"Site content service not initialized"};if(Q.sectionId&&!Q.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let x={rootJobId:`generate-${Date.now()}`,progressToken:w.progressToken,pluginId:f,operationType:"content_operations",interfaceType:w.interfaceType,channelId:w.channelId},I=await B.generateContent(Q,x);return{success:!0,message:`Generated ${I.queuedSections} of ${I.totalSections} sections. ${I.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:I.batchId,jobsQueued:I.queuedSections,totalSections:I.totalSections,jobs:I.jobs}}})]}var _a0={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.0",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 aGA extends mw{siteContentService;constructor(){super("site-content",_a0,{},X.object({}))}async onRegister(A){A.entities.register("site-content",Aj,rGA),this.siteContentService=new oGA(A)}async getTools(){return Ca0(()=>this.siteContentService,this.id)}}function fj(){return new aGA}B0();HA();tf();HA();B0();var Va0=X.enum(["available","early access","coming soon","planned"]),Ma0=X.object({title:X.string(),description:X.string()}),oY=X.object({name:X.string(),availability:Va0,order:X.number()}),pa=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(Ma0).min(1).max(6),story:X.string()}),dn2=oY.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),yN=X2.extend({entityType:X.literal("product"),metadata:dn2}),ra=yN.extend({frontmatter:oY,body:pa,labels:X.record(X.string(),X.string())}),da=ra.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional()});B0();HA();HA();class lN extends ff{constructor(){super(pa,{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 sGA extends q2{constructor(){super({entityType:"product",schema:yN,frontmatterSchema:oY,bodyFormatter:new lN})}toMarkdown(A){let f=this.extractBody(A.content);try{let Q=this.parseFrontMatter(A.content,oY);return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,oY),Q=w2(f.name);return{content:A,entityType:"product",metadata:{name:f.name,slug:Q,availability:f.availability,order:f.order}}}}var oa=new sGA;HA();B0();var Oa0=X.object({title:X.string(),description:X.string()}),ja0=X.object({title:X.string(),description:X.string()}),on2=X.object({title:X.string(),description:X.string()}),Ra0=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),aY=X.object({headline:X.string(),tagline:X.string()}),an2=X.object({title:X.string(),description:X.string()}),aa=X.object({vision:X.string(),pillars:X.array(Oa0).min(1).max(6),approach:X.array(an2).min(1).max(6),productsIntro:X.string(),technologies:X.array(on2).min(1).max(6),benefits:X.array(ja0).min(1).max(6),cta:Ra0}),Pa0=aY.pick({headline:!0}).extend({slug:X.string()}),nN=X2.extend({entityType:X.literal("products-overview"),metadata:Pa0}),Qj=nN.extend({frontmatter:aY,body:aa,labels:X.record(X.string(),X.string())});B0();HA();HA();class pN extends ff{constructor(){super(aa,{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 tGA extends q2{constructor(){super({entityType:"products-overview",schema:nN,frontmatterSchema:aY,bodyFormatter:new pN})}toMarkdown(A){let f=this.extractBody(A.content);try{let Q=this.parseFrontMatter(A.content,aY);return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,aY),Q=w2(f.headline);return{content:A,entityType:"products-overview",metadata:{headline:f.headline,slug:Q}}}}var eGA=new tGA;B0();HA();var sn2=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function ga0(A,f){let Q=H2(A.content,oY),w=f.parse(Q.content),B=f.getLabels();return ra.parse({...A,frontmatter:Q.metadata,body:w,labels:B})}function ia0(A,f){let Q=H2(A.content,aY),w=f.parse(Q.content),B=f.getLabels();return Qj.parse({...A,frontmatter:Q.metadata,body:w,labels:B})}class sa{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new pN;productFormatter=new lN;constructor(A){this.logger=A;this.logger.debug("ProductsDataSource initialized")}async fetch(A,f,Q){let w=sn2.parse(A),B=Q.entityService;if(w.entityType==="products-overview"){let D=(await B.listEntities("products-overview",{limit:1}))[0];if(!D)throw Error("Products overview entity not found");let u=ia0(D,this.overviewFormatter);return f.parse(u)}if(w.query?.id){let D=(await B.listEntities("product",{filter:{metadata:{slug:w.query.id}},limit:1}))[0];if(!D)throw Error(`Product not found: ${w.query.id}`);return f.parse({product:ga0(D,this.productFormatter)})}let[x,I]=await Promise.all([B.listEntities("products-overview",{limit:1}),B.listEntities("product",{sortFields:[{field:"order",direction:"asc"}]})]),$=x[0];if(!$)throw Error("Products overview entity not found");return f.parse({overview:ia0($,this.overviewFormatter),products:I.map((c)=>ga0(c,this.productFormatter))})}}import{jsxDEV as y0,Fragment as Ap2}from"preact/jsx-dev-runtime";var Ta0=({overview:A,products:f})=>{let{frontmatter:Q,body:w,labels:B}=A;return y0(Ap2,{children:[y0(p2,{title:Q.headline,description:Q.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:`
|
|
26546
|
+
`;var ya=Ea0;import{join as nn2}from"path";var ha0=["prompt","note","link","wishlist","topics","directory-sync","agents","mcp","discord","a2a"],ba0=[...ha0,"image","dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder","webserver"],pn2=[...ba0,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],La0=OU({name:"rover",version:"0.1.0",model:"gpt-5.4-mini",site:eO,theme:ya,presets:{core:ha0,default:ba0,full:pn2},evalDisable:["discord","webserver","mcp","analytics","dashboard"],capabilities:[["prompt",ZW,void 0],["image",iq,void 0],["dashboard",SO,void 0],["blog",xWA,{}],["series",YWA,void 0],["decks",bO,void 0],["note",KW,{}],["link",FW,{}],["portfolio",SWA,{}],["topics",Ua,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",UGA,{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",PO,{autoGenerateOnBlogPublish:!0}],["newsletter",go0,{doubleOptIn:!0}],["obsidian-vault",bGA,{autoSync:!0}],["wishlist",La,{}],["stock-photo",RGA,{}],["agents",ia,void 0],["directory-sync",VZ,{seedContent:!0,seedContentPath:nn2(import.meta.dir,"..","seed-content"),initialSync:!0}],["analytics",za,{}],["site-info",xW,void 0],["site-builder",uW,{cms:{}}]],interfaces:[["mcp",rU,()=>({})],["discord",LH,()=>({})],["webserver",qH,()=>({})],["a2a",Cz,()=>({})]],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"}}});e3();B0();HA();HA();B0();var la=X.object({routeId:X.string(),sectionId:X.string()}),Aj=X2.extend({entityType:X.literal("site-content"),template:X.string().optional(),content:X.string(),metadata:la});B0();class qa0 extends q2{constructor(){super({entityType:"site-content",schema:Aj,frontmatterSchema:la})}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 rGA=new qa0;HA();var na=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")}),gMQ=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 dGA{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,Q){let w=this.context.logger.child("SiteContentOperations"),B=await this.fetchRoutes(),x=B;if(A.routeId){if(x=B.filter((u)=>u.id===A.routeId),x.length===0)throw Error(`Route not found: ${A.routeId}`)}let I=[];for(let u of x)for(let K of u.sections){if(A.sectionId&&K.id!==A.sectionId)continue;if(K.content){w.debug("Section has static content, skipping",{routeId:u.id,sectionId:K.id});continue}if(K.template){let F=this.context.templates.getCapabilities(K.template);if(!F){w.warn("Template not found, skipping section",{routeId:u.id,sectionId:K.id,templateName:K.template});continue}if(!F.canGenerate){w.debug("Template doesn't support generation, skipping",{routeId:u.id,sectionId:K.id,templateName:K.template,capabilities:F});continue}}else{w.debug("Section has no template, skipping",{routeId:u.id,sectionId:K.id});continue}if(!A.force&&!A.dryRun){let F=`${u.id}:${K.id}`;if(await this.context.entityService.getEntity("site-content",F)){w.debug("Content already exists, skipping",{routeId:u.id,sectionId:K.id});continue}}I.push({route:u,section:K})}let $=I.length;if(A.dryRun)return{jobs:[],totalSections:$,queuedSections:$,batchId:`dry-run-${Date.now()}`};let c=[],D=[];for(let{route:u,section:K}of I){let F=`${u.id}:${K.id}`,Z=K.template,J={routeId:u.id,sectionId:K.id,entityId:F,entityType:"site-content",templateName:Z,context:{prompt:typeof K.content==="string"?K.content:void 0,data:{routeId:u.id,sectionId:K.id,routeTitle:u.title,routeDescription:u.description,sectionContent:K.content},conversationId:"system"},siteConfig:f};D.push({type:"shell:content-generation",data:J})}if(D.length>0){let u=this.createJobOptions(Q,"site:content-generation"),K=await this.context.jobs.enqueueBatch(D,u);for(let F=0;F<I.length;F++){let Z=I[F];if(Z)c.push({jobId:`${K}-${F}`,routeId:Z.route.id,sectionId:Z.section.id})}return{jobs:c,totalSections:$,queuedSections:c.length,batchId:K}}return{jobs:[],totalSections:$,queuedSections:0,batchId:`empty-${Date.now()}`}}}class oGA{siteConfig;operations;constructor(A,f){this.siteConfig=f;this.operations=new dGA(A)}async generateContent(A,f){let Q=na.parse(A);return this.operations.generate(Q,this.siteConfig,f)}}B0();function Ca0(A,f){return[Tf(f,"generate","Generate content for all routes, a specific route, or a specific section",na,async(Q,w)=>{let B=A();if(!B)return{success:!1,error:"Site content service not initialized"};if(Q.sectionId&&!Q.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let x={rootJobId:`generate-${Date.now()}`,progressToken:w.progressToken,pluginId:f,operationType:"content_operations",interfaceType:w.interfaceType,channelId:w.channelId},I=await B.generateContent(Q,x);return{success:!0,message:`Generated ${I.queuedSections} of ${I.totalSections} sections. ${I.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:I.batchId,jobsQueued:I.queuedSections,totalSections:I.totalSections,jobs:I.jobs}}})]}var _a0={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.1",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 aGA extends mw{siteContentService;constructor(){super("site-content",_a0,{},X.object({}))}async onRegister(A){A.entities.register("site-content",Aj,rGA),this.siteContentService=new oGA(A)}async getTools(){return Ca0(()=>this.siteContentService,this.id)}}function fj(){return new aGA}B0();HA();tf();HA();B0();var Va0=X.enum(["available","early access","coming soon","planned"]),Ma0=X.object({title:X.string(),description:X.string()}),oY=X.object({name:X.string(),availability:Va0,order:X.number()}),pa=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(Ma0).min(1).max(6),story:X.string()}),dn2=oY.pick({name:!0,availability:!0,order:!0}).extend({slug:X.string()}),yN=X2.extend({entityType:X.literal("product"),metadata:dn2}),ra=yN.extend({frontmatter:oY,body:pa,labels:X.record(X.string(),X.string())}),da=ra.extend({url:X.string().optional(),typeLabel:X.string().optional(),listUrl:X.string().optional(),listLabel:X.string().optional()});B0();HA();HA();class lN extends ff{constructor(){super(pa,{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 sGA extends q2{constructor(){super({entityType:"product",schema:yN,frontmatterSchema:oY,bodyFormatter:new lN})}toMarkdown(A){let f=this.extractBody(A.content);try{let Q=this.parseFrontMatter(A.content,oY);return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,oY),Q=w2(f.name);return{content:A,entityType:"product",metadata:{name:f.name,slug:Q,availability:f.availability,order:f.order}}}}var oa=new sGA;HA();B0();var Oa0=X.object({title:X.string(),description:X.string()}),ja0=X.object({title:X.string(),description:X.string()}),on2=X.object({title:X.string(),description:X.string()}),Ra0=X.object({heading:X.string(),buttonText:X.string(),link:X.string()}),aY=X.object({headline:X.string(),tagline:X.string()}),an2=X.object({title:X.string(),description:X.string()}),aa=X.object({vision:X.string(),pillars:X.array(Oa0).min(1).max(6),approach:X.array(an2).min(1).max(6),productsIntro:X.string(),technologies:X.array(on2).min(1).max(6),benefits:X.array(ja0).min(1).max(6),cta:Ra0}),Pa0=aY.pick({headline:!0}).extend({slug:X.string()}),nN=X2.extend({entityType:X.literal("products-overview"),metadata:Pa0}),Qj=nN.extend({frontmatter:aY,body:aa,labels:X.record(X.string(),X.string())});B0();HA();HA();class pN extends ff{constructor(){super(aa,{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 tGA extends q2{constructor(){super({entityType:"products-overview",schema:nN,frontmatterSchema:aY,bodyFormatter:new pN})}toMarkdown(A){let f=this.extractBody(A.content);try{let Q=this.parseFrontMatter(A.content,aY);return this.buildMarkdown(f,Q)}catch{return f}}fromMarkdown(A){let f=this.parseFrontMatter(A,aY),Q=w2(f.headline);return{content:A,entityType:"products-overview",metadata:{headline:f.headline,slug:Q}}}}var eGA=new tGA;B0();HA();var sn2=X.object({entityType:X.string(),query:X.object({id:X.string().optional()}).optional()});function ga0(A,f){let Q=H2(A.content,oY),w=f.parse(Q.content),B=f.getLabels();return ra.parse({...A,frontmatter:Q.metadata,body:w,labels:B})}function ia0(A,f){let Q=H2(A.content,aY),w=f.parse(Q.content),B=f.getLabels();return Qj.parse({...A,frontmatter:Q.metadata,body:w,labels:B})}class sa{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new pN;productFormatter=new lN;constructor(A){this.logger=A;this.logger.debug("ProductsDataSource initialized")}async fetch(A,f,Q){let w=sn2.parse(A),B=Q.entityService;if(w.entityType==="products-overview"){let D=(await B.listEntities("products-overview",{limit:1}))[0];if(!D)throw Error("Products overview entity not found");let u=ia0(D,this.overviewFormatter);return f.parse(u)}if(w.query?.id){let D=(await B.listEntities("product",{filter:{metadata:{slug:w.query.id}},limit:1}))[0];if(!D)throw Error(`Product not found: ${w.query.id}`);return f.parse({product:ga0(D,this.productFormatter)})}let[x,I]=await Promise.all([B.listEntities("products-overview",{limit:1}),B.listEntities("product",{sortFields:[{field:"order",direction:"asc"}]})]),$=x[0];if(!$)throw Error("Products overview entity not found");return f.parse({overview:ia0($,this.overviewFormatter),products:I.map((c)=>ga0(c,this.productFormatter))})}}import{jsxDEV as y0,Fragment as Ap2}from"preact/jsx-dev-runtime";var Ta0=({overview:A,products:f})=>{let{frontmatter:Q,body:w,labels:B}=A;return y0(Ap2,{children:[y0(p2,{title:Q.headline,description:Q.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:`
|
|
26547
26547
|
@keyframes wave-drift {
|
|
26548
26548
|
from { transform: translateX(0); }
|
|
26549
26549
|
to { transform: translateX(-50%); }
|
|
@@ -26571,7 +26571,7 @@ ${I}`;try{await A.entityService.createEntity({id:$,entityType:"topic",content:c,
|
|
|
26571
26571
|
@media (prefers-reduced-motion: reduce) {
|
|
26572
26572
|
.detail-wave { animation: none; }
|
|
26573
26573
|
}
|
|
26574
|
-
`},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(kx,{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:Q.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:w.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:Q.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:w.role},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:Q.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:w.purpose},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:Q.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:w.audience},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:Q.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:w.values},void 0,!1,void 0,this),M1(M9,{tags:Q.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:w.features},void 0,!1,void 0,this),M1("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-16",children:Q.features.map(($,c)=>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(c+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:$.title},void 0,!1,void 0,this),M1("p",{className:"text-white/70 leading-relaxed",children:$.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},$.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:w.story},void 0,!1,void 0,this),M1("div",{className:"space-y-6",children:I.map(($,c)=>M1("p",{className:c===0?"text-2xl md:text-3xl leading-relaxed text-heading font-light":"text-lg leading-relaxed text-theme-muted",children:$},c,!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:Q.tagline},void 0,!1,void 0,this),M1("p",{className:"text-lg text-white/60 mb-10 max-w-xl",children:Q.promise},void 0,!1,void 0,this),M1(h8,{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)};HA();var AJA=X.object({route:X.string().default("/products")});var Sa0={name:"@brains/products",private:!0,version:"0.2.0-alpha.
|
|
26574
|
+
`},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(kx,{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:Q.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:w.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:Q.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:w.role},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:Q.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:w.purpose},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:Q.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:w.audience},void 0,!1,void 0,this),M1("p",{className:"text-lg leading-relaxed text-theme-muted",children:Q.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:w.values},void 0,!1,void 0,this),M1(M9,{tags:Q.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:w.features},void 0,!1,void 0,this),M1("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-16",children:Q.features.map(($,c)=>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(c+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:$.title},void 0,!1,void 0,this),M1("p",{className:"text-white/70 leading-relaxed",children:$.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},$.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:w.story},void 0,!1,void 0,this),M1("div",{className:"space-y-6",children:I.map(($,c)=>M1("p",{className:c===0?"text-2xl md:text-3xl leading-relaxed text-heading font-light":"text-lg leading-relaxed text-theme-muted",children:$},c,!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:Q.tagline},void 0,!1,void 0,this),M1("p",{className:"text-lg text-white/60 mb-10 max-w-xl",children:Q.promise},void 0,!1,void 0,this),M1(h8,{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)};HA();var AJA=X.object({route:X.string().default("/products")});var Sa0={name:"@brains/products",private:!0,version:"0.2.0-alpha.1",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 wp2=X.object({overview:Qj,products:X.array(da)}),Bp2=X.object({product:da});class fJA extends zf{entityType=oa.entityType;schema=yN;adapter=oa;constructor(A={}){super("products",Sa0,A,AJA)}getTemplates(){return{"product-list":a0({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:wp2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:Ta0}}),"product-detail":a0({name:"product-detail",description:"Individual product detail page",schema:Bp2,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:ma0}})}}getDataSources(){return[new sa(this.logger.child("ProductsDataSource"))]}async onRegister(A){A.entities.register("products-overview",nN,eGA)}}function QJA(A={}){return new fJA(A)}import{join as Sp2}from"path";var ya0=`/*
|
|
26575
26575
|
* Shared globals + helpers used by tree / constellation / roots canvas
|
|
26576
26576
|
* scripts. Concatenated in front of each variant canvas at site-package
|
|
26577
26577
|
* load time (see sites/rizom/src/index.ts) so the variant canvases
|
|
@@ -28955,7 +28955,7 @@ Your task is to:
|
|
|
28955
28955
|
2. Generate a clear, natural summary that captures key points, decisions, and action items
|
|
28956
28956
|
3. Return structured data in the required JSON format
|
|
28957
28957
|
|
|
28958
|
-
Be concise but comprehensive, focusing on the most important information.`});B0();HA();var dp2=X.object({entityType:X.literal("summary"),query:X.object({id:X.string().optional(),conversationId:X.string().optional(),limit:X.number().optional()}).optional()});class YJA{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 VD,this.logger.debug("SummaryDataSource initialized")}async fetch(A,f,Q){let w=dp2.parse(A),B=Q.entityService,x=w.query?.conversationId??w.query?.id;if(x){let D=await B.getEntity(w.query?.conversationId?"summary":w.entityType,x);if(!D)throw Error(`Summary not found: ${x}`);let u;try{let F=H2(D.content,X.record(X.string(),X.unknown()));u=this.adapter.parseEntriesFromContent(F.content)}catch{u=this.adapter.parseEntriesFromContent(D.content)}let K={conversationId:D.metadata.conversationId,channelName:D.metadata.channelName,entries:u,totalMessages:D.metadata.totalMessages,entryCount:u.length,updated:D.updated};return f.parse(K)}let $=(await B.listEntities(w.entityType,{limit:w.query?.limit??100})).map((D)=>{let u;try{let F=H2(D.content,X.record(X.string(),X.unknown()));u=this.adapter.parseEntriesFromContent(F.content)}catch{u=this.adapter.parseEntriesFromContent(D.content)}let K=u[0];return{id:D.id,conversationId:D.metadata.conversationId,channelName:D.metadata.channelName,entryCount:u.length,totalMessages:D.metadata.totalMessages,latestEntry:K?.title??"No entries",updated:D.updated,created:D.created}}),c={summaries:$,totalCount:$.length};return this.logger.debug("Creating list data",{summaryCount:$.length,firstSummary:$[0]?.id}),f.parse(c)}}var Os0={name:"@brains/summary",private:!0,version:"0.2.0-alpha.
|
|
28958
|
+
Be concise but comprehensive, focusing on the most important information.`});B0();HA();var dp2=X.object({entityType:X.literal("summary"),query:X.object({id:X.string().optional(),conversationId:X.string().optional(),limit:X.number().optional()}).optional()});class YJA{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 VD,this.logger.debug("SummaryDataSource initialized")}async fetch(A,f,Q){let w=dp2.parse(A),B=Q.entityService,x=w.query?.conversationId??w.query?.id;if(x){let D=await B.getEntity(w.query?.conversationId?"summary":w.entityType,x);if(!D)throw Error(`Summary not found: ${x}`);let u;try{let F=H2(D.content,X.record(X.string(),X.unknown()));u=this.adapter.parseEntriesFromContent(F.content)}catch{u=this.adapter.parseEntriesFromContent(D.content)}let K={conversationId:D.metadata.conversationId,channelName:D.metadata.channelName,entries:u,totalMessages:D.metadata.totalMessages,entryCount:u.length,updated:D.updated};return f.parse(K)}let $=(await B.listEntities(w.entityType,{limit:w.query?.limit??100})).map((D)=>{let u;try{let F=H2(D.content,X.record(X.string(),X.unknown()));u=this.adapter.parseEntriesFromContent(F.content)}catch{u=this.adapter.parseEntriesFromContent(D.content)}let K=u[0];return{id:D.id,conversationId:D.metadata.conversationId,channelName:D.metadata.channelName,entryCount:u.length,totalMessages:D.metadata.totalMessages,latestEntry:K?.title??"No entries",updated:D.updated,created:D.created}}),c={summaries:$,totalCount:$.length};return this.logger.debug("Creating list data",{summaryCount:$.length,firstSummary:$[0]?.id}),f.parse(c)}}var Os0={name:"@brains/summary",private:!0,version:"0.2.0-alpha.1",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 ap2=new VD;class uJA extends zf{entityType="summary";schema=wj;adapter=ap2;digestHandler=null;constructor(A){super("summary",Os0,A??{},$JA)}getConfig(){return this.config}getTemplates(){return{"summary-list":_s0,"summary-detail":Vs0,"ai-response":Ms0}}getDataSources(){return[new YJA(this.logger)]}async onRegister(A){if(this.digestHandler=tY.getInstance(A,this.logger),this.config.enableAutoSummary)A.messaging.subscribe("conversation:digest",async(f)=>{let Q=hg.parse(f.payload);return await this.handleDigestMessage({...f,payload:Q}),{success:!0}}),this.logger.debug("Summary plugin subscribed to digest events")}async derive(A,f,Q){}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:v0(f)})}}}function UJA(A){return new uJA(A)}var js0=["prompt","directory-sync","note","link","topics","agents","mcp","discord","a2a"],tp2=[...js0,"image","site-info","site-content","site-builder","webserver"],Rs0=OU({name:"relay",version:"0.1.0",model:"gpt-5.4-mini",site:oN,theme:aN,presets:{core:js0,default:tp2},evalDisable:["webserver","discord"],capabilities:[["prompt",ZW,void 0],["note",KW,{}],["link",FW,{}],["image",iq,void 0],["topics",Ua,{}],["summary",UJA,{}],["decks",bO,void 0],["agents",ia,void 0],["directory-sync",VZ,{seedContent:!0,seedContentPath:sp2(import.meta.dir,"..","seed-content"),initialSync:!0}],["site-content",fj,void 0],["site-info",xW,void 0],["site-builder",uW,{}]],interfaces:[["mcp",rU,()=>({})],["discord",LH,()=>({captureUrls:!0})],["a2a",Cz,()=>({})],["webserver",qH,()=>({})]],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 Za2}from"fs";import{join as Wa2}from"path";import{execSync as Ga2}from"child_process";import{parseArgs as fr2}from"util";var Qr2={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 eY(A,f){let Q=A[f];return typeof Q==="string"?Q:void 0}function sN(A,f){let Q=A[f];return typeof Q==="boolean"?Q:void 0}function Ps0(A){let{values:f,positionals:Q}=fr2({args:A,options:Qr2,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:Q[0]??"help",args:Q.slice(1),flags:{model:eY(f,"model"),domain:eY(f,"domain"),"content-repo":eY(f,"content-repo"),backend:eY(f,"backend"),"push-to":eY(f,"push-to"),"ai-api-key":eY(f,"ai-api-key"),"no-interactive":sN(f,"no-interactive"),preview:sN(f,"preview"),deploy:sN(f,"deploy"),regen:sN(f,"regen"),all:sN(f,"all"),only:eY(f,"only"),"dry-run":sN(f,"dry-run"),remote:eY(f,"remote"),token:eY(f,"token")}}}import{mkdirSync as Qa2}from"fs";import{join as wa2}from"path";import{spawn as Ba2,execSync as xa2}from"child_process";var Us={name:"@rizom/brain",version:"0.2.0-alpha.1",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"],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 ms0,writeFileSync as Ks,chmodSync as Fs,existsSync as Ss0,readFileSync as XJA}from"fs";import{basename as ZJA,dirname as WJA,join as tw,resolve as kr2}from"path";import{fileURLToPath as zr2}from"url";Ij();import{existsSync as gs0,readFileSync as cr2}from"fs";import{dirname as Dr2,join as is0}from"path";var Hs={rover:`# This env file uses @env-spec - see https://varlock.dev/env-spec for more info
|
|
28959
28959
|
#
|
|
28960
28960
|
# @defaultRequired=false @defaultSensitive=false
|
|
28961
28961
|
# ----------
|