@rizom/brain 0.2.0-alpha.128 → 0.2.0-alpha.129
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 +37 -37
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/site.js +4 -4
- package/dist/site.js.map +1 -1
- package/package.json +1 -1
package/dist/brain.js
CHANGED
|
@@ -542,7 +542,7 @@ Some entity actions are gated by policy beyond simple tool availability. Two cas
|
|
|
542
542
|
hash text NOT NULL,
|
|
543
543
|
created_at numeric
|
|
544
544
|
)
|
|
545
|
-
`;await A.session.run($);let f=(await A.values(g0`SELECT id, hash, created_at FROM ${g0.identifier(w)} ORDER BY created_at DESC LIMIT 1`))[0]??void 0,Y=[];for(let X of B)if(!f||Number(f[2])<X.folderMillis){for(let H of X.sql)Y.push(A.run(g0.raw(H)));Y.push(A.run(g0`INSERT INTO ${g0.identifier(w)} ("hash", "created_at") VALUES(${X.hash}, ${X.folderMillis})`))}await A.session.migrate(Y)}var Wu=i(()=>{LIA();l$()});async function bIA(A,Q){let B=Q?.child("entity-migrate")??e2.getInstance().child("entity-migrate"),{db:w,client:$,url:D}=Je(A);B.debug("Running entity database migrations...");try{await Le($,D);let Y=import.meta.url.includes("/dist/")?new URL("./migrations/entity-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),await be($),B.debug("Entity database migrations completed successfully")}catch(f){throw B.error("Entity database migration failed:",f),f}finally{$.close()}}var NIA=i(()=>{Wu();AU0();K0()});async function jIA(A,Q){let B=Q?.child("job-queue-migrate")??e2.getInstance().child("job-queue-migrate"),{db:w,client:$,url:D}=Fe(A);B.debug("Running job queue migrations...");try{await Ie($,D);let Y=import.meta.url.includes("/dist/")?new URL("./migrations/job-queue",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),B.debug("Job queue migrations completed successfully")}catch(f){throw B.error("Job queue migration failed:",f),f}finally{$.close()}}var _IA=i(()=>{Wu();pK0();K0()});async function MIA(A,Q){let B=Q?.child("conversation-migrate")??e2.getInstance().child("conversation-migrate"),{db:w,client:$,url:D}=Ce(A);B.debug("Running conversation database migrations...");try{if(D.startsWith("file:"))await $.execute("PRAGMA journal_mode = WAL");let Y=import.meta.url.includes("/dist/")?new URL("./migrations/conversation-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),B.debug("Conversation database migrations completed successfully")}catch(f){throw B.error("Conversation database migration failed:",f),f}finally{$.close()}}var PIA=i(()=>{Wu();uU0();K0()});async function kIA(A,Q){let B=Q?.child("runtime-state-migrate")??e2.getInstance().child("runtime-state-migrate"),{db:w,client:$,url:D}=V10(A);B.debug("Running runtime state migrations...");try{await J10($,D);let Y=import.meta.url.includes("/dist/")?new URL("./migrations/runtime-state",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),B.debug("Runtime state migrations completed successfully")}catch(f){throw B.error("Runtime state migration failed:",f),f}finally{$.close()}}var OIA=i(()=>{Wu();K0();FL0()});class Zu{logger;migrations;constructor(A,Q){this.logger=A,this.migrations=Q??{getStandardConfigWithDirectories:CS,migrateEntities:bIA,migrateJobQueue:jIA,migrateConversations:MIA,migrateRuntimeState:kIA}}async runAllMigrations(A){this.logger.debug("Running database migrations...");let Q=await this.migrations.getStandardConfigWithDirectories();if(A?.database)Q.database.url=A.database;if(A?.jobQueueDatabase)Q.jobQueueDatabase.url=A.jobQueueDatabase;if(A?.conversationDatabase)Q.conversationDatabase.url=A.conversationDatabase;if(A?.runtimeStateDatabase)Q.runtimeStateDatabase.url=A.runtimeStateDatabase;await this.migrateEntityDatabase(Q),await this.migrateJobQueueDatabase(Q),await this.migrateConversationDatabase(Q),await this.migrateRuntimeStateDatabase(Q),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)}async migrateRuntimeStateDatabase(A){this.logger.debug("Running runtime state database migrations..."),await this.migrations.migrateRuntimeState({url:A.runtimeStateDatabase.url,...A.runtimeStateDatabase.authToken&&{authToken:A.runtimeStateDatabase.authToken}},this.logger)}}var gL0=i(()=>{k10();NIA();_IA();PIA();OIA()});function tx2(){return process.env[ax2]}function xIA(){return tx2()!=="production"}var ax2="NODE_ENV";var x10;var TL0=i(()=>{K0();x10=K.object({theme:K.object({primaryColor:K.string().describe("Primary color for the CLI theme").default("#0066cc"),accentColor:K.string().describe("Accent color for the CLI theme").default("#ff6600")}).describe("Theme configuration for the CLI interface").default({primaryColor:"#0066cc",accentColor:"#ff6600"})})});var vIA;var RIA=i(()=>{vIA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.128",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.2.6"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/react":"^19.0.3",typescript:"^5.3.3"}}});var WB=O((AR2,R10)=>{(function(){function A(Y0,u0){Object.defineProperty(w.prototype,Y0,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",u0[0],u0[1])}})}function Q(Y0){if(Y0===null||typeof Y0!=="object")return null;return Y0=C0&&Y0[C0]||Y0["@@iterator"],typeof Y0==="function"?Y0:null}function B(Y0,u0){Y0=(Y0=Y0.constructor)&&(Y0.displayName||Y0.name)||"ReactClass";var R0=Y0+"."+u0;G0[R0]||(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.",u0,Y0),G0[R0]=!0)}function w(Y0,u0,R0){this.props=Y0,this.context=u0,this.refs=l0,this.updater=R0||J0}function $(){}function D(Y0,u0,R0){this.props=Y0,this.context=u0,this.refs=l0,this.updater=R0||J0}function f(){}function Y(Y0){return""+Y0}function X(Y0){try{Y(Y0);var u0=!1}catch(zA){u0=!0}if(u0){u0=console;var R0=u0.error,n0=typeof Symbol==="function"&&Symbol.toStringTag&&Y0[Symbol.toStringTag]||Y0.constructor.name||"Object";return R0.call(u0,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n0),Y(Y0)}}function H(Y0){if(Y0==null)return null;if(typeof Y0==="function")return Y0.$$typeof===YA?null:Y0.displayName||Y0.name||null;if(typeof Y0==="string")return Y0;switch(Y0){case A0:return"Fragment";case Z0:return"Profiler";case n:return"StrictMode";case DA:return"Suspense";case f0:return"SuspenseList";case z0:return"Activity"}if(typeof Y0==="object")switch(typeof Y0.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),Y0.$$typeof){case l:return"Portal";case $0:return Y0.displayName||"Context";case I0:return(Y0._context.displayName||"Context")+".Consumer";case i0:var u0=Y0.render;return Y0=Y0.displayName,Y0||(Y0=u0.displayName||u0.name||"",Y0=Y0!==""?"ForwardRef("+Y0+")":"ForwardRef"),Y0;case M0:return u0=Y0.displayName||null,u0!==null?u0:H(Y0.type)||"Memo";case x0:u0=Y0._payload,Y0=Y0._init;try{return H(Y0(u0))}catch(R0){}}return null}function W(Y0){if(Y0===A0)return"<>";if(typeof Y0==="object"&&Y0!==null&&Y0.$$typeof===x0)return"<...>";try{var u0=H(Y0);return u0?"<"+u0+">":"<...>"}catch(R0){return"<...>"}}function Z(){var Y0=wA.A;return Y0===null?null:Y0.getOwner()}function G(){return Error("react-stack-top-frame")}function F(Y0){if(k0.call(Y0,"key")){var u0=Object.getOwnPropertyDescriptor(Y0,"key").get;if(u0&&u0.isReactWarning)return!1}return Y0.key!==void 0}function I(Y0,u0){function R0(){H0||(H0=!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)",u0))}R0.isReactWarning=!0,Object.defineProperty(Y0,"key",{get:R0,configurable:!0})}function L(){var Y0=H(this.type);return Q1[Y0]||(Q1[Y0]=!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.")),Y0=this.props.ref,Y0!==void 0?Y0:null}function b(Y0,u0,R0,n0,zA,_A){var $A=R0.ref;return Y0={$$typeof:p,type:Y0,key:u0,props:R0,_owner:n0},($A!==void 0?$A:null)!==null?Object.defineProperty(Y0,"ref",{enumerable:!1,get:L}):Object.defineProperty(Y0,"ref",{enumerable:!1,value:null}),Y0._store={},Object.defineProperty(Y0._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(Y0,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(Y0,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:zA}),Object.defineProperty(Y0,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:_A}),Object.freeze&&(Object.freeze(Y0.props),Object.freeze(Y0)),Y0}function N(Y0,u0){return u0=b(Y0.type,u0,Y0.props,Y0._owner,Y0._debugStack,Y0._debugTask),Y0._store&&(u0._store.validated=Y0._store.validated),u0}function M(Y0){j(Y0)?Y0._store&&(Y0._store.validated=1):typeof Y0==="object"&&Y0!==null&&Y0.$$typeof===x0&&(Y0._payload.status==="fulfilled"?j(Y0._payload.value)&&Y0._payload.value._store&&(Y0._payload.value._store.validated=1):Y0._store&&(Y0._store.validated=1))}function j(Y0){return typeof Y0==="object"&&Y0!==null&&Y0.$$typeof===p}function g(Y0){var u0={"=":"=0",":":"=2"};return"$"+Y0.replace(/[=:]/g,function(R0){return u0[R0]})}function E(Y0,u0){return typeof Y0==="object"&&Y0!==null&&Y0.key!=null?(X(Y0.key),g(""+Y0.key)):u0.toString(36)}function y(Y0){switch(Y0.status){case"fulfilled":return Y0.value;case"rejected":throw Y0.reason;default:switch(typeof Y0.status==="string"?Y0.then(f,f):(Y0.status="pending",Y0.then(function(u0){Y0.status==="pending"&&(Y0.status="fulfilled",Y0.value=u0)},function(u0){Y0.status==="pending"&&(Y0.status="rejected",Y0.reason=u0)})),Y0.status){case"fulfilled":return Y0.value;case"rejected":throw Y0.reason}}throw Y0}function h(Y0,u0,R0,n0,zA){var _A=typeof Y0;if(_A==="undefined"||_A==="boolean")Y0=null;var $A=!1;if(Y0===null)$A=!0;else switch(_A){case"bigint":case"string":case"number":$A=!0;break;case"object":switch(Y0.$$typeof){case p:case l:$A=!0;break;case x0:return $A=Y0._init,h($A(Y0._payload),u0,R0,n0,zA)}}if($A){$A=Y0,zA=zA($A);var tA=n0===""?"."+E($A,0):n0;return FA(zA)?(R0="",tA!=null&&(R0=tA.replace(y0,"$&/")+"/"),h(zA,u0,R0,"",function(l1){return l1})):zA!=null&&(j(zA)&&(zA.key!=null&&($A&&$A.key===zA.key||X(zA.key)),R0=N(zA,R0+(zA.key==null||$A&&$A.key===zA.key?"":(""+zA.key).replace(y0,"$&/")+"/")+tA),n0!==""&&$A!=null&&j($A)&&$A.key==null&&$A._store&&!$A._store.validated&&(R0._store.validated=2),zA=R0),u0.push(zA)),1}if($A=0,tA=n0===""?".":n0+":",FA(Y0))for(var gA=0;gA<Y0.length;gA++)n0=Y0[gA],_A=tA+E(n0,gA),$A+=h(n0,u0,R0,_A,zA);else if(gA=Q(Y0),typeof gA==="function")for(gA===Y0.entries&&(o0||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),o0=!0),Y0=gA.call(Y0),gA=0;!(n0=Y0.next()).done;)n0=n0.value,_A=tA+E(n0,gA++),$A+=h(n0,u0,R0,_A,zA);else if(_A==="object"){if(typeof Y0.then==="function")return h(y(Y0),u0,R0,n0,zA);throw u0=String(Y0),Error("Objects are not valid as a React child (found: "+(u0==="[object Object]"?"object with keys {"+Object.keys(Y0).join(", ")+"}":u0)+"). If you meant to render a collection of children, use an array instead.")}return $A}function T(Y0,u0,R0){if(Y0==null)return Y0;var n0=[],zA=0;return h(Y0,n0,"","",function(_A){return u0.call(R0,_A,zA++)}),n0}function S(Y0){if(Y0._status===-1){var u0=Y0._ioInfo;u0!=null&&(u0.start=u0.end=performance.now()),u0=Y0._result;var R0=u0();if(R0.then(function(zA){if(Y0._status===0||Y0._status===-1){Y0._status=1,Y0._result=zA;var _A=Y0._ioInfo;_A!=null&&(_A.end=performance.now()),R0.status===void 0&&(R0.status="fulfilled",R0.value=zA)}},function(zA){if(Y0._status===0||Y0._status===-1){Y0._status=2,Y0._result=zA;var _A=Y0._ioInfo;_A!=null&&(_A.end=performance.now()),R0.status===void 0&&(R0.status="rejected",R0.reason=zA)}}),u0=Y0._ioInfo,u0!=null){u0.value=R0;var n0=R0.displayName;typeof n0==="string"&&(u0.name=n0)}Y0._status===-1&&(Y0._status=0,Y0._result=R0)}if(Y0._status===1)return u0=Y0._result,u0===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
545
|
+
`;await A.session.run($);let f=(await A.values(g0`SELECT id, hash, created_at FROM ${g0.identifier(w)} ORDER BY created_at DESC LIMIT 1`))[0]??void 0,Y=[];for(let X of B)if(!f||Number(f[2])<X.folderMillis){for(let H of X.sql)Y.push(A.run(g0.raw(H)));Y.push(A.run(g0`INSERT INTO ${g0.identifier(w)} ("hash", "created_at") VALUES(${X.hash}, ${X.folderMillis})`))}await A.session.migrate(Y)}var Wu=i(()=>{LIA();l$()});async function bIA(A,Q){let B=Q?.child("entity-migrate")??e2.getInstance().child("entity-migrate"),{db:w,client:$,url:D}=Je(A);B.debug("Running entity database migrations...");try{await Le($,D);let Y=import.meta.url.includes("/dist/")?new URL("./migrations/entity-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),await be($),B.debug("Entity database migrations completed successfully")}catch(f){throw B.error("Entity database migration failed:",f),f}finally{$.close()}}var NIA=i(()=>{Wu();AU0();K0()});async function jIA(A,Q){let B=Q?.child("job-queue-migrate")??e2.getInstance().child("job-queue-migrate"),{db:w,client:$,url:D}=Fe(A);B.debug("Running job queue migrations...");try{await Ie($,D);let Y=import.meta.url.includes("/dist/")?new URL("./migrations/job-queue",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),B.debug("Job queue migrations completed successfully")}catch(f){throw B.error("Job queue migration failed:",f),f}finally{$.close()}}var _IA=i(()=>{Wu();pK0();K0()});async function MIA(A,Q){let B=Q?.child("conversation-migrate")??e2.getInstance().child("conversation-migrate"),{db:w,client:$,url:D}=Ce(A);B.debug("Running conversation database migrations...");try{if(D.startsWith("file:"))await $.execute("PRAGMA journal_mode = WAL");let Y=import.meta.url.includes("/dist/")?new URL("./migrations/conversation-service",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),B.debug("Conversation database migrations completed successfully")}catch(f){throw B.error("Conversation database migration failed:",f),f}finally{$.close()}}var PIA=i(()=>{Wu();uU0();K0()});async function kIA(A,Q){let B=Q?.child("runtime-state-migrate")??e2.getInstance().child("runtime-state-migrate"),{db:w,client:$,url:D}=V10(A);B.debug("Running runtime state migrations...");try{await J10($,D);let Y=import.meta.url.includes("/dist/")?new URL("./migrations/runtime-state",import.meta.url).pathname:new URL("../drizzle",import.meta.url).pathname;await YV(w,{migrationsFolder:Y}),B.debug("Runtime state migrations completed successfully")}catch(f){throw B.error("Runtime state migration failed:",f),f}finally{$.close()}}var OIA=i(()=>{Wu();K0();FL0()});class Zu{logger;migrations;constructor(A,Q){this.logger=A,this.migrations=Q??{getStandardConfigWithDirectories:CS,migrateEntities:bIA,migrateJobQueue:jIA,migrateConversations:MIA,migrateRuntimeState:kIA}}async runAllMigrations(A){this.logger.debug("Running database migrations...");let Q=await this.migrations.getStandardConfigWithDirectories();if(A?.database)Q.database.url=A.database;if(A?.jobQueueDatabase)Q.jobQueueDatabase.url=A.jobQueueDatabase;if(A?.conversationDatabase)Q.conversationDatabase.url=A.conversationDatabase;if(A?.runtimeStateDatabase)Q.runtimeStateDatabase.url=A.runtimeStateDatabase;await this.migrateEntityDatabase(Q),await this.migrateJobQueueDatabase(Q),await this.migrateConversationDatabase(Q),await this.migrateRuntimeStateDatabase(Q),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)}async migrateRuntimeStateDatabase(A){this.logger.debug("Running runtime state database migrations..."),await this.migrations.migrateRuntimeState({url:A.runtimeStateDatabase.url,...A.runtimeStateDatabase.authToken&&{authToken:A.runtimeStateDatabase.authToken}},this.logger)}}var gL0=i(()=>{k10();NIA();_IA();PIA();OIA()});function tx2(){return process.env[ax2]}function xIA(){return tx2()!=="production"}var ax2="NODE_ENV";var x10;var TL0=i(()=>{K0();x10=K.object({theme:K.object({primaryColor:K.string().describe("Primary color for the CLI theme").default("#0066cc"),accentColor:K.string().describe("Accent color for the CLI theme").default("#ff6600")}).describe("Theme configuration for the CLI interface").default({primaryColor:"#0066cc",accentColor:"#ff6600"})})});var vIA;var RIA=i(()=>{vIA={name:"@brains/chat-repl",private:!0,version:"0.2.0-alpha.129",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.2.6"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/react":"^19.0.3",typescript:"^5.3.3"}}});var WB=O((AR2,R10)=>{(function(){function A(Y0,u0){Object.defineProperty(w.prototype,Y0,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",u0[0],u0[1])}})}function Q(Y0){if(Y0===null||typeof Y0!=="object")return null;return Y0=C0&&Y0[C0]||Y0["@@iterator"],typeof Y0==="function"?Y0:null}function B(Y0,u0){Y0=(Y0=Y0.constructor)&&(Y0.displayName||Y0.name)||"ReactClass";var R0=Y0+"."+u0;G0[R0]||(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.",u0,Y0),G0[R0]=!0)}function w(Y0,u0,R0){this.props=Y0,this.context=u0,this.refs=l0,this.updater=R0||J0}function $(){}function D(Y0,u0,R0){this.props=Y0,this.context=u0,this.refs=l0,this.updater=R0||J0}function f(){}function Y(Y0){return""+Y0}function X(Y0){try{Y(Y0);var u0=!1}catch(zA){u0=!0}if(u0){u0=console;var R0=u0.error,n0=typeof Symbol==="function"&&Symbol.toStringTag&&Y0[Symbol.toStringTag]||Y0.constructor.name||"Object";return R0.call(u0,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n0),Y(Y0)}}function H(Y0){if(Y0==null)return null;if(typeof Y0==="function")return Y0.$$typeof===YA?null:Y0.displayName||Y0.name||null;if(typeof Y0==="string")return Y0;switch(Y0){case A0:return"Fragment";case Z0:return"Profiler";case n:return"StrictMode";case DA:return"Suspense";case f0:return"SuspenseList";case z0:return"Activity"}if(typeof Y0==="object")switch(typeof Y0.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),Y0.$$typeof){case l:return"Portal";case $0:return Y0.displayName||"Context";case I0:return(Y0._context.displayName||"Context")+".Consumer";case i0:var u0=Y0.render;return Y0=Y0.displayName,Y0||(Y0=u0.displayName||u0.name||"",Y0=Y0!==""?"ForwardRef("+Y0+")":"ForwardRef"),Y0;case M0:return u0=Y0.displayName||null,u0!==null?u0:H(Y0.type)||"Memo";case x0:u0=Y0._payload,Y0=Y0._init;try{return H(Y0(u0))}catch(R0){}}return null}function W(Y0){if(Y0===A0)return"<>";if(typeof Y0==="object"&&Y0!==null&&Y0.$$typeof===x0)return"<...>";try{var u0=H(Y0);return u0?"<"+u0+">":"<...>"}catch(R0){return"<...>"}}function Z(){var Y0=wA.A;return Y0===null?null:Y0.getOwner()}function G(){return Error("react-stack-top-frame")}function F(Y0){if(k0.call(Y0,"key")){var u0=Object.getOwnPropertyDescriptor(Y0,"key").get;if(u0&&u0.isReactWarning)return!1}return Y0.key!==void 0}function I(Y0,u0){function R0(){H0||(H0=!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)",u0))}R0.isReactWarning=!0,Object.defineProperty(Y0,"key",{get:R0,configurable:!0})}function L(){var Y0=H(this.type);return Q1[Y0]||(Q1[Y0]=!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.")),Y0=this.props.ref,Y0!==void 0?Y0:null}function b(Y0,u0,R0,n0,zA,_A){var $A=R0.ref;return Y0={$$typeof:p,type:Y0,key:u0,props:R0,_owner:n0},($A!==void 0?$A:null)!==null?Object.defineProperty(Y0,"ref",{enumerable:!1,get:L}):Object.defineProperty(Y0,"ref",{enumerable:!1,value:null}),Y0._store={},Object.defineProperty(Y0._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(Y0,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(Y0,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:zA}),Object.defineProperty(Y0,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:_A}),Object.freeze&&(Object.freeze(Y0.props),Object.freeze(Y0)),Y0}function N(Y0,u0){return u0=b(Y0.type,u0,Y0.props,Y0._owner,Y0._debugStack,Y0._debugTask),Y0._store&&(u0._store.validated=Y0._store.validated),u0}function M(Y0){j(Y0)?Y0._store&&(Y0._store.validated=1):typeof Y0==="object"&&Y0!==null&&Y0.$$typeof===x0&&(Y0._payload.status==="fulfilled"?j(Y0._payload.value)&&Y0._payload.value._store&&(Y0._payload.value._store.validated=1):Y0._store&&(Y0._store.validated=1))}function j(Y0){return typeof Y0==="object"&&Y0!==null&&Y0.$$typeof===p}function g(Y0){var u0={"=":"=0",":":"=2"};return"$"+Y0.replace(/[=:]/g,function(R0){return u0[R0]})}function E(Y0,u0){return typeof Y0==="object"&&Y0!==null&&Y0.key!=null?(X(Y0.key),g(""+Y0.key)):u0.toString(36)}function y(Y0){switch(Y0.status){case"fulfilled":return Y0.value;case"rejected":throw Y0.reason;default:switch(typeof Y0.status==="string"?Y0.then(f,f):(Y0.status="pending",Y0.then(function(u0){Y0.status==="pending"&&(Y0.status="fulfilled",Y0.value=u0)},function(u0){Y0.status==="pending"&&(Y0.status="rejected",Y0.reason=u0)})),Y0.status){case"fulfilled":return Y0.value;case"rejected":throw Y0.reason}}throw Y0}function h(Y0,u0,R0,n0,zA){var _A=typeof Y0;if(_A==="undefined"||_A==="boolean")Y0=null;var $A=!1;if(Y0===null)$A=!0;else switch(_A){case"bigint":case"string":case"number":$A=!0;break;case"object":switch(Y0.$$typeof){case p:case l:$A=!0;break;case x0:return $A=Y0._init,h($A(Y0._payload),u0,R0,n0,zA)}}if($A){$A=Y0,zA=zA($A);var tA=n0===""?"."+E($A,0):n0;return FA(zA)?(R0="",tA!=null&&(R0=tA.replace(y0,"$&/")+"/"),h(zA,u0,R0,"",function(l1){return l1})):zA!=null&&(j(zA)&&(zA.key!=null&&($A&&$A.key===zA.key||X(zA.key)),R0=N(zA,R0+(zA.key==null||$A&&$A.key===zA.key?"":(""+zA.key).replace(y0,"$&/")+"/")+tA),n0!==""&&$A!=null&&j($A)&&$A.key==null&&$A._store&&!$A._store.validated&&(R0._store.validated=2),zA=R0),u0.push(zA)),1}if($A=0,tA=n0===""?".":n0+":",FA(Y0))for(var gA=0;gA<Y0.length;gA++)n0=Y0[gA],_A=tA+E(n0,gA),$A+=h(n0,u0,R0,_A,zA);else if(gA=Q(Y0),typeof gA==="function")for(gA===Y0.entries&&(o0||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),o0=!0),Y0=gA.call(Y0),gA=0;!(n0=Y0.next()).done;)n0=n0.value,_A=tA+E(n0,gA++),$A+=h(n0,u0,R0,_A,zA);else if(_A==="object"){if(typeof Y0.then==="function")return h(y(Y0),u0,R0,n0,zA);throw u0=String(Y0),Error("Objects are not valid as a React child (found: "+(u0==="[object Object]"?"object with keys {"+Object.keys(Y0).join(", ")+"}":u0)+"). If you meant to render a collection of children, use an array instead.")}return $A}function T(Y0,u0,R0){if(Y0==null)return Y0;var n0=[],zA=0;return h(Y0,n0,"","",function(_A){return u0.call(R0,_A,zA++)}),n0}function S(Y0){if(Y0._status===-1){var u0=Y0._ioInfo;u0!=null&&(u0.start=u0.end=performance.now()),u0=Y0._result;var R0=u0();if(R0.then(function(zA){if(Y0._status===0||Y0._status===-1){Y0._status=1,Y0._result=zA;var _A=Y0._ioInfo;_A!=null&&(_A.end=performance.now()),R0.status===void 0&&(R0.status="fulfilled",R0.value=zA)}},function(zA){if(Y0._status===0||Y0._status===-1){Y0._status=2,Y0._result=zA;var _A=Y0._ioInfo;_A!=null&&(_A.end=performance.now()),R0.status===void 0&&(R0.status="rejected",R0.reason=zA)}}),u0=Y0._ioInfo,u0!=null){u0.value=R0;var n0=R0.displayName;typeof n0==="string"&&(u0.name=n0)}Y0._status===-1&&(Y0._status=0,Y0._result=R0)}if(Y0._status===1)return u0=Y0._result,u0===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
546
546
|
|
|
547
547
|
Your code should look like:
|
|
548
548
|
const MyComponent = lazy(() => import('./MyComponent'))
|
|
@@ -1839,7 +1839,7 @@ Example bad output: "A dreamlike crystal formation glowing with ethereal light i
|
|
|
1839
1839
|
Title: "${A.entityTitle??Y}"
|
|
1840
1840
|
|
|
1841
1841
|
Content:
|
|
1842
|
-
${W}`,Rg2);H=`${w.trim()} ${N.imagePrompt}`}catch(N){this.logger.warn("AI prompt distillation failed, using fallback",{error:hA(N)})}}await this.reportProgress(B,{progress:MQ.PROCESS,message:"Generating image"});let Z=this.context.identity.get(),G=this.context.identity.getProfile(),I=wjA(Z,G)+H,L;try{L=await this.context.ai.generateImage(I,{...$&&{aspectRatio:$}})}catch(N){return this.logger.error("Image generation failed",{jobId:Q,error:hA(N)}),x6.failure(N)}await this.reportProgress(B,{progress:MQ.GENERATE,message:"Creating image entity"});let b=CY.createImageEntity({dataUrl:L.dataUrl,title:Y,status:"draft",attachmentType:"generated",...D&&{sourceEntityType:D},...f&&{sourceEntityId:f}});if(await jY({entityService:this.context.entityService,entity:{...b,id:X}}),this.logger.debug("Created image entity",{imageId:X}),D&&f){await this.reportProgress(B,{progress:MQ.SAVE,message:`Updating ${D} with cover image`});let N=await GN(this.context.entityService,D,f,this.logger);if(!N)return x6.failure(Error(`Target entity not found: ${D}/${f}`));let M=$j(N,X);await this.context.entities.update(M),this.logger.debug("Updated target entity with cover image",{targetEntityType:D,targetEntityId:f,imageId:X})}return await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:Q,imageId:X,targetEntityType:D,targetEntityId:f}),{success:!0,imageId:X}}catch(H){let W=hA(H);return this.logger.error("Image generation job failed",{jobId:Q,error:W}),await UU({entityService:this.context.entityService,entityType:"image",id:X,error:W}),x6.failure(H)}}summarizeDataForLog(A){return{title:A.title,promptLength:A.prompt.length,aspectRatio:A.aspectRatio,targetEntityType:A.targetEntityType,targetEntityId:A.targetEntityId}}}p0();K0();Cw();D4();var hg2=K.object({sourceEntityType:K.string().min(1),sourceEntityId:K.string().min(1),attachmentType:K.string().min(1),imageId:K.string().min(1),dedupKey:K.string().min(1).optional(),replace:K.boolean().optional(),targetEntityType:K.string().min(1).optional(),targetEntityId:K.string().min(1).optional(),targetImageField:K.enum(["coverImageId","ogImageId"]).optional()});class Aj0 extends PB{context;constructor(A,Q){super(Q,{schema:hg2,jobTypeName:"image-render-source"});this.context=A}async process(A,Q,B){this.logger.debug("Starting source image render job",{jobId:Q,sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType,imageId:A.imageId});try{if(A.replace!==!0&&A.dedupKey){let f=await this.findImageByDedupKey(A.dedupKey);if(f)return await this.updateTarget(A,f.id),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Reusing existing generated image"}),{success:!0,imageId:f.id,reused:!0}}await this.reportProgress(B,{progress:MQ.PROCESS,message:"Rendering source image"});let w=await this.context.attachments.resolve({sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType});if(!w)return x6.failure(Error(`No attachment provider found for ${A.sourceEntityType}/${A.attachmentType}`));if(w.type!=="image")return x6.failure(Error(`Attachment provider returned ${w.type}; expected image`));await this.reportProgress(B,{progress:MQ.GENERATE,message:"Creating image entity"});let $=w.mimeType.split("/")[1]??"png",D=CY.createImageEntity({dataUrl:xL0(w.data.toString("base64"),$),title:A.imageId,status:"draft",sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType,...A.dedupKey&&{dedupKey:A.dedupKey}});return await jY({entityService:this.context.entityService,entity:{...D,id:A.imageId}}),await this.updateTarget(A,A.imageId),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Image render complete"}),{success:!0,imageId:A.imageId,reused:!1}}catch(w){let $=hA(w);return this.logger.error("Source image render job failed",{jobId:Q,error:$}),await UU({entityService:this.context.entityService,entityType:"image",id:A.imageId,error:$}),x6.failure(w)}}async findImageByDedupKey(A){return(await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{dedupKey:A}}}})).find((B)=>B.metadata.status!=="pending"&&B.metadata.status!=="failed")}async updateTarget(A,Q){if(!A.targetEntityType||!A.targetEntityId)return;let B=await GN(this.context.entityService,A.targetEntityType,A.targetEntityId,this.logger);if(!B)throw Error(`Target entity not found: ${A.targetEntityType}/${A.targetEntityId}`);let $=(A.targetImageField??"coverImageId")==="ogImageId"?Hu(B,Q):$j(B,Q);await this.context.entities.update($)}}p0();K0();Cw();D4();K0();var lR={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function t20(A){return["image/png","image/jpeg","image/webp","image/gif"].includes(A.toLowerCase())}function e20(A){let Q=Cg2(A.title,A.filename),B=Y1(Q);if(!B)throw Error("Could not derive an image id from the uploaded filename. Provide a title.");return{id:B,title:Q}}function $jA(A,Q){return`data:${A};base64,${Q.toString("base64")}`}function Cg2(A,Q){let B=A?.trim();if(B)return B;return Q.replace(/\.[^.]+$/,"").trim()||Q}var yg2=K.object({uploadId:K.string().min(1),imageId:K.string().min(1).optional(),title:K.string().optional()});class Qj0 extends PB{context;constructor(A,Q){super(A,{schema:yg2,jobTypeName:"upload-promote"});this.context=Q}async process(A,Q,B){try{await this.reportProgress(B,{progress:10,message:"Reading uploaded image"});let w=await this.context.uploads.scoped(lR).read(A.uploadId);if(!t20(w.record.mediaType))throw Error("Only image uploads can be promoted to image entities");let $=e20({filename:w.record.filename,...A.title!==void 0?{title:A.title}:{}}),D=A.imageId??$.id;await this.reportProgress(B,{progress:60,message:"Saving uploaded image"});let f=new Date().toISOString(),Y=CY.createImageEntity({dataUrl:$jA(w.record.mediaType,w.content),title:$.title,status:"draft",sourceUploadId:A.uploadId,sourceFilename:w.record.filename,sourceMediaType:w.record.mediaType,attachmentType:"uploaded"}),X=await jY({entityService:this.context.entityService,entity:{id:D,...Y,created:f,updated:f}});return await this.reportProgress(B,{progress:100,message:"Uploaded image promoted"}),{entityId:X.entityId,status:"created"}}catch(w){if(A.imageId)await UU({entityService:this.context.entityService,entityType:"image",id:A.imageId,error:hA(w)});return x6.failure(w)}}summarizeDataForLog(A){return{uploadId:A.uploadId,imageId:A.imageId,hasTitle:A.title!==void 0}}}var DjA={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.128",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/contracts":"workspace:*","@brains/entity-service":"workspace:*","@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 gg2="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",Tg2=K.object({defaultAspectRatio:K.enum(["1:1","16:9","9:16","4:3","3:4"]).default("16:9").describe("Default aspect ratio for generated images")});function NZ(A){let Q=A?.trim();if(!Q)return;return Q}function Sg2(A){let Q=NZ(A.prompt);if(Q)return Q;let B=NZ(A.content);if(B&&!eN0(B))return B;return}function mg2(A){let Q=A.attachmentType==="og-image"?"og":A.attachmentType;return Y1(`${Q}-${A.sourceEntityType}-${A.sourceEntityId}`)}function fjA(A){let Q=NZ(A.title)??(A.targetEntityId?`cover-${A.targetEntityId}`:A.prompt.slice(0,60).trim());return Y1(Q)}async function ug2(A,Q){let B=`${Q.attachmentType}:${Q.sourceEntityType}:${Q.sourceEntityId}:resolved-attachment`,w=await A.entityService.getEntity({entityType:Q.sourceEntityType,id:Q.sourceEntityId});return w?`${B}:${w.contentHash}`:B}function Bj0(A,Q="generated"){let B=encodeURIComponent(A);return{mediaType:"image/png",url:`/api/chat/attachments/image?id=${B}`,downloadUrl:`/api/chat/attachments/image?id=${B}&download=1`,filename:`${A}.png`,source:{entityType:"image",entityId:A,attachmentType:Q}}}function cg2(A){let Q=encodeURIComponent(A.entityId);return{mediaType:A.mediaType,url:`/api/chat/attachments/image?id=${Q}`,downloadUrl:`/api/chat/attachments/image?id=${Q}&download=1`,filename:A.filename,source:{entityType:"image",entityId:A.entityId,attachmentType:"uploaded"}}}class wj0 extends PQ{entityType=CY.entityType;schema=Yu;adapter=CY;constructor(A={}){super("image",DjA,A,Tg2)}getEntityTypeConfig(){return{embeddable:!1}}async interceptCreate(A,Q,B){if(A.from?.kind===lR.refKind)return this.promoteUpload(A,B);let w=Sg2(A),$=NZ(A.targetEntityType),D=NZ(A.targetEntityId),f=$===this.entityType?D:void 0,Y=A.from;if(Y?.kind==="entity-attachment")return this.enqueueSourceImageRender({...A,from:Y},B);if(!$||!D||f){if(!w)return{kind:"continue",input:A};let G=NZ(A.title)??f,F=fjA({prompt:w,...G&&{title:G}});await this.createPendingImage(B,{id:F,title:G??w.slice(0,60).trim(),alt:G??w.slice(0,60).trim(),attachmentType:"generated"});let I=await B.jobs.enqueue({type:"image-generate",data:{prompt:w,...G&&{title:G}}});return{kind:"handled",result:{success:!0,data:{entityId:F,status:"generating",jobId:I,attachment:Bj0(F)}}}}let X=await nD(B.entityService,$,D,this.logger,"Target entity");if(!X.ok)return{kind:"handled",result:{success:!1,error:X.error}};if(!w)return{kind:"continue",input:{...A,targetEntityId:X.entity.id}};let H=s20(X.entity.content),W=fjA({prompt:w,...A.title&&{title:A.title},targetEntityId:X.entity.id});await this.createPendingImage(B,{id:W,title:A.title??`cover-${X.entity.id}`,alt:A.title??`cover-${X.entity.id}`,attachmentType:"generated",sourceEntityType:$,sourceEntityId:X.entity.id});let Z=await B.jobs.enqueue({type:"image-generate",data:{prompt:w,...A.title&&{title:A.title},targetEntityType:$,targetEntityId:X.entity.id,entityTitle:typeof X.entity.metadata.title==="string"?X.entity.metadata.title:X.entity.id,...H&&{entityContent:H}}});return{kind:"handled",result:{success:!0,data:{entityId:W,status:"generating",jobId:Z,attachment:Bj0(W)}}}}async promoteUpload(A,Q){let B=A.from;if(B?.kind!==lR.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let w=B.id,$;try{$=await Q.uploads.scoped(lR).readRecord(w)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(!t20($.mediaType))return{kind:"handled",result:{success:!1,error:"Only image uploads can be promoted to image entities"}};let D;try{D=e20({filename:$.filename,...A.title!==void 0?{title:A.title}:{}})}catch(Y){return{kind:"handled",result:{success:!1,error:Y instanceof Error?Y.message:String(Y)}}}await this.createPendingImage(Q,{id:D.id,title:D.title,alt:D.title,sourceUploadId:w,sourceFilename:$.filename,sourceMediaType:$.mediaType,attachmentType:"uploaded"});let f=await Q.jobs.enqueue({type:"upload-promote",data:{uploadId:w,imageId:D.id,title:D.title}});return{kind:"handled",result:{success:!0,data:{entityId:D.id,status:"generating",jobId:f,attachment:cg2({mediaType:$.mediaType,entityId:D.id,filename:$.filename})}}}}async enqueueSourceImageRender(A,Q){let B=NZ(A.from.sourceEntityType),w=NZ(A.from.sourceEntityId),$=NZ(A.from.attachmentType);if(!B||!w||!$)return{kind:"handled",result:{success:!1,error:"Image source requires sourceEntityType, sourceEntityId, and attachmentType"}};let D=await nD(Q.entityService,B,w,this.logger,"Source entity");if(!D.ok)return{kind:"handled",result:{success:!1,error:D.error}};let f=NZ(A.targetEntityType),Y=NZ(A.targetEntityId),X;if(f&&Y){let F=await nD(Q.entityService,f,Y,this.logger,"Target entity");if(!F.ok)return{kind:"handled",result:{success:!1,error:F.error}};X=F.entity.id}let H={sourceEntityType:B,sourceEntityId:D.entity.id,attachmentType:$},W=await ug2(Q,H),Z=mg2(H);await this.createPendingImage(Q,{id:Z,title:Z,alt:Z,sourceEntityType:H.sourceEntityType,sourceEntityId:H.sourceEntityId,attachmentType:$,dedupKey:W});let G=await Q.jobs.enqueue({type:"image-render-source",data:{...H,imageId:Z,dedupKey:W,...A.replace===!0&&{replace:!0},...f&&{targetEntityType:f},...X&&{targetEntityId:X},...$==="og-image"&&{targetImageField:"ogImageId"}}});return{kind:"handled",result:{success:!0,data:{entityId:Z,status:"generating",jobId:G,attachment:Bj0(Z,$)}}}}async createPendingImage(A,Q){let B=new Date().toISOString(),w=CY.createImageEntity({dataUrl:gg2,title:Q.title,alt:Q.alt,status:"pending",attachmentType:Q.attachmentType,...Q.sourceEntityType&&{sourceEntityType:Q.sourceEntityType},...Q.sourceEntityId&&{sourceEntityId:Q.sourceEntityId},...Q.sourceUploadId&&{sourceUploadId:Q.sourceUploadId},...Q.sourceFilename&&{sourceFilename:Q.sourceFilename},...Q.sourceMediaType&&{sourceMediaType:Q.sourceMediaType},...Q.dedupKey&&{dedupKey:Q.dedupKey}});await qN({entityService:A.entityService,entity:{id:Q.id,...w,created:B,updated:B}})}async getInstructions(){return'For durable raw image saves/promotions from uploaded images, call system_upload_save with the exact upload object shown in the current turn or conversation "Available upload refs" hint. Do this only after the user explicitly asks to save/import/promote the uploaded image file itself. If that hint is absent, omit upload entirely; never invent upload IDs or placeholder upload refs. Describing or summarizing an uploaded image should use it as chat context, not create an image entity. Saving an image description, discussion, interpretation, caption, summary, study notes, or a prior assistant answer as a note should call system_create with entityType "note" and source: { kind: "prior-response" }, not system_upload_save or an upload source. After a bare upload acknowledgement, a short label/title-only follow-up is ambiguous; ask what to do with the upload instead of turning that label into an AI image-generation prompt. For AI-generated images and cover images, call system_create with entityType: "image" and source: { kind: "generate", prompt }, and omit upload or attachment sources unless the user explicitly asks to reuse the uploaded image file. Cover image and OG/social preview image are separate domain concepts: cover-image changes/removal use coverImageId, while OG/Open Graph/social preview image changes use ogImageId. To remove a cover image, call system_update on the target entity with fields.coverImageId set to null; do not clear ogImageId unless the user explicitly asked to remove an OG/social preview image. For direct requests like "set image X as the cover for entity Y", call system_update with fields.coverImageId set to X; do not stop after looking up either side when the user provided exact IDs.'}createGenerationHandler(A){return new a20(A,this.logger)}async onRegister(A){A.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["image/*"],handler:async(B)=>{let w=await this.promoteUpload({entityType:this.entityType,...B.title!==void 0?{title:B.title}:{},from:B.upload},A);return w.kind==="handled"?w.result:{success:!1,error:"Image upload save was not handled"}}});let Q=new a20(A,this.logger);A.jobs.registerHandler("image-generate",Q),A.jobs.registerHandler("image-render-source",new Aj0(A,this.logger)),A.jobs.registerHandler("upload-promote",new Qj0(this.logger.child("UploadPromotionJobHandler"),A))}}function Yc(A){return new wj0(A)}p0();import{StdioServerTransport as lg2}from"@modelcontextprotocol/sdk/server/stdio.js";function YjA(){return{info:(A,...Q)=>console.error(`[STDIO MCP] ${A}`,...Q),debug:(A,...Q)=>console.error(`[STDIO MCP DEBUG] ${A}`,...Q),error:(A,...Q)=>console.error(`[STDIO MCP ERROR] ${A}`,...Q),warn:(A,...Q)=>console.error(`[STDIO MCP WARN] ${A}`,...Q)}}function $j0(){return{info:(A,...Q)=>console.log(`[HTTP MCP] ${A}`,...Q),debug:(A,...Q)=>console.debug(`[HTTP MCP DEBUG] ${A}`,...Q),error:(A,...Q)=>console.error(`[HTTP MCP ERROR] ${A}`,...Q),warn:(A,...Q)=>console.warn(`[HTTP MCP WARN] ${A}`,...Q)}}function AQ0(A){if(A&&typeof A==="object"&&"info"in A&&"debug"in A&&"error"in A&&"warn"in A){let Q=A;return{info:(B,...w)=>Q.info(B,...w),debug:(B,...w)=>Q.debug(B,...w),error:(B,...w)=>Q.error(B,...w),warn:(B,...w)=>Q.warn(B,...w)}}return $j0()}class jZ{static instance=null;mcpServer=null;transport=null;config;logger;static getInstance(A){return jZ.instance??=new jZ(A),jZ.instance}static resetInstance(){if(jZ.instance)jZ.instance.stop(),jZ.instance=null}static createFresh(A){return new jZ(A)}constructor(A={}){this.config=A,this.logger=this.config.logger?AQ0(this.config.logger):YjA()}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 lg2,await this.mcpServer.connect(this.transport),this.logger.info("Stdio transport started successfully")}stop(){if(this.logger.info("Stopping stdio transport"),this.transport)this.transport=null;this.logger.info("Stdio transport stopped")}isRunning(){return this.transport!==null}}import{randomUUID as XjA}from"crypto";import{WebStandardStreamableHTTPServerTransport as pg2}from"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";import{isInitializeRequest as ig2}from"@modelcontextprotocol/sdk/types.js";p0();var dg2={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, DELETE, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization, MCP-Session-Id, MCP-Protocol-Version, Last-Event-ID","Access-Control-Allow-Private-Network":"true","X-Content-Type-Options":"nosniff"};function ng2(A){let Q=new URL(A.url),w=A.headers.get("x-forwarded-proto")?.split(",")[0]?.trim(),$=A.headers.get("x-forwarded-host")??A.headers.get("host");if(!$)return Q.origin;return`${w??Q.protocol.replace(":","")}://${$}`}class Eq{static instance=null;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?AQ0(this.config.logger):$j0(),this.authConfig=A.auth??{},!this.authConfig.disabled&&!this.authConfig.token&&!this.authConfig.verifyBearerToken)throw Error("MCP HTTP transport requires an auth token or bearer token verifier. Set MCP_AUTH_TOKEN, configure OAuth verification, or pass auth: { disabled: true } for local dev.")}static getInstance(A){return Eq.instance??=new Eq(A),Eq.instance}static resetInstance(){Eq.instance=null}static createFresh(A){return new Eq(A)}withCors(A){let Q=new Headers(A.headers);for(let[B,w]of Object.entries(dg2))Q.set(B,w);return new Response(A.body,{status:A.status,statusText:A.statusText,headers:Q})}createJsonResponse(A,Q=200){return this.withCors(new Response(JSON.stringify(A),{status:Q,headers:{"Content-Type":"application/json"}}))}createTextResponse(A,Q=200){return this.withCors(new Response(A,{status:Q,headers:{"Content-Type":"text/plain; charset=utf-8"}}))}getAuthErrorResponse(A,Q=401,B){let w=this.createJsonResponse({jsonrpc:"2.0",error:{code:-32001,message:A},id:null},Q);if(!B)return w;let $=new Headers(w.headers);return $.set("WWW-Authenticate",B),new Response(w.body,{status:w.status,statusText:w.statusText,headers:$})}getBearerChallenge(A,Q={}){let w={resource_metadata:`${ng2(A)}/.well-known/oauth-protected-resource`,...Q};return`Bearer ${Object.entries(w).map(([D,f])=>`${D}="${rg2(f)}"`).join(", ")}`}async authenticate(A){let Q=new URL(A.url).pathname;if(Q==="/health"||Q==="/status"||Q==="/mcp"&&A.method==="OPTIONS")return null;if(this.authConfig.disabled)return null;let B=A.headers.get("authorization");if(!B?.startsWith("Bearer "))return this.logger.warn("Authentication failed: Missing Bearer token"),this.getAuthErrorResponse("Unauthorized: Bearer token required",401,this.getBearerChallenge(A,{realm:"mcp"}));if(this.authConfig.token){if(B.substring(7)!==this.authConfig.token)return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(A,{error:"invalid_token"}));return this.logger.debug("Authentication successful"),null}try{let w=await this.authConfig.verifyBearerToken?.(A);if(!w)return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(A,{error:"invalid_token"}));let $=this.authConfig.requiredScopes??[],D=$.filter((f)=>!w.scope?.includes(f));if(D.length>0)return this.logger.warn(`Authentication failed: Missing required scope(s): ${D.join(", ")}`),this.getAuthErrorResponse("Forbidden: Missing required scope",403,this.getBearerChallenge(A,{error:"insufficient_scope",scope:$.join(" ")}));return this.logger.debug("Authentication successful"),null}catch(w){return this.logger.warn("Authentication failed: Invalid token",w),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(A,{error:"invalid_token"}))}}async handleMcpRequest(A){let Q=A.headers.get("mcp-session-id")??void 0;if(A.method==="GET"){if(!Q||!this.transports[Q])return this.createTextResponse("Invalid or missing session ID",400);return this.logger.debug(`GET /mcp - SSE stream for session ${Q}`),this.withCors(await this.transports[Q].handleRequest(A))}if(A.method==="DELETE"){if(!Q||!this.transports[Q])return this.createTextResponse("Invalid or missing session ID",400);return this.logger.info(`DELETE /mcp - Terminating session ${Q}`),this.withCors(await this.transports[Q].handleRequest(A))}if(A.method==="OPTIONS")return this.withCors(new Response(null,{status:204}));if(A.method!=="POST")return this.createTextResponse("Method Not Allowed",405);if(!this.mcpServer)return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Service Unavailable: MCP server not connected"},id:null},503);let B=await A.json();this.logger.debug(`POST /mcp - Session: ${Q??"new"}`);try{let w;if(Q&&this.transports[Q])w=this.transports[Q];else if(!Q&&ig2(B))w=new pg2({sessionIdGenerator:()=>XjA(),onsessioninitialized:(D)=>{this.logger.info(`Session initialized: ${D}`),this.transports[D]=w},onsessionclosed:(D)=>{this.logger.info(`Session closed: ${D}`),delete this.transports[D]}}),await(this.mcpTransport?this.mcpTransport.createMcpServer():this.mcpServer).connect(w);else return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32000,message:"Bad Request: Server not initialized"},id:null},400);return this.withCors(await w.handleRequest(A,{parsedBody:B}))}catch(w){return this.logger.error("MCP transport error:",w),this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}},500)}}async handleAgentChatRequest(A){if(!this.agentService)return this.createJsonResponse({error:"Agent service not connected"},503);let{message:Q,conversationId:B}=await A.json();if(!Q||typeof Q!=="string")return this.createJsonResponse({error:"Missing or invalid 'message' field"},400);let w=B??XjA();this.logger.debug(`POST /api/chat - conversation: ${w}`);try{let $=await this.agentService.chat(Q,w);return this.createJsonResponse($)}catch($){return this.logger.error("Agent chat error:",$),this.createJsonResponse({error:$ instanceof Error?$.message:"Internal error"},500)}}async handleAgentConfirmRequest(A){if(!this.agentService)return this.createJsonResponse({error:"Agent service not connected"},503);let{conversationId:Q,confirmed:B,approvalId:w,context:$}=await A.json();if(!Q||typeof Q!=="string")return this.createJsonResponse({error:"Missing or invalid 'conversationId' field"},400);if(typeof B!=="boolean")return this.createJsonResponse({error:"Missing or invalid 'confirmed' field"},400);if(typeof w!=="string"||w.length===0)return this.createJsonResponse({error:"Missing or invalid 'approvalId' field"},400);let D=nU0.safeParse($);if(!D.success||!D.data.userPermissionLevel)return this.createJsonResponse({error:"Missing or invalid 'context' field"},400);this.logger.debug(`POST /api/chat/confirm - conversation: ${Q}`);try{let f=await this.agentService.confirmPendingAction(Q,B,w,D.data);return this.createJsonResponse(f)}catch(f){return this.logger.error("Agent confirm error:",f),this.createJsonResponse({error:f instanceof Error?f.message:"Internal error"},500)}}async handleRequest(A){let Q=new URL(A.url);this.logger.debug(`${A.method} ${Q.pathname}`);let B=await this.authenticate(A);if(B)return B;if(Q.pathname==="/health")return this.createJsonResponse({status:"ok",transport:"streamable-http",timestamp:new Date().toISOString()});if(Q.pathname==="/status")return this.createJsonResponse({sessions:Object.keys(this.transports).length,uptime:process.uptime(),memory:process.memoryUsage(),port:this.boundPort??this.config.port??3333});if(Q.pathname==="/mcp")return this.handleMcpRequest(A);if(Q.pathname==="/api/chat"&&A.method==="POST")return this.handleAgentChatRequest(A);if(Q.pathname==="/api/chat/confirm"&&A.method==="POST")return this.handleAgentConfirmRequest(A);return this.createTextResponse("Not Found",404)}connectMCPServer(A,Q){this.mcpServer=A,this.mcpTransport=Q??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=Number(this.config.port??3333),Q=this.config.host??"0.0.0.0";try{this.server=Bun.serve({port:A,hostname:Q,fetch:(B)=>this.handleRequest(B)}),this.boundPort=this.server.port??A,this.logger.info(`StreamableHTTP server listening on http://${Q}:${this.boundPort}/mcp`)}catch(B){if(B.code==="EADDRINUSE")this.logger.error(`Port ${A} is already in use`);throw B}}async stop(){for(let A in this.transports)try{let Q=this.transports[A];if(Q)this.logger.debug(`Closing transport for session ${A}`),await Q.close(),delete this.transports[A]}catch(Q){this.logger.error(`Error closing transport for session ${A}:`,Q)}if(this.server)await this.server.stop(),this.logger.info("StreamableHTTP server stopped"),this.server=null,this.boundPort=null}getPort(){if(this.boundPort===null)throw Error("Server is not running");return this.boundPort}getApp(){return{fetch:(A)=>this.handleRequest(A)}}isRunning(){return this.server!==null}getSessionCount(){return Object.keys(this.transports).length}}function rg2(A){return A.replace(/["\\]/g,(Q)=>`\\${Q}`)}import{randomUUID as sg2}from"crypto";import{mkdir as ag2,readFile as tg2,writeFile as eg2,chmod as AT2}from"fs/promises";import{dirname as QT2,join as BT2}from"path";function HjA(A){let Q=A.toLowerCase();return Q==="localhost"||Q==="[::1]"||Q==="::1"||Q.startsWith("127.")}function WjA(A){try{return new URL(A)}catch{return}}function Dj0(A,Q){if(A===Q)return!0;let B=WjA(A),w=WjA(Q);if(!B||!w)return!1;if(!HjA(B.hostname)||!HjA(w.hostname))return!1;return B.protocol===w.protocol&&B.port===w.port&&og2(B.pathname,w.pathname)&&B.search===w.search&&B.hash===w.hash}function og2(A,Q){return A===Q||A===`${Q}/debug`||Q===`${A}/debug`}function fj0(A,Q){return A.some((B)=>Dj0(B,Q))}var wT2="oauth-auth-codes.json",$T2=600;function ZjA(){return Math.floor(Date.now()/1000)}function DT2(A){if(!A||typeof A!=="object")return!1;let Q=A;return typeof Q.code==="string"&&typeof Q.client_id==="string"&&typeof Q.redirect_uri==="string"&&typeof Q.code_challenge==="string"&&Q.code_challenge_method==="S256"&&typeof Q.subject==="string"&&typeof Q.created_at==="number"&&typeof Q.expires_at==="number"}function fT2(A){if(!A||typeof A!=="object")return{codes:[]};let Q=A.codes;if(!Array.isArray(Q))return{codes:[]};return{codes:Q.filter(DT2)}}async function YT2(A){let Q=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(A));return Buffer.from(Q).toString("base64url")}class QQ0{storeFile;writeQueue=Promise.resolve();constructor(A){this.storeFile=BT2(A.storageDir,A.storeFile??wT2)}async createCode(A){let Q=ZjA(),B={code:`ocd_${sg2()}`,client_id:A.clientId,redirect_uri:A.redirectUri,code_challenge:A.codeChallenge,code_challenge_method:"S256",...A.scope?{scope:A.scope}:{},subject:A.subject,created_at:Q,expires_at:Q+$T2};return await this.enqueueWrite(async()=>{let w=await this.readStore();w.codes=w.codes.filter(($)=>$.expires_at>Q),w.codes.push(B),await this.writeStore(w)}),B}async consumeCode(A){let Q=ZjA(),B;if(await this.enqueueWrite(async()=>{let w=await this.readStore(),$=w.codes.findIndex((Y)=>Y.code===A.code),D=$>=0?w.codes[$]:void 0;if(!D)throw new _Z("Authorization code not found");if(D.consumed_at!==void 0)throw new _Z("Authorization code already consumed");if(D.expires_at<=Q)throw new _Z("Authorization code expired");if(D.client_id!==A.clientId)throw new _Z("Authorization code client mismatch");if(!Dj0(D.redirect_uri,A.redirectUri))throw new _Z("Authorization code redirect URI mismatch");let f=await YT2(A.codeVerifier);if(D.code_challenge!==f)throw new _Z("PKCE verification failed");B={...D,consumed_at:Q},w.codes[$]=B,await this.writeStore(w)}),!B)throw new _Z("Authorization code not consumed");return B}async enqueueWrite(A){return this.writeQueue=this.writeQueue.then(A,A),this.writeQueue}async readStore(){try{return fT2(JSON.parse(await tg2(this.storeFile,"utf8")))}catch(A){if(A.code==="ENOENT")return{codes:[]};throw A}}async writeStore(A){await ag2(QT2(this.storeFile),{recursive:!0,mode:448}),await eg2(this.storeFile,`${JSON.stringify(A,null,2)}
|
|
1842
|
+
${W}`,Rg2);H=`${w.trim()} ${N.imagePrompt}`}catch(N){this.logger.warn("AI prompt distillation failed, using fallback",{error:hA(N)})}}await this.reportProgress(B,{progress:MQ.PROCESS,message:"Generating image"});let Z=this.context.identity.get(),G=this.context.identity.getProfile(),I=wjA(Z,G)+H,L;try{L=await this.context.ai.generateImage(I,{...$&&{aspectRatio:$}})}catch(N){return this.logger.error("Image generation failed",{jobId:Q,error:hA(N)}),x6.failure(N)}await this.reportProgress(B,{progress:MQ.GENERATE,message:"Creating image entity"});let b=CY.createImageEntity({dataUrl:L.dataUrl,title:Y,status:"draft",attachmentType:"generated",...D&&{sourceEntityType:D},...f&&{sourceEntityId:f}});if(await jY({entityService:this.context.entityService,entity:{...b,id:X}}),this.logger.debug("Created image entity",{imageId:X}),D&&f){await this.reportProgress(B,{progress:MQ.SAVE,message:`Updating ${D} with cover image`});let N=await GN(this.context.entityService,D,f,this.logger);if(!N)return x6.failure(Error(`Target entity not found: ${D}/${f}`));let M=$j(N,X);await this.context.entities.update(M),this.logger.debug("Updated target entity with cover image",{targetEntityType:D,targetEntityId:f,imageId:X})}return await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Image generation complete"}),this.logger.info("Image generation job complete",{jobId:Q,imageId:X,targetEntityType:D,targetEntityId:f}),{success:!0,imageId:X}}catch(H){let W=hA(H);return this.logger.error("Image generation job failed",{jobId:Q,error:W}),await UU({entityService:this.context.entityService,entityType:"image",id:X,error:W}),x6.failure(H)}}summarizeDataForLog(A){return{title:A.title,promptLength:A.prompt.length,aspectRatio:A.aspectRatio,targetEntityType:A.targetEntityType,targetEntityId:A.targetEntityId}}}p0();K0();Cw();D4();var hg2=K.object({sourceEntityType:K.string().min(1),sourceEntityId:K.string().min(1),attachmentType:K.string().min(1),imageId:K.string().min(1),dedupKey:K.string().min(1).optional(),replace:K.boolean().optional(),targetEntityType:K.string().min(1).optional(),targetEntityId:K.string().min(1).optional(),targetImageField:K.enum(["coverImageId","ogImageId"]).optional()});class Aj0 extends PB{context;constructor(A,Q){super(Q,{schema:hg2,jobTypeName:"image-render-source"});this.context=A}async process(A,Q,B){this.logger.debug("Starting source image render job",{jobId:Q,sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType,imageId:A.imageId});try{if(A.replace!==!0&&A.dedupKey){let f=await this.findImageByDedupKey(A.dedupKey);if(f)return await this.updateTarget(A,f.id),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Reusing existing generated image"}),{success:!0,imageId:f.id,reused:!0}}await this.reportProgress(B,{progress:MQ.PROCESS,message:"Rendering source image"});let w=await this.context.attachments.resolve({sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType});if(!w)return x6.failure(Error(`No attachment provider found for ${A.sourceEntityType}/${A.attachmentType}`));if(w.type!=="image")return x6.failure(Error(`Attachment provider returned ${w.type}; expected image`));await this.reportProgress(B,{progress:MQ.GENERATE,message:"Creating image entity"});let $=w.mimeType.split("/")[1]??"png",D=CY.createImageEntity({dataUrl:xL0(w.data.toString("base64"),$),title:A.imageId,status:"draft",sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType,...A.dedupKey&&{dedupKey:A.dedupKey}});return await jY({entityService:this.context.entityService,entity:{...D,id:A.imageId}}),await this.updateTarget(A,A.imageId),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Image render complete"}),{success:!0,imageId:A.imageId,reused:!1}}catch(w){let $=hA(w);return this.logger.error("Source image render job failed",{jobId:Q,error:$}),await UU({entityService:this.context.entityService,entityType:"image",id:A.imageId,error:$}),x6.failure(w)}}async findImageByDedupKey(A){return(await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{dedupKey:A}}}})).find((B)=>B.metadata.status!=="pending"&&B.metadata.status!=="failed")}async updateTarget(A,Q){if(!A.targetEntityType||!A.targetEntityId)return;let B=await GN(this.context.entityService,A.targetEntityType,A.targetEntityId,this.logger);if(!B)throw Error(`Target entity not found: ${A.targetEntityType}/${A.targetEntityId}`);let $=(A.targetImageField??"coverImageId")==="ogImageId"?Hu(B,Q):$j(B,Q);await this.context.entities.update($)}}p0();K0();Cw();D4();K0();var lR={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function t20(A){return["image/png","image/jpeg","image/webp","image/gif"].includes(A.toLowerCase())}function e20(A){let Q=Cg2(A.title,A.filename),B=Y1(Q);if(!B)throw Error("Could not derive an image id from the uploaded filename. Provide a title.");return{id:B,title:Q}}function $jA(A,Q){return`data:${A};base64,${Q.toString("base64")}`}function Cg2(A,Q){let B=A?.trim();if(B)return B;return Q.replace(/\.[^.]+$/,"").trim()||Q}var yg2=K.object({uploadId:K.string().min(1),imageId:K.string().min(1).optional(),title:K.string().optional()});class Qj0 extends PB{context;constructor(A,Q){super(A,{schema:yg2,jobTypeName:"upload-promote"});this.context=Q}async process(A,Q,B){try{await this.reportProgress(B,{progress:10,message:"Reading uploaded image"});let w=await this.context.uploads.scoped(lR).read(A.uploadId);if(!t20(w.record.mediaType))throw Error("Only image uploads can be promoted to image entities");let $=e20({filename:w.record.filename,...A.title!==void 0?{title:A.title}:{}}),D=A.imageId??$.id;await this.reportProgress(B,{progress:60,message:"Saving uploaded image"});let f=new Date().toISOString(),Y=CY.createImageEntity({dataUrl:$jA(w.record.mediaType,w.content),title:$.title,status:"draft",sourceUploadId:A.uploadId,sourceFilename:w.record.filename,sourceMediaType:w.record.mediaType,attachmentType:"uploaded"}),X=await jY({entityService:this.context.entityService,entity:{id:D,...Y,created:f,updated:f}});return await this.reportProgress(B,{progress:100,message:"Uploaded image promoted"}),{entityId:X.entityId,status:"created"}}catch(w){if(A.imageId)await UU({entityService:this.context.entityService,entityType:"image",id:A.imageId,error:hA(w)});return x6.failure(w)}}summarizeDataForLog(A){return{uploadId:A.uploadId,imageId:A.imageId,hasTitle:A.title!==void 0}}}var DjA={name:"@brains/image-plugin",private:!0,version:"0.2.0-alpha.129",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/contracts":"workspace:*","@brains/entity-service":"workspace:*","@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 gg2="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",Tg2=K.object({defaultAspectRatio:K.enum(["1:1","16:9","9:16","4:3","3:4"]).default("16:9").describe("Default aspect ratio for generated images")});function NZ(A){let Q=A?.trim();if(!Q)return;return Q}function Sg2(A){let Q=NZ(A.prompt);if(Q)return Q;let B=NZ(A.content);if(B&&!eN0(B))return B;return}function mg2(A){let Q=A.attachmentType==="og-image"?"og":A.attachmentType;return Y1(`${Q}-${A.sourceEntityType}-${A.sourceEntityId}`)}function fjA(A){let Q=NZ(A.title)??(A.targetEntityId?`cover-${A.targetEntityId}`:A.prompt.slice(0,60).trim());return Y1(Q)}async function ug2(A,Q){let B=`${Q.attachmentType}:${Q.sourceEntityType}:${Q.sourceEntityId}:resolved-attachment`,w=await A.entityService.getEntity({entityType:Q.sourceEntityType,id:Q.sourceEntityId});return w?`${B}:${w.contentHash}`:B}function Bj0(A,Q="generated"){let B=encodeURIComponent(A);return{mediaType:"image/png",url:`/api/chat/attachments/image?id=${B}`,downloadUrl:`/api/chat/attachments/image?id=${B}&download=1`,filename:`${A}.png`,source:{entityType:"image",entityId:A,attachmentType:Q}}}function cg2(A){let Q=encodeURIComponent(A.entityId);return{mediaType:A.mediaType,url:`/api/chat/attachments/image?id=${Q}`,downloadUrl:`/api/chat/attachments/image?id=${Q}&download=1`,filename:A.filename,source:{entityType:"image",entityId:A.entityId,attachmentType:"uploaded"}}}class wj0 extends PQ{entityType=CY.entityType;schema=Yu;adapter=CY;constructor(A={}){super("image",DjA,A,Tg2)}getEntityTypeConfig(){return{embeddable:!1}}async interceptCreate(A,Q,B){if(A.from?.kind===lR.refKind)return this.promoteUpload(A,B);let w=Sg2(A),$=NZ(A.targetEntityType),D=NZ(A.targetEntityId),f=$===this.entityType?D:void 0,Y=A.from;if(Y?.kind==="entity-attachment")return this.enqueueSourceImageRender({...A,from:Y},B);if(!$||!D||f){if(!w)return{kind:"continue",input:A};let G=NZ(A.title)??f,F=fjA({prompt:w,...G&&{title:G}});await this.createPendingImage(B,{id:F,title:G??w.slice(0,60).trim(),alt:G??w.slice(0,60).trim(),attachmentType:"generated"});let I=await B.jobs.enqueue({type:"image-generate",data:{prompt:w,...G&&{title:G}}});return{kind:"handled",result:{success:!0,data:{entityId:F,status:"generating",jobId:I,attachment:Bj0(F)}}}}let X=await nD(B.entityService,$,D,this.logger,"Target entity");if(!X.ok)return{kind:"handled",result:{success:!1,error:X.error}};if(!w)return{kind:"continue",input:{...A,targetEntityId:X.entity.id}};let H=s20(X.entity.content),W=fjA({prompt:w,...A.title&&{title:A.title},targetEntityId:X.entity.id});await this.createPendingImage(B,{id:W,title:A.title??`cover-${X.entity.id}`,alt:A.title??`cover-${X.entity.id}`,attachmentType:"generated",sourceEntityType:$,sourceEntityId:X.entity.id});let Z=await B.jobs.enqueue({type:"image-generate",data:{prompt:w,...A.title&&{title:A.title},targetEntityType:$,targetEntityId:X.entity.id,entityTitle:typeof X.entity.metadata.title==="string"?X.entity.metadata.title:X.entity.id,...H&&{entityContent:H}}});return{kind:"handled",result:{success:!0,data:{entityId:W,status:"generating",jobId:Z,attachment:Bj0(W)}}}}async promoteUpload(A,Q){let B=A.from;if(B?.kind!==lR.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let w=B.id,$;try{$=await Q.uploads.scoped(lR).readRecord(w)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(!t20($.mediaType))return{kind:"handled",result:{success:!1,error:"Only image uploads can be promoted to image entities"}};let D;try{D=e20({filename:$.filename,...A.title!==void 0?{title:A.title}:{}})}catch(Y){return{kind:"handled",result:{success:!1,error:Y instanceof Error?Y.message:String(Y)}}}await this.createPendingImage(Q,{id:D.id,title:D.title,alt:D.title,sourceUploadId:w,sourceFilename:$.filename,sourceMediaType:$.mediaType,attachmentType:"uploaded"});let f=await Q.jobs.enqueue({type:"upload-promote",data:{uploadId:w,imageId:D.id,title:D.title}});return{kind:"handled",result:{success:!0,data:{entityId:D.id,status:"generating",jobId:f,attachment:cg2({mediaType:$.mediaType,entityId:D.id,filename:$.filename})}}}}async enqueueSourceImageRender(A,Q){let B=NZ(A.from.sourceEntityType),w=NZ(A.from.sourceEntityId),$=NZ(A.from.attachmentType);if(!B||!w||!$)return{kind:"handled",result:{success:!1,error:"Image source requires sourceEntityType, sourceEntityId, and attachmentType"}};let D=await nD(Q.entityService,B,w,this.logger,"Source entity");if(!D.ok)return{kind:"handled",result:{success:!1,error:D.error}};let f=NZ(A.targetEntityType),Y=NZ(A.targetEntityId),X;if(f&&Y){let F=await nD(Q.entityService,f,Y,this.logger,"Target entity");if(!F.ok)return{kind:"handled",result:{success:!1,error:F.error}};X=F.entity.id}let H={sourceEntityType:B,sourceEntityId:D.entity.id,attachmentType:$},W=await ug2(Q,H),Z=mg2(H);await this.createPendingImage(Q,{id:Z,title:Z,alt:Z,sourceEntityType:H.sourceEntityType,sourceEntityId:H.sourceEntityId,attachmentType:$,dedupKey:W});let G=await Q.jobs.enqueue({type:"image-render-source",data:{...H,imageId:Z,dedupKey:W,...A.replace===!0&&{replace:!0},...f&&{targetEntityType:f},...X&&{targetEntityId:X},...$==="og-image"&&{targetImageField:"ogImageId"}}});return{kind:"handled",result:{success:!0,data:{entityId:Z,status:"generating",jobId:G,attachment:Bj0(Z,$)}}}}async createPendingImage(A,Q){let B=new Date().toISOString(),w=CY.createImageEntity({dataUrl:gg2,title:Q.title,alt:Q.alt,status:"pending",attachmentType:Q.attachmentType,...Q.sourceEntityType&&{sourceEntityType:Q.sourceEntityType},...Q.sourceEntityId&&{sourceEntityId:Q.sourceEntityId},...Q.sourceUploadId&&{sourceUploadId:Q.sourceUploadId},...Q.sourceFilename&&{sourceFilename:Q.sourceFilename},...Q.sourceMediaType&&{sourceMediaType:Q.sourceMediaType},...Q.dedupKey&&{dedupKey:Q.dedupKey}});await qN({entityService:A.entityService,entity:{id:Q.id,...w,created:B,updated:B}})}async getInstructions(){return'For durable raw image saves/promotions from uploaded images, call system_upload_save with the exact upload object shown in the current turn or conversation "Available upload refs" hint. Do this only after the user explicitly asks to save/import/promote the uploaded image file itself. If that hint is absent, omit upload entirely; never invent upload IDs or placeholder upload refs. Describing or summarizing an uploaded image should use it as chat context, not create an image entity. Saving an image description, discussion, interpretation, caption, summary, study notes, or a prior assistant answer as a note should call system_create with entityType "note" and source: { kind: "prior-response" }, not system_upload_save or an upload source. After a bare upload acknowledgement, a short label/title-only follow-up is ambiguous; ask what to do with the upload instead of turning that label into an AI image-generation prompt. For AI-generated images and cover images, call system_create with entityType: "image" and source: { kind: "generate", prompt }, and omit upload or attachment sources unless the user explicitly asks to reuse the uploaded image file. Cover image and OG/social preview image are separate domain concepts: cover-image changes/removal use coverImageId, while OG/Open Graph/social preview image changes use ogImageId. To remove a cover image, call system_update on the target entity with fields.coverImageId set to null; do not clear ogImageId unless the user explicitly asked to remove an OG/social preview image. For direct requests like "set image X as the cover for entity Y", call system_update with fields.coverImageId set to X; do not stop after looking up either side when the user provided exact IDs.'}createGenerationHandler(A){return new a20(A,this.logger)}async onRegister(A){A.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["image/*"],handler:async(B)=>{let w=await this.promoteUpload({entityType:this.entityType,...B.title!==void 0?{title:B.title}:{},from:B.upload},A);return w.kind==="handled"?w.result:{success:!1,error:"Image upload save was not handled"}}});let Q=new a20(A,this.logger);A.jobs.registerHandler("image-generate",Q),A.jobs.registerHandler("image-render-source",new Aj0(A,this.logger)),A.jobs.registerHandler("upload-promote",new Qj0(this.logger.child("UploadPromotionJobHandler"),A))}}function Yc(A){return new wj0(A)}p0();import{StdioServerTransport as lg2}from"@modelcontextprotocol/sdk/server/stdio.js";function YjA(){return{info:(A,...Q)=>console.error(`[STDIO MCP] ${A}`,...Q),debug:(A,...Q)=>console.error(`[STDIO MCP DEBUG] ${A}`,...Q),error:(A,...Q)=>console.error(`[STDIO MCP ERROR] ${A}`,...Q),warn:(A,...Q)=>console.error(`[STDIO MCP WARN] ${A}`,...Q)}}function $j0(){return{info:(A,...Q)=>console.log(`[HTTP MCP] ${A}`,...Q),debug:(A,...Q)=>console.debug(`[HTTP MCP DEBUG] ${A}`,...Q),error:(A,...Q)=>console.error(`[HTTP MCP ERROR] ${A}`,...Q),warn:(A,...Q)=>console.warn(`[HTTP MCP WARN] ${A}`,...Q)}}function AQ0(A){if(A&&typeof A==="object"&&"info"in A&&"debug"in A&&"error"in A&&"warn"in A){let Q=A;return{info:(B,...w)=>Q.info(B,...w),debug:(B,...w)=>Q.debug(B,...w),error:(B,...w)=>Q.error(B,...w),warn:(B,...w)=>Q.warn(B,...w)}}return $j0()}class jZ{static instance=null;mcpServer=null;transport=null;config;logger;static getInstance(A){return jZ.instance??=new jZ(A),jZ.instance}static resetInstance(){if(jZ.instance)jZ.instance.stop(),jZ.instance=null}static createFresh(A){return new jZ(A)}constructor(A={}){this.config=A,this.logger=this.config.logger?AQ0(this.config.logger):YjA()}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 lg2,await this.mcpServer.connect(this.transport),this.logger.info("Stdio transport started successfully")}stop(){if(this.logger.info("Stopping stdio transport"),this.transport)this.transport=null;this.logger.info("Stdio transport stopped")}isRunning(){return this.transport!==null}}import{randomUUID as XjA}from"crypto";import{WebStandardStreamableHTTPServerTransport as pg2}from"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";import{isInitializeRequest as ig2}from"@modelcontextprotocol/sdk/types.js";p0();var dg2={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, DELETE, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization, MCP-Session-Id, MCP-Protocol-Version, Last-Event-ID","Access-Control-Allow-Private-Network":"true","X-Content-Type-Options":"nosniff"};function ng2(A){let Q=new URL(A.url),w=A.headers.get("x-forwarded-proto")?.split(",")[0]?.trim(),$=A.headers.get("x-forwarded-host")??A.headers.get("host");if(!$)return Q.origin;return`${w??Q.protocol.replace(":","")}://${$}`}class Eq{static instance=null;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?AQ0(this.config.logger):$j0(),this.authConfig=A.auth??{},!this.authConfig.disabled&&!this.authConfig.token&&!this.authConfig.verifyBearerToken)throw Error("MCP HTTP transport requires an auth token or bearer token verifier. Set MCP_AUTH_TOKEN, configure OAuth verification, or pass auth: { disabled: true } for local dev.")}static getInstance(A){return Eq.instance??=new Eq(A),Eq.instance}static resetInstance(){Eq.instance=null}static createFresh(A){return new Eq(A)}withCors(A){let Q=new Headers(A.headers);for(let[B,w]of Object.entries(dg2))Q.set(B,w);return new Response(A.body,{status:A.status,statusText:A.statusText,headers:Q})}createJsonResponse(A,Q=200){return this.withCors(new Response(JSON.stringify(A),{status:Q,headers:{"Content-Type":"application/json"}}))}createTextResponse(A,Q=200){return this.withCors(new Response(A,{status:Q,headers:{"Content-Type":"text/plain; charset=utf-8"}}))}getAuthErrorResponse(A,Q=401,B){let w=this.createJsonResponse({jsonrpc:"2.0",error:{code:-32001,message:A},id:null},Q);if(!B)return w;let $=new Headers(w.headers);return $.set("WWW-Authenticate",B),new Response(w.body,{status:w.status,statusText:w.statusText,headers:$})}getBearerChallenge(A,Q={}){let w={resource_metadata:`${ng2(A)}/.well-known/oauth-protected-resource`,...Q};return`Bearer ${Object.entries(w).map(([D,f])=>`${D}="${rg2(f)}"`).join(", ")}`}async authenticate(A){let Q=new URL(A.url).pathname;if(Q==="/health"||Q==="/status"||Q==="/mcp"&&A.method==="OPTIONS")return null;if(this.authConfig.disabled)return null;let B=A.headers.get("authorization");if(!B?.startsWith("Bearer "))return this.logger.warn("Authentication failed: Missing Bearer token"),this.getAuthErrorResponse("Unauthorized: Bearer token required",401,this.getBearerChallenge(A,{realm:"mcp"}));if(this.authConfig.token){if(B.substring(7)!==this.authConfig.token)return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(A,{error:"invalid_token"}));return this.logger.debug("Authentication successful"),null}try{let w=await this.authConfig.verifyBearerToken?.(A);if(!w)return this.logger.warn("Authentication failed: Invalid token"),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(A,{error:"invalid_token"}));let $=this.authConfig.requiredScopes??[],D=$.filter((f)=>!w.scope?.includes(f));if(D.length>0)return this.logger.warn(`Authentication failed: Missing required scope(s): ${D.join(", ")}`),this.getAuthErrorResponse("Forbidden: Missing required scope",403,this.getBearerChallenge(A,{error:"insufficient_scope",scope:$.join(" ")}));return this.logger.debug("Authentication successful"),null}catch(w){return this.logger.warn("Authentication failed: Invalid token",w),this.getAuthErrorResponse("Unauthorized: Invalid token",401,this.getBearerChallenge(A,{error:"invalid_token"}))}}async handleMcpRequest(A){let Q=A.headers.get("mcp-session-id")??void 0;if(A.method==="GET"){if(!Q||!this.transports[Q])return this.createTextResponse("Invalid or missing session ID",400);return this.logger.debug(`GET /mcp - SSE stream for session ${Q}`),this.withCors(await this.transports[Q].handleRequest(A))}if(A.method==="DELETE"){if(!Q||!this.transports[Q])return this.createTextResponse("Invalid or missing session ID",400);return this.logger.info(`DELETE /mcp - Terminating session ${Q}`),this.withCors(await this.transports[Q].handleRequest(A))}if(A.method==="OPTIONS")return this.withCors(new Response(null,{status:204}));if(A.method!=="POST")return this.createTextResponse("Method Not Allowed",405);if(!this.mcpServer)return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Service Unavailable: MCP server not connected"},id:null},503);let B=await A.json();this.logger.debug(`POST /mcp - Session: ${Q??"new"}`);try{let w;if(Q&&this.transports[Q])w=this.transports[Q];else if(!Q&&ig2(B))w=new pg2({sessionIdGenerator:()=>XjA(),onsessioninitialized:(D)=>{this.logger.info(`Session initialized: ${D}`),this.transports[D]=w},onsessionclosed:(D)=>{this.logger.info(`Session closed: ${D}`),delete this.transports[D]}}),await(this.mcpTransport?this.mcpTransport.createMcpServer():this.mcpServer).connect(w);else return this.createJsonResponse({jsonrpc:"2.0",error:{code:-32000,message:"Bad Request: Server not initialized"},id:null},400);return this.withCors(await w.handleRequest(A,{parsedBody:B}))}catch(w){return this.logger.error("MCP transport error:",w),this.createJsonResponse({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}},500)}}async handleAgentChatRequest(A){if(!this.agentService)return this.createJsonResponse({error:"Agent service not connected"},503);let{message:Q,conversationId:B}=await A.json();if(!Q||typeof Q!=="string")return this.createJsonResponse({error:"Missing or invalid 'message' field"},400);let w=B??XjA();this.logger.debug(`POST /api/chat - conversation: ${w}`);try{let $=await this.agentService.chat(Q,w);return this.createJsonResponse($)}catch($){return this.logger.error("Agent chat error:",$),this.createJsonResponse({error:$ instanceof Error?$.message:"Internal error"},500)}}async handleAgentConfirmRequest(A){if(!this.agentService)return this.createJsonResponse({error:"Agent service not connected"},503);let{conversationId:Q,confirmed:B,approvalId:w,context:$}=await A.json();if(!Q||typeof Q!=="string")return this.createJsonResponse({error:"Missing or invalid 'conversationId' field"},400);if(typeof B!=="boolean")return this.createJsonResponse({error:"Missing or invalid 'confirmed' field"},400);if(typeof w!=="string"||w.length===0)return this.createJsonResponse({error:"Missing or invalid 'approvalId' field"},400);let D=nU0.safeParse($);if(!D.success||!D.data.userPermissionLevel)return this.createJsonResponse({error:"Missing or invalid 'context' field"},400);this.logger.debug(`POST /api/chat/confirm - conversation: ${Q}`);try{let f=await this.agentService.confirmPendingAction(Q,B,w,D.data);return this.createJsonResponse(f)}catch(f){return this.logger.error("Agent confirm error:",f),this.createJsonResponse({error:f instanceof Error?f.message:"Internal error"},500)}}async handleRequest(A){let Q=new URL(A.url);this.logger.debug(`${A.method} ${Q.pathname}`);let B=await this.authenticate(A);if(B)return B;if(Q.pathname==="/health")return this.createJsonResponse({status:"ok",transport:"streamable-http",timestamp:new Date().toISOString()});if(Q.pathname==="/status")return this.createJsonResponse({sessions:Object.keys(this.transports).length,uptime:process.uptime(),memory:process.memoryUsage(),port:this.boundPort??this.config.port??3333});if(Q.pathname==="/mcp")return this.handleMcpRequest(A);if(Q.pathname==="/api/chat"&&A.method==="POST")return this.handleAgentChatRequest(A);if(Q.pathname==="/api/chat/confirm"&&A.method==="POST")return this.handleAgentConfirmRequest(A);return this.createTextResponse("Not Found",404)}connectMCPServer(A,Q){this.mcpServer=A,this.mcpTransport=Q??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=Number(this.config.port??3333),Q=this.config.host??"0.0.0.0";try{this.server=Bun.serve({port:A,hostname:Q,fetch:(B)=>this.handleRequest(B)}),this.boundPort=this.server.port??A,this.logger.info(`StreamableHTTP server listening on http://${Q}:${this.boundPort}/mcp`)}catch(B){if(B.code==="EADDRINUSE")this.logger.error(`Port ${A} is already in use`);throw B}}async stop(){for(let A in this.transports)try{let Q=this.transports[A];if(Q)this.logger.debug(`Closing transport for session ${A}`),await Q.close(),delete this.transports[A]}catch(Q){this.logger.error(`Error closing transport for session ${A}:`,Q)}if(this.server)await this.server.stop(),this.logger.info("StreamableHTTP server stopped"),this.server=null,this.boundPort=null}getPort(){if(this.boundPort===null)throw Error("Server is not running");return this.boundPort}getApp(){return{fetch:(A)=>this.handleRequest(A)}}isRunning(){return this.server!==null}getSessionCount(){return Object.keys(this.transports).length}}function rg2(A){return A.replace(/["\\]/g,(Q)=>`\\${Q}`)}import{randomUUID as sg2}from"crypto";import{mkdir as ag2,readFile as tg2,writeFile as eg2,chmod as AT2}from"fs/promises";import{dirname as QT2,join as BT2}from"path";function HjA(A){let Q=A.toLowerCase();return Q==="localhost"||Q==="[::1]"||Q==="::1"||Q.startsWith("127.")}function WjA(A){try{return new URL(A)}catch{return}}function Dj0(A,Q){if(A===Q)return!0;let B=WjA(A),w=WjA(Q);if(!B||!w)return!1;if(!HjA(B.hostname)||!HjA(w.hostname))return!1;return B.protocol===w.protocol&&B.port===w.port&&og2(B.pathname,w.pathname)&&B.search===w.search&&B.hash===w.hash}function og2(A,Q){return A===Q||A===`${Q}/debug`||Q===`${A}/debug`}function fj0(A,Q){return A.some((B)=>Dj0(B,Q))}var wT2="oauth-auth-codes.json",$T2=600;function ZjA(){return Math.floor(Date.now()/1000)}function DT2(A){if(!A||typeof A!=="object")return!1;let Q=A;return typeof Q.code==="string"&&typeof Q.client_id==="string"&&typeof Q.redirect_uri==="string"&&typeof Q.code_challenge==="string"&&Q.code_challenge_method==="S256"&&typeof Q.subject==="string"&&typeof Q.created_at==="number"&&typeof Q.expires_at==="number"}function fT2(A){if(!A||typeof A!=="object")return{codes:[]};let Q=A.codes;if(!Array.isArray(Q))return{codes:[]};return{codes:Q.filter(DT2)}}async function YT2(A){let Q=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(A));return Buffer.from(Q).toString("base64url")}class QQ0{storeFile;writeQueue=Promise.resolve();constructor(A){this.storeFile=BT2(A.storageDir,A.storeFile??wT2)}async createCode(A){let Q=ZjA(),B={code:`ocd_${sg2()}`,client_id:A.clientId,redirect_uri:A.redirectUri,code_challenge:A.codeChallenge,code_challenge_method:"S256",...A.scope?{scope:A.scope}:{},subject:A.subject,created_at:Q,expires_at:Q+$T2};return await this.enqueueWrite(async()=>{let w=await this.readStore();w.codes=w.codes.filter(($)=>$.expires_at>Q),w.codes.push(B),await this.writeStore(w)}),B}async consumeCode(A){let Q=ZjA(),B;if(await this.enqueueWrite(async()=>{let w=await this.readStore(),$=w.codes.findIndex((Y)=>Y.code===A.code),D=$>=0?w.codes[$]:void 0;if(!D)throw new _Z("Authorization code not found");if(D.consumed_at!==void 0)throw new _Z("Authorization code already consumed");if(D.expires_at<=Q)throw new _Z("Authorization code expired");if(D.client_id!==A.clientId)throw new _Z("Authorization code client mismatch");if(!Dj0(D.redirect_uri,A.redirectUri))throw new _Z("Authorization code redirect URI mismatch");let f=await YT2(A.codeVerifier);if(D.code_challenge!==f)throw new _Z("PKCE verification failed");B={...D,consumed_at:Q},w.codes[$]=B,await this.writeStore(w)}),!B)throw new _Z("Authorization code not consumed");return B}async enqueueWrite(A){return this.writeQueue=this.writeQueue.then(A,A),this.writeQueue}async readStore(){try{return fT2(JSON.parse(await tg2(this.storeFile,"utf8")))}catch(A){if(A.code==="ENOENT")return{codes:[]};throw A}}async writeStore(A){await ag2(QT2(this.storeFile),{recursive:!0,mode:448}),await eg2(this.storeFile,`${JSON.stringify(A,null,2)}
|
|
1843
1843
|
`,{mode:384}),await AT2(this.storeFile,384)}}class _Z extends Error{constructor(A){super(A);this.name="InvalidGrantError"}}K0();import{randomUUID as KjA}from"crypto";import{mkdir as XT2,readFile as HT2,writeFile as WT2,chmod as ZT2}from"fs/promises";import{dirname as KT2,join as UT2}from"path";var GT2="oauth-clients.json",zT2=K.enum(["none","client_secret_basic","client_secret_post"]),qT2=K.object({redirect_uris:K.array(K.string().url()).min(1),token_endpoint_auth_method:zT2.default("none"),grant_types:K.array(K.enum(["authorization_code","refresh_token"])).default(["authorization_code","refresh_token"]),response_types:K.array(K.literal("code")).default(["code"]),scope:K.string().optional(),client_name:K.string().optional(),client_uri:K.string().url().optional(),logo_uri:K.string().url().optional(),contacts:K.array(K.string()).optional()});function FT2(){return Math.floor(Date.now()/1000)}function IT2(){return`ocs_${KjA().replaceAll("-","")}`}function VT2(A){if(!A||typeof A!=="object")return{clients:[]};let Q=A.clients;if(!Array.isArray(Q))return{clients:[]};return{clients:Q.filter(JT2)}}function JT2(A){if(!A||typeof A!=="object")return!1;let Q=A;return typeof Q.client_id==="string"&&Array.isArray(Q.redirect_uris)&&Q.redirect_uris.every((B)=>typeof B==="string")&&typeof Q.client_id_issued_at==="number"}class BQ0{storeFile;writeQueue=Promise.resolve();constructor(A){this.storeFile=UT2(A.storageDir,A.storeFile??GT2)}async registerClient(A){let Q=qT2.safeParse(A);if(!Q.success)throw new Xc(Q.error.message);let B=Q.data,w=FT2(),$=`oc_${KjA()}`,D=B.token_endpoint_auth_method==="none",f={client_id:$,client_id_issued_at:w,redirect_uris:B.redirect_uris,token_endpoint_auth_method:B.token_endpoint_auth_method,grant_types:B.grant_types,response_types:B.response_types,...B.scope?{scope:B.scope}:{},...B.client_name?{client_name:B.client_name}:{},...B.client_uri?{client_uri:B.client_uri}:{},...B.logo_uri?{logo_uri:B.logo_uri}:{},...B.contacts?{contacts:B.contacts}:{},...!D?{client_secret:IT2(),client_secret_expires_at:0}:{}};return await this.enqueueWrite(async()=>{let Y=await this.readStore();Y.clients.push(f),await this.writeStore(Y)}),f}async getClient(A){return(await this.readStore()).clients.find((B)=>B.client_id===A)}async enqueueWrite(A){return this.writeQueue=this.writeQueue.then(A,A),this.writeQueue}async readStore(){try{return VT2(JSON.parse(await HT2(this.storeFile,"utf8")))}catch(A){if(A.code==="ENOENT")return{clients:[]};throw A}}async writeStore(A){await XT2(KT2(this.storeFile),{recursive:!0,mode:448}),await WT2(this.storeFile,`${JSON.stringify(A,null,2)}
|
|
1844
1844
|
`,{mode:384}),await ZT2(this.storeFile,384)}}class Xc extends Error{constructor(A){super(A);this.name="InvalidClientMetadataError"}}import{createHash as LT2}from"crypto";import{mkdir as bT2,readFile as NT2,writeFile as jT2,chmod as _T2}from"fs/promises";import{dirname as MT2,join as PT2}from"path";var kT2="oauth-signing-key.jwk";function UjA(A){if(!A||typeof A!=="object")return!1;let Q=A;return Q.kty==="EC"&&Q.crv==="P-256"&&typeof Q.x==="string"&&typeof Q.y==="string"&&typeof Q.d==="string"}function GjA(A){let Q=JSON.stringify({crv:A.crv,kty:A.kty,x:A.x,y:A.y});return LT2("sha256").update(Q).digest("base64url")}function OT2(A){return{kty:"EC",crv:"P-256",x:A.x,y:A.y,kid:A.kid,use:"sig",alg:"ES256"}}async function xT2(){let A=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!0,["sign","verify"]),Q=await crypto.subtle.exportKey("jwk",A.privateKey);if(!UjA(Q))throw Error("Generated OAuth signing key is not a P-256 private JWK");let B=GjA(Q);return{...Q,kid:B,use:"sig",alg:"ES256"}}class wQ0{keyFile;cachedKey;loadPromise;constructor(A){this.keyFile=PT2(A.storageDir,A.keyFile??kT2)}async getPrivateJwk(){if(this.cachedKey)return this.cachedKey;this.loadPromise??=this.loadOrCreateKey();try{return this.cachedKey=await this.loadPromise,this.cachedKey}catch(A){throw this.loadPromise=void 0,A}}async loadOrCreateKey(){let A=await this.readExistingKey();if(A)return A;let Q=await xT2();return await bT2(MT2(this.keyFile),{recursive:!0,mode:448}),await jT2(this.keyFile,`${JSON.stringify(Q,null,2)}
|
|
1845
1845
|
`,{mode:384}),await _T2(this.keyFile,384),Q}async getPublicJwk(){return OT2(await this.getPrivateJwk())}async readExistingKey(){try{let A=JSON.parse(await NT2(this.keyFile,"utf8"));if(!UjA(A))throw Error(`OAuth signing key at ${this.keyFile} is not a private P-256 JWK`);let Q=typeof A.kid==="string"?A.kid:GjA(A);return{...A,kid:Q,use:"sig",alg:"ES256"}}catch(A){if(A.code==="ENOENT")return;throw A}}}var $Q={};sB($Q,{trimPadding:()=>qjA,toUTF8String:()=>ST2,toBuffer:()=>yT2,toBase64:()=>gT2,isBase64URL:()=>uT2,isBase64:()=>mT2,fromUTF8String:()=>TT2,fromBuffer:()=>ET2});var zjA=(A)=>{let Q=typeof Uint8Array>"u"?[]:new Uint8Array(256),B=64;for(let w=0;w<64;w++)Q[A.charCodeAt(w)]=w;return Q},RT2=zjA("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),vT2=zjA("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),hT2=/^[-A-Za-z0-9\-_]*$/,CT2=/^[-A-Za-z0-9+/]*={0,3}$/,EU={};EU.toArrayBuffer=(A,Q)=>{let B=A.length,w=A.length*0.75,$,D=0,f,Y,X,H;if(A[A.length-1]==="="){if(w--,A[A.length-2]==="=")w--}let W=new ArrayBuffer(w),Z=new Uint8Array(W),G=Q?vT2:RT2;for($=0;$<B;$+=4)f=G[A.charCodeAt($)],Y=G[A.charCodeAt($+1)],X=G[A.charCodeAt($+2)],H=G[A.charCodeAt($+3)],Z[D++]=f<<2|Y>>4,Z[D++]=(Y&15)<<4|X>>2,Z[D++]=(X&3)<<6|H&63;return W};EU.fromArrayBuffer=(A,Q)=>{let B=new Uint8Array(A),w,$="",D=B.length,f=Q?"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(w=0;w<D;w+=3)$+=f[B[w]>>2],$+=f[(B[w]&3)<<4|B[w+1]>>4],$+=f[(B[w+1]&15)<<2|B[w+2]>>6],$+=f[B[w+2]&63];let Y=D%3;if(Y===2)$=$.substring(0,$.length-1)+(Q?"":"=");else if(Y===1)$=$.substring(0,$.length-2)+(Q?"":"==");return $};EU.toString=(A,Q)=>{return new TextDecoder().decode(EU.toArrayBuffer(A,Q))};EU.fromString=(A,Q)=>{return EU.fromArrayBuffer(new TextEncoder().encode(A),Q)};EU.validate=(A,Q)=>{if(!(typeof A==="string"||A instanceof String))return!1;try{return Q?hT2.test(A):CT2.test(A)}catch(B){return!1}};EU.base64=EU;var gq=EU;function yT2(A,Q="base64url"){let B=gq.toArrayBuffer(A,Q==="base64url");return new Uint8Array(B)}function ET2(A,Q="base64url"){let B=new Uint8Array(A);return gq.fromArrayBuffer(B.buffer,Q==="base64url")}function gT2(A){let Q=gq.toArrayBuffer(A,!0);return gq.fromArrayBuffer(Q)}function TT2(A){return gq.fromString(A,!0)}function ST2(A){return gq.toString(A,!0)}function mT2(A){return gq.validate(A,!1)}function uT2(A){return A=qjA(A),gq.validate(A,!0)}function qjA(A){return A.replace(/=/g,"")}var fD={};sB(fD,{encode:()=>XS2,decodeFirst:()=>YS2});function pR(A,Q,B){if(Q<24)return[Q,1];let w=A.byteLength-B-1,$=new DataView(A.buffer,B+1),D,f=0;switch(Q){case 24:{if(w>0)D=$.getUint8(0),f=2;break}case 25:{if(w>1)D=$.getUint16(0,!1),f=3;break}case 26:{if(w>3)D=$.getUint32(0,!1),f=5;break}case 27:{if(w>7){let Y=$.getBigUint64(0,!1);if(Y>=24n&&Y<=Number.MAX_SAFE_INTEGER)return[Number(Y),9]}break}}if(D&&D>=24)return[D,f];throw Error("Length not supported or not well formed")}var $Q0=0,Hc=1,Yj0=2,Xj0=3,Hj0=4,Wj0=5,Zj0=6,FjA=7;function gU(A,Q){let B=A<<5;if(Q<0)throw Error("CBOR Data Item argument must not be negative");let w;if(typeof Q=="number"){if(!Number.isInteger(Q))throw Error("CBOR Data Item argument must be an integer");w=BigInt(Q)}else w=Q;if(A==Hc){if(w==0n)throw Error("CBOR Data Item argument cannot be zero when negative");w=w-1n}if(w>18446744073709551615n)throw Error("CBOR number out of range");let $=new Uint8Array(8);if(new DataView($.buffer).setBigUint64(0,w,!1),w<=23)return[B|$[7]];else if(w<=255)return[B|24,$[7]];else if(w<=65535)return[B|25,...$.slice(6)];else if(w<=4294967295)return[B|26,...$.slice(4)];else return[B|27,...$]}class fQ0{constructor(A,Q){Object.defineProperty(this,"tagId",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"tagValue",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.tagId=A,this.tagValue=Q}get tag(){return this.tagId}get value(){return this.tagValue}}function IjA(A,Q,B){return pR(A,Q,B)}function cT2(A,Q,B){let[w,$]=IjA(A,Q,B);return[-w-1,$]}function VjA(A,Q,B){let[w,$]=pR(A,Q,B),D=B+$;return[new Uint8Array(A.buffer.slice(D,D+w)),$+w]}var lT2=new TextDecoder;function pT2(A,Q,B){let[w,$]=VjA(A,Q,B);return[lT2.decode(w),$]}function iT2(A,Q,B){if(Q===0)return[[],1];let[w,$]=pR(A,Q,B),D=$,f=[];for(let Y=0;Y<w;Y++){if(A.byteLength-B-D<=0)throw Error("array is not supported or well formed");let[H,W]=bj(A,B+D);f.push(H),D+=W}return[f,D]}var DQ0="Map is not supported or well formed";function dT2(A,Q,B){if(Q===0)return[new Map,1];let[w,$]=pR(A,Q,B),D=$,f=new Map;for(let Y=0;Y<w;Y++){let X=A.byteLength-B-D;if(X<=0)throw Error(DQ0);let[H,W]=bj(A,B+D);if(D+=W,X-=W,X<=0)throw Error(DQ0);if(typeof H!=="string"&&typeof H!=="number")throw Error(DQ0);if(f.has(H))throw Error(DQ0);let[Z,G]=bj(A,B+D);D+=G,f.set(H,Z)}return[f,D]}function nT2(A,Q){if(Q+3>A.byteLength)throw Error("CBOR stream ended before end of Float 16");let B=A.getUint16(Q+1,!1);if(B==31744)return[1/0,3];else if(B==32256)return[NaN,3];else if(B==64512)return[-1/0,3];throw Error("Float16 data is unsupported")}function rT2(A,Q){if(Q+5>A.byteLength)throw Error("CBOR stream ended before end of Float 32");return[A.getFloat32(Q+1,!1),5]}function oT2(A,Q){if(Q+9>A.byteLength)throw Error("CBOR stream ended before end of Float 64");return[A.getFloat64(Q+1,!1),9]}function sT2(A,Q,B){let[w,$]=pR(A,Q,B),[D,f]=bj(A,B+$);return[new fQ0(w,D),$+f]}function bj(A,Q){if(Q>=A.byteLength)throw Error("CBOR stream ended before tag value");let B=A.getUint8(Q),w=B>>5,$=B&31;switch(w){case $Q0:return IjA(A,$,Q);case Hc:return cT2(A,$,Q);case Yj0:return VjA(A,$,Q);case Xj0:return pT2(A,$,Q);case Hj0:return iT2(A,$,Q);case Wj0:return dT2(A,$,Q);case Zj0:return sT2(A,$,Q);case FjA:switch($){case 20:return[!1,1];case 21:return[!0,1];case 22:return[null,1];case 23:return[void 0,1];case 25:return nT2(A,Q);case 26:return rT2(A,Q);case 27:return oT2(A,Q)}}throw Error(`Unsupported or not well formed at ${Q}`)}function aT2(A){if(A===!0)return 245;else if(A===!1)return 244;else if(A===null)return 246;return 247}function tT2(A){if(Math.fround(A)==A||!Number.isFinite(A)||Number.isNaN(A)){let Q=new Uint8Array(5);return Q[0]=250,new DataView(Q.buffer).setFloat32(1,A,!1),Q}else{let Q=new Uint8Array(9);return Q[0]=251,new DataView(Q.buffer).setFloat64(1,A,!1),Q}}function eT2(A){if(typeof A=="number"){if(Number.isSafeInteger(A))if(A<0)return gU(Hc,Math.abs(A));else return gU($Q0,A);return[tT2(A)]}else if(A<0n)return gU(Hc,A*-1n);else return gU($Q0,A)}var AS2=new TextEncoder;function QS2(A,Q){Q.push(...gU(Xj0,A.length)),Q.push(AS2.encode(A))}function BS2(A,Q){Q.push(...gU(Yj0,A.length)),Q.push(A)}function wS2(A,Q){Q.push(...gU(Hj0,A.length));for(let B of A)Wc(B,Q)}function $S2(A,Q){Q.push(new Uint8Array(gU(Wj0,A.size)));for(let[B,w]of A.entries())Wc(B,Q),Wc(w,Q)}function DS2(A,Q){Q.push(...gU(Zj0,A.tag)),Wc(A.value,Q)}function Wc(A,Q){if(typeof A=="boolean"||A===null||A==null){Q.push(aT2(A));return}if(typeof A=="number"||typeof A=="bigint"){Q.push(...eT2(A));return}if(typeof A=="string"){QS2(A,Q);return}if(A instanceof Uint8Array){BS2(A,Q);return}if(Array.isArray(A)){wS2(A,Q);return}if(A instanceof Map){$S2(A,Q);return}if(A instanceof fQ0){DS2(A,Q);return}throw Error("Not implemented")}function Kj0(A,Q){if(A.byteLength===0||A.byteLength<=Q||Q<0)throw Error("No data");if(A instanceof Uint8Array)return bj(new DataView(A.buffer),Q);else if(A instanceof ArrayBuffer)return bj(new DataView(A),Q);return bj(A,Q)}function Uj0(A){let Q=[];Wc(A,Q);let B=0;for(let D of Q)if(typeof D=="number")B+=1;else B+=D.length;let w=new Uint8Array(B),$=0;for(let D of Q)if(typeof D=="number")w[$]=D,$+=1;else w.set(D,$),$+=D.length;return w}function YS2(A){let Q=new Uint8Array(A),B=Kj0(Q,0),[w]=B;return w}function XS2(A){return Uj0(A)}var SU={};sB(SU,{verify:()=>AOA,getRandomValues:()=>jjA,digest:()=>NjA});function JjA(A){let Q=A.get(QQ.kty);return Gj0(Q)&&Q===gY.OKP}function LV(A){let Q=A.get(QQ.kty);return Gj0(Q)&&Q===gY.EC2}function iR(A){let Q=A.get(QQ.kty);return Gj0(Q)&&Q===gY.RSA}var QQ;(function(A){A[A.kty=1]="kty",A[A.alg=3]="alg",A[A.crv=-1]="crv",A[A.x=-2]="x",A[A.y=-3]="y",A[A.n=-1]="n",A[A.e=-2]="e"})(QQ||(QQ={}));var gY;(function(A){A[A.OKP=1]="OKP",A[A.EC2=2]="EC2",A[A.RSA=3]="RSA"})(gY||(gY={}));function Gj0(A){return Object.values(gY).indexOf(A)>=0}var Y4;(function(A){A[A.P256=1]="P256",A[A.P384=2]="P384",A[A.P521=3]="P521",A[A.ED25519=6]="ED25519",A[A.SECP256K1=8]="SECP256K1"})(Y4||(Y4={}));function LjA(A){return Object.values(Y4).indexOf(A)>=0}var RQ;(function(A){A[A.ES256=-7]="ES256",A[A.EdDSA=-8]="EdDSA",A[A.ES384=-35]="ES384",A[A.ES512=-36]="ES512",A[A.PS256=-37]="PS256",A[A.PS384=-38]="PS384",A[A.PS512=-39]="PS512",A[A.ES256K=-47]="ES256K",A[A.RS256=-257]="RS256",A[A.RS384=-258]="RS384",A[A.RS512=-259]="RS512",A[A.RS1=-65535]="RS1"})(RQ||(RQ={}));function TU(A){return Object.values(RQ).indexOf(A)>=0}function bV(A){if([RQ.RS1].indexOf(A)>=0)return"SHA-1";else if([RQ.ES256,RQ.PS256,RQ.RS256].indexOf(A)>=0)return"SHA-256";else if([RQ.ES384,RQ.PS384,RQ.RS384].indexOf(A)>=0)return"SHA-384";else if([RQ.ES512,RQ.PS512,RQ.RS512,RQ.EdDSA].indexOf(A)>=0)return"SHA-512";throw Error(`Could not map COSE alg value of ${A} to a WebCrypto alg`)}var Zc=void 0;function wf(){return new Promise((Q,B)=>{if(Zc)return Q(Zc);let w=WS2.stubThisGlobalThisCrypto();if(w)return Zc=w,Q(Zc);return B(new bjA)})}class bjA extends Error{constructor(){super("An instance of the Crypto API could not be located");this.name="MissingWebCrypto"}}var WS2={stubThisGlobalThisCrypto:()=>globalThis.crypto,setCachedCrypto:(A)=>{Zc=A}};async function NjA(A,Q){let B=await wf(),w=bV(Q),$=await B.subtle.digest(w,A);return new Uint8Array($)}async function jjA(A){return(await wf()).getRandomValues(A),A}async function dR(A){let Q=await wf(),{keyData:B,algorithm:w}=A;return Q.subtle.importKey("jwk",B,w,!1,["verify"])}async function YQ0(A){let{cosePublicKey:Q,signature:B,data:w,shaHashOverride:$}=A,D=await wf(),f=Q.get(QQ.alg),Y=Q.get(QQ.crv),X=Q.get(QQ.x),H=Q.get(QQ.y);if(!f)throw Error("Public key was missing alg (EC2)");if(!Y)throw Error("Public key was missing crv (EC2)");if(!X)throw Error("Public key was missing x (EC2)");if(!H)throw Error("Public key was missing y (EC2)");let W;if(Y===Y4.P256)W="P-256";else if(Y===Y4.P384)W="P-384";else if(Y===Y4.P521)W="P-521";else throw Error(`Unexpected COSE crv value of ${Y} (EC2)`);let Z={kty:"EC",crv:W,x:$Q.fromBuffer(X),y:$Q.fromBuffer(H),ext:!1},F=await dR({keyData:Z,algorithm:{name:"ECDSA",namedCurve:W}}),I=bV(f);if($)I=bV($);let L={name:"ECDSA",hash:{name:I}};return D.subtle.verify(L,F,B,w)}function zj0(A){if([RQ.EdDSA].indexOf(A)>=0)return"Ed25519";else if([RQ.ES256,RQ.ES384,RQ.ES512,RQ.ES256K].indexOf(A)>=0)return"ECDSA";else if([RQ.RS256,RQ.RS384,RQ.RS512,RQ.RS1].indexOf(A)>=0)return"RSASSA-PKCS1-v1_5";else if([RQ.PS256,RQ.PS384,RQ.PS512].indexOf(A)>=0)return"RSA-PSS";throw Error(`Could not map COSE alg value of ${A} to a WebCrypto key alg name`)}async function XQ0(A){let{cosePublicKey:Q,signature:B,data:w,shaHashOverride:$}=A,D=await wf(),f=Q.get(QQ.alg),Y=Q.get(QQ.n),X=Q.get(QQ.e);if(!f)throw Error("Public key was missing alg (RSA)");if(!TU(f))throw Error(`Public key had invalid alg ${f} (RSA)`);if(!Y)throw Error("Public key was missing n (RSA)");if(!X)throw Error("Public key was missing e (RSA)");let H={kty:"RSA",alg:"",n:$Q.fromBuffer(Y),e:$Q.fromBuffer(X),ext:!1},W={name:zj0(f),hash:{name:bV(f)}},Z={name:zj0(f)};if($)W.hash.name=bV($);if(W.name==="RSASSA-PKCS1-v1_5"){if(W.hash.name==="SHA-256")H.alg="RS256";else if(W.hash.name==="SHA-384")H.alg="RS384";else if(W.hash.name==="SHA-512")H.alg="RS512";else if(W.hash.name==="SHA-1")H.alg="RS1"}else if(W.name==="RSA-PSS"){let F=0;if(W.hash.name==="SHA-256")H.alg="PS256",F=32;else if(W.hash.name==="SHA-384")H.alg="PS384",F=48;else if(W.hash.name==="SHA-512")H.alg="PS512",F=64;Z.saltLength=F}else throw Error(`Unexpected RSA key algorithm ${f} (${W.name})`);let G=await dR({keyData:H,algorithm:W});return D.subtle.verify(Z,G,B,w)}function HQ0(A){let Q=q2.toHex(A);return[Q.slice(0,8),Q.slice(8,12),Q.slice(12,16),Q.slice(16,20),Q.slice(20,32)].join("-")}function G$(A){let Q;if(typeof A==="string")if($Q.isBase64URL(A))Q=$Q.toBase64(A);else if($Q.isBase64(A))Q=A;else throw Error("Certificate is not a valid base64 or base64url string");else Q=$Q.fromBuffer(A,"base64");let B="";for(let w=0;w<Math.ceil(Q.length/64);w+=1){let $=64*w;B+=`${Q.substr($,64)}
|
|
@@ -2418,8 +2418,8 @@ ${N}`)}if(w!==void 0&&D?.algorithms!==void 0){let b=D.algorithms.map((N)=>N.alg)
|
|
|
2418
2418
|
</form>
|
|
2419
2419
|
</main>
|
|
2420
2420
|
</body>
|
|
2421
|
-
</html>`}function sl(A){let Q=`${new URL(A.url).pathname}${new URL(A.url).search}`;return new Response(xP0(Q,"Operator login required"),{status:401,headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}})}function AG(A){return A.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""")}import{randomUUID as cc2}from"crypto";function UxA(A){return Buffer.from(JSON.stringify(A)).toString("base64url")}function uc2(A){let Q=new Uint8Array(A);if(Q.length===64)return Q;if(Q[0]!==48)return Q;let B=2;if(Q[1]&&Q[1]>128)B+=Q[1]-128;if(Q[B]!==2)throw Error("Invalid DER ECDSA signature");let w=Q[B+1];if(w===void 0)throw Error("Invalid DER ECDSA signature");let $=B+2,D=Q.slice($,$+w);if(B=$+w,Q[B]!==2)throw Error("Invalid DER ECDSA signature");let f=Q[B+1];if(f===void 0)throw Error("Invalid DER ECDSA signature");let Y=B+2,X=Q.slice(Y,Y+f);return new Uint8Array([...GxA(D),...GxA(X)])}function GxA(A){let Q=A;while(Q.length>32&&Q[0]===0)Q=Q.slice(1);if(Q.length>32)throw Error("Invalid P-256 signature component length");if(Q.length===32)return Q;let B=new Uint8Array(32);return B.set(Q,32-Q.length),B}async function vP0(A,Q){let B={typ:"JWT",alg:"ES256",kid:A.kid},w=`${UxA(B)}.${UxA(Q)}`,$=await crypto.subtle.importKey("jwk",A,{name:"ECDSA",namedCurve:"P-256"},!1,["sign"]),D=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},$,new TextEncoder().encode(w));return`${w}.${Buffer.from(uc2(D)).toString("base64url")}`}var lc2=600;class hP0{clientStore;authCodeStore;refreshTokenStore;sessionStore;keyStore;authorizationApprovalTokens=new Map;constructor(A){this.clientStore=A.clientStore,this.authCodeStore=A.authCodeStore,this.refreshTokenStore=A.refreshTokenStore,this.sessionStore=A.sessionStore,this.keyStore=A.keyStore}async handleAuthorizePage(A){let Q=await this.sessionStore.getSessionFromRequest(A);if(!Q)return sl(A);let B=await this.validateAuthorizationRequest(new URL(A.url).searchParams);if(!B.success)return new Response(B.error,{status:400});let w=this.createAuthorizationApprovalToken(Q,B.params);return Kh(KxA(B.params,w))}async handleAuthorizeApproval(A){let Q=await this.sessionStore.getSessionFromRequest(A);if(!Q)return sl(A);let B=await A.formData(),w=await this.validateAuthorizationRequest(new URLSearchParams(MP0(B)));if(!w.success)return new Response(w.error,{status:400});let $=B.get("approval_token"),D=typeof $==="string"?$:void 0;if(!D||!this.consumeAuthorizationApprovalToken(D,Q,w.params))return new Response("Invalid authorization approval token",{status:400});let f=await this.authCodeStore.createCode({clientId:w.params.clientId,redirectUri:w.params.redirectUri,codeChallenge:w.params.codeChallenge,...w.params.scope?{scope:w.params.scope}:{},subject:Q.subject}),Y=new URL(w.params.redirectUri);if(Y.searchParams.set("code",f.code),w.params.state)Y.searchParams.set("state",w.params.state);return Response.redirect(Y.toString(),302)}createAuthorizationApprovalToken(A,Q){this.pruneExpiredAuthorizationApprovalTokens();let B=`oat_${cc2()}`;return this.authorizationApprovalTokens.set(B,{token:B,sessionId:A.id,clientId:Q.clientId,redirectUri:Q.redirectUri,codeChallenge:Q.codeChallenge,...Q.scope?{scope:Q.scope}:{},...Q.state?{state:Q.state}:{},expiresAt:Math.floor(Date.now()/1000)+lc2}),B}consumeAuthorizationApprovalToken(A,Q,B){this.pruneExpiredAuthorizationApprovalTokens();let w=this.authorizationApprovalTokens.get(A);if(!w)return!1;return this.authorizationApprovalTokens.delete(A),w.sessionId===Q.id&&w.clientId===B.clientId&&w.redirectUri===B.redirectUri&&w.codeChallenge===B.codeChallenge&&w.scope===B.scope&&w.state===B.state}pruneExpiredAuthorizationApprovalTokens(){let A=Math.floor(Date.now()/1000);for(let[Q,B]of this.authorizationApprovalTokens.entries())if(B.expiresAt<=A)this.authorizationApprovalTokens.delete(Q)}async validateAuthorizationRequest(A){let Q=A.get("response_type"),B=A.get("client_id"),w=A.get("redirect_uri"),$=A.get("code_challenge"),D=A.get("code_challenge_method"),f=A.get("scope")??void 0,Y=A.get("state")??void 0;if(Q!=="code")return{success:!1,error:"Unsupported response_type"};if(!B)return{success:!1,error:"Missing client_id"};if(!w)return{success:!1,error:"Missing redirect_uri"};if(!$)return{success:!1,error:"Missing code_challenge"};if(D!=="S256")return{success:!1,error:"Unsupported code_challenge_method"};let X=await this.clientStore.getClient(B);if(!X)return{success:!1,error:"Unknown client_id"};if(!fj0(X.redirect_uris,w))return{success:!1,error:"Unregistered redirect_uri"};let H=f??X.scope;return{success:!0,params:{clientId:B,redirectUri:w,codeChallenge:$,...H?{scope:H}:{},...Y?{state:Y}:{},clientName:X.client_name??X.client_id}}}async handleClientRegistration(A){let Q;try{Q=await A.json()}catch{return y6("invalid_client_metadata","Request body must be JSON")}try{let B=await this.clientStore.registerClient(Q);return iY(B,201)}catch(B){if(B instanceof Xc)return y6("invalid_client_metadata",B.message);throw B}}async handleTokenRequest(A,Q){let B=await _P0(A),w=B.get("grant_type"),$=kP0(A,B),D=$.clientId??B.get("client_id");if($.error)return y6("invalid_client",$.error);if(!D)return y6("invalid_request","client_id is required");let f=await this.clientStore.getClient(D),Y=PP0(f,$);if(Y)return y6("invalid_client",Y);if(w==="authorization_code")return this.handleAuthorizationCodeGrant(B,D,Q);if(w==="refresh_token")return this.handleRefreshTokenGrant(B,D,Q);return y6("unsupported_grant_type","Only authorization_code and refresh_token are supported")}async handleAuthorizationCodeGrant(A,Q,B){let w=A.get("code"),$=A.get("redirect_uri"),D=A.get("code_verifier");if(!w||!$||!D)return y6("invalid_request","code, redirect_uri, and code_verifier are required");let f=await this.clientStore.getClient(Q);if(!f||!fj0(f.redirect_uris,$))return y6("invalid_grant","Unregistered redirect_uri");try{let Y=await this.authCodeStore.consumeCode({code:w,clientId:Q,redirectUri:$,codeVerifier:D});return await this.createTokenResponse({issuer:B,clientId:Q,subject:Y.subject,...Y.scope?{scope:Y.scope}:{}})}catch(Y){if(Y instanceof _Z)return y6("invalid_grant",Y.message);throw Y}}async handleRefreshTokenGrant(A,Q,B){let w=A.get("refresh_token");if(!w)return y6("invalid_request","refresh_token is required");try{let $=await this.refreshTokenStore.rotateToken(w,Q);return await this.createTokenResponse({issuer:B,clientId:Q,subject:$.consumed.subject,...$.consumed.scope?{scope:$.consumed.scope}:{},refreshToken:$.replacement.token})}catch($){if($ instanceof f3)return y6("invalid_grant",$.message);throw $}}async createTokenResponse(A){let Q=Math.floor(Date.now()/1000),B=900,w=await vP0(await this.keyStore.getPrivateJwk(),{iss:A.issuer,sub:A.subject,aud:A.clientId,iat:Q,exp:Q+900,...A.scope?{scope:A.scope}:{}}),$=A.refreshToken??(await this.refreshTokenStore.issueToken({clientId:A.clientId,subject:A.subject,...A.scope?{scope:A.scope}:{}})).token;return iY({access_token:w,token_type:"Bearer",expires_in:900,...A.scope?{scope:A.scope}:{},refresh_token:$})}async handleRevokeRequest(A){let Q=await _P0(A),B=kP0(A,Q),w=B.clientId??Q.get("client_id")??void 0,$=Q.get("token");if(B.error)return y6("invalid_client",B.error);if(!$)return y6("invalid_request","token is required");if(w){let D=await this.clientStore.getClient(w),f=PP0(D,B);if(f)return y6("invalid_client",f)}return await this.refreshTokenStore.revokeToken($,w),new Response(null,{status:200})}}class CP0{passkeyService;sessionStore;setupFlow;constructor(A){this.passkeyService=A.passkeyService,this.sessionStore=A.sessionStore,this.setupFlow=A.setupFlow}async handleRegistrationOptions(A){if(await this.passkeyService.hasCredentials())return y6("access_denied","Passkey setup already completed");if(!this.setupFlow.hasValidSetupToken(A))return y6("access_denied","Invalid setup token");let Q=await this.passkeyService.generateRegistrationOptions(uB0(A));return iY(Q)}async handleRegistrationVerify(A){if(await this.passkeyService.hasCredentials())return y6("access_denied","Passkey setup already completed");if(!this.setupFlow.hasValidSetupToken(A))return y6("access_denied","Invalid setup token");let Q=await this.passkeyService.verifyRegistrationResponse(await A.json(),uB0(A));if(!Q.verified)return y6("access_denied","Passkey registration failed");await this.setupFlow.clearSetupState();let B=await this.sessionStore.createSession(Q.subject??"single-operator",{secure:dl(A)});return iY({verified:!0},200,{"Set-Cookie":B.cookie})}async handleAuthenticationOptions(A){if(!await this.passkeyService.hasCredentials())return y6("access_denied","No passkey registered");let Q=await this.passkeyService.generateAuthenticationOptions(uB0(A));return iY(Q)}async handleAuthenticationVerify(A){let Q=await this.passkeyService.verifyAuthenticationResponse(await A.json(),uB0(A));if(!Q.verified)return y6("access_denied","Passkey authentication failed");let B=await this.sessionStore.createSession(Q.subject??"single-operator",{secure:dl(A)});return iY({verified:!0},200,{"Set-Cookie":B.cookie})}}function uB0(A){let Q=Dh(A),B=new URL(Q);return{origin:B.origin,rpID:B.hostname}}import{randomUUID as pc2}from"crypto";var al=86400;class yP0{setupStateStore;passkeyService;setupTokenTtlSeconds;setupToken;constructor(A){this.setupStateStore=A.setupStateStore,this.passkeyService=A.passkeyService,this.setupTokenTtlSeconds=A.setupTokenTtlSeconds??al}async ensureSetupToken(){let A=this.getValidSetupToken();if(A)return A;let Q=await this.setupStateStore.getValidSetupToken(Math.floor(Date.now()/1000));if(Q)return this.setupToken=Q,Q;return this.createSetupToken()}async createSetupToken(){return this.setupToken={token:`setup_${pc2()}`,expiresAt:Math.floor(Date.now()/1000)+this.setupTokenTtlSeconds},await this.setupStateStore.saveSetupToken(this.setupToken),this.setupToken}getValidSetupToken(){if(!this.setupToken)return;if(this.setupToken.expiresAt<=Math.floor(Date.now()/1000)){this.setupToken=void 0;return}return this.setupToken}hasValidSetupToken(A){let Q=this.getValidSetupToken();if(!Q)return!1;let B=new URL(A.url);return(B.searchParams.get("setup_token")??B.searchParams.get("token"))===Q.token}async clearSetupState(){this.setupToken=void 0,await this.setupStateStore.clearSetupState()}getSetupUrl(A){let Q=this.getValidSetupToken();if(!Q)return;return eU(A,`/setup?token=${encodeURIComponent(Q.token)}`)}async getOperatorSetupRequired(A){if(await this.passkeyService.hasCredentials())return;let Q=this.getValidSetupToken();if(!Q)return;return{setupUrl:eU(A,`/setup?token=${encodeURIComponent(Q.token)}`),expiresAt:Q.expiresAt,setupTokenId:$P0(Q.token)}}async handleSetupPage(A){if(await this.passkeyService.hasCredentials())return new Response("Setup already completed",{status:404});if(!this.hasValidSetupToken(A))return new Response("Not Found",{status:404});let Q=new URL(A.url).searchParams.get("token")??"";return Kh(WxA(Q))}async hasSetupEmailDelivery(A,Q){return this.setupStateStore.hasDelivery(A,Q)}async recordSetupEmailDelivery(A,Q,B={}){await this.setupStateStore.recordDelivery(A,Q,B)}}class cB0{issuer;trustedIssuers;allowLocalhostIssuers;keyStore;clientStore;authCodeStore;sessionStore;passkeyService;setupFlow;oauthEndpoints;webauthnEndpoints;logger;constructor(A){this.issuer=EZ(A.issuer),this.trustedIssuers=new Set([this.issuer,...(A.trustedIssuers??[]).map((Q)=>EZ(Q))]),this.allowLocalhostIssuers=A.allowLocalhostIssuers??$h(this.issuer),this.keyStore=new wQ0({storageDir:A.storageDir}),this.clientStore=new BQ0({storageDir:A.storageDir}),this.authCodeStore=new QQ0({storageDir:A.storageDir}),this.sessionStore=new EB0({storageDir:A.storageDir}),this.passkeyService=new RB0({storageDir:A.storageDir,...A.logger?{logger:A.logger}:{}}),this.setupFlow=new yP0({setupStateStore:new DP0({storageDir:A.storageDir}),passkeyService:this.passkeyService,setupTokenTtlSeconds:A.setupTokenTtlSeconds??al}),this.oauthEndpoints=new hP0({clientStore:this.clientStore,authCodeStore:this.authCodeStore,refreshTokenStore:new hB0({storageDir:A.storageDir}),sessionStore:this.sessionStore,keyStore:this.keyStore}),this.webauthnEndpoints=new CP0({passkeyService:this.passkeyService,sessionStore:this.sessionStore,setupFlow:this.setupFlow}),this.logger=A.logger}getIssuer(){return this.issuer}async initialize(){if(await this.keyStore.getPrivateJwk(),this.logger?.debug("Auth service signing key loaded"),!await this.hasPasskeyCredentials()){await this.setupFlow.ensureSetupToken();let A=this.getSetupUrl();if(A)if($h(this.issuer))this.logger?.warn(`Passkey setup required: ${A}`);else this.logger?.warn("Passkey setup required. Ask through an anchor-visible interface for the setup URL.")}}async hasPasskeyCredentials(){return this.passkeyService.hasCredentials()}async getJwks(){return{keys:[await this.keyStore.getPublicJwk()]}}getAuthorizationServerMetadata(A=this.issuer){let Q=EZ(A);return{issuer:Q,authorization_endpoint:eU(Q,"/authorize"),token_endpoint:eU(Q,"/token"),registration_endpoint:eU(Q,"/register"),revocation_endpoint:eU(Q,"/revoke"),jwks_uri:eU(Q,"/.well-known/jwks.json"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none","client_secret_basic","client_secret_post"],scopes_supported:["openid","profile","email","offline_access","mcp"],subject_types_supported:["public"],id_token_signing_alg_values_supported:["ES256"]}}getProtectedResourceMetadata(A,Q=this.issuer){return{resource:A,authorization_servers:[EZ(Q)],bearer_methods_supported:["header"],resource_signing_alg_values_supported:["ES256"],scopes_supported:["mcp"]}}async registerClient(A){return this.clientStore.registerClient(A)}async getRegisteredClient(A){return this.clientStore.getClient(A)}async createOperatorSession(A="single-operator",Q={}){return this.sessionStore.createSession(A,Q)}async getOperatorSession(A){return this.sessionStore.getSessionFromRequest(A)}createOperatorLoginResponse(A){return sl(A)}async verifyBearerToken(A,Q={}){let B=jP0(A);if(!B)return;let w=Q.issuer?EZ(Q.issuer):this.resolveRequestIssuer(A);return NP0(B,await this.getJwks(),{issuer:w,...Q.audience?{audience:Q.audience}:{}})}getSetupUrl(A=this.issuer){return this.setupFlow.getSetupUrl(A)}async getOperatorSetupRequired(A=this.issuer){return this.setupFlow.getOperatorSetupRequired(A)}async hasSetupEmailDelivery(A,Q){return this.setupFlow.hasSetupEmailDelivery(A,Q)}async recordSetupEmailDelivery(A,Q,B={}){await this.setupFlow.recordSetupEmailDelivery(A,Q,B)}async handleRequest(A){let Q;try{Q=this.resolveRequestIssuer(A)}catch(w){return this.logger?.warn("Rejected OAuth request from untrusted issuer",{error:w instanceof Error?w.message:String(w)}),new Response("Untrusted OAuth issuer",{status:400})}let B=new URL(A.url).pathname;if(A.method==="OPTIONS"&&YxA(B))return XxA();if(A.method==="GET"){if(B==="/.well-known/oauth-authorization-server")return aV(iY(this.getAuthorizationServerMetadata(Q)));if(B==="/.well-known/jwks.json")return aV(iY(await this.getJwks()));if(B==="/.well-known/oauth-protected-resource")return aV(iY(this.getProtectedResourceMetadata(Q,Q)))}if(A.method==="GET"&&B==="/setup")return this.setupFlow.handleSetupPage(A);if(A.method==="GET"&&B==="/login")return this.handleLoginPage(A);if((A.method==="GET"||A.method==="POST")&&B==="/logout")return this.handleLogout(A);if(A.method==="POST"&&B==="/webauthn/register/options")return this.webauthnEndpoints.handleRegistrationOptions(A);if(A.method==="POST"&&B==="/webauthn/register/verify")return this.webauthnEndpoints.handleRegistrationVerify(A);if(A.method==="POST"&&B==="/webauthn/auth/options")return this.webauthnEndpoints.handleAuthenticationOptions(A);if(A.method==="POST"&&B==="/webauthn/auth/verify")return this.webauthnEndpoints.handleAuthenticationVerify(A);if(A.method==="GET"&&B==="/authorize")return this.oauthEndpoints.handleAuthorizePage(A);if(A.method==="POST"&&B==="/authorize")return this.oauthEndpoints.handleAuthorizeApproval(A);if(A.method==="POST"&&B==="/register")return aV(await this.oauthEndpoints.handleClientRegistration(A));if(A.method==="POST"&&B==="/token")return aV(await this.oauthEndpoints.handleTokenRequest(A,Q));if(A.method==="POST"&&B==="/revoke")return aV(await this.oauthEndpoints.handleRevokeRequest(A));return new Response("Not Found",{status:404})}async handleWellKnownRequest(A){return this.handleRequest(A)}resolveRequestIssuer(A){let Q=Dh(A,this.issuer);if(this.trustedIssuers.has(Q)||this.allowLocalhostIssuers&&$h(Q))return Q;throw Error(`Request issuer ${Q} is not in trusted issuers`)}handleLoginPage(A){let Q=OP0(new URL(A.url).searchParams.get("return_to"));return Kh(xP0(Q))}async handleLogout(A){await this.sessionStore.revokeSessionFromRequest(A);let Q=OP0(new URL(A.url).searchParams.get("return_to"));return new Response(null,{status:302,headers:{Location:Q,"Set-Cookie":XP0(dl(A)),"Cache-Control":"no-store"}})}}K0();var lB0="email:send",zxA=K.object({to:K.string().email(),subject:K.string().min(1),text:K.string().min(1),html:K.string().min(1).optional(),sensitivity:K.enum(["normal","secret"]).default("normal")}).strict();p0();K0();var qxA={name:"@brains/notifications",private:!0,version:"0.2.0-alpha.128",description:"Generic notification routing for transactional and administrative messages",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/email-contracts":"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 EP0="notifications:send",dc2=K.object({}),nc2=K.discriminatedUnion("type",[K.object({type:K.literal("email"),address:K.string().email()}).strict()]),rc2=K.object({recipient:nc2,title:K.string().min(1),body:K.string().min(1),html:K.string().min(1).optional(),sensitivity:K.enum(["normal","secret"]).default("normal")}).strict(),FxA=K.discriminatedUnion("status",[K.object({status:K.literal("sent"),deliveryId:K.string().optional()}).strict(),K.object({status:K.literal("failed")}).strict()]);class IxA extends pQ{constructor(A={}){super("notifications",qxA,A,dc2)}async onRegister(A){A.messaging.subscribe(EP0,async(Q)=>{let B=rc2.parse(Q.payload),w={to:B.recipient.address,subject:B.title,text:B.body,...B.html?{html:B.html}:{},sensitivity:B.sensitivity},$=await A.messaging.send({type:lB0,payload:w});if(!("success"in $)||!$.success||!$.data)return{success:!1,error:"Notification delivery failed"};let D=$.data;if(D.status!=="sent")return{success:!1,error:"Notification delivery failed"};return{success:!0,data:D.id?{status:"sent",deliveryId:D.id}:{status:"sent"}}})}}function pB0(A={}){return new IxA(A)}p0();K0();var VxA={name:"@brains/auth-service",private:!0,version:"0.2.0-alpha.128",description:"Embedded OAuth/OIDC auth service for brain operator authentication",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"},dependencies:{"@brains/notifications":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@simplewebauthn/server":"^13.3.0",jose:"^6.2.3"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"},files:["src"]};var sc2=K.union([K.string().email(),K.object({to:K.string().email(),subject:K.string().min(1),body:K.string().min(1)}).strict()]),ac2=K.object({issuer:K.string().optional(),trustedIssuers:K.array(K.string()).default([]),allowLocalhostIssuers:K.boolean().optional(),storageDir:K.string().default("./data/auth"),setupTokenTtlSeconds:K.number().int().positive().default(al),setupEmail:sc2.optional()}),tc2=K.object({}),iB0;function gH(){return iB0}class gP0 extends pQ{service;constructor(A={}){super("auth-service",VxA,A,ac2)}async onRegister(A){await super.onRegister(A);let Q=this.config.issuer??(A.preferLocalUrls?A.localSiteUrl??A.siteUrl:A.siteUrl??A.localSiteUrl);this.service=new cB0({storageDir:this.config.storageDir,...Q?{issuer:Q}:{},trustedIssuers:this.config.trustedIssuers,...this.config.allowLocalhostIssuers!==void 0?{allowLocalhostIssuers:this.config.allowLocalhostIssuers}:{},setupTokenTtlSeconds:this.config.setupTokenTtlSeconds,logger:A.logger}),await this.service.initialize(),iB0=this.service}async onReady(A){await this.requestSetupEmailIfNeeded(A)}async onShutdown(){if(iB0===this.service)iB0=void 0;this.service=void 0}async getTools(){return[BB(this.id,"get_passkey_setup_url","Get the first-passkey setup URL when operator setup is required. Anchor-only.",tc2,async()=>{let A=this.getService();if(await A.hasPasskeyCredentials())return b8({status:"complete"});let Q=await A.getOperatorSetupRequired();if(Q)return b8({status:"setup_required",setupUrl:Q.setupUrl,expiresAt:Q.expiresAt});return b8({status:"unavailable",reason:"Passkey setup URL is not available."})},{visibility:"anchor"})]}getWebRoutes(){let A=(Q)=>this.getService().handleRequest(Q);return[{path:"/.well-known/oauth-authorization-server",method:"GET",public:!0,handler:A},{path:"/.well-known/oauth-authorization-server",method:"OPTIONS",public:!0,handler:A},{path:"/.well-known/jwks.json",method:"GET",public:!0,handler:A},{path:"/.well-known/jwks.json",method:"OPTIONS",public:!0,handler:A},{path:"/.well-known/oauth-protected-resource",method:"GET",public:!0,handler:A},{path:"/.well-known/oauth-protected-resource",method:"OPTIONS",public:!0,handler:A},{path:"/setup",method:"GET",public:!0,handler:A},{path:"/login",method:"GET",public:!0,handler:A},{path:"/logout",method:"GET",public:!0,handler:A},{path:"/logout",method:"POST",public:!0,handler:A},{path:"/authorize",method:"GET",public:!0,handler:A},{path:"/authorize",method:"POST",public:!0,handler:A},{path:"/register",method:"POST",public:!0,handler:A},{path:"/register",method:"OPTIONS",public:!0,handler:A},{path:"/token",method:"POST",public:!0,handler:A},{path:"/token",method:"OPTIONS",public:!0,handler:A},{path:"/revoke",method:"POST",public:!0,handler:A},{path:"/revoke",method:"OPTIONS",public:!0,handler:A},{path:"/webauthn/register/options",method:"POST",public:!0,handler:A},{path:"/webauthn/register/verify",method:"POST",public:!0,handler:A},{path:"/webauthn/auth/options",method:"POST",public:!0,handler:A},{path:"/webauthn/auth/verify",method:"POST",public:!0,handler:A}]}getService(){if(!this.service)throw Error("AuthServicePlugin has not been registered");return this.service}async requestSetupEmailIfNeeded(A){if(!this.config.setupEmail)return;let Q=this.getService();if(await Q.hasPasskeyCredentials())return;let B=await Q.getOperatorSetupRequired();if(!B)return;let w=ec2(this.config.setupEmail,B);if(await Q.hasSetupEmailDelivery(B.setupTokenId,w.to))return;let $=await A.messaging.send({type:EP0,payload:{recipient:{type:"email",address:w.to},title:w.subject,body:w.body,sensitivity:"secret"}});if(!("success"in $)||!$.success||!$.data){A.logger.warn("Passkey setup email delivery was not confirmed");return}let D=FxA.safeParse($.data);if(!D.success||D.data.status!=="sent"){A.logger.warn("Passkey setup email delivery was not confirmed");return}await Q.recordSetupEmailDelivery(B.setupTokenId,w.to,D.data.deliveryId?{deliveryId:D.data.deliveryId}:{})}}function ec2(A,Q){if(typeof A==="string"){let B=new Date(Q.expiresAt*1000).toISOString(),w=new URL(Q.setupUrl).origin;return{to:A,subject:"Set up your brain passkey",body:["Set up your brain passkey using this single-use link:","",Q.setupUrl,"",`This link expires at ${B}.`,`Dashboard: ${w}/`,`MCP endpoint: ${w}/mcp`,"The first successful passkey registration completes setup and closes this link."].join(`
|
|
2422
|
-
`)}}return{to:A.to,subject:JxA(A.subject,Q),body:JxA(A.body,Q)}}function JxA(A,Q){let B=new Date(Q.expiresAt*1000).toISOString(),w=new URL(Q.setupUrl).origin;return A.replaceAll("{{setupUrl}}",Q.setupUrl).replaceAll("{{expiresAt}}",B).replaceAll("{{origin}}",w)}function tl(A){return new gP0(A)}K0();var TP0=K.object({transport:K.enum(["stdio","http"]).default("http"),httpPort:K.number().describe("Port for HTTP transport (only used when transport is 'http')").default(3333),authToken:K.string().describe("Bearer token for HTTP transport authentication").optional()});function LxA(A,Q){return[]}p0();function SP0(A,Q){A.messaging.subscribe("job-progress",async(B)=>{let w=OO.safeParse(B.payload);if(!w.success)return Q.warn("Received invalid job-progress message",{error:w.error.message}),{success:!1};let $=w.data,D=$.type,f=$.status,Y=$.id;if(Q.debug(`${D} ${Y} - ${f}:`,{id:$.id,message:$.message,progress:$.progress,metadata:$.metadata}),$.batchDetails)Q.debug(`Batch details for ${Y}:`,{totalOperations:$.batchDetails.totalOperations,completedOperations:$.batchDetails.completedOperations,failedOperations:$.batchDetails.failedOperations,currentOperation:$.batchDetails.currentOperation,errors:$.batchDetails.errors});if($.jobDetails)Q.debug(`Job details for ${Y}:`,{jobType:$.jobDetails.jobType,priority:$.jobDetails.priority,retryCount:$.jobDetails.retryCount});return{success:!0}}),Q.debug("Subscribed to job progress events")}var bxA={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.128",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/auth-service":"workspace:*","@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 tV extends GU{mcpTransport;stdioServer;httpServer;domain;constructor(A={}){let Q={...A,authToken:A.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",bxA,Q,TP0)}async getTools(){return LxA(this.id,()=>this.context)}async getResources(){return[]}async onRegister(A){if(this.domain=A.domain,this.config.transport==="http"&&!A.plugins.has("webserver"))throw Error("MCP HTTP transport requires the webserver interface. Standalone HTTP listeners have been removed.");if(this.logger.debug(`MCP interface initialized with ${this.config.transport} transport`),this.config.transport==="http")A.endpoints.register({label:"MCP",url:"/mcp",priority:30,visibility:"trusted"}),A.interactions.register({id:"mcp",label:"MCP",description:"Connect a trusted client through the Model Context Protocol.",href:"/mcp",kind:"protocol",priority:30,visibility:"trusted"});SP0(A,this.logger)}getOrCreateHttpServer(){if(this.httpServer)return this.httpServer;let A=gH();return this.httpServer=Eq.createFresh({port:this.config.httpPort,logger:this.logger,auth:this.config.authToken?{token:this.config.authToken}:A?{requiredScopes:["mcp"],verifyBearerToken:async(Q)=>A.verifyBearerToken(Q)}:{disabled:!0}}),this.httpServer}getWebRoutes(){if(this.config.transport!=="http")return[];let A=(Q)=>this.getOrCreateHttpServer().handleRequest(Q);return[{path:"/status",method:"GET",public:!0,handler:A},{path:"/mcp",method:"GET",public:!0,handler:A},{path:"/mcp",method:"POST",public:!0,handler:A},{path:"/mcp",method:"DELETE",public:!0,handler:A},{path:"/mcp",method:"OPTIONS",public:!0,handler:A}]}createDaemon(){return{start:async()=>{await this.startServer()},stop:async()=>{await this.stopServer()},healthCheck:async()=>{let A=this.isServerRunning(),Q="MCP server not running";if(A)if(this.config.transport==="http")Q=`MCP HTTP: ${this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/mcp"}`;else Q="MCP stdio server running";return{status:A?"healthy":"error",message:Q,lastCheck:new Date,details:{transport:this.config.transport,url:this.config.transport==="http"?this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/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");let A=this.context;this.mcpTransport=A.mcpTransport;let Q=this.config.transport==="stdio"?"stdio":"http",B=this.context.permissions.getUserLevel("mcp",Q);if(this.config.transport==="http"&&(this.config.authToken||gH()))B="anchor",this.logger.debug("HTTP authentication configured - authenticated users will have anchor permissions");if(this.mcpTransport.setPermissionLevel(B),this.logger.debug(`Starting MCP ${this.config.transport} transport with ${B} permissions`),this.config.transport==="stdio"){this.stdioServer=jZ.createFresh();let w=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(w),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=this.getOrCreateHttpServer();let w=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(w,this.mcpTransport),this.httpServer.connectAgentService(A.agent),this.logger.debug("MCP HTTP transport mounted on shared webserver host")}}async stopServer(){if(this.logger.debug(`Stopping MCP ${this.config.transport} transport`),this.stdioServer)this.stdioServer.stop(),this.stdioServer=void 0;if(this.httpServer)await this.httpServer.stop(),this.httpServer=void 0;this.mcpTransport=void 0}async handleProgressEvent(A,Q){}async onShutdown(){jZ.resetInstance(),Eq.resetInstance()}}p0();K0();var QX=f1(rC0(),1);K0();p0();var oC0=K.object({botToken:K.string().min(1).describe("Discord bot token"),allowedChannels:K.array(K.string()).default([]),requireMention:K.boolean().default(!0),allowDMs:K.boolean().default(!0),showTypingIndicator:K.boolean().default(!0),statusMessage:K.string().default("Mention me to chat"),useThreads:K.boolean().default(!0),threadAutoArchive:K.union([K.literal(60),K.literal(1440),K.literal(4320),K.literal(10080)]).default(1440),...bN.shape,captureUrlEmoji:K.string().default("\uD83D\uDD16")});var LH1={name:"@brains/discord",private:!0,version:"0.2.0-alpha.128",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 o60=2000,LLQ=8000,bLQ=100;function s60(A){return!!A&&typeof A==="object"&&"send"in A&&"sendTyping"in A}class EJ extends eW{client=null;fetchText;pendingConfirmations=new Map;typingIntervals=new Map;constructor(A,Q={}){super("discord",LH1,A,oC0);this.fetchText=Q.fetchText??zt}async onRegister(A){await super.onRegister(A),this.client=new QX.Client({intents:[QX.GatewayIntentBits.Guilds,QX.GatewayIntentBits.GuildMessages,QX.GatewayIntentBits.MessageContent,QX.GatewayIntentBits.DirectMessages],partials:[QX.Partials.Channel]}),this.client.on(QX.Events.MessageCreate,(Q)=>{this.handleMessage(Q)}),this.client.on(QX.Events.InteractionCreate,(Q)=>{this.handleInteraction(Q)}),this.client.once(QX.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({channelId:A,message:Q}){if(!A||!this.client)return;let B=this.client.channels.cache.get(A);if(!s60(B))return;let w=ob(Q,o60);for(let $ of w)B.send($).catch((D)=>this.logger.error("Failed to send message",{error:D}))}async sendMessageWithId({channelId:A,message:Q,approvalCard:B,approvalCards:w}){let $=w??(B?[B]:[]),D=$.length>0?this.buildApprovalMessagePayload(Q,$):Q;return this.sendPayloadWithId(A,D)}async sendPayloadWithId(A,Q){if(!A||!this.client)return;let B=this.client.channels.cache.get(A);if(!s60(B))return;if(typeof Q!=="string")return(await B.send(Q)).id;let w=ob(Q,o60),$;for(let D of w)$=(await B.send(D)).id;return $}async editMessage({channelId:A,messageId:Q,newMessage:B}){if(!A||!this.client)return!1;let w=this.client.channels.cache.get(A);if(!s60(w))return!1;try{return await(await w.messages.fetch(Q)).edit(B.slice(0,o60)),!0}catch{return!1}}supportsMessageEditing(){return!0}async handleMessage(A){if(A.author.id===this.client?.user?.id)return;if(!this.context)return;let Q=!A.guild,B=A.channel.isThread();if(Q&&!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&&"ownerId"in A.channel&&A.channel.ownerId===this.client?.user?.id,D=this.getSpaceChannelId(A),f=!Q&&this.isConfiguredSpace(D),Y={channelId:D,isBot:A.author.bot};if(this.config.allowedChannels.length>0&&!Q&&!this.isAllowedChannel(A.channel.id,D))return;let X=Q||$||!this.config.requireMention||w;if(f&&(!X||this.willRouteUseNonSpaceConversation(A)))await this.capturePassiveSpaceMessage(A,D).catch((Z)=>this.logger.error("Passive Discord space capture failed",{error:Z,channelId:D}));if(!X){if(this.config.captureUrls){let Z=this.extractCaptureableUrls(A.content,this.config.blockedUrlDomains);if(Z.length>0){await A.react(this.config.captureUrlEmoji).catch((G)=>this.logger.debug("React failed",{error:G}));for(let G of Z)await this.captureUrlViaAgent(G,A.channel.id,A.author.id,"discord",Y).catch((F)=>this.logger.error("URL capture failed",{error:F,url:G}))}}return}let H=this.stripMention(A.content);if(A.attachments.size>0){let Z=this.context.permissions.getUserLevel("discord",A.author.id,Y);if(Z==="anchor"||Z==="trusted")for(let F of A.attachments.values()){let I=F.name,L=F.contentType??void 0,b=F.size;if(!this.isUploadableTextFile(I,L))continue;if(!this.isFileSizeAllowed(b))continue;try{let N=await this.fetchText(F.url);H+=`
|
|
2421
|
+
</html>`}function sl(A){let Q=`${new URL(A.url).pathname}${new URL(A.url).search}`;return new Response(xP0(Q,"Operator login required"),{status:401,headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}})}function AG(A){return A.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""")}import{randomUUID as cc2}from"crypto";function UxA(A){return Buffer.from(JSON.stringify(A)).toString("base64url")}function uc2(A){let Q=new Uint8Array(A);if(Q.length===64)return Q;if(Q[0]!==48)return Q;let B=2;if(Q[1]&&Q[1]>128)B+=Q[1]-128;if(Q[B]!==2)throw Error("Invalid DER ECDSA signature");let w=Q[B+1];if(w===void 0)throw Error("Invalid DER ECDSA signature");let $=B+2,D=Q.slice($,$+w);if(B=$+w,Q[B]!==2)throw Error("Invalid DER ECDSA signature");let f=Q[B+1];if(f===void 0)throw Error("Invalid DER ECDSA signature");let Y=B+2,X=Q.slice(Y,Y+f);return new Uint8Array([...GxA(D),...GxA(X)])}function GxA(A){let Q=A;while(Q.length>32&&Q[0]===0)Q=Q.slice(1);if(Q.length>32)throw Error("Invalid P-256 signature component length");if(Q.length===32)return Q;let B=new Uint8Array(32);return B.set(Q,32-Q.length),B}async function vP0(A,Q){let B={typ:"JWT",alg:"ES256",kid:A.kid},w=`${UxA(B)}.${UxA(Q)}`,$=await crypto.subtle.importKey("jwk",A,{name:"ECDSA",namedCurve:"P-256"},!1,["sign"]),D=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},$,new TextEncoder().encode(w));return`${w}.${Buffer.from(uc2(D)).toString("base64url")}`}var lc2=600;class hP0{clientStore;authCodeStore;refreshTokenStore;sessionStore;keyStore;authorizationApprovalTokens=new Map;constructor(A){this.clientStore=A.clientStore,this.authCodeStore=A.authCodeStore,this.refreshTokenStore=A.refreshTokenStore,this.sessionStore=A.sessionStore,this.keyStore=A.keyStore}async handleAuthorizePage(A){let Q=await this.sessionStore.getSessionFromRequest(A);if(!Q)return sl(A);let B=await this.validateAuthorizationRequest(new URL(A.url).searchParams);if(!B.success)return new Response(B.error,{status:400});let w=this.createAuthorizationApprovalToken(Q,B.params);return Kh(KxA(B.params,w))}async handleAuthorizeApproval(A){let Q=await this.sessionStore.getSessionFromRequest(A);if(!Q)return sl(A);let B=await A.formData(),w=await this.validateAuthorizationRequest(new URLSearchParams(MP0(B)));if(!w.success)return new Response(w.error,{status:400});let $=B.get("approval_token"),D=typeof $==="string"?$:void 0;if(!D||!this.consumeAuthorizationApprovalToken(D,Q,w.params))return new Response("Invalid authorization approval token",{status:400});let f=await this.authCodeStore.createCode({clientId:w.params.clientId,redirectUri:w.params.redirectUri,codeChallenge:w.params.codeChallenge,...w.params.scope?{scope:w.params.scope}:{},subject:Q.subject}),Y=new URL(w.params.redirectUri);if(Y.searchParams.set("code",f.code),w.params.state)Y.searchParams.set("state",w.params.state);return Response.redirect(Y.toString(),302)}createAuthorizationApprovalToken(A,Q){this.pruneExpiredAuthorizationApprovalTokens();let B=`oat_${cc2()}`;return this.authorizationApprovalTokens.set(B,{token:B,sessionId:A.id,clientId:Q.clientId,redirectUri:Q.redirectUri,codeChallenge:Q.codeChallenge,...Q.scope?{scope:Q.scope}:{},...Q.state?{state:Q.state}:{},expiresAt:Math.floor(Date.now()/1000)+lc2}),B}consumeAuthorizationApprovalToken(A,Q,B){this.pruneExpiredAuthorizationApprovalTokens();let w=this.authorizationApprovalTokens.get(A);if(!w)return!1;return this.authorizationApprovalTokens.delete(A),w.sessionId===Q.id&&w.clientId===B.clientId&&w.redirectUri===B.redirectUri&&w.codeChallenge===B.codeChallenge&&w.scope===B.scope&&w.state===B.state}pruneExpiredAuthorizationApprovalTokens(){let A=Math.floor(Date.now()/1000);for(let[Q,B]of this.authorizationApprovalTokens.entries())if(B.expiresAt<=A)this.authorizationApprovalTokens.delete(Q)}async validateAuthorizationRequest(A){let Q=A.get("response_type"),B=A.get("client_id"),w=A.get("redirect_uri"),$=A.get("code_challenge"),D=A.get("code_challenge_method"),f=A.get("scope")??void 0,Y=A.get("state")??void 0;if(Q!=="code")return{success:!1,error:"Unsupported response_type"};if(!B)return{success:!1,error:"Missing client_id"};if(!w)return{success:!1,error:"Missing redirect_uri"};if(!$)return{success:!1,error:"Missing code_challenge"};if(D!=="S256")return{success:!1,error:"Unsupported code_challenge_method"};let X=await this.clientStore.getClient(B);if(!X)return{success:!1,error:"Unknown client_id"};if(!fj0(X.redirect_uris,w))return{success:!1,error:"Unregistered redirect_uri"};let H=f??X.scope;return{success:!0,params:{clientId:B,redirectUri:w,codeChallenge:$,...H?{scope:H}:{},...Y?{state:Y}:{},clientName:X.client_name??X.client_id}}}async handleClientRegistration(A){let Q;try{Q=await A.json()}catch{return y6("invalid_client_metadata","Request body must be JSON")}try{let B=await this.clientStore.registerClient(Q);return iY(B,201)}catch(B){if(B instanceof Xc)return y6("invalid_client_metadata",B.message);throw B}}async handleTokenRequest(A,Q){let B=await _P0(A),w=B.get("grant_type"),$=kP0(A,B),D=$.clientId??B.get("client_id");if($.error)return y6("invalid_client",$.error);if(!D)return y6("invalid_request","client_id is required");let f=await this.clientStore.getClient(D),Y=PP0(f,$);if(Y)return y6("invalid_client",Y);if(w==="authorization_code")return this.handleAuthorizationCodeGrant(B,D,Q);if(w==="refresh_token")return this.handleRefreshTokenGrant(B,D,Q);return y6("unsupported_grant_type","Only authorization_code and refresh_token are supported")}async handleAuthorizationCodeGrant(A,Q,B){let w=A.get("code"),$=A.get("redirect_uri"),D=A.get("code_verifier");if(!w||!$||!D)return y6("invalid_request","code, redirect_uri, and code_verifier are required");let f=await this.clientStore.getClient(Q);if(!f||!fj0(f.redirect_uris,$))return y6("invalid_grant","Unregistered redirect_uri");try{let Y=await this.authCodeStore.consumeCode({code:w,clientId:Q,redirectUri:$,codeVerifier:D});return await this.createTokenResponse({issuer:B,clientId:Q,subject:Y.subject,...Y.scope?{scope:Y.scope}:{}})}catch(Y){if(Y instanceof _Z)return y6("invalid_grant",Y.message);throw Y}}async handleRefreshTokenGrant(A,Q,B){let w=A.get("refresh_token");if(!w)return y6("invalid_request","refresh_token is required");try{let $=await this.refreshTokenStore.rotateToken(w,Q);return await this.createTokenResponse({issuer:B,clientId:Q,subject:$.consumed.subject,...$.consumed.scope?{scope:$.consumed.scope}:{},refreshToken:$.replacement.token})}catch($){if($ instanceof f3)return y6("invalid_grant",$.message);throw $}}async createTokenResponse(A){let Q=Math.floor(Date.now()/1000),B=900,w=await vP0(await this.keyStore.getPrivateJwk(),{iss:A.issuer,sub:A.subject,aud:A.clientId,iat:Q,exp:Q+900,...A.scope?{scope:A.scope}:{}}),$=A.refreshToken??(await this.refreshTokenStore.issueToken({clientId:A.clientId,subject:A.subject,...A.scope?{scope:A.scope}:{}})).token;return iY({access_token:w,token_type:"Bearer",expires_in:900,...A.scope?{scope:A.scope}:{},refresh_token:$})}async handleRevokeRequest(A){let Q=await _P0(A),B=kP0(A,Q),w=B.clientId??Q.get("client_id")??void 0,$=Q.get("token");if(B.error)return y6("invalid_client",B.error);if(!$)return y6("invalid_request","token is required");if(w){let D=await this.clientStore.getClient(w),f=PP0(D,B);if(f)return y6("invalid_client",f)}return await this.refreshTokenStore.revokeToken($,w),new Response(null,{status:200})}}class CP0{passkeyService;sessionStore;setupFlow;constructor(A){this.passkeyService=A.passkeyService,this.sessionStore=A.sessionStore,this.setupFlow=A.setupFlow}async handleRegistrationOptions(A){if(await this.passkeyService.hasCredentials())return y6("access_denied","Passkey setup already completed");if(!this.setupFlow.hasValidSetupToken(A))return y6("access_denied","Invalid setup token");let Q=await this.passkeyService.generateRegistrationOptions(uB0(A));return iY(Q)}async handleRegistrationVerify(A){if(await this.passkeyService.hasCredentials())return y6("access_denied","Passkey setup already completed");if(!this.setupFlow.hasValidSetupToken(A))return y6("access_denied","Invalid setup token");let Q=await this.passkeyService.verifyRegistrationResponse(await A.json(),uB0(A));if(!Q.verified)return y6("access_denied","Passkey registration failed");await this.setupFlow.clearSetupState();let B=await this.sessionStore.createSession(Q.subject??"single-operator",{secure:dl(A)});return iY({verified:!0},200,{"Set-Cookie":B.cookie})}async handleAuthenticationOptions(A){if(!await this.passkeyService.hasCredentials())return y6("access_denied","No passkey registered");let Q=await this.passkeyService.generateAuthenticationOptions(uB0(A));return iY(Q)}async handleAuthenticationVerify(A){let Q=await this.passkeyService.verifyAuthenticationResponse(await A.json(),uB0(A));if(!Q.verified)return y6("access_denied","Passkey authentication failed");let B=await this.sessionStore.createSession(Q.subject??"single-operator",{secure:dl(A)});return iY({verified:!0},200,{"Set-Cookie":B.cookie})}}function uB0(A){let Q=Dh(A),B=new URL(Q);return{origin:B.origin,rpID:B.hostname}}import{randomUUID as pc2}from"crypto";var al=86400;class yP0{setupStateStore;passkeyService;setupTokenTtlSeconds;setupToken;constructor(A){this.setupStateStore=A.setupStateStore,this.passkeyService=A.passkeyService,this.setupTokenTtlSeconds=A.setupTokenTtlSeconds??al}async ensureSetupToken(){let A=this.getValidSetupToken();if(A)return A;let Q=await this.setupStateStore.getValidSetupToken(Math.floor(Date.now()/1000));if(Q)return this.setupToken=Q,Q;return this.createSetupToken()}async createSetupToken(){return this.setupToken={token:`setup_${pc2()}`,expiresAt:Math.floor(Date.now()/1000)+this.setupTokenTtlSeconds},await this.setupStateStore.saveSetupToken(this.setupToken),this.setupToken}getValidSetupToken(){if(!this.setupToken)return;if(this.setupToken.expiresAt<=Math.floor(Date.now()/1000)){this.setupToken=void 0;return}return this.setupToken}hasValidSetupToken(A){let Q=this.getValidSetupToken();if(!Q)return!1;let B=new URL(A.url);return(B.searchParams.get("setup_token")??B.searchParams.get("token"))===Q.token}async clearSetupState(){this.setupToken=void 0,await this.setupStateStore.clearSetupState()}getSetupUrl(A){let Q=this.getValidSetupToken();if(!Q)return;return eU(A,`/setup?token=${encodeURIComponent(Q.token)}`)}async getOperatorSetupRequired(A){if(await this.passkeyService.hasCredentials())return;let Q=this.getValidSetupToken();if(!Q)return;return{setupUrl:eU(A,`/setup?token=${encodeURIComponent(Q.token)}`),expiresAt:Q.expiresAt,setupTokenId:$P0(Q.token)}}async handleSetupPage(A){if(await this.passkeyService.hasCredentials())return new Response("Setup already completed",{status:404});if(!this.hasValidSetupToken(A))return new Response("Not Found",{status:404});let Q=new URL(A.url).searchParams.get("token")??"";return Kh(WxA(Q))}async hasSetupEmailDelivery(A,Q){return this.setupStateStore.hasDelivery(A,Q)}async recordSetupEmailDelivery(A,Q,B={}){await this.setupStateStore.recordDelivery(A,Q,B)}}class cB0{issuer;trustedIssuers;allowLocalhostIssuers;keyStore;clientStore;authCodeStore;sessionStore;passkeyService;setupFlow;oauthEndpoints;webauthnEndpoints;logger;constructor(A){this.issuer=EZ(A.issuer),this.trustedIssuers=new Set([this.issuer,...(A.trustedIssuers??[]).map((Q)=>EZ(Q))]),this.allowLocalhostIssuers=A.allowLocalhostIssuers??$h(this.issuer),this.keyStore=new wQ0({storageDir:A.storageDir}),this.clientStore=new BQ0({storageDir:A.storageDir}),this.authCodeStore=new QQ0({storageDir:A.storageDir}),this.sessionStore=new EB0({storageDir:A.storageDir}),this.passkeyService=new RB0({storageDir:A.storageDir,...A.logger?{logger:A.logger}:{}}),this.setupFlow=new yP0({setupStateStore:new DP0({storageDir:A.storageDir}),passkeyService:this.passkeyService,setupTokenTtlSeconds:A.setupTokenTtlSeconds??al}),this.oauthEndpoints=new hP0({clientStore:this.clientStore,authCodeStore:this.authCodeStore,refreshTokenStore:new hB0({storageDir:A.storageDir}),sessionStore:this.sessionStore,keyStore:this.keyStore}),this.webauthnEndpoints=new CP0({passkeyService:this.passkeyService,sessionStore:this.sessionStore,setupFlow:this.setupFlow}),this.logger=A.logger}getIssuer(){return this.issuer}async initialize(){if(await this.keyStore.getPrivateJwk(),this.logger?.debug("Auth service signing key loaded"),!await this.hasPasskeyCredentials()){await this.setupFlow.ensureSetupToken();let A=this.getSetupUrl();if(A)if($h(this.issuer))this.logger?.warn(`Passkey setup required: ${A}`);else this.logger?.warn("Passkey setup required. Ask through an anchor-visible interface for the setup URL.")}}async hasPasskeyCredentials(){return this.passkeyService.hasCredentials()}async getJwks(){return{keys:[await this.keyStore.getPublicJwk()]}}getAuthorizationServerMetadata(A=this.issuer){let Q=EZ(A);return{issuer:Q,authorization_endpoint:eU(Q,"/authorize"),token_endpoint:eU(Q,"/token"),registration_endpoint:eU(Q,"/register"),revocation_endpoint:eU(Q,"/revoke"),jwks_uri:eU(Q,"/.well-known/jwks.json"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none","client_secret_basic","client_secret_post"],scopes_supported:["openid","profile","email","offline_access","mcp"],subject_types_supported:["public"],id_token_signing_alg_values_supported:["ES256"]}}getProtectedResourceMetadata(A,Q=this.issuer){return{resource:A,authorization_servers:[EZ(Q)],bearer_methods_supported:["header"],resource_signing_alg_values_supported:["ES256"],scopes_supported:["mcp"]}}async registerClient(A){return this.clientStore.registerClient(A)}async getRegisteredClient(A){return this.clientStore.getClient(A)}async createOperatorSession(A="single-operator",Q={}){return this.sessionStore.createSession(A,Q)}async getOperatorSession(A){return this.sessionStore.getSessionFromRequest(A)}createOperatorLoginResponse(A){return sl(A)}async verifyBearerToken(A,Q={}){let B=jP0(A);if(!B)return;let w=Q.issuer?EZ(Q.issuer):this.resolveRequestIssuer(A);return NP0(B,await this.getJwks(),{issuer:w,...Q.audience?{audience:Q.audience}:{}})}getSetupUrl(A=this.issuer){return this.setupFlow.getSetupUrl(A)}async getOperatorSetupRequired(A=this.issuer){return this.setupFlow.getOperatorSetupRequired(A)}async hasSetupEmailDelivery(A,Q){return this.setupFlow.hasSetupEmailDelivery(A,Q)}async recordSetupEmailDelivery(A,Q,B={}){await this.setupFlow.recordSetupEmailDelivery(A,Q,B)}async handleRequest(A){let Q;try{Q=this.resolveRequestIssuer(A)}catch(w){return this.logger?.warn("Rejected OAuth request from untrusted issuer",{error:w instanceof Error?w.message:String(w)}),new Response("Untrusted OAuth issuer",{status:400})}let B=new URL(A.url).pathname;if(A.method==="OPTIONS"&&YxA(B))return XxA();if(A.method==="GET"){if(B==="/.well-known/oauth-authorization-server")return aV(iY(this.getAuthorizationServerMetadata(Q)));if(B==="/.well-known/jwks.json")return aV(iY(await this.getJwks()));if(B==="/.well-known/oauth-protected-resource")return aV(iY(this.getProtectedResourceMetadata(Q,Q)))}if(A.method==="GET"&&B==="/setup")return this.setupFlow.handleSetupPage(A);if(A.method==="GET"&&B==="/login")return this.handleLoginPage(A);if((A.method==="GET"||A.method==="POST")&&B==="/logout")return this.handleLogout(A);if(A.method==="POST"&&B==="/webauthn/register/options")return this.webauthnEndpoints.handleRegistrationOptions(A);if(A.method==="POST"&&B==="/webauthn/register/verify")return this.webauthnEndpoints.handleRegistrationVerify(A);if(A.method==="POST"&&B==="/webauthn/auth/options")return this.webauthnEndpoints.handleAuthenticationOptions(A);if(A.method==="POST"&&B==="/webauthn/auth/verify")return this.webauthnEndpoints.handleAuthenticationVerify(A);if(A.method==="GET"&&B==="/authorize")return this.oauthEndpoints.handleAuthorizePage(A);if(A.method==="POST"&&B==="/authorize")return this.oauthEndpoints.handleAuthorizeApproval(A);if(A.method==="POST"&&B==="/register")return aV(await this.oauthEndpoints.handleClientRegistration(A));if(A.method==="POST"&&B==="/token")return aV(await this.oauthEndpoints.handleTokenRequest(A,Q));if(A.method==="POST"&&B==="/revoke")return aV(await this.oauthEndpoints.handleRevokeRequest(A));return new Response("Not Found",{status:404})}async handleWellKnownRequest(A){return this.handleRequest(A)}resolveRequestIssuer(A){let Q=Dh(A,this.issuer);if(this.trustedIssuers.has(Q)||this.allowLocalhostIssuers&&$h(Q))return Q;throw Error(`Request issuer ${Q} is not in trusted issuers`)}handleLoginPage(A){let Q=OP0(new URL(A.url).searchParams.get("return_to"));return Kh(xP0(Q))}async handleLogout(A){await this.sessionStore.revokeSessionFromRequest(A);let Q=OP0(new URL(A.url).searchParams.get("return_to"));return new Response(null,{status:302,headers:{Location:Q,"Set-Cookie":XP0(dl(A)),"Cache-Control":"no-store"}})}}K0();var lB0="email:send",zxA=K.object({to:K.string().email(),subject:K.string().min(1),text:K.string().min(1),html:K.string().min(1).optional(),sensitivity:K.enum(["normal","secret"]).default("normal")}).strict();p0();K0();var qxA={name:"@brains/notifications",private:!0,version:"0.2.0-alpha.129",description:"Generic notification routing for transactional and administrative messages",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/email-contracts":"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 EP0="notifications:send",dc2=K.object({}),nc2=K.discriminatedUnion("type",[K.object({type:K.literal("email"),address:K.string().email()}).strict()]),rc2=K.object({recipient:nc2,title:K.string().min(1),body:K.string().min(1),html:K.string().min(1).optional(),sensitivity:K.enum(["normal","secret"]).default("normal")}).strict(),FxA=K.discriminatedUnion("status",[K.object({status:K.literal("sent"),deliveryId:K.string().optional()}).strict(),K.object({status:K.literal("failed")}).strict()]);class IxA extends pQ{constructor(A={}){super("notifications",qxA,A,dc2)}async onRegister(A){A.messaging.subscribe(EP0,async(Q)=>{let B=rc2.parse(Q.payload),w={to:B.recipient.address,subject:B.title,text:B.body,...B.html?{html:B.html}:{},sensitivity:B.sensitivity},$=await A.messaging.send({type:lB0,payload:w});if(!("success"in $)||!$.success||!$.data)return{success:!1,error:"Notification delivery failed"};let D=$.data;if(D.status!=="sent")return{success:!1,error:"Notification delivery failed"};return{success:!0,data:D.id?{status:"sent",deliveryId:D.id}:{status:"sent"}}})}}function pB0(A={}){return new IxA(A)}p0();K0();var VxA={name:"@brains/auth-service",private:!0,version:"0.2.0-alpha.129",description:"Embedded OAuth/OIDC auth service for brain operator authentication",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"},dependencies:{"@brains/notifications":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@simplewebauthn/server":"^13.3.0",jose:"^6.2.3"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"},files:["src"]};var sc2=K.union([K.string().email(),K.object({to:K.string().email(),subject:K.string().min(1),body:K.string().min(1)}).strict()]),ac2=K.object({issuer:K.string().optional(),trustedIssuers:K.array(K.string()).default([]),allowLocalhostIssuers:K.boolean().optional(),storageDir:K.string().default("./data/auth"),setupTokenTtlSeconds:K.number().int().positive().default(al),setupEmail:sc2.optional()}),tc2=K.object({}),iB0;function gH(){return iB0}class gP0 extends pQ{service;constructor(A={}){super("auth-service",VxA,A,ac2)}async onRegister(A){await super.onRegister(A);let Q=this.config.issuer??(A.preferLocalUrls?A.localSiteUrl??A.siteUrl:A.siteUrl??A.localSiteUrl);this.service=new cB0({storageDir:this.config.storageDir,...Q?{issuer:Q}:{},trustedIssuers:this.config.trustedIssuers,...this.config.allowLocalhostIssuers!==void 0?{allowLocalhostIssuers:this.config.allowLocalhostIssuers}:{},setupTokenTtlSeconds:this.config.setupTokenTtlSeconds,logger:A.logger}),await this.service.initialize(),iB0=this.service}async onReady(A){await this.requestSetupEmailIfNeeded(A)}async onShutdown(){if(iB0===this.service)iB0=void 0;this.service=void 0}async getTools(){return[BB(this.id,"get_passkey_setup_url","Get the first-passkey setup URL when operator setup is required. Anchor-only.",tc2,async()=>{let A=this.getService();if(await A.hasPasskeyCredentials())return b8({status:"complete"});let Q=await A.getOperatorSetupRequired();if(Q)return b8({status:"setup_required",setupUrl:Q.setupUrl,expiresAt:Q.expiresAt});return b8({status:"unavailable",reason:"Passkey setup URL is not available."})},{visibility:"anchor"})]}getWebRoutes(){let A=(Q)=>this.getService().handleRequest(Q);return[{path:"/.well-known/oauth-authorization-server",method:"GET",public:!0,handler:A},{path:"/.well-known/oauth-authorization-server",method:"OPTIONS",public:!0,handler:A},{path:"/.well-known/jwks.json",method:"GET",public:!0,handler:A},{path:"/.well-known/jwks.json",method:"OPTIONS",public:!0,handler:A},{path:"/.well-known/oauth-protected-resource",method:"GET",public:!0,handler:A},{path:"/.well-known/oauth-protected-resource",method:"OPTIONS",public:!0,handler:A},{path:"/setup",method:"GET",public:!0,handler:A},{path:"/login",method:"GET",public:!0,handler:A},{path:"/logout",method:"GET",public:!0,handler:A},{path:"/logout",method:"POST",public:!0,handler:A},{path:"/authorize",method:"GET",public:!0,handler:A},{path:"/authorize",method:"POST",public:!0,handler:A},{path:"/register",method:"POST",public:!0,handler:A},{path:"/register",method:"OPTIONS",public:!0,handler:A},{path:"/token",method:"POST",public:!0,handler:A},{path:"/token",method:"OPTIONS",public:!0,handler:A},{path:"/revoke",method:"POST",public:!0,handler:A},{path:"/revoke",method:"OPTIONS",public:!0,handler:A},{path:"/webauthn/register/options",method:"POST",public:!0,handler:A},{path:"/webauthn/register/verify",method:"POST",public:!0,handler:A},{path:"/webauthn/auth/options",method:"POST",public:!0,handler:A},{path:"/webauthn/auth/verify",method:"POST",public:!0,handler:A}]}getService(){if(!this.service)throw Error("AuthServicePlugin has not been registered");return this.service}async requestSetupEmailIfNeeded(A){if(!this.config.setupEmail)return;let Q=this.getService();if(await Q.hasPasskeyCredentials())return;let B=await Q.getOperatorSetupRequired();if(!B)return;let w=ec2(this.config.setupEmail,B);if(await Q.hasSetupEmailDelivery(B.setupTokenId,w.to))return;let $=await A.messaging.send({type:EP0,payload:{recipient:{type:"email",address:w.to},title:w.subject,body:w.body,sensitivity:"secret"}});if(!("success"in $)||!$.success||!$.data){A.logger.warn("Passkey setup email delivery was not confirmed");return}let D=FxA.safeParse($.data);if(!D.success||D.data.status!=="sent"){A.logger.warn("Passkey setup email delivery was not confirmed");return}await Q.recordSetupEmailDelivery(B.setupTokenId,w.to,D.data.deliveryId?{deliveryId:D.data.deliveryId}:{})}}function ec2(A,Q){if(typeof A==="string"){let B=new Date(Q.expiresAt*1000).toISOString(),w=new URL(Q.setupUrl).origin;return{to:A,subject:"Set up your brain passkey",body:["Set up your brain passkey using this single-use link:","",Q.setupUrl,"",`This link expires at ${B}.`,`Dashboard: ${w}/`,`MCP endpoint: ${w}/mcp`,"The first successful passkey registration completes setup and closes this link."].join(`
|
|
2422
|
+
`)}}return{to:A.to,subject:JxA(A.subject,Q),body:JxA(A.body,Q)}}function JxA(A,Q){let B=new Date(Q.expiresAt*1000).toISOString(),w=new URL(Q.setupUrl).origin;return A.replaceAll("{{setupUrl}}",Q.setupUrl).replaceAll("{{expiresAt}}",B).replaceAll("{{origin}}",w)}function tl(A){return new gP0(A)}K0();var TP0=K.object({transport:K.enum(["stdio","http"]).default("http"),httpPort:K.number().describe("Port for HTTP transport (only used when transport is 'http')").default(3333),authToken:K.string().describe("Bearer token for HTTP transport authentication").optional()});function LxA(A,Q){return[]}p0();function SP0(A,Q){A.messaging.subscribe("job-progress",async(B)=>{let w=OO.safeParse(B.payload);if(!w.success)return Q.warn("Received invalid job-progress message",{error:w.error.message}),{success:!1};let $=w.data,D=$.type,f=$.status,Y=$.id;if(Q.debug(`${D} ${Y} - ${f}:`,{id:$.id,message:$.message,progress:$.progress,metadata:$.metadata}),$.batchDetails)Q.debug(`Batch details for ${Y}:`,{totalOperations:$.batchDetails.totalOperations,completedOperations:$.batchDetails.completedOperations,failedOperations:$.batchDetails.failedOperations,currentOperation:$.batchDetails.currentOperation,errors:$.batchDetails.errors});if($.jobDetails)Q.debug(`Job details for ${Y}:`,{jobType:$.jobDetails.jobType,priority:$.jobDetails.priority,retryCount:$.jobDetails.retryCount});return{success:!0}}),Q.debug("Subscribed to job progress events")}var bxA={name:"@brains/mcp",private:!0,version:"0.2.0-alpha.129",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/auth-service":"workspace:*","@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 tV extends GU{mcpTransport;stdioServer;httpServer;domain;constructor(A={}){let Q={...A,authToken:A.authToken??process.env.MCP_AUTH_TOKEN};super("mcp",bxA,Q,TP0)}async getTools(){return LxA(this.id,()=>this.context)}async getResources(){return[]}async onRegister(A){if(this.domain=A.domain,this.config.transport==="http"&&!A.plugins.has("webserver"))throw Error("MCP HTTP transport requires the webserver interface. Standalone HTTP listeners have been removed.");if(this.logger.debug(`MCP interface initialized with ${this.config.transport} transport`),this.config.transport==="http")A.endpoints.register({label:"MCP",url:"/mcp",priority:30,visibility:"trusted"}),A.interactions.register({id:"mcp",label:"MCP",description:"Connect a trusted client through the Model Context Protocol.",href:"/mcp",kind:"protocol",priority:30,visibility:"trusted"});SP0(A,this.logger)}getOrCreateHttpServer(){if(this.httpServer)return this.httpServer;let A=gH();return this.httpServer=Eq.createFresh({port:this.config.httpPort,logger:this.logger,auth:this.config.authToken?{token:this.config.authToken}:A?{requiredScopes:["mcp"],verifyBearerToken:async(Q)=>A.verifyBearerToken(Q)}:{disabled:!0}}),this.httpServer}getWebRoutes(){if(this.config.transport!=="http")return[];let A=(Q)=>this.getOrCreateHttpServer().handleRequest(Q);return[{path:"/status",method:"GET",public:!0,handler:A},{path:"/mcp",method:"GET",public:!0,handler:A},{path:"/mcp",method:"POST",public:!0,handler:A},{path:"/mcp",method:"DELETE",public:!0,handler:A},{path:"/mcp",method:"OPTIONS",public:!0,handler:A}]}createDaemon(){return{start:async()=>{await this.startServer()},stop:async()=>{await this.stopServer()},healthCheck:async()=>{let A=this.isServerRunning(),Q="MCP server not running";if(A)if(this.config.transport==="http")Q=`MCP HTTP: ${this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/mcp"}`;else Q="MCP stdio server running";return{status:A?"healthy":"error",message:Q,lastCheck:new Date,details:{transport:this.config.transport,url:this.config.transport==="http"?this.domain?`https://${this.domain}/mcp`:"http://localhost:8080/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");let A=this.context;this.mcpTransport=A.mcpTransport;let Q=this.config.transport==="stdio"?"stdio":"http",B=this.context.permissions.getUserLevel("mcp",Q);if(this.config.transport==="http"&&(this.config.authToken||gH()))B="anchor",this.logger.debug("HTTP authentication configured - authenticated users will have anchor permissions");if(this.mcpTransport.setPermissionLevel(B),this.logger.debug(`Starting MCP ${this.config.transport} transport with ${B} permissions`),this.config.transport==="stdio"){this.stdioServer=jZ.createFresh();let w=this.mcpTransport.getMcpServer();this.stdioServer.connectMCPServer(w),await this.stdioServer.start(),this.logger.debug("MCP STDIO transport started")}else{this.httpServer=this.getOrCreateHttpServer();let w=this.mcpTransport.getMcpServer();this.httpServer.connectMCPServer(w,this.mcpTransport),this.httpServer.connectAgentService(A.agent),this.logger.debug("MCP HTTP transport mounted on shared webserver host")}}async stopServer(){if(this.logger.debug(`Stopping MCP ${this.config.transport} transport`),this.stdioServer)this.stdioServer.stop(),this.stdioServer=void 0;if(this.httpServer)await this.httpServer.stop(),this.httpServer=void 0;this.mcpTransport=void 0}async handleProgressEvent(A,Q){}async onShutdown(){jZ.resetInstance(),Eq.resetInstance()}}p0();K0();var QX=f1(rC0(),1);K0();p0();var oC0=K.object({botToken:K.string().min(1).describe("Discord bot token"),allowedChannels:K.array(K.string()).default([]),requireMention:K.boolean().default(!0),allowDMs:K.boolean().default(!0),showTypingIndicator:K.boolean().default(!0),statusMessage:K.string().default("Mention me to chat"),useThreads:K.boolean().default(!0),threadAutoArchive:K.union([K.literal(60),K.literal(1440),K.literal(4320),K.literal(10080)]).default(1440),...bN.shape,captureUrlEmoji:K.string().default("\uD83D\uDD16")});var LH1={name:"@brains/discord",private:!0,version:"0.2.0-alpha.129",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 o60=2000,LLQ=8000,bLQ=100;function s60(A){return!!A&&typeof A==="object"&&"send"in A&&"sendTyping"in A}class EJ extends eW{client=null;fetchText;pendingConfirmations=new Map;typingIntervals=new Map;constructor(A,Q={}){super("discord",LH1,A,oC0);this.fetchText=Q.fetchText??zt}async onRegister(A){await super.onRegister(A),this.client=new QX.Client({intents:[QX.GatewayIntentBits.Guilds,QX.GatewayIntentBits.GuildMessages,QX.GatewayIntentBits.MessageContent,QX.GatewayIntentBits.DirectMessages],partials:[QX.Partials.Channel]}),this.client.on(QX.Events.MessageCreate,(Q)=>{this.handleMessage(Q)}),this.client.on(QX.Events.InteractionCreate,(Q)=>{this.handleInteraction(Q)}),this.client.once(QX.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({channelId:A,message:Q}){if(!A||!this.client)return;let B=this.client.channels.cache.get(A);if(!s60(B))return;let w=ob(Q,o60);for(let $ of w)B.send($).catch((D)=>this.logger.error("Failed to send message",{error:D}))}async sendMessageWithId({channelId:A,message:Q,approvalCard:B,approvalCards:w}){let $=w??(B?[B]:[]),D=$.length>0?this.buildApprovalMessagePayload(Q,$):Q;return this.sendPayloadWithId(A,D)}async sendPayloadWithId(A,Q){if(!A||!this.client)return;let B=this.client.channels.cache.get(A);if(!s60(B))return;if(typeof Q!=="string")return(await B.send(Q)).id;let w=ob(Q,o60),$;for(let D of w)$=(await B.send(D)).id;return $}async editMessage({channelId:A,messageId:Q,newMessage:B}){if(!A||!this.client)return!1;let w=this.client.channels.cache.get(A);if(!s60(w))return!1;try{return await(await w.messages.fetch(Q)).edit(B.slice(0,o60)),!0}catch{return!1}}supportsMessageEditing(){return!0}async handleMessage(A){if(A.author.id===this.client?.user?.id)return;if(!this.context)return;let Q=!A.guild,B=A.channel.isThread();if(Q&&!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&&"ownerId"in A.channel&&A.channel.ownerId===this.client?.user?.id,D=this.getSpaceChannelId(A),f=!Q&&this.isConfiguredSpace(D),Y={channelId:D,isBot:A.author.bot};if(this.config.allowedChannels.length>0&&!Q&&!this.isAllowedChannel(A.channel.id,D))return;let X=Q||$||!this.config.requireMention||w;if(f&&(!X||this.willRouteUseNonSpaceConversation(A)))await this.capturePassiveSpaceMessage(A,D).catch((Z)=>this.logger.error("Passive Discord space capture failed",{error:Z,channelId:D}));if(!X){if(this.config.captureUrls){let Z=this.extractCaptureableUrls(A.content,this.config.blockedUrlDomains);if(Z.length>0){await A.react(this.config.captureUrlEmoji).catch((G)=>this.logger.debug("React failed",{error:G}));for(let G of Z)await this.captureUrlViaAgent(G,A.channel.id,A.author.id,"discord",Y).catch((F)=>this.logger.error("URL capture failed",{error:F,url:G}))}}return}let H=this.stripMention(A.content);if(A.attachments.size>0){let Z=this.context.permissions.getUserLevel("discord",A.author.id,Y);if(Z==="anchor"||Z==="trusted")for(let F of A.attachments.values()){let I=F.name,L=F.contentType??void 0,b=F.size;if(!this.isUploadableTextFile(I,L))continue;if(!this.isFileSizeAllowed(b))continue;try{let N=await this.fetchText(F.url);H+=`
|
|
2423
2423
|
|
|
2424
2424
|
`+this.formatFileUploadMessage(I,N)}catch(N){this.logger.error("Failed to download attachment",{error:N,filename:I})}}}if(H=H.trim(),!H)return;let W=A.channel.id;await this.routeToAgent(H,W,A,Y)}async handleInteraction(A){if(!this.context||!A.isButton())return;let Q=this.parseApprovalButtonCustomId(A.customId);if(!Q)return;let B=`discord-${A.channelId}`;if(!this.pendingConfirmations.get(B)?.has(Q.approvalId)){await A.reply({content:"This approval is no longer pending or has changed.",ephemeral:!0}).catch((D)=>this.logger.debug("Failed to reply to stale approval button",{error:D}));return}await A.deferUpdate().catch((D)=>this.logger.debug("Failed to defer approval button",{error:D}));let $=await this.context.agent.confirmPendingAction(B,Q.confirmed,Q.approvalId,this.buildInteractionConfirmationContext(A));await this.handleAgentResponseToolStatuses($,B),this.syncPendingApprovalsAfterResolution(B,Q.approvalId,$),await this.sendApprovalResultMessage({channelId:A.channelId,response:$})}buildInteractionConfirmationContext(A){if(!this.context)throw Error("Discord context is not registered");return{userPermissionLevel:this.context.permissions.getUserLevel("discord",A.user.id,{channelId:A.channelId}),interfaceType:"discord",channelId:A.channelId,actor:{actorId:`discord:${A.user.id}`,interfaceType:"discord",role:"user",displayName:A.user.displayName,username:A.user.username,isBot:Boolean(A.user.bot)}}}async capturePassiveSpaceMessage(A,Q){if(!this.context)return;let B=this.stripMention(A.content).trim();if(!B)return;let w=`discord-${Q}`,$=this.getChannelName(A);await this.context.conversations.start({sessionId:w,interfaceType:"discord",channelId:Q,metadata:{channelName:$,interfaceType:"discord",channelId:Q}}),await this.context.conversations.addMessage({conversationId:w,role:"user",content:B,metadata:this.buildUserMessageMetadata(A,Q,$,{threadId:A.channel.isThread()?A.channel.id:void 0})})}async routeToAgent(A,Q,B,w){if(!this.context)return;let $=this.context.agent,D=Q;if(this.config.useThreads&&B.guild&&!B.channel.isThread())try{D=(await B.startThread({name:r7(A,bLQ),autoArchiveDuration:this.config.threadAutoArchive})).id}catch(H){this.logger.error("Failed to create thread",{error:H})}let f=`discord-${D}`,Y=this.context.permissions.getUserLevel("discord",B.author.id,w),X=this.getChannelName(B);this.startProcessingInput(D);try{let H=this.client?.channels.cache.get(D);if(s60(H))this.startTypingIndicator(H);if(this.pendingConfirmations.has(f)){await this.handleConfirmationResponse(A,f,D,B,w);return}let W=await $.chat(A,f,{userPermissionLevel:Y,interfaceType:"discord",channelId:D,channelName:X,...this.buildUserMessageMetadata(B,Q,X,{threadId:D!==Q||B.channel.isThread()?D:void 0})});await this.handleAgentResponseToolStatuses(W,f);let Z=this.getPendingApprovalCards(W.cards);if(Z.length>0)this.pendingConfirmations.set(f,new Set(Z.map((F)=>F.id)));else if(W.pendingConfirmations)this.pendingConfirmations.set(f,new Set(W.pendingConfirmations.map((F)=>F.id)));let G=await this.sendMessageWithId({channelId:D,message:this.formatAgentResponseText(W.text,Z),approvalCards:Z});if(G&&W.toolResults){for(let F of W.toolResults)if(F.jobId)this.trackAgentResponseForJob(F.jobId,G,D)}}catch(H){this.logger.error("Error handling message",{error:H,channelId:D}),this.sendMessageToChannel({channelId:D,message:`**Error:** ${H instanceof Error?H.message:"Unknown error"}`})}finally{this.endProcessingInput(),this.stopTypingIndicator(D)}}buildApprovalMessagePayload(A,Q){let B=Q.length>1;return{content:r7(A.trim().length>0?`${A}
|
|
2425
2425
|
|
|
@@ -2486,7 +2486,7 @@ ${A.value}
|
|
|
2486
2486
|
`);if(t60(A))return this.renderList(A,0,(Q)=>this.nodeToDiscordMarkdown(Q));if(A.type==="break")return`
|
|
2487
2487
|
`;if(A.type==="thematicBreak")return"---";if(ry0(A))return`\`\`\`
|
|
2488
2488
|
${oy0(A)}
|
|
2489
|
-
\`\`\``;return this.defaultNodeToText(A,(Q)=>this.nodeToDiscordMarkdown(Q))}},xV1={DeferredChannelMessageWithSource:5,DeferredUpdateMessage:6},X50="https://discord.com/api/v10",RV1=2000,ikQ=/^[0-9a-f]{64}$/,dkQ=/^[0-9a-f]+$/,nkQ=class A{name="discord";userName;botUserId;apiBaseUrl;botToken;publicKey;applicationId;mentionRoleIds;chat=null;logger;formatConverter=new pkQ;requestContext=new CkQ;threadParentCache=new Map;static THREAD_PARENT_CACHE_TTL=300000;constructor(Q={}){let B=Q.botToken??process.env.DISCORD_BOT_TOKEN;if(!B)throw new rH("discord","botToken is required. Set DISCORD_BOT_TOKEN or provide it in config.");let w=Q.publicKey??process.env.DISCORD_PUBLIC_KEY;if(!w)throw new rH("discord","publicKey is required. Set DISCORD_PUBLIC_KEY or provide it in config.");let $=Q.applicationId??process.env.DISCORD_APPLICATION_ID;if(!$)throw new rH("discord","applicationId is required. Set DISCORD_APPLICATION_ID or provide it in config.");if(this.apiBaseUrl=Q.apiUrl??process.env.DISCORD_API_URL??X50,this.botToken=B,this.publicKey=w.trim().toLowerCase(),this.applicationId=$,this.mentionRoleIds=Q.mentionRoleIds??(process.env.DISCORD_MENTION_ROLE_IDS?process.env.DISCORD_MENTION_ROLE_IDS.split(",").map((D)=>D.trim()):[]),this.botUserId=$,this.logger=Q.logger??new D50("info").child("discord"),this.userName=Q.userName??"bot",!ikQ.test(this.publicKey))this.logger.error("Invalid Discord public key format",{length:this.publicKey.length,isHex:dkQ.test(this.publicKey)})}async initialize(Q){this.chat=Q,this.logger.info("Discord adapter initialized")}async getUser(Q){try{let w=await(await this.discordFetch(`/users/${Q}`,"GET")).json();return{avatarUrl:w.avatar?`https://cdn.discordapp.com/avatars/${w.id}/${w.avatar}.png`:void 0,email:void 0,fullName:w.global_name||w.username,isBot:w.bot??!1,userId:w.id,userName:w.username}}catch{return null}}async handleWebhook(Q,B){let w=await Q.arrayBuffer(),$=new Uint8Array(w),D=new TextDecoder().decode($),f=Q.headers.get("x-discord-gateway-token");if(f){if(f!==this.botToken)return this.logger.warn("Invalid gateway token"),new Response("Invalid gateway token",{status:401});this.logger.info("Discord forwarded Gateway event received");try{let Z=JSON.parse(D);return this.handleForwardedGatewayEvent(Z,B)}catch{return new Response("Invalid JSON",{status:400})}}this.logger.info("Discord webhook received",{bodyLength:D.length,bodyBytesLength:$.length,hasSignature:!!Q.headers.get("x-signature-ed25519"),hasTimestamp:!!Q.headers.get("x-signature-timestamp")});let Y=Q.headers.get("x-signature-ed25519"),X=Q.headers.get("x-signature-timestamp");if(!await this.verifySignature($,Y,X))return this.logger.warn("Discord signature verification failed, returning 401"),new Response("Invalid signature",{status:401});this.logger.info("Discord signature verification passed");let W;try{W=JSON.parse(D)}catch{return new Response("Invalid JSON",{status:400})}if(this.logger.info("Discord interaction parsed",{type:W.type,typeIsPing:W.type===MC.Ping,expectedPingType:MC.Ping,id:W.id}),W.type===MC.Ping){let Z=JSON.stringify({type:di.InteractionResponseType.PONG});return this.logger.info("Discord PING received, responding with PONG",{responseBody:Z,responseType:di.InteractionResponseType.PONG}),new Response(Z,{status:200,headers:{"Content-Type":"application/json"}})}if(W.type===MC.MessageComponent)return this.handleComponentInteraction(W,B),this.respondToInteraction({type:xV1.DeferredUpdateMessage});if(W.type===MC.ApplicationCommand)return this.handleApplicationCommandInteraction(W,B),this.respondToInteraction({type:xV1.DeferredChannelMessageWithSource});return new Response("Unknown interaction type",{status:400})}async verifySignature(Q,B,w){if(!(B&&w))return this.logger.warn("Discord signature verification failed: missing headers",{hasSignature:!!B,hasTimestamp:!!w}),!1;try{this.logger.info("Discord signature verification attempt",{bodyBytesLength:Q.length,signatureLength:B.length,timestampLength:w.length,publicKeyLength:this.publicKey.length,timestamp:w,signaturePrefix:B.slice(0,16),publicKey:this.publicKey});let $=await di.verifyKey(Q,B,w,this.publicKey);if(!$){let D=new TextDecoder().decode(Q);this.logger.warn("Discord signature verification failed: invalid signature",{publicKeyLength:this.publicKey.length,signatureLength:B.length,publicKeyPrefix:this.publicKey.slice(0,8),publicKeySuffix:this.publicKey.slice(-8),timestamp:w,bodyLength:Q.length,bodyPrefix:D.slice(0,50)})}return $}catch($){return this.logger.warn("Discord signature verification failed: exception",{error:$}),!1}}respondToInteraction(Q){return Response.json(Q)}handleComponentInteraction(Q,B){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring interaction");return}let w=Q.data?.custom_id;if(!w){this.logger.warn("No custom_id in component interaction");return}let $=Q.member?.user||Q.user;if(!$){this.logger.warn("No user in component interaction");return}let D=Q.channel_id,f=Q.guild_id||"@me",Y=Q.message?.id;if(!(D&&Y)){this.logger.warn("Missing channel_id or message_id in interaction");return}let X=Q.channel,H=X?.type===11||X?.type===12,W=H&&X?.parent_id?X.parent_id:D,Z=H?this.encodeThreadId({guildId:f,channelId:W,threadId:D}):this.encodeThreadId({guildId:f,channelId:D}),G=EkQ(w),F={actionId:G.actionId,value:G.value??G.actionId,user:{userId:$.id,userName:$.username,fullName:$.global_name||$.username,isBot:$.bot??!1,isMe:!1},messageId:Y,threadId:Z,adapter:this,raw:Q};this.logger.debug("Processing Discord button action",{actionId:w,messageId:Y,threadId:Z}),this.chat.processAction(F,B)}handleApplicationCommandInteraction(Q,B){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring interaction");return}let w=Q.data?.name;if(!w){this.logger.warn("No command name in application command interaction");return}let $=Q.member?.user||Q.user;if(!$){this.logger.warn("No user in application command interaction");return}let D=Q.channel_id;if(!D){this.logger.warn("Missing channel_id in application command interaction");return}let f=Q.guild_id||"@me",Y=Q.channel,X=Y?.type===11||Y?.type===12,H=X&&Y?.parent_id?Y.parent_id:D,W=X?this.encodeThreadId({guildId:f,channelId:H,threadId:D}):this.encodeThreadId({guildId:f,channelId:D}),{command:Z,text:G}=this.parseSlashCommand(w,Q.data?.options);this.logger.debug("Processing Discord slash command",{command:Z,text:G,userId:$.id,channelId:W}),this.requestContext.run({slashCommand:{channelId:W,interactionToken:Q.token,initialResponseSent:!1}},()=>{this.chat?.processSlashCommand({command:Z,text:G,user:{userId:$.id,userName:$.username,fullName:$.global_name||$.username,isBot:$.bot??!1,isMe:$.id===this.applicationId},adapter:this,raw:Q,channelId:W},B)})}parseSlashCommand(Q,B){let w=[Q.startsWith("/")?Q:`/${Q}`],$=[],D=(f)=>{for(let Y of f){if(Y.value!==void 0){$.push(String(Y.value));continue}if(Y.options&&Y.options.length>0)w.push(Y.name),D(Y.options)}};if(B&&B.length>0)D(B);return{command:w.join(" "),text:$.join(" ").trim()}}async handleGatewayInteraction(Q){if(Q.isChatInputCommand()){await Q.deferReply(),this.handleApplicationCommandInteraction(this.normalizeGatewaySlashCommandInteraction(Q));return}if(Q.isMessageComponent())await Q.deferUpdate(),this.handleComponentInteraction(this.normalizeGatewayComponentInteraction(Q))}normalizeGatewaySlashCommandInteraction(Q){return{application_id:Q.applicationId,channel:this.normalizeGatewayChannel(Q),channel_id:Q.channelId??void 0,data:{name:Q.commandName,options:this.normalizeGatewayCommandOptions(Q.options.data),type:Q.commandType},guild_id:Q.guildId??void 0,id:Q.id,token:Q.token,type:Q.type,user:this.normalizeGatewayUser(Q.user),version:Q.version}}normalizeGatewayComponentInteraction(Q){let B="values"in Q&&Array.isArray(Q.values)?Q.values:void 0;return{application_id:Q.applicationId,channel:this.normalizeGatewayChannel(Q),channel_id:Q.channelId??void 0,data:{component_type:Q.componentType,custom_id:Q.customId,values:B},guild_id:Q.guildId??void 0,id:Q.id,message:{id:Q.message.id},token:Q.token,type:Q.type,user:this.normalizeGatewayUser(Q.user),version:Q.version}}normalizeGatewayChannel(Q){if(!Q.channel)return;let B="parentId"in Q.channel&&typeof Q.channel.parentId==="string"?Q.channel.parentId:void 0;return{id:Q.channel.id,parent_id:B,type:Q.channel.type}}normalizeGatewayCommandOptions(Q){return Q.map((B)=>({name:B.name,options:B.options?this.normalizeGatewayCommandOptions(B.options):void 0,type:B.type,value:B.value}))}normalizeGatewayUser(Q){return{avatar:Q.avatar??void 0,bot:Q.bot,discriminator:Q.discriminator,global_name:Q.globalName??void 0,id:Q.id,username:Q.username}}async handleForwardedGatewayEvent(Q,B){switch(this.logger.info("Processing forwarded Gateway event",{type:Q.type,timestamp:Q.timestamp}),Q.type){case"GATEWAY_MESSAGE_CREATE":await this.handleForwardedMessage(Q.data,B);break;case"GATEWAY_MESSAGE_REACTION_ADD":await this.handleForwardedReaction(Q.data,!0,B);break;case"GATEWAY_MESSAGE_REACTION_REMOVE":await this.handleForwardedReaction(Q.data,!1,B);break;default:this.logger.debug("Forwarded Gateway event (no handler)",{type:Q.type})}return new Response(JSON.stringify({ok:!0}),{status:200,headers:{"Content-Type":"application/json"}})}async handleForwardedMessage(Q,B){if(!this.chat)return;let w=Q.guild_id||"@me",$=Q.channel_id,D,f=$;if(Q.thread)D=Q.thread.id,f=Q.thread.parent_id;else if(Q.channel_type===11||Q.channel_type===12)try{let F=await(await this.discordFetch(`/channels/${$}`,"GET")).json();if(F.parent_id)D=$,f=F.parent_id,this.logger.debug("Fetched thread parent for forwarded message",{threadId:$,parentId:F.parent_id})}catch(G){this.logger.error("Failed to fetch thread parent",{error:String(G),channelId:$})}let Y=Q.is_mention||Q.mentions.some((G)=>G.id===this.applicationId),X=this.mentionRoleIds.length>0&&Q.mention_roles?.some((G)=>this.mentionRoleIds.includes(G)),H=Y||X;if(!D&&H)try{let G=await this.createDiscordThread($,Q.id);D=G.id,this.logger.debug("Created Discord thread for forwarded mention",{channelId:$,messageId:Q.id,threadId:G.id})}catch(G){this.logger.error("Failed to create Discord thread for mention",{error:String(G),messageId:Q.id})}let W=this.encodeThreadId({guildId:w,channelId:f,threadId:D}),Z=new x5({id:Q.id,threadId:W,text:Q.content,formatted:this.formatConverter.toAst(Q.content),author:{userId:Q.author.id,userName:Q.author.username,fullName:Q.author.global_name||Q.author.username,isBot:Q.author.bot===!0,isMe:Q.author.id===this.applicationId},metadata:{dateSent:new Date(Q.timestamp),edited:!1},attachments:Q.attachments.map((G)=>({type:this.getAttachmentType(G.content_type),url:G.url,name:G.filename,mimeType:G.content_type,size:G.size})),raw:Q,isMention:H});try{await this.chat.handleIncomingMessage(this,W,Z)}catch(G){this.logger.error("Error handling forwarded message",{error:String(G),messageId:Q.id})}}async handleForwardedReaction(Q,B,w){if(!this.chat)return;let $=Q.guild_id||"@me",D=Q.channel_id,f,Y=D;if(Q.channel_type===DM.GuildPublicThread||Q.channel_type===DM.GuildPrivateThread){let F=this.threadParentCache.get(D);if(F&&F.expiresAt>Date.now())f=D,Y=F.parentId;else try{let L=await(await this.discordFetch(`/channels/${D}`,"GET")).json();if(L.parent_id)f=D,Y=L.parent_id,this.threadParentCache.set(D,{parentId:L.parent_id,expiresAt:Date.now()+A.THREAD_PARENT_CACHE_TTL})}catch(I){this.logger.error("Failed to fetch thread parent for reaction",{error:String(I),channelId:D})}}let X=this.encodeThreadId({guildId:$,channelId:Y,threadId:f}),H=Q.emoji.name||"unknown",W=this.normalizeDiscordEmoji(H),Z=Q.user??Q.member?.user;if(!Z){this.logger.warn("Reaction event missing user info",{data:Q});return}let G={adapter:this,threadId:X,messageId:Q.message_id,emoji:W,rawEmoji:Q.emoji.id?`<:${H}:${Q.emoji.id}>`:H,added:B,user:{userId:Z.id,userName:Z.username,fullName:Z.username,isBot:Z.bot===!0,isMe:Z.id===this.applicationId},raw:Q};this.chat.processReaction(G)}async postMessage(Q,B){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=Q;if($)w=$;let f={},Y=[],X=[],H=Y50(B);if(H){let I=vE0(H);Y.push(...I.embeds),X.push(...I.components)}else f.content=this.truncateContent(QM(this.formatConverter.renderPostable(B),"discord"));if(Y.length>0)f.embeds=Y;if(X.length>0)f.components=X;let W=ZE0(B),Z=this.tryPostSlashResponse(D,f,W);if(Z)return Z;if(W.length>0)return this.postMessageWithFiles(w,D,f,W);this.logger.debug("Discord API: POST message",{channelId:w,contentLength:f.content?.length||0,embedCount:Y.length,componentCount:X.length});let F=await(await this.discordFetch(`/channels/${w}/messages`,"POST",f)).json();return this.logger.debug("Discord API: POST message response",{messageId:F.id}),{id:F.id,threadId:D,raw:F}}tryPostSlashResponse(Q,B,w){let $=this.requestContext.getStore()?.slashCommand;if(!$||$.channelId!==Q)return;return this.postSlashCommandResponse($,Q,B,w)}async postSlashCommandResponse(Q,B,w,$){let D=!Q.initialResponseSent;Q.initialResponseSent=!0;let f=D?`/webhooks/${this.applicationId}/${Q.interactionToken}/messages/@original`:`/webhooks/${this.applicationId}/${Q.interactionToken}?wait=true`,Y=D?"PATCH":"POST";this.logger.debug("Discord interaction webhook: responding to slash command",{threadId:B,isInitialResponse:D,hasFiles:$.length>0});let H=await($.length>0?await this.discordInteractionFetchWithFiles(f,Y,w,$):await this.discordInteractionFetch(f,Y,w)).json();return{id:H.id,threadId:B,raw:H}}async createDiscordThread(Q,B){let w=`Thread ${new Date().toLocaleString()}`;this.logger.debug("Discord API: POST thread",{channelId:Q,messageId:B,threadName:w});try{let D=await(await this.discordFetch(`/channels/${Q}/messages/${B}/threads`,"POST",{name:w,auto_archive_duration:1440})).json();return this.logger.debug("Discord API: POST thread response",{threadId:D.id,threadName:D.name}),D}catch($){if($ instanceof NC&&typeof $.message==="string"&&$.message.includes('"code"')&&$.message.includes("160004"))return this.logger.debug("Thread already exists for message, reusing existing thread",{channelId:Q,messageId:B}),{id:B,name:w};throw $}}truncateContent(Q){if(Q.length<=RV1)return Q;return`${Q.slice(0,RV1-3)}...`}async postMessageWithFiles(Q,B,w,$){let D=new FormData;D.append("payload_json",JSON.stringify(w));for(let X=0;X<$.length;X++){let H=$[X];if(!H)continue;let W=await KE0(H.data,{platform:"discord"});if(!W)continue;let Z=new Blob([new Uint8Array(W)],{type:H.mimeType||"application/octet-stream"});D.append(`files[${X}]`,Z,H.filename)}let f=await fetch(`${X50}/channels/${Q}/messages`,{method:"POST",headers:{Authorization:`Bot ${this.botToken}`},body:D});if(!f.ok){let X=await f.text();throw new NC("discord",`Failed to post message: ${f.status} ${X}`)}let Y=await f.json();return{id:Y.id,threadId:B,raw:Y}}async discordInteractionFetch(Q,B,w){let $=await fetch(`${X50}${Q}`,{method:B,headers:w?{"Content-Type":"application/json"}:void 0,body:w?JSON.stringify(w):void 0});if(!$.ok){let D=await $.text();throw this.logger.error("Discord interaction API error",{path:Q,method:B,status:$.status,error:D}),new NC("discord",`Discord interaction API error: ${$.status} ${D}`)}return $}async discordInteractionFetchWithFiles(Q,B,w,$){let D=new FormData;D.append("payload_json",JSON.stringify(w));for(let Y=0;Y<$.length;Y++){let X=$[Y];if(!X)continue;let H=await KE0(X.data,{platform:"discord"});if(!H)continue;let W=new Blob([new Uint8Array(H)],{type:X.mimeType||"application/octet-stream"});D.append(`files[${Y}]`,W,X.filename)}let f=await fetch(`${X50}${Q}`,{method:B,body:D});if(!f.ok){let Y=await f.text();throw this.logger.error("Discord interaction API error",{path:Q,method:B,status:f.status,error:Y}),new NC("discord",`Discord interaction API error: ${f.status} ${Y}`)}return f}async editMessage(Q,B,w){let{channelId:$,threadId:D}=this.decodeThreadId(Q),f=D||$,Y={},X=[],H=[],W=Y50(w);if(W){let F=vE0(W);X.push(...F.embeds),H.push(...F.components),Y.content=""}else Y.content=this.truncateContent(QM(this.formatConverter.renderPostable(w),"discord"));if(X.length>0)Y.embeds=X;if(H.length>0)Y.components=H;this.logger.debug("Discord API: PATCH message",{channelId:f,messageId:B,contentLength:Y.content?.length||0});let G=await(await this.discordFetch(`/channels/${f}/messages/${B}`,"PATCH",Y)).json();return this.logger.debug("Discord API: PATCH message response",{messageId:G.id}),{id:G.id,threadId:Q,raw:G}}async deleteMessage(Q,B){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=$||w;this.logger.debug("Discord API: DELETE message",{channelId:D,messageId:B}),await this.discordFetch(`/channels/${D}/messages/${B}`,"DELETE"),this.logger.debug("Discord API: DELETE message response",{ok:!0})}async addReaction(Q,B,w){let{channelId:$,threadId:D}=this.decodeThreadId(Q),f=D||$,Y=this.encodeEmoji(w);this.logger.debug("Discord API: PUT reaction",{channelId:f,messageId:B,emoji:Y}),await this.discordFetch(`/channels/${f}/messages/${B}/reactions/${Y}/@me`,"PUT"),this.logger.debug("Discord API: PUT reaction response",{ok:!0})}async removeReaction(Q,B,w){let{channelId:$,threadId:D}=this.decodeThreadId(Q),f=D||$,Y=this.encodeEmoji(w);this.logger.debug("Discord API: DELETE reaction",{channelId:f,messageId:B,emoji:Y}),await this.discordFetch(`/channels/${f}/messages/${B}/reactions/${Y}/@me`,"DELETE"),this.logger.debug("Discord API: DELETE reaction response",{ok:!0})}encodeEmoji(Q){let B=ui.toDiscord?ui.toDiscord(Q):String(Q);return encodeURIComponent(B)}async startTyping(Q,B){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=$||w;this.logger.debug("Discord API: POST typing",{channelId:D}),await this.discordFetch(`/channels/${D}/typing`,"POST")}async fetchMessages(Q,B={}){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=$||w,f=B.limit||50,Y=B.direction??"backward",X=new URLSearchParams;if(X.set("limit",String(f)),B.cursor)if(Y==="backward")X.set("before",B.cursor);else X.set("after",B.cursor);this.logger.debug("Discord API: GET messages",{channelId:D,limit:f,direction:Y,cursor:B.cursor});let W=await(await this.discordFetch(`/channels/${D}/messages?${X.toString()}`,"GET")).json();this.logger.debug("Discord API: GET messages response",{messageCount:W.length});let G=[...W].reverse().map((I)=>this.parseDiscordMessage(I,Q)),F;if(W.length===f)if(Y==="backward")F=W.at(-1)?.id;else F=W[0]?.id;return{messages:G,nextCursor:F}}async fetchThread(Q){let{channelId:B,guildId:w}=this.decodeThreadId(Q);this.logger.debug("Discord API: GET channel",{channelId:B});let D=await(await this.discordFetch(`/channels/${B}`,"GET")).json();return{id:Q,channelId:B,channelName:D.name,isDM:D.type===DM.DM||D.type===DM.GroupDM,metadata:{guildId:w,channelType:D.type,raw:D}}}async openDM(Q){this.logger.debug("Discord API: POST DM channel",{userId:Q});let w=await(await this.discordFetch("/users/@me/channels","POST",{recipient_id:Q})).json();return this.logger.debug("Discord API: POST DM channel response",{channelId:w.id}),this.encodeThreadId({guildId:"@me",channelId:w.id})}isDM(Q){let{guildId:B}=this.decodeThreadId(Q);return B==="@me"}encodeThreadId(Q){let B=Q.threadId?`:${Q.threadId}`:"";return`discord:${Q.guildId}:${Q.channelId}${B}`}decodeThreadId(Q){let B=Q.split(":");if(B.length<3||B[0]!=="discord")throw new rH("discord",`Invalid Discord thread ID: ${Q}`);return{guildId:B[1],channelId:B[2],threadId:B[3]}}parseMessage(Q){let B=Q,w=B.guild_id||"@me",$=this.encodeThreadId({guildId:w,channelId:B.channel_id});return this.parseDiscordMessage(B,$)}parseDiscordMessage(Q,B){let w=Q.type===kz1.ThreadStarterMessage&&Q.referenced_message?Q.referenced_message:Q,$=w.author,D=$.bot??!1,f=$.id===this.botUserId;return new x5({id:w.id,threadId:B,text:this.formatConverter.extractPlainText(w.content),formatted:this.formatConverter.toAst(w.content),raw:Q,author:{userId:$.id,userName:$.username,fullName:$.global_name||$.username,isBot:D,isMe:f},metadata:{dateSent:new Date(w.timestamp),edited:w.edited_timestamp!==null,editedAt:w.edited_timestamp?new Date(w.edited_timestamp):void 0},attachments:(w.attachments||[]).map((Y)=>({type:this.getAttachmentType(Y.content_type),url:Y.url,name:Y.filename,mimeType:Y.content_type,size:Y.size,width:Y.width??void 0,height:Y.height??void 0}))})}getAttachmentType(Q){if(!Q)return"file";if(Q.startsWith("image/"))return"image";if(Q.startsWith("video/"))return"video";if(Q.startsWith("audio/"))return"audio";return"file"}renderFormatted(Q){return this.formatConverter.fromAst(Q)}async discordFetch(Q,B,w){let $=`${this.apiBaseUrl}${Q}`,D={Authorization:`Bot ${this.botToken}`};if(w)D["Content-Type"]="application/json";let f=await fetch($,{method:B,headers:D,body:w?JSON.stringify(w):void 0});if(!f.ok){let Y=await f.text();throw this.logger.error("Discord API error",{path:Q,method:B,status:f.status,error:Y}),new NC("discord",`Discord API error: ${f.status} ${Y}`)}return f}async startGatewayListener(Q,B=180000,w,$){if(!this.chat)return new Response("Chat instance not initialized",{status:500});if(!Q.waitUntil)return new Response("waitUntil not provided",{status:500});this.logger.info("Starting Discord Gateway listener",{durationMs:B,webhookUrl:$?"configured":"not configured"});let D=this.runGatewayListener(B,w,$);return Q.waitUntil(D),new Response(JSON.stringify({status:"listening",durationMs:B,message:`Gateway listener started, will run for ${B/1000} seconds`}),{status:200,headers:{"Content-Type":"application/json"}})}async runGatewayListener(Q,B,w){let $=new T9.Client({intents:[T9.GatewayIntentBits.Guilds,T9.GatewayIntentBits.GuildMessages,T9.GatewayIntentBits.MessageContent,T9.GatewayIntentBits.DirectMessages,T9.GatewayIntentBits.GuildMessageReactions,T9.GatewayIntentBits.DirectMessageReactions],partials:[T9.Partials.Channel]}),D=!1;if(w)$.on("raw",async(f)=>{if(D)return;if(!f.t)return;this.logger.info("Discord Gateway forwarding event",{type:f.t}),await this.forwardGatewayEvent(w,{type:`GATEWAY_${f.t}`,timestamp:Date.now(),data:f.d})});else this.setupLegacyGatewayHandlers($,()=>D);$.on(T9.Events.ClientReady,()=>{this.logger.info("Discord Gateway connected",{username:$.user?.username,id:$.user?.id})}),$.on(T9.Events.Error,(f)=>{this.logger.error("Discord Gateway error",{error:String(f)})});try{await $.login(this.botToken),await new Promise((f)=>{let Y=setTimeout(f,Q);if(B){if(B.aborted){clearTimeout(Y),f();return}B.addEventListener("abort",()=>{this.logger.info("Discord Gateway listener received abort signal (new listener started)"),clearTimeout(Y),f()},{once:!0})}}),this.logger.info("Discord Gateway listener duration elapsed, disconnecting")}catch(f){this.logger.error("Discord Gateway listener error",{error:String(f)})}finally{D=!0,$.destroy(),this.logger.info("Discord Gateway listener stopped")}}setupLegacyGatewayHandlers(Q,B){Q.on(T9.Events.MessageCreate,async(w)=>{if(B()){this.logger.debug("Ignoring message - Gateway is shutting down");return}if(w.author.bot){this.logger.debug("Ignoring message from bot",{authorId:w.author.id,authorName:w.author.username,isMe:w.author.id===Q.user?.id});return}let $=w.mentions.has(Q.user?.id??""),D=this.mentionRoleIds.length>0&&w.mentions.roles.some((Y)=>this.mentionRoleIds.includes(Y.id)),f=$||D;this.logger.info("Discord Gateway message received",{channelId:w.channelId,guildId:w.guildId,authorId:w.author.id,isMentioned:f,isUserMentioned:$,isRoleMentioned:D,content:w.content.slice(0,100)}),await this.handleGatewayMessage(w,f)}),Q.on(T9.Events.InteractionCreate,async(w)=>{if(B()){this.logger.debug("Ignoring interaction - Gateway is shutting down");return}this.logger.info("Discord Gateway interaction received",{id:w.id,type:w.type});try{await this.handleGatewayInteraction(w)}catch($){this.logger.error("Error handling Gateway interaction",{error:String($),interactionId:w.id})}}),Q.on(T9.Events.MessageReactionAdd,async(w,$)=>{if(B()){this.logger.debug("Ignoring reaction - Gateway is shutting down");return}if($.bot){this.logger.debug("Ignoring reaction from bot",{userId:$.id,isMe:$.id===Q.user?.id});return}if(this.logger.info("Discord Gateway reaction added",{emoji:w.emoji.name,messageId:w.message.id,channelId:w.message.channelId,userId:$.id}),$.username)await this.handleGatewayReaction(w,$,!0)}),Q.on(T9.Events.MessageReactionRemove,async(w,$)=>{if(B()){this.logger.debug("Ignoring reaction removal - Gateway is shutting down");return}if($.bot){this.logger.debug("Ignoring reaction removal from bot",{userId:$.id,isMe:$.id===Q.user?.id});return}if(this.logger.info("Discord Gateway reaction removed",{emoji:w.emoji.name,messageId:w.message.id,channelId:w.message.channelId,userId:$.id}),$.username)await this.handleGatewayReaction(w,$,!1)})}async forwardGatewayEvent(Q,B){try{this.logger.debug("Forwarding Gateway event to webhook",{type:B.type,webhookUrl:Q});let w=await fetch(Q,{method:"POST",headers:{"Content-Type":"application/json","x-discord-gateway-token":this.botToken},body:JSON.stringify(B)});if(w.ok)this.logger.debug("Gateway event forwarded successfully",{type:B.type});else{let $=await w.text();this.logger.error("Failed to forward Gateway event",{type:B.type,status:w.status,error:$})}}catch(w){this.logger.error("Error forwarding Gateway event",{type:B.type,error:String(w)})}}async handleGatewayMessage(Q,B){if(!this.chat)return;let w=Q.guildId||"@me",$=Q.channelId,D=Q.channel.isThread(),f,Y=$;if(D&&"parentId"in Q.channel&&Q.channel.parentId)f=$,Y=Q.channel.parentId;if(!f&&B)try{let W=await this.createDiscordThread($,Q.id);f=W.id,this.logger.debug("Created Discord thread for incoming mention",{channelId:$,messageId:Q.id,threadId:W.id})}catch(W){this.logger.error("Failed to create Discord thread for mention",{error:String(W),messageId:Q.id})}let X=this.encodeThreadId({guildId:w,channelId:Y,threadId:f}),H=new x5({id:Q.id,threadId:X,text:Q.content,formatted:this.formatConverter.toAst(Q.content),author:{userId:Q.author.id,userName:Q.author.username,fullName:Q.author.displayName||Q.author.username,isBot:Q.author.bot,isMe:!1},metadata:{dateSent:Q.createdAt,edited:Q.editedAt!==null,editedAt:Q.editedAt??void 0},attachments:Q.attachments.map((W)=>({type:this.getAttachmentType(W.contentType),url:W.url,name:W.name,mimeType:W.contentType??void 0,size:W.size})),raw:{id:Q.id,channel_id:$,guild_id:w,content:Q.content,author:{id:Q.author.id,username:Q.author.username},timestamp:Q.createdAt.toISOString()},isMention:B});try{await this.chat.handleIncomingMessage(this,X,H)}catch(W){this.logger.error("Error handling Gateway message",{error:String(W),messageId:Q.id})}}async handleGatewayReaction(Q,B,w){if(!this.chat)return;let $=Q.message.guildId||"@me",D=Q.message.channelId,f=Q.message.channel?.isThread?.(),Y=D,X;if(f&&Q.message.channel?.parentId)X=D,Y=Q.message.channel.parentId;let H=this.encodeThreadId({guildId:$,channelId:Y,threadId:X}),W=Q.emoji.name||"unknown",Z=this.normalizeDiscordEmoji(W),G={adapter:this,threadId:H,messageId:Q.message.id,emoji:Z,rawEmoji:Q.emoji.id?`<:${W}:${Q.emoji.id}>`:W,added:w,user:{userId:B.id,userName:B.username,fullName:B.username,isBot:B.bot===!0,isMe:B.id===this.applicationId},raw:{emoji:Q.emoji,message_id:Q.message.id,channel_id:Q.message.channelId,guild_id:Q.message.guildId,user_id:B.id}};this.chat.processReaction(G)}channelIdFromThreadId(Q){return Q.split(":").slice(0,3).join(":")}async fetchChannelMessages(Q,B={}){let $=Q.split(":")[2];if(!$)throw new rH("discord",`Invalid Discord channel ID: ${Q}`);let D=B.limit||50,f=B.direction??"backward",Y=new URLSearchParams;if(Y.set("limit",String(D)),B.cursor)if(f==="backward")Y.set("before",B.cursor);else Y.set("after",B.cursor);this.logger.debug("Discord API: GET channel messages",{channelId:$,limit:D,direction:f,cursor:B.cursor});let H=await(await this.discordFetch(`/channels/${$}/messages?${Y.toString()}`,"GET")).json();this.logger.debug("Discord API: GET channel messages response",{messageCount:H.length});let Z=[...H].reverse().map((F)=>this.parseDiscordMessage(F,Q)),G;if(H.length===D)if(f==="backward")G=H.at(-1)?.id;else G=H[0]?.id;return{messages:Z,nextCursor:G}}async listThreads(Q,B={}){let w=Q.split(":"),$=w[1],D=w[2];if(!($&&D))throw new rH("discord",`Invalid Discord channel ID: ${Q}`);this.logger.debug("Discord API: GET threads",{guildId:$,channelId:D});let X=((await(await this.discordFetch(`/guilds/${$}/threads/active`,"GET")).json()).threads||[]).filter((b)=>b.parent_id===D),H=[];try{H=(await(await this.discordFetch(`/channels/${D}/threads/archived/public?limit=${B.limit||50}`,"GET")).json()).threads||[]}catch{this.logger.debug("Could not fetch archived threads (may lack permissions)")}let W=[...X,...H],Z=new Set,G=W.filter((b)=>{if(Z.has(b.id))return!1;return Z.add(b.id),!0}),F=B.limit||50,I=G.slice(0,F),L=[];for(let b of I){let N=this.encodeThreadId({guildId:$,channelId:D,threadId:b.id});try{let g=(await(await this.discordFetch(`/channels/${b.id}/messages?limit=1&after=0`,"GET")).json())[0];if(g)L.push({id:N,rootMessage:this.parseDiscordMessage(g,N),replyCount:b.total_message_sent??b.message_count,lastReplyAt:b.thread_metadata?.archive_timestamp?new Date(b.thread_metadata.archive_timestamp):void 0})}catch{L.push({id:N,rootMessage:new x5({id:b.id,threadId:N,text:b.name,formatted:this.formatConverter.toAst(b.name),raw:b,author:{userId:"unknown",userName:"unknown",fullName:"unknown",isBot:!1,isMe:!1},metadata:{dateSent:new Date,edited:!1},attachments:[]}),replyCount:b.total_message_sent??b.message_count})}}return this.logger.debug("Discord API: listThreads result",{threadCount:L.length}),{threads:L,nextCursor:G.length>F?String(F):void 0}}async fetchChannelInfo(Q){let w=Q.split(":")[2];if(!w)throw new rH("discord",`Invalid Discord channel ID: ${Q}`);this.logger.debug("Discord API: GET channel info",{channelId:w});let D=await(await this.discordFetch(`/channels/${w}`,"GET")).json();return{id:Q,name:D.name,isDM:D.type===DM.DM||D.type===DM.GroupDM,memberCount:D.member_count,metadata:{channelType:D.type,raw:D}}}async postChannelMessage(Q,B){let $=Q.split(":")[2];if(!$)throw new rH("discord",`Invalid Discord channel ID: ${Q}`);let D={},f=[],Y=[],X=Y50(B);if(X){let F=vE0(X);f.push(...F.embeds),Y.push(...F.components)}else D.content=this.truncateContent(QM(this.formatConverter.renderPostable(B),"discord"));if(f.length>0)D.embeds=f;if(Y.length>0)D.components=Y;let H=ZE0(B),W=this.tryPostSlashResponse(Q,D,H);if(W)return W;if(H.length>0)return this.postMessageWithFiles($,Q,D,H);this.logger.debug("Discord API: POST channel message",{channelId:$,contentLength:D.content?.length||0});let G=await(await this.discordFetch(`/channels/${$}/messages`,"POST",D)).json();return{id:G.id,threadId:Q,raw:G}}normalizeDiscordEmoji(Q){let w={"\uD83D\uDC4D":"thumbs_up","\uD83D\uDC4E":"thumbs_down","\u2764\uFE0F":"heart","\u2764":"heart","\uD83D\uDD25":"fire","\uD83D\uDE80":"rocket","\uD83D\uDE4C":"raised_hands","\u2705":"check","\u274C":"x","\uD83D\uDC4B":"wave","\uD83E\uDD14":"thinking","\uD83D\uDE0A":"smile","\uD83D\uDE02":"laugh","\uD83C\uDF89":"party","\u2B50":"star","\u2728":"sparkles","\uD83D\uDC40":"eyes","\uD83D\uDCAF":"100"}[Q]||Q;return SJ(w)}};function CV1(A){return new nkQ(A??{})}var rkQ=class{subscriptions=new Set;locks=new Map;cache=new Map;queues=new Map;connected=!1;connectPromise=null;async connect(){if(this.connected)return;if(!this.connectPromise)this.connectPromise=Promise.resolve().then(()=>{this.connected=!0});await this.connectPromise}async disconnect(){this.connected=!1,this.connectPromise=null,this.subscriptions.clear(),this.locks.clear(),this.queues.clear()}async subscribe(A){this.ensureConnected(),this.subscriptions.add(A)}async unsubscribe(A){this.ensureConnected(),this.subscriptions.delete(A)}async isSubscribed(A){return this.ensureConnected(),this.subscriptions.has(A)}async acquireLock(A,Q){this.ensureConnected(),this.cleanExpiredLocks();let B=this.locks.get(A);if(B&&B.expiresAt>Date.now())return null;let w={threadId:A,token:okQ(),expiresAt:Date.now()+Q};return this.locks.set(A,w),w}async forceReleaseLock(A){this.ensureConnected(),this.locks.delete(A)}async releaseLock(A){this.ensureConnected();let Q=this.locks.get(A.threadId);if(Q&&Q.token===A.token)this.locks.delete(A.threadId)}async extendLock(A,Q){this.ensureConnected();let B=this.locks.get(A.threadId);if(!B||B.token!==A.token)return!1;if(B.expiresAt<Date.now())return this.locks.delete(A.threadId),!1;return B.expiresAt=Date.now()+Q,!0}async get(A){this.ensureConnected();let Q=this.cache.get(A);if(!Q)return null;if(Q.expiresAt!==null&&Q.expiresAt<=Date.now())return this.cache.delete(A),null;return Q.value}async set(A,Q,B){this.ensureConnected(),this.cache.set(A,{value:Q,expiresAt:B?Date.now()+B:null})}async setIfNotExists(A,Q,B){this.ensureConnected();let w=this.cache.get(A);if(w)if(w.expiresAt!==null&&w.expiresAt<=Date.now())this.cache.delete(A);else return!1;return this.cache.set(A,{value:Q,expiresAt:B?Date.now()+B:null}),!0}async delete(A){this.ensureConnected(),this.cache.delete(A)}async appendToList(A,Q,B){this.ensureConnected();let w=this.cache.get(A),$;if(w&&w.expiresAt!==null&&w.expiresAt<=Date.now())$=[];else if(w&&Array.isArray(w.value))$=w.value;else $=[];if($.push(Q),B?.maxLength&&$.length>B.maxLength)$=$.slice($.length-B.maxLength);this.cache.set(A,{value:$,expiresAt:B?.ttlMs?Date.now()+B.ttlMs:null})}async enqueue(A,Q,B){this.ensureConnected();let w=this.queues.get(A);if(!w)w=[],this.queues.set(A,w);if(w.push(Q),w.length>B)w.splice(0,w.length-B);return w.length}async dequeue(A){this.ensureConnected();let Q=this.queues.get(A);if(!Q||Q.length===0)return null;let B=Q.shift();if(Q.length===0)this.queues.delete(A);return B??null}async queueDepth(A){return this.ensureConnected(),this.queues.get(A)?.length??0}async getList(A){this.ensureConnected();let Q=this.cache.get(A);if(!Q)return[];if(Q.expiresAt!==null&&Q.expiresAt<=Date.now())return this.cache.delete(A),[];if(Array.isArray(Q.value))return Q.value;return[]}ensureConnected(){if(!this.connected)throw Error("MemoryStateAdapter is not connected. Call connect() first.")}cleanExpiredLocks(){let A=Date.now();for(let[Q,B]of this.locks)if(B.expiresAt<=A)this.locks.delete(Q)}_getSubscriptionCount(){return this.subscriptions.size}_getLockCount(){return this.cleanExpiredLocks(),this.locks.size}};function okQ(){return`mem_${Date.now()}_${Math.random().toString(36).substring(2,15)}`}function H50(A){return new rkQ}K0();p0();K0();var skQ=K.object({botToken:K.string().min(1).describe("Discord bot token"),publicKey:K.string().min(1).describe("Discord application public key"),applicationId:K.string().min(1).describe("Discord application ID"),mentionRoleIds:K.array(K.string()).default([]),allowedChannels:K.array(K.string()).default([]),requireMention:K.boolean().default(!0),allowDMs:K.boolean().default(!0),showTypingIndicator:K.boolean().default(!0),useThreads:K.boolean().default(!0),...bN.shape,captureUrlEmoji:K.string().default("\uD83D\uDD16")}),hE0=K.object({userName:K.string().default("brain"),adapters:K.object({discord:skQ.optional()}).default({}),gatewayRunMs:K.number().int().positive().default(540000),gatewayRestartDelayMs:K.number().int().nonnegative().default(1000)});class W50{ttlMs;threads=new Map;sentMessages=new Map;constructor(A=3600000){this.ttlMs=A}set(A){this.cleanup(),this.threads.set(A.id,{thread:A,expiresAt:Date.now()+this.ttlMs})}get(A){if(!A)return;let Q=this.threads.get(A);if(!Q)return;if(Q.expiresAt<=Date.now()){this.threads.delete(A);return}return Q.expiresAt=Date.now()+this.ttlMs,Q.thread}trackMessage(A,Q){this.sentMessages.set(this.messageKey(A,Q.id),Q)}getMessage(A,Q){if(!A)return;return this.sentMessages.get(this.messageKey(A,Q))}clear(){this.threads.clear(),this.sentMessages.clear()}cleanup(){let A=Date.now();for(let[Q,B]of this.threads)if(B.expiresAt<=A)this.threads.delete(Q)}messageKey(A,Q){return`${A}:${Q}`}}K0();var akQ=K.object({subscribedAt:K.string().datetime(),routingMode:K.enum(["auto","mention-required"]).optional(),mentionRequiredNoticeSent:K.boolean().optional()}),tkQ="chat.discord.subscriptions";function CE0(A){return A.scoped({namespace:tkQ,schema:akQ})}function yV1(A,Q=H50()){let B=CE0(A);return new EV1(Q,B)}class EV1{memoryState;subscriptions;constructor(A,Q){this.memoryState=A;this.subscriptions=Q}connect(){return this.memoryState.connect()}disconnect(){return this.memoryState.disconnect()}async subscribe(A){await this.subscriptions.set(A,{subscribedAt:new Date().toISOString()})}async unsubscribe(A){await this.subscriptions.delete(A)}isSubscribed(A){return this.subscriptions.has(A)}acquireLock(A,Q){return this.memoryState.acquireLock(A,Q)}appendToList(A,Q,B){return this.memoryState.appendToList(A,Q,B)}delete(A){return this.memoryState.delete(A)}dequeue(A){return this.memoryState.dequeue(A)}enqueue(A,Q,B){return this.memoryState.enqueue(A,Q,B)}extendLock(A,Q){return this.memoryState.extendLock(A,Q)}forceReleaseLock(A){return this.memoryState.forceReleaseLock(A)}get(A){return this.memoryState.get(A)}getList(A){return this.memoryState.getList(A)}queueDepth(A){return this.memoryState.queueDepth(A)}releaseLock(A){return this.memoryState.releaseLock(A)}set(A,Q,B){return this.memoryState.set(A,Q,B)}setIfNotExists(A,Q,B){return this.memoryState.setIfNotExists(A,Q,B)}}function ni(){return{namespace:"discord-chat",refKind:"discord-chat-upload",routePath:"/api/webhooks/chat/discord/uploads"}}var yE0=["discord"];var gV1={name:"@brains/chat",private:!0,version:"0.2.0-alpha.128",description:"Discord Chat SDK 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:*","@chat-adapter/discord":"^4.29.0","@chat-adapter/state-memory":"^4.29.0",chat:"^4.29.0"},devDependencies:{"@brains/core":"workspace:*","@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest"}};var AOQ=/https?:\/\/\S+/i,QOQ=/[\s\S]+/,BOQ={discord:2000},wOQ="https://discord.com/api/v10",$OQ=8388608,DOQ=5,fOQ=5,TV1=DOQ*fOQ,SV1=80,EE0="approval.confirm",mV1="approval.cancel",uV1="chat.prompt",YOQ="chat.event.unavailable",XOQ="I\u2019ll stop auto-replying now that more people joined. Mention me if you need me.",HOQ=K.object({type:K.literal("card"),children:K.array(K.object({type:K.string()}).passthrough()),imageUrl:K.string().optional(),subtitle:K.string().optional(),title:K.string().optional()}).passthrough(),WOQ=K.object({card:K.custom((A)=>HOQ.safeParse(A).success),fallbackText:K.string().optional()});class Z50 extends eW{app;threadRegistry=new W50;pendingApprovals;uploadContinuity;approvalCardMessages=new Map;promptActions=new Map;toolStatusMessages=new Map;discordGatewayAdapter;discordSubscriptions;gatewayAbortController;gatewayLoopPromise;constructor(A={}){super("chat",gV1,A,hE0);this.pendingApprovals=new NS({loadMessages:async(Q)=>{return await this.context?.conversations.getMessages(Q,{limit:50})??[]},onRestoreError:(Q,B)=>{this.logger.debug("Failed to load pending chat approvals",{error:Q,conversationId:B})}}),this.uploadContinuity=new xS({sourceKind:"discord-chat-upload",loadMessages:async(Q)=>{return await this.context?.conversations.getMessages(Q,{limit:50})??[]},restoreAttachment:async(Q)=>{let B=this.context?.uploads.scoped(ni());if(!B)throw Error("Chat upload store unavailable");let w=await B.read(Q);return this.createChatAttachmentFromStoredUpload(w.record.filename,w.record.mediaType,w.content,w.record.ref)},onLoadError:(Q,B)=>{this.logger.debug("Failed to load prior chat uploads",{error:Q,conversationId:B})},onRestoreError:(Q,B)=>{this.logger.debug("Failed to restore prior chat upload",{error:Q,uploadId:B})}})}async onRegister(A){await super.onRegister(A),this.discordSubscriptions=CE0(A.runtimeState),this.app=this.createChatApp(A),this.registerChatHandlers(this.app)}getWebRoutes(){return[{path:"/api/webhooks/chat/discord",method:"POST",public:!0,handler:async(A)=>{if(!this.app?.webhooks?.discord)return new Response("Discord chat webhook not configured",{status:404});return this.app.webhooks.discord(A)}},{path:"/api/webhooks/chat/discord/uploads",method:"GET",public:!0,handler:async(A)=>{return this.handleDiscordUploadRequest(A)}}]}async handleDiscordUploadRequest(A){if(!this.config.adapters.discord)return new Response("Discord chat uploads not configured",{status:404});let Q=new URL(A.url).searchParams.get("id")?.trim();if(!Q)return new Response("Missing upload id",{status:400});try{let B=this.getDiscordUploadStore(),{record:w,content:$}=await B.read(Q),D=new Uint8Array($).buffer;return new Response(D,{headers:{"Content-Type":w.mediaType,"Content-Length":String($.byteLength),"Cache-Control":"private, no-store","X-Content-Type-Options":"nosniff","Content-Disposition":lI({disposition:new URL(A.url).searchParams.has("download")?"attachment":"inline",filename:w.filename})}})}catch{return new Response("Upload not found",{status:404})}}getDiscordUploadStore(){if(!this.context)throw Error("Chat interface not registered");return this.context.uploads.scoped(ni())}createDaemon(){if(!this.config.adapters.discord)return;return{start:async()=>{await this.startGatewayLoop()},stop:async()=>{await this.stopGatewayLoop()},healthCheck:async()=>({status:this.gatewayLoopPromise?"healthy":"error",message:this.gatewayLoopPromise?"Chat gateway loop running":"Chat gateway loop stopped",lastCheck:new Date})}}sendMessageToChannel({channelId:A,message:Q}){let B=this.threadRegistry.get(A);if(!B)return;let w=this.toDiscordCardOutput(Q);if(w){B.post(w).catch(($)=>this.logger.error("Failed to send chat message",{error:$,channelId:A}));return}if(typeof Q!=="string")return;for(let $ of this.chunkForChannel(A,Q))B.post($).catch((D)=>this.logger.error("Failed to send chat message",{error:D,channelId:A}))}async sendMessageWithId({channelId:A,message:Q}){let B=this.threadRegistry.get(A);if(!B)return;let w=this.toDiscordCardOutput(Q);if(w){let D=await B.post(w);return this.threadRegistry.trackMessage(B.id,D),D.id}if(typeof Q!=="string")return;let $;for(let D of this.chunkForChannel(A,Q))$=await B.post(D),this.threadRegistry.trackMessage(B.id,$);return $?.id}async editMessage({channelId:A,messageId:Q,newMessage:B}){let w=this.threadRegistry.getMessage(A,Q);if(!w)return!1;try{let $=await w.edit(this.toDiscordCardOutput(B)??(typeof B==="string"?B:""));if(A)this.threadRegistry.trackMessage(A,$);return!0}catch{return!1}}supportsMessageEditing(){return!0}toDiscordCardOutput(A){let Q=WOQ.safeParse(A);if(!Q.success)return;let{card:B,fallbackText:w}=Q.data;if(w===void 0)return{card:B};return{card:B,fallbackText:w}}formatProgressOutput(A){return this.formatProgressPayload(A)}formatCompletionOutput(A){return this.formatProgressPayload(A)}formatProgressPayload(A){let Q=tO(A),B=[{type:"text",content:Q.label}];if(Q.amount)B.push({type:"text",content:Q.amount});if(Q.message)B.push({type:"text",content:Q.message});return{card:{type:"card",title:Q.title,children:B},fallbackText:Q.fallback}}async handleProgressEvent(A,Q){let B=A.metadata.interfaceType;if(B&&B!==this.id){if(!this.isEnabledPlatform(B))return;let w={...A,metadata:{...A.metadata,interfaceType:this.id}};await super.handleProgressEvent(w,w.metadata);return}await super.handleProgressEvent(A,Q)}async handleToolActivityEvent(A){if(A.interfaceType===this.id){await super.handleToolActivityEvent(A);return}if(!this.isEnabledPlatform(A.interfaceType))return;await super.handleToolActivityEvent({...A,interfaceType:this.id})}async handleToolStatusUpdate(A){if(A.interfaceType!==this.id||!A.channelId)return;let Q=IS(A);if(A.state==="running"){await this.sendToolStatusMessage(Q,A);return}await this.updateToolStatusMessage(Q,A)}async sendToolStatusMessage(A,Q){let B=Q.channelId;if(!B)return;let w=this.threadRegistry.get(B);if(!w)return;let $=await w.post(this.formatToolStatusPayload(Q));this.threadRegistry.trackMessage(B,$),this.toolStatusMessages.set(A,{channelId:B,message:$})}async updateToolStatusMessage(A,Q){let B=this.formatToolStatusPayload(Q),w=this.toolStatusMessages.get(A);if(w){let Y=await w.message.edit(B);this.threadRegistry.trackMessage(w.channelId,Y),this.toolStatusMessages.delete(A);return}let $=Q.channelId;if(!$)return;let D=this.threadRegistry.get($);if(!D)return;let f=await D.post(B);this.threadRegistry.trackMessage($,f)}formatToolStatusPayload(A){let Q=aO(A),B=[{type:"text",content:Q.label}];if(A.error)B.push({type:"text",content:A.error});return{card:{type:"card",title:Q.title,children:B},fallbackText:Q.fallback}}isEnabledPlatform(A){return A==="discord"&&Boolean(this.config.adapters.discord)}chunkForChannel(A,Q){let B=this.parseChatPlatform(A),w=B?BOQ[B]:void 0;return w?ob(Q,w):[Q]}parseChatPlatform(A){let Q=A?.split(":")[0];return yE0.find((B)=>B===Q)}createChatApp(A){let Q=this.config.adapters.discord;if(!Q)return new HE0({userName:this.config.userName,adapters:{},state:H50()});let B=CV1({botToken:Q.botToken,publicKey:Q.publicKey,applicationId:Q.applicationId,mentionRoleIds:Q.mentionRoleIds});return this.discordGatewayAdapter=B,new HE0({userName:this.config.userName,adapters:{discord:B},concurrency:{strategy:"queue",maxQueueSize:5,onQueueFull:"drop-oldest"},state:yV1(A.runtimeState)})}registerChatHandlers(A){if(A.onDirectMessage(async(Q,B,w,$)=>{await this.handleRoutedMessage(Q,B,$)}),A.onNewMention(async(Q,B,w)=>{let $=this.getPlatformConfig(Q);if($&&this.shouldRouteDiscordMessage(Q,B,$)&&!Q.isDM&&$.useThreads)await this.subscribeOwnedDiscordThread(Q,B);await this.handleRoutedMessage(Q,B,w)}),A.onSubscribedMessage(async(Q,B,w)=>{if(!await this.shouldRouteSubscribedMessage(Q,B))return;await this.handleRoutedMessage(Q,B,w)}),this.config.adapters.discord&&!this.config.adapters.discord.requireMention)A.onNewMessage(QOQ,async(Q,B,w)=>{await this.handleRoutedMessage(Q,B,w)});A.onNewMessage(AOQ,async(Q,B)=>{await this.handlePassiveUrlCapture(Q,B)}),A.onAction([EE0,mV1],async(Q)=>{await this.handleApprovalAction(Q)}),A.onAction(uV1,async(Q)=>{await this.handlePromptAction(Q)})}async handlePromptAction(A){if(!this.context||!A.thread||!A.value)return;let Q=A.adapter.name;if(!this.isEnabledPlatform(Q))return;let B=A.thread;if(!this.shouldHandleDiscordAction(B,Q))return;let w=this.promptActions.get(A.value);if(w?.threadId!==B.id){await B.post(this.formatNoticePayload("That suggested action is no longer available.","Action unavailable"));return}let $=this.getThreadIdParts(B.id),D=this.context.permissions.getUserLevel(Q,A.user.userId,{channelId:$.channelId??B.channelId,isBot:Boolean(A.user.isBot)}),f=this.getConversationId(Q,B.id),Y=B.id;this.startProcessingInput(Y);try{if(this.getPlatformConfig(B)?.showTypingIndicator)await B.startTyping().catch((H)=>this.logger.debug("Typing indicator failed",{error:H,channelId:Y}));let X=await this.context.agent.chat(w.prompt,f,{userPermissionLevel:D,interfaceType:Q,channelId:Y,channelName:B.isDM?"DM":B.channelId,...this.buildActionEventMetadata(Q,B,A)});await this.renderAgentResponse({thread:B,channelId:Y,conversationId:f,response:X,userPermissionLevel:D})}catch(X){this.logger.error("Error handling chat prompt action",{error:X,channelId:Y}),await B.post(this.toDiscordCardOutput(this.formatErrorPayload(X))??"Message failed.")}finally{this.endProcessingInput()}}async handleApprovalAction(A){if(!this.context||!A.thread||!A.value)return;let Q=A.adapter.name;if(!this.isEnabledPlatform(Q))return;let B=this.getConversationId(Q,A.thread.id);if(!(await this.getPendingApprovalIds(B)).has(A.value)){await A.thread.post(this.formatNoticePayload("That approval is no longer pending."));return}let $=A.thread;if(!this.shouldHandleDiscordAction($,Q))return;let D=this.getThreadIdParts($.id),f=this.context.permissions.getUserLevel(Q,A.user.userId,{channelId:D.channelId??$.channelId,isBot:Boolean(A.user.isBot)});await this.confirmApproval({thread:$,conversationId:B,approvalId:A.value,confirmed:A.actionId===EE0,userPermissionLevel:f,metadata:this.buildActionEventMetadata(Q,$,A)})}shouldHandleDiscordAction(A,Q){if(Q!=="discord")return!0;let B=this.config.adapters.discord;if(!B)return!1;if(A.isDM&&!B.allowDMs)return!1;return this.isAllowedChannel(A,B)}async subscribeOwnedDiscordThread(A,Q){if(!this.isBotCreatedDiscordThread(A,Q))return;try{await A.subscribe(),await this.discordSubscriptions?.set(A.id,{subscribedAt:new Date().toISOString()})}catch(B){this.logger.debug("Discord thread subscription failed",{error:B,threadId:A.id})}}async shouldRouteSubscribedMessage(A,Q){if(this.getPlatform(A)!=="discord")return!1;if(A.isDM)return!0;let B=await this.discordSubscriptions?.get(A.id);if(!B)return!1;if(B.routingMode==="mention-required"){if(!Q.isMention&&!B.mentionRequiredNoticeSent)await this.postMentionRequiredNotice(A,B);return Boolean(Q.isMention)}if(!await this.shouldRequireMentionInSubscribedThread(A))return!0;let $={...B,routingMode:"mention-required"};if(!Q.isMention&&!B.mentionRequiredNoticeSent)await this.postMentionRequiredNotice(A,$);else await this.discordSubscriptions?.set(A.id,$);return Boolean(Q.isMention)}async postMentionRequiredNotice(A,Q){await A.post(XOQ),await this.discordSubscriptions?.set(A.id,{...Q,routingMode:"mention-required",mentionRequiredNoticeSent:!0})}async shouldRequireMentionInSubscribedThread(A){try{return(await A.getParticipants()).filter((w)=>!w.isBot&&!w.isMe).length>1}catch(Q){return this.logger.debug("Failed to inspect Discord thread participants",{error:Q,threadId:A.id}),!1}}isBotCreatedDiscordThread(A,Q){if(A.isDM)return!1;let B=this.getThreadIdParts(A.id);if(!B.threadId)return!1;let w=this.getRawDiscordChannelId(Q);return w!==void 0&&w!==B.threadId}getRawDiscordChannelId(A){let Q=A.raw;if(typeof Q!=="object"||Q===null)return;let B=Q.channel_id;return typeof B==="string"?B:void 0}async handleRoutedMessage(A,Q,B){if(!this.context)return;let w=this.getPlatform(A);if(w!=="discord")return;let $=this.getPlatformConfig(A);if(!$)return;if(!this.shouldRouteDiscordMessage(A,Q,$))return;await this.routeToAgent(w,A,Q,B)}shouldRouteDiscordMessage(A,Q,B){if(A.isDM&&!B.allowDMs)return!1;if(Q.author.isMe)return!1;if(Q.author.isBot&&!Q.isMention)return!1;if(!this.isAllowedChannel(A,B))return!1;return!0}async routeToAgent(A,Q,B,w){if(!this.context)return;this.threadRegistry.set(Q);let $=this.getConversationId(A,Q.id),D=Q.id,f=this.getPermissionContext(Q,B),Y=this.context.permissions.getUserLevel(A,B.author.userId,f),X=await this.buildAgentInput(A,Q,B,Y),H=[...X.attachments];if(await this.attachPriorUploads($,X,Y),await this.postUploadNotices(Q,X.notices),!X.message&&X.attachments.length===0)return;this.rememberUploadAttachments($,H),this.startProcessingInput(D);try{if(this.getPlatformConfig(Q)?.showTypingIndicator)await Q.startTyping().catch((F)=>this.logger.debug("Typing indicator failed",{error:F,channelId:D}));let W=await this.getPendingApprovalIds($);if(W.size>0){await this.handleConfirmationResponse(X.message,$,Q,W,Y,this.buildUserMessageMetadata(A,Q,B));return}let Z=this.buildCoalescedAgentInput(X.message,w),G=await this.context.agent.chat(Z.message,$,{userPermissionLevel:Y,interfaceType:A,channelId:D,channelName:this.getChannelName(Q),...this.buildUserMessageMetadata(A,Q,B,Z.metadata),...X.attachments.length>0?{attachments:X.attachments}:{}});await this.renderAgentResponse({thread:Q,channelId:D,conversationId:$,response:G,userPermissionLevel:Y})}catch(W){this.logger.error("Error handling chat message",{error:W,channelId:D}),this.sendMessageToChannel({channelId:D,message:this.formatErrorPayload(W)})}finally{this.endProcessingInput()}}async renderAgentResponse(A){this.rememberPendingConfirmationsFromResponse(A.conversationId,A.response),await this.handleAgentResponseToolStatuses(A.response,A.conversationId);let Q=await this.resolveArtifactDelivery(A.response.cards,A.userPermissionLevel),B=await this.sendAgentResponseWithFiles({thread:A.thread,channelId:A.channelId,message:this.formatAgentResponseText(A.response.text,A.response.cards,A.response.pendingConfirmations,Q.deniedCardIds),files:Q.files}),w=await this.sendArtifactCards(A.thread,A.response.cards,Q.deniedCardIds);await this.sendSupplementalCards(A.thread,A.response.cards,A.response.pendingConfirmations),await this.sendPendingConfirmationCards(A.thread,A.conversationId,A.response.pendingConfirmations);let $=w??B;if($)for(let D of oe(A.response))this.trackAgentResponseForJob(D,$,A.channelId)}rememberPendingConfirmationsFromResponse(A,Q){this.pendingApprovals.rememberFromResponse(A,Q)}async getPendingApprovalIds(A){return this.pendingApprovals.getApprovalIds(A)}async handleConfirmationResponse(A,Q,B,w,$,D){let f=ge({message:A,approvalIds:w});if(f.kind==="not-confirmation"){this.pendingApprovals.deleteConversation(Q),await B.post(this.formatNoticePayload("No pending approval to resolve."));return}if(f.kind==="notice"){await B.post(this.formatNoticePayload(f.message));return}await this.confirmApproval({thread:B,conversationId:Q,approvalId:f.approvalId,confirmed:f.confirmed,userPermissionLevel:$,...D?{metadata:D}:{}})}async confirmApproval(A){let Q=await this.context?.agent.confirmPendingAction(A.conversationId,A.confirmed,A.approvalId,{userPermissionLevel:A.userPermissionLevel,interfaceType:"discord",channelId:A.thread.id,channelName:A.thread.isDM?"DM":A.thread.channelId,...A.metadata});if(this.removePendingApproval(A.conversationId,A.approvalId),!Q)return;this.syncPendingConfirmationsFromResponse(A.conversationId,Q,A.approvalId),await this.handleAgentResponseToolStatuses(Q,A.conversationId);let B=await this.resolveArtifactDelivery(Q.cards,A.userPermissionLevel);await this.resolveApprovalCard(A.conversationId,A.approvalId,A.confirmed),await this.sendAgentResponseWithFiles({thread:A.thread,channelId:A.thread.id,message:this.formatConfirmationResponsePayload(Q,A.confirmed,this.getRemainingApprovalHelp(A.conversationId,Q),B.deniedCardIds),files:B.files}),await this.sendArtifactCards(A.thread,Q.cards,B.deniedCardIds),await this.sendSupplementalCards(A.thread,Q.cards,Q.pendingConfirmations),await this.sendPendingConfirmationCards(A.thread,A.conversationId,Q.pendingConfirmations)}formatNoticePayload(A,Q="Approval notice"){return{card:{type:"card",title:Q,children:[{type:"text",content:A}]},fallbackText:A}}formatErrorPayload(A){let Q=A instanceof Error?A.message:"Unknown error";return{card:{type:"card",title:"Message failed",children:[{type:"text",content:Q}]},fallbackText:`Message failed: ${Q}`}}formatAgentResponseText(A,Q,B,w){return ie({text:A,cards:Q,pendingConfirmations:B,deniedCardIds:w,formatCard:($)=>this.formatStructuredCard($,w)}).join(`
|
|
2489
|
+
\`\`\``;return this.defaultNodeToText(A,(Q)=>this.nodeToDiscordMarkdown(Q))}},xV1={DeferredChannelMessageWithSource:5,DeferredUpdateMessage:6},X50="https://discord.com/api/v10",RV1=2000,ikQ=/^[0-9a-f]{64}$/,dkQ=/^[0-9a-f]+$/,nkQ=class A{name="discord";userName;botUserId;apiBaseUrl;botToken;publicKey;applicationId;mentionRoleIds;chat=null;logger;formatConverter=new pkQ;requestContext=new CkQ;threadParentCache=new Map;static THREAD_PARENT_CACHE_TTL=300000;constructor(Q={}){let B=Q.botToken??process.env.DISCORD_BOT_TOKEN;if(!B)throw new rH("discord","botToken is required. Set DISCORD_BOT_TOKEN or provide it in config.");let w=Q.publicKey??process.env.DISCORD_PUBLIC_KEY;if(!w)throw new rH("discord","publicKey is required. Set DISCORD_PUBLIC_KEY or provide it in config.");let $=Q.applicationId??process.env.DISCORD_APPLICATION_ID;if(!$)throw new rH("discord","applicationId is required. Set DISCORD_APPLICATION_ID or provide it in config.");if(this.apiBaseUrl=Q.apiUrl??process.env.DISCORD_API_URL??X50,this.botToken=B,this.publicKey=w.trim().toLowerCase(),this.applicationId=$,this.mentionRoleIds=Q.mentionRoleIds??(process.env.DISCORD_MENTION_ROLE_IDS?process.env.DISCORD_MENTION_ROLE_IDS.split(",").map((D)=>D.trim()):[]),this.botUserId=$,this.logger=Q.logger??new D50("info").child("discord"),this.userName=Q.userName??"bot",!ikQ.test(this.publicKey))this.logger.error("Invalid Discord public key format",{length:this.publicKey.length,isHex:dkQ.test(this.publicKey)})}async initialize(Q){this.chat=Q,this.logger.info("Discord adapter initialized")}async getUser(Q){try{let w=await(await this.discordFetch(`/users/${Q}`,"GET")).json();return{avatarUrl:w.avatar?`https://cdn.discordapp.com/avatars/${w.id}/${w.avatar}.png`:void 0,email:void 0,fullName:w.global_name||w.username,isBot:w.bot??!1,userId:w.id,userName:w.username}}catch{return null}}async handleWebhook(Q,B){let w=await Q.arrayBuffer(),$=new Uint8Array(w),D=new TextDecoder().decode($),f=Q.headers.get("x-discord-gateway-token");if(f){if(f!==this.botToken)return this.logger.warn("Invalid gateway token"),new Response("Invalid gateway token",{status:401});this.logger.info("Discord forwarded Gateway event received");try{let Z=JSON.parse(D);return this.handleForwardedGatewayEvent(Z,B)}catch{return new Response("Invalid JSON",{status:400})}}this.logger.info("Discord webhook received",{bodyLength:D.length,bodyBytesLength:$.length,hasSignature:!!Q.headers.get("x-signature-ed25519"),hasTimestamp:!!Q.headers.get("x-signature-timestamp")});let Y=Q.headers.get("x-signature-ed25519"),X=Q.headers.get("x-signature-timestamp");if(!await this.verifySignature($,Y,X))return this.logger.warn("Discord signature verification failed, returning 401"),new Response("Invalid signature",{status:401});this.logger.info("Discord signature verification passed");let W;try{W=JSON.parse(D)}catch{return new Response("Invalid JSON",{status:400})}if(this.logger.info("Discord interaction parsed",{type:W.type,typeIsPing:W.type===MC.Ping,expectedPingType:MC.Ping,id:W.id}),W.type===MC.Ping){let Z=JSON.stringify({type:di.InteractionResponseType.PONG});return this.logger.info("Discord PING received, responding with PONG",{responseBody:Z,responseType:di.InteractionResponseType.PONG}),new Response(Z,{status:200,headers:{"Content-Type":"application/json"}})}if(W.type===MC.MessageComponent)return this.handleComponentInteraction(W,B),this.respondToInteraction({type:xV1.DeferredUpdateMessage});if(W.type===MC.ApplicationCommand)return this.handleApplicationCommandInteraction(W,B),this.respondToInteraction({type:xV1.DeferredChannelMessageWithSource});return new Response("Unknown interaction type",{status:400})}async verifySignature(Q,B,w){if(!(B&&w))return this.logger.warn("Discord signature verification failed: missing headers",{hasSignature:!!B,hasTimestamp:!!w}),!1;try{this.logger.info("Discord signature verification attempt",{bodyBytesLength:Q.length,signatureLength:B.length,timestampLength:w.length,publicKeyLength:this.publicKey.length,timestamp:w,signaturePrefix:B.slice(0,16),publicKey:this.publicKey});let $=await di.verifyKey(Q,B,w,this.publicKey);if(!$){let D=new TextDecoder().decode(Q);this.logger.warn("Discord signature verification failed: invalid signature",{publicKeyLength:this.publicKey.length,signatureLength:B.length,publicKeyPrefix:this.publicKey.slice(0,8),publicKeySuffix:this.publicKey.slice(-8),timestamp:w,bodyLength:Q.length,bodyPrefix:D.slice(0,50)})}return $}catch($){return this.logger.warn("Discord signature verification failed: exception",{error:$}),!1}}respondToInteraction(Q){return Response.json(Q)}handleComponentInteraction(Q,B){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring interaction");return}let w=Q.data?.custom_id;if(!w){this.logger.warn("No custom_id in component interaction");return}let $=Q.member?.user||Q.user;if(!$){this.logger.warn("No user in component interaction");return}let D=Q.channel_id,f=Q.guild_id||"@me",Y=Q.message?.id;if(!(D&&Y)){this.logger.warn("Missing channel_id or message_id in interaction");return}let X=Q.channel,H=X?.type===11||X?.type===12,W=H&&X?.parent_id?X.parent_id:D,Z=H?this.encodeThreadId({guildId:f,channelId:W,threadId:D}):this.encodeThreadId({guildId:f,channelId:D}),G=EkQ(w),F={actionId:G.actionId,value:G.value??G.actionId,user:{userId:$.id,userName:$.username,fullName:$.global_name||$.username,isBot:$.bot??!1,isMe:!1},messageId:Y,threadId:Z,adapter:this,raw:Q};this.logger.debug("Processing Discord button action",{actionId:w,messageId:Y,threadId:Z}),this.chat.processAction(F,B)}handleApplicationCommandInteraction(Q,B){if(!this.chat){this.logger.warn("Chat instance not initialized, ignoring interaction");return}let w=Q.data?.name;if(!w){this.logger.warn("No command name in application command interaction");return}let $=Q.member?.user||Q.user;if(!$){this.logger.warn("No user in application command interaction");return}let D=Q.channel_id;if(!D){this.logger.warn("Missing channel_id in application command interaction");return}let f=Q.guild_id||"@me",Y=Q.channel,X=Y?.type===11||Y?.type===12,H=X&&Y?.parent_id?Y.parent_id:D,W=X?this.encodeThreadId({guildId:f,channelId:H,threadId:D}):this.encodeThreadId({guildId:f,channelId:D}),{command:Z,text:G}=this.parseSlashCommand(w,Q.data?.options);this.logger.debug("Processing Discord slash command",{command:Z,text:G,userId:$.id,channelId:W}),this.requestContext.run({slashCommand:{channelId:W,interactionToken:Q.token,initialResponseSent:!1}},()=>{this.chat?.processSlashCommand({command:Z,text:G,user:{userId:$.id,userName:$.username,fullName:$.global_name||$.username,isBot:$.bot??!1,isMe:$.id===this.applicationId},adapter:this,raw:Q,channelId:W},B)})}parseSlashCommand(Q,B){let w=[Q.startsWith("/")?Q:`/${Q}`],$=[],D=(f)=>{for(let Y of f){if(Y.value!==void 0){$.push(String(Y.value));continue}if(Y.options&&Y.options.length>0)w.push(Y.name),D(Y.options)}};if(B&&B.length>0)D(B);return{command:w.join(" "),text:$.join(" ").trim()}}async handleGatewayInteraction(Q){if(Q.isChatInputCommand()){await Q.deferReply(),this.handleApplicationCommandInteraction(this.normalizeGatewaySlashCommandInteraction(Q));return}if(Q.isMessageComponent())await Q.deferUpdate(),this.handleComponentInteraction(this.normalizeGatewayComponentInteraction(Q))}normalizeGatewaySlashCommandInteraction(Q){return{application_id:Q.applicationId,channel:this.normalizeGatewayChannel(Q),channel_id:Q.channelId??void 0,data:{name:Q.commandName,options:this.normalizeGatewayCommandOptions(Q.options.data),type:Q.commandType},guild_id:Q.guildId??void 0,id:Q.id,token:Q.token,type:Q.type,user:this.normalizeGatewayUser(Q.user),version:Q.version}}normalizeGatewayComponentInteraction(Q){let B="values"in Q&&Array.isArray(Q.values)?Q.values:void 0;return{application_id:Q.applicationId,channel:this.normalizeGatewayChannel(Q),channel_id:Q.channelId??void 0,data:{component_type:Q.componentType,custom_id:Q.customId,values:B},guild_id:Q.guildId??void 0,id:Q.id,message:{id:Q.message.id},token:Q.token,type:Q.type,user:this.normalizeGatewayUser(Q.user),version:Q.version}}normalizeGatewayChannel(Q){if(!Q.channel)return;let B="parentId"in Q.channel&&typeof Q.channel.parentId==="string"?Q.channel.parentId:void 0;return{id:Q.channel.id,parent_id:B,type:Q.channel.type}}normalizeGatewayCommandOptions(Q){return Q.map((B)=>({name:B.name,options:B.options?this.normalizeGatewayCommandOptions(B.options):void 0,type:B.type,value:B.value}))}normalizeGatewayUser(Q){return{avatar:Q.avatar??void 0,bot:Q.bot,discriminator:Q.discriminator,global_name:Q.globalName??void 0,id:Q.id,username:Q.username}}async handleForwardedGatewayEvent(Q,B){switch(this.logger.info("Processing forwarded Gateway event",{type:Q.type,timestamp:Q.timestamp}),Q.type){case"GATEWAY_MESSAGE_CREATE":await this.handleForwardedMessage(Q.data,B);break;case"GATEWAY_MESSAGE_REACTION_ADD":await this.handleForwardedReaction(Q.data,!0,B);break;case"GATEWAY_MESSAGE_REACTION_REMOVE":await this.handleForwardedReaction(Q.data,!1,B);break;default:this.logger.debug("Forwarded Gateway event (no handler)",{type:Q.type})}return new Response(JSON.stringify({ok:!0}),{status:200,headers:{"Content-Type":"application/json"}})}async handleForwardedMessage(Q,B){if(!this.chat)return;let w=Q.guild_id||"@me",$=Q.channel_id,D,f=$;if(Q.thread)D=Q.thread.id,f=Q.thread.parent_id;else if(Q.channel_type===11||Q.channel_type===12)try{let F=await(await this.discordFetch(`/channels/${$}`,"GET")).json();if(F.parent_id)D=$,f=F.parent_id,this.logger.debug("Fetched thread parent for forwarded message",{threadId:$,parentId:F.parent_id})}catch(G){this.logger.error("Failed to fetch thread parent",{error:String(G),channelId:$})}let Y=Q.is_mention||Q.mentions.some((G)=>G.id===this.applicationId),X=this.mentionRoleIds.length>0&&Q.mention_roles?.some((G)=>this.mentionRoleIds.includes(G)),H=Y||X;if(!D&&H)try{let G=await this.createDiscordThread($,Q.id);D=G.id,this.logger.debug("Created Discord thread for forwarded mention",{channelId:$,messageId:Q.id,threadId:G.id})}catch(G){this.logger.error("Failed to create Discord thread for mention",{error:String(G),messageId:Q.id})}let W=this.encodeThreadId({guildId:w,channelId:f,threadId:D}),Z=new x5({id:Q.id,threadId:W,text:Q.content,formatted:this.formatConverter.toAst(Q.content),author:{userId:Q.author.id,userName:Q.author.username,fullName:Q.author.global_name||Q.author.username,isBot:Q.author.bot===!0,isMe:Q.author.id===this.applicationId},metadata:{dateSent:new Date(Q.timestamp),edited:!1},attachments:Q.attachments.map((G)=>({type:this.getAttachmentType(G.content_type),url:G.url,name:G.filename,mimeType:G.content_type,size:G.size})),raw:Q,isMention:H});try{await this.chat.handleIncomingMessage(this,W,Z)}catch(G){this.logger.error("Error handling forwarded message",{error:String(G),messageId:Q.id})}}async handleForwardedReaction(Q,B,w){if(!this.chat)return;let $=Q.guild_id||"@me",D=Q.channel_id,f,Y=D;if(Q.channel_type===DM.GuildPublicThread||Q.channel_type===DM.GuildPrivateThread){let F=this.threadParentCache.get(D);if(F&&F.expiresAt>Date.now())f=D,Y=F.parentId;else try{let L=await(await this.discordFetch(`/channels/${D}`,"GET")).json();if(L.parent_id)f=D,Y=L.parent_id,this.threadParentCache.set(D,{parentId:L.parent_id,expiresAt:Date.now()+A.THREAD_PARENT_CACHE_TTL})}catch(I){this.logger.error("Failed to fetch thread parent for reaction",{error:String(I),channelId:D})}}let X=this.encodeThreadId({guildId:$,channelId:Y,threadId:f}),H=Q.emoji.name||"unknown",W=this.normalizeDiscordEmoji(H),Z=Q.user??Q.member?.user;if(!Z){this.logger.warn("Reaction event missing user info",{data:Q});return}let G={adapter:this,threadId:X,messageId:Q.message_id,emoji:W,rawEmoji:Q.emoji.id?`<:${H}:${Q.emoji.id}>`:H,added:B,user:{userId:Z.id,userName:Z.username,fullName:Z.username,isBot:Z.bot===!0,isMe:Z.id===this.applicationId},raw:Q};this.chat.processReaction(G)}async postMessage(Q,B){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=Q;if($)w=$;let f={},Y=[],X=[],H=Y50(B);if(H){let I=vE0(H);Y.push(...I.embeds),X.push(...I.components)}else f.content=this.truncateContent(QM(this.formatConverter.renderPostable(B),"discord"));if(Y.length>0)f.embeds=Y;if(X.length>0)f.components=X;let W=ZE0(B),Z=this.tryPostSlashResponse(D,f,W);if(Z)return Z;if(W.length>0)return this.postMessageWithFiles(w,D,f,W);this.logger.debug("Discord API: POST message",{channelId:w,contentLength:f.content?.length||0,embedCount:Y.length,componentCount:X.length});let F=await(await this.discordFetch(`/channels/${w}/messages`,"POST",f)).json();return this.logger.debug("Discord API: POST message response",{messageId:F.id}),{id:F.id,threadId:D,raw:F}}tryPostSlashResponse(Q,B,w){let $=this.requestContext.getStore()?.slashCommand;if(!$||$.channelId!==Q)return;return this.postSlashCommandResponse($,Q,B,w)}async postSlashCommandResponse(Q,B,w,$){let D=!Q.initialResponseSent;Q.initialResponseSent=!0;let f=D?`/webhooks/${this.applicationId}/${Q.interactionToken}/messages/@original`:`/webhooks/${this.applicationId}/${Q.interactionToken}?wait=true`,Y=D?"PATCH":"POST";this.logger.debug("Discord interaction webhook: responding to slash command",{threadId:B,isInitialResponse:D,hasFiles:$.length>0});let H=await($.length>0?await this.discordInteractionFetchWithFiles(f,Y,w,$):await this.discordInteractionFetch(f,Y,w)).json();return{id:H.id,threadId:B,raw:H}}async createDiscordThread(Q,B){let w=`Thread ${new Date().toLocaleString()}`;this.logger.debug("Discord API: POST thread",{channelId:Q,messageId:B,threadName:w});try{let D=await(await this.discordFetch(`/channels/${Q}/messages/${B}/threads`,"POST",{name:w,auto_archive_duration:1440})).json();return this.logger.debug("Discord API: POST thread response",{threadId:D.id,threadName:D.name}),D}catch($){if($ instanceof NC&&typeof $.message==="string"&&$.message.includes('"code"')&&$.message.includes("160004"))return this.logger.debug("Thread already exists for message, reusing existing thread",{channelId:Q,messageId:B}),{id:B,name:w};throw $}}truncateContent(Q){if(Q.length<=RV1)return Q;return`${Q.slice(0,RV1-3)}...`}async postMessageWithFiles(Q,B,w,$){let D=new FormData;D.append("payload_json",JSON.stringify(w));for(let X=0;X<$.length;X++){let H=$[X];if(!H)continue;let W=await KE0(H.data,{platform:"discord"});if(!W)continue;let Z=new Blob([new Uint8Array(W)],{type:H.mimeType||"application/octet-stream"});D.append(`files[${X}]`,Z,H.filename)}let f=await fetch(`${X50}/channels/${Q}/messages`,{method:"POST",headers:{Authorization:`Bot ${this.botToken}`},body:D});if(!f.ok){let X=await f.text();throw new NC("discord",`Failed to post message: ${f.status} ${X}`)}let Y=await f.json();return{id:Y.id,threadId:B,raw:Y}}async discordInteractionFetch(Q,B,w){let $=await fetch(`${X50}${Q}`,{method:B,headers:w?{"Content-Type":"application/json"}:void 0,body:w?JSON.stringify(w):void 0});if(!$.ok){let D=await $.text();throw this.logger.error("Discord interaction API error",{path:Q,method:B,status:$.status,error:D}),new NC("discord",`Discord interaction API error: ${$.status} ${D}`)}return $}async discordInteractionFetchWithFiles(Q,B,w,$){let D=new FormData;D.append("payload_json",JSON.stringify(w));for(let Y=0;Y<$.length;Y++){let X=$[Y];if(!X)continue;let H=await KE0(X.data,{platform:"discord"});if(!H)continue;let W=new Blob([new Uint8Array(H)],{type:X.mimeType||"application/octet-stream"});D.append(`files[${Y}]`,W,X.filename)}let f=await fetch(`${X50}${Q}`,{method:B,body:D});if(!f.ok){let Y=await f.text();throw this.logger.error("Discord interaction API error",{path:Q,method:B,status:f.status,error:Y}),new NC("discord",`Discord interaction API error: ${f.status} ${Y}`)}return f}async editMessage(Q,B,w){let{channelId:$,threadId:D}=this.decodeThreadId(Q),f=D||$,Y={},X=[],H=[],W=Y50(w);if(W){let F=vE0(W);X.push(...F.embeds),H.push(...F.components),Y.content=""}else Y.content=this.truncateContent(QM(this.formatConverter.renderPostable(w),"discord"));if(X.length>0)Y.embeds=X;if(H.length>0)Y.components=H;this.logger.debug("Discord API: PATCH message",{channelId:f,messageId:B,contentLength:Y.content?.length||0});let G=await(await this.discordFetch(`/channels/${f}/messages/${B}`,"PATCH",Y)).json();return this.logger.debug("Discord API: PATCH message response",{messageId:G.id}),{id:G.id,threadId:Q,raw:G}}async deleteMessage(Q,B){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=$||w;this.logger.debug("Discord API: DELETE message",{channelId:D,messageId:B}),await this.discordFetch(`/channels/${D}/messages/${B}`,"DELETE"),this.logger.debug("Discord API: DELETE message response",{ok:!0})}async addReaction(Q,B,w){let{channelId:$,threadId:D}=this.decodeThreadId(Q),f=D||$,Y=this.encodeEmoji(w);this.logger.debug("Discord API: PUT reaction",{channelId:f,messageId:B,emoji:Y}),await this.discordFetch(`/channels/${f}/messages/${B}/reactions/${Y}/@me`,"PUT"),this.logger.debug("Discord API: PUT reaction response",{ok:!0})}async removeReaction(Q,B,w){let{channelId:$,threadId:D}=this.decodeThreadId(Q),f=D||$,Y=this.encodeEmoji(w);this.logger.debug("Discord API: DELETE reaction",{channelId:f,messageId:B,emoji:Y}),await this.discordFetch(`/channels/${f}/messages/${B}/reactions/${Y}/@me`,"DELETE"),this.logger.debug("Discord API: DELETE reaction response",{ok:!0})}encodeEmoji(Q){let B=ui.toDiscord?ui.toDiscord(Q):String(Q);return encodeURIComponent(B)}async startTyping(Q,B){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=$||w;this.logger.debug("Discord API: POST typing",{channelId:D}),await this.discordFetch(`/channels/${D}/typing`,"POST")}async fetchMessages(Q,B={}){let{channelId:w,threadId:$}=this.decodeThreadId(Q),D=$||w,f=B.limit||50,Y=B.direction??"backward",X=new URLSearchParams;if(X.set("limit",String(f)),B.cursor)if(Y==="backward")X.set("before",B.cursor);else X.set("after",B.cursor);this.logger.debug("Discord API: GET messages",{channelId:D,limit:f,direction:Y,cursor:B.cursor});let W=await(await this.discordFetch(`/channels/${D}/messages?${X.toString()}`,"GET")).json();this.logger.debug("Discord API: GET messages response",{messageCount:W.length});let G=[...W].reverse().map((I)=>this.parseDiscordMessage(I,Q)),F;if(W.length===f)if(Y==="backward")F=W.at(-1)?.id;else F=W[0]?.id;return{messages:G,nextCursor:F}}async fetchThread(Q){let{channelId:B,guildId:w}=this.decodeThreadId(Q);this.logger.debug("Discord API: GET channel",{channelId:B});let D=await(await this.discordFetch(`/channels/${B}`,"GET")).json();return{id:Q,channelId:B,channelName:D.name,isDM:D.type===DM.DM||D.type===DM.GroupDM,metadata:{guildId:w,channelType:D.type,raw:D}}}async openDM(Q){this.logger.debug("Discord API: POST DM channel",{userId:Q});let w=await(await this.discordFetch("/users/@me/channels","POST",{recipient_id:Q})).json();return this.logger.debug("Discord API: POST DM channel response",{channelId:w.id}),this.encodeThreadId({guildId:"@me",channelId:w.id})}isDM(Q){let{guildId:B}=this.decodeThreadId(Q);return B==="@me"}encodeThreadId(Q){let B=Q.threadId?`:${Q.threadId}`:"";return`discord:${Q.guildId}:${Q.channelId}${B}`}decodeThreadId(Q){let B=Q.split(":");if(B.length<3||B[0]!=="discord")throw new rH("discord",`Invalid Discord thread ID: ${Q}`);return{guildId:B[1],channelId:B[2],threadId:B[3]}}parseMessage(Q){let B=Q,w=B.guild_id||"@me",$=this.encodeThreadId({guildId:w,channelId:B.channel_id});return this.parseDiscordMessage(B,$)}parseDiscordMessage(Q,B){let w=Q.type===kz1.ThreadStarterMessage&&Q.referenced_message?Q.referenced_message:Q,$=w.author,D=$.bot??!1,f=$.id===this.botUserId;return new x5({id:w.id,threadId:B,text:this.formatConverter.extractPlainText(w.content),formatted:this.formatConverter.toAst(w.content),raw:Q,author:{userId:$.id,userName:$.username,fullName:$.global_name||$.username,isBot:D,isMe:f},metadata:{dateSent:new Date(w.timestamp),edited:w.edited_timestamp!==null,editedAt:w.edited_timestamp?new Date(w.edited_timestamp):void 0},attachments:(w.attachments||[]).map((Y)=>({type:this.getAttachmentType(Y.content_type),url:Y.url,name:Y.filename,mimeType:Y.content_type,size:Y.size,width:Y.width??void 0,height:Y.height??void 0}))})}getAttachmentType(Q){if(!Q)return"file";if(Q.startsWith("image/"))return"image";if(Q.startsWith("video/"))return"video";if(Q.startsWith("audio/"))return"audio";return"file"}renderFormatted(Q){return this.formatConverter.fromAst(Q)}async discordFetch(Q,B,w){let $=`${this.apiBaseUrl}${Q}`,D={Authorization:`Bot ${this.botToken}`};if(w)D["Content-Type"]="application/json";let f=await fetch($,{method:B,headers:D,body:w?JSON.stringify(w):void 0});if(!f.ok){let Y=await f.text();throw this.logger.error("Discord API error",{path:Q,method:B,status:f.status,error:Y}),new NC("discord",`Discord API error: ${f.status} ${Y}`)}return f}async startGatewayListener(Q,B=180000,w,$){if(!this.chat)return new Response("Chat instance not initialized",{status:500});if(!Q.waitUntil)return new Response("waitUntil not provided",{status:500});this.logger.info("Starting Discord Gateway listener",{durationMs:B,webhookUrl:$?"configured":"not configured"});let D=this.runGatewayListener(B,w,$);return Q.waitUntil(D),new Response(JSON.stringify({status:"listening",durationMs:B,message:`Gateway listener started, will run for ${B/1000} seconds`}),{status:200,headers:{"Content-Type":"application/json"}})}async runGatewayListener(Q,B,w){let $=new T9.Client({intents:[T9.GatewayIntentBits.Guilds,T9.GatewayIntentBits.GuildMessages,T9.GatewayIntentBits.MessageContent,T9.GatewayIntentBits.DirectMessages,T9.GatewayIntentBits.GuildMessageReactions,T9.GatewayIntentBits.DirectMessageReactions],partials:[T9.Partials.Channel]}),D=!1;if(w)$.on("raw",async(f)=>{if(D)return;if(!f.t)return;this.logger.info("Discord Gateway forwarding event",{type:f.t}),await this.forwardGatewayEvent(w,{type:`GATEWAY_${f.t}`,timestamp:Date.now(),data:f.d})});else this.setupLegacyGatewayHandlers($,()=>D);$.on(T9.Events.ClientReady,()=>{this.logger.info("Discord Gateway connected",{username:$.user?.username,id:$.user?.id})}),$.on(T9.Events.Error,(f)=>{this.logger.error("Discord Gateway error",{error:String(f)})});try{await $.login(this.botToken),await new Promise((f)=>{let Y=setTimeout(f,Q);if(B){if(B.aborted){clearTimeout(Y),f();return}B.addEventListener("abort",()=>{this.logger.info("Discord Gateway listener received abort signal (new listener started)"),clearTimeout(Y),f()},{once:!0})}}),this.logger.info("Discord Gateway listener duration elapsed, disconnecting")}catch(f){this.logger.error("Discord Gateway listener error",{error:String(f)})}finally{D=!0,$.destroy(),this.logger.info("Discord Gateway listener stopped")}}setupLegacyGatewayHandlers(Q,B){Q.on(T9.Events.MessageCreate,async(w)=>{if(B()){this.logger.debug("Ignoring message - Gateway is shutting down");return}if(w.author.bot){this.logger.debug("Ignoring message from bot",{authorId:w.author.id,authorName:w.author.username,isMe:w.author.id===Q.user?.id});return}let $=w.mentions.has(Q.user?.id??""),D=this.mentionRoleIds.length>0&&w.mentions.roles.some((Y)=>this.mentionRoleIds.includes(Y.id)),f=$||D;this.logger.info("Discord Gateway message received",{channelId:w.channelId,guildId:w.guildId,authorId:w.author.id,isMentioned:f,isUserMentioned:$,isRoleMentioned:D,content:w.content.slice(0,100)}),await this.handleGatewayMessage(w,f)}),Q.on(T9.Events.InteractionCreate,async(w)=>{if(B()){this.logger.debug("Ignoring interaction - Gateway is shutting down");return}this.logger.info("Discord Gateway interaction received",{id:w.id,type:w.type});try{await this.handleGatewayInteraction(w)}catch($){this.logger.error("Error handling Gateway interaction",{error:String($),interactionId:w.id})}}),Q.on(T9.Events.MessageReactionAdd,async(w,$)=>{if(B()){this.logger.debug("Ignoring reaction - Gateway is shutting down");return}if($.bot){this.logger.debug("Ignoring reaction from bot",{userId:$.id,isMe:$.id===Q.user?.id});return}if(this.logger.info("Discord Gateway reaction added",{emoji:w.emoji.name,messageId:w.message.id,channelId:w.message.channelId,userId:$.id}),$.username)await this.handleGatewayReaction(w,$,!0)}),Q.on(T9.Events.MessageReactionRemove,async(w,$)=>{if(B()){this.logger.debug("Ignoring reaction removal - Gateway is shutting down");return}if($.bot){this.logger.debug("Ignoring reaction removal from bot",{userId:$.id,isMe:$.id===Q.user?.id});return}if(this.logger.info("Discord Gateway reaction removed",{emoji:w.emoji.name,messageId:w.message.id,channelId:w.message.channelId,userId:$.id}),$.username)await this.handleGatewayReaction(w,$,!1)})}async forwardGatewayEvent(Q,B){try{this.logger.debug("Forwarding Gateway event to webhook",{type:B.type,webhookUrl:Q});let w=await fetch(Q,{method:"POST",headers:{"Content-Type":"application/json","x-discord-gateway-token":this.botToken},body:JSON.stringify(B)});if(w.ok)this.logger.debug("Gateway event forwarded successfully",{type:B.type});else{let $=await w.text();this.logger.error("Failed to forward Gateway event",{type:B.type,status:w.status,error:$})}}catch(w){this.logger.error("Error forwarding Gateway event",{type:B.type,error:String(w)})}}async handleGatewayMessage(Q,B){if(!this.chat)return;let w=Q.guildId||"@me",$=Q.channelId,D=Q.channel.isThread(),f,Y=$;if(D&&"parentId"in Q.channel&&Q.channel.parentId)f=$,Y=Q.channel.parentId;if(!f&&B)try{let W=await this.createDiscordThread($,Q.id);f=W.id,this.logger.debug("Created Discord thread for incoming mention",{channelId:$,messageId:Q.id,threadId:W.id})}catch(W){this.logger.error("Failed to create Discord thread for mention",{error:String(W),messageId:Q.id})}let X=this.encodeThreadId({guildId:w,channelId:Y,threadId:f}),H=new x5({id:Q.id,threadId:X,text:Q.content,formatted:this.formatConverter.toAst(Q.content),author:{userId:Q.author.id,userName:Q.author.username,fullName:Q.author.displayName||Q.author.username,isBot:Q.author.bot,isMe:!1},metadata:{dateSent:Q.createdAt,edited:Q.editedAt!==null,editedAt:Q.editedAt??void 0},attachments:Q.attachments.map((W)=>({type:this.getAttachmentType(W.contentType),url:W.url,name:W.name,mimeType:W.contentType??void 0,size:W.size})),raw:{id:Q.id,channel_id:$,guild_id:w,content:Q.content,author:{id:Q.author.id,username:Q.author.username},timestamp:Q.createdAt.toISOString()},isMention:B});try{await this.chat.handleIncomingMessage(this,X,H)}catch(W){this.logger.error("Error handling Gateway message",{error:String(W),messageId:Q.id})}}async handleGatewayReaction(Q,B,w){if(!this.chat)return;let $=Q.message.guildId||"@me",D=Q.message.channelId,f=Q.message.channel?.isThread?.(),Y=D,X;if(f&&Q.message.channel?.parentId)X=D,Y=Q.message.channel.parentId;let H=this.encodeThreadId({guildId:$,channelId:Y,threadId:X}),W=Q.emoji.name||"unknown",Z=this.normalizeDiscordEmoji(W),G={adapter:this,threadId:H,messageId:Q.message.id,emoji:Z,rawEmoji:Q.emoji.id?`<:${W}:${Q.emoji.id}>`:W,added:w,user:{userId:B.id,userName:B.username,fullName:B.username,isBot:B.bot===!0,isMe:B.id===this.applicationId},raw:{emoji:Q.emoji,message_id:Q.message.id,channel_id:Q.message.channelId,guild_id:Q.message.guildId,user_id:B.id}};this.chat.processReaction(G)}channelIdFromThreadId(Q){return Q.split(":").slice(0,3).join(":")}async fetchChannelMessages(Q,B={}){let $=Q.split(":")[2];if(!$)throw new rH("discord",`Invalid Discord channel ID: ${Q}`);let D=B.limit||50,f=B.direction??"backward",Y=new URLSearchParams;if(Y.set("limit",String(D)),B.cursor)if(f==="backward")Y.set("before",B.cursor);else Y.set("after",B.cursor);this.logger.debug("Discord API: GET channel messages",{channelId:$,limit:D,direction:f,cursor:B.cursor});let H=await(await this.discordFetch(`/channels/${$}/messages?${Y.toString()}`,"GET")).json();this.logger.debug("Discord API: GET channel messages response",{messageCount:H.length});let Z=[...H].reverse().map((F)=>this.parseDiscordMessage(F,Q)),G;if(H.length===D)if(f==="backward")G=H.at(-1)?.id;else G=H[0]?.id;return{messages:Z,nextCursor:G}}async listThreads(Q,B={}){let w=Q.split(":"),$=w[1],D=w[2];if(!($&&D))throw new rH("discord",`Invalid Discord channel ID: ${Q}`);this.logger.debug("Discord API: GET threads",{guildId:$,channelId:D});let X=((await(await this.discordFetch(`/guilds/${$}/threads/active`,"GET")).json()).threads||[]).filter((b)=>b.parent_id===D),H=[];try{H=(await(await this.discordFetch(`/channels/${D}/threads/archived/public?limit=${B.limit||50}`,"GET")).json()).threads||[]}catch{this.logger.debug("Could not fetch archived threads (may lack permissions)")}let W=[...X,...H],Z=new Set,G=W.filter((b)=>{if(Z.has(b.id))return!1;return Z.add(b.id),!0}),F=B.limit||50,I=G.slice(0,F),L=[];for(let b of I){let N=this.encodeThreadId({guildId:$,channelId:D,threadId:b.id});try{let g=(await(await this.discordFetch(`/channels/${b.id}/messages?limit=1&after=0`,"GET")).json())[0];if(g)L.push({id:N,rootMessage:this.parseDiscordMessage(g,N),replyCount:b.total_message_sent??b.message_count,lastReplyAt:b.thread_metadata?.archive_timestamp?new Date(b.thread_metadata.archive_timestamp):void 0})}catch{L.push({id:N,rootMessage:new x5({id:b.id,threadId:N,text:b.name,formatted:this.formatConverter.toAst(b.name),raw:b,author:{userId:"unknown",userName:"unknown",fullName:"unknown",isBot:!1,isMe:!1},metadata:{dateSent:new Date,edited:!1},attachments:[]}),replyCount:b.total_message_sent??b.message_count})}}return this.logger.debug("Discord API: listThreads result",{threadCount:L.length}),{threads:L,nextCursor:G.length>F?String(F):void 0}}async fetchChannelInfo(Q){let w=Q.split(":")[2];if(!w)throw new rH("discord",`Invalid Discord channel ID: ${Q}`);this.logger.debug("Discord API: GET channel info",{channelId:w});let D=await(await this.discordFetch(`/channels/${w}`,"GET")).json();return{id:Q,name:D.name,isDM:D.type===DM.DM||D.type===DM.GroupDM,memberCount:D.member_count,metadata:{channelType:D.type,raw:D}}}async postChannelMessage(Q,B){let $=Q.split(":")[2];if(!$)throw new rH("discord",`Invalid Discord channel ID: ${Q}`);let D={},f=[],Y=[],X=Y50(B);if(X){let F=vE0(X);f.push(...F.embeds),Y.push(...F.components)}else D.content=this.truncateContent(QM(this.formatConverter.renderPostable(B),"discord"));if(f.length>0)D.embeds=f;if(Y.length>0)D.components=Y;let H=ZE0(B),W=this.tryPostSlashResponse(Q,D,H);if(W)return W;if(H.length>0)return this.postMessageWithFiles($,Q,D,H);this.logger.debug("Discord API: POST channel message",{channelId:$,contentLength:D.content?.length||0});let G=await(await this.discordFetch(`/channels/${$}/messages`,"POST",D)).json();return{id:G.id,threadId:Q,raw:G}}normalizeDiscordEmoji(Q){let w={"\uD83D\uDC4D":"thumbs_up","\uD83D\uDC4E":"thumbs_down","\u2764\uFE0F":"heart","\u2764":"heart","\uD83D\uDD25":"fire","\uD83D\uDE80":"rocket","\uD83D\uDE4C":"raised_hands","\u2705":"check","\u274C":"x","\uD83D\uDC4B":"wave","\uD83E\uDD14":"thinking","\uD83D\uDE0A":"smile","\uD83D\uDE02":"laugh","\uD83C\uDF89":"party","\u2B50":"star","\u2728":"sparkles","\uD83D\uDC40":"eyes","\uD83D\uDCAF":"100"}[Q]||Q;return SJ(w)}};function CV1(A){return new nkQ(A??{})}var rkQ=class{subscriptions=new Set;locks=new Map;cache=new Map;queues=new Map;connected=!1;connectPromise=null;async connect(){if(this.connected)return;if(!this.connectPromise)this.connectPromise=Promise.resolve().then(()=>{this.connected=!0});await this.connectPromise}async disconnect(){this.connected=!1,this.connectPromise=null,this.subscriptions.clear(),this.locks.clear(),this.queues.clear()}async subscribe(A){this.ensureConnected(),this.subscriptions.add(A)}async unsubscribe(A){this.ensureConnected(),this.subscriptions.delete(A)}async isSubscribed(A){return this.ensureConnected(),this.subscriptions.has(A)}async acquireLock(A,Q){this.ensureConnected(),this.cleanExpiredLocks();let B=this.locks.get(A);if(B&&B.expiresAt>Date.now())return null;let w={threadId:A,token:okQ(),expiresAt:Date.now()+Q};return this.locks.set(A,w),w}async forceReleaseLock(A){this.ensureConnected(),this.locks.delete(A)}async releaseLock(A){this.ensureConnected();let Q=this.locks.get(A.threadId);if(Q&&Q.token===A.token)this.locks.delete(A.threadId)}async extendLock(A,Q){this.ensureConnected();let B=this.locks.get(A.threadId);if(!B||B.token!==A.token)return!1;if(B.expiresAt<Date.now())return this.locks.delete(A.threadId),!1;return B.expiresAt=Date.now()+Q,!0}async get(A){this.ensureConnected();let Q=this.cache.get(A);if(!Q)return null;if(Q.expiresAt!==null&&Q.expiresAt<=Date.now())return this.cache.delete(A),null;return Q.value}async set(A,Q,B){this.ensureConnected(),this.cache.set(A,{value:Q,expiresAt:B?Date.now()+B:null})}async setIfNotExists(A,Q,B){this.ensureConnected();let w=this.cache.get(A);if(w)if(w.expiresAt!==null&&w.expiresAt<=Date.now())this.cache.delete(A);else return!1;return this.cache.set(A,{value:Q,expiresAt:B?Date.now()+B:null}),!0}async delete(A){this.ensureConnected(),this.cache.delete(A)}async appendToList(A,Q,B){this.ensureConnected();let w=this.cache.get(A),$;if(w&&w.expiresAt!==null&&w.expiresAt<=Date.now())$=[];else if(w&&Array.isArray(w.value))$=w.value;else $=[];if($.push(Q),B?.maxLength&&$.length>B.maxLength)$=$.slice($.length-B.maxLength);this.cache.set(A,{value:$,expiresAt:B?.ttlMs?Date.now()+B.ttlMs:null})}async enqueue(A,Q,B){this.ensureConnected();let w=this.queues.get(A);if(!w)w=[],this.queues.set(A,w);if(w.push(Q),w.length>B)w.splice(0,w.length-B);return w.length}async dequeue(A){this.ensureConnected();let Q=this.queues.get(A);if(!Q||Q.length===0)return null;let B=Q.shift();if(Q.length===0)this.queues.delete(A);return B??null}async queueDepth(A){return this.ensureConnected(),this.queues.get(A)?.length??0}async getList(A){this.ensureConnected();let Q=this.cache.get(A);if(!Q)return[];if(Q.expiresAt!==null&&Q.expiresAt<=Date.now())return this.cache.delete(A),[];if(Array.isArray(Q.value))return Q.value;return[]}ensureConnected(){if(!this.connected)throw Error("MemoryStateAdapter is not connected. Call connect() first.")}cleanExpiredLocks(){let A=Date.now();for(let[Q,B]of this.locks)if(B.expiresAt<=A)this.locks.delete(Q)}_getSubscriptionCount(){return this.subscriptions.size}_getLockCount(){return this.cleanExpiredLocks(),this.locks.size}};function okQ(){return`mem_${Date.now()}_${Math.random().toString(36).substring(2,15)}`}function H50(A){return new rkQ}K0();p0();K0();var skQ=K.object({botToken:K.string().min(1).describe("Discord bot token"),publicKey:K.string().min(1).describe("Discord application public key"),applicationId:K.string().min(1).describe("Discord application ID"),mentionRoleIds:K.array(K.string()).default([]),allowedChannels:K.array(K.string()).default([]),requireMention:K.boolean().default(!0),allowDMs:K.boolean().default(!0),showTypingIndicator:K.boolean().default(!0),useThreads:K.boolean().default(!0),...bN.shape,captureUrlEmoji:K.string().default("\uD83D\uDD16")}),hE0=K.object({userName:K.string().default("brain"),adapters:K.object({discord:skQ.optional()}).default({}),gatewayRunMs:K.number().int().positive().default(540000),gatewayRestartDelayMs:K.number().int().nonnegative().default(1000)});class W50{ttlMs;threads=new Map;sentMessages=new Map;constructor(A=3600000){this.ttlMs=A}set(A){this.cleanup(),this.threads.set(A.id,{thread:A,expiresAt:Date.now()+this.ttlMs})}get(A){if(!A)return;let Q=this.threads.get(A);if(!Q)return;if(Q.expiresAt<=Date.now()){this.threads.delete(A);return}return Q.expiresAt=Date.now()+this.ttlMs,Q.thread}trackMessage(A,Q){this.sentMessages.set(this.messageKey(A,Q.id),Q)}getMessage(A,Q){if(!A)return;return this.sentMessages.get(this.messageKey(A,Q))}clear(){this.threads.clear(),this.sentMessages.clear()}cleanup(){let A=Date.now();for(let[Q,B]of this.threads)if(B.expiresAt<=A)this.threads.delete(Q)}messageKey(A,Q){return`${A}:${Q}`}}K0();var akQ=K.object({subscribedAt:K.string().datetime(),routingMode:K.enum(["auto","mention-required"]).optional(),mentionRequiredNoticeSent:K.boolean().optional()}),tkQ="chat.discord.subscriptions";function CE0(A){return A.scoped({namespace:tkQ,schema:akQ})}function yV1(A,Q=H50()){let B=CE0(A);return new EV1(Q,B)}class EV1{memoryState;subscriptions;constructor(A,Q){this.memoryState=A;this.subscriptions=Q}connect(){return this.memoryState.connect()}disconnect(){return this.memoryState.disconnect()}async subscribe(A){await this.subscriptions.set(A,{subscribedAt:new Date().toISOString()})}async unsubscribe(A){await this.subscriptions.delete(A)}isSubscribed(A){return this.subscriptions.has(A)}acquireLock(A,Q){return this.memoryState.acquireLock(A,Q)}appendToList(A,Q,B){return this.memoryState.appendToList(A,Q,B)}delete(A){return this.memoryState.delete(A)}dequeue(A){return this.memoryState.dequeue(A)}enqueue(A,Q,B){return this.memoryState.enqueue(A,Q,B)}extendLock(A,Q){return this.memoryState.extendLock(A,Q)}forceReleaseLock(A){return this.memoryState.forceReleaseLock(A)}get(A){return this.memoryState.get(A)}getList(A){return this.memoryState.getList(A)}queueDepth(A){return this.memoryState.queueDepth(A)}releaseLock(A){return this.memoryState.releaseLock(A)}set(A,Q,B){return this.memoryState.set(A,Q,B)}setIfNotExists(A,Q,B){return this.memoryState.setIfNotExists(A,Q,B)}}function ni(){return{namespace:"discord-chat",refKind:"discord-chat-upload",routePath:"/api/webhooks/chat/discord/uploads"}}var yE0=["discord"];var gV1={name:"@brains/chat",private:!0,version:"0.2.0-alpha.129",description:"Discord Chat SDK 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:*","@chat-adapter/discord":"^4.29.0","@chat-adapter/state-memory":"^4.29.0",chat:"^4.29.0"},devDependencies:{"@brains/core":"workspace:*","@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest"}};var AOQ=/https?:\/\/\S+/i,QOQ=/[\s\S]+/,BOQ={discord:2000},wOQ="https://discord.com/api/v10",$OQ=8388608,DOQ=5,fOQ=5,TV1=DOQ*fOQ,SV1=80,EE0="approval.confirm",mV1="approval.cancel",uV1="chat.prompt",YOQ="chat.event.unavailable",XOQ="I\u2019ll stop auto-replying now that more people joined. Mention me if you need me.",HOQ=K.object({type:K.literal("card"),children:K.array(K.object({type:K.string()}).passthrough()),imageUrl:K.string().optional(),subtitle:K.string().optional(),title:K.string().optional()}).passthrough(),WOQ=K.object({card:K.custom((A)=>HOQ.safeParse(A).success),fallbackText:K.string().optional()});class Z50 extends eW{app;threadRegistry=new W50;pendingApprovals;uploadContinuity;approvalCardMessages=new Map;promptActions=new Map;toolStatusMessages=new Map;discordGatewayAdapter;discordSubscriptions;gatewayAbortController;gatewayLoopPromise;constructor(A={}){super("chat",gV1,A,hE0);this.pendingApprovals=new NS({loadMessages:async(Q)=>{return await this.context?.conversations.getMessages(Q,{limit:50})??[]},onRestoreError:(Q,B)=>{this.logger.debug("Failed to load pending chat approvals",{error:Q,conversationId:B})}}),this.uploadContinuity=new xS({sourceKind:"discord-chat-upload",loadMessages:async(Q)=>{return await this.context?.conversations.getMessages(Q,{limit:50})??[]},restoreAttachment:async(Q)=>{let B=this.context?.uploads.scoped(ni());if(!B)throw Error("Chat upload store unavailable");let w=await B.read(Q);return this.createChatAttachmentFromStoredUpload(w.record.filename,w.record.mediaType,w.content,w.record.ref)},onLoadError:(Q,B)=>{this.logger.debug("Failed to load prior chat uploads",{error:Q,conversationId:B})},onRestoreError:(Q,B)=>{this.logger.debug("Failed to restore prior chat upload",{error:Q,uploadId:B})}})}async onRegister(A){await super.onRegister(A),this.discordSubscriptions=CE0(A.runtimeState),this.app=this.createChatApp(A),this.registerChatHandlers(this.app)}getWebRoutes(){return[{path:"/api/webhooks/chat/discord",method:"POST",public:!0,handler:async(A)=>{if(!this.app?.webhooks?.discord)return new Response("Discord chat webhook not configured",{status:404});return this.app.webhooks.discord(A)}},{path:"/api/webhooks/chat/discord/uploads",method:"GET",public:!0,handler:async(A)=>{return this.handleDiscordUploadRequest(A)}}]}async handleDiscordUploadRequest(A){if(!this.config.adapters.discord)return new Response("Discord chat uploads not configured",{status:404});let Q=new URL(A.url).searchParams.get("id")?.trim();if(!Q)return new Response("Missing upload id",{status:400});try{let B=this.getDiscordUploadStore(),{record:w,content:$}=await B.read(Q),D=new Uint8Array($).buffer;return new Response(D,{headers:{"Content-Type":w.mediaType,"Content-Length":String($.byteLength),"Cache-Control":"private, no-store","X-Content-Type-Options":"nosniff","Content-Disposition":lI({disposition:new URL(A.url).searchParams.has("download")?"attachment":"inline",filename:w.filename})}})}catch{return new Response("Upload not found",{status:404})}}getDiscordUploadStore(){if(!this.context)throw Error("Chat interface not registered");return this.context.uploads.scoped(ni())}createDaemon(){if(!this.config.adapters.discord)return;return{start:async()=>{await this.startGatewayLoop()},stop:async()=>{await this.stopGatewayLoop()},healthCheck:async()=>({status:this.gatewayLoopPromise?"healthy":"error",message:this.gatewayLoopPromise?"Chat gateway loop running":"Chat gateway loop stopped",lastCheck:new Date})}}sendMessageToChannel({channelId:A,message:Q}){let B=this.threadRegistry.get(A);if(!B)return;let w=this.toDiscordCardOutput(Q);if(w){B.post(w).catch(($)=>this.logger.error("Failed to send chat message",{error:$,channelId:A}));return}if(typeof Q!=="string")return;for(let $ of this.chunkForChannel(A,Q))B.post($).catch((D)=>this.logger.error("Failed to send chat message",{error:D,channelId:A}))}async sendMessageWithId({channelId:A,message:Q}){let B=this.threadRegistry.get(A);if(!B)return;let w=this.toDiscordCardOutput(Q);if(w){let D=await B.post(w);return this.threadRegistry.trackMessage(B.id,D),D.id}if(typeof Q!=="string")return;let $;for(let D of this.chunkForChannel(A,Q))$=await B.post(D),this.threadRegistry.trackMessage(B.id,$);return $?.id}async editMessage({channelId:A,messageId:Q,newMessage:B}){let w=this.threadRegistry.getMessage(A,Q);if(!w)return!1;try{let $=await w.edit(this.toDiscordCardOutput(B)??(typeof B==="string"?B:""));if(A)this.threadRegistry.trackMessage(A,$);return!0}catch{return!1}}supportsMessageEditing(){return!0}toDiscordCardOutput(A){let Q=WOQ.safeParse(A);if(!Q.success)return;let{card:B,fallbackText:w}=Q.data;if(w===void 0)return{card:B};return{card:B,fallbackText:w}}formatProgressOutput(A){return this.formatProgressPayload(A)}formatCompletionOutput(A){return this.formatProgressPayload(A)}formatProgressPayload(A){let Q=tO(A),B=[{type:"text",content:Q.label}];if(Q.amount)B.push({type:"text",content:Q.amount});if(Q.message)B.push({type:"text",content:Q.message});return{card:{type:"card",title:Q.title,children:B},fallbackText:Q.fallback}}async handleProgressEvent(A,Q){let B=A.metadata.interfaceType;if(B&&B!==this.id){if(!this.isEnabledPlatform(B))return;let w={...A,metadata:{...A.metadata,interfaceType:this.id}};await super.handleProgressEvent(w,w.metadata);return}await super.handleProgressEvent(A,Q)}async handleToolActivityEvent(A){if(A.interfaceType===this.id){await super.handleToolActivityEvent(A);return}if(!this.isEnabledPlatform(A.interfaceType))return;await super.handleToolActivityEvent({...A,interfaceType:this.id})}async handleToolStatusUpdate(A){if(A.interfaceType!==this.id||!A.channelId)return;let Q=IS(A);if(A.state==="running"){await this.sendToolStatusMessage(Q,A);return}await this.updateToolStatusMessage(Q,A)}async sendToolStatusMessage(A,Q){let B=Q.channelId;if(!B)return;let w=this.threadRegistry.get(B);if(!w)return;let $=await w.post(this.formatToolStatusPayload(Q));this.threadRegistry.trackMessage(B,$),this.toolStatusMessages.set(A,{channelId:B,message:$})}async updateToolStatusMessage(A,Q){let B=this.formatToolStatusPayload(Q),w=this.toolStatusMessages.get(A);if(w){let Y=await w.message.edit(B);this.threadRegistry.trackMessage(w.channelId,Y),this.toolStatusMessages.delete(A);return}let $=Q.channelId;if(!$)return;let D=this.threadRegistry.get($);if(!D)return;let f=await D.post(B);this.threadRegistry.trackMessage($,f)}formatToolStatusPayload(A){let Q=aO(A),B=[{type:"text",content:Q.label}];if(A.error)B.push({type:"text",content:A.error});return{card:{type:"card",title:Q.title,children:B},fallbackText:Q.fallback}}isEnabledPlatform(A){return A==="discord"&&Boolean(this.config.adapters.discord)}chunkForChannel(A,Q){let B=this.parseChatPlatform(A),w=B?BOQ[B]:void 0;return w?ob(Q,w):[Q]}parseChatPlatform(A){let Q=A?.split(":")[0];return yE0.find((B)=>B===Q)}createChatApp(A){let Q=this.config.adapters.discord;if(!Q)return new HE0({userName:this.config.userName,adapters:{},state:H50()});let B=CV1({botToken:Q.botToken,publicKey:Q.publicKey,applicationId:Q.applicationId,mentionRoleIds:Q.mentionRoleIds});return this.discordGatewayAdapter=B,new HE0({userName:this.config.userName,adapters:{discord:B},concurrency:{strategy:"queue",maxQueueSize:5,onQueueFull:"drop-oldest"},state:yV1(A.runtimeState)})}registerChatHandlers(A){if(A.onDirectMessage(async(Q,B,w,$)=>{await this.handleRoutedMessage(Q,B,$)}),A.onNewMention(async(Q,B,w)=>{let $=this.getPlatformConfig(Q);if($&&this.shouldRouteDiscordMessage(Q,B,$)&&!Q.isDM&&$.useThreads)await this.subscribeOwnedDiscordThread(Q,B);await this.handleRoutedMessage(Q,B,w)}),A.onSubscribedMessage(async(Q,B,w)=>{if(!await this.shouldRouteSubscribedMessage(Q,B))return;await this.handleRoutedMessage(Q,B,w)}),this.config.adapters.discord&&!this.config.adapters.discord.requireMention)A.onNewMessage(QOQ,async(Q,B,w)=>{await this.handleRoutedMessage(Q,B,w)});A.onNewMessage(AOQ,async(Q,B)=>{await this.handlePassiveUrlCapture(Q,B)}),A.onAction([EE0,mV1],async(Q)=>{await this.handleApprovalAction(Q)}),A.onAction(uV1,async(Q)=>{await this.handlePromptAction(Q)})}async handlePromptAction(A){if(!this.context||!A.thread||!A.value)return;let Q=A.adapter.name;if(!this.isEnabledPlatform(Q))return;let B=A.thread;if(!this.shouldHandleDiscordAction(B,Q))return;let w=this.promptActions.get(A.value);if(w?.threadId!==B.id){await B.post(this.formatNoticePayload("That suggested action is no longer available.","Action unavailable"));return}let $=this.getThreadIdParts(B.id),D=this.context.permissions.getUserLevel(Q,A.user.userId,{channelId:$.channelId??B.channelId,isBot:Boolean(A.user.isBot)}),f=this.getConversationId(Q,B.id),Y=B.id;this.startProcessingInput(Y);try{if(this.getPlatformConfig(B)?.showTypingIndicator)await B.startTyping().catch((H)=>this.logger.debug("Typing indicator failed",{error:H,channelId:Y}));let X=await this.context.agent.chat(w.prompt,f,{userPermissionLevel:D,interfaceType:Q,channelId:Y,channelName:B.isDM?"DM":B.channelId,...this.buildActionEventMetadata(Q,B,A)});await this.renderAgentResponse({thread:B,channelId:Y,conversationId:f,response:X,userPermissionLevel:D})}catch(X){this.logger.error("Error handling chat prompt action",{error:X,channelId:Y}),await B.post(this.toDiscordCardOutput(this.formatErrorPayload(X))??"Message failed.")}finally{this.endProcessingInput()}}async handleApprovalAction(A){if(!this.context||!A.thread||!A.value)return;let Q=A.adapter.name;if(!this.isEnabledPlatform(Q))return;let B=this.getConversationId(Q,A.thread.id);if(!(await this.getPendingApprovalIds(B)).has(A.value)){await A.thread.post(this.formatNoticePayload("That approval is no longer pending."));return}let $=A.thread;if(!this.shouldHandleDiscordAction($,Q))return;let D=this.getThreadIdParts($.id),f=this.context.permissions.getUserLevel(Q,A.user.userId,{channelId:D.channelId??$.channelId,isBot:Boolean(A.user.isBot)});await this.confirmApproval({thread:$,conversationId:B,approvalId:A.value,confirmed:A.actionId===EE0,userPermissionLevel:f,metadata:this.buildActionEventMetadata(Q,$,A)})}shouldHandleDiscordAction(A,Q){if(Q!=="discord")return!0;let B=this.config.adapters.discord;if(!B)return!1;if(A.isDM&&!B.allowDMs)return!1;return this.isAllowedChannel(A,B)}async subscribeOwnedDiscordThread(A,Q){if(!this.isBotCreatedDiscordThread(A,Q))return;try{await A.subscribe(),await this.discordSubscriptions?.set(A.id,{subscribedAt:new Date().toISOString()})}catch(B){this.logger.debug("Discord thread subscription failed",{error:B,threadId:A.id})}}async shouldRouteSubscribedMessage(A,Q){if(this.getPlatform(A)!=="discord")return!1;if(A.isDM)return!0;let B=await this.discordSubscriptions?.get(A.id);if(!B)return!1;if(B.routingMode==="mention-required"){if(!Q.isMention&&!B.mentionRequiredNoticeSent)await this.postMentionRequiredNotice(A,B);return Boolean(Q.isMention)}if(!await this.shouldRequireMentionInSubscribedThread(A))return!0;let $={...B,routingMode:"mention-required"};if(!Q.isMention&&!B.mentionRequiredNoticeSent)await this.postMentionRequiredNotice(A,$);else await this.discordSubscriptions?.set(A.id,$);return Boolean(Q.isMention)}async postMentionRequiredNotice(A,Q){await A.post(XOQ),await this.discordSubscriptions?.set(A.id,{...Q,routingMode:"mention-required",mentionRequiredNoticeSent:!0})}async shouldRequireMentionInSubscribedThread(A){try{return(await A.getParticipants()).filter((w)=>!w.isBot&&!w.isMe).length>1}catch(Q){return this.logger.debug("Failed to inspect Discord thread participants",{error:Q,threadId:A.id}),!1}}isBotCreatedDiscordThread(A,Q){if(A.isDM)return!1;let B=this.getThreadIdParts(A.id);if(!B.threadId)return!1;let w=this.getRawDiscordChannelId(Q);return w!==void 0&&w!==B.threadId}getRawDiscordChannelId(A){let Q=A.raw;if(typeof Q!=="object"||Q===null)return;let B=Q.channel_id;return typeof B==="string"?B:void 0}async handleRoutedMessage(A,Q,B){if(!this.context)return;let w=this.getPlatform(A);if(w!=="discord")return;let $=this.getPlatformConfig(A);if(!$)return;if(!this.shouldRouteDiscordMessage(A,Q,$))return;await this.routeToAgent(w,A,Q,B)}shouldRouteDiscordMessage(A,Q,B){if(A.isDM&&!B.allowDMs)return!1;if(Q.author.isMe)return!1;if(Q.author.isBot&&!Q.isMention)return!1;if(!this.isAllowedChannel(A,B))return!1;return!0}async routeToAgent(A,Q,B,w){if(!this.context)return;this.threadRegistry.set(Q);let $=this.getConversationId(A,Q.id),D=Q.id,f=this.getPermissionContext(Q,B),Y=this.context.permissions.getUserLevel(A,B.author.userId,f),X=await this.buildAgentInput(A,Q,B,Y),H=[...X.attachments];if(await this.attachPriorUploads($,X,Y),await this.postUploadNotices(Q,X.notices),!X.message&&X.attachments.length===0)return;this.rememberUploadAttachments($,H),this.startProcessingInput(D);try{if(this.getPlatformConfig(Q)?.showTypingIndicator)await Q.startTyping().catch((F)=>this.logger.debug("Typing indicator failed",{error:F,channelId:D}));let W=await this.getPendingApprovalIds($);if(W.size>0){await this.handleConfirmationResponse(X.message,$,Q,W,Y,this.buildUserMessageMetadata(A,Q,B));return}let Z=this.buildCoalescedAgentInput(X.message,w),G=await this.context.agent.chat(Z.message,$,{userPermissionLevel:Y,interfaceType:A,channelId:D,channelName:this.getChannelName(Q),...this.buildUserMessageMetadata(A,Q,B,Z.metadata),...X.attachments.length>0?{attachments:X.attachments}:{}});await this.renderAgentResponse({thread:Q,channelId:D,conversationId:$,response:G,userPermissionLevel:Y})}catch(W){this.logger.error("Error handling chat message",{error:W,channelId:D}),this.sendMessageToChannel({channelId:D,message:this.formatErrorPayload(W)})}finally{this.endProcessingInput()}}async renderAgentResponse(A){this.rememberPendingConfirmationsFromResponse(A.conversationId,A.response),await this.handleAgentResponseToolStatuses(A.response,A.conversationId);let Q=await this.resolveArtifactDelivery(A.response.cards,A.userPermissionLevel),B=await this.sendAgentResponseWithFiles({thread:A.thread,channelId:A.channelId,message:this.formatAgentResponseText(A.response.text,A.response.cards,A.response.pendingConfirmations,Q.deniedCardIds),files:Q.files}),w=await this.sendArtifactCards(A.thread,A.response.cards,Q.deniedCardIds);await this.sendSupplementalCards(A.thread,A.response.cards,A.response.pendingConfirmations),await this.sendPendingConfirmationCards(A.thread,A.conversationId,A.response.pendingConfirmations);let $=w??B;if($)for(let D of oe(A.response))this.trackAgentResponseForJob(D,$,A.channelId)}rememberPendingConfirmationsFromResponse(A,Q){this.pendingApprovals.rememberFromResponse(A,Q)}async getPendingApprovalIds(A){return this.pendingApprovals.getApprovalIds(A)}async handleConfirmationResponse(A,Q,B,w,$,D){let f=ge({message:A,approvalIds:w});if(f.kind==="not-confirmation"){this.pendingApprovals.deleteConversation(Q),await B.post(this.formatNoticePayload("No pending approval to resolve."));return}if(f.kind==="notice"){await B.post(this.formatNoticePayload(f.message));return}await this.confirmApproval({thread:B,conversationId:Q,approvalId:f.approvalId,confirmed:f.confirmed,userPermissionLevel:$,...D?{metadata:D}:{}})}async confirmApproval(A){let Q=await this.context?.agent.confirmPendingAction(A.conversationId,A.confirmed,A.approvalId,{userPermissionLevel:A.userPermissionLevel,interfaceType:"discord",channelId:A.thread.id,channelName:A.thread.isDM?"DM":A.thread.channelId,...A.metadata});if(this.removePendingApproval(A.conversationId,A.approvalId),!Q)return;this.syncPendingConfirmationsFromResponse(A.conversationId,Q,A.approvalId),await this.handleAgentResponseToolStatuses(Q,A.conversationId);let B=await this.resolveArtifactDelivery(Q.cards,A.userPermissionLevel);await this.resolveApprovalCard(A.conversationId,A.approvalId,A.confirmed),await this.sendAgentResponseWithFiles({thread:A.thread,channelId:A.thread.id,message:this.formatConfirmationResponsePayload(Q,A.confirmed,this.getRemainingApprovalHelp(A.conversationId,Q),B.deniedCardIds),files:B.files}),await this.sendArtifactCards(A.thread,Q.cards,B.deniedCardIds),await this.sendSupplementalCards(A.thread,Q.cards,Q.pendingConfirmations),await this.sendPendingConfirmationCards(A.thread,A.conversationId,Q.pendingConfirmations)}formatNoticePayload(A,Q="Approval notice"){return{card:{type:"card",title:Q,children:[{type:"text",content:A}]},fallbackText:A}}formatErrorPayload(A){let Q=A instanceof Error?A.message:"Unknown error";return{card:{type:"card",title:"Message failed",children:[{type:"text",content:Q}]},fallbackText:`Message failed: ${Q}`}}formatAgentResponseText(A,Q,B,w){return ie({text:A,cards:Q,pendingConfirmations:B,deniedCardIds:w,formatCard:($)=>this.formatStructuredCard($,w)}).join(`
|
|
2490
2490
|
|
|
2491
2491
|
`)}formatConfirmationResponsePayload(A,Q,B,w){let $=de({response:A,confirmed:Q,remainingApprovalHelp:B,deniedCardIds:w,formatCard:(D)=>this.formatStructuredCard(D,w),formatPendingConfirmationHelp:_S});return{card:{type:"card",title:pe($.variant),children:$.parts.map((D)=>({type:"text",content:D}))},fallbackText:$.parts.join(`
|
|
2492
2492
|
|
|
@@ -2559,7 +2559,7 @@ ${oy0(A)}
|
|
|
2559
2559
|
<p>Once built, this page will be replaced with your actual website.</p>
|
|
2560
2560
|
</div>
|
|
2561
2561
|
</body>
|
|
2562
|
-
</html>`;var JJ1={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.
|
|
2562
|
+
</html>`;var JJ1={name:"@brains/webserver",private:!0,version:"0.2.0-alpha.129",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/messaging-service":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};class mJ extends GU{serverManager;siteUrl;previewUrl;constructor(A={}){super("webserver",JJ1,A,aE0)}async onRegister(A){if(this.siteUrl=A.siteUrl,this.previewUrl=A.previewUrl,this.siteUrl)A.endpoints.register({label:"Site",url:this.siteUrl,priority:10}),A.interactions.register({id:"site",label:"Public site",description:"Visit the published public site for this brain.",href:this.siteUrl,kind:"human",priority:10});if(this.config.enablePreview&&this.previewUrl)A.endpoints.register({label:"Preview",url:this.previewUrl,priority:20,visibility:"anchor"}),A.interactions.register({id:"preview",label:"Preview site",description:"Open the private preview build.",href:this.previewUrl,kind:"admin",priority:20,visibility:"anchor"});this.serverManager=new N50({logger:A.logger,productionDistDir:this.config.productionDistDir,sharedImagesDir:this.config.sharedImagesDir,productionPort:this.config.productionPort,...this.config.enablePreview&&this.config.previewDistDir&&{previewDistDir:this.config.previewDistDir},...this.config.enablePreview&&this.config.previewPort&&{previewPort:this.config.previewPort},getHealthData:()=>A.appInfo(),getWebRoutes:()=>A.webRoutes.getRoutes(),getApiRoutes:()=>A.apiRoutes.getRoutes(),messageBus:A.apiRoutes.getMessageBus()})}getServerManager(){if(!this.serverManager)throw Error("ServerManager not initialized \u2014 onRegister not called");return this.serverManager}requiresDaemonStartup(){return!0}createDaemon(){return{start:async()=>{await this.ensureDistDirectories(),await this.getServerManager().start()},stop:async()=>{await this.serverManager?.stop()},healthCheck:async()=>{let A=this.serverManager?.getStatus(),Q=A?.running??!1,B=this.siteUrl??A?.productionUrl??`http://localhost:${this.config.productionPort}`,w=this.previewUrl??A?.previewUrl??`http://localhost:${this.config.previewPort}`,$=[];if(Q){if($.push(`Production: ${B}`),A?.previewUrl)$.push(`Preview: ${w}`)}return{status:Q?"healthy":"error",message:Q?$.join(", "):"Webserver not running",lastCheck:new Date,details:{preview:!!A?.previewUrl,production:Q,previewUrl:A?.previewUrl?w:void 0,productionUrl:Q?B:void 0}}}}}async handleProgressEvent(A,Q){}async ensureDistDirectories(){let{mkdir:A,writeFile:Q}=await import("fs/promises");if(this.config.enablePreview&&this.config.previewDistDir&&!LJ1(this.config.previewDistDir))await A(this.config.previewDistDir,{recursive:!0}),await Q(bJ1(this.config.previewDistDir,"index.html"),tE0),this.logger.debug(`Created preview directory at ${this.config.previewDistDir}`);if(!LJ1(this.config.productionDistDir))await A(this.config.productionDistDir,{recursive:!0}),await Q(bJ1(this.config.productionDistDir,"index.html"),tE0),this.logger.debug(`Created production directory at ${this.config.productionDistDir}`)}}Cw();p0();K0();var aJ1="vercel.ai.error",eOQ=Symbol.for(aJ1),NJ1,jJ1,mB=class A extends(jJ1=Error,NJ1=eOQ,jJ1){constructor({name:Q,message:B,cause:w}){super(B);this[NJ1]=!0,this.name=Q,this.cause=w}static isInstance(Q){return A.hasMarker(Q,aJ1)}static hasMarker(Q,B){let w=Symbol.for(B);return Q!=null&&typeof Q==="object"&&w in Q&&typeof Q[w]==="boolean"&&Q[w]===!0}},tJ1="AI_APICallError",eJ1=`vercel.ai.error.${tJ1}`,AxQ=Symbol.for(eJ1),_J1,MJ1,mU8=class extends(MJ1=mB,_J1=AxQ,MJ1){constructor({message:A,url:Q,requestBodyValues:B,statusCode:w,responseHeaders:$,responseBody:D,cause:f,isRetryable:Y=w!=null&&(w===408||w===409||w===429||w>=500),data:X}){super({name:tJ1,message:A,cause:f});this[_J1]=!0,this.url=Q,this.requestBodyValues=B,this.statusCode=w,this.responseHeaders=$,this.responseBody=D,this.isRetryable=Y,this.data=X}static isInstance(A){return mB.hasMarker(A,eJ1)}},AL1="AI_EmptyResponseBodyError",QL1=`vercel.ai.error.${AL1}`,QxQ=Symbol.for(QL1),PJ1,kJ1,uU8=class extends(kJ1=mB,PJ1=QxQ,kJ1){constructor({message:A="Empty response body"}={}){super({name:AL1,message:A});this[PJ1]=!0}static isInstance(A){return mB.hasMarker(A,QL1)}};function BL1(A){if(A==null)return"unknown error";if(typeof A==="string")return A;if(A instanceof Error)return A.message;return JSON.stringify(A)}var wL1="AI_InvalidArgumentError",$L1=`vercel.ai.error.${wL1}`,BxQ=Symbol.for($L1),OJ1,xJ1,DL1=class extends(xJ1=mB,OJ1=BxQ,xJ1){constructor({message:A,cause:Q,argument:B}){super({name:wL1,message:A,cause:Q});this[OJ1]=!0,this.argument=B}static isInstance(A){return mB.hasMarker(A,$L1)}},fL1="AI_InvalidPromptError",YL1=`vercel.ai.error.${fL1}`,wxQ=Symbol.for(YL1),RJ1,vJ1,cU8=class extends(vJ1=mB,RJ1=wxQ,vJ1){constructor({prompt:A,message:Q,cause:B}){super({name:fL1,message:`Invalid prompt: ${Q}`,cause:B});this[RJ1]=!0,this.prompt=A}static isInstance(A){return mB.hasMarker(A,YL1)}},XL1="AI_InvalidResponseDataError",HL1=`vercel.ai.error.${XL1}`,$xQ=Symbol.for(HL1),hJ1,CJ1,lU8=class extends(CJ1=mB,hJ1=$xQ,CJ1){constructor({data:A,message:Q=`Invalid response data: ${JSON.stringify(A)}.`}){super({name:XL1,message:Q});this[hJ1]=!0,this.data=A}static isInstance(A){return mB.hasMarker(A,HL1)}},WL1="AI_JSONParseError",ZL1=`vercel.ai.error.${WL1}`,DxQ=Symbol.for(ZL1),yJ1,EJ1,eE0=class extends(EJ1=mB,yJ1=DxQ,EJ1){constructor({text:A,cause:Q}){super({name:WL1,message:`JSON parsing failed: Text: ${A}.
|
|
2563
2563
|
Error message: ${BL1(Q)}`,cause:Q});this[yJ1]=!0,this.text=A}static isInstance(A){return mB.hasMarker(A,ZL1)}},KL1="AI_LoadAPIKeyError",UL1=`vercel.ai.error.${KL1}`,fxQ=Symbol.for(UL1),gJ1,TJ1,pU8=class extends(TJ1=mB,gJ1=fxQ,TJ1){constructor({message:A}){super({name:KL1,message:A});this[gJ1]=!0}static isInstance(A){return mB.hasMarker(A,UL1)}},GL1="AI_LoadSettingError",zL1=`vercel.ai.error.${GL1}`,YxQ=Symbol.for(zL1),SJ1,mJ1,iU8=class extends(mJ1=mB,SJ1=YxQ,mJ1){constructor({message:A}){super({name:GL1,message:A});this[SJ1]=!0}static isInstance(A){return mB.hasMarker(A,zL1)}},qL1="AI_NoContentGeneratedError",FL1=`vercel.ai.error.${qL1}`,XxQ=Symbol.for(FL1),uJ1,cJ1,dU8=class extends(cJ1=mB,uJ1=XxQ,cJ1){constructor({message:A="No content generated."}={}){super({name:qL1,message:A});this[uJ1]=!0}static isInstance(A){return mB.hasMarker(A,FL1)}},IL1="AI_NoSuchModelError",VL1=`vercel.ai.error.${IL1}`,HxQ=Symbol.for(VL1),lJ1,pJ1,nU8=class extends(pJ1=mB,lJ1=HxQ,pJ1){constructor({errorName:A=IL1,modelId:Q,modelType:B,message:w=`No such ${B}: ${Q}`}){super({name:A,message:w});this[lJ1]=!0,this.modelId=Q,this.modelType=B}static isInstance(A){return mB.hasMarker(A,VL1)}},JL1="AI_TooManyEmbeddingValuesForCallError",LL1=`vercel.ai.error.${JL1}`,WxQ=Symbol.for(LL1),iJ1,dJ1,rU8=class extends(dJ1=mB,iJ1=WxQ,dJ1){constructor(A){super({name:JL1,message:`Too many values for a single embedding call. The ${A.provider} model "${A.modelId}" can only embed up to ${A.maxEmbeddingsPerCall} values per call, but ${A.values.length} values were provided.`});this[iJ1]=!0,this.provider=A.provider,this.modelId=A.modelId,this.maxEmbeddingsPerCall=A.maxEmbeddingsPerCall,this.values=A.values}static isInstance(A){return mB.hasMarker(A,LL1)}},bL1="AI_TypeValidationError",NL1=`vercel.ai.error.${bL1}`,ZxQ=Symbol.for(NL1),nJ1,rJ1,IG=class A extends(rJ1=mB,nJ1=ZxQ,rJ1){constructor({value:Q,cause:B,context:w}){let $="Type validation failed";if(w==null?void 0:w.field)$+=` for ${w.field}`;if((w==null?void 0:w.entityName)||(w==null?void 0:w.entityId)){$+=" (";let D=[];if(w.entityName)D.push(w.entityName);if(w.entityId)D.push(`id: "${w.entityId}"`);$+=D.join(", "),$+=")"}super({name:bL1,message:`${$}: Value: ${JSON.stringify(Q)}.
|
|
2564
2564
|
Error message: ${BL1(B)}`,cause:B});this[nJ1]=!0,this.value=Q,this.context=w}static isInstance(Q){return mB.hasMarker(Q,NL1)}static wrap({value:Q,cause:B,context:w}){var $,D,f;if(A.isInstance(B)&&B.value===Q&&(($=B.context)==null?void 0:$.field)===(w==null?void 0:w.field)&&((D=B.context)==null?void 0:D.entityName)===(w==null?void 0:w.entityName)&&((f=B.context)==null?void 0:f.entityId)===(w==null?void 0:w.entityId))return B;return new A({value:Q,cause:B,context:w})}},jL1="AI_UnsupportedFunctionalityError",_L1=`vercel.ai.error.${jL1}`,KxQ=Symbol.for(_L1),oJ1,sJ1,oU8=class extends(sJ1=mB,oJ1=KxQ,sJ1){constructor({functionality:A,message:Q=`'${A}' functionality not supported.`}){super({name:jL1,message:Q});this[oJ1]=!0,this.functionality=A}static isInstance(A){return mB.hasMarker(A,_L1)}};F1();JU();JU();JU();var RL1="AI_DownloadError",vL1=`vercel.ai.error.${RL1}`,UxQ=Symbol.for(vL1),ML1,PL1,oH=class extends(PL1=mB,ML1=UxQ,PL1){constructor({url:A,statusCode:Q,statusText:B,cause:w,message:$=w==null?`Failed to download ${A}: ${Q} ${B}`:`Failed to download ${A}: ${w}`}){super({name:RL1,message:$,cause:w});this[ML1]=!0,this.url=A,this.statusCode=Q,this.statusText=B}static isInstance(A){return mB.hasMarker(A,vL1)}},Dg0=2147483648;async function hL1({response:A,url:Q,maxBytes:B=Dg0}){let w=A.headers.get("content-length");if(w!=null){let W=parseInt(w,10);if(!isNaN(W)&&W>B)throw new oH({url:Q,message:`Download of ${Q} exceeded maximum size of ${B} bytes (Content-Length: ${W}).`})}let $=A.body;if($==null)return new Uint8Array(0);let D=$.getReader(),f=[],Y=0;try{while(!0){let{done:W,value:Z}=await D.read();if(W)break;if(Y+=Z.length,Y>B)throw new oH({url:Q,message:`Download of ${Q} exceeded maximum size of ${B} bytes.`});f.push(Z)}}finally{try{await D.cancel()}finally{D.releaseLock()}}let X=new Uint8Array(Y),H=0;for(let W of f)X.set(W,H),H+=W.length;return X}function fg0(A){let Q;try{Q=new URL(A)}catch(w){throw new oH({url:A,message:`Invalid URL: ${A}`})}if(Q.protocol==="data:")return;if(Q.protocol!=="http:"&&Q.protocol!=="https:")throw new oH({url:A,message:`URL scheme must be http, https, or data, got ${Q.protocol}`});let B=Q.hostname;if(!B)throw new oH({url:A,message:"URL must have a hostname"});if(B==="localhost"||B.endsWith(".local")||B.endsWith(".localhost"))throw new oH({url:A,message:`URL with hostname ${B} is not allowed`});if(B.startsWith("[")&&B.endsWith("]")){let w=B.slice(1,-1);if(GxQ(w))throw new oH({url:A,message:`URL with IPv6 address ${B} is not allowed`});return}if(CL1(B)){if(Bg0(B))throw new oH({url:A,message:`URL with IP address ${B} is not allowed`});return}}function CL1(A){let Q=A.split(".");if(Q.length!==4)return!1;return Q.every((B)=>{let w=Number(B);return Number.isInteger(w)&&w>=0&&w<=255&&String(w)===B})}function Bg0(A){let Q=A.split(".").map(Number),[B,w]=Q;if(B===0)return!0;if(B===10)return!0;if(B===127)return!0;if(B===169&&w===254)return!0;if(B===172&&w>=16&&w<=31)return!0;if(B===192&&w===168)return!0;return!1}function GxQ(A){let Q=A.toLowerCase();if(Q==="::1")return!0;if(Q==="::")return!0;if(Q.startsWith("::ffff:")){let B=Q.slice(7);if(CL1(B))return Bg0(B);let w=B.split(":");if(w.length===2){let $=parseInt(w[0],16),D=parseInt(w[1],16);if(!isNaN($)&&!isNaN(D)){let f=$>>8&255,Y=$&255,X=D>>8&255,H=D&255;return Bg0(`${f}.${Y}.${X}.${H}`)}}}if(Q.startsWith("fc")||Q.startsWith("fd"))return!0;if(Q.startsWith("fe80"))return!0;return!1}var k3=({prefix:A,size:Q=16,alphabet:B="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",separator:w="-"}={})=>{let $=()=>{let D=B.length,f=Array(Q);for(let Y=0;Y<Q;Y++)f[Y]=B[Math.random()*D|0];return f.join("")};if(A==null)return $;if(B.includes(w))throw new DL1({argument:"separator",message:`The separator "${w}" must not be part of the alphabet "${B}".`});return()=>`${A}${w}${$()}`},yL1=k3();function Yg0(A){if(A==null)return"unknown error";if(typeof A==="string")return A;if(A instanceof Error)return A.message;return JSON.stringify(A)}function EL1(A=globalThis){var Q,B,w;if(A.window)return"runtime/browser";if((Q=A.navigator)==null?void 0:Q.userAgent)return`runtime/${A.navigator.userAgent.toLowerCase()}`;if((w=(B=A.process)==null?void 0:B.versions)==null?void 0:w.node)return`runtime/node.js/${A.process.version.substring(0)}`;if(A.EdgeRuntime)return"runtime/vercel-edge";return"runtime/unknown"}function zxQ(A){if(A==null)return{};let Q={};if(A instanceof Headers)A.forEach((B,w)=>{Q[w.toLowerCase()]=B});else{if(!Array.isArray(A))A=Object.entries(A);for(let[B,w]of A)if(w!=null)Q[B.toLowerCase()]=w}return Q}function j50(A,...Q){let B=new Headers(zxQ(A)),w=B.get("user-agent")||"";return B.set("user-agent",[w,...Q].filter(Boolean).join(" ")),Object.fromEntries(B.entries())}var qxQ=/"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/,FxQ=/"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;function kL1(A){let Q=JSON.parse(A);if(Q===null||typeof Q!=="object")return Q;if(qxQ.test(A)===!1&&FxQ.test(A)===!1)return Q;return IxQ(Q)}function IxQ(A){let Q=[A];while(Q.length){let B=Q;Q=[];for(let w of B){if(Object.prototype.hasOwnProperty.call(w,"__proto__"))throw SyntaxError("Object contains forbidden prototype property");if(Object.prototype.hasOwnProperty.call(w,"constructor")&&w.constructor!==null&&typeof w.constructor==="object"&&Object.prototype.hasOwnProperty.call(w.constructor,"prototype"))throw SyntaxError("Object contains forbidden prototype property");for(let $ in w){let D=w[$];if(D&&typeof D==="object")Q.push(D)}}}return A}function VxQ(A){let{stackTraceLimit:Q}=Error;try{Error.stackTraceLimit=0}catch(B){return kL1(A)}try{return kL1(A)}finally{Error.stackTraceLimit=Q}}function Xg0(A){if(A.type==="object"||Array.isArray(A.type)&&A.type.includes("object")){A.additionalProperties=!1;let{properties:B}=A;if(B!=null)for(let w of Object.keys(B))B[w]=WM(B[w])}if(A.items!=null)A.items=Array.isArray(A.items)?A.items.map(WM):WM(A.items);if(A.anyOf!=null)A.anyOf=A.anyOf.map(WM);if(A.allOf!=null)A.allOf=A.allOf.map(WM);if(A.oneOf!=null)A.oneOf=A.oneOf.map(WM);let{definitions:Q}=A;if(Q!=null)for(let B of Object.keys(Q))Q[B]=WM(Q[B]);return A}function WM(A){if(typeof A==="boolean")return A;return Xg0(A)}var JxQ=Symbol("Let zodToJsonSchema decide on which parser to use"),OL1={name:void 0,$refStrategy:"root",basePath:["#"],effectStrategy:"input",pipeStrategy:"all",dateStrategy:"format:date-time",mapStrategy:"entries",removeAdditionalStrategy:"passthrough",allowedAdditionalProperties:!0,rejectedAdditionalProperties:!1,definitionPath:"definitions",strictUnions:!1,definitions:{},errorMessages:!1,patternStrategy:"escape",applyRegexFlags:!1,emailStrategy:"format:email",base64Strategy:"contentEncoding:base64",nameStrategy:"ref"},LxQ=(A)=>typeof A==="string"?{...OL1,name:A}:{...OL1,...A};function HX(){return{}}function bxQ(A,Q){var B,w,$;let D={type:"array"};if(((B=A.type)==null?void 0:B._def)&&(($=(w=A.type)==null?void 0:w._def)==null?void 0:$.typeName)!==KA.ZodAny)D.items=lw(A.type._def,{...Q,currentPath:[...Q.currentPath,"items"]});if(A.minLength)D.minItems=A.minLength.value;if(A.maxLength)D.maxItems=A.maxLength.value;if(A.exactLength)D.minItems=A.exactLength.value,D.maxItems=A.exactLength.value;return D}function NxQ(A){let Q={type:"integer",format:"int64"};if(!A.checks)return Q;for(let B of A.checks)switch(B.kind){case"min":if(B.inclusive)Q.minimum=B.value;else Q.exclusiveMinimum=B.value;break;case"max":if(B.inclusive)Q.maximum=B.value;else Q.exclusiveMaximum=B.value;break;case"multipleOf":Q.multipleOf=B.value;break}return Q}function jxQ(){return{type:"boolean"}}function gL1(A,Q){return lw(A.type._def,Q)}var _xQ=(A,Q)=>{return lw(A.innerType._def,Q)};function TL1(A,Q,B){let w=B!=null?B:Q.dateStrategy;if(Array.isArray(w))return{anyOf:w.map(($,D)=>TL1(A,Q,$))};switch(w){case"string":case"format:date-time":return{type:"string",format:"date-time"};case"format:date":return{type:"string",format:"date"};case"integer":return MxQ(A)}}var MxQ=(A)=>{let Q={type:"integer",format:"unix-time"};for(let B of A.checks)switch(B.kind){case"min":Q.minimum=B.value;break;case"max":Q.maximum=B.value;break}return Q};function PxQ(A,Q){return{...lw(A.innerType._def,Q),default:A.defaultValue()}}function kxQ(A,Q){return Q.effectStrategy==="input"?lw(A.schema._def,Q):HX()}function OxQ(A){return{type:"string",enum:Array.from(A.values)}}var xxQ=(A)=>{if("type"in A&&A.type==="string")return!1;return"allOf"in A};function RxQ(A,Q){let B=[lw(A.left._def,{...Q,currentPath:[...Q.currentPath,"allOf","0"]}),lw(A.right._def,{...Q,currentPath:[...Q.currentPath,"allOf","1"]})].filter(($)=>!!$),w=[];return B.forEach(($)=>{if(xxQ($))w.push(...$.allOf);else{let D=$;if("additionalProperties"in $&&$.additionalProperties===!1){let{additionalProperties:f,...Y}=$;D=Y}w.push(D)}}),w.length?{allOf:w}:void 0}function vxQ(A){let Q=typeof A.value;if(Q!=="bigint"&&Q!=="number"&&Q!=="boolean"&&Q!=="string")return{type:Array.isArray(A.value)?"array":"object"};return{type:Q==="bigint"?"integer":Q,const:A.value}}var Ag0=void 0,sZ={cuid:/^[cC][^\s-]{8,}$/,cuid2:/^[0-9a-z]+$/,ulid:/^[0-9A-HJKMNP-TV-Z]{26}$/,email:/^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,emoji:()=>{if(Ag0===void 0)Ag0=RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$","u");return Ag0},uuid:/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,ipv4:/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,ipv4Cidr:/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,ipv6:/^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,ipv6Cidr:/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,base64:/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,base64url:/^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,nanoid:/^[a-zA-Z0-9_-]{21}$/,jwt:/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/};function SL1(A,Q){let B={type:"string"};if(A.checks)for(let w of A.checks)switch(w.kind){case"min":B.minLength=typeof B.minLength==="number"?Math.max(B.minLength,w.value):w.value;break;case"max":B.maxLength=typeof B.maxLength==="number"?Math.min(B.maxLength,w.value):w.value;break;case"email":switch(Q.emailStrategy){case"format:email":aZ(B,"email",w.message,Q);break;case"format:idn-email":aZ(B,"idn-email",w.message,Q);break;case"pattern:zod":jD(B,sZ.email,w.message,Q);break}break;case"url":aZ(B,"uri",w.message,Q);break;case"uuid":aZ(B,"uuid",w.message,Q);break;case"regex":jD(B,w.regex,w.message,Q);break;case"cuid":jD(B,sZ.cuid,w.message,Q);break;case"cuid2":jD(B,sZ.cuid2,w.message,Q);break;case"startsWith":jD(B,RegExp(`^${Qg0(w.value,Q)}`),w.message,Q);break;case"endsWith":jD(B,RegExp(`${Qg0(w.value,Q)}$`),w.message,Q);break;case"datetime":aZ(B,"date-time",w.message,Q);break;case"date":aZ(B,"date",w.message,Q);break;case"time":aZ(B,"time",w.message,Q);break;case"duration":aZ(B,"duration",w.message,Q);break;case"length":B.minLength=typeof B.minLength==="number"?Math.max(B.minLength,w.value):w.value,B.maxLength=typeof B.maxLength==="number"?Math.min(B.maxLength,w.value):w.value;break;case"includes":{jD(B,RegExp(Qg0(w.value,Q)),w.message,Q);break}case"ip":{if(w.version!=="v6")aZ(B,"ipv4",w.message,Q);if(w.version!=="v4")aZ(B,"ipv6",w.message,Q);break}case"base64url":jD(B,sZ.base64url,w.message,Q);break;case"jwt":jD(B,sZ.jwt,w.message,Q);break;case"cidr":{if(w.version!=="v6")jD(B,sZ.ipv4Cidr,w.message,Q);if(w.version!=="v4")jD(B,sZ.ipv6Cidr,w.message,Q);break}case"emoji":jD(B,sZ.emoji(),w.message,Q);break;case"ulid":{jD(B,sZ.ulid,w.message,Q);break}case"base64":{switch(Q.base64Strategy){case"format:binary":{aZ(B,"binary",w.message,Q);break}case"contentEncoding:base64":{B.contentEncoding="base64";break}case"pattern:zod":{jD(B,sZ.base64,w.message,Q);break}}break}case"nanoid":jD(B,sZ.nanoid,w.message,Q);case"toLowerCase":case"toUpperCase":case"trim":break;default:}return B}function Qg0(A,Q){return Q.patternStrategy==="escape"?CxQ(A):A}var hxQ=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");function CxQ(A){let Q="";for(let B=0;B<A.length;B++){if(!hxQ.has(A[B]))Q+="\\";Q+=A[B]}return Q}function aZ(A,Q,B,w){var $;if(A.format||(($=A.anyOf)==null?void 0:$.some((D)=>D.format))){if(!A.anyOf)A.anyOf=[];if(A.format)A.anyOf.push({format:A.format}),delete A.format;A.anyOf.push({format:Q,...B&&w.errorMessages&&{errorMessage:{format:B}}})}else A.format=Q}function jD(A,Q,B,w){var $;if(A.pattern||(($=A.allOf)==null?void 0:$.some((D)=>D.pattern))){if(!A.allOf)A.allOf=[];if(A.pattern)A.allOf.push({pattern:A.pattern}),delete A.pattern;A.allOf.push({pattern:xL1(Q,w),...B&&w.errorMessages&&{errorMessage:{pattern:B}}})}else A.pattern=xL1(Q,w)}function xL1(A,Q){var B;if(!Q.applyRegexFlags||!A.flags)return A.source;let w={i:A.flags.includes("i"),m:A.flags.includes("m"),s:A.flags.includes("s")},$=w.i?A.source.toLowerCase():A.source,D="",f=!1,Y=!1,X=!1;for(let H=0;H<$.length;H++){if(f){D+=$[H],f=!1;continue}if(w.i){if(Y){if($[H].match(/[a-z]/)){if(X)D+=$[H],D+=`${$[H-2]}-${$[H]}`.toUpperCase(),X=!1;else if($[H+1]==="-"&&((B=$[H+2])==null?void 0:B.match(/[a-z]/)))D+=$[H],X=!0;else D+=`${$[H]}${$[H].toUpperCase()}`;continue}}else if($[H].match(/[a-z]/)){D+=`[${$[H]}${$[H].toUpperCase()}]`;continue}}if(w.m){if($[H]==="^"){D+=`(^|(?<=[\r
|
|
2565
2565
|
]))`;continue}else if($[H]==="$"){D+=`($|(?=[\r
|
|
@@ -2569,7 +2569,7 @@ Error message: ${BL1(B)}`,cause:B});this[nJ1]=!0,this.value=Q,this.context=w}sta
|
|
|
2569
2569
|
|
|
2570
2570
|
`)},flush(A){A.enqueue(`data: [DONE]
|
|
2571
2571
|
|
|
2572
|
-
`)}})}},avQ={"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-vercel-ai-ui-message-stream":"v1","x-accel-buffering":"no"};function Ab1({status:A,statusText:Q,headers:B,stream:w,consumeSseStream:$}){let D=w.pipeThrough(new svQ);if($){let[f,Y]=D.tee();D=f,$({stream:Y})}return new Response(D.pipeThrough(new TextEncoderStream),{status:A,statusText:Q,headers:ovQ(B,avQ)})}var Ad=z.record(z.string(),ZM.optional()),TG8=_50(()=>ei(z.union([z.strictObject({type:z.literal("text-start"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("text-delta"),id:z.string(),delta:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("text-end"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("error"),errorText:z.string()}),z.strictObject({type:z.literal("tool-input-start"),toolCallId:z.string(),toolName:z.string(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),title:z.string().optional()}),z.strictObject({type:z.literal("tool-input-delta"),toolCallId:z.string(),inputTextDelta:z.string()}),z.strictObject({type:z.literal("tool-input-available"),toolCallId:z.string(),toolName:z.string(),input:z.unknown(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),title:z.string().optional()}),z.strictObject({type:z.literal("tool-input-error"),toolCallId:z.string(),toolName:z.string(),input:z.unknown(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),errorText:z.string(),title:z.string().optional()}),z.strictObject({type:z.literal("tool-approval-request"),approvalId:z.string(),toolCallId:z.string()}),z.strictObject({type:z.literal("tool-output-available"),toolCallId:z.string(),output:z.unknown(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),preliminary:z.boolean().optional()}),z.strictObject({type:z.literal("tool-output-error"),toolCallId:z.string(),errorText:z.string(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional()}),z.strictObject({type:z.literal("tool-output-denied"),toolCallId:z.string()}),z.strictObject({type:z.literal("reasoning-start"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("reasoning-delta"),id:z.string(),delta:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("reasoning-end"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("source-url"),sourceId:z.string(),url:z.string(),title:z.string().optional(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("source-document"),sourceId:z.string(),mediaType:z.string(),title:z.string(),filename:z.string().optional(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("file"),url:z.string(),mediaType:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.custom((A)=>typeof A==="string"&&A.startsWith("data-"),{message:'Type must start with "data-"'}),id:z.string().optional(),data:z.unknown(),transient:z.boolean().optional()}),z.strictObject({type:z.literal("start-step")}),z.strictObject({type:z.literal("finish-step")}),z.strictObject({type:z.literal("start"),messageId:z.string().optional(),messageMetadata:z.unknown().optional()}),z.strictObject({type:z.literal("finish"),finishReason:z.enum(["stop","length","content-filter","tool-calls","error","other"]).optional(),messageMetadata:z.unknown().optional()}),z.strictObject({type:z.literal("abort"),reason:z.string().optional()}),z.strictObject({type:z.literal("message-metadata"),messageMetadata:z.unknown()})])));function tvQ(A){return A.type.startsWith("data-")}function Wg0(A){return A.type.startsWith("tool-")}function evQ(A){return A.type==="dynamic-tool"}function uL1(A){return Wg0(A)||evQ(A)}function cL1(A){return A.type.split("-").slice(1).join("-")}function AhQ({lastMessage:A,messageId:Q}){return{message:(A==null?void 0:A.role)==="assistant"?A:{id:Q,metadata:void 0,role:"assistant",parts:[]},activeTextParts:{},activeReasoningParts:{},partialToolCalls:{}}}function QhQ({stream:A,messageMetadataSchema:Q,dataPartSchemas:B,runUpdateMessageJob:w,onError:$,onToolCall:D,onData:f}){return A.pipeThrough(new TransformStream({async transform(Y,X){await w(async({state:H,write:W})=>{var Z,G,F,I;function L(j){let E=H.message.parts.filter(uL1).find((y)=>y.toolCallId===j);if(E==null)throw new hC({chunkType:"tool-invocation",chunkId:j,message:`No tool invocation found for tool call ID "${j}".`});return E}function b(j){var g;let E=H.message.parts.find((T)=>Wg0(T)&&T.toolCallId===j.toolCallId),y=j,h=E;if(E!=null){if(E.state=j.state,h.input=y.input,h.output=y.output,h.errorText=y.errorText,h.rawInput=y.rawInput,h.preliminary=y.preliminary,j.title!==void 0)h.title=j.title;if(j.toolMetadata!==void 0)h.toolMetadata=j.toolMetadata;h.providerExecuted=(g=y.providerExecuted)!=null?g:E.providerExecuted;let T=y.providerMetadata;if(T!=null)if(j.state==="output-available"||j.state==="output-error"){let S=E;S.resultProviderMetadata=T}else E.callProviderMetadata=T}else H.message.parts.push({type:`tool-${j.toolName}`,toolCallId:j.toolCallId,state:j.state,title:j.title,...j.toolMetadata!==void 0?{toolMetadata:j.toolMetadata}:{},input:y.input,output:y.output,rawInput:y.rawInput,errorText:y.errorText,providerExecuted:y.providerExecuted,preliminary:y.preliminary,...y.providerMetadata!=null&&(j.state==="output-available"||j.state==="output-error")?{resultProviderMetadata:y.providerMetadata}:{},...y.providerMetadata!=null&&!(j.state==="output-available"||j.state==="output-error")?{callProviderMetadata:y.providerMetadata}:{}})}function N(j){var g,E;let y=H.message.parts.find((S)=>S.type==="dynamic-tool"&&S.toolCallId===j.toolCallId),h=j,T=y;if(y!=null){if(y.state=j.state,T.toolName=j.toolName,T.input=h.input,T.output=h.output,T.errorText=h.errorText,T.rawInput=(g=h.rawInput)!=null?g:T.rawInput,T.preliminary=h.preliminary,j.title!==void 0)T.title=j.title;if(j.toolMetadata!==void 0)T.toolMetadata=j.toolMetadata;T.providerExecuted=(E=h.providerExecuted)!=null?E:y.providerExecuted;let S=h.providerMetadata;if(S!=null)if(j.state==="output-available"||j.state==="output-error"){let c=y;c.resultProviderMetadata=S}else y.callProviderMetadata=S}else H.message.parts.push({type:"dynamic-tool",toolName:j.toolName,toolCallId:j.toolCallId,state:j.state,input:h.input,output:h.output,errorText:h.errorText,preliminary:h.preliminary,providerExecuted:h.providerExecuted,title:j.title,...j.toolMetadata!==void 0?{toolMetadata:j.toolMetadata}:{},...h.providerMetadata!=null&&(j.state==="output-available"||j.state==="output-error")?{resultProviderMetadata:h.providerMetadata}:{},...h.providerMetadata!=null&&!(j.state==="output-available"||j.state==="output-error")?{callProviderMetadata:h.providerMetadata}:{}})}async function M(j){if(j!=null){let g=H.message.metadata!=null?eL1(H.message.metadata,j):j;if(Q!=null)await k50({value:g,schema:Q,context:{field:"message.metadata",entityId:H.message.id}});H.message.metadata=g}}switch(Y.type){case"text-start":{let j={type:"text",text:"",providerMetadata:Y.providerMetadata,state:"streaming"};H.activeTextParts[Y.id]=j,H.message.parts.push(j),W();break}case"text-delta":{let j=H.activeTextParts[Y.id];if(j==null)throw new hC({chunkType:"text-delta",chunkId:Y.id,message:`Received text-delta for missing text part with ID "${Y.id}". Ensure a "text-start" chunk is sent before any "text-delta" chunks.`});j.text+=Y.delta,j.providerMetadata=(Z=Y.providerMetadata)!=null?Z:j.providerMetadata,W();break}case"text-end":{let j=H.activeTextParts[Y.id];if(j==null)throw new hC({chunkType:"text-end",chunkId:Y.id,message:`Received text-end for missing text part with ID "${Y.id}". Ensure a "text-start" chunk is sent before any "text-end" chunks.`});j.state="done",j.providerMetadata=(G=Y.providerMetadata)!=null?G:j.providerMetadata,delete H.activeTextParts[Y.id],W();break}case"reasoning-start":{let j={type:"reasoning",text:"",providerMetadata:Y.providerMetadata,state:"streaming"};H.activeReasoningParts[Y.id]=j,H.message.parts.push(j),W();break}case"reasoning-delta":{let j=H.activeReasoningParts[Y.id];if(j==null)throw new hC({chunkType:"reasoning-delta",chunkId:Y.id,message:`Received reasoning-delta for missing reasoning part with ID "${Y.id}". Ensure a "reasoning-start" chunk is sent before any "reasoning-delta" chunks.`});j.text+=Y.delta,j.providerMetadata=(F=Y.providerMetadata)!=null?F:j.providerMetadata,W();break}case"reasoning-end":{let j=H.activeReasoningParts[Y.id];if(j==null)throw new hC({chunkType:"reasoning-end",chunkId:Y.id,message:`Received reasoning-end for missing reasoning part with ID "${Y.id}". Ensure a "reasoning-start" chunk is sent before any "reasoning-end" chunks.`});j.providerMetadata=(I=Y.providerMetadata)!=null?I:j.providerMetadata,j.state="done",delete H.activeReasoningParts[Y.id],W();break}case"file":{H.message.parts.push({type:"file",mediaType:Y.mediaType,url:Y.url,...Y.providerMetadata!=null?{providerMetadata:Y.providerMetadata}:{}}),W();break}case"source-url":{H.message.parts.push({type:"source-url",sourceId:Y.sourceId,url:Y.url,title:Y.title,providerMetadata:Y.providerMetadata}),W();break}case"source-document":{H.message.parts.push({type:"source-document",sourceId:Y.sourceId,mediaType:Y.mediaType,title:Y.title,filename:Y.filename,providerMetadata:Y.providerMetadata}),W();break}case"tool-input-start":{let j=H.message.parts.filter(Wg0);if(H.partialToolCalls[Y.toolCallId]={text:"",toolName:Y.toolName,index:j.length,dynamic:Y.dynamic,title:Y.title,toolMetadata:Y.toolMetadata},Y.dynamic)N({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-streaming",input:void 0,providerExecuted:Y.providerExecuted,title:Y.title,toolMetadata:Y.toolMetadata,providerMetadata:Y.providerMetadata});else b({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-streaming",input:void 0,providerExecuted:Y.providerExecuted,title:Y.title,toolMetadata:Y.toolMetadata,providerMetadata:Y.providerMetadata});W();break}case"tool-input-delta":{let j=H.partialToolCalls[Y.toolCallId];if(j==null)throw new hC({chunkType:"tool-input-delta",chunkId:Y.toolCallId,message:`Received tool-input-delta for missing tool call with ID "${Y.toolCallId}". Ensure a "tool-input-start" chunk is sent before any "tool-input-delta" chunks.`});j.text+=Y.inputTextDelta;let{value:g}=await Qd(j.text);if(j.dynamic)N({toolCallId:Y.toolCallId,toolName:j.toolName,state:"input-streaming",input:g,title:j.title,toolMetadata:j.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:j.toolName,state:"input-streaming",input:g,title:j.title,toolMetadata:j.toolMetadata});W();break}case"tool-input-available":{if(Y.dynamic)N({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-available",input:Y.input,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:Y.title,toolMetadata:Y.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-available",input:Y.input,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:Y.title,toolMetadata:Y.toolMetadata});if(W(),D&&!Y.providerExecuted)await D({toolCall:Y});break}case"tool-input-error":{let j=H.message.parts.filter(uL1).find((E)=>E.toolCallId===Y.toolCallId);if(j!=null?j.type==="dynamic-tool":!!Y.dynamic)N({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"output-error",input:Y.input,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,toolMetadata:Y.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"output-error",input:void 0,rawInput:Y.input,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,toolMetadata:Y.toolMetadata});W();break}case"tool-approval-request":{let j=L(Y.toolCallId);j.state="approval-requested",j.approval={id:Y.approvalId},W();break}case"tool-output-denied":{let j=L(Y.toolCallId);j.state="output-denied",W();break}case"tool-output-available":{let j=L(Y.toolCallId);if(j.type==="dynamic-tool")N({toolCallId:Y.toolCallId,toolName:j.toolName,state:"output-available",input:j.input,output:Y.output,preliminary:Y.preliminary,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:cL1(j),state:"output-available",input:j.input,output:Y.output,providerExecuted:Y.providerExecuted,preliminary:Y.preliminary,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});W();break}case"tool-output-error":{let j=L(Y.toolCallId);if(j.type==="dynamic-tool")N({toolCallId:Y.toolCallId,toolName:j.toolName,state:"output-error",input:j.input,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:cL1(j),state:"output-error",input:j.input,rawInput:j.rawInput,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});W();break}case"start-step":{H.message.parts.push({type:"step-start"});break}case"finish-step":{H.activeTextParts={},H.activeReasoningParts={};break}case"start":{if(Y.messageId!=null)H.message.id=Y.messageId;if(await M(Y.messageMetadata),Y.messageId!=null||Y.messageMetadata!=null)W();break}case"finish":{if(Y.finishReason!=null)H.finishReason=Y.finishReason;if(await M(Y.messageMetadata),Y.messageMetadata!=null)W();break}case"message-metadata":{if(await M(Y.messageMetadata),Y.messageMetadata!=null)W();break}case"error":{$==null||$(Error(Y.errorText));break}default:if(tvQ(Y)){if((B==null?void 0:B[Y.type])!=null){let E=H.message.parts.findIndex((h)=>("id"in h)&&("data"in h)&&h.id===Y.id&&h.type===Y.type),y=E>=0?E:H.message.parts.length;await k50({value:Y.data,schema:B[Y.type],context:{field:`message.parts[${y}].data`,entityName:Y.type,entityId:Y.id}})}let j=Y;if(j.transient){f==null||f(j);break}let g=j.id!=null?H.message.parts.find((E)=>j.type===E.type&&j.id===E.id):void 0;if(g!=null)g.data=j.data;else H.message.parts.push(j);f==null||f(j),W()}}X.enqueue(Y)})}}))}function BhQ({messageId:A,originalMessages:Q=[],onStepFinish:B,onFinish:w,onError:$,stream:D}){let f=Q==null?void 0:Q[Q.length-1];if((f==null?void 0:f.role)!=="assistant")f=void 0;else A=f.id;let Y=!1,X=D.pipeThrough(new TransformStream({transform(I,L){if(I.type==="start"){let b=I;if(b.messageId==null&&A!=null)b.messageId=A}if(I.type==="abort")Y=!0;L.enqueue(I)}}));if(w==null&&B==null)return X;let H=AhQ({lastMessage:f?structuredClone(f):void 0,messageId:A!=null?A:""}),W=async(I)=>{await I({state:H,write:()=>{}})},Z=!1,G=async()=>{if(Z||!w)return;Z=!0;let I=H.message.id===(f==null?void 0:f.id);await w({isAborted:Y,isContinuation:I,responseMessage:H.message,messages:[...I?Q.slice(0,-1):Q,H.message],finishReason:H.finishReason})},F=async()=>{if(!B)return;let I=H.message.id===(f==null?void 0:f.id);try{await B({isContinuation:I,responseMessage:structuredClone(H.message),messages:[...I?Q.slice(0,-1):Q,structuredClone(H.message)]})}catch(L){$(L)}};return QhQ({stream:X,runUpdateMessageJob:W,onError:$}).pipeThrough(new TransformStream({async transform(I,L){if(I.type==="finish-step")await F();L.enqueue(I)},async cancel(){await G()},async flush(){await G()}}))}var SG8=k3({prefix:"aitxt",size:24});function Qb1({execute:A,onError:Q=Yg0,originalMessages:B,onStepFinish:w,onFinish:$,generateId:D=yL1}){let f,Y=[],X=new ReadableStream({start(Z){f=Z}});function H(Z){try{f.enqueue(Z)}catch(G){}}try{let Z=A({writer:{write(G){H(G)},merge(G){Y.push((async()=>{let F=G.getReader();while(!0){let{done:I,value:L}=await F.read();if(I)break;H(L)}})().catch((F)=>{H({type:"error",errorText:Q(F)})}))},onError:Q}});if(Z)Y.push(Z.catch((G)=>{H({type:"error",errorText:Q(G)})}))}catch(Z){H({type:"error",errorText:Q(Z)})}return new Promise(async(Z)=>{while(Y.length>0)await Y.shift();Z()}).finally(()=>{try{f.close()}catch(Z){}}),BhQ({stream:X,messageId:D(),originalMessages:B,onStepFinish:w,onFinish:$,onError:Q})}var Pf=z.record(z.string(),ZM.optional()),lG8=_50(()=>ei(z.array(z.object({id:z.string(),role:z.enum(["system","user","assistant"]),metadata:z.unknown().optional(),parts:z.array(z.union([z.object({type:z.literal("text"),text:z.string(),state:z.enum(["streaming","done"]).optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("reasoning"),text:z.string(),state:z.enum(["streaming","done"]).optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("source-url"),sourceId:z.string(),url:z.string(),title:z.string().optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("source-document"),sourceId:z.string(),mediaType:z.string(),title:z.string(),filename:z.string().optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("file"),mediaType:z.string(),filename:z.string().optional(),url:z.string(),providerMetadata:L2.optional()}),z.object({type:z.literal("step-start")}),z.object({type:z.string().startsWith("data-"),id:z.string().optional(),data:z.unknown()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-streaming"),input:z.unknown().optional(),providerExecuted:z.boolean().optional(),callProviderMetadata:L2.optional(),output:z.never().optional(),errorText:z.never().optional(),approval:z.never().optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-available"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.never().optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-requested"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.never().optional(),reason:z.never().optional()})}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-responded"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.boolean(),reason:z.string().optional()})}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-available"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.unknown(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),preliminary:z.boolean().optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-error"),input:z.unknown().optional(),rawInput:z.unknown().optional(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.string(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-denied"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!1),reason:z.string().optional()})}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-streaming"),providerExecuted:z.boolean().optional(),callProviderMetadata:L2.optional(),input:z.unknown().optional(),output:z.never().optional(),errorText:z.never().optional(),approval:z.never().optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-available"),providerExecuted:z.boolean().optional(),input:z.unknown(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.never().optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-requested"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.never().optional(),reason:z.never().optional()})}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-responded"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.boolean(),reason:z.string().optional()})}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-available"),providerExecuted:z.boolean().optional(),input:z.unknown(),output:z.unknown(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),preliminary:z.boolean().optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-error"),providerExecuted:z.boolean().optional(),input:z.unknown().optional(),rawInput:z.unknown().optional(),output:z.never().optional(),errorText:z.string(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-denied"),providerExecuted:z.boolean().optional(),input:z.unknown(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!1),reason:z.string().optional()})})])).nonempty("Message must contain at least one part")})).nonempty("Messages array must not be empty")));var iG8=k3({prefix:"aiobj",size:24});function Bb1(A){return({url:Q,abortSignal:B})=>RvQ({url:Q,maxBytes:A==null?void 0:A.maxBytes,abortSignal:B})}var nG8=k3({prefix:"aiobj",size:24});var rG8=Bb1();var whQ="AI_NoSuchProviderError",$hQ=`vercel.ai.error.${whQ}`,DhQ=Symbol.for($hQ),fhQ;fhQ=DhQ;var oG8=Bb1();var wb1={name:"@brains/web-chat",private:!0,version:"0.2.0-alpha.128",description:"Web chat interface for Brains",type:"module",exports:{".":"./src/index.ts"},files:["src","dist","package.json"],scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix",test:"bun test"},dependencies:{"@ai-sdk/react":"^3.0.116","@brains/auth-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@streamdown/cjk":"^1.0.3","@streamdown/code":"^1.1.1","@streamdown/math":"^1.0.2","@streamdown/mermaid":"^1.0.2",ai:"^6.0.86","class-variance-authority":"^0.7.0",cmdk:"^1.1.1","lucide-react":"^1.16.0",nanoid:"^5.0.4","radix-ui":"^1.4.3",react:"^19.2.6","react-dom":"^19.2.6",shiki:"^4.1.0",streamdown:"^2.5.0","use-stick-to-bottom":"^1.1.4"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/react":"^19.0.3","@types/react-dom":"^19.0.3",typescript:"^5.3.3",vite:"^7.2.4"}};p0();async function $b1(A,Q){let B=await Q.resolvePermissionLevel(A);if(B==="public")return Q.createOperatorLoginRequiredResponse(A);let w=new URL(A.url),$=w.searchParams.get("id")?.trim();if(!$)return new Response("Missing document id",{status:400});let D=await fb1({entityType:"document",id:$,permissionLevel:B,entityService:Q.entityService});if(!D)return new Response("Document not found",{status:404});if(typeof D.content!=="string")return new Response("Document content is not a PDF",{status:415});let f=NN("document",D.content);if(!f)return new Response("Document content is not a PDF",{status:415});let Y=jN(D.metadata,$,"document",f.mimeType);return Yb1({requestUrl:w,data:f.data,mediaType:f.mimeType,filename:Y})}async function Db1(A,Q){let B=await Q.resolvePermissionLevel(A);if(B==="public")return Q.createOperatorLoginRequiredResponse(A);let w=new URL(A.url),$=w.searchParams.get("id")?.trim();if(!$)return new Response("Missing image id",{status:400});let D=await fb1({entityType:"image",id:$,permissionLevel:B,entityService:Q.entityService});if(!D)return new Response("Image not found",{status:404});if(typeof D.content!=="string")return new Response("Image content is not an image",{status:415});let f=NN("image",D.content);if(!f)return new Response("Image content is not an image",{status:415});let Y=jN(D.metadata,$,"image",f.mimeType);return Yb1({requestUrl:w,data:f.data,mediaType:f.mimeType,filename:Y})}async function fb1(A){let Q={entityType:A.entityType,id:A.id},B=await Ax({entityRef:Q,userLevel:A.permissionLevel,getEntity:(w)=>A.entityService.getEntity(w),getVisibleEntity:(w,$)=>A.entityService.getEntity({...w,visibilityScope:$})});return B.status==="visible"?B.entity:void 0}function Yb1(A){let Q=new Headers({"Content-Type":A.mediaType,"Content-Length":String(A.data.byteLength),"Content-Disposition":lI({disposition:A.requestUrl.searchParams.has("download")?"attachment":"inline",filename:A.filename})});return new Response(A.data,{headers:Q})}K0();p0();var Bd="upload",Xb1=nO;var XhQ={namespace:"upload",refKind:Bd,routePath:"/api/chat/uploads"};function O50(){return XhQ}p0();YG0();var Hb1=ee;var Wb1=A00;var HhQ="file",WhQ=16384;async function Zb1(A,Q){if(!await Q.resolveOperatorSession(A))return new Response("Forbidden",{status:403});let B=Number(A.headers.get("content-length"));if(Number.isFinite(B)&&B>Wb1+WhQ)return new Response("File upload too large",{status:400});let w;try{w=await A.formData()}catch{return new Response("Invalid multipart upload",{status:400})}let $=w.get(HhQ);if(!($ instanceof File))return new Response("Missing upload file",{status:400});let D=Buffer.from(await $.arrayBuffer()),f=Uq({filename:$.name,mediaType:$.type,content:D});if(!f.ok)return new Response(f.message,{status:400});let Y=Q.getUploadStore(),X=await Y.save({filename:f.filename,mediaType:f.mediaType,content:D});return Response.json(Y.toResponseBody(X),{status:201})}async function Kb1(A,Q){if(!await Q.resolveOperatorSession(A))return new Response("Forbidden",{status:403});let B=new URL(A.url).searchParams.get("id")?.trim();if(!B)return new Response("Missing upload id",{status:400});let w=await zb1(B,Q.getUploadStore());if(w instanceof Response)return w;let{record:$,content:D}=w,f=qb1($,D);if(f instanceof Response)return f;let Y=new URL(A.url).searchParams.has("download")?"attachment":"inline",X=new Uint8Array(D).buffer;return new Response(X,{headers:{"Content-Type":$.mediaType,"Content-Length":String(D.byteLength),"Content-Disposition":lI({disposition:Y,filename:$.filename})}})}function Ub1(A){let Q=Kq(A.filename??Hb1),B=KhQ(A.url);if(!B)return new Response(`Unsupported file upload URL: ${Q}`,{status:400});let w=Uq({filename:Q,mediaType:A.mediaType,content:B.buffer});if(!w.ok)return new Response(w.message,{status:400});return Fb1(w,B.buffer)}async function Gb1(A,Q){let B=await zb1(A,Q);if(B instanceof Response)return B;let{record:w,content:$}=B,D=qb1(w,$);if(D instanceof Response)return D;return Fb1(D,$,{kind:Bd,id:A})}async function zb1(A,Q){try{return await Q.read(A)}catch(B){if(B instanceof zU)return ZhQ(B);throw B}}function qb1(A,Q){let B=Uq({filename:A.filename,mediaType:A.mediaType,content:Q});if(!B.ok)return new Response(B.message,{status:400});return B}function Fb1(A,Q,B){if(A.kind==="text")return{kind:"text",filename:A.filename,mediaType:A.mediaType,content:A.text,sizeBytes:A.sizeBytes,...B!==void 0?{source:B}:{}};return{kind:"file",filename:A.filename,mediaType:A.mediaType,data:new Uint8Array(Q),sizeBytes:A.sizeBytes,...B!==void 0?{source:B}:{}}}function ZhQ(A){switch(A.code){case"invalid_ref":return new Response("Invalid upload ref",{status:400});case"invalid_metadata":return new Response("Invalid upload metadata",{status:500});case"not_found":return new Response("Upload not found",{status:404})}}function KhQ(A){let Q=/^data:[^,]*,(.*)$/s.exec(A);if(!Q)return null;let w=A.slice(5,A.indexOf(",")).split(";").some(($)=>$.toLowerCase()==="base64");try{let $=w?Buffer.from(Q[1]??"","base64"):Buffer.from(decodeURIComponent(Q[1]??""),"utf8");return{buffer:$,byteLength:$.byteLength}}catch{return null}}var UhQ=K.object({type:K.literal("text"),text:K.string()}),GhQ=K.object({type:K.literal("file"),mediaType:K.string().optional(),filename:K.string().optional(),url:K.string()}),zhQ=K.object({state:K.literal("approval-responded"),approval:K.object({id:K.string(),approved:K.boolean()})}).passthrough(),qhQ=K.object({id:K.string().optional(),role:K.string(),parts:K.array(K.unknown()).optional(),content:K.string().optional()}),Ib1=K.object({id:K.string().optional(),messages:K.array(qhQ).min(1),trigger:K.string().optional()}),FhQ=K.object({kind:K.literal(Bd),id:K.string().regex(Xb1)}),IhQ=K.object({type:K.literal("data-upload"),data:K.object({ref:FhQ})});async function Vb1(A,Q){let B=VhQ(A);if(!B)return{message:"",attachments:[]};let w=[],$=[];for(let f of B.parts??[]){let Y=UhQ.safeParse(f);if(Y.success){if(Y.data.text.length>0)w.push(Y.data.text);continue}let X=GhQ.safeParse(f);if(X.success){let W=Ub1(X.data);if(W instanceof Response)return W;$.push(W);continue}let H=IhQ.safeParse(f);if(H.success){let W=await Gb1(H.data.data.ref.id,Q.uploadStore);if(W instanceof Response)return W;$.push(W);continue}if(JhQ(f)==="data-upload")return new Response("Invalid upload ref",{status:400})}return{message:w.length>0?w.join(`
|
|
2572
|
+
`)}})}},avQ={"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-vercel-ai-ui-message-stream":"v1","x-accel-buffering":"no"};function Ab1({status:A,statusText:Q,headers:B,stream:w,consumeSseStream:$}){let D=w.pipeThrough(new svQ);if($){let[f,Y]=D.tee();D=f,$({stream:Y})}return new Response(D.pipeThrough(new TextEncoderStream),{status:A,statusText:Q,headers:ovQ(B,avQ)})}var Ad=z.record(z.string(),ZM.optional()),TG8=_50(()=>ei(z.union([z.strictObject({type:z.literal("text-start"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("text-delta"),id:z.string(),delta:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("text-end"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("error"),errorText:z.string()}),z.strictObject({type:z.literal("tool-input-start"),toolCallId:z.string(),toolName:z.string(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),title:z.string().optional()}),z.strictObject({type:z.literal("tool-input-delta"),toolCallId:z.string(),inputTextDelta:z.string()}),z.strictObject({type:z.literal("tool-input-available"),toolCallId:z.string(),toolName:z.string(),input:z.unknown(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),title:z.string().optional()}),z.strictObject({type:z.literal("tool-input-error"),toolCallId:z.string(),toolName:z.string(),input:z.unknown(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),errorText:z.string(),title:z.string().optional()}),z.strictObject({type:z.literal("tool-approval-request"),approvalId:z.string(),toolCallId:z.string()}),z.strictObject({type:z.literal("tool-output-available"),toolCallId:z.string(),output:z.unknown(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional(),preliminary:z.boolean().optional()}),z.strictObject({type:z.literal("tool-output-error"),toolCallId:z.string(),errorText:z.string(),providerExecuted:z.boolean().optional(),providerMetadata:L2.optional(),toolMetadata:Ad.optional(),dynamic:z.boolean().optional()}),z.strictObject({type:z.literal("tool-output-denied"),toolCallId:z.string()}),z.strictObject({type:z.literal("reasoning-start"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("reasoning-delta"),id:z.string(),delta:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("reasoning-end"),id:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("source-url"),sourceId:z.string(),url:z.string(),title:z.string().optional(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("source-document"),sourceId:z.string(),mediaType:z.string(),title:z.string(),filename:z.string().optional(),providerMetadata:L2.optional()}),z.strictObject({type:z.literal("file"),url:z.string(),mediaType:z.string(),providerMetadata:L2.optional()}),z.strictObject({type:z.custom((A)=>typeof A==="string"&&A.startsWith("data-"),{message:'Type must start with "data-"'}),id:z.string().optional(),data:z.unknown(),transient:z.boolean().optional()}),z.strictObject({type:z.literal("start-step")}),z.strictObject({type:z.literal("finish-step")}),z.strictObject({type:z.literal("start"),messageId:z.string().optional(),messageMetadata:z.unknown().optional()}),z.strictObject({type:z.literal("finish"),finishReason:z.enum(["stop","length","content-filter","tool-calls","error","other"]).optional(),messageMetadata:z.unknown().optional()}),z.strictObject({type:z.literal("abort"),reason:z.string().optional()}),z.strictObject({type:z.literal("message-metadata"),messageMetadata:z.unknown()})])));function tvQ(A){return A.type.startsWith("data-")}function Wg0(A){return A.type.startsWith("tool-")}function evQ(A){return A.type==="dynamic-tool"}function uL1(A){return Wg0(A)||evQ(A)}function cL1(A){return A.type.split("-").slice(1).join("-")}function AhQ({lastMessage:A,messageId:Q}){return{message:(A==null?void 0:A.role)==="assistant"?A:{id:Q,metadata:void 0,role:"assistant",parts:[]},activeTextParts:{},activeReasoningParts:{},partialToolCalls:{}}}function QhQ({stream:A,messageMetadataSchema:Q,dataPartSchemas:B,runUpdateMessageJob:w,onError:$,onToolCall:D,onData:f}){return A.pipeThrough(new TransformStream({async transform(Y,X){await w(async({state:H,write:W})=>{var Z,G,F,I;function L(j){let E=H.message.parts.filter(uL1).find((y)=>y.toolCallId===j);if(E==null)throw new hC({chunkType:"tool-invocation",chunkId:j,message:`No tool invocation found for tool call ID "${j}".`});return E}function b(j){var g;let E=H.message.parts.find((T)=>Wg0(T)&&T.toolCallId===j.toolCallId),y=j,h=E;if(E!=null){if(E.state=j.state,h.input=y.input,h.output=y.output,h.errorText=y.errorText,h.rawInput=y.rawInput,h.preliminary=y.preliminary,j.title!==void 0)h.title=j.title;if(j.toolMetadata!==void 0)h.toolMetadata=j.toolMetadata;h.providerExecuted=(g=y.providerExecuted)!=null?g:E.providerExecuted;let T=y.providerMetadata;if(T!=null)if(j.state==="output-available"||j.state==="output-error"){let S=E;S.resultProviderMetadata=T}else E.callProviderMetadata=T}else H.message.parts.push({type:`tool-${j.toolName}`,toolCallId:j.toolCallId,state:j.state,title:j.title,...j.toolMetadata!==void 0?{toolMetadata:j.toolMetadata}:{},input:y.input,output:y.output,rawInput:y.rawInput,errorText:y.errorText,providerExecuted:y.providerExecuted,preliminary:y.preliminary,...y.providerMetadata!=null&&(j.state==="output-available"||j.state==="output-error")?{resultProviderMetadata:y.providerMetadata}:{},...y.providerMetadata!=null&&!(j.state==="output-available"||j.state==="output-error")?{callProviderMetadata:y.providerMetadata}:{}})}function N(j){var g,E;let y=H.message.parts.find((S)=>S.type==="dynamic-tool"&&S.toolCallId===j.toolCallId),h=j,T=y;if(y!=null){if(y.state=j.state,T.toolName=j.toolName,T.input=h.input,T.output=h.output,T.errorText=h.errorText,T.rawInput=(g=h.rawInput)!=null?g:T.rawInput,T.preliminary=h.preliminary,j.title!==void 0)T.title=j.title;if(j.toolMetadata!==void 0)T.toolMetadata=j.toolMetadata;T.providerExecuted=(E=h.providerExecuted)!=null?E:y.providerExecuted;let S=h.providerMetadata;if(S!=null)if(j.state==="output-available"||j.state==="output-error"){let c=y;c.resultProviderMetadata=S}else y.callProviderMetadata=S}else H.message.parts.push({type:"dynamic-tool",toolName:j.toolName,toolCallId:j.toolCallId,state:j.state,input:h.input,output:h.output,errorText:h.errorText,preliminary:h.preliminary,providerExecuted:h.providerExecuted,title:j.title,...j.toolMetadata!==void 0?{toolMetadata:j.toolMetadata}:{},...h.providerMetadata!=null&&(j.state==="output-available"||j.state==="output-error")?{resultProviderMetadata:h.providerMetadata}:{},...h.providerMetadata!=null&&!(j.state==="output-available"||j.state==="output-error")?{callProviderMetadata:h.providerMetadata}:{}})}async function M(j){if(j!=null){let g=H.message.metadata!=null?eL1(H.message.metadata,j):j;if(Q!=null)await k50({value:g,schema:Q,context:{field:"message.metadata",entityId:H.message.id}});H.message.metadata=g}}switch(Y.type){case"text-start":{let j={type:"text",text:"",providerMetadata:Y.providerMetadata,state:"streaming"};H.activeTextParts[Y.id]=j,H.message.parts.push(j),W();break}case"text-delta":{let j=H.activeTextParts[Y.id];if(j==null)throw new hC({chunkType:"text-delta",chunkId:Y.id,message:`Received text-delta for missing text part with ID "${Y.id}". Ensure a "text-start" chunk is sent before any "text-delta" chunks.`});j.text+=Y.delta,j.providerMetadata=(Z=Y.providerMetadata)!=null?Z:j.providerMetadata,W();break}case"text-end":{let j=H.activeTextParts[Y.id];if(j==null)throw new hC({chunkType:"text-end",chunkId:Y.id,message:`Received text-end for missing text part with ID "${Y.id}". Ensure a "text-start" chunk is sent before any "text-end" chunks.`});j.state="done",j.providerMetadata=(G=Y.providerMetadata)!=null?G:j.providerMetadata,delete H.activeTextParts[Y.id],W();break}case"reasoning-start":{let j={type:"reasoning",text:"",providerMetadata:Y.providerMetadata,state:"streaming"};H.activeReasoningParts[Y.id]=j,H.message.parts.push(j),W();break}case"reasoning-delta":{let j=H.activeReasoningParts[Y.id];if(j==null)throw new hC({chunkType:"reasoning-delta",chunkId:Y.id,message:`Received reasoning-delta for missing reasoning part with ID "${Y.id}". Ensure a "reasoning-start" chunk is sent before any "reasoning-delta" chunks.`});j.text+=Y.delta,j.providerMetadata=(F=Y.providerMetadata)!=null?F:j.providerMetadata,W();break}case"reasoning-end":{let j=H.activeReasoningParts[Y.id];if(j==null)throw new hC({chunkType:"reasoning-end",chunkId:Y.id,message:`Received reasoning-end for missing reasoning part with ID "${Y.id}". Ensure a "reasoning-start" chunk is sent before any "reasoning-end" chunks.`});j.providerMetadata=(I=Y.providerMetadata)!=null?I:j.providerMetadata,j.state="done",delete H.activeReasoningParts[Y.id],W();break}case"file":{H.message.parts.push({type:"file",mediaType:Y.mediaType,url:Y.url,...Y.providerMetadata!=null?{providerMetadata:Y.providerMetadata}:{}}),W();break}case"source-url":{H.message.parts.push({type:"source-url",sourceId:Y.sourceId,url:Y.url,title:Y.title,providerMetadata:Y.providerMetadata}),W();break}case"source-document":{H.message.parts.push({type:"source-document",sourceId:Y.sourceId,mediaType:Y.mediaType,title:Y.title,filename:Y.filename,providerMetadata:Y.providerMetadata}),W();break}case"tool-input-start":{let j=H.message.parts.filter(Wg0);if(H.partialToolCalls[Y.toolCallId]={text:"",toolName:Y.toolName,index:j.length,dynamic:Y.dynamic,title:Y.title,toolMetadata:Y.toolMetadata},Y.dynamic)N({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-streaming",input:void 0,providerExecuted:Y.providerExecuted,title:Y.title,toolMetadata:Y.toolMetadata,providerMetadata:Y.providerMetadata});else b({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-streaming",input:void 0,providerExecuted:Y.providerExecuted,title:Y.title,toolMetadata:Y.toolMetadata,providerMetadata:Y.providerMetadata});W();break}case"tool-input-delta":{let j=H.partialToolCalls[Y.toolCallId];if(j==null)throw new hC({chunkType:"tool-input-delta",chunkId:Y.toolCallId,message:`Received tool-input-delta for missing tool call with ID "${Y.toolCallId}". Ensure a "tool-input-start" chunk is sent before any "tool-input-delta" chunks.`});j.text+=Y.inputTextDelta;let{value:g}=await Qd(j.text);if(j.dynamic)N({toolCallId:Y.toolCallId,toolName:j.toolName,state:"input-streaming",input:g,title:j.title,toolMetadata:j.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:j.toolName,state:"input-streaming",input:g,title:j.title,toolMetadata:j.toolMetadata});W();break}case"tool-input-available":{if(Y.dynamic)N({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-available",input:Y.input,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:Y.title,toolMetadata:Y.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"input-available",input:Y.input,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:Y.title,toolMetadata:Y.toolMetadata});if(W(),D&&!Y.providerExecuted)await D({toolCall:Y});break}case"tool-input-error":{let j=H.message.parts.filter(uL1).find((E)=>E.toolCallId===Y.toolCallId);if(j!=null?j.type==="dynamic-tool":!!Y.dynamic)N({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"output-error",input:Y.input,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,toolMetadata:Y.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:Y.toolName,state:"output-error",input:void 0,rawInput:Y.input,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,toolMetadata:Y.toolMetadata});W();break}case"tool-approval-request":{let j=L(Y.toolCallId);j.state="approval-requested",j.approval={id:Y.approvalId},W();break}case"tool-output-denied":{let j=L(Y.toolCallId);j.state="output-denied",W();break}case"tool-output-available":{let j=L(Y.toolCallId);if(j.type==="dynamic-tool")N({toolCallId:Y.toolCallId,toolName:j.toolName,state:"output-available",input:j.input,output:Y.output,preliminary:Y.preliminary,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:cL1(j),state:"output-available",input:j.input,output:Y.output,providerExecuted:Y.providerExecuted,preliminary:Y.preliminary,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});W();break}case"tool-output-error":{let j=L(Y.toolCallId);if(j.type==="dynamic-tool")N({toolCallId:Y.toolCallId,toolName:j.toolName,state:"output-error",input:j.input,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});else b({toolCallId:Y.toolCallId,toolName:cL1(j),state:"output-error",input:j.input,rawInput:j.rawInput,errorText:Y.errorText,providerExecuted:Y.providerExecuted,providerMetadata:Y.providerMetadata,title:j.title,toolMetadata:j.toolMetadata});W();break}case"start-step":{H.message.parts.push({type:"step-start"});break}case"finish-step":{H.activeTextParts={},H.activeReasoningParts={};break}case"start":{if(Y.messageId!=null)H.message.id=Y.messageId;if(await M(Y.messageMetadata),Y.messageId!=null||Y.messageMetadata!=null)W();break}case"finish":{if(Y.finishReason!=null)H.finishReason=Y.finishReason;if(await M(Y.messageMetadata),Y.messageMetadata!=null)W();break}case"message-metadata":{if(await M(Y.messageMetadata),Y.messageMetadata!=null)W();break}case"error":{$==null||$(Error(Y.errorText));break}default:if(tvQ(Y)){if((B==null?void 0:B[Y.type])!=null){let E=H.message.parts.findIndex((h)=>("id"in h)&&("data"in h)&&h.id===Y.id&&h.type===Y.type),y=E>=0?E:H.message.parts.length;await k50({value:Y.data,schema:B[Y.type],context:{field:`message.parts[${y}].data`,entityName:Y.type,entityId:Y.id}})}let j=Y;if(j.transient){f==null||f(j);break}let g=j.id!=null?H.message.parts.find((E)=>j.type===E.type&&j.id===E.id):void 0;if(g!=null)g.data=j.data;else H.message.parts.push(j);f==null||f(j),W()}}X.enqueue(Y)})}}))}function BhQ({messageId:A,originalMessages:Q=[],onStepFinish:B,onFinish:w,onError:$,stream:D}){let f=Q==null?void 0:Q[Q.length-1];if((f==null?void 0:f.role)!=="assistant")f=void 0;else A=f.id;let Y=!1,X=D.pipeThrough(new TransformStream({transform(I,L){if(I.type==="start"){let b=I;if(b.messageId==null&&A!=null)b.messageId=A}if(I.type==="abort")Y=!0;L.enqueue(I)}}));if(w==null&&B==null)return X;let H=AhQ({lastMessage:f?structuredClone(f):void 0,messageId:A!=null?A:""}),W=async(I)=>{await I({state:H,write:()=>{}})},Z=!1,G=async()=>{if(Z||!w)return;Z=!0;let I=H.message.id===(f==null?void 0:f.id);await w({isAborted:Y,isContinuation:I,responseMessage:H.message,messages:[...I?Q.slice(0,-1):Q,H.message],finishReason:H.finishReason})},F=async()=>{if(!B)return;let I=H.message.id===(f==null?void 0:f.id);try{await B({isContinuation:I,responseMessage:structuredClone(H.message),messages:[...I?Q.slice(0,-1):Q,structuredClone(H.message)]})}catch(L){$(L)}};return QhQ({stream:X,runUpdateMessageJob:W,onError:$}).pipeThrough(new TransformStream({async transform(I,L){if(I.type==="finish-step")await F();L.enqueue(I)},async cancel(){await G()},async flush(){await G()}}))}var SG8=k3({prefix:"aitxt",size:24});function Qb1({execute:A,onError:Q=Yg0,originalMessages:B,onStepFinish:w,onFinish:$,generateId:D=yL1}){let f,Y=[],X=new ReadableStream({start(Z){f=Z}});function H(Z){try{f.enqueue(Z)}catch(G){}}try{let Z=A({writer:{write(G){H(G)},merge(G){Y.push((async()=>{let F=G.getReader();while(!0){let{done:I,value:L}=await F.read();if(I)break;H(L)}})().catch((F)=>{H({type:"error",errorText:Q(F)})}))},onError:Q}});if(Z)Y.push(Z.catch((G)=>{H({type:"error",errorText:Q(G)})}))}catch(Z){H({type:"error",errorText:Q(Z)})}return new Promise(async(Z)=>{while(Y.length>0)await Y.shift();Z()}).finally(()=>{try{f.close()}catch(Z){}}),BhQ({stream:X,messageId:D(),originalMessages:B,onStepFinish:w,onFinish:$,onError:Q})}var Pf=z.record(z.string(),ZM.optional()),lG8=_50(()=>ei(z.array(z.object({id:z.string(),role:z.enum(["system","user","assistant"]),metadata:z.unknown().optional(),parts:z.array(z.union([z.object({type:z.literal("text"),text:z.string(),state:z.enum(["streaming","done"]).optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("reasoning"),text:z.string(),state:z.enum(["streaming","done"]).optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("source-url"),sourceId:z.string(),url:z.string(),title:z.string().optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("source-document"),sourceId:z.string(),mediaType:z.string(),title:z.string(),filename:z.string().optional(),providerMetadata:L2.optional()}),z.object({type:z.literal("file"),mediaType:z.string(),filename:z.string().optional(),url:z.string(),providerMetadata:L2.optional()}),z.object({type:z.literal("step-start")}),z.object({type:z.string().startsWith("data-"),id:z.string().optional(),data:z.unknown()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-streaming"),input:z.unknown().optional(),providerExecuted:z.boolean().optional(),callProviderMetadata:L2.optional(),output:z.never().optional(),errorText:z.never().optional(),approval:z.never().optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-available"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.never().optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-requested"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.never().optional(),reason:z.never().optional()})}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-responded"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.boolean(),reason:z.string().optional()})}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-available"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.unknown(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),preliminary:z.boolean().optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-error"),input:z.unknown().optional(),rawInput:z.unknown().optional(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.string(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.literal("dynamic-tool"),toolName:z.string(),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-denied"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!1),reason:z.string().optional()})}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-streaming"),providerExecuted:z.boolean().optional(),callProviderMetadata:L2.optional(),input:z.unknown().optional(),output:z.never().optional(),errorText:z.never().optional(),approval:z.never().optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("input-available"),providerExecuted:z.boolean().optional(),input:z.unknown(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.never().optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-requested"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.never().optional(),reason:z.never().optional()})}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("approval-responded"),input:z.unknown(),providerExecuted:z.boolean().optional(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.boolean(),reason:z.string().optional()})}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-available"),providerExecuted:z.boolean().optional(),input:z.unknown(),output:z.unknown(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),preliminary:z.boolean().optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-error"),providerExecuted:z.boolean().optional(),input:z.unknown().optional(),rawInput:z.unknown().optional(),output:z.never().optional(),errorText:z.string(),callProviderMetadata:L2.optional(),resultProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!0),reason:z.string().optional()}).optional()}),z.object({type:z.string().startsWith("tool-"),toolCallId:z.string(),toolMetadata:Pf.optional(),state:z.literal("output-denied"),providerExecuted:z.boolean().optional(),input:z.unknown(),output:z.never().optional(),errorText:z.never().optional(),callProviderMetadata:L2.optional(),approval:z.object({id:z.string(),approved:z.literal(!1),reason:z.string().optional()})})])).nonempty("Message must contain at least one part")})).nonempty("Messages array must not be empty")));var iG8=k3({prefix:"aiobj",size:24});function Bb1(A){return({url:Q,abortSignal:B})=>RvQ({url:Q,maxBytes:A==null?void 0:A.maxBytes,abortSignal:B})}var nG8=k3({prefix:"aiobj",size:24});var rG8=Bb1();var whQ="AI_NoSuchProviderError",$hQ=`vercel.ai.error.${whQ}`,DhQ=Symbol.for($hQ),fhQ;fhQ=DhQ;var oG8=Bb1();var wb1={name:"@brains/web-chat",private:!0,version:"0.2.0-alpha.129",description:"Web chat interface for Brains",type:"module",exports:{".":"./src/index.ts"},files:["src","dist","package.json"],scripts:{build:"bun scripts/build-ui.ts","build:ui":"bun scripts/build-ui.ts",typecheck:"tsc --noEmit && tsc --noEmit -p ui-react/tsconfig.json",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix",test:"bun test"},dependencies:{"@ai-sdk/react":"^3.0.116","@brains/auth-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@streamdown/cjk":"^1.0.3","@streamdown/code":"^1.1.1","@streamdown/math":"^1.0.2","@streamdown/mermaid":"^1.0.2",ai:"^6.0.86","class-variance-authority":"^0.7.0",cmdk:"^1.1.1","lucide-react":"^1.16.0",nanoid:"^5.0.4","radix-ui":"^1.4.3",react:"^19.2.6","react-dom":"^19.2.6",shiki:"^4.1.0",streamdown:"^2.5.0","use-stick-to-bottom":"^1.1.4"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/react":"^19.0.3","@types/react-dom":"^19.0.3",typescript:"^5.3.3",vite:"^7.2.4"}};p0();async function $b1(A,Q){let B=await Q.resolvePermissionLevel(A);if(B==="public")return Q.createOperatorLoginRequiredResponse(A);let w=new URL(A.url),$=w.searchParams.get("id")?.trim();if(!$)return new Response("Missing document id",{status:400});let D=await fb1({entityType:"document",id:$,permissionLevel:B,entityService:Q.entityService});if(!D)return new Response("Document not found",{status:404});if(typeof D.content!=="string")return new Response("Document content is not a PDF",{status:415});let f=NN("document",D.content);if(!f)return new Response("Document content is not a PDF",{status:415});let Y=jN(D.metadata,$,"document",f.mimeType);return Yb1({requestUrl:w,data:f.data,mediaType:f.mimeType,filename:Y})}async function Db1(A,Q){let B=await Q.resolvePermissionLevel(A);if(B==="public")return Q.createOperatorLoginRequiredResponse(A);let w=new URL(A.url),$=w.searchParams.get("id")?.trim();if(!$)return new Response("Missing image id",{status:400});let D=await fb1({entityType:"image",id:$,permissionLevel:B,entityService:Q.entityService});if(!D)return new Response("Image not found",{status:404});if(typeof D.content!=="string")return new Response("Image content is not an image",{status:415});let f=NN("image",D.content);if(!f)return new Response("Image content is not an image",{status:415});let Y=jN(D.metadata,$,"image",f.mimeType);return Yb1({requestUrl:w,data:f.data,mediaType:f.mimeType,filename:Y})}async function fb1(A){let Q={entityType:A.entityType,id:A.id},B=await Ax({entityRef:Q,userLevel:A.permissionLevel,getEntity:(w)=>A.entityService.getEntity(w),getVisibleEntity:(w,$)=>A.entityService.getEntity({...w,visibilityScope:$})});return B.status==="visible"?B.entity:void 0}function Yb1(A){let Q=new Headers({"Content-Type":A.mediaType,"Content-Length":String(A.data.byteLength),"Content-Disposition":lI({disposition:A.requestUrl.searchParams.has("download")?"attachment":"inline",filename:A.filename})});return new Response(A.data,{headers:Q})}K0();p0();var Bd="upload",Xb1=nO;var XhQ={namespace:"upload",refKind:Bd,routePath:"/api/chat/uploads"};function O50(){return XhQ}p0();YG0();var Hb1=ee;var Wb1=A00;var HhQ="file",WhQ=16384;async function Zb1(A,Q){if(!await Q.resolveOperatorSession(A))return new Response("Forbidden",{status:403});let B=Number(A.headers.get("content-length"));if(Number.isFinite(B)&&B>Wb1+WhQ)return new Response("File upload too large",{status:400});let w;try{w=await A.formData()}catch{return new Response("Invalid multipart upload",{status:400})}let $=w.get(HhQ);if(!($ instanceof File))return new Response("Missing upload file",{status:400});let D=Buffer.from(await $.arrayBuffer()),f=Uq({filename:$.name,mediaType:$.type,content:D});if(!f.ok)return new Response(f.message,{status:400});let Y=Q.getUploadStore(),X=await Y.save({filename:f.filename,mediaType:f.mediaType,content:D});return Response.json(Y.toResponseBody(X),{status:201})}async function Kb1(A,Q){if(!await Q.resolveOperatorSession(A))return new Response("Forbidden",{status:403});let B=new URL(A.url).searchParams.get("id")?.trim();if(!B)return new Response("Missing upload id",{status:400});let w=await zb1(B,Q.getUploadStore());if(w instanceof Response)return w;let{record:$,content:D}=w,f=qb1($,D);if(f instanceof Response)return f;let Y=new URL(A.url).searchParams.has("download")?"attachment":"inline",X=new Uint8Array(D).buffer;return new Response(X,{headers:{"Content-Type":$.mediaType,"Content-Length":String(D.byteLength),"Content-Disposition":lI({disposition:Y,filename:$.filename})}})}function Ub1(A){let Q=Kq(A.filename??Hb1),B=KhQ(A.url);if(!B)return new Response(`Unsupported file upload URL: ${Q}`,{status:400});let w=Uq({filename:Q,mediaType:A.mediaType,content:B.buffer});if(!w.ok)return new Response(w.message,{status:400});return Fb1(w,B.buffer)}async function Gb1(A,Q){let B=await zb1(A,Q);if(B instanceof Response)return B;let{record:w,content:$}=B,D=qb1(w,$);if(D instanceof Response)return D;return Fb1(D,$,{kind:Bd,id:A})}async function zb1(A,Q){try{return await Q.read(A)}catch(B){if(B instanceof zU)return ZhQ(B);throw B}}function qb1(A,Q){let B=Uq({filename:A.filename,mediaType:A.mediaType,content:Q});if(!B.ok)return new Response(B.message,{status:400});return B}function Fb1(A,Q,B){if(A.kind==="text")return{kind:"text",filename:A.filename,mediaType:A.mediaType,content:A.text,sizeBytes:A.sizeBytes,...B!==void 0?{source:B}:{}};return{kind:"file",filename:A.filename,mediaType:A.mediaType,data:new Uint8Array(Q),sizeBytes:A.sizeBytes,...B!==void 0?{source:B}:{}}}function ZhQ(A){switch(A.code){case"invalid_ref":return new Response("Invalid upload ref",{status:400});case"invalid_metadata":return new Response("Invalid upload metadata",{status:500});case"not_found":return new Response("Upload not found",{status:404})}}function KhQ(A){let Q=/^data:[^,]*,(.*)$/s.exec(A);if(!Q)return null;let w=A.slice(5,A.indexOf(",")).split(";").some(($)=>$.toLowerCase()==="base64");try{let $=w?Buffer.from(Q[1]??"","base64"):Buffer.from(decodeURIComponent(Q[1]??""),"utf8");return{buffer:$,byteLength:$.byteLength}}catch{return null}}var UhQ=K.object({type:K.literal("text"),text:K.string()}),GhQ=K.object({type:K.literal("file"),mediaType:K.string().optional(),filename:K.string().optional(),url:K.string()}),zhQ=K.object({state:K.literal("approval-responded"),approval:K.object({id:K.string(),approved:K.boolean()})}).passthrough(),qhQ=K.object({id:K.string().optional(),role:K.string(),parts:K.array(K.unknown()).optional(),content:K.string().optional()}),Ib1=K.object({id:K.string().optional(),messages:K.array(qhQ).min(1),trigger:K.string().optional()}),FhQ=K.object({kind:K.literal(Bd),id:K.string().regex(Xb1)}),IhQ=K.object({type:K.literal("data-upload"),data:K.object({ref:FhQ})});async function Vb1(A,Q){let B=VhQ(A);if(!B)return{message:"",attachments:[]};let w=[],$=[];for(let f of B.parts??[]){let Y=UhQ.safeParse(f);if(Y.success){if(Y.data.text.length>0)w.push(Y.data.text);continue}let X=GhQ.safeParse(f);if(X.success){let W=Ub1(X.data);if(W instanceof Response)return W;$.push(W);continue}let H=IhQ.safeParse(f);if(H.success){let W=await Gb1(H.data.data.ref.id,Q.uploadStore);if(W instanceof Response)return W;$.push(W);continue}if(JhQ(f)==="data-upload")return new Response("Invalid upload ref",{status:400})}return{message:w.length>0?w.join(`
|
|
2573
2573
|
|
|
2574
2574
|
`):B.content??"",attachments:$,...B.id?{messageId:B.id}:{}}}function Jb1(A){let Q=A.messages.at(-1);if(!Q||Q.role==="user")return[];return(Q.parts??[]).map((B)=>zhQ.safeParse(B)).filter((B)=>B.success).map((B)=>B.data.approval)}function VhQ(A){for(let Q=A.messages.length-1;Q>=0;Q-=1){let B=A.messages[Q];if(B?.role==="user")return B}return}function JhQ(A){if(typeof A!=="object"||A===null||!("type"in A))return;let Q=A.type;return typeof Q==="string"?Q:void 0}p0();var LhQ=/\n{0,2}\[Entities affected this turn: [\s\S]*? Reference these IDs directly in follow-ups instead of searching for them\.\]\s*$/;function x50(A){return A.replace(LhQ,"").trimEnd()}p0();function Lb1(A,Q,B){A.write({type:"text-start",id:Q}),A.write({type:"text-delta",id:Q,delta:B}),A.write({type:"text-end",id:Q})}function Zg0(A,Q){for(let B of Q){let w=Y00(B);if(w.kind==="attachment"){A.write({type:"data-attachment",id:w.id,data:w});continue}if(w.kind==="sources"){A.write({type:"data-sources",id:w.id,data:w});continue}if(w.kind==="actions"){A.write({type:"data-actions",id:w.id,data:w});continue}let $=w.toolCallId??w.id,D=w.input??{};switch(A.write({type:"tool-input-available",toolCallId:$,toolName:w.toolName,input:D,dynamic:!0,title:w.preview?`${w.summary}
|
|
2575
2575
|
|
|
@@ -4868,7 +4868,7 @@ details.web-chat-data-part[open] > summary > .web-chat-data-part-chevron {
|
|
|
4868
4868
|
|
|
4869
4869
|
`);$=f.pop()??"";for(let Y of f){let X=Y.split(`
|
|
4870
4870
|
`).find((b)=>b.startsWith("data: "));if(!X)continue;let H;try{H=JSON.parse(X.slice(6))}catch{return B.cancel().catch(()=>{}),{success:!1,error:"Malformed SSE event from remote agent"}}let W=H.result;if(!W)continue;if(W.final!==!0)continue;B.cancel().catch(()=>{});let G=W.status,F=G?.state??"unknown",L=(G?.message?.parts??[]).filter((b)=>b.kind==="text"&&typeof b.text==="string").map((b)=>b.text).join(`
|
|
4871
|
-
`)||"No response text";return{success:!0,data:{state:F,response:L}}}D=await db1(B,Q)}return{success:!1,error:"Stream ended without a terminal event"}}class wd extends Error{timeoutMs;constructor(A){super(`request timed out after ${A}ms`);this.timeoutMs=A;this.name="A2ARequestTimeoutError"}}class $d extends Error{timeoutMs;constructor(A){super(`A2A stream stalled waiting for final event after ${A}ms`);this.timeoutMs=A;this.name="A2AStreamIdleTimeoutError"}}async function ohQ(A,Q,B,w){let $=new AbortController,D;try{return await Promise.race([A(Q,{...B,signal:$.signal}),new Promise((f,Y)=>{D=setTimeout(()=>{$.abort(),Y(new wd(w))},w)})])}catch(f){if(f instanceof wd)throw f;if($.signal.aborted)throw new wd(w);throw f}finally{if(D)clearTimeout(D)}}async function db1(A,Q){let B;try{return await Promise.race([A.read(),new Promise((w,$)=>{B=setTimeout(()=>$(new $d(Q)),Q)})])}catch(w){if(w instanceof $d)A.cancel().catch(()=>{});throw w}finally{if(B)clearTimeout(B)}}function shQ(A){if(A instanceof wd||A instanceof $d)return!0;return A instanceof Error}function ahQ(A,Q){let B=Q>1?` after ${Q} attempts`:"";if(A instanceof $d)return`${A.message}${B}`;let w=A instanceof Error?A.message:"Unknown network error";return`Failed to reach remote agent${B}: ${w}`}function rb1(A={}){let Q=A.fetch??globalThis.fetch,B={requestTimeoutMs:A.requestTimeoutMs??chQ,streamIdleTimeoutMs:A.streamIdleTimeoutMs??lhQ,maxNetworkAttempts:A.maxNetworkAttempts??phQ};return{name:"a2a_call",description:"Call a saved remote A2A agent by its local directory id. Use this when the user asks what a saved agent has to say or asks a saved agent for its skills/capabilities. Use only a saved agent id such as yeehaa.io or docs.rizom.ai. For follow-ups to a prior exact-id call, call again with the same id so the tool revalidates current directory state. Never pass a display name like Brain, never pass a full URL, and do not use this tool to probe whether an agent exists. If the user gives a URL, an unsaved agent, or an ambiguous name, ask them to add/save or clarify the agent first.",inputSchema:ib1,visibility:"anchor",handler:async(w)=>{let $=K.object(ib1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};let{agent:D,message:f}=$.data,Y=ihQ(D);if(!Y)return{success:!1,error:"Invalid agent id. Use a saved agent id from your directory, not a URL."};if(!A.entityService)return{success:!1,error:"Agent directory is unavailable. Add the agent first, then try again."};let X=await A.entityService.getEntity({entityType:"agent",id:Y,visibilityScope:x9("a2a_call tool is anchor-only and resolves saved remote agents at any visibility")});if(!X)return{success:!1,error:`Agent ${Y} is not in your directory. Add it first.`};if(X.metadata.status!=="approved")return{success:!1,error:`Agent ${Y} is discovered but not approved yet. Approve it first.`};let H=`https://${Y}`,W=await dhQ(H,Q);if(!W)return{success:!1,error:`Could not fetch Agent Card from ${H}`};let Z=W.url,G;if(A.outboundTokens)try{let F=new URL(Z).hostname;G=A.outboundTokens[F]}catch{}return nhQ(Z,f,Q,G,B)}}}var Vg0={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.128",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"}};var ehQ={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","X-Content-Type-Options":"nosniff"};class yC extends GU{agentCard;taskManager=new Fg0;agentService;permissionContext;app;hasWebserver=!1;constructor(A={}){super("a2a",Vg0,A,gb1)}async onRegister(A){if(await super.onRegister(A),this.hasWebserver=A.plugins.has("webserver"),this.agentService=A.agent,this.permissionContext=A.permissions,this.hasWebserver)A.endpoints.register({label:"A2A",url:"/a2a",priority:25}),A.interactions.register({id:"a2a",label:"A2A",description:"Let other agents discover and talk to this brain.",href:"/a2a",kind:"agent",priority:25}),this.logger.info("A2A interface registered",{domain:A.domain});else this.logger.info("A2A interface registered in tool-only mode",{domain:A.domain})}async onReady(A){await this.rebuildAgentCard(A)}async rebuildAgentCard(A){let Q=A.identity.get(),B=A.identity.getProfile(),w=A.tools.listForPermissionLevel("public"),$=this.config.trustedTokens&&Object.keys(this.config.trustedTokens).length>0,D;if(A.entityService.hasEntityType("skill"))try{let f=await A.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}});if(f.length>0)D=f.map((Y)=>_Y.safeParse(Y.metadata)).filter((Y)=>Y.success).map((Y)=>Y.data)}catch{}this.agentCard=Tb1({character:Q,profile:B,version:Vg0.version,domain:A.domain,organization:this.config.organization,tools:w,skills:D,authEnabled:$}),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 Q=A.slice(7),B=this.config.trustedTokens[Q];if(!B||!this.permissionContext)return"public";return this.permissionContext.getUserLevel("a2a",B)}withCors(A){let Q=new Headers(A.headers);for(let[B,w]of Object.entries(ehQ))Q.set(B,w);return new Response(A.body,{status:A.status,statusText:A.statusText,headers:Q})}getOrCreateApp(){if(this.app)return this.app;let A=new OC;return A.get("/.well-known/agent-card.json",(Q)=>{if(!this.agentCard)return this.withCors(Q.json({error:"Agent Card not ready"},503));return this.withCors(Q.json(this.agentCard))}),A.get("/a2a",(Q)=>{return this.withCors(Q.json({error:"Use POST with JSON-RPC 2.0 requests.",agentCard:"/.well-known/agent-card.json"},405))}),A.options("/a2a",()=>this.withCors(new Response(null,{status:204}))),A.post("/a2a",async(Q)=>{if(!this.agentService)return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503));let B;try{B=await Q.req.json()}catch{return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null}))}let w=ub1.safeParse(B);if(!w.success)return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null}));let $=this.resolveCallerPermission(Q.req.header("Authorization"));if(w.data.method==="message/stream"){let f=lb1.safeParse(w.data.params??{});if(!f.success)return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${f.error.message}`},id:w.data.id}));let{stream:Y}=pb1(w.data.id,f.data.message,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:$});return this.withCors(new Response(Y,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}))}let D=await cb1(w.data,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:$});return this.withCors(Q.json(D))}),this.app=A,A}getWebRoutes(){if(!this.hasWebserver)return[];let A=(Q)=>Promise.resolve(this.getOrCreateApp().fetch(Q));return[{path:"/.well-known/agent-card.json",method:"GET",public:!0,handler:A},{path:"/a2a",method:"GET",public:!0,handler:A},{path:"/a2a",method:"POST",public:!0,handler:A},{path:"/a2a",method:"OPTIONS",public:!0,handler:A}]}async getTools(){return[rb1({outboundTokens:this.config.outboundTokens,requestTimeoutMs:this.config.requestTimeoutMs,streamIdleTimeoutMs:this.config.streamIdleTimeoutMs,maxNetworkAttempts:this.config.maxNetworkAttempts,entityService:this.getContext().entityService})]}async getInstructions(){return"## Agent-to-agent calls\n- Use `a2a_call` only for agents already saved in the local `agent` directory.\n- Pass only the saved local agent id to `a2a_call` (for example `yeehaa.io` or `docs.rizom.ai`). Never pass a full URL or a display name like `Brain`.\n- If the user names an exact saved local agent id such as `yeehaa.io` or `docs.rizom.ai`, call `a2a_call` directly with that id. Do not preflight with `system_list` or `system_get`; the tool validates saved/approved status and reports errors.\n- If the user asks you to ask, message, contact, hear what a saved agent has to say, or ask a saved agent for its own skills/capabilities, treat that as an agent-directory request first and call `a2a_call` in the same turn. Do not stop after listing the agent, drafting the question, searching general content locally, or reading the saved agent entity metadata.\n- After `a2a_call` returns within a turn, answer that turn from its response. Do **not** supplement with `system_get` (or any other read tool) on the agent entity, unless the user explicitly asks for directory/profile details about the agent itself.\n- Do not create, capture, or generate a note containing the user's question in the same turn as a saved-agent contact request. The user asked to ask the saved agent, not to persist the question.\n- If `a2a_call` fails because auth, re-authentication, network, or the remote agent is unavailable, report that failure directly. Do not answer from memory, local docs, onboarding docs, or general knowledge; the saved agent was the requested source.\n- Each new turn that asks the same saved agent something \u2014 including short follow-ups like \"what skills does it have\", \"and what about X\", \"tell me more\" \u2014 is a **new** contact request and needs its **own** fresh `a2a_call`. Do not assume the previous turn's a2a response already covers a new question, and do not substitute `system_list`/`system_get` or a no-tool answer for the fresh call. If the previous turn targeted an exact saved local id such as `yeehaa.io`, use that same id again for the follow-up even if the previous response was a refusal or error; let `a2a_call` validate the current directory state again.\n- If the user gives a full URL for an agent, do not pass that URL to `a2a_call`. Use a saved local agent id only. If that URL is not already saved in the local directory, tell the user to add it first.\n- If the user refers to an agent by name, first make sure that name resolves to exactly one saved agent id. If multiple saved agents could match, ask a concise clarification question naming the matching saved agent ids and do not call any agent yet. Never choose the first match.\n- After asking that clarification question, end the turn. Do not call `a2a_call` later in the same turn.\n- If the target agent is not in the directory, do not create a wish, reminder, todo, note, fallback task, or any new entity. Tell the user to add it first.\n- In these invalid agent-target cases, do not call any tool unless the user explicitly asks you to add/save the agent.\n- Only use creation tools for an agent if the user explicitly asks you to add or save that agent.\n- If the target agent is discovered but not approved yet, do not call it and do not create a wish. Tell the user it must be approved first."}createDaemon(){return{start:async()=>{if(this.hasWebserver)this.logger.info("A2A mounted on shared webserver host");else this.logger.info("A2A running without webserver routes")},stop:async()=>{this.logger.info("A2A server stopped")}}}}p0();class Jg0{logger;handleImport;handleDelete;deleteOnFileRemoval;fileOperations;constructor(A,Q,B,w,$=!0){if(this.logger=A,this.fileOperations=w,this.deleteOnFileRemoval=$,B)this.handleImport=async(D)=>{let f=await B({type:"directory-import",data:{paths:[D]}});this.logger.debug("Queued import job for file change",{jobId:f,path:D})},this.handleDelete=async(D)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:D});return}try{let{entityType:f,id:Y}=this.fileOperations.parseEntityFromPath(D),X=await B({type:"directory-delete",data:{entityId:Y,entityType:f,filePath:D}});this.logger.info("Queued delete job for removed file",{jobId:X,path:D,entityId:Y,entityType:f})}catch(f){this.logger.warn("Could not extract entity info from deleted file",{path:D,error:f})}};else this.handleImport=async(D)=>{await Q([D])},this.handleDelete=async(D)=>{this.logger.warn("File deleted but no job queue available",{path:D})}}async handleFileChange(A,Q){this.logger.debug("Processing file change",{event:A,path:Q});try{switch(A){case"add":case"change":await this.handleImport(Q);break;case"delete":case"unlink":await this.handleDelete(Q);break;default:this.logger.debug("Unhandled file event",{event:A,path:Q})}}catch(B){this.logger.error("Failed to handle file change",{event:A,path:Q,error:B})}}}var K_1=f1(H_1(),1);import{extname as aTQ}from"path";var a50=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function zM(A){let Q=aTQ(A).toLowerCase();return a50.includes(Q)}function W_1(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 VT0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}import{isAbsolute as tTQ,relative as eTQ,sep as Z_1,join as ASQ}from"path";function sH(A,Q){return tTQ(Q)?Q:ASQ(A,Q)}function cC(A,Q){let B=sH(A,Q),w=eTQ(A,B);return Z_1==="/"?w:w.split(Z_1).join("/")}function QSQ(A,Q){if(!cC(Q,A).startsWith("image/"))return!1;return zM(A)}function BSQ(A,Q){if(cC(Q,A).split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return QSQ(A,Q)}class JT0{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=K_1.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,Q){if(!BSQ(Q,this.syncPath))return;this.logger.debug("File change detected",{event:A,path:Q});let B=cC(this.syncPath,Q);if(this.pendingChanges.set(B,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[Q,B]of A){let w=sH(this.syncPath,Q);try{if(this.onFileChange)await this.onFileChange(B,w)}catch($){this.logger.error("Error processing file change",{path:Q,event:B,error:$})}}}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}async function U_1(A,Q){if(A?.isWatching())return Q.logger.debug("Already watching directory"),A;return wSQ(Q)}function G_1(A){if(A)A.stop();return}function z_1(A,Q){if(A)A.setCallback(Q)}async function wSQ(A){let{logger:Q,syncPath:B,watchInterval:w,importEntities:$,jobQueueCallback:D,fileOperations:f,deleteOnFileRemoval:Y}=A,X=new Jg0(Q,$,D,f,Y),H=new JT0({syncPath:B,watchInterval:w,logger:Q,onFileChange:async(W,Z)=>{await X.handleFileChange(W,Z)}});return await H.start(),H}async function q_1(A){let Q=Date.now();A.logger.debug("Starting sync (import only)");let B=await A.importEntities(),w=await A.removeOrphanedEntities(),$=Date.now()-Q;return A.markSynced(new Date),A.logger.debug("Sync completed",{duration:$,imported:B.imported,orphansDeleted:w.deleted}),{export:{exported:0,failed:0,errors:[]},import:B,duration:$}}p0();class LT0{logger;syncPath;deleteOnFileRemoval;constructor(A){this.logger=A.logger,this.syncPath=A.syncPath,this.deleteOnFileRemoval=A.deleteOnFileRemoval}prepareBatchOperations(A){let Q=[],B=this.createImportOperations(A);Q.push(...B);let w=B.length;if(this.deleteOnFileRemoval)Q.push({type:"directory-cleanup",data:{}});let $=A.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:w,totalFiles:$}),{operations:Q,exportOperationsCount:0,importOperationsCount:w,totalFiles:$}}async queueSyncBatch(A,Q,B,w){let $=this.prepareBatchOperations(B);if($.operations.length===0)return this.logger.debug("No sync operations needed",{source:Q}),null;return{batchId:await A.jobs.enqueueBatch($.operations,{source:Q,rootJobId:w?.rootJobId??S$(),metadata:{progressToken:w?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:w?.pluginId??"directory-sync",interfaceType:w?.interfaceType,channelId:w?.channelId}}),operationCount:$.operations.length,exportOperationsCount:$.exportOperationsCount,importOperationsCount:$.importOperationsCount,totalFiles:$.totalFiles}}createImportOperations(A){if(A.length===0)return[];let Q=50,B=[];for(let w=0;w<A.length;w+=Q){let $=A.slice(w,w+Q);B.push({type:"directory-import",data:{batchIndex:Math.floor(w/Q),paths:$,batchSize:$.length}})}return B}}class bT0{syncInProgress=!1;logger;fileOperations;batchOperationsManager;constructor(A){this.logger=A.logger,this.fileOperations=A.fileOperations,this.batchOperationsManager=new LT0({logger:A.logger,syncPath:A.syncPath,deleteOnFileRemoval:A.deleteOnFileRemoval})}async queueSyncBatch(A,Q,B){if(this.syncInProgress)return this.logger.debug("Sync already in progress, skipping",{source:Q}),null;this.syncInProgress=!0;try{let w=await this.fileOperations.getAllSyncFiles();return await this.batchOperationsManager.queueSyncBatch(A,Q,w,B)}finally{this.syncInProgress=!1}}}class NT0{options;constructor(A){this.options=A}createExportDeps(A,Q){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:A,entityTypes:Q}}createImportDeps(A){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,quarantine:this.options.quarantine,imageJobQueue:this.createImageJobQueueDeps(),entityTypes:A}}createCleanupDeps(A,Q){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:A,entityTypes:Q}}createImageJobQueueDeps(){return{logger:this.options.logger,syncPath:this.options.syncPath,jobQueueCallback:this.options.getJobQueueCallback(),coverImageConverter:this.options.coverImageConverter,inlineImageConverter:this.options.inlineImageConverter}}}import{basename as HSQ,dirname as WSQ,extname as ZSQ}from"path";import{extname as $SQ}from"path";var t50=[".pdf"],F_1=".meta.json";function qM(A){let Q=$SQ(A).toLowerCase();return t50.includes(Q)}function I_1(A){return A.toLowerCase().endsWith(F_1)}function jT0(A){return`${A}${F_1}`}function V_1(A){switch(A.toLowerCase().replace(".","")){case"pdf":default:return"application/pdf"}}import{extname as DSQ,join as e50}from"path";function A$0(A,Q){let w=cC(A,Q).split("/"),$,D;if(w.length===1)$="note",D=w;else if(w.length>1&&w[0])$=w[0],D=w.slice(1);else $="note",D=w;let f;if(D.length>1){let Y=D[D.length-1];if(Y)D[D.length-1]=J_1(Y);f=D.join(":")}else f=J_1(D[0]??"");return{entityType:$,id:f}}function L_1(A,Q,B,w=".md"){let $=Q.split(":").filter((H)=>H.length>0),D=B==="note";if($.length===1)return D?e50(A,`${$[0]}${w}`):e50(A,B,`${$[0]}${w}`);let f=$;if($[0]===B)f=$.slice(1);let Y=f[f.length-1],X=f.slice(0,-1);if(D)return e50(A,...X,`${Y}${w}`);return e50(A,B,...X,`${Y}${w}`)}function b_1(A){if(A.entityType==="document")return".pdf";if(A.entityType!=="image")return".md";let Q=A.metadata.format;if(Q)return VT0(Q);let B=A.content.match(/^data:image\/([a-z+]+);base64,/i);return B?.[1]?VT0(B[1]):".md"}function J_1(A){let Q=DSQ(A).toLowerCase();return Q===".md"||a50.includes(Q)||t50.includes(Q)?A.slice(0,-Q.length):A}bY();import{mkdir as KSQ,readFile as lC,writeFile as MT0,stat as USQ,utimes as GSQ}from"fs/promises";import{join as Q$0}from"path";import{mkdir as N_1,readdir as YSQ,stat as XSQ}from"fs/promises";import{access as fSQ}from"fs/promises";async function y5(A){try{return await fSQ(A),!0}catch{return!1}}async function _T0(A,Q){return P_1(A,Q,{includeDocuments:!1,includeImages:!1})}async function j_1(A,Q){return P_1(A,Q,{includeDocuments:!0,includeImages:!0})}async function __1(A,Q){if(!await y5(A))await N_1(A,{recursive:!0});for(let B of Q)if(B!=="note")await N_1(Q$0(A,B),{recursive:!0})}async function M_1(A,Q){let B=[],w={totalFiles:0,byEntityType:{}};if(!await y5(A))return{files:B,stats:w};let $=await _T0(A,Q);for(let D of $)try{let f=Q$0(A,D),Y=await XSQ(f),{entityType:X}=A$0(A,D);B.push({path:D,entityType:X,modified:Y.mtime}),w.totalFiles++,w.byEntityType[X]=(w.byEntityType[X]??0)+1}catch{continue}return{files:B,stats:w}}async function P_1(A,Q,B){let w=[];if(!await y5(A))return w;let $=async(D,f="",Y=!1,X=!1)=>{let H=await YSQ(D,{withFileTypes:!0});for(let W of H){let Z=f?Q$0(f,W.name):W.name;if(W.isFile()&&!W.name.endsWith(".invalid")&&!I_1(W.name)){if(W.name.endsWith(".md"))w.push(Z);else if(B.includeImages&&Y&&zM(W.name))w.push(Z);else if(B.includeDocuments&&X&&qM(W.name))w.push(Z)}else if(W.isDirectory()&&!W.name.startsWith(".")){if(f===""&&!Q.hasEntityType(W.name))continue;let G=Q$0(D,W.name),F=W.name==="image"&&f==="",I=W.name==="document"&&f==="";await $(G,Z,Y||F,X||I)}}};return await $(A),w}function zSQ(A){return typeof A==="object"&&A!==null}class PT0{syncPath;entityService;constructor(A,Q){this.syncPath=A,this.entityService=Q}parseEntityFromPath(A){return A$0(this.syncPath,A)}async readEntity(A){let Q=sH(this.syncPath,A),B=await USQ(Q),{entityType:w,id:$}=this.parseEntityFromPath(A),D=B.birthtime.getTime()>0?B.birthtime:B.mtime,f=B.mtime,Y,X;if(zM(A)||qM(A)){let Z=(await lC(Q)).toString("base64"),G=ZSQ(A);if(Y=`data:${qM(A)?V_1(G):W_1(G)};base64,${Z}`,qM(A))X=await this.readDocumentSidecar(Q,A)}else Y=await lC(Q,"utf-8");let H={entityType:w,id:$,content:Y,created:D,updated:f};if(X)H.metadata=X;return H}async readDocumentSidecar(A,Q){let B={mimeType:"application/pdf",filename:HSQ(Q)},w=jT0(A);if(!await y5(w))return B;try{let $=await lC(w,"utf-8"),D=JSON.parse($),f=zSQ(D)?D:{};return{...B,...f}}catch{return B}}async writeEntity(A){let Q=this.getEntityFilePath(A),B=A.entityType==="image",w=A.entityType==="document";if(B||w){let D=B?/^data:image\/[a-z+]+;base64,(.+)$/i:/^data:application\/pdf;base64,(.+)$/i,f=A.content.match(D),Y=f?.[1]?Buffer.from(f[1],"base64"):Buffer.from(A.content,"base64"),X=!1;if(await y5(Q)){let H=await lC(Q),W=RB(H.toString("base64")),Z=RB(Y.toString("base64"));if(W===Z)X=!0}if(!X)await this.ensureEntityDirectory(A,Q),await MT0(Q,Y);if(w)await this.writeDocumentSidecar(A,Q);if(X)return}else{let D=this.entityService.serializeEntity(A);if(await y5(Q)){let f=await lC(Q,"utf-8"),Y=RB(f),X=RB(D);if(Y===X)return}await this.ensureEntityDirectory(A,Q),await MT0(Q,D,"utf-8")}let $=new Date(A.updated);await GSQ(Q,$,$)}async ensureEntityDirectory(A,Q){if(A.entityType!=="note")await KSQ(WSQ(Q),{recursive:!0})}async writeDocumentSidecar(A,Q){let B=A.metadata,w={};for(let[f,Y]of Object.entries(B)){if(f==="mimeType")continue;if(Y===void 0)continue;w[f]=Y}let $=jT0(Q),D=`${JSON.stringify(w,null,2)}
|
|
4871
|
+
`)||"No response text";return{success:!0,data:{state:F,response:L}}}D=await db1(B,Q)}return{success:!1,error:"Stream ended without a terminal event"}}class wd extends Error{timeoutMs;constructor(A){super(`request timed out after ${A}ms`);this.timeoutMs=A;this.name="A2ARequestTimeoutError"}}class $d extends Error{timeoutMs;constructor(A){super(`A2A stream stalled waiting for final event after ${A}ms`);this.timeoutMs=A;this.name="A2AStreamIdleTimeoutError"}}async function ohQ(A,Q,B,w){let $=new AbortController,D;try{return await Promise.race([A(Q,{...B,signal:$.signal}),new Promise((f,Y)=>{D=setTimeout(()=>{$.abort(),Y(new wd(w))},w)})])}catch(f){if(f instanceof wd)throw f;if($.signal.aborted)throw new wd(w);throw f}finally{if(D)clearTimeout(D)}}async function db1(A,Q){let B;try{return await Promise.race([A.read(),new Promise((w,$)=>{B=setTimeout(()=>$(new $d(Q)),Q)})])}catch(w){if(w instanceof $d)A.cancel().catch(()=>{});throw w}finally{if(B)clearTimeout(B)}}function shQ(A){if(A instanceof wd||A instanceof $d)return!0;return A instanceof Error}function ahQ(A,Q){let B=Q>1?` after ${Q} attempts`:"";if(A instanceof $d)return`${A.message}${B}`;let w=A instanceof Error?A.message:"Unknown network error";return`Failed to reach remote agent${B}: ${w}`}function rb1(A={}){let Q=A.fetch??globalThis.fetch,B={requestTimeoutMs:A.requestTimeoutMs??chQ,streamIdleTimeoutMs:A.streamIdleTimeoutMs??lhQ,maxNetworkAttempts:A.maxNetworkAttempts??phQ};return{name:"a2a_call",description:"Call a saved remote A2A agent by its local directory id. Use this when the user asks what a saved agent has to say or asks a saved agent for its skills/capabilities. Use only a saved agent id such as yeehaa.io or docs.rizom.ai. For follow-ups to a prior exact-id call, call again with the same id so the tool revalidates current directory state. Never pass a display name like Brain, never pass a full URL, and do not use this tool to probe whether an agent exists. If the user gives a URL, an unsaved agent, or an ambiguous name, ask them to add/save or clarify the agent first.",inputSchema:ib1,visibility:"anchor",handler:async(w)=>{let $=K.object(ib1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};let{agent:D,message:f}=$.data,Y=ihQ(D);if(!Y)return{success:!1,error:"Invalid agent id. Use a saved agent id from your directory, not a URL."};if(!A.entityService)return{success:!1,error:"Agent directory is unavailable. Add the agent first, then try again."};let X=await A.entityService.getEntity({entityType:"agent",id:Y,visibilityScope:x9("a2a_call tool is anchor-only and resolves saved remote agents at any visibility")});if(!X)return{success:!1,error:`Agent ${Y} is not in your directory. Add it first.`};if(X.metadata.status!=="approved")return{success:!1,error:`Agent ${Y} is discovered but not approved yet. Approve it first.`};let H=`https://${Y}`,W=await dhQ(H,Q);if(!W)return{success:!1,error:`Could not fetch Agent Card from ${H}`};let Z=W.url,G;if(A.outboundTokens)try{let F=new URL(Z).hostname;G=A.outboundTokens[F]}catch{}return nhQ(Z,f,Q,G,B)}}}var Vg0={name:"@brains/a2a",private:!0,version:"0.2.0-alpha.129",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"}};var ehQ={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","X-Content-Type-Options":"nosniff"};class yC extends GU{agentCard;taskManager=new Fg0;agentService;permissionContext;app;hasWebserver=!1;constructor(A={}){super("a2a",Vg0,A,gb1)}async onRegister(A){if(await super.onRegister(A),this.hasWebserver=A.plugins.has("webserver"),this.agentService=A.agent,this.permissionContext=A.permissions,this.hasWebserver)A.endpoints.register({label:"A2A",url:"/a2a",priority:25}),A.interactions.register({id:"a2a",label:"A2A",description:"Let other agents discover and talk to this brain.",href:"/a2a",kind:"agent",priority:25}),this.logger.info("A2A interface registered",{domain:A.domain});else this.logger.info("A2A interface registered in tool-only mode",{domain:A.domain})}async onReady(A){await this.rebuildAgentCard(A)}async rebuildAgentCard(A){let Q=A.identity.get(),B=A.identity.getProfile(),w=A.tools.listForPermissionLevel("public"),$=this.config.trustedTokens&&Object.keys(this.config.trustedTokens).length>0,D;if(A.entityService.hasEntityType("skill"))try{let f=await A.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}});if(f.length>0)D=f.map((Y)=>_Y.safeParse(Y.metadata)).filter((Y)=>Y.success).map((Y)=>Y.data)}catch{}this.agentCard=Tb1({character:Q,profile:B,version:Vg0.version,domain:A.domain,organization:this.config.organization,tools:w,skills:D,authEnabled:$}),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 Q=A.slice(7),B=this.config.trustedTokens[Q];if(!B||!this.permissionContext)return"public";return this.permissionContext.getUserLevel("a2a",B)}withCors(A){let Q=new Headers(A.headers);for(let[B,w]of Object.entries(ehQ))Q.set(B,w);return new Response(A.body,{status:A.status,statusText:A.statusText,headers:Q})}getOrCreateApp(){if(this.app)return this.app;let A=new OC;return A.get("/.well-known/agent-card.json",(Q)=>{if(!this.agentCard)return this.withCors(Q.json({error:"Agent Card not ready"},503));return this.withCors(Q.json(this.agentCard))}),A.get("/a2a",(Q)=>{return this.withCors(Q.json({error:"Use POST with JSON-RPC 2.0 requests.",agentCard:"/.well-known/agent-card.json"},405))}),A.options("/a2a",()=>this.withCors(new Response(null,{status:204}))),A.post("/a2a",async(Q)=>{if(!this.agentService)return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32603,message:"Agent service not ready"},id:null},503));let B;try{B=await Q.req.json()}catch{return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32700,message:"Parse error"},id:null}))}let w=ub1.safeParse(B);if(!w.success)return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid request"},id:null}));let $=this.resolveCallerPermission(Q.req.header("Authorization"));if(w.data.method==="message/stream"){let f=lb1.safeParse(w.data.params??{});if(!f.success)return this.withCors(Q.json({jsonrpc:"2.0",error:{code:-32602,message:`Invalid params: ${f.error.message}`},id:w.data.id}));let{stream:Y}=pb1(w.data.id,f.data.message,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:$});return this.withCors(new Response(Y,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}}))}let D=await cb1(w.data,{taskManager:this.taskManager,agentService:this.agentService,callerPermissionLevel:$});return this.withCors(Q.json(D))}),this.app=A,A}getWebRoutes(){if(!this.hasWebserver)return[];let A=(Q)=>Promise.resolve(this.getOrCreateApp().fetch(Q));return[{path:"/.well-known/agent-card.json",method:"GET",public:!0,handler:A},{path:"/a2a",method:"GET",public:!0,handler:A},{path:"/a2a",method:"POST",public:!0,handler:A},{path:"/a2a",method:"OPTIONS",public:!0,handler:A}]}async getTools(){return[rb1({outboundTokens:this.config.outboundTokens,requestTimeoutMs:this.config.requestTimeoutMs,streamIdleTimeoutMs:this.config.streamIdleTimeoutMs,maxNetworkAttempts:this.config.maxNetworkAttempts,entityService:this.getContext().entityService})]}async getInstructions(){return"## Agent-to-agent calls\n- Use `a2a_call` only for agents already saved in the local `agent` directory.\n- Pass only the saved local agent id to `a2a_call` (for example `yeehaa.io` or `docs.rizom.ai`). Never pass a full URL or a display name like `Brain`.\n- If the user names an exact saved local agent id such as `yeehaa.io` or `docs.rizom.ai`, call `a2a_call` directly with that id. Do not preflight with `system_list` or `system_get`; the tool validates saved/approved status and reports errors.\n- If the user asks you to ask, message, contact, hear what a saved agent has to say, or ask a saved agent for its own skills/capabilities, treat that as an agent-directory request first and call `a2a_call` in the same turn. Do not stop after listing the agent, drafting the question, searching general content locally, or reading the saved agent entity metadata.\n- After `a2a_call` returns within a turn, answer that turn from its response. Do **not** supplement with `system_get` (or any other read tool) on the agent entity, unless the user explicitly asks for directory/profile details about the agent itself.\n- Do not create, capture, or generate a note containing the user's question in the same turn as a saved-agent contact request. The user asked to ask the saved agent, not to persist the question.\n- If `a2a_call` fails because auth, re-authentication, network, or the remote agent is unavailable, report that failure directly. Do not answer from memory, local docs, onboarding docs, or general knowledge; the saved agent was the requested source.\n- Each new turn that asks the same saved agent something \u2014 including short follow-ups like \"what skills does it have\", \"and what about X\", \"tell me more\" \u2014 is a **new** contact request and needs its **own** fresh `a2a_call`. Do not assume the previous turn's a2a response already covers a new question, and do not substitute `system_list`/`system_get` or a no-tool answer for the fresh call. If the previous turn targeted an exact saved local id such as `yeehaa.io`, use that same id again for the follow-up even if the previous response was a refusal or error; let `a2a_call` validate the current directory state again.\n- If the user gives a full URL for an agent, do not pass that URL to `a2a_call`. Use a saved local agent id only. If that URL is not already saved in the local directory, tell the user to add it first.\n- If the user refers to an agent by name, first make sure that name resolves to exactly one saved agent id. If multiple saved agents could match, ask a concise clarification question naming the matching saved agent ids and do not call any agent yet. Never choose the first match.\n- After asking that clarification question, end the turn. Do not call `a2a_call` later in the same turn.\n- If the target agent is not in the directory, do not create a wish, reminder, todo, note, fallback task, or any new entity. Tell the user to add it first.\n- In these invalid agent-target cases, do not call any tool unless the user explicitly asks you to add/save the agent.\n- Only use creation tools for an agent if the user explicitly asks you to add or save that agent.\n- If the target agent is discovered but not approved yet, do not call it and do not create a wish. Tell the user it must be approved first."}createDaemon(){return{start:async()=>{if(this.hasWebserver)this.logger.info("A2A mounted on shared webserver host");else this.logger.info("A2A running without webserver routes")},stop:async()=>{this.logger.info("A2A server stopped")}}}}p0();class Jg0{logger;handleImport;handleDelete;deleteOnFileRemoval;fileOperations;constructor(A,Q,B,w,$=!0){if(this.logger=A,this.fileOperations=w,this.deleteOnFileRemoval=$,B)this.handleImport=async(D)=>{let f=await B({type:"directory-import",data:{paths:[D]}});this.logger.debug("Queued import job for file change",{jobId:f,path:D})},this.handleDelete=async(D)=>{if(!this.deleteOnFileRemoval){this.logger.warn("File deleted but deleteOnFileRemoval is disabled",{path:D});return}try{let{entityType:f,id:Y}=this.fileOperations.parseEntityFromPath(D),X=await B({type:"directory-delete",data:{entityId:Y,entityType:f,filePath:D}});this.logger.info("Queued delete job for removed file",{jobId:X,path:D,entityId:Y,entityType:f})}catch(f){this.logger.warn("Could not extract entity info from deleted file",{path:D,error:f})}};else this.handleImport=async(D)=>{await Q([D])},this.handleDelete=async(D)=>{this.logger.warn("File deleted but no job queue available",{path:D})}}async handleFileChange(A,Q){this.logger.debug("Processing file change",{event:A,path:Q});try{switch(A){case"add":case"change":await this.handleImport(Q);break;case"delete":case"unlink":await this.handleDelete(Q);break;default:this.logger.debug("Unhandled file event",{event:A,path:Q})}}catch(B){this.logger.error("Failed to handle file change",{event:A,path:Q,error:B})}}}var K_1=f1(H_1(),1);import{extname as aTQ}from"path";var a50=[".png",".jpg",".jpeg",".webp",".gif",".svg"];function zM(A){let Q=aTQ(A).toLowerCase();return a50.includes(Q)}function W_1(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 VT0(A){switch(A.toLowerCase()){case"jpeg":return".jpg";case"svg+xml":return".svg";default:return`.${A.toLowerCase()}`}}import{isAbsolute as tTQ,relative as eTQ,sep as Z_1,join as ASQ}from"path";function sH(A,Q){return tTQ(Q)?Q:ASQ(A,Q)}function cC(A,Q){let B=sH(A,Q),w=eTQ(A,B);return Z_1==="/"?w:w.split(Z_1).join("/")}function QSQ(A,Q){if(!cC(Q,A).startsWith("image/"))return!1;return zM(A)}function BSQ(A,Q){if(cC(Q,A).split("/")[0]?.startsWith("_"))return!1;if(A.endsWith(".md"))return!0;return QSQ(A,Q)}class JT0{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=K_1.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,Q){if(!BSQ(Q,this.syncPath))return;this.logger.debug("File change detected",{event:A,path:Q});let B=cC(this.syncPath,Q);if(this.pendingChanges.set(B,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[Q,B]of A){let w=sH(this.syncPath,Q);try{if(this.onFileChange)await this.onFileChange(B,w)}catch($){this.logger.error("Error processing file change",{path:Q,event:B,error:$})}}}isWatching(){return!!this.watcher}getPendingChangesCount(){return this.pendingChanges.size}}async function U_1(A,Q){if(A?.isWatching())return Q.logger.debug("Already watching directory"),A;return wSQ(Q)}function G_1(A){if(A)A.stop();return}function z_1(A,Q){if(A)A.setCallback(Q)}async function wSQ(A){let{logger:Q,syncPath:B,watchInterval:w,importEntities:$,jobQueueCallback:D,fileOperations:f,deleteOnFileRemoval:Y}=A,X=new Jg0(Q,$,D,f,Y),H=new JT0({syncPath:B,watchInterval:w,logger:Q,onFileChange:async(W,Z)=>{await X.handleFileChange(W,Z)}});return await H.start(),H}async function q_1(A){let Q=Date.now();A.logger.debug("Starting sync (import only)");let B=await A.importEntities(),w=await A.removeOrphanedEntities(),$=Date.now()-Q;return A.markSynced(new Date),A.logger.debug("Sync completed",{duration:$,imported:B.imported,orphansDeleted:w.deleted}),{export:{exported:0,failed:0,errors:[]},import:B,duration:$}}p0();class LT0{logger;syncPath;deleteOnFileRemoval;constructor(A){this.logger=A.logger,this.syncPath=A.syncPath,this.deleteOnFileRemoval=A.deleteOnFileRemoval}prepareBatchOperations(A){let Q=[],B=this.createImportOperations(A);Q.push(...B);let w=B.length;if(this.deleteOnFileRemoval)Q.push({type:"directory-cleanup",data:{}});let $=A.length;return this.logger.debug("Prepared batch operations",{exportOperationsCount:0,importOperationsCount:w,totalFiles:$}),{operations:Q,exportOperationsCount:0,importOperationsCount:w,totalFiles:$}}async queueSyncBatch(A,Q,B,w){let $=this.prepareBatchOperations(B);if($.operations.length===0)return this.logger.debug("No sync operations needed",{source:Q}),null;return{batchId:await A.jobs.enqueueBatch($.operations,{source:Q,rootJobId:w?.rootJobId??S$(),metadata:{progressToken:w?.progressToken,operationType:"file_operations",operationTarget:this.syncPath,pluginId:w?.pluginId??"directory-sync",interfaceType:w?.interfaceType,channelId:w?.channelId}}),operationCount:$.operations.length,exportOperationsCount:$.exportOperationsCount,importOperationsCount:$.importOperationsCount,totalFiles:$.totalFiles}}createImportOperations(A){if(A.length===0)return[];let Q=50,B=[];for(let w=0;w<A.length;w+=Q){let $=A.slice(w,w+Q);B.push({type:"directory-import",data:{batchIndex:Math.floor(w/Q),paths:$,batchSize:$.length}})}return B}}class bT0{syncInProgress=!1;logger;fileOperations;batchOperationsManager;constructor(A){this.logger=A.logger,this.fileOperations=A.fileOperations,this.batchOperationsManager=new LT0({logger:A.logger,syncPath:A.syncPath,deleteOnFileRemoval:A.deleteOnFileRemoval})}async queueSyncBatch(A,Q,B){if(this.syncInProgress)return this.logger.debug("Sync already in progress, skipping",{source:Q}),null;this.syncInProgress=!0;try{let w=await this.fileOperations.getAllSyncFiles();return await this.batchOperationsManager.queueSyncBatch(A,Q,w,B)}finally{this.syncInProgress=!1}}}class NT0{options;constructor(A){this.options=A}createExportDeps(A,Q){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:A,entityTypes:Q}}createImportDeps(A){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,quarantine:this.options.quarantine,imageJobQueue:this.createImageJobQueueDeps(),entityTypes:A}}createCleanupDeps(A,Q){return{entityService:this.options.entityService,logger:this.options.logger,fileOperations:this.options.fileOperations,deleteOnFileRemoval:A,entityTypes:Q}}createImageJobQueueDeps(){return{logger:this.options.logger,syncPath:this.options.syncPath,jobQueueCallback:this.options.getJobQueueCallback(),coverImageConverter:this.options.coverImageConverter,inlineImageConverter:this.options.inlineImageConverter}}}import{basename as HSQ,dirname as WSQ,extname as ZSQ}from"path";import{extname as $SQ}from"path";var t50=[".pdf"],F_1=".meta.json";function qM(A){let Q=$SQ(A).toLowerCase();return t50.includes(Q)}function I_1(A){return A.toLowerCase().endsWith(F_1)}function jT0(A){return`${A}${F_1}`}function V_1(A){switch(A.toLowerCase().replace(".","")){case"pdf":default:return"application/pdf"}}import{extname as DSQ,join as e50}from"path";function A$0(A,Q){let w=cC(A,Q).split("/"),$,D;if(w.length===1)$="note",D=w;else if(w.length>1&&w[0])$=w[0],D=w.slice(1);else $="note",D=w;let f;if(D.length>1){let Y=D[D.length-1];if(Y)D[D.length-1]=J_1(Y);f=D.join(":")}else f=J_1(D[0]??"");return{entityType:$,id:f}}function L_1(A,Q,B,w=".md"){let $=Q.split(":").filter((H)=>H.length>0),D=B==="note";if($.length===1)return D?e50(A,`${$[0]}${w}`):e50(A,B,`${$[0]}${w}`);let f=$;if($[0]===B)f=$.slice(1);let Y=f[f.length-1],X=f.slice(0,-1);if(D)return e50(A,...X,`${Y}${w}`);return e50(A,B,...X,`${Y}${w}`)}function b_1(A){if(A.entityType==="document")return".pdf";if(A.entityType!=="image")return".md";let Q=A.metadata.format;if(Q)return VT0(Q);let B=A.content.match(/^data:image\/([a-z+]+);base64,/i);return B?.[1]?VT0(B[1]):".md"}function J_1(A){let Q=DSQ(A).toLowerCase();return Q===".md"||a50.includes(Q)||t50.includes(Q)?A.slice(0,-Q.length):A}bY();import{mkdir as KSQ,readFile as lC,writeFile as MT0,stat as USQ,utimes as GSQ}from"fs/promises";import{join as Q$0}from"path";import{mkdir as N_1,readdir as YSQ,stat as XSQ}from"fs/promises";import{access as fSQ}from"fs/promises";async function y5(A){try{return await fSQ(A),!0}catch{return!1}}async function _T0(A,Q){return P_1(A,Q,{includeDocuments:!1,includeImages:!1})}async function j_1(A,Q){return P_1(A,Q,{includeDocuments:!0,includeImages:!0})}async function __1(A,Q){if(!await y5(A))await N_1(A,{recursive:!0});for(let B of Q)if(B!=="note")await N_1(Q$0(A,B),{recursive:!0})}async function M_1(A,Q){let B=[],w={totalFiles:0,byEntityType:{}};if(!await y5(A))return{files:B,stats:w};let $=await _T0(A,Q);for(let D of $)try{let f=Q$0(A,D),Y=await XSQ(f),{entityType:X}=A$0(A,D);B.push({path:D,entityType:X,modified:Y.mtime}),w.totalFiles++,w.byEntityType[X]=(w.byEntityType[X]??0)+1}catch{continue}return{files:B,stats:w}}async function P_1(A,Q,B){let w=[];if(!await y5(A))return w;let $=async(D,f="",Y=!1,X=!1)=>{let H=await YSQ(D,{withFileTypes:!0});for(let W of H){let Z=f?Q$0(f,W.name):W.name;if(W.isFile()&&!W.name.endsWith(".invalid")&&!I_1(W.name)){if(W.name.endsWith(".md"))w.push(Z);else if(B.includeImages&&Y&&zM(W.name))w.push(Z);else if(B.includeDocuments&&X&&qM(W.name))w.push(Z)}else if(W.isDirectory()&&!W.name.startsWith(".")){if(f===""&&!Q.hasEntityType(W.name))continue;let G=Q$0(D,W.name),F=W.name==="image"&&f==="",I=W.name==="document"&&f==="";await $(G,Z,Y||F,X||I)}}};return await $(A),w}function zSQ(A){return typeof A==="object"&&A!==null}class PT0{syncPath;entityService;constructor(A,Q){this.syncPath=A,this.entityService=Q}parseEntityFromPath(A){return A$0(this.syncPath,A)}async readEntity(A){let Q=sH(this.syncPath,A),B=await USQ(Q),{entityType:w,id:$}=this.parseEntityFromPath(A),D=B.birthtime.getTime()>0?B.birthtime:B.mtime,f=B.mtime,Y,X;if(zM(A)||qM(A)){let Z=(await lC(Q)).toString("base64"),G=ZSQ(A);if(Y=`data:${qM(A)?V_1(G):W_1(G)};base64,${Z}`,qM(A))X=await this.readDocumentSidecar(Q,A)}else Y=await lC(Q,"utf-8");let H={entityType:w,id:$,content:Y,created:D,updated:f};if(X)H.metadata=X;return H}async readDocumentSidecar(A,Q){let B={mimeType:"application/pdf",filename:HSQ(Q)},w=jT0(A);if(!await y5(w))return B;try{let $=await lC(w,"utf-8"),D=JSON.parse($),f=zSQ(D)?D:{};return{...B,...f}}catch{return B}}async writeEntity(A){let Q=this.getEntityFilePath(A),B=A.entityType==="image",w=A.entityType==="document";if(B||w){let D=B?/^data:image\/[a-z+]+;base64,(.+)$/i:/^data:application\/pdf;base64,(.+)$/i,f=A.content.match(D),Y=f?.[1]?Buffer.from(f[1],"base64"):Buffer.from(A.content,"base64"),X=!1;if(await y5(Q)){let H=await lC(Q),W=RB(H.toString("base64")),Z=RB(Y.toString("base64"));if(W===Z)X=!0}if(!X)await this.ensureEntityDirectory(A,Q),await MT0(Q,Y);if(w)await this.writeDocumentSidecar(A,Q);if(X)return}else{let D=this.entityService.serializeEntity(A);if(await y5(Q)){let f=await lC(Q,"utf-8"),Y=RB(f),X=RB(D);if(Y===X)return}await this.ensureEntityDirectory(A,Q),await MT0(Q,D,"utf-8")}let $=new Date(A.updated);await GSQ(Q,$,$)}async ensureEntityDirectory(A,Q){if(A.entityType!=="note")await KSQ(WSQ(Q),{recursive:!0})}async writeDocumentSidecar(A,Q){let B=A.metadata,w={};for(let[f,Y]of Object.entries(B)){if(f==="mimeType")continue;if(Y===void 0)continue;w[f]=Y}let $=jT0(Q),D=`${JSON.stringify(w,null,2)}
|
|
4872
4872
|
`;if(await y5($)){if(await lC($,"utf-8")===D)return}await this.ensureEntityDirectory(A,$),await MT0($,D,"utf-8")}getFilePath(A,Q,B=".md"){return L_1(this.syncPath,A,Q,B)}getEntityFilePath(A){return this.getFilePath(A.id,A.entityType,b_1(A))}async getAllMarkdownFiles(){return _T0(this.syncPath,this.entityService)}async getAllSyncFiles(){return j_1(this.syncPath,this.entityService)}async ensureDirectoryStructure(A){await __1(this.syncPath,A)}shouldUpdateEntity(A,Q){let B=RB(Q.content);return A.contentHash!==B}async gatherFileStatus(){return M_1(this.syncPath,this.entityService)}async syncDirectoryExists(){return y5(this.syncPath)}async fileExists(A){return y5(A)}}D4();K0();D4();async function B$0(A,Q,B,w){let{sourceUrl:$}=A,D=await Q.listEntities({entityType:"image",options:{filter:{metadata:{sourceUrl:$}},limit:1}});if(D[0])return w.debug("Reusing existing image entity",{sourceUrl:$,imageId:D[0].id}),D[0].id;let f=await B($),{base64:Y}=$V(f),X=wj(Y),H=DV(Y);if(!X||!H)throw Error("Could not detect image format or dimensions");let W=await Q.createEntity({entity:{id:A.id,entityType:"image",content:f,metadata:{title:A.title,alt:A.alt,format:X,width:H.width,height:H.height,sourceUrl:$}}});return w.debug("Created image entity from URL",{sourceUrl:$,imageId:W.entityId}),W.entityId}var k_1=K.object({title:K.string(),slug:K.string().optional(),coverImageUrl:K.string().url(),coverImageId:K.string().optional(),coverImageAlt:K.string().optional()});class kT0{entityService;fetcher;logger;constructor(A,Q,B=NH){this.entityService=A;this.fetcher=B;this.logger=Q.child("FrontmatterImageConverter")}detectCoverImageUrl(A){let Q;try{Q=lB(A)}catch{return null}let{frontmatter:B}=Q,w=k_1.safeParse(B);if(!w.success)return null;if(w.data.coverImageId)return null;let{title:$,slug:D,coverImageUrl:f,coverImageAlt:Y}=w.data;if(!oz(f))return null;return{sourceUrl:f,postTitle:$,postSlug:D??Y1($),customAlt:Y}}async convert(A){let Q;try{Q=lB(A)}catch(H){return this.logger.debug("Parse failed",{error:H}),{content:A,converted:!1}}let{frontmatter:B}=Q,w=k_1.safeParse(B);if(!w.success)return{content:A,converted:!1};if(w.data.coverImageId)return{content:A,converted:!1};let{title:$,slug:D,coverImageUrl:f,coverImageAlt:Y}=w.data;if(!oz(f))return{content:A,converted:!1};let X={postTitle:$,postSlug:D??Y1($),sourceUrl:f,customAlt:Y};try{let H=await this.createImageEntity(X),W={...B};return delete W.coverImageUrl,delete W.coverImageAlt,W.coverImageId=H,{content:dz(W,Q.content),converted:!0,imageId:H}}catch(H){return this.logger.warn("Failed to convert coverImageUrl",{url:f,error:hA(H)}),{content:A,converted:!1}}}async createImageEntity(A){let{postTitle:Q,postSlug:B,sourceUrl:w,customAlt:$}=A,D=`Cover image for ${Q}`;return B$0({id:`${B}-cover`,title:D,alt:$??D,sourceUrl:w},this.entityService,this.fetcher,this.logger)}}D4();K0();class Id{entityService;fetcher;logger;constructor(A,Q,B=NH){this.entityService=A;this.fetcher=B;this.logger=Q.child("MarkdownImageConverter")}detectInlineImages(A,Q){let B=[],w=CL0(A);for(let $ of w){if(!oz($.url))continue;if($.url.startsWith("entity://"))continue;let D=this.reconstructMarkdown($);B.push({sourceUrl:$.url,alt:$.alt,originalMarkdown:D,postSlug:Q})}return B}reconstructMarkdown(A){if(A.title)return``;return``}async convert(A,Q){let B=this.detectInlineImages(A,Q);if(B.length===0)return{content:A,converted:!1,convertedCount:0};let w=A,$=0,D=0;for(let f of B)try{let Y=await this.createImageEntity(f,D++),X=``;w=w.replace(f.originalMarkdown,X),$++,this.logger.debug("Converted inline image",{sourceUrl:f.sourceUrl,imageId:Y})}catch(Y){this.logger.warn("Failed to convert inline image",{sourceUrl:f.sourceUrl,error:hA(Y)})}return{content:w,converted:$>0,convertedCount:$}}async createImageEntity(A,Q){let{sourceUrl:B,alt:w,postSlug:$}=A;return B$0({id:`${$}-inline-${Q}`,title:w||`Inline image ${Q+1} for ${$}`,alt:w||"",sourceUrl:B},this.entityService,this.fetcher,this.logger)}}class OT0{logger;entityService;fileOperations;constructor(A,Q,B){this.logger=A,this.entityService=Q,this.fileOperations=B}async importEntitiesWithProgress(A,Q,B,w){this.logger.debug("Importing entities with progress reporting");let $={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},D=A??await this.fileOperations.getAllSyncFiles(),f=D.length;await Q.report({progress:0,message:`Starting import of ${f} files`});for(let Y=0;Y<f;Y+=B){let X=D.slice(Y,Y+B),H=await w(X);$.imported+=H.imported,$.skipped+=H.skipped,$.failed+=H.failed,$.quarantined+=H.quarantined,$.errors.push(...H.errors),$.quarantinedFiles.push(...H.quarantinedFiles),$.jobIds.push(...H.jobIds);let W=Math.min(Y+B,f),Z=Math.round(W/f*40);await Q.report({progress:Z,message:`Imported ${W}/${f} files`})}return $}async exportEntitiesWithProgress(A,Q,B,w){this.logger.debug("Exporting entities with progress reporting");let $=A??this.entityService.getEntityTypes();await Q.report({progress:50,message:`Starting export of ${$.length} entity types`});let D=await w(A);return await Q.report({progress:100,message:`Exported ${D.exported} entities`}),this.logger.debug("Export completed",D),D}}K0();import{rename as qSQ,appendFile as FSQ,readFile as ISQ,writeFile as VSQ,access as JSQ}from"fs/promises";import{join as O_1}from"path";class xT0{logger;syncPath;constructor(A,Q){this.logger=A;this.syncPath=Q}isValidationError(A){if(A instanceof K.ZodError)return!0;let Q=hA(A);return Q.includes("invalid_type")||Q.includes("invalid_enum_value")||Q.includes("Required")||Q.includes("Invalid frontmatter")||Q.includes("Unknown entity type")}async quarantineInvalidFile(A,Q,B,w){let $=w(A),D=`${$}.invalid`;try{await qSQ($,D),B.quarantined++,B.quarantinedFiles.push(A);let f=O_1(this.syncPath,".import-errors.log"),Y=new Date().toISOString(),X=hA(Q),H=`${Y} - ${A}: ${X}
|
|
4873
4873
|
\u2192 ${A}.invalid
|
|
4874
4874
|
|
|
@@ -4896,7 +4896,7 @@ details.web-chat-data-part[open] > summary > .web-chat-data-part-chevron {
|
|
|
4896
4896
|
*...and ${A.files.length-10} more files*`)}if(A.exists&&A.stats.totalFiles===0)Q.push(`
|
|
4897
4897
|
## Getting Started
|
|
4898
4898
|
`),Q.push("Your sync directory is empty. Entities will be organized as follows:"),Q.push("- Base entities: `/<entity-id>.md`"),Q.push("- Other types: `/<entity-type>/<entity-id>.md`");return Q.join(`
|
|
4899
|
-
`)}}p0();class O$0 extends PB{directorySync;constructor(A,Q,B){super(A,{schema:xS0,jobTypeName:"directory-export"});this.directorySync=B}async process(A,Q,B){this.logger.debug("Processing directory export job",{jobId:Q,data:A});let w=Date.now();try{let $=await this.directorySync.exportEntitiesWithProgress(A.entityTypes,B,A.batchSize??100);return this.logger.debug("Directory export job completed",{jobId:Q,exported:$.exported,failed:$.failed,duration:Date.now()-w}),$}catch($){throw this.logger.error("Directory export job failed",{jobId:Q,error:$}),$}}summarizeDataForLog(A){return{entityTypes:A.entityTypes??"all",batchSize:A.batchSize}}}p0();class x$0 extends PB{directorySync;constructor(A,Q,B){super(A,{schema:OS0,jobTypeName:"directory-import"});this.directorySync=B}async process(A,Q,B){this.logger.debug("Processing directory import job",{jobId:Q,data:A});let w=Date.now();try{let $=await this.directorySync.importEntitiesWithProgress(A.paths,B,A.batchSize??100);return this.logger.debug("Directory import job completed",{jobId:Q,imported:$.imported,skipped:$.skipped,failed:$.failed,quarantined:$.quarantined,duration:Date.now()-w}),$}catch($){throw this.logger.error("Directory import job failed",{jobId:Q,error:$}),$}}summarizeDataForLog(A){return{pathCount:A.paths?.length??"all",batchSize:A.batchSize}}}p0();class R$0 extends PB{directorySync;context;constructor(A,Q,B){super(A,{schema:PS0,jobTypeName:"directory-sync"});this.context=Q,this.directorySync=B}async process(A,Q,B){let w=Date.now(),$=A.syncDirection??"both";this.logger.info("Starting directory sync job",{jobId:Q,operation:A.operation,syncDirection:$});let D={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},f={exported:0,failed:0,errors:[]};if($!=="export")if(await B.report({progress:10,message:"Scanning directory for changes"}),D=await this.importWithProgress(A.paths,B),$==="import")await this.waitForImportJobs(D.jobIds,B),await B.report({progress:100,message:`Import complete: ${D.imported} imported`});else await B.report({progress:50,message:`Imported ${D.imported} entities`}),await this.waitForImportJobs(D.jobIds,B),await B.report({progress:56,message:"Processing complete, starting export"});if($!=="import"){let X=$==="export"?10:60;await B.report({progress:X,message:"Exporting entities to directory"}),f=await this.exportWithProgress(A.entityTypes,B),await B.report({progress:100,message:$==="export"?`Export complete: ${f.exported} exported`:`Sync complete: ${D.imported} imported, ${f.exported} exported`})}let Y=Date.now()-w;return this.logger.info("Directory sync job completed",{jobId:Q,duration:Y,imported:D.imported,exported:f.exported}),{import:D,export:f,duration:Y}}async importWithProgress(A,Q){try{return await this.directorySync.importEntitiesWithProgress(A,Q,10)}catch(B){throw this.logger.error("Import phase failed",{error:B}),B}}async exportWithProgress(A,Q){try{return await this.directorySync.exportEntitiesWithProgress(A,Q,10)}catch(B){throw this.logger.error("Export phase failed",{error:B}),B}}async waitForImportJobs(A,Q){if(A.length===0)return;this.logger.debug(`Waiting for ${A.length} import jobs to complete`);let{entityService:B}=this.context,w=300000,$=500,D=Date.now(),f=async()=>{let X=(await Promise.all(A.map((W)=>B.getAsyncJobStatus(W)))).filter((W)=>W&&(W.status==="completed"||W.status==="failed")).length;if(X===A.length){this.logger.debug("All import jobs completed");return}if(Date.now()-D>w){this.logger.warn(`Timeout waiting for import jobs (${X}/${A.length} completed)`);return}let H=Math.round(X/A.length*100);return await Q.report({progress:50+Math.round(H*0.05),message:`Processing ${X}/${A.length} entities`}),await new Promise((W)=>setTimeout(W,$)),f()};return f()}summarizeDataForLog(A){return{operation:A.operation,syncDirection:A.syncDirection}}}p0();class v$0 extends PB{context;directorySync;gitSync;constructor(A,Q,B,w){super(A,{schema:kS0,jobTypeName:"sync-request"});this.context=Q;this.directorySync=B;this.gitSync=w}async process(A,Q,B){await B.report({progress:5,message:"Pulling latest content from git"});let w=await this.gitSync.withLock(async()=>{return await this.gitSync.pull(),await B.report({progress:35,message:"Scanning pulled content for sync changes"}),this.directorySync.queueSyncBatch(this.context,A.source,{rootJobId:Q,interfaceType:A.interfaceType,channelId:A.channelId})});if(!w)return await B.report({progress:100,message:"Sync complete: no files to import"}),{gitPulled:!0,batchQueued:!1};return await B.report({progress:100,message:`Sync queued: ${w.importOperationsCount} import jobs for ${w.totalFiles} files`}),zlQ(w)}summarizeDataForLog(A){return{source:A.source,interfaceType:A.interfaceType,channelId:A.channelId}}}function zlQ(A){return{gitPulled:!0,batchQueued:!0,batchId:A.batchId,importOperations:A.importOperationsCount,totalFiles:A.totalFiles}}p0();class h$0 extends PB{context;constructor(A,Q,B){super(A,{schema:P$0,jobTypeName:"directory-delete"});this.context=Q}async process(A,Q,B){let w=P$0.parse(A);this.logger.info("Processing entity deletion for removed file",{entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}),await B.report({progress:0,total:1,message:`Deleting ${w.entityType}:${w.entityId}`});try{let $=await this.context.entityService.deleteEntity({entityType:w.entityType,id:w.entityId});if($)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 B.report({progress:1,total:1,message:`Deleted ${w.entityType}:${w.entityId}`}),{deleted:$,entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}}catch($){throw this.logger.error("Failed to delete entity",{entityId:w.entityId,entityType:w.entityType,error:$}),$}}summarizeDataForLog(A){return{entityId:A.entityId,entityType:A.entityType,filePath:A.filePath}}}p0();K0();var qlQ=K.object({});class C$0 extends PB{directorySync;constructor(A,Q){super(A,{schema:qlQ,jobTypeName:"directory-cleanup"});this.directorySync=Q}async process(A,Q,B){await B.report({progress:0,message:"Removing orphaned entities"});let w=await this.directorySync.removeOrphanedEntities();return await B.report({progress:100,message:`Cleanup complete: ${w.deleted} orphans removed`}),w}}p0();D4();K0();Cw();D4();import{readFile as FlQ,writeFile as IlQ}from"fs/promises";var VlQ=RS0;class y$0 extends PB{context;fetcher;constructor(A,Q,B=NH){super(Q,{schema:VlQ,jobTypeName:"cover-image-convert"});this.context=A,this.fetcher=B}async process(A,Q,B){let{filePath:w,sourceUrl:$,postTitle:D,postSlug:f,customAlt:Y}=A;this.logger.debug("Starting image conversion job",{jobId:Q,filePath:w,sourceUrl:$,postSlug:f});try{await this.reportProgress(B,{progress:MQ.INIT,message:`Reading file: ${w}`});let X;try{X=await FlQ(w,"utf-8")}catch(L){return this.logger.error("Failed to read file",{filePath:w,error:hA(L)}),x6.failure(L)}let H;try{H=lB(X)}catch(L){return this.logger.warn("Failed to parse markdown",{filePath:w,error:hA(L)}),x6.failure(L)}let W=H.frontmatter;if(W.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:w}),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(B,{progress:MQ.FETCH,message:"Checking for existing image"});let Z=await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{sourceUrl:$}},limit:1}}),G;if(Z[0])G=Z[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:$,imageId:G}),await this.reportProgress(B,{progress:MQ.EXTRACT,message:`Reusing existing image: ${G}`});else{await this.reportProgress(B,{progress:MQ.PROCESS,message:`Fetching image from ${$}`});let L;try{L=await this.fetcher($)}catch(E){return this.logger.error("Failed to fetch image",{sourceUrl:$,error:hA(E)}),x6.failure(E)}await this.reportProgress(B,{progress:MQ.GENERATE,message:"Creating image entity"});let{base64:b}=$V(L),N=wj(b),M=DV(b);if(!N||!M)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:$}),x6.failure(Error("Could not detect image format or dimensions"));G=`${f}-cover`;let j=`Cover image for ${D}`,g=Y??j;await this.context.entityService.createEntity({entity:{id:G,entityType:"image",content:L,metadata:{title:j,alt:g,format:N,width:M.width,height:M.height,sourceUrl:$}}}),this.logger.debug("Created image entity",{imageId:G,sourceUrl:$}),await this.reportProgress(B,{progress:MQ.EXTRACT,message:`Created image: ${G}`})}await this.reportProgress(B,{progress:MQ.SAVE,message:"Updating file"});let F={...W};delete F.coverImageUrl,delete F.coverImageAlt,F.coverImageId=G;let I=dz(F,H.content);try{await IlQ(w,I,"utf-8")}catch(L){return this.logger.error("Failed to write file",{filePath:w,error:hA(L)}),x6.failure(L)}return await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:w,imageId:G,sourceUrl:$}),{success:!0,imageId:G}}catch(X){return this.logger.error("Image conversion job failed",{jobId:Q,filePath:w,error:hA(X)}),x6.failure(X)}}summarizeDataForLog(A){return{filePath:A.filePath,sourceUrl:A.sourceUrl,postSlug:A.postSlug}}}p0();D4();K0();Cw();import{readFile as JlQ,writeFile as LlQ}from"fs/promises";class E$0 extends PB{converter;constructor(A,Q,B=NH){super(Q,{schema:vS0,jobTypeName:"inline-image-convert"});this.converter=new Id(A.entityService,Q,B)}async process(A,Q,B){let{filePath:w,postSlug:$}=A;this.logger.debug("Starting inline image conversion job",{jobId:Q,filePath:w,postSlug:$});try{await this.reportProgress(B,{progress:MQ.INIT,message:`Reading file: ${w}`});let D;try{D=await JlQ(w,"utf-8")}catch(X){let H=hA(X);return this.logger.error("Failed to read file",{filePath:w,error:H}),{success:!1,error:H}}await this.reportProgress(B,{progress:MQ.FETCH,message:"Detecting inline images"});let f=this.converter.detectInlineImages(D,$);if(f.length===0)return this.logger.debug("No inline images to convert",{filePath:w}),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:w,count:f.length}),await this.reportProgress(B,{progress:MQ.PROCESS,message:`Converting ${f.length} images`});let Y=await this.converter.convert(D,$);if(!Y.converted)return this.logger.debug("No images were converted",{filePath:w}),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(B,{progress:MQ.SAVE,message:"Writing updated file"});try{await LlQ(w,Y.content,"utf-8")}catch(X){let H=hA(X);return this.logger.error("Failed to write file",{filePath:w,error:H}),{success:!1,error:H}}return await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:w,convertedCount:Y.convertedCount}),{success:!0,convertedCount:Y.convertedCount}}catch(D){let f=hA(D);return this.logger.error("Inline image conversion job failed",{jobId:Q,filePath:w,error:f}),{success:!1,error:f}}}summarizeDataForLog(A){return{filePath:A.filePath,postSlug:A.postSlug}}}function YO1(A,Q,B){let w=($)=>B.child($);A.jobs.registerHandler("directory-sync",new R$0(w("DirectorySyncJobHandler"),A,Q)),A.jobs.registerHandler("directory-export",new O$0(w("DirectoryExportJobHandler"),A,Q)),A.jobs.registerHandler("directory-import",new x$0(w("DirectoryImportJobHandler"),A,Q)),A.jobs.registerHandler("directory-delete",new h$0(w("DirectoryDeleteJobHandler"),A,Q)),A.jobs.registerHandler("directory-cleanup",new C$0(w("DirectoryCleanupJobHandler"),Q)),A.jobs.registerHandler("cover-image-convert",new y$0(A,w("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new E$0(A,w("InlineImageConversionJobHandler"))),B.debug("Registered async job handlers")}p0();import{unlink as blQ,access as NlQ}from"fs/promises";function XO1(A,Q,B,w){let{subscribe:$}=A.messaging,{entityService:D}=A;$("entity:created",async(f)=>{let{entity:Y}=f.payload;try{await Q.fileOps.writeEntity(Y),B.debug("Auto-exported created entity",{id:Y.id,entityType:Y.entityType})}catch(X){B.error("Auto-export FAILED for created entity",{id:Y.id,entityType:Y.entityType,error:X instanceof Error?X.message:String(X),stack:X instanceof Error?X.stack:void 0})}return{success:!0}}),$("entity:updated",async(f)=>{let{entityType:Y,entityId:X}=f.payload;try{let H=await D.getEntity({entityType:Y,id:X});if(!H)return B.debug("Entity not found in DB, skipping export",{entityType:Y,entityId:X}),{success:!1};await Q.fileOps.writeEntity(H),B.debug("Auto-exported updated entity",{id:H.id,entityType:H.entityType})}catch(H){B.error("Auto-export FAILED for updated entity",{entityType:Y,entityId:X,error:H instanceof Error?H.message:String(H),stack:H instanceof Error?H.stack:void 0})}return{success:!0}}),$("entity:deleted",async(f)=>{let{entityId:Y,entityType:X}=f.payload,H=Q.fileOps.getFilePath(Y,X);if(await NlQ(H).then(()=>!0,()=>!1))await blQ(H),B.debug("Auto-deleted entity file",{id:Y,entityType:X,path:H});return{success:!0}}),B.debug("Setup auto-sync for entity events",{entityTypes:w})}function HO1(A,Q,B){Q.setJobQueueCallback(async(w)=>{let $=[{type:w.type,data:w.data}];return A.jobs.enqueueBatch($,{priority:5,source:"directory-sync-watcher",rootJobId:S$(),metadata:{operationType:"file_operations",operationTarget:B,pluginId:"directory-sync"}})})}K0();p0();import{readdir as KO1,mkdir as _lQ,copyFile as MlQ}from"fs/promises";import{join as ZO1,resolve as hS0}from"path";import{join as jlQ}from"path";async function WO1(A){if(!await y5(jlQ(A,".git")))return!1;try{return await AK(A).revparse(["--verify","HEAD"]),!0}catch{return!1}}async function PlQ(A,Q){if(!await y5(A))return!0;if((await KO1(A)).filter(($)=>!$.startsWith(".")&&!$.startsWith("_")).length>0)return!1;if(await WO1(A))return Q.debug("Git repository with history detected - skipping seed content",{path:A}),!1;return!0}async function UO1(A,Q){let B=await KO1(A,{withFileTypes:!0});for(let w of B){let $=ZO1(A,w.name),D=ZO1(Q,w.name);if(w.isDirectory()){if(!await y5(D))await _lQ(D,{recursive:!0});await UO1($,D)}else await MlQ($,D)}}async function GO1(A,Q,B){let w=hS0(process.cwd(),A);B=B?hS0(B):hS0(process.cwd(),"seed-content");let $=await PlQ(w,Q);if($&&await y5(B))Q.debug("Copying seed content to brain-data directory"),await UO1(B,w),Q.debug("Seed content copied successfully");else if($)Q.debug("No seed content directory found, starting with empty brain-data");else Q.debug("brain-data directory not empty, skipping seed content")}function zO1(A,Q,B,w,$){let D=!1,f=async()=>{if(D)return;D=!0;let Y=Q();if(B.seedContent){let X=B.syncPath??A.dataDir;await GO1(X,w,B.seedContentPath)}try{if($){w.debug("Git enabled \u2014 pulling before import");let H=await $.pull();if(H.files.length>0)w.info("Pulled changes from remote",{filesChanged:H.files.length})}w.debug("Starting initial sync");let X=await Y.sync();w.debug("Initial sync completed",{imported:X.import.imported,failed:X.import.failed,duration:X.duration}),await A.messaging.send({type:FN.initialSyncCompleted,payload:{success:!0},...{broadcast:!0}})}catch(X){w.error("Initial sync failed",X),await A.messaging.send({type:FN.initialSyncCompleted,payload:{success:!1,error:hA(X)},...{broadcast:!0}})}};A.messaging.subscribe(FN.pluginsRegistered,async()=>{return w.debug("Plugins registered, starting initial sync"),await f(),{success:!0}})}K0();function qO1(A,Q,B,w){let $=new QN(()=>{Q.withLock(async()=>{try{await Q.commit(),await Q.push()}catch(Y){w.error("Git auto-commit failed",{error:Y})}})},B),D=["entity:created","entity:updated","entity:deleted"],f=[];for(let Y of D){let X=A.subscribe(Y,async()=>{return $.trigger(),{success:!0}});f.push(X)}return()=>{$.dispose();for(let Y of f)Y()}}function FO1(A,Q,B,w,$){if(w<=0)return()=>{};let D=w*60*1000,f=!1,Y=async()=>{if(f)return;f=!0;try{let{files:H,result:W}=await A.withLock(async()=>{let Z=await A.pull();if(Z.files.length===0)return{files:[],result:null};let G=await Q.queueSyncBatch(B,"periodic-sync");return{files:Z.files,result:G}});if(H.length>0)$.info("Periodic sync: pulled changes",{filesChanged:H.length});if(W)$.debug("Periodic sync: queued imports",{importOperations:W.importOperationsCount,totalFiles:W.totalFiles})}catch(H){$.error("Periodic git sync failed",{error:H})}finally{f=!1}},X=setInterval(()=>{Y()},D);return $.info("Started periodic git sync",{intervalMinutes:w}),()=>{clearInterval(X)}}import{spawnSync as VO1}from"child_process";import{cpSync as klQ,existsSync as IO1,mkdirSync as OlQ,mkdtempSync as xlQ,rmSync as RlQ}from"fs";import{tmpdir as vlQ}from"os";import{fileURLToPath as hlQ}from"url";import{join as ClQ,resolve as ylQ}from"path";function iJ(A,Q){let B=VO1("git",Q,{cwd:A,stdio:"pipe"});if(B.status!==0){let w=B.stderr.toString().trim(),$=B.stdout.toString().trim();throw Error(w||$||`git ${Q.join(" ")} failed`)}}function ElQ(A){return A.startsWith("file://")}function glQ(A){return hlQ(A)}function TlQ(A,Q){return VO1("git",["--git-dir",A,"show-ref","--verify","--quiet",`refs/heads/${Q}`]).status===0}async function JO1(A){if(!A.bootstrapFromSeed)return;if(!A.gitUrl||!ElQ(A.gitUrl))return;if(!A.seedContentPath)throw Error("directory-sync git.bootstrapFromSeed requires seedContentPath for local file:// remotes");let Q=A.branch??"main",B=glQ(A.gitUrl),w=ylQ(A.seedContentPath);if(!IO1(w))throw Error(`Seed content path not found: ${w}`);if(!IO1(B))A.logger.debug("Creating local bare content remote",{remotePath:B,branch:Q}),OlQ(B,{recursive:!0}),iJ(process.cwd(),["init","--bare",`--initial-branch=${Q}`,B]);if(TlQ(B,Q)){A.logger.debug("Content remote already initialized",{remotePath:B,branch:Q});return}A.logger.debug("Seeding local content remote",{remotePath:B,seedPath:w,branch:Q});let $=xlQ(ClQ(vlQ(),"directory-sync-seed-"));try{iJ($,["init",`--initial-branch=${Q}`]),iJ($,["config","user.name",A.authorName??"Brain"]),iJ($,["config","user.email",A.authorEmail??"brain@localhost"]),klQ(w,$,{recursive:!0}),iJ($,["add","."]),iJ($,["commit","-m","seed content remote"]),iJ($,["remote","add","origin",A.gitUrl]),iJ($,["push","-u","origin",Q])}finally{RlQ($,{recursive:!0,force:!0})}}function LO1(A,Q,B,w,$){let{subscribe:D}=A.messaging;D("entity:export:request",async(f)=>{try{return{success:!0,data:await Q().exportEntities(f.payload.entityTypes)}}catch(Y){return{success:!1,error:Y instanceof Error?Y.message:"Export failed"}}}),D("entity:import:request",async(f)=>{try{let Y=Q(),X=f.payload.paths,H=await Y.importEntities(X);if(X&&X.length>0)await Y.removeOrphanedEntities();return{success:!0,data:H}}catch(Y){return{success:!1,error:Y instanceof Error?Y.message:"Import failed"}}}),D("sync:status:request",async()=>{try{let Y=await Q().getStatus();return{success:!0,data:{syncPath:Y.syncPath,isInitialized:Y.exists,watchEnabled:Y.watching}}}catch(f){return{success:!1,error:f instanceof Error?f.message:"Status check failed"}}}),D("sync:configure:request",async(f)=>{try{return await B({syncPath:f.payload.syncPath}),{success:!0,data:{syncPath:f.payload.syncPath,configured:!0}}}catch(Y){return{success:!1,error:Y instanceof Error?Y.message:"Configuration failed"}}}),D("git-sync:get-repo-info",async()=>{if(!$?.repo)return{success:!1,error:"Git not configured"};return{success:!0,data:{repo:$.repo,branch:$.branch??"main"}}}),w.debug("Registered message handlers")}p0();K0();p0();K0();function bO1(A,Q){return BB(A,"history","Get version history for an entity from git. Without sha: returns commit list. With sha: returns entity content at that version.",K.object({entityType:K.string().describe("Entity type (e.g. post, note, link)"),id:K.string().describe("Entity ID"),sha:K.string().optional().describe("Commit SHA to retrieve content at. Omit to list commit history."),limit:K.number().int().positive().optional().default(10).describe("Max commits to return (list mode only)")}),async(B)=>{let w=`${B.entityType}/${B.id}.md`;try{if(B.sha){let D=await Q.show(B.sha,w);return b8({sha:B.sha,entityType:B.entityType,id:B.id,content:D},`Content at ${B.sha.slice(0,7)}`)}let $=await Q.log(w,B.limit);if($.length===0)return b8({commits:[]},`No history found for ${B.entityType}/${B.id}`);return b8({commits:$,entityType:B.entityType,id:B.id},`${$.length} version${$.length===1?"":"s"} found`)}catch($){return u$($ instanceof Error?$.message:"History lookup failed")}})}function NO1(A,Q,B,w){let $=[BB(B,"sync","Sync brain entities with the filesystem. Use this for refresh, pull, sync, or backup-to-git requests. Pulls from git if configured, then imports files. Git commit and push happen automatically after imports complete.",K.object({}),async(D,f)=>{try{let Y=f.channelId?`${f.interfaceType}:${f.channelId}`:`plugin:${B}`,X={interfaceType:f.interfaceType,channelId:f.channelId};if(w){let W=await Q.jobs.enqueue({type:"sync-request",data:{source:Y,interfaceType:X.interfaceType,channelId:X.channelId},toolContext:f});return b8({jobId:W,status:"queued",gitPulled:!0},"Sync queued: git pull and filesystem scan will run in the background")}let H=await A.queueSyncBatch(Q,Y,X);if(!H)return b8({gitPulled:!1},"No files to sync");return b8({batchId:H.batchId,importOperations:H.importOperationsCount,totalFiles:H.totalFiles,gitPulled:!1},`Sync started: ${H.importOperationsCount} import jobs queued for ${H.totalFiles} files`)}catch(Y){return u$(Y instanceof Error?Y.message:"Sync failed")}},{cli:{name:"sync"}}),BB(B,"status","Get sync and git repository status \u2014 last sync time, watching state, pending git changes. Use this for status questions, not for actually syncing or backing up.",K.object({}),async()=>{try{let D=await A.getStatus(),f={syncPath:D.syncPath,lastSync:D.lastSync?.toISOString(),watching:D.watching};if(w){let Y=await w.getStatus();f.git={isRepo:Y.isRepo,branch:Y.branch,hasChanges:Y.hasChanges,ahead:Y.ahead,behind:Y.behind,remote:Y.remote}}return b8(f)}catch(D){return u$(D instanceof Error?D.message:"Status check failed")}},{visibility:"public"})];if(w)$.push(bO1(B,w));return $}var jO1={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.128",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/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",chokidar:"^3.5.3","simple-git":"^3.21.0"},devDependencies:{"@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"},peerDependencies:{}};class CS0 extends pQ{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",jO1,A,Rd)}requireDirectorySync(){if(!this.directorySync)throw Error("DirectorySync service not initialized");return this.directorySync}hasGitSync(){return this.gitSync!==void 0}async onRegister(A){let{logger:Q,entityService:B}=A;A.templates.register({status:{name:"status",description:"Directory synchronization status",schema:vd,basePrompt:"",formatter:new k$0,requiredPermission:"anchor"}});let w=this.config.syncPath??A.dataDir;this.directorySync=new Vd({syncPath:w,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:B,logger:Q});try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:w})}catch(f){throw this.logger.error("Failed to initialize directory",f),f}await this.registerJobHandlers(A);let $=this.requireDirectorySync();if(XO1(A,$,this.logger,this.config.entityTypes),this.config.autoSync)HO1(A,$,this.config.syncPath??A.dataDir);let D=this.config.git!==void 0&&(this.config.git.repo!==void 0||this.config.git.gitUrl!==void 0);if(this.config.git&&!D)this.logger.debug("Git block present but no repo/gitUrl configured \u2014 git sync disabled");if(D&&this.config.git){await JO1({gitUrl:this.config.git.gitUrl,branch:this.config.git.branch,seedContentPath:this.config.seedContentPath,bootstrapFromSeed:this.config.git.bootstrapFromSeed,authorName:this.config.git.authorName,authorEmail:this.config.git.authorEmail,logger:this.logger.child("ContentRemoteBootstrap")});let f=this.config.syncPath??A.dataDir;if(this.gitSync=new MS0({logger:this.logger.child("GitSync"),dataDir:f,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}),A.jobs.registerHandler("sync-request",new v$0(this.logger.child("DirectorySyncRequestJobHandler"),A,this.requireDirectorySync(),this.gitSync)),this.gitCleanups.push(qO1(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push(FO1(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)zO1(A,()=>this.requireDirectorySync(),this.config,this.logger,this.gitSync);LO1(A,()=>this.requireDirectorySync(),(f)=>this.configure(f),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return NO1(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 Q=this.getContext();this.directorySync=new Vd({...this.config,syncPath:A.syncPath,entityService:Q.entityService,logger:Q.logger}),await this.directorySync.initialize(),this.logger.info("Directory sync reconfigured",{path:A.syncPath})}async registerJobHandlers(A){YO1(A,this.requireDirectorySync(),this.logger)}}function JM(A={}){return new CS0(A)}p0();K0();var _O1={name:"@brains/email-resend",private:!0,version:"0.2.0-alpha.128",description:"Generic email delivery adapter for Resend",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/email-contracts":"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 ulQ=K.object({apiKey:K.string().min(1).optional(),from:K.string().min(1).optional()});class MO1 extends pQ{fetchImpl;constructor(A={},Q={}){super("email-resend",_O1,A,ulQ);this.fetchImpl=Q.fetchImpl??fetch}async onRegister(A){if(!this.config.apiKey||!this.config.from){this.logger.warn("Email Resend adapter is disabled because apiKey or from is missing");return}let Q=this.logger;A.messaging.subscribe(lB0,async(B)=>{let w=zxA.parse(B.payload);try{return{success:!0,data:await this.sendWithResend(w)}}catch($){if(w.sensitivity==="secret")Q.warn("Email delivery failed for a secret message");else Q.warn("Email delivery failed",{to:w.to,subject:w.subject,error:$ instanceof Error?$.message:String($)});return{success:!1,error:"Email delivery failed"}}})}async sendWithResend(A){let Q=this.config.apiKey,B=this.config.from;if(!Q||!B)return{status:"failed"};let w=await this.fetchImpl("https://api.resend.com/emails",{method:"POST",headers:{Authorization:`Bearer ${Q}`,"Content-Type":"application/json"},body:JSON.stringify({from:B,to:A.to,subject:A.subject,text:A.text,...A.html?{html:A.html}:{}})});if(!w.ok)throw Error("Resend email request failed");let $=await w.json();return $.id?{status:"sent",id:$.id}:{status:"sent"}}}function g$0(A={}){return new MO1(A)}p0();import{render as Sl1}from"preact-render-to-string";import{h as wP}from"preact";function PO1(A){var Q,B,w="";if(typeof A=="string"||typeof A=="number")w+=A;else if(typeof A=="object")if(Array.isArray(A)){var $=A.length;for(Q=0;Q<$;Q++)A[Q]&&(B=PO1(A[Q]))&&(w&&(w+=" "),w+=B)}else for(B in A)A[B]&&(w&&(w+=" "),w+=B);return w}function sC(){for(var A,Q,B=0,w="",$=arguments.length;B<$;B++)(A=arguments[B])&&(Q=PO1(A))&&(w&&(w+=" "),w+=Q);return w}var clQ=(A)=>{let Q=plQ(A),{conflictingClassGroups:B,conflictingClassGroupModifiers:w}=A;return{getClassGroupId:(f)=>{let Y=f.split("-");if(Y[0]===""&&Y.length!==1)Y.shift();return vO1(Y,Q)||llQ(f)},getConflictingClassGroupIds:(f,Y)=>{let X=B[f]||[];if(Y&&w[f])return[...X,...w[f]];return X}}},vO1=(A,Q)=>{if(A.length===0)return Q.classGroupId;let B=A[0],w=Q.nextPart.get(B),$=w?vO1(A.slice(1),w):void 0;if($)return $;if(Q.validators.length===0)return;let D=A.join("-");return Q.validators.find(({validator:f})=>f(D))?.classGroupId},kO1=/^\[(.+)\]$/,llQ=(A)=>{if(kO1.test(A)){let Q=kO1.exec(A)[1],B=Q?.substring(0,Q.indexOf(":"));if(B)return"arbitrary.."+B}},plQ=(A)=>{let{theme:Q,prefix:B}=A,w={nextPart:new Map,validators:[]};return dlQ(Object.entries(A.classGroups),B).forEach(([D,f])=>{ES0(f,w,D,Q)}),w},ES0=(A,Q,B,w)=>{A.forEach(($)=>{if(typeof $==="string"){let D=$===""?Q:OO1(Q,$);D.classGroupId=B;return}if(typeof $==="function"){if(ilQ($)){ES0($(w),Q,B,w);return}Q.validators.push({validator:$,classGroupId:B});return}Object.entries($).forEach(([D,f])=>{ES0(f,OO1(Q,D),B,w)})})},OO1=(A,Q)=>{let B=A;return Q.split("-").forEach((w)=>{if(!B.nextPart.has(w))B.nextPart.set(w,{nextPart:new Map,validators:[]});B=B.nextPart.get(w)}),B},ilQ=(A)=>A.isThemeGetter,dlQ=(A,Q)=>{if(!Q)return A;return A.map(([B,w])=>{let $=w.map((D)=>{if(typeof D==="string")return Q+D;if(typeof D==="object")return Object.fromEntries(Object.entries(D).map(([f,Y])=>[Q+f,Y]));return D});return[B,$]})},nlQ=(A)=>{if(A<1)return{get:()=>{return},set:()=>{}};let Q=0,B=new Map,w=new Map,$=(D,f)=>{if(B.set(D,f),Q++,Q>A)Q=0,w=B,B=new Map};return{get(D){let f=B.get(D);if(f!==void 0)return f;if((f=w.get(D))!==void 0)return $(D,f),f},set(D,f){if(B.has(D))B.set(D,f);else $(D,f)}}};var rlQ=(A)=>{let{separator:Q,experimentalParseClassName:B}=A,w=Q.length===1,$=Q[0],D=Q.length,f=(Y)=>{let X=[],H=0,W=0,Z;for(let b=0;b<Y.length;b++){let N=Y[b];if(H===0){if(N===$&&(w||Y.slice(b,b+D)===Q)){X.push(Y.slice(W,b)),W=b+D;continue}if(N==="/"){Z=b;continue}}if(N==="[")H++;else if(N==="]")H--}let G=X.length===0?Y:Y.substring(W),F=G.startsWith("!"),I=F?G.substring(1):G,L=Z&&Z>W?Z-W:void 0;return{modifiers:X,hasImportantModifier:F,baseClassName:I,maybePostfixModifierPosition:L}};if(B)return(Y)=>B({className:Y,parseClassName:f});return f},olQ=(A)=>{if(A.length<=1)return A;let Q=[],B=[];return A.forEach((w)=>{if(w[0]==="[")Q.push(...B.sort(),w),B=[];else B.push(w)}),Q.push(...B.sort()),Q},slQ=(A)=>({cache:nlQ(A.cacheSize),parseClassName:rlQ(A),...clQ(A)}),alQ=/\s+/,tlQ=(A,Q)=>{let{parseClassName:B,getClassGroupId:w,getConflictingClassGroupIds:$}=Q,D=[],f=A.trim().split(alQ),Y="";for(let X=f.length-1;X>=0;X-=1){let H=f[X],{modifiers:W,hasImportantModifier:Z,baseClassName:G,maybePostfixModifierPosition:F}=B(H),I=Boolean(F),L=w(I?G.substring(0,F):G);if(!L){if(!I){Y=H+(Y.length>0?" "+Y:Y);continue}if(L=w(G),!L){Y=H+(Y.length>0?" "+Y:Y);continue}I=!1}let b=olQ(W).join(":"),N=Z?b+"!":b,M=N+L;if(D.includes(M))continue;D.push(M);let j=$(L,I);for(let g=0;g<j.length;++g){let E=j[g];D.push(N+E)}Y=H+(Y.length>0?" "+Y:Y)}return Y};function elQ(){let A=0,Q,B,w="";while(A<arguments.length)if(Q=arguments[A++]){if(B=hO1(Q))w&&(w+=" "),w+=B}return w}var hO1=(A)=>{if(typeof A==="string")return A;let Q,B="";for(let w=0;w<A.length;w++)if(A[w]){if(Q=hO1(A[w]))B&&(B+=" "),B+=Q}return B};function xO1(A,...Q){let B,w,$,D=f;function f(X){let H=Q.reduce((W,Z)=>Z(W),A());return B=slQ(H),w=B.cache.get,$=B.cache.set,D=Y,Y(X)}function Y(X){let H=w(X);if(H)return H;let W=tlQ(X,B);return $(X,W),W}return function(){return D(elQ.apply(null,arguments))}}var a8=(A)=>{let Q=(B)=>B[A]||[];return Q.isThemeGetter=!0,Q},CO1=/^\[(?:([a-z-]+):)?(.+)\]$/i,ApQ=/^\d+\/\d+$/,QpQ=new Set(["px","full","screen"]),BpQ=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,wpQ=/\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$/,$pQ=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,DpQ=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,fpQ=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,v3=(A)=>aC(A)||QpQ.has(A)||ApQ.test(A),dJ=(A)=>tC(A,"length",GpQ),aC=(A)=>Boolean(A)&&!Number.isNaN(Number(A)),yS0=(A)=>tC(A,"number",aC),hd=(A)=>Boolean(A)&&Number.isInteger(Number(A)),YpQ=(A)=>A.endsWith("%")&&aC(A.slice(0,-1)),tQ=(A)=>CO1.test(A),nJ=(A)=>BpQ.test(A),XpQ=new Set(["length","size","percentage"]),HpQ=(A)=>tC(A,XpQ,yO1),WpQ=(A)=>tC(A,"position",yO1),ZpQ=new Set(["image","url"]),KpQ=(A)=>tC(A,ZpQ,qpQ),UpQ=(A)=>tC(A,"",zpQ),Cd=()=>!0,tC=(A,Q,B)=>{let w=CO1.exec(A);if(w){if(w[1])return typeof Q==="string"?w[1]===Q:Q.has(w[1]);return B(w[2])}return!1},GpQ=(A)=>wpQ.test(A)&&!$pQ.test(A),yO1=()=>!1,zpQ=(A)=>DpQ.test(A),qpQ=(A)=>fpQ.test(A);var RO1=()=>{let A=a8("colors"),Q=a8("spacing"),B=a8("blur"),w=a8("brightness"),$=a8("borderColor"),D=a8("borderRadius"),f=a8("borderSpacing"),Y=a8("borderWidth"),X=a8("contrast"),H=a8("grayscale"),W=a8("hueRotate"),Z=a8("invert"),G=a8("gap"),F=a8("gradientColorStops"),I=a8("gradientColorStopPositions"),L=a8("inset"),b=a8("margin"),N=a8("opacity"),M=a8("padding"),j=a8("saturate"),g=a8("scale"),E=a8("sepia"),y=a8("skew"),h=a8("space"),T=a8("translate"),S=()=>["auto","contain","none"],c=()=>["auto","hidden","clip","visible","scroll"],m=()=>["auto",tQ,Q],w0=()=>[tQ,Q],o=()=>["",v3,dJ],v=()=>["auto",aC,tQ],P=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],x=()=>["solid","dashed","dotted","double","none"],p=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],l=()=>["start","end","center","between","around","evenly","stretch"],A0=()=>["","0",tQ],n=()=>["auto","avoid","all","avoid-page","page","left","right","column"],Z0=()=>[aC,tQ];return{cacheSize:500,separator:":",theme:{colors:[Cd],spacing:[v3,dJ],blur:["none","",nJ,tQ],brightness:Z0(),borderColor:[A],borderRadius:["none","","full",nJ,tQ],borderSpacing:w0(),borderWidth:o(),contrast:Z0(),grayscale:A0(),hueRotate:Z0(),invert:A0(),gap:w0(),gradientColorStops:[A],gradientColorStopPositions:[YpQ,dJ],inset:m(),margin:m(),opacity:Z0(),padding:w0(),saturate:Z0(),scale:Z0(),sepia:A0(),skew:Z0(),space:w0(),translate:w0()},classGroups:{aspect:[{aspect:["auto","square","video",tQ]}],container:["container"],columns:[{columns:[nJ]}],"break-after":[{"break-after":n()}],"break-before":[{"break-before":n()}],"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:[...P(),tQ]}],overflow:[{overflow:c()}],"overflow-x":[{"overflow-x":c()}],"overflow-y":[{"overflow-y":c()}],overscroll:[{overscroll:S()}],"overscroll-x":[{"overscroll-x":S()}],"overscroll-y":[{"overscroll-y":S()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[L]}],"inset-x":[{"inset-x":[L]}],"inset-y":[{"inset-y":[L]}],start:[{start:[L]}],end:[{end:[L]}],top:[{top:[L]}],right:[{right:[L]}],bottom:[{bottom:[L]}],left:[{left:[L]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",hd,tQ]}],basis:[{basis:m()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",tQ]}],grow:[{grow:A0()}],shrink:[{shrink:A0()}],order:[{order:["first","last","none",hd,tQ]}],"grid-cols":[{"grid-cols":[Cd]}],"col-start-end":[{col:["auto",{span:["full",hd,tQ]},tQ]}],"col-start":[{"col-start":v()}],"col-end":[{"col-end":v()}],"grid-rows":[{"grid-rows":[Cd]}],"row-start-end":[{row:["auto",{span:[hd,tQ]},tQ]}],"row-start":[{"row-start":v()}],"row-end":[{"row-end":v()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",tQ]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",tQ]}],gap:[{gap:[G]}],"gap-x":[{"gap-x":[G]}],"gap-y":[{"gap-y":[G]}],"justify-content":[{justify:["normal",...l()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...l(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...l(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[M]}],px:[{px:[M]}],py:[{py:[M]}],ps:[{ps:[M]}],pe:[{pe:[M]}],pt:[{pt:[M]}],pr:[{pr:[M]}],pb:[{pb:[M]}],pl:[{pl:[M]}],m:[{m:[b]}],mx:[{mx:[b]}],my:[{my:[b]}],ms:[{ms:[b]}],me:[{me:[b]}],mt:[{mt:[b]}],mr:[{mr:[b]}],mb:[{mb:[b]}],ml:[{ml:[b]}],"space-x":[{"space-x":[h]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[h]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",tQ,Q]}],"min-w":[{"min-w":[tQ,Q,"min","max","fit"]}],"max-w":[{"max-w":[tQ,Q,"none","full","min","max","fit","prose",{screen:[nJ]},nJ]}],h:[{h:[tQ,Q,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[tQ,Q,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[tQ,Q,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[tQ,Q,"auto","min","max","fit"]}],"font-size":[{text:["base",nJ,dJ]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",yS0]}],"font-family":[{font:[Cd]}],"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",tQ]}],"line-clamp":[{"line-clamp":["none",aC,yS0]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",v3,tQ]}],"list-image":[{"list-image":["none",tQ]}],"list-style-type":[{list:["none","disc","decimal",tQ]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[A]}],"placeholder-opacity":[{"placeholder-opacity":[N]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[A]}],"text-opacity":[{"text-opacity":[N]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...x(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",v3,dJ]}],"underline-offset":[{"underline-offset":["auto",v3,tQ]}],"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:w0()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",tQ]}],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",tQ]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[N]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...P(),WpQ]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",HpQ]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},KpQ]}],"bg-color":[{bg:[A]}],"gradient-from-pos":[{from:[I]}],"gradient-via-pos":[{via:[I]}],"gradient-to-pos":[{to:[I]}],"gradient-from":[{from:[F]}],"gradient-via":[{via:[F]}],"gradient-to":[{to:[F]}],rounded:[{rounded:[D]}],"rounded-s":[{"rounded-s":[D]}],"rounded-e":[{"rounded-e":[D]}],"rounded-t":[{"rounded-t":[D]}],"rounded-r":[{"rounded-r":[D]}],"rounded-b":[{"rounded-b":[D]}],"rounded-l":[{"rounded-l":[D]}],"rounded-ss":[{"rounded-ss":[D]}],"rounded-se":[{"rounded-se":[D]}],"rounded-ee":[{"rounded-ee":[D]}],"rounded-es":[{"rounded-es":[D]}],"rounded-tl":[{"rounded-tl":[D]}],"rounded-tr":[{"rounded-tr":[D]}],"rounded-br":[{"rounded-br":[D]}],"rounded-bl":[{"rounded-bl":[D]}],"border-w":[{border:[Y]}],"border-w-x":[{"border-x":[Y]}],"border-w-y":[{"border-y":[Y]}],"border-w-s":[{"border-s":[Y]}],"border-w-e":[{"border-e":[Y]}],"border-w-t":[{"border-t":[Y]}],"border-w-r":[{"border-r":[Y]}],"border-w-b":[{"border-b":[Y]}],"border-w-l":[{"border-l":[Y]}],"border-opacity":[{"border-opacity":[N]}],"border-style":[{border:[...x(),"hidden"]}],"divide-x":[{"divide-x":[Y]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[Y]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[N]}],"divide-style":[{divide:x()}],"border-color":[{border:[$]}],"border-color-x":[{"border-x":[$]}],"border-color-y":[{"border-y":[$]}],"border-color-s":[{"border-s":[$]}],"border-color-e":[{"border-e":[$]}],"border-color-t":[{"border-t":[$]}],"border-color-r":[{"border-r":[$]}],"border-color-b":[{"border-b":[$]}],"border-color-l":[{"border-l":[$]}],"divide-color":[{divide:[$]}],"outline-style":[{outline:["",...x()]}],"outline-offset":[{"outline-offset":[v3,tQ]}],"outline-w":[{outline:[v3,dJ]}],"outline-color":[{outline:[A]}],"ring-w":[{ring:o()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[A]}],"ring-opacity":[{"ring-opacity":[N]}],"ring-offset-w":[{"ring-offset":[v3,dJ]}],"ring-offset-color":[{"ring-offset":[A]}],shadow:[{shadow:["","inner","none",nJ,UpQ]}],"shadow-color":[{shadow:[Cd]}],opacity:[{opacity:[N]}],"mix-blend":[{"mix-blend":[...p(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":p()}],filter:[{filter:["","none"]}],blur:[{blur:[B]}],brightness:[{brightness:[w]}],contrast:[{contrast:[X]}],"drop-shadow":[{"drop-shadow":["","none",nJ,tQ]}],grayscale:[{grayscale:[H]}],"hue-rotate":[{"hue-rotate":[W]}],invert:[{invert:[Z]}],saturate:[{saturate:[j]}],sepia:[{sepia:[E]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[B]}],"backdrop-brightness":[{"backdrop-brightness":[w]}],"backdrop-contrast":[{"backdrop-contrast":[X]}],"backdrop-grayscale":[{"backdrop-grayscale":[H]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[W]}],"backdrop-invert":[{"backdrop-invert":[Z]}],"backdrop-opacity":[{"backdrop-opacity":[N]}],"backdrop-saturate":[{"backdrop-saturate":[j]}],"backdrop-sepia":[{"backdrop-sepia":[E]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[f]}],"border-spacing-x":[{"border-spacing-x":[f]}],"border-spacing-y":[{"border-spacing-y":[f]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",tQ]}],duration:[{duration:Z0()}],ease:[{ease:["linear","in","out","in-out",tQ]}],delay:[{delay:Z0()}],animate:[{animate:["none","spin","ping","pulse","bounce",tQ]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[g]}],"scale-x":[{"scale-x":[g]}],"scale-y":[{"scale-y":[g]}],rotate:[{rotate:[hd,tQ]}],"translate-x":[{"translate-x":[T]}],"translate-y":[{"translate-y":[T]}],"skew-x":[{"skew-x":[y]}],"skew-y":[{"skew-y":[y]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",tQ]}],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",tQ]}],"caret-color":[{caret:[A]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":w0()}],"scroll-mx":[{"scroll-mx":w0()}],"scroll-my":[{"scroll-my":w0()}],"scroll-ms":[{"scroll-ms":w0()}],"scroll-me":[{"scroll-me":w0()}],"scroll-mt":[{"scroll-mt":w0()}],"scroll-mr":[{"scroll-mr":w0()}],"scroll-mb":[{"scroll-mb":w0()}],"scroll-ml":[{"scroll-ml":w0()}],"scroll-p":[{"scroll-p":w0()}],"scroll-px":[{"scroll-px":w0()}],"scroll-py":[{"scroll-py":w0()}],"scroll-ps":[{"scroll-ps":w0()}],"scroll-pe":[{"scroll-pe":w0()}],"scroll-pt":[{"scroll-pt":w0()}],"scroll-pr":[{"scroll-pr":w0()}],"scroll-pb":[{"scroll-pb":w0()}],"scroll-pl":[{"scroll-pl":w0()}],"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",tQ]}],fill:[{fill:[A,"none"]}],"stroke-w":[{stroke:[v3,dJ,yS0]}],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"]}}},FpQ=(A,{cacheSize:Q,prefix:B,separator:w,experimentalParseClassName:$,extend:D={},override:f={}})=>{yd(A,"cacheSize",Q),yd(A,"prefix",B),yd(A,"separator",w),yd(A,"experimentalParseClassName",$);for(let Y in f)IpQ(A[Y],f[Y]);for(let Y in D)VpQ(A[Y],D[Y]);return A},yd=(A,Q,B)=>{if(B!==void 0)A[Q]=B},IpQ=(A,Q)=>{if(Q)for(let B in Q)yd(A,B,Q[B])},VpQ=(A,Q)=>{if(Q)for(let B in Q){let w=Q[B];if(w!==void 0)A[B]=(A[B]||[]).concat(w)}},T$0=(A,...Q)=>typeof A==="function"?xO1(RO1,A,...Q):xO1(()=>FpQ(RO1(),A),...Q);var JpQ=T$0({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 $2(...A){return JpQ(sC(A))}var EO1=(A)=>typeof A==="boolean"?`${A}`:A===0?"0":A,gO1=sC,D8=(A,Q)=>(B)=>{var w;if((Q===null||Q===void 0?void 0:Q.variants)==null)return gO1(A,B===null||B===void 0?void 0:B.class,B===null||B===void 0?void 0:B.className);let{variants:$,defaultVariants:D}=Q,f=Object.keys($).map((H)=>{let W=B===null||B===void 0?void 0:B[H],Z=D===null||D===void 0?void 0:D[H];if(W===null)return null;let G=EO1(W)||EO1(Z);return $[H][G]}),Y=B&&Object.entries(B).reduce((H,W)=>{let[Z,G]=W;if(G===void 0)return H;return H[Z]=G,H},{}),X=Q===null||Q===void 0?void 0:(w=Q.compoundVariants)===null||w===void 0?void 0:w.reduce((H,W)=>{let{class:Z,className:G,...F}=W;return Object.entries(F).every((I)=>{let[L,b]=I;return Array.isArray(b)?b.includes({...D,...Y}[L]):{...D,...Y}[L]===b})?[...H,Z,G]:H},[]);return gO1(A,f,X,B===null||B===void 0?void 0:B.class,B===null||B===void 0?void 0:B.className)};import{jsxDEV as gS0}from"preact/jsx-dev-runtime";var TO1=D8("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 TS0({variant:A,title:Q,children:B,className:w}){return gS0("div",{className:$2(TO1({variant:A}),w),role:"alert",children:[Q&&gS0("p",{className:"font-medium text-current opacity-90",children:Q},void 0,!1,void 0,this),gS0("div",{className:$2(Q&&"mt-1","text-sm text-current opacity-75"),children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as LpQ}from"preact/jsx-dev-runtime";var SO1=D8("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 LM({variant:A,size:Q,className:B,children:w,ssrOnClick:$,type:D="button",...f}){return LpQ("button",{type:D,className:$2(SO1({variant:A,size:Q}),B),...f,...$&&{onclick:$},children:w},void 0,!1,void 0,this)}import{jsxDEV as bpQ}from"preact/jsx-dev-runtime";var mO1=D8("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 D9({href:A,children:Q,variant:B,size:w,external:$=!1,className:D,"aria-label":f}){let Y=$?{target:"_blank",rel:"noopener noreferrer"}:{};return bpQ("a",{href:A,className:$2(mO1({variant:B,size:w}),D),"aria-label":f,...Y,children:Q},void 0,!1,void 0,this)}import{jsxDEV as S$0}from"preact/jsx-dev-runtime";var uO1=D8("transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2",{variants:{variant:{default:"rounded-[10px] bg-theme-subtle border border-theme text-theme-muted hover:text-accent hover:border-brand/40",light:"rounded-[10px] bg-theme-subtle border border-theme text-theme-muted hover:text-accent",dark:"rounded-[10px] bg-theme-dark hover:bg-theme-muted text-theme-inverse",footer:"rounded-full 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"}}),NpQ={sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6"};function eC({variant:A,size:Q,className:B}){let w=NpQ[Q??"md"];return S$0("button",{onclick:"toggleTheme()",type:"button",className:$2(uO1({variant:A,size:Q}),B),"aria-label":"Toggle dark mode",children:S$0("svg",{className:$2(w,"transition-colors"),fill:"none",stroke:"currentColor",strokeWidth:1.6,viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:[S$0("path",{className:"sun-icon",strokeLinecap:"round",strokeLinejoin:"round",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),S$0("path",{className:"moon-icon",strokeLinecap:"round",strokeLinejoin:"round",d:"M20.354 15.354A9 9 0 018.646 3.646 9 9 0 1020.354 15.354z"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}import{jsxDEV as SS0}from"preact/jsx-dev-runtime";var cO1=D8("flex flex-wrap",{variants:{orientation:{horizontal:"justify-center gap-6 items-center",vertical:"flex-col gap-2.5"}},defaultVariants:{orientation:"horizontal"}});function m$0({items:A,className:Q,linkClassName:B="hover:text-accent transition-colors",orientation:w,children:$}){if(A.length===0&&!$)return null;let D=[...A].sort((f,Y)=>f.priority-Y.priority);return SS0("ul",{className:$2(cO1({orientation:w}),Q),children:[D.map((f)=>SS0("li",{children:SS0("a",{href:f.href,className:B,children:f.label},void 0,!1,void 0,this)},f.href,!1,void 0,this)),$]},void 0,!0,void 0,this)}import{jsxDEV as Eb8}from"preact/jsx-dev-runtime";import{jsxDEV as Sb8}from"preact/jsx-dev-runtime";import{createContext as jpQ,h as _pQ}from"preact";import{useContext as MpQ}from"preact/hooks";var mS0=jpQ(null);function Ay({headCollector:A,children:Q}){return _pQ(mS0.Provider,{value:A},Q)}function lO1(){return MpQ(mS0)}function NQ(A){let Q=lO1();if(Q)Q.setHeadProps(A);return null}import{createContext as QaQ,h as BaQ}from"preact";import{useContext as waQ}from"preact/hooks";hN0();var eh1=f1(th1(),1),esQ=new Qc({gfm:!0,breaks:!0}),AaQ={allowedTags:["h1","h2","h3","h4","h5","h6","p","br","hr","ul","ol","li","blockquote","cite","code","pre","em","strong","del","ins","sub","sup","a","img","span","table","thead","tbody","tr","th","td","div"],allowedAttributes:{a:["href","title","name"],img:["src","srcset","sizes","alt","title","width","height","class","loading","decoding"],code:["class"],pre:["class"],span:["class"],cite:["class"],div:["class"],th:["align","colspan","rowspan","scope"],td:["align","colspan","rowspan"]},allowedSchemes:["http","https","mailto","tel"],allowedSchemesByTag:{img:["http","https","entity"]},allowProtocolRelative:!1,disallowedTagsMode:"discard"};function Hu0(A,Q){let{imageRenderer:B}=Q??{},$=(B?new Qc({gfm:!0,breaks:!0}).use({renderer:{image(D,f,Y){return B(D,f,Y)??!1}}}):esQ).parse(A);return $=$.replace(/<\/blockquote>\s*<p>(\u2014|--|\u2013)([\s\S]*?)<\/p>/g,`</blockquote>
|
|
4899
|
+
`)}}p0();class O$0 extends PB{directorySync;constructor(A,Q,B){super(A,{schema:xS0,jobTypeName:"directory-export"});this.directorySync=B}async process(A,Q,B){this.logger.debug("Processing directory export job",{jobId:Q,data:A});let w=Date.now();try{let $=await this.directorySync.exportEntitiesWithProgress(A.entityTypes,B,A.batchSize??100);return this.logger.debug("Directory export job completed",{jobId:Q,exported:$.exported,failed:$.failed,duration:Date.now()-w}),$}catch($){throw this.logger.error("Directory export job failed",{jobId:Q,error:$}),$}}summarizeDataForLog(A){return{entityTypes:A.entityTypes??"all",batchSize:A.batchSize}}}p0();class x$0 extends PB{directorySync;constructor(A,Q,B){super(A,{schema:OS0,jobTypeName:"directory-import"});this.directorySync=B}async process(A,Q,B){this.logger.debug("Processing directory import job",{jobId:Q,data:A});let w=Date.now();try{let $=await this.directorySync.importEntitiesWithProgress(A.paths,B,A.batchSize??100);return this.logger.debug("Directory import job completed",{jobId:Q,imported:$.imported,skipped:$.skipped,failed:$.failed,quarantined:$.quarantined,duration:Date.now()-w}),$}catch($){throw this.logger.error("Directory import job failed",{jobId:Q,error:$}),$}}summarizeDataForLog(A){return{pathCount:A.paths?.length??"all",batchSize:A.batchSize}}}p0();class R$0 extends PB{directorySync;context;constructor(A,Q,B){super(A,{schema:PS0,jobTypeName:"directory-sync"});this.context=Q,this.directorySync=B}async process(A,Q,B){let w=Date.now(),$=A.syncDirection??"both";this.logger.info("Starting directory sync job",{jobId:Q,operation:A.operation,syncDirection:$});let D={imported:0,skipped:0,failed:0,quarantined:0,quarantinedFiles:[],errors:[],jobIds:[]},f={exported:0,failed:0,errors:[]};if($!=="export")if(await B.report({progress:10,message:"Scanning directory for changes"}),D=await this.importWithProgress(A.paths,B),$==="import")await this.waitForImportJobs(D.jobIds,B),await B.report({progress:100,message:`Import complete: ${D.imported} imported`});else await B.report({progress:50,message:`Imported ${D.imported} entities`}),await this.waitForImportJobs(D.jobIds,B),await B.report({progress:56,message:"Processing complete, starting export"});if($!=="import"){let X=$==="export"?10:60;await B.report({progress:X,message:"Exporting entities to directory"}),f=await this.exportWithProgress(A.entityTypes,B),await B.report({progress:100,message:$==="export"?`Export complete: ${f.exported} exported`:`Sync complete: ${D.imported} imported, ${f.exported} exported`})}let Y=Date.now()-w;return this.logger.info("Directory sync job completed",{jobId:Q,duration:Y,imported:D.imported,exported:f.exported}),{import:D,export:f,duration:Y}}async importWithProgress(A,Q){try{return await this.directorySync.importEntitiesWithProgress(A,Q,10)}catch(B){throw this.logger.error("Import phase failed",{error:B}),B}}async exportWithProgress(A,Q){try{return await this.directorySync.exportEntitiesWithProgress(A,Q,10)}catch(B){throw this.logger.error("Export phase failed",{error:B}),B}}async waitForImportJobs(A,Q){if(A.length===0)return;this.logger.debug(`Waiting for ${A.length} import jobs to complete`);let{entityService:B}=this.context,w=300000,$=500,D=Date.now(),f=async()=>{let X=(await Promise.all(A.map((W)=>B.getAsyncJobStatus(W)))).filter((W)=>W&&(W.status==="completed"||W.status==="failed")).length;if(X===A.length){this.logger.debug("All import jobs completed");return}if(Date.now()-D>w){this.logger.warn(`Timeout waiting for import jobs (${X}/${A.length} completed)`);return}let H=Math.round(X/A.length*100);return await Q.report({progress:50+Math.round(H*0.05),message:`Processing ${X}/${A.length} entities`}),await new Promise((W)=>setTimeout(W,$)),f()};return f()}summarizeDataForLog(A){return{operation:A.operation,syncDirection:A.syncDirection}}}p0();class v$0 extends PB{context;directorySync;gitSync;constructor(A,Q,B,w){super(A,{schema:kS0,jobTypeName:"sync-request"});this.context=Q;this.directorySync=B;this.gitSync=w}async process(A,Q,B){await B.report({progress:5,message:"Pulling latest content from git"});let w=await this.gitSync.withLock(async()=>{return await this.gitSync.pull(),await B.report({progress:35,message:"Scanning pulled content for sync changes"}),this.directorySync.queueSyncBatch(this.context,A.source,{rootJobId:Q,interfaceType:A.interfaceType,channelId:A.channelId})});if(!w)return await B.report({progress:100,message:"Sync complete: no files to import"}),{gitPulled:!0,batchQueued:!1};return await B.report({progress:100,message:`Sync queued: ${w.importOperationsCount} import jobs for ${w.totalFiles} files`}),zlQ(w)}summarizeDataForLog(A){return{source:A.source,interfaceType:A.interfaceType,channelId:A.channelId}}}function zlQ(A){return{gitPulled:!0,batchQueued:!0,batchId:A.batchId,importOperations:A.importOperationsCount,totalFiles:A.totalFiles}}p0();class h$0 extends PB{context;constructor(A,Q,B){super(A,{schema:P$0,jobTypeName:"directory-delete"});this.context=Q}async process(A,Q,B){let w=P$0.parse(A);this.logger.info("Processing entity deletion for removed file",{entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}),await B.report({progress:0,total:1,message:`Deleting ${w.entityType}:${w.entityId}`});try{let $=await this.context.entityService.deleteEntity({entityType:w.entityType,id:w.entityId});if($)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 B.report({progress:1,total:1,message:`Deleted ${w.entityType}:${w.entityId}`}),{deleted:$,entityId:w.entityId,entityType:w.entityType,filePath:w.filePath}}catch($){throw this.logger.error("Failed to delete entity",{entityId:w.entityId,entityType:w.entityType,error:$}),$}}summarizeDataForLog(A){return{entityId:A.entityId,entityType:A.entityType,filePath:A.filePath}}}p0();K0();var qlQ=K.object({});class C$0 extends PB{directorySync;constructor(A,Q){super(A,{schema:qlQ,jobTypeName:"directory-cleanup"});this.directorySync=Q}async process(A,Q,B){await B.report({progress:0,message:"Removing orphaned entities"});let w=await this.directorySync.removeOrphanedEntities();return await B.report({progress:100,message:`Cleanup complete: ${w.deleted} orphans removed`}),w}}p0();D4();K0();Cw();D4();import{readFile as FlQ,writeFile as IlQ}from"fs/promises";var VlQ=RS0;class y$0 extends PB{context;fetcher;constructor(A,Q,B=NH){super(Q,{schema:VlQ,jobTypeName:"cover-image-convert"});this.context=A,this.fetcher=B}async process(A,Q,B){let{filePath:w,sourceUrl:$,postTitle:D,postSlug:f,customAlt:Y}=A;this.logger.debug("Starting image conversion job",{jobId:Q,filePath:w,sourceUrl:$,postSlug:f});try{await this.reportProgress(B,{progress:MQ.INIT,message:`Reading file: ${w}`});let X;try{X=await FlQ(w,"utf-8")}catch(L){return this.logger.error("Failed to read file",{filePath:w,error:hA(L)}),x6.failure(L)}let H;try{H=lB(X)}catch(L){return this.logger.warn("Failed to parse markdown",{filePath:w,error:hA(L)}),x6.failure(L)}let W=H.frontmatter;if(W.coverImageId)return this.logger.debug("File already has coverImageId, skipping",{filePath:w}),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Already converted"}),{success:!0,skipped:!0};await this.reportProgress(B,{progress:MQ.FETCH,message:"Checking for existing image"});let Z=await this.context.entityService.listEntities({entityType:"image",options:{filter:{metadata:{sourceUrl:$}},limit:1}}),G;if(Z[0])G=Z[0].id,this.logger.debug("Reusing existing image entity",{sourceUrl:$,imageId:G}),await this.reportProgress(B,{progress:MQ.EXTRACT,message:`Reusing existing image: ${G}`});else{await this.reportProgress(B,{progress:MQ.PROCESS,message:`Fetching image from ${$}`});let L;try{L=await this.fetcher($)}catch(E){return this.logger.error("Failed to fetch image",{sourceUrl:$,error:hA(E)}),x6.failure(E)}await this.reportProgress(B,{progress:MQ.GENERATE,message:"Creating image entity"});let{base64:b}=$V(L),N=wj(b),M=DV(b);if(!N||!M)return this.logger.error("Could not detect image format or dimensions",{sourceUrl:$}),x6.failure(Error("Could not detect image format or dimensions"));G=`${f}-cover`;let j=`Cover image for ${D}`,g=Y??j;await this.context.entityService.createEntity({entity:{id:G,entityType:"image",content:L,metadata:{title:j,alt:g,format:N,width:M.width,height:M.height,sourceUrl:$}}}),this.logger.debug("Created image entity",{imageId:G,sourceUrl:$}),await this.reportProgress(B,{progress:MQ.EXTRACT,message:`Created image: ${G}`})}await this.reportProgress(B,{progress:MQ.SAVE,message:"Updating file"});let F={...W};delete F.coverImageUrl,delete F.coverImageAlt,F.coverImageId=G;let I=dz(F,H.content);try{await IlQ(w,I,"utf-8")}catch(L){return this.logger.error("Failed to write file",{filePath:w,error:hA(L)}),x6.failure(L)}return await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Conversion complete"}),this.logger.info("Image conversion complete",{filePath:w,imageId:G,sourceUrl:$}),{success:!0,imageId:G}}catch(X){return this.logger.error("Image conversion job failed",{jobId:Q,filePath:w,error:hA(X)}),x6.failure(X)}}summarizeDataForLog(A){return{filePath:A.filePath,sourceUrl:A.sourceUrl,postSlug:A.postSlug}}}p0();D4();K0();Cw();import{readFile as JlQ,writeFile as LlQ}from"fs/promises";class E$0 extends PB{converter;constructor(A,Q,B=NH){super(Q,{schema:vS0,jobTypeName:"inline-image-convert"});this.converter=new Id(A.entityService,Q,B)}async process(A,Q,B){let{filePath:w,postSlug:$}=A;this.logger.debug("Starting inline image conversion job",{jobId:Q,filePath:w,postSlug:$});try{await this.reportProgress(B,{progress:MQ.INIT,message:`Reading file: ${w}`});let D;try{D=await JlQ(w,"utf-8")}catch(X){let H=hA(X);return this.logger.error("Failed to read file",{filePath:w,error:H}),{success:!1,error:H}}await this.reportProgress(B,{progress:MQ.FETCH,message:"Detecting inline images"});let f=this.converter.detectInlineImages(D,$);if(f.length===0)return this.logger.debug("No inline images to convert",{filePath:w}),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"No images to convert"}),{success:!0,skipped:!0,convertedCount:0};this.logger.debug("Found inline images to convert",{filePath:w,count:f.length}),await this.reportProgress(B,{progress:MQ.PROCESS,message:`Converting ${f.length} images`});let Y=await this.converter.convert(D,$);if(!Y.converted)return this.logger.debug("No images were converted",{filePath:w}),await this.reportProgress(B,{progress:MQ.COMPLETE,message:"No images converted"}),{success:!0,skipped:!0,convertedCount:0};await this.reportProgress(B,{progress:MQ.SAVE,message:"Writing updated file"});try{await LlQ(w,Y.content,"utf-8")}catch(X){let H=hA(X);return this.logger.error("Failed to write file",{filePath:w,error:H}),{success:!1,error:H}}return await this.reportProgress(B,{progress:MQ.COMPLETE,message:"Conversion complete"}),this.logger.info("Inline image conversion complete",{filePath:w,convertedCount:Y.convertedCount}),{success:!0,convertedCount:Y.convertedCount}}catch(D){let f=hA(D);return this.logger.error("Inline image conversion job failed",{jobId:Q,filePath:w,error:f}),{success:!1,error:f}}}summarizeDataForLog(A){return{filePath:A.filePath,postSlug:A.postSlug}}}function YO1(A,Q,B){let w=($)=>B.child($);A.jobs.registerHandler("directory-sync",new R$0(w("DirectorySyncJobHandler"),A,Q)),A.jobs.registerHandler("directory-export",new O$0(w("DirectoryExportJobHandler"),A,Q)),A.jobs.registerHandler("directory-import",new x$0(w("DirectoryImportJobHandler"),A,Q)),A.jobs.registerHandler("directory-delete",new h$0(w("DirectoryDeleteJobHandler"),A,Q)),A.jobs.registerHandler("directory-cleanup",new C$0(w("DirectoryCleanupJobHandler"),Q)),A.jobs.registerHandler("cover-image-convert",new y$0(A,w("CoverImageConversionJobHandler"))),A.jobs.registerHandler("inline-image-convert",new E$0(A,w("InlineImageConversionJobHandler"))),B.debug("Registered async job handlers")}p0();import{unlink as blQ,access as NlQ}from"fs/promises";function XO1(A,Q,B,w){let{subscribe:$}=A.messaging,{entityService:D}=A;$("entity:created",async(f)=>{let{entity:Y}=f.payload;try{await Q.fileOps.writeEntity(Y),B.debug("Auto-exported created entity",{id:Y.id,entityType:Y.entityType})}catch(X){B.error("Auto-export FAILED for created entity",{id:Y.id,entityType:Y.entityType,error:X instanceof Error?X.message:String(X),stack:X instanceof Error?X.stack:void 0})}return{success:!0}}),$("entity:updated",async(f)=>{let{entityType:Y,entityId:X}=f.payload;try{let H=await D.getEntity({entityType:Y,id:X});if(!H)return B.debug("Entity not found in DB, skipping export",{entityType:Y,entityId:X}),{success:!1};await Q.fileOps.writeEntity(H),B.debug("Auto-exported updated entity",{id:H.id,entityType:H.entityType})}catch(H){B.error("Auto-export FAILED for updated entity",{entityType:Y,entityId:X,error:H instanceof Error?H.message:String(H),stack:H instanceof Error?H.stack:void 0})}return{success:!0}}),$("entity:deleted",async(f)=>{let{entityId:Y,entityType:X}=f.payload,H=Q.fileOps.getFilePath(Y,X);if(await NlQ(H).then(()=>!0,()=>!1))await blQ(H),B.debug("Auto-deleted entity file",{id:Y,entityType:X,path:H});return{success:!0}}),B.debug("Setup auto-sync for entity events",{entityTypes:w})}function HO1(A,Q,B){Q.setJobQueueCallback(async(w)=>{let $=[{type:w.type,data:w.data}];return A.jobs.enqueueBatch($,{priority:5,source:"directory-sync-watcher",rootJobId:S$(),metadata:{operationType:"file_operations",operationTarget:B,pluginId:"directory-sync"}})})}K0();p0();import{readdir as KO1,mkdir as _lQ,copyFile as MlQ}from"fs/promises";import{join as ZO1,resolve as hS0}from"path";import{join as jlQ}from"path";async function WO1(A){if(!await y5(jlQ(A,".git")))return!1;try{return await AK(A).revparse(["--verify","HEAD"]),!0}catch{return!1}}async function PlQ(A,Q){if(!await y5(A))return!0;if((await KO1(A)).filter(($)=>!$.startsWith(".")&&!$.startsWith("_")).length>0)return!1;if(await WO1(A))return Q.debug("Git repository with history detected - skipping seed content",{path:A}),!1;return!0}async function UO1(A,Q){let B=await KO1(A,{withFileTypes:!0});for(let w of B){let $=ZO1(A,w.name),D=ZO1(Q,w.name);if(w.isDirectory()){if(!await y5(D))await _lQ(D,{recursive:!0});await UO1($,D)}else await MlQ($,D)}}async function GO1(A,Q,B){let w=hS0(process.cwd(),A);B=B?hS0(B):hS0(process.cwd(),"seed-content");let $=await PlQ(w,Q);if($&&await y5(B))Q.debug("Copying seed content to brain-data directory"),await UO1(B,w),Q.debug("Seed content copied successfully");else if($)Q.debug("No seed content directory found, starting with empty brain-data");else Q.debug("brain-data directory not empty, skipping seed content")}function zO1(A,Q,B,w,$){let D=!1,f=async()=>{if(D)return;D=!0;let Y=Q();if(B.seedContent){let X=B.syncPath??A.dataDir;await GO1(X,w,B.seedContentPath)}try{if($){w.debug("Git enabled \u2014 pulling before import");let H=await $.pull();if(H.files.length>0)w.info("Pulled changes from remote",{filesChanged:H.files.length})}w.debug("Starting initial sync");let X=await Y.sync();w.debug("Initial sync completed",{imported:X.import.imported,failed:X.import.failed,duration:X.duration}),await A.messaging.send({type:FN.initialSyncCompleted,payload:{success:!0},...{broadcast:!0}})}catch(X){w.error("Initial sync failed",X),await A.messaging.send({type:FN.initialSyncCompleted,payload:{success:!1,error:hA(X)},...{broadcast:!0}})}};A.messaging.subscribe(FN.pluginsRegistered,async()=>{return w.debug("Plugins registered, starting initial sync"),await f(),{success:!0}})}K0();function qO1(A,Q,B,w){let $=new QN(()=>{Q.withLock(async()=>{try{await Q.commit(),await Q.push()}catch(Y){w.error("Git auto-commit failed",{error:Y})}})},B),D=["entity:created","entity:updated","entity:deleted"],f=[];for(let Y of D){let X=A.subscribe(Y,async()=>{return $.trigger(),{success:!0}});f.push(X)}return()=>{$.dispose();for(let Y of f)Y()}}function FO1(A,Q,B,w,$){if(w<=0)return()=>{};let D=w*60*1000,f=!1,Y=async()=>{if(f)return;f=!0;try{let{files:H,result:W}=await A.withLock(async()=>{let Z=await A.pull();if(Z.files.length===0)return{files:[],result:null};let G=await Q.queueSyncBatch(B,"periodic-sync");return{files:Z.files,result:G}});if(H.length>0)$.info("Periodic sync: pulled changes",{filesChanged:H.length});if(W)$.debug("Periodic sync: queued imports",{importOperations:W.importOperationsCount,totalFiles:W.totalFiles})}catch(H){$.error("Periodic git sync failed",{error:H})}finally{f=!1}},X=setInterval(()=>{Y()},D);return $.info("Started periodic git sync",{intervalMinutes:w}),()=>{clearInterval(X)}}import{spawnSync as VO1}from"child_process";import{cpSync as klQ,existsSync as IO1,mkdirSync as OlQ,mkdtempSync as xlQ,rmSync as RlQ}from"fs";import{tmpdir as vlQ}from"os";import{fileURLToPath as hlQ}from"url";import{join as ClQ,resolve as ylQ}from"path";function iJ(A,Q){let B=VO1("git",Q,{cwd:A,stdio:"pipe"});if(B.status!==0){let w=B.stderr.toString().trim(),$=B.stdout.toString().trim();throw Error(w||$||`git ${Q.join(" ")} failed`)}}function ElQ(A){return A.startsWith("file://")}function glQ(A){return hlQ(A)}function TlQ(A,Q){return VO1("git",["--git-dir",A,"show-ref","--verify","--quiet",`refs/heads/${Q}`]).status===0}async function JO1(A){if(!A.bootstrapFromSeed)return;if(!A.gitUrl||!ElQ(A.gitUrl))return;if(!A.seedContentPath)throw Error("directory-sync git.bootstrapFromSeed requires seedContentPath for local file:// remotes");let Q=A.branch??"main",B=glQ(A.gitUrl),w=ylQ(A.seedContentPath);if(!IO1(w))throw Error(`Seed content path not found: ${w}`);if(!IO1(B))A.logger.debug("Creating local bare content remote",{remotePath:B,branch:Q}),OlQ(B,{recursive:!0}),iJ(process.cwd(),["init","--bare",`--initial-branch=${Q}`,B]);if(TlQ(B,Q)){A.logger.debug("Content remote already initialized",{remotePath:B,branch:Q});return}A.logger.debug("Seeding local content remote",{remotePath:B,seedPath:w,branch:Q});let $=xlQ(ClQ(vlQ(),"directory-sync-seed-"));try{iJ($,["init",`--initial-branch=${Q}`]),iJ($,["config","user.name",A.authorName??"Brain"]),iJ($,["config","user.email",A.authorEmail??"brain@localhost"]),klQ(w,$,{recursive:!0}),iJ($,["add","."]),iJ($,["commit","-m","seed content remote"]),iJ($,["remote","add","origin",A.gitUrl]),iJ($,["push","-u","origin",Q])}finally{RlQ($,{recursive:!0,force:!0})}}function LO1(A,Q,B,w,$){let{subscribe:D}=A.messaging;D("entity:export:request",async(f)=>{try{return{success:!0,data:await Q().exportEntities(f.payload.entityTypes)}}catch(Y){return{success:!1,error:Y instanceof Error?Y.message:"Export failed"}}}),D("entity:import:request",async(f)=>{try{let Y=Q(),X=f.payload.paths,H=await Y.importEntities(X);if(X&&X.length>0)await Y.removeOrphanedEntities();return{success:!0,data:H}}catch(Y){return{success:!1,error:Y instanceof Error?Y.message:"Import failed"}}}),D("sync:status:request",async()=>{try{let Y=await Q().getStatus();return{success:!0,data:{syncPath:Y.syncPath,isInitialized:Y.exists,watchEnabled:Y.watching}}}catch(f){return{success:!1,error:f instanceof Error?f.message:"Status check failed"}}}),D("sync:configure:request",async(f)=>{try{return await B({syncPath:f.payload.syncPath}),{success:!0,data:{syncPath:f.payload.syncPath,configured:!0}}}catch(Y){return{success:!1,error:Y instanceof Error?Y.message:"Configuration failed"}}}),D("git-sync:get-repo-info",async()=>{if(!$?.repo)return{success:!1,error:"Git not configured"};return{success:!0,data:{repo:$.repo,branch:$.branch??"main"}}}),w.debug("Registered message handlers")}p0();K0();p0();K0();function bO1(A,Q){return BB(A,"history","Get version history for an entity from git. Without sha: returns commit list. With sha: returns entity content at that version.",K.object({entityType:K.string().describe("Entity type (e.g. post, note, link)"),id:K.string().describe("Entity ID"),sha:K.string().optional().describe("Commit SHA to retrieve content at. Omit to list commit history."),limit:K.number().int().positive().optional().default(10).describe("Max commits to return (list mode only)")}),async(B)=>{let w=`${B.entityType}/${B.id}.md`;try{if(B.sha){let D=await Q.show(B.sha,w);return b8({sha:B.sha,entityType:B.entityType,id:B.id,content:D},`Content at ${B.sha.slice(0,7)}`)}let $=await Q.log(w,B.limit);if($.length===0)return b8({commits:[]},`No history found for ${B.entityType}/${B.id}`);return b8({commits:$,entityType:B.entityType,id:B.id},`${$.length} version${$.length===1?"":"s"} found`)}catch($){return u$($ instanceof Error?$.message:"History lookup failed")}})}function NO1(A,Q,B,w){let $=[BB(B,"sync","Sync brain entities with the filesystem. Use this for refresh, pull, sync, or backup-to-git requests. Pulls from git if configured, then imports files. Git commit and push happen automatically after imports complete.",K.object({}),async(D,f)=>{try{let Y=f.channelId?`${f.interfaceType}:${f.channelId}`:`plugin:${B}`,X={interfaceType:f.interfaceType,channelId:f.channelId};if(w){let W=await Q.jobs.enqueue({type:"sync-request",data:{source:Y,interfaceType:X.interfaceType,channelId:X.channelId},toolContext:f});return b8({jobId:W,status:"queued",gitPulled:!0},"Sync queued: git pull and filesystem scan will run in the background")}let H=await A.queueSyncBatch(Q,Y,X);if(!H)return b8({gitPulled:!1},"No files to sync");return b8({batchId:H.batchId,importOperations:H.importOperationsCount,totalFiles:H.totalFiles,gitPulled:!1},`Sync started: ${H.importOperationsCount} import jobs queued for ${H.totalFiles} files`)}catch(Y){return u$(Y instanceof Error?Y.message:"Sync failed")}},{cli:{name:"sync"}}),BB(B,"status","Get sync and git repository status \u2014 last sync time, watching state, pending git changes. Use this for status questions, not for actually syncing or backing up.",K.object({}),async()=>{try{let D=await A.getStatus(),f={syncPath:D.syncPath,lastSync:D.lastSync?.toISOString(),watching:D.watching};if(w){let Y=await w.getStatus();f.git={isRepo:Y.isRepo,branch:Y.branch,hasChanges:Y.hasChanges,ahead:Y.ahead,behind:Y.behind,remote:Y.remote}}return b8(f)}catch(D){return u$(D instanceof Error?D.message:"Status check failed")}},{visibility:"public"})];if(w)$.push(bO1(B,w));return $}var jO1={name:"@brains/directory-sync",private:!0,version:"0.2.0-alpha.129",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/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",chokidar:"^3.5.3","simple-git":"^3.21.0"},devDependencies:{"@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"},peerDependencies:{}};class CS0 extends pQ{directorySync;gitSync;gitCleanups=[];constructor(A={}){super("directory-sync",jO1,A,Rd)}requireDirectorySync(){if(!this.directorySync)throw Error("DirectorySync service not initialized");return this.directorySync}hasGitSync(){return this.gitSync!==void 0}async onRegister(A){let{logger:Q,entityService:B}=A;A.templates.register({status:{name:"status",description:"Directory synchronization status",schema:vd,basePrompt:"",formatter:new k$0,requiredPermission:"anchor"}});let w=this.config.syncPath??A.dataDir;this.directorySync=new Vd({syncPath:w,autoSync:this.config.autoSync,watchInterval:this.config.watchInterval,includeMetadata:this.config.includeMetadata,entityTypes:this.config.entityTypes,deleteOnFileRemoval:this.config.deleteOnFileRemoval,entityService:B,logger:Q});try{await this.directorySync.initializeDirectory(),this.logger.debug("Directory structure initialized",{path:w})}catch(f){throw this.logger.error("Failed to initialize directory",f),f}await this.registerJobHandlers(A);let $=this.requireDirectorySync();if(XO1(A,$,this.logger,this.config.entityTypes),this.config.autoSync)HO1(A,$,this.config.syncPath??A.dataDir);let D=this.config.git!==void 0&&(this.config.git.repo!==void 0||this.config.git.gitUrl!==void 0);if(this.config.git&&!D)this.logger.debug("Git block present but no repo/gitUrl configured \u2014 git sync disabled");if(D&&this.config.git){await JO1({gitUrl:this.config.git.gitUrl,branch:this.config.git.branch,seedContentPath:this.config.seedContentPath,bootstrapFromSeed:this.config.git.bootstrapFromSeed,authorName:this.config.git.authorName,authorEmail:this.config.git.authorEmail,logger:this.logger.child("ContentRemoteBootstrap")});let f=this.config.syncPath??A.dataDir;if(this.gitSync=new MS0({logger:this.logger.child("GitSync"),dataDir:f,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}),A.jobs.registerHandler("sync-request",new v$0(this.logger.child("DirectorySyncRequestJobHandler"),A,this.requireDirectorySync(),this.gitSync)),this.gitCleanups.push(qO1(A.messaging,this.gitSync,this.config.commitDebounce,this.logger.child("GitAutoCommit"))),this.config.autoSync)this.gitCleanups.push(FO1(this.gitSync,this.requireDirectorySync(),A,this.config.syncInterval,this.logger.child("GitPeriodicSync")))}if(this.config.initialSync)zO1(A,()=>this.requireDirectorySync(),this.config,this.logger,this.gitSync);LO1(A,()=>this.requireDirectorySync(),(f)=>this.configure(f),this.logger,this.config.git)}async getTools(){let A=this.requireDirectorySync();return NO1(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 Q=this.getContext();this.directorySync=new Vd({...this.config,syncPath:A.syncPath,entityService:Q.entityService,logger:Q.logger}),await this.directorySync.initialize(),this.logger.info("Directory sync reconfigured",{path:A.syncPath})}async registerJobHandlers(A){YO1(A,this.requireDirectorySync(),this.logger)}}function JM(A={}){return new CS0(A)}p0();K0();var _O1={name:"@brains/email-resend",private:!0,version:"0.2.0-alpha.129",description:"Generic email delivery adapter for Resend",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/email-contracts":"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 ulQ=K.object({apiKey:K.string().min(1).optional(),from:K.string().min(1).optional()});class MO1 extends pQ{fetchImpl;constructor(A={},Q={}){super("email-resend",_O1,A,ulQ);this.fetchImpl=Q.fetchImpl??fetch}async onRegister(A){if(!this.config.apiKey||!this.config.from){this.logger.warn("Email Resend adapter is disabled because apiKey or from is missing");return}let Q=this.logger;A.messaging.subscribe(lB0,async(B)=>{let w=zxA.parse(B.payload);try{return{success:!0,data:await this.sendWithResend(w)}}catch($){if(w.sensitivity==="secret")Q.warn("Email delivery failed for a secret message");else Q.warn("Email delivery failed",{to:w.to,subject:w.subject,error:$ instanceof Error?$.message:String($)});return{success:!1,error:"Email delivery failed"}}})}async sendWithResend(A){let Q=this.config.apiKey,B=this.config.from;if(!Q||!B)return{status:"failed"};let w=await this.fetchImpl("https://api.resend.com/emails",{method:"POST",headers:{Authorization:`Bearer ${Q}`,"Content-Type":"application/json"},body:JSON.stringify({from:B,to:A.to,subject:A.subject,text:A.text,...A.html?{html:A.html}:{}})});if(!w.ok)throw Error("Resend email request failed");let $=await w.json();return $.id?{status:"sent",id:$.id}:{status:"sent"}}}function g$0(A={}){return new MO1(A)}p0();import{render as Sl1}from"preact-render-to-string";import{h as wP}from"preact";function PO1(A){var Q,B,w="";if(typeof A=="string"||typeof A=="number")w+=A;else if(typeof A=="object")if(Array.isArray(A)){var $=A.length;for(Q=0;Q<$;Q++)A[Q]&&(B=PO1(A[Q]))&&(w&&(w+=" "),w+=B)}else for(B in A)A[B]&&(w&&(w+=" "),w+=B);return w}function sC(){for(var A,Q,B=0,w="",$=arguments.length;B<$;B++)(A=arguments[B])&&(Q=PO1(A))&&(w&&(w+=" "),w+=Q);return w}var clQ=(A)=>{let Q=plQ(A),{conflictingClassGroups:B,conflictingClassGroupModifiers:w}=A;return{getClassGroupId:(f)=>{let Y=f.split("-");if(Y[0]===""&&Y.length!==1)Y.shift();return vO1(Y,Q)||llQ(f)},getConflictingClassGroupIds:(f,Y)=>{let X=B[f]||[];if(Y&&w[f])return[...X,...w[f]];return X}}},vO1=(A,Q)=>{if(A.length===0)return Q.classGroupId;let B=A[0],w=Q.nextPart.get(B),$=w?vO1(A.slice(1),w):void 0;if($)return $;if(Q.validators.length===0)return;let D=A.join("-");return Q.validators.find(({validator:f})=>f(D))?.classGroupId},kO1=/^\[(.+)\]$/,llQ=(A)=>{if(kO1.test(A)){let Q=kO1.exec(A)[1],B=Q?.substring(0,Q.indexOf(":"));if(B)return"arbitrary.."+B}},plQ=(A)=>{let{theme:Q,prefix:B}=A,w={nextPart:new Map,validators:[]};return dlQ(Object.entries(A.classGroups),B).forEach(([D,f])=>{ES0(f,w,D,Q)}),w},ES0=(A,Q,B,w)=>{A.forEach(($)=>{if(typeof $==="string"){let D=$===""?Q:OO1(Q,$);D.classGroupId=B;return}if(typeof $==="function"){if(ilQ($)){ES0($(w),Q,B,w);return}Q.validators.push({validator:$,classGroupId:B});return}Object.entries($).forEach(([D,f])=>{ES0(f,OO1(Q,D),B,w)})})},OO1=(A,Q)=>{let B=A;return Q.split("-").forEach((w)=>{if(!B.nextPart.has(w))B.nextPart.set(w,{nextPart:new Map,validators:[]});B=B.nextPart.get(w)}),B},ilQ=(A)=>A.isThemeGetter,dlQ=(A,Q)=>{if(!Q)return A;return A.map(([B,w])=>{let $=w.map((D)=>{if(typeof D==="string")return Q+D;if(typeof D==="object")return Object.fromEntries(Object.entries(D).map(([f,Y])=>[Q+f,Y]));return D});return[B,$]})},nlQ=(A)=>{if(A<1)return{get:()=>{return},set:()=>{}};let Q=0,B=new Map,w=new Map,$=(D,f)=>{if(B.set(D,f),Q++,Q>A)Q=0,w=B,B=new Map};return{get(D){let f=B.get(D);if(f!==void 0)return f;if((f=w.get(D))!==void 0)return $(D,f),f},set(D,f){if(B.has(D))B.set(D,f);else $(D,f)}}};var rlQ=(A)=>{let{separator:Q,experimentalParseClassName:B}=A,w=Q.length===1,$=Q[0],D=Q.length,f=(Y)=>{let X=[],H=0,W=0,Z;for(let b=0;b<Y.length;b++){let N=Y[b];if(H===0){if(N===$&&(w||Y.slice(b,b+D)===Q)){X.push(Y.slice(W,b)),W=b+D;continue}if(N==="/"){Z=b;continue}}if(N==="[")H++;else if(N==="]")H--}let G=X.length===0?Y:Y.substring(W),F=G.startsWith("!"),I=F?G.substring(1):G,L=Z&&Z>W?Z-W:void 0;return{modifiers:X,hasImportantModifier:F,baseClassName:I,maybePostfixModifierPosition:L}};if(B)return(Y)=>B({className:Y,parseClassName:f});return f},olQ=(A)=>{if(A.length<=1)return A;let Q=[],B=[];return A.forEach((w)=>{if(w[0]==="[")Q.push(...B.sort(),w),B=[];else B.push(w)}),Q.push(...B.sort()),Q},slQ=(A)=>({cache:nlQ(A.cacheSize),parseClassName:rlQ(A),...clQ(A)}),alQ=/\s+/,tlQ=(A,Q)=>{let{parseClassName:B,getClassGroupId:w,getConflictingClassGroupIds:$}=Q,D=[],f=A.trim().split(alQ),Y="";for(let X=f.length-1;X>=0;X-=1){let H=f[X],{modifiers:W,hasImportantModifier:Z,baseClassName:G,maybePostfixModifierPosition:F}=B(H),I=Boolean(F),L=w(I?G.substring(0,F):G);if(!L){if(!I){Y=H+(Y.length>0?" "+Y:Y);continue}if(L=w(G),!L){Y=H+(Y.length>0?" "+Y:Y);continue}I=!1}let b=olQ(W).join(":"),N=Z?b+"!":b,M=N+L;if(D.includes(M))continue;D.push(M);let j=$(L,I);for(let g=0;g<j.length;++g){let E=j[g];D.push(N+E)}Y=H+(Y.length>0?" "+Y:Y)}return Y};function elQ(){let A=0,Q,B,w="";while(A<arguments.length)if(Q=arguments[A++]){if(B=hO1(Q))w&&(w+=" "),w+=B}return w}var hO1=(A)=>{if(typeof A==="string")return A;let Q,B="";for(let w=0;w<A.length;w++)if(A[w]){if(Q=hO1(A[w]))B&&(B+=" "),B+=Q}return B};function xO1(A,...Q){let B,w,$,D=f;function f(X){let H=Q.reduce((W,Z)=>Z(W),A());return B=slQ(H),w=B.cache.get,$=B.cache.set,D=Y,Y(X)}function Y(X){let H=w(X);if(H)return H;let W=tlQ(X,B);return $(X,W),W}return function(){return D(elQ.apply(null,arguments))}}var a8=(A)=>{let Q=(B)=>B[A]||[];return Q.isThemeGetter=!0,Q},CO1=/^\[(?:([a-z-]+):)?(.+)\]$/i,ApQ=/^\d+\/\d+$/,QpQ=new Set(["px","full","screen"]),BpQ=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,wpQ=/\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$/,$pQ=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,DpQ=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,fpQ=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,v3=(A)=>aC(A)||QpQ.has(A)||ApQ.test(A),dJ=(A)=>tC(A,"length",GpQ),aC=(A)=>Boolean(A)&&!Number.isNaN(Number(A)),yS0=(A)=>tC(A,"number",aC),hd=(A)=>Boolean(A)&&Number.isInteger(Number(A)),YpQ=(A)=>A.endsWith("%")&&aC(A.slice(0,-1)),tQ=(A)=>CO1.test(A),nJ=(A)=>BpQ.test(A),XpQ=new Set(["length","size","percentage"]),HpQ=(A)=>tC(A,XpQ,yO1),WpQ=(A)=>tC(A,"position",yO1),ZpQ=new Set(["image","url"]),KpQ=(A)=>tC(A,ZpQ,qpQ),UpQ=(A)=>tC(A,"",zpQ),Cd=()=>!0,tC=(A,Q,B)=>{let w=CO1.exec(A);if(w){if(w[1])return typeof Q==="string"?w[1]===Q:Q.has(w[1]);return B(w[2])}return!1},GpQ=(A)=>wpQ.test(A)&&!$pQ.test(A),yO1=()=>!1,zpQ=(A)=>DpQ.test(A),qpQ=(A)=>fpQ.test(A);var RO1=()=>{let A=a8("colors"),Q=a8("spacing"),B=a8("blur"),w=a8("brightness"),$=a8("borderColor"),D=a8("borderRadius"),f=a8("borderSpacing"),Y=a8("borderWidth"),X=a8("contrast"),H=a8("grayscale"),W=a8("hueRotate"),Z=a8("invert"),G=a8("gap"),F=a8("gradientColorStops"),I=a8("gradientColorStopPositions"),L=a8("inset"),b=a8("margin"),N=a8("opacity"),M=a8("padding"),j=a8("saturate"),g=a8("scale"),E=a8("sepia"),y=a8("skew"),h=a8("space"),T=a8("translate"),S=()=>["auto","contain","none"],c=()=>["auto","hidden","clip","visible","scroll"],m=()=>["auto",tQ,Q],w0=()=>[tQ,Q],o=()=>["",v3,dJ],v=()=>["auto",aC,tQ],P=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],x=()=>["solid","dashed","dotted","double","none"],p=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],l=()=>["start","end","center","between","around","evenly","stretch"],A0=()=>["","0",tQ],n=()=>["auto","avoid","all","avoid-page","page","left","right","column"],Z0=()=>[aC,tQ];return{cacheSize:500,separator:":",theme:{colors:[Cd],spacing:[v3,dJ],blur:["none","",nJ,tQ],brightness:Z0(),borderColor:[A],borderRadius:["none","","full",nJ,tQ],borderSpacing:w0(),borderWidth:o(),contrast:Z0(),grayscale:A0(),hueRotate:Z0(),invert:A0(),gap:w0(),gradientColorStops:[A],gradientColorStopPositions:[YpQ,dJ],inset:m(),margin:m(),opacity:Z0(),padding:w0(),saturate:Z0(),scale:Z0(),sepia:A0(),skew:Z0(),space:w0(),translate:w0()},classGroups:{aspect:[{aspect:["auto","square","video",tQ]}],container:["container"],columns:[{columns:[nJ]}],"break-after":[{"break-after":n()}],"break-before":[{"break-before":n()}],"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:[...P(),tQ]}],overflow:[{overflow:c()}],"overflow-x":[{"overflow-x":c()}],"overflow-y":[{"overflow-y":c()}],overscroll:[{overscroll:S()}],"overscroll-x":[{"overscroll-x":S()}],"overscroll-y":[{"overscroll-y":S()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[L]}],"inset-x":[{"inset-x":[L]}],"inset-y":[{"inset-y":[L]}],start:[{start:[L]}],end:[{end:[L]}],top:[{top:[L]}],right:[{right:[L]}],bottom:[{bottom:[L]}],left:[{left:[L]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",hd,tQ]}],basis:[{basis:m()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",tQ]}],grow:[{grow:A0()}],shrink:[{shrink:A0()}],order:[{order:["first","last","none",hd,tQ]}],"grid-cols":[{"grid-cols":[Cd]}],"col-start-end":[{col:["auto",{span:["full",hd,tQ]},tQ]}],"col-start":[{"col-start":v()}],"col-end":[{"col-end":v()}],"grid-rows":[{"grid-rows":[Cd]}],"row-start-end":[{row:["auto",{span:[hd,tQ]},tQ]}],"row-start":[{"row-start":v()}],"row-end":[{"row-end":v()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",tQ]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",tQ]}],gap:[{gap:[G]}],"gap-x":[{"gap-x":[G]}],"gap-y":[{"gap-y":[G]}],"justify-content":[{justify:["normal",...l()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...l(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...l(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[M]}],px:[{px:[M]}],py:[{py:[M]}],ps:[{ps:[M]}],pe:[{pe:[M]}],pt:[{pt:[M]}],pr:[{pr:[M]}],pb:[{pb:[M]}],pl:[{pl:[M]}],m:[{m:[b]}],mx:[{mx:[b]}],my:[{my:[b]}],ms:[{ms:[b]}],me:[{me:[b]}],mt:[{mt:[b]}],mr:[{mr:[b]}],mb:[{mb:[b]}],ml:[{ml:[b]}],"space-x":[{"space-x":[h]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[h]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",tQ,Q]}],"min-w":[{"min-w":[tQ,Q,"min","max","fit"]}],"max-w":[{"max-w":[tQ,Q,"none","full","min","max","fit","prose",{screen:[nJ]},nJ]}],h:[{h:[tQ,Q,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[tQ,Q,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[tQ,Q,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[tQ,Q,"auto","min","max","fit"]}],"font-size":[{text:["base",nJ,dJ]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",yS0]}],"font-family":[{font:[Cd]}],"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",tQ]}],"line-clamp":[{"line-clamp":["none",aC,yS0]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",v3,tQ]}],"list-image":[{"list-image":["none",tQ]}],"list-style-type":[{list:["none","disc","decimal",tQ]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[A]}],"placeholder-opacity":[{"placeholder-opacity":[N]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[A]}],"text-opacity":[{"text-opacity":[N]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...x(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",v3,dJ]}],"underline-offset":[{"underline-offset":["auto",v3,tQ]}],"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:w0()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",tQ]}],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",tQ]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[N]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...P(),WpQ]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",HpQ]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},KpQ]}],"bg-color":[{bg:[A]}],"gradient-from-pos":[{from:[I]}],"gradient-via-pos":[{via:[I]}],"gradient-to-pos":[{to:[I]}],"gradient-from":[{from:[F]}],"gradient-via":[{via:[F]}],"gradient-to":[{to:[F]}],rounded:[{rounded:[D]}],"rounded-s":[{"rounded-s":[D]}],"rounded-e":[{"rounded-e":[D]}],"rounded-t":[{"rounded-t":[D]}],"rounded-r":[{"rounded-r":[D]}],"rounded-b":[{"rounded-b":[D]}],"rounded-l":[{"rounded-l":[D]}],"rounded-ss":[{"rounded-ss":[D]}],"rounded-se":[{"rounded-se":[D]}],"rounded-ee":[{"rounded-ee":[D]}],"rounded-es":[{"rounded-es":[D]}],"rounded-tl":[{"rounded-tl":[D]}],"rounded-tr":[{"rounded-tr":[D]}],"rounded-br":[{"rounded-br":[D]}],"rounded-bl":[{"rounded-bl":[D]}],"border-w":[{border:[Y]}],"border-w-x":[{"border-x":[Y]}],"border-w-y":[{"border-y":[Y]}],"border-w-s":[{"border-s":[Y]}],"border-w-e":[{"border-e":[Y]}],"border-w-t":[{"border-t":[Y]}],"border-w-r":[{"border-r":[Y]}],"border-w-b":[{"border-b":[Y]}],"border-w-l":[{"border-l":[Y]}],"border-opacity":[{"border-opacity":[N]}],"border-style":[{border:[...x(),"hidden"]}],"divide-x":[{"divide-x":[Y]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[Y]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[N]}],"divide-style":[{divide:x()}],"border-color":[{border:[$]}],"border-color-x":[{"border-x":[$]}],"border-color-y":[{"border-y":[$]}],"border-color-s":[{"border-s":[$]}],"border-color-e":[{"border-e":[$]}],"border-color-t":[{"border-t":[$]}],"border-color-r":[{"border-r":[$]}],"border-color-b":[{"border-b":[$]}],"border-color-l":[{"border-l":[$]}],"divide-color":[{divide:[$]}],"outline-style":[{outline:["",...x()]}],"outline-offset":[{"outline-offset":[v3,tQ]}],"outline-w":[{outline:[v3,dJ]}],"outline-color":[{outline:[A]}],"ring-w":[{ring:o()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[A]}],"ring-opacity":[{"ring-opacity":[N]}],"ring-offset-w":[{"ring-offset":[v3,dJ]}],"ring-offset-color":[{"ring-offset":[A]}],shadow:[{shadow:["","inner","none",nJ,UpQ]}],"shadow-color":[{shadow:[Cd]}],opacity:[{opacity:[N]}],"mix-blend":[{"mix-blend":[...p(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":p()}],filter:[{filter:["","none"]}],blur:[{blur:[B]}],brightness:[{brightness:[w]}],contrast:[{contrast:[X]}],"drop-shadow":[{"drop-shadow":["","none",nJ,tQ]}],grayscale:[{grayscale:[H]}],"hue-rotate":[{"hue-rotate":[W]}],invert:[{invert:[Z]}],saturate:[{saturate:[j]}],sepia:[{sepia:[E]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[B]}],"backdrop-brightness":[{"backdrop-brightness":[w]}],"backdrop-contrast":[{"backdrop-contrast":[X]}],"backdrop-grayscale":[{"backdrop-grayscale":[H]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[W]}],"backdrop-invert":[{"backdrop-invert":[Z]}],"backdrop-opacity":[{"backdrop-opacity":[N]}],"backdrop-saturate":[{"backdrop-saturate":[j]}],"backdrop-sepia":[{"backdrop-sepia":[E]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[f]}],"border-spacing-x":[{"border-spacing-x":[f]}],"border-spacing-y":[{"border-spacing-y":[f]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",tQ]}],duration:[{duration:Z0()}],ease:[{ease:["linear","in","out","in-out",tQ]}],delay:[{delay:Z0()}],animate:[{animate:["none","spin","ping","pulse","bounce",tQ]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[g]}],"scale-x":[{"scale-x":[g]}],"scale-y":[{"scale-y":[g]}],rotate:[{rotate:[hd,tQ]}],"translate-x":[{"translate-x":[T]}],"translate-y":[{"translate-y":[T]}],"skew-x":[{"skew-x":[y]}],"skew-y":[{"skew-y":[y]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",tQ]}],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",tQ]}],"caret-color":[{caret:[A]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":w0()}],"scroll-mx":[{"scroll-mx":w0()}],"scroll-my":[{"scroll-my":w0()}],"scroll-ms":[{"scroll-ms":w0()}],"scroll-me":[{"scroll-me":w0()}],"scroll-mt":[{"scroll-mt":w0()}],"scroll-mr":[{"scroll-mr":w0()}],"scroll-mb":[{"scroll-mb":w0()}],"scroll-ml":[{"scroll-ml":w0()}],"scroll-p":[{"scroll-p":w0()}],"scroll-px":[{"scroll-px":w0()}],"scroll-py":[{"scroll-py":w0()}],"scroll-ps":[{"scroll-ps":w0()}],"scroll-pe":[{"scroll-pe":w0()}],"scroll-pt":[{"scroll-pt":w0()}],"scroll-pr":[{"scroll-pr":w0()}],"scroll-pb":[{"scroll-pb":w0()}],"scroll-pl":[{"scroll-pl":w0()}],"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",tQ]}],fill:[{fill:[A,"none"]}],"stroke-w":[{stroke:[v3,dJ,yS0]}],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"]}}},FpQ=(A,{cacheSize:Q,prefix:B,separator:w,experimentalParseClassName:$,extend:D={},override:f={}})=>{yd(A,"cacheSize",Q),yd(A,"prefix",B),yd(A,"separator",w),yd(A,"experimentalParseClassName",$);for(let Y in f)IpQ(A[Y],f[Y]);for(let Y in D)VpQ(A[Y],D[Y]);return A},yd=(A,Q,B)=>{if(B!==void 0)A[Q]=B},IpQ=(A,Q)=>{if(Q)for(let B in Q)yd(A,B,Q[B])},VpQ=(A,Q)=>{if(Q)for(let B in Q){let w=Q[B];if(w!==void 0)A[B]=(A[B]||[]).concat(w)}},T$0=(A,...Q)=>typeof A==="function"?xO1(RO1,A,...Q):xO1(()=>FpQ(RO1(),A),...Q);var JpQ=T$0({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 $2(...A){return JpQ(sC(A))}var EO1=(A)=>typeof A==="boolean"?`${A}`:A===0?"0":A,gO1=sC,D8=(A,Q)=>(B)=>{var w;if((Q===null||Q===void 0?void 0:Q.variants)==null)return gO1(A,B===null||B===void 0?void 0:B.class,B===null||B===void 0?void 0:B.className);let{variants:$,defaultVariants:D}=Q,f=Object.keys($).map((H)=>{let W=B===null||B===void 0?void 0:B[H],Z=D===null||D===void 0?void 0:D[H];if(W===null)return null;let G=EO1(W)||EO1(Z);return $[H][G]}),Y=B&&Object.entries(B).reduce((H,W)=>{let[Z,G]=W;if(G===void 0)return H;return H[Z]=G,H},{}),X=Q===null||Q===void 0?void 0:(w=Q.compoundVariants)===null||w===void 0?void 0:w.reduce((H,W)=>{let{class:Z,className:G,...F}=W;return Object.entries(F).every((I)=>{let[L,b]=I;return Array.isArray(b)?b.includes({...D,...Y}[L]):{...D,...Y}[L]===b})?[...H,Z,G]:H},[]);return gO1(A,f,X,B===null||B===void 0?void 0:B.class,B===null||B===void 0?void 0:B.className)};import{jsxDEV as gS0}from"preact/jsx-dev-runtime";var TO1=D8("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 TS0({variant:A,title:Q,children:B,className:w}){return gS0("div",{className:$2(TO1({variant:A}),w),role:"alert",children:[Q&&gS0("p",{className:"font-medium text-current opacity-90",children:Q},void 0,!1,void 0,this),gS0("div",{className:$2(Q&&"mt-1","text-sm text-current opacity-75"),children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}import{jsxDEV as LpQ}from"preact/jsx-dev-runtime";var SO1=D8("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 LM({variant:A,size:Q,className:B,children:w,ssrOnClick:$,type:D="button",...f}){return LpQ("button",{type:D,className:$2(SO1({variant:A,size:Q}),B),...f,...$&&{onclick:$},children:w},void 0,!1,void 0,this)}import{jsxDEV as bpQ}from"preact/jsx-dev-runtime";var mO1=D8("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 D9({href:A,children:Q,variant:B,size:w,external:$=!1,className:D,"aria-label":f}){let Y=$?{target:"_blank",rel:"noopener noreferrer"}:{};return bpQ("a",{href:A,className:$2(mO1({variant:B,size:w}),D),"aria-label":f,...Y,children:Q},void 0,!1,void 0,this)}import{jsxDEV as S$0}from"preact/jsx-dev-runtime";var uO1=D8("transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2",{variants:{variant:{default:"rounded-[10px] bg-theme-subtle border border-theme text-theme-muted hover:text-accent hover:border-brand/40",light:"rounded-[10px] bg-theme-subtle border border-theme text-theme-muted hover:text-accent",dark:"rounded-[10px] bg-theme-dark hover:bg-theme-muted text-theme-inverse",footer:"rounded-full 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"}}),NpQ={sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6"};function eC({variant:A,size:Q,className:B}){let w=NpQ[Q??"md"];return S$0("button",{onclick:"toggleTheme()",type:"button",className:$2(uO1({variant:A,size:Q}),B),"aria-label":"Toggle dark mode",children:S$0("svg",{className:$2(w,"transition-colors"),fill:"none",stroke:"currentColor",strokeWidth:1.6,viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:[S$0("path",{className:"sun-icon",strokeLinecap:"round",strokeLinejoin:"round",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),S$0("path",{className:"moon-icon",strokeLinecap:"round",strokeLinejoin:"round",d:"M20.354 15.354A9 9 0 018.646 3.646 9 9 0 1020.354 15.354z"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}import{jsxDEV as SS0}from"preact/jsx-dev-runtime";var cO1=D8("flex flex-wrap",{variants:{orientation:{horizontal:"justify-center gap-6 items-center",vertical:"flex-col gap-2.5"}},defaultVariants:{orientation:"horizontal"}});function m$0({items:A,className:Q,linkClassName:B="hover:text-accent transition-colors",orientation:w,children:$}){if(A.length===0&&!$)return null;let D=[...A].sort((f,Y)=>f.priority-Y.priority);return SS0("ul",{className:$2(cO1({orientation:w}),Q),children:[D.map((f)=>SS0("li",{children:SS0("a",{href:f.href,className:B,children:f.label},void 0,!1,void 0,this)},f.href,!1,void 0,this)),$]},void 0,!0,void 0,this)}import{jsxDEV as Eb8}from"preact/jsx-dev-runtime";import{jsxDEV as Sb8}from"preact/jsx-dev-runtime";import{createContext as jpQ,h as _pQ}from"preact";import{useContext as MpQ}from"preact/hooks";var mS0=jpQ(null);function Ay({headCollector:A,children:Q}){return _pQ(mS0.Provider,{value:A},Q)}function lO1(){return MpQ(mS0)}function NQ(A){let Q=lO1();if(Q)Q.setHeadProps(A);return null}import{createContext as QaQ,h as BaQ}from"preact";import{useContext as waQ}from"preact/hooks";hN0();var eh1=f1(th1(),1),esQ=new Qc({gfm:!0,breaks:!0}),AaQ={allowedTags:["h1","h2","h3","h4","h5","h6","p","br","hr","ul","ol","li","blockquote","cite","code","pre","em","strong","del","ins","sub","sup","a","img","span","table","thead","tbody","tr","th","td","div"],allowedAttributes:{a:["href","title","name"],img:["src","srcset","sizes","alt","title","width","height","class","loading","decoding"],code:["class"],pre:["class"],span:["class"],cite:["class"],div:["class"],th:["align","colspan","rowspan","scope"],td:["align","colspan","rowspan"]},allowedSchemes:["http","https","mailto","tel"],allowedSchemesByTag:{img:["http","https","entity"]},allowProtocolRelative:!1,disallowedTagsMode:"discard"};function Hu0(A,Q){let{imageRenderer:B}=Q??{},$=(B?new Qc({gfm:!0,breaks:!0}).use({renderer:{image(D,f,Y){return B(D,f,Y)??!1}}}):esQ).parse(A);return $=$.replace(/<\/blockquote>\s*<p>(\u2014|--|\u2013)([\s\S]*?)<\/p>/g,`</blockquote>
|
|
4900
4900
|
<cite class="block-attribution"><span class="emdash">$1</span>$2</cite>`),eh1.default($,AaQ)}var AC1=QaQ(null);function Fy({imageRenderer:A,children:Q}){return BaQ(AC1.Provider,{value:A??null},Q)}function QC1(){return waQ(AC1)}function u3(){let A=QC1();return(Q)=>Hu0(Q,A?{imageRenderer:A}:void 0)}var $aQ=/<pre><code class="language-mermaid">([\s\S]*?)<\/code><\/pre>/g,DaQ={"&":"&","<":"<",">":">",""":'"',"'":"'"},faQ=/&(?:amp|lt|gt|quot|#39);/g;function YaQ(A){return A.replace(faQ,(Q)=>DaQ[Q]??Q)}function Wu0(A){return A.replace($aQ,(Q,B)=>{return`<div class="mermaid">${YaQ(B)}</div>`})}var BC1=/<!--\s*\.slide:\s*(.*?)\s*-->/g;function wC1(A){let Q={};for(let w of A.matchAll(BC1)){let $=w[1]??"";for(let f of $.matchAll(/([\w-]+)=["']([^"']*?)["']/g)){let Y=f[1],X=f[2];if(Y&&X!==void 0)Q[Y]=X}let D=$.replace(/([\w-]+)=["']([^"']*?)["']/g,"").trim();if(D)for(let f of D.matchAll(/(?:^|\s)([\w-]+)(?=\s|$)/g)){let Y=f[1];if(Y)Q[Y]="true"}}let B=A.replace(BC1,"").replace(/^\n+/,"").replace(/\n{3,}/g,`
|
|
4901
4901
|
|
|
4902
4902
|
`).trim();return{attributes:Q,markdown:B}}var XaQ=/<!--\s*\.break\s*-->/;function $C1(A){let Q=A.split(XaQ);return Q.length>1?Q:null}import{jsxDEV as MG}from"preact/jsx-dev-runtime";var Zu0=({markdown:A,deck:Q})=>{let B=u3(),$=A.split(/^---$/gm).map((W)=>W.trim()).map((W)=>{let{attributes:Z,markdown:G}=wC1(W),F=$C1(G),I;if(F)I=`<div class="slide-columns">${F.map((b)=>`<div class="slide-column">${Wu0(B(b.trim()))}</div>`).join("")}</div>`;else I=Wu0(B(G));return{attributes:Z,htmlContent:I}}),D=$.some((W)=>W.htmlContent.includes('class="mermaid"')),f=Q?.frontmatter?.title??Q?.metadata?.title,Y=Q?.frontmatter?.description??Q?.metadata?.description,X=Q?.ogImageUrl??Q?.coverImageUrl,H=$.map(({attributes:W,htmlContent:Z},G)=>MG("section",{...W,dangerouslySetInnerHTML:{__html:Z}},G,!1,void 0,this));return MG("section",{className:"presentation-section",children:[f&&MG(NQ,{title:f,...Y?{description:Y}:{},...X?{ogImage:X}:{},ogType:"article"},void 0,!1,void 0,this),MG("link",{rel:"stylesheet",href:"https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.min.css"},void 0,!1,void 0,this),MG("div",{className:"reveal",children:MG("div",{className:"slides",children:H},void 0,!1,void 0,this)},void 0,!1,void 0,this),MG("script",{src:"https://cdn.jsdelivr.net/npm/reveal.js@5.1.0/dist/reveal.min.js",defer:!0},void 0,!1,void 0,this),D&&MG("script",{src:"https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js",defer:!0},void 0,!1,void 0,this),MG("script",{dangerouslySetInnerHTML:{__html:`
|
|
@@ -5883,13 +5883,13 @@ ${A.map((D)=>({url:`${Q}${D.path}`,lastmod:B,changefreq:D.path==="/"?"daily":"we
|
|
|
5883
5883
|
`+$:B,f=TG(this.outputDir,"styles","main.css");await this.cssProcessor.process(D,f,this.workingDir,this.outputDir,this.logger);let Y=await P7.readFile(f,"utf-8"),X=w.length>0?w:Q;if(X.length>0){let H=X.join(`
|
|
5884
5884
|
`)+`
|
|
5885
5885
|
|
|
5886
|
-
`+Y;await P7.writeFile(f,H,"utf-8")}this.logger.debug("CSS processed successfully with font imports")}async copyStaticAssets(){this.logger.debug("Copying static assets from public/ directory");let A=TG(process.cwd(),"public");try{await P7.access(A)}catch{this.logger.debug("No public/ directory found, skipping static assets");return}let Q=await P7.readdir(A,{withFileTypes:!0});for(let B of Q){let w=TG(A,B.name),$=TG(this.outputDir,B.name);if(B.isDirectory())await this.copyDirectory(w,$);else await P7.copyFile(w,$),this.logger.debug(`Copied static asset: ${B.name}`)}this.logger.debug("Static assets copied successfully")}async writeInlineStaticAssets(A){if(!A)return;let Q=Object.entries(A);if(Q.length===0)return;this.logger.debug(`Writing ${Q.length} inline static asset(s) from SitePackage`),await Promise.all(Q.map(async([B,w])=>{let $=B.startsWith("/")?B.slice(1):B,D=TG(this.outputDir,$);await P7.mkdir(K7B(D),{recursive:!0}),await P7.writeFile(D,w,"utf-8"),this.logger.debug(`Wrote inline static asset: ${$}`)}))}async copyDirectory(A,Q){await P7.mkdir(Q,{recursive:!0});let B=await P7.readdir(A,{withFileTypes:!0});for(let w of B){let $=TG(A,w.name),D=TG(Q,w.name);if(w.isDirectory())await this.copyDirectory($,D);else await P7.copyFile($,D)}}}function pl0(A){return new ml1(A)}M5();K0();K0();M5();var ul1=K.object({environment:K.enum(["preview","production"]),outputDir:K.string(),workingDir:K.string().optional(),sharedImagesDir:K.string().default("./dist/images"),enableContentGeneration:K.boolean().default(!1),cleanBeforeBuild:K.boolean().default(!0),siteConfig:qY,layouts:K.record(K.any()),themeCSS:K.string().optional()}),SC8=K.object({success:K.boolean(),outputDir:K.string(),filesGenerated:K.number(),routesBuilt:K.number(),errors:K.array(K.string()).optional(),warnings:K.array(K.string()).optional()});function cl1(A){let Q=A.list(),B=Q.length===0?["No routes registered for site build"]:[];return{routes:Q,warnings:B}}function ll1(A,Q,B){let w=Q.getProfile(),$=B.getNavigationItems("primary"),D=B.getNavigationItems("secondary");return{...A,...w.socialLinks!==void 0&&{socialLinks:w.socialLinks},navigation:{primary:$,secondary:D},copyright:A.copyright??"Powered by Rizom"}}M5();D4();M5();K0();var U7B=K.object({id:K.string(),entityType:K.string(),content:K.string(),metadata:K.object({slug:K.string()}).passthrough()}).passthrough(),G7B=K.object({content:K.string(),metadata:K.object({width:K.number().optional(),height:K.number().optional()}).passthrough()});async function q40(A,Q){let B=Q.urlGenerator??s7.getInstance();if(A===null||A===void 0)return A;if(Array.isArray(A))return Promise.all(A.map((g)=>q40(g,{...Q,urlGenerator:B})));if(typeof A!=="object")return A;let w={},$=Object.entries(A),D=await Promise.all($.map(([,g])=>q40(g,{...Q,urlGenerator:B})));for(let g=0;g<$.length;g++){let E=$[g];if(E)w[E[0]]=D[g]}let f=U7B.safeParse(A);if(!f.success)return w;let Y=f.data,X=Y.entityType,H=Y.metadata.slug,W=Q.pipelineContext.entityDisplay?.[X],Z=W?W.label:X.charAt(0).toUpperCase()+X.slice(1),G=W?W.pluralName??W.label.toLowerCase()+"s":GY(X),F=`/${G}`,I=G.charAt(0).toUpperCase()+G.slice(1),L=Xu(Y),b=await z7B(L,Q),N=_10(Y)??L,M=await q7B(N,Q);return{...w,...Y,url:B.generateUrl(X,H),typeLabel:Z,listUrl:F,listLabel:I,...b,...M&&{ogImageUrl:M}}}async function z7B(A,Q){let B=A?Q.imageBuildService?.get(A):void 0;if(B)return{coverImageUrl:B.src,coverImageWidth:B.width,coverImageHeight:B.height,...B.srcset&&{coverImageSrcset:B.srcset,coverImageSizes:B.sizes}};let w=await il1(A,Q.pipelineContext.services.entityService);if(!w)return{};return{coverImageUrl:w.url,...w.width&&{coverImageWidth:w.width},...w.height&&{coverImageHeight:w.height}}}async function q7B(A,Q){if(!A)return;let B=Q.imageBuildService?.get(A);if(B)return pl1(B.src,Q.siteUrl);let w=await il1(A,Q.pipelineContext.services.entityService);if(!w)return;if(w.url.startsWith("data:"))return;return pl1(w.url,Q.siteUrl)}function pl1(A,Q){if(/^https?:\/\//i.test(A)||A.startsWith("data:"))return A;if(!Q)return A;return`${Q.replace(/\/$/,"")}/${A.replace(/^\//,"")}`}async function il1(A,Q){if(!A)return;let B=await Q.getEntity({entityType:"image",id:A}),w=G7B.safeParse(B);if(!w.success)return;return{url:w.data.content,...w.data.metadata.width&&{width:w.data.metadata.width},...w.data.metadata.height&&{height:w.data.metadata.height}}}async function dl1(A,Q){let B=new Set;try{let w=A.getEntityTypes();for(let $ of w){if($==="image")continue;let D=await A.listEntities({entityType:$});for(let f of D){let Y=Xu(f);if(Y)B.add(Y);let X=_10(f);if(X)B.add(X)}}}catch(w){Q.warn("Failed to collect image IDs for pre-resolution",{error:hA(w)})}return[...B]}async function nl1(A,Q,B,w,$){if(!A.template)return A.content??null;let D=A.template,f=A.dataQuery?{dataParams:A.dataQuery,fallback:A.content,publishedOnly:B,visibilityScope:w}:{savedContent:{entityType:"site-content",entityId:`${Q.id}:${A.id}`},fallback:A.content,visibilityScope:w},Y=await $.pipelineContext.services.resolveTemplateContent(D,f);if(!Y)return null;return q40(Y,{pipelineContext:$.pipelineContext,imageBuildService:$.imageBuildService,siteUrl:$.siteUrl,urlGenerator:s7.getInstance()})}function rl1(A){return{routes:A.routes,siteConfig:{title:A.siteMetadata.title,description:A.siteMetadata.description,...A.siteMetadata.url&&{url:A.siteMetadata.url},...A.siteMetadata.copyright&&{copyright:A.siteMetadata.copyright},...A.siteMetadata.themeMode&&{themeMode:A.siteMetadata.themeMode},...A.siteMetadata.analyticsScript&&{analyticsScript:A.siteMetadata.analyticsScript}},headScripts:A.buildOptions.headScripts,...A.buildOptions.staticAssets&&{staticAssets:A.buildOptions.staticAssets},getContent:async(Q,B)=>{let w=A.parsedOptions.environment==="production";return nl1(B,Q,w,"public",{pipelineContext:A.pipelineContext,imageBuildService:A.imageBuildService,siteUrl:A.siteMetadata.url})},getViewTemplate:(Q)=>{return A.pipelineContext.services.getViewTemplate(Q)},layouts:A.parsedOptions.layouts,getSiteLayoutInfo:async()=>{return ll1(A.siteMetadata,A.pipelineContext.profileService,A.pipelineContext.routeRegistry)},...A.parsedOptions.themeCSS!==void 0&&{themeCSS:A.parsedOptions.themeCSS},...A.buildOptions.slots&&{slots:A.buildOptions.slots},imageBuildService:A.imageBuildService}}import{join as F7B}from"path";async function ol1(A){let Q=A.parsedOptions.workingDir??F7B(A.parsedOptions.outputDir,".preact-work"),B=A.staticSiteBuilderFactory({logger:A.logger.child("StaticSiteBuilder"),workingDir:Q,outputDir:A.parsedOptions.outputDir});if(A.parsedOptions.cleanBeforeBuild)await B.clean();return B}async function sl1(A){await new G40({logger:A.pipelineContext.logger.child("DynamicRouteGenerator"),entityService:A.pipelineContext.services.entityService,listViewTemplateNames:()=>A.pipelineContext.services.listViewTemplateNames()},A.pipelineContext.routeRegistry,A.pipelineContext.entityDisplay,{visibilityScope:"public",...A.publishedOnly!==void 0&&{publishedOnly:A.publishedOnly}}).generateEntityRoutes()}async function al1(A){let Q=new U40(A.pipelineContext.services.entityService,A.pipelineContext.logger,A.sharedImagesDir),B=await dl1(A.pipelineContext.services.entityService,A.pipelineContext.logger);if(B.length>0)await Q.resolveAll(B);return Q}async function tl1(A){let Q=A.reporter?.createSub({scale:{start:85,end:95}});await A.staticSiteBuilder.build(A.buildContext,(B)=>{Q?.report(B).catch(()=>{})})}function el1(A){return{success:!0,outputDir:A.outputDir,filesGenerated:A.routesBuilt+1,routesBuilt:A.routesBuilt,...A.warnings.length>0&&{warnings:A.warnings}}}function Ap1(A){return{success:!1,outputDir:A.outputDir,filesGenerated:0,routesBuilt:0,errors:[A.errorMessage]}}async function Qp1(A){let Q=ul1.parse(A.buildOptions),B=D7.from(A.progress),w=[];try{await B?.report({message:"Starting site build",progress:0,total:100}),await B?.report({message:"Generating dynamic routes",progress:10,total:100}),await sl1({pipelineContext:A.pipelineContext,publishedOnly:Q.environment==="production"});let $=await ol1({logger:A.pipelineContext.logger,parsedOptions:Q,staticSiteBuilderFactory:A.staticSiteBuilderFactory}),D=cl1(A.pipelineContext.routeRegistry);w.push(...D.warnings);let{routes:f}=D;await B?.report({message:`Building ${f.length} routes`,progress:20,total:100}),await B?.report({message:"Resolving images",progress:25,total:100});let Y=await al1({pipelineContext:A.pipelineContext,sharedImagesDir:Q.sharedImagesDir}),X=rl1({routes:f,parsedOptions:Q,buildOptions:A.buildOptions,pipelineContext:A.pipelineContext,imageBuildService:Y,siteMetadata:Q.siteConfig});return await tl1({staticSiteBuilder:$,buildContext:X,reporter:B}),await B?.report({message:"Site build complete",progress:100,total:100}),el1({outputDir:Q.outputDir,routesBuilt:f.length,warnings:w})}catch($){let D=Error("Site build process failed");return A.pipelineContext.logger.error("Site build failed",{error:D,originalError:$}),Ap1({outputDir:Q.outputDir,errorMessage:D.message})}}class NX{static instance=null;static defaultStaticSiteBuilderFactory=pl0;pipelineContext;staticSiteBuilderFactory;static setDefaultStaticSiteBuilderFactory(A){NX.defaultStaticSiteBuilderFactory=A}static getInstance(A,Q,B,w,$=void 0){return NX.instance??=new NX(A,NX.defaultStaticSiteBuilderFactory,Q,B,w,$),NX.instance}static resetInstance(){NX.instance=null}static createFresh(A,Q,B,w,$,D=void 0){return new NX(A,$??NX.defaultStaticSiteBuilderFactory,Q,B,w,D)}constructor(A,Q,B,w,$,D){this.pipelineContext={logger:A,services:B,routeRegistry:w,profileService:$,entityDisplay:D},this.staticSiteBuilderFactory=Q,s7.getInstance().configure(D)}async build(A,Q){return Qp1({buildOptions:A,progress:Q,pipelineContext:this.pipelineContext,staticSiteBuilderFactory:this.staticSiteBuilderFactory})}}K0();class il0{config;context;pluginId;logger;debounces=new Map;unsubscribeFunctions=[];constructor(A,Q,B,w){this.config=A;this.context=Q;this.pluginId=B;this.logger=w}requestBuild(A){let Q=A??(this.config.previewOutputDir?"preview":"production"),B=this.debounces.get(Q);if(!B)B=new QN(()=>{this.enqueueBuild(Q)},this.config.rebuildDebounce),this.debounces.set(Q,B);B.trigger()}setupAutoRebuild(){let A=new Set(["note"]),Q=async(w)=>{let{entityType:$}=w.payload;if(!A.has($))this.logger.debug(`Entity type ${$} will trigger rebuild`),this.requestBuild();return{success:!0}},B=["entity:created","entity:updated","entity:deleted"];for(let w of B)this.unsubscribeFunctions.push(this.context.messaging.subscribe(w,Q));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 Q=A==="production"?this.config.productionOutputDir:this.config.previewOutputDir;this.logger.debug(`Triggering ${A} site rebuild`);try{await this.context.jobs.enqueue({type:"site-build",data:{environment:A,outputDir:Q,workingDir:this.config.workingDir,enableContentGeneration:!0,metadata:{trigger:"debounced-rebuild",timestamp:new Date().toISOString()}},options:{priority:0,source:this.pluginId,metadata:{operationType:"content_operations"},deduplication:"skip"}}),this.logger.debug("Site rebuild enqueued")}catch(B){this.logger.error("Failed to enqueue site rebuild",{error:B})}}}M5();function I7B(A,Q){return A.map((B)=>({...B,template:B.template.includes(":")?B.template:`${Q}:${B.template}`}))}function F40(A,Q,B){for(let w of A)B.register({...w,pluginId:Q,sections:w.sections?I7B(w.sections,Q):[]})}function Bp1(A,Q,B){A.messaging.subscribe("plugin:site-builder:route:register",async(w)=>{try{let $=St.parse(w.payload),{routes:D,pluginId:f}=$;return F40(D,f,Q),{success:!0}}catch($){return B.error("Failed to register routes",{error:$}),{success:!1,error:"Failed to register routes"}}}),A.messaging.subscribe("plugin:site-builder:route:unregister",async(w)=>{try{let $=mt.parse(w.payload),{paths:D,pluginId:f}=$;if(D)for(let Y of D)Q.unregister(Y);else if(f)Q.unregisterByPlugin(f);return{success:!0}}catch($){return B.error("Failed to unregister routes",{error:$}),{success:!1,error:"Failed to unregister routes"}}}),A.messaging.subscribe("plugin:site-builder:route:list",async(w)=>{try{let $=ut.parse(w.payload);return{success:!0,data:{routes:Q.list($.pluginId?$:void 0)}}}catch($){return B.error("Failed to list routes",{error:$}),{success:!1,error:"Failed to list routes"}}}),A.messaging.subscribe("plugin:site-builder:route:get",async(w)=>{try{let $=ct.parse(w.payload);return{success:!0,data:{route:Q.get($.path)}}}catch($){return B.error("Failed to get route",{error:$}),{success:!1,error:"Failed to get route"}}}),A.messaging.subscribe("site-builder:routes:list",async()=>{return{success:!0,data:Q.list()}})}import{promises as wp1}from"fs";import{join as $p1}from"path";async function V7B(A,Q,B){let w=A.siteConfig.url??"https://example.com",$=Q.list(),D=cl0(w,A.environment);await wp1.writeFile($p1(A.outputDir,"robots.txt"),D,"utf-8"),B.info(`Generated robots.txt for ${A.environment} environment`);let f=ll0($,w);await wp1.writeFile($p1(A.outputDir,"sitemap.xml"),f,"utf-8"),B.info(`Generated sitemap.xml with ${$.length} URLs`)}function Dp1(A){let{context:Q,routeRegistry:B,logger:w}=A;Q.messaging.subscribe("site:build:completed",async($)=>{try{let D=$.payload;return w.info(`Received site:build:completed event for ${D.environment} environment - generating SEO files`),await V7B(D,B,w),{success:!0}}catch(D){return w.error("Failed to generate SEO files",D),{success:!1}}})}p0();K0();M5();var fp1=K.object({environment:K.enum(["preview","production"]).optional(),outputDir:K.string(),workingDir:K.string().optional(),enableContentGeneration:K.boolean().optional(),siteConfig:qY.optional()});M5();M5();async function Dr(A,Q){try{let B=await A({type:cT,payload:void 0});if("success"in B&&B.success&&B.data){let w=qY.safeParse(B.data);if(w.success)return qY.parse({...Q,...w.data})}}catch{}return Q}class dl0 extends PB{sendMessage;cfg;constructor(A,Q,B){super(A,{schema:fp1,jobTypeName:"site-build"});this.sendMessage=Q;this.cfg=B}async process(A,Q,B){let w=A.environment??"preview",$=A.enableContentGeneration??!1;try{this.logger.debug("Starting site build job",{jobId:Q,environment:w,outputDir:A.outputDir}),await B.report({progress:0,total:100,message:`Starting site build for ${w} environment`});let D=B.createSub({scale:{start:10,end:90}}),f=await Dr(this.sendMessage,A.siteConfig??this.cfg.defaultSiteConfig),Y=await this.cfg.siteBuilder.build({outputDir:A.outputDir,workingDir:A.workingDir,sharedImagesDir:this.cfg.sharedImagesDir,enableContentGeneration:$,environment:w,cleanBeforeBuild:!0,siteConfig:f,layouts:this.cfg.layouts,themeCSS:this.cfg.themeCSS,slots:this.cfg.slots,headScripts:this.cfg.getHeadScripts?.(),...this.cfg.staticAssets&&{staticAssets:this.cfg.staticAssets}},D.toCallback());if(await B.report({progress:100,total:100,message:`Site build completed: ${Y.routesBuilt} routes built`}),this.logger.debug("Site build job completed",{jobId:Q,environment:w,routesBuilt:Y.routesBuilt,success:Y.success}),Y.success){this.logger.info(`Emitting site:build:completed event for ${w} environment`);let X=w==="preview"?this.cfg.previewUrl??this.cfg.siteUrl:this.cfg.siteUrl;await this.sendMessage({type:"site:build:completed",payload:{outputDir:A.outputDir,environment:w,routesBuilt:Y.routesBuilt,siteConfig:{...f,url:X},generateEntityUrl:(H,W)=>s7.getInstance().generateUrl(H,W)},broadcast:!0})}return{success:Y.success,routesBuilt:Y.routesBuilt,outputDir:A.outputDir,environment:w,...Y.errors&&{errors:Y.errors},...Y.warnings&&{warnings:Y.warnings}}}catch(D){throw this.logger.error("Site build job failed",D),D}}summarizeDataForLog(A){return{environment:A.environment,outputDir:A.outputDir}}}K0();M5();var J7B=K.object({slot:K.enum(XN).optional().default("primary"),limit:K.number().optional()});class nl0{routeRegistry;logger;id="site:navigation";name="Site Navigation DataSource";description="Provides navigation items for site menus";constructor(A,Q){this.routeRegistry=A;this.logger=Q;this.logger.debug("NavigationDataSource initialized")}async fetch(A,Q,B){let w=J7B.parse(A??{});this.logger.debug("NavigationDataSource fetch called",{params:w});let $=this.routeRegistry.getNavigationItems(w.slot),D=w.limit?$.slice(0,w.limit):$,f=D.map((X)=>({label:X.label,href:X.href}));this.logger.debug("NavigationDataSource returning",{slot:w.slot,itemCount:D.length,items:f});let Y={navigation:f};return Q.parse(Y)}}M5();p0();K0();var L7B=K.object({environment:K.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function Yp1(A,Q){return[BB(A,"build-site","Build a static site from registered routes. Call this for every user build/rebuild request, including repeated requests like 'build it again' or 'one more build'.",L7B,async(B)=>{return Q(B.environment),{success:!0,message:`Site build requested${B.environment?` for ${B.environment}`:""} (debounced)`,data:{}}},{cli:{name:"build"}})]}K0();M5();var Xp1=K.object({previewOutputDir:K.string().describe("Output directory for preview builds").default("./dist/site-preview"),productionOutputDir:K.string().describe("Output directory for production builds").default("./dist/site-production"),sharedImagesDir:K.string().describe("Shared directory for optimized images (used by both preview and production)").default("./dist/images"),workingDir:K.string().optional().describe("Working directory for builds").default("./.preact-work"),siteInfo:qY.default({title:"Brain",description:"A knowledge management system"}),themeCSS:K.string().describe("Custom CSS theme overrides to inject into builds").optional(),analyticsScript:K.string().describe("Analytics tracking script to inject into page head (e.g., Cloudflare Web Analytics)").optional(),templates:K.any().optional().describe("Template definitions to register"),routes:K.array(HN).optional().describe("Routes to register"),layouts:K.record(K.any()).optional().describe("Layout components (at least 'default' required)"),autoRebuild:K.boolean().default(!0).describe("Automatically rebuild site when content changes"),rebuildDebounce:K.number().min(100).describe("Debounce time in ms before triggering site rebuild after content changes").default(5000),entityDisplay:K.record(K.object({label:K.string().describe("Display label for entity type (e.g., 'Essay')"),pluralName:K.string().optional().describe("URL path segment (defaults to label.toLowerCase() + 's')"),layout:K.string().optional().describe("Layout name for this entity type's generated routes (defaults to 'default')"),paginate:K.boolean().optional().describe("Enable pagination for list pages"),pageSize:K.number().optional().describe("Items per page (default: 10)"),navigation:K.object({show:K.boolean().optional().describe("Show in navigation"),slot:K.enum(XN).optional().describe("Navigation slot (primary or secondary)"),priority:K.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:K.record(K.string()).optional().describe("Static files to write to the output directory at build time. Keys are output paths (e.g. '/canvases/tree.js'), values are file contents as strings. Typically supplied by a SitePackage via text imports.")});var Hp1={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.128",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/image":"workspace:*","@brains/plugins":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-engine":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*","@tailwindcss/typography":"^0.5.19",preact:"^10.27.2","preact-render-to-string":"^6.3.1"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14",eslint:"^8.56.0",typescript:"^5.3.3"}};class rl0 extends pQ{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 Q=A.layouts??{};super("site-builder",Hp1,{...A,layouts:Q},Xp1);this.layouts=Q}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new z40(A.logger),this._slotRegistry=new r70,A.messaging.subscribe("plugin:site-builder:slot:register",async(B)=>{let{slotName:w,pluginId:$,render:D,priority:f}=B.payload;return this._slotRegistry?.register(w,{pluginId:$,render:D,...f!==void 0&&{priority:f}}),{success:!0}}),A.messaging.subscribe("plugin:site-builder:head-script:register",async(B)=>{let{pluginId:w,script:$}=B.payload;return this.headScripts.set(w,$),{success:!0}}),A.entities.registerDataSource(new nl0(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=t4.getInstance(A.entityService,A.logger),Bp1(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)F40(this.config.routes,this.id,this.routeRegistry);let Q={entityService:A.entityService,sendMessage:A.messaging.send,resolveTemplateContent:(B,w)=>A.templates.resolve(B,w),getViewTemplate:(B)=>A.views.get(B),listViewTemplateNames:()=>A.views.list().map((B)=>B.name)};if(this.siteBuilder=NX.getInstance(A.logger.child("SiteBuilder"),Q,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new dl0(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 il0(this.config,A,this.id,this.logger),this.config.autoRebuild)this.logger.debug("Auto-rebuild enabled"),this.rebuildManager.setupAutoRebuild();A.messaging.subscribe(lT,async()=>{let B=await this.getInstructions();if(B)A.registerInstructions(B);return{success:!0}}),Dp1({context:A,routeRegistry:this._routeRegistry,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 Yp1(this.id,(Q)=>A.requestBuild(Q))}async getResources(){let A=this.getContext();return[{uri:"brain://site",name:"Site Metadata",description:"Site metadata \u2014 title, description, domain, URLs",mimeType:"application/json",handler:async()=>{let Q=await Dr(A.messaging.send,this.config.siteInfo);return{contents:[{uri:"brain://site",mimeType:"application/json",text:JSON.stringify({...Q,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 Q=this.routeRegistry.list();return{contents:[{uri:"site://routes",mimeType:"application/json",text:JSON.stringify(Q.map((B)=>({id:B.id,path:B.path,title:B.title,description:B.description,sections:B.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 Q=A.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(Q.map((B)=>({name:B.name,description:B.description,hasWebRenderer:!!B.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let A=this.getContext(),Q="## Site Builder Actions\n- When the user asks to build, rebuild, publish, or build the website/site again, call `site-builder_build-site` immediately.\n- Every repeated build request requires a fresh `site-builder_build-site` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.",B=await Dr(A.messaging.send,this.config.siteInfo);return`## Your Site
|
|
5886
|
+
`+Y;await P7.writeFile(f,H,"utf-8")}this.logger.debug("CSS processed successfully with font imports")}async copyStaticAssets(){this.logger.debug("Copying static assets from public/ directory");let A=TG(process.cwd(),"public");try{await P7.access(A)}catch{this.logger.debug("No public/ directory found, skipping static assets");return}let Q=await P7.readdir(A,{withFileTypes:!0});for(let B of Q){let w=TG(A,B.name),$=TG(this.outputDir,B.name);if(B.isDirectory())await this.copyDirectory(w,$);else await P7.copyFile(w,$),this.logger.debug(`Copied static asset: ${B.name}`)}this.logger.debug("Static assets copied successfully")}async writeInlineStaticAssets(A){if(!A)return;let Q=Object.entries(A);if(Q.length===0)return;this.logger.debug(`Writing ${Q.length} inline static asset(s) from SitePackage`),await Promise.all(Q.map(async([B,w])=>{let $=B.startsWith("/")?B.slice(1):B,D=TG(this.outputDir,$);await P7.mkdir(K7B(D),{recursive:!0}),await P7.writeFile(D,w,"utf-8"),this.logger.debug(`Wrote inline static asset: ${$}`)}))}async copyDirectory(A,Q){await P7.mkdir(Q,{recursive:!0});let B=await P7.readdir(A,{withFileTypes:!0});for(let w of B){let $=TG(A,w.name),D=TG(Q,w.name);if(w.isDirectory())await this.copyDirectory($,D);else await P7.copyFile($,D)}}}function pl0(A){return new ml1(A)}M5();K0();K0();M5();var ul1=K.object({environment:K.enum(["preview","production"]),outputDir:K.string(),workingDir:K.string().optional(),sharedImagesDir:K.string().default("./dist/images"),enableContentGeneration:K.boolean().default(!1),cleanBeforeBuild:K.boolean().default(!0),siteConfig:qY,layouts:K.record(K.any()),themeCSS:K.string().optional()}),SC8=K.object({success:K.boolean(),outputDir:K.string(),filesGenerated:K.number(),routesBuilt:K.number(),errors:K.array(K.string()).optional(),warnings:K.array(K.string()).optional()});function cl1(A){let Q=A.list(),B=Q.length===0?["No routes registered for site build"]:[];return{routes:Q,warnings:B}}function ll1(A,Q,B){let w=Q.getProfile(),$=B.getNavigationItems("primary"),D=B.getNavigationItems("secondary");return{...A,...w.socialLinks!==void 0&&{socialLinks:w.socialLinks},navigation:{primary:$,secondary:D},copyright:A.copyright??"Powered by Rizom"}}M5();D4();M5();K0();var U7B=K.object({id:K.string(),entityType:K.string(),content:K.string(),metadata:K.object({slug:K.string()}).passthrough()}).passthrough(),G7B=K.object({content:K.string(),metadata:K.object({width:K.number().optional(),height:K.number().optional()}).passthrough()});async function q40(A,Q){let B=Q.urlGenerator??s7.getInstance();if(A===null||A===void 0)return A;if(Array.isArray(A))return Promise.all(A.map((g)=>q40(g,{...Q,urlGenerator:B})));if(typeof A!=="object")return A;let w={},$=Object.entries(A),D=await Promise.all($.map(([,g])=>q40(g,{...Q,urlGenerator:B})));for(let g=0;g<$.length;g++){let E=$[g];if(E)w[E[0]]=D[g]}let f=U7B.safeParse(A);if(!f.success)return w;let Y=f.data,X=Y.entityType,H=Y.metadata.slug,W=Q.pipelineContext.entityDisplay?.[X],Z=W?W.label:X.charAt(0).toUpperCase()+X.slice(1),G=W?W.pluralName??W.label.toLowerCase()+"s":GY(X),F=`/${G}`,I=G.charAt(0).toUpperCase()+G.slice(1),L=Xu(Y),b=await z7B(L,Q),N=_10(Y)??L,M=await q7B(N,Q);return{...w,...Y,url:B.generateUrl(X,H),typeLabel:Z,listUrl:F,listLabel:I,...b,...M&&{ogImageUrl:M}}}async function z7B(A,Q){let B=A?Q.imageBuildService?.get(A):void 0;if(B)return{coverImageUrl:B.src,coverImageWidth:B.width,coverImageHeight:B.height,...B.srcset&&{coverImageSrcset:B.srcset,coverImageSizes:B.sizes}};let w=await il1(A,Q.pipelineContext.services.entityService);if(!w)return{};return{coverImageUrl:w.url,...w.width&&{coverImageWidth:w.width},...w.height&&{coverImageHeight:w.height}}}async function q7B(A,Q){if(!A)return;let B=Q.imageBuildService?.get(A);if(B)return pl1(B.src,Q.siteUrl);let w=await il1(A,Q.pipelineContext.services.entityService);if(!w)return;if(w.url.startsWith("data:"))return;return pl1(w.url,Q.siteUrl)}function pl1(A,Q){if(/^https?:\/\//i.test(A)||A.startsWith("data:"))return A;if(!Q)return A;return`${Q.replace(/\/$/,"")}/${A.replace(/^\//,"")}`}async function il1(A,Q){if(!A)return;let B=await Q.getEntity({entityType:"image",id:A}),w=G7B.safeParse(B);if(!w.success)return;return{url:w.data.content,...w.data.metadata.width&&{width:w.data.metadata.width},...w.data.metadata.height&&{height:w.data.metadata.height}}}async function dl1(A,Q){let B=new Set;try{let w=A.getEntityTypes();for(let $ of w){if($==="image")continue;let D=await A.listEntities({entityType:$});for(let f of D){let Y=Xu(f);if(Y)B.add(Y);let X=_10(f);if(X)B.add(X)}}}catch(w){Q.warn("Failed to collect image IDs for pre-resolution",{error:hA(w)})}return[...B]}async function nl1(A,Q,B,w,$){if(!A.template)return A.content??null;let D=A.template,f=A.dataQuery?{dataParams:A.dataQuery,fallback:A.content,publishedOnly:B,visibilityScope:w}:{savedContent:{entityType:"site-content",entityId:`${Q.id}:${A.id}`},fallback:A.content,visibilityScope:w},Y=await $.pipelineContext.services.resolveTemplateContent(D,f);if(!Y)return null;return q40(Y,{pipelineContext:$.pipelineContext,imageBuildService:$.imageBuildService,siteUrl:$.siteUrl,urlGenerator:s7.getInstance()})}function rl1(A){return{routes:A.routes,siteConfig:{title:A.siteMetadata.title,description:A.siteMetadata.description,...A.siteMetadata.url&&{url:A.siteMetadata.url},...A.siteMetadata.copyright&&{copyright:A.siteMetadata.copyright},...A.siteMetadata.themeMode&&{themeMode:A.siteMetadata.themeMode},...A.siteMetadata.analyticsScript&&{analyticsScript:A.siteMetadata.analyticsScript}},headScripts:A.buildOptions.headScripts,...A.buildOptions.staticAssets&&{staticAssets:A.buildOptions.staticAssets},getContent:async(Q,B)=>{let w=A.parsedOptions.environment==="production";return nl1(B,Q,w,"public",{pipelineContext:A.pipelineContext,imageBuildService:A.imageBuildService,siteUrl:A.siteMetadata.url})},getViewTemplate:(Q)=>{return A.pipelineContext.services.getViewTemplate(Q)},layouts:A.parsedOptions.layouts,getSiteLayoutInfo:async()=>{return ll1(A.siteMetadata,A.pipelineContext.profileService,A.pipelineContext.routeRegistry)},...A.parsedOptions.themeCSS!==void 0&&{themeCSS:A.parsedOptions.themeCSS},...A.buildOptions.slots&&{slots:A.buildOptions.slots},imageBuildService:A.imageBuildService}}import{join as F7B}from"path";async function ol1(A){let Q=A.parsedOptions.workingDir??F7B(A.parsedOptions.outputDir,".preact-work"),B=A.staticSiteBuilderFactory({logger:A.logger.child("StaticSiteBuilder"),workingDir:Q,outputDir:A.parsedOptions.outputDir});if(A.parsedOptions.cleanBeforeBuild)await B.clean();return B}async function sl1(A){await new G40({logger:A.pipelineContext.logger.child("DynamicRouteGenerator"),entityService:A.pipelineContext.services.entityService,listViewTemplateNames:()=>A.pipelineContext.services.listViewTemplateNames()},A.pipelineContext.routeRegistry,A.pipelineContext.entityDisplay,{visibilityScope:"public",...A.publishedOnly!==void 0&&{publishedOnly:A.publishedOnly}}).generateEntityRoutes()}async function al1(A){let Q=new U40(A.pipelineContext.services.entityService,A.pipelineContext.logger,A.sharedImagesDir),B=await dl1(A.pipelineContext.services.entityService,A.pipelineContext.logger);if(B.length>0)await Q.resolveAll(B);return Q}async function tl1(A){let Q=A.reporter?.createSub({scale:{start:85,end:95}});await A.staticSiteBuilder.build(A.buildContext,(B)=>{Q?.report(B).catch(()=>{})})}function el1(A){return{success:!0,outputDir:A.outputDir,filesGenerated:A.routesBuilt+1,routesBuilt:A.routesBuilt,...A.warnings.length>0&&{warnings:A.warnings}}}function Ap1(A){return{success:!1,outputDir:A.outputDir,filesGenerated:0,routesBuilt:0,errors:[A.errorMessage]}}async function Qp1(A){let Q=ul1.parse(A.buildOptions),B=D7.from(A.progress),w=[];try{await B?.report({message:"Starting site build",progress:0,total:100}),await B?.report({message:"Generating dynamic routes",progress:10,total:100}),await sl1({pipelineContext:A.pipelineContext,publishedOnly:Q.environment==="production"});let $=await ol1({logger:A.pipelineContext.logger,parsedOptions:Q,staticSiteBuilderFactory:A.staticSiteBuilderFactory}),D=cl1(A.pipelineContext.routeRegistry);w.push(...D.warnings);let{routes:f}=D;await B?.report({message:`Building ${f.length} routes`,progress:20,total:100}),await B?.report({message:"Resolving images",progress:25,total:100});let Y=await al1({pipelineContext:A.pipelineContext,sharedImagesDir:Q.sharedImagesDir}),X=rl1({routes:f,parsedOptions:Q,buildOptions:A.buildOptions,pipelineContext:A.pipelineContext,imageBuildService:Y,siteMetadata:Q.siteConfig});return await tl1({staticSiteBuilder:$,buildContext:X,reporter:B}),await B?.report({message:"Site build complete",progress:100,total:100}),el1({outputDir:Q.outputDir,routesBuilt:f.length,warnings:w})}catch($){let D=Error("Site build process failed");return A.pipelineContext.logger.error("Site build failed",{error:D,originalError:$}),Ap1({outputDir:Q.outputDir,errorMessage:D.message})}}class NX{static instance=null;static defaultStaticSiteBuilderFactory=pl0;pipelineContext;staticSiteBuilderFactory;static setDefaultStaticSiteBuilderFactory(A){NX.defaultStaticSiteBuilderFactory=A}static getInstance(A,Q,B,w,$=void 0){return NX.instance??=new NX(A,NX.defaultStaticSiteBuilderFactory,Q,B,w,$),NX.instance}static resetInstance(){NX.instance=null}static createFresh(A,Q,B,w,$,D=void 0){return new NX(A,$??NX.defaultStaticSiteBuilderFactory,Q,B,w,D)}constructor(A,Q,B,w,$,D){this.pipelineContext={logger:A,services:B,routeRegistry:w,profileService:$,entityDisplay:D},this.staticSiteBuilderFactory=Q,s7.getInstance().configure(D)}async build(A,Q){return Qp1({buildOptions:A,progress:Q,pipelineContext:this.pipelineContext,staticSiteBuilderFactory:this.staticSiteBuilderFactory})}}K0();class il0{config;context;pluginId;logger;debounces=new Map;unsubscribeFunctions=[];constructor(A,Q,B,w){this.config=A;this.context=Q;this.pluginId=B;this.logger=w}requestBuild(A){let Q=A??(this.config.previewOutputDir?"preview":"production"),B=this.debounces.get(Q);if(!B)B=new QN(()=>{this.enqueueBuild(Q)},this.config.rebuildDebounce),this.debounces.set(Q,B);B.trigger()}setupAutoRebuild(){let A=new Set(["note"]),Q=async(w)=>{let{entityType:$}=w.payload;if(!A.has($))this.logger.debug(`Entity type ${$} will trigger rebuild`),this.requestBuild();return{success:!0}},B=["entity:created","entity:updated","entity:deleted"];for(let w of B)this.unsubscribeFunctions.push(this.context.messaging.subscribe(w,Q));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 Q=A==="production"?this.config.productionOutputDir:this.config.previewOutputDir;this.logger.debug(`Triggering ${A} site rebuild`);try{await this.context.jobs.enqueue({type:"site-build",data:{environment:A,outputDir:Q,workingDir:this.config.workingDir,enableContentGeneration:!0,metadata:{trigger:"debounced-rebuild",timestamp:new Date().toISOString()}},options:{priority:0,source:this.pluginId,metadata:{operationType:"content_operations"},deduplication:"skip"}}),this.logger.debug("Site rebuild enqueued")}catch(B){this.logger.error("Failed to enqueue site rebuild",{error:B})}}}M5();function I7B(A,Q){return A.map((B)=>({...B,template:B.template.includes(":")?B.template:`${Q}:${B.template}`}))}function F40(A,Q,B){for(let w of A)B.register({...w,pluginId:Q,sections:w.sections?I7B(w.sections,Q):[]})}function Bp1(A,Q,B){A.messaging.subscribe("plugin:site-builder:route:register",async(w)=>{try{let $=St.parse(w.payload),{routes:D,pluginId:f}=$;return F40(D,f,Q),{success:!0}}catch($){return B.error("Failed to register routes",{error:$}),{success:!1,error:"Failed to register routes"}}}),A.messaging.subscribe("plugin:site-builder:route:unregister",async(w)=>{try{let $=mt.parse(w.payload),{paths:D,pluginId:f}=$;if(D)for(let Y of D)Q.unregister(Y);else if(f)Q.unregisterByPlugin(f);return{success:!0}}catch($){return B.error("Failed to unregister routes",{error:$}),{success:!1,error:"Failed to unregister routes"}}}),A.messaging.subscribe("plugin:site-builder:route:list",async(w)=>{try{let $=ut.parse(w.payload);return{success:!0,data:{routes:Q.list($.pluginId?$:void 0)}}}catch($){return B.error("Failed to list routes",{error:$}),{success:!1,error:"Failed to list routes"}}}),A.messaging.subscribe("plugin:site-builder:route:get",async(w)=>{try{let $=ct.parse(w.payload);return{success:!0,data:{route:Q.get($.path)}}}catch($){return B.error("Failed to get route",{error:$}),{success:!1,error:"Failed to get route"}}}),A.messaging.subscribe("site-builder:routes:list",async()=>{return{success:!0,data:Q.list()}})}import{promises as wp1}from"fs";import{join as $p1}from"path";async function V7B(A,Q,B){let w=A.siteConfig.url??"https://example.com",$=Q.list(),D=cl0(w,A.environment);await wp1.writeFile($p1(A.outputDir,"robots.txt"),D,"utf-8"),B.info(`Generated robots.txt for ${A.environment} environment`);let f=ll0($,w);await wp1.writeFile($p1(A.outputDir,"sitemap.xml"),f,"utf-8"),B.info(`Generated sitemap.xml with ${$.length} URLs`)}function Dp1(A){let{context:Q,routeRegistry:B,logger:w}=A;Q.messaging.subscribe("site:build:completed",async($)=>{try{let D=$.payload;return w.info(`Received site:build:completed event for ${D.environment} environment - generating SEO files`),await V7B(D,B,w),{success:!0}}catch(D){return w.error("Failed to generate SEO files",D),{success:!1}}})}p0();K0();M5();var fp1=K.object({environment:K.enum(["preview","production"]).optional(),outputDir:K.string(),workingDir:K.string().optional(),enableContentGeneration:K.boolean().optional(),siteConfig:qY.optional()});M5();M5();async function Dr(A,Q){try{let B=await A({type:cT,payload:void 0});if("success"in B&&B.success&&B.data){let w=qY.safeParse(B.data);if(w.success)return qY.parse({...Q,...w.data})}}catch{}return Q}class dl0 extends PB{sendMessage;cfg;constructor(A,Q,B){super(A,{schema:fp1,jobTypeName:"site-build"});this.sendMessage=Q;this.cfg=B}async process(A,Q,B){let w=A.environment??"preview",$=A.enableContentGeneration??!1;try{this.logger.debug("Starting site build job",{jobId:Q,environment:w,outputDir:A.outputDir}),await B.report({progress:0,total:100,message:`Starting site build for ${w} environment`});let D=B.createSub({scale:{start:10,end:90}}),f=await Dr(this.sendMessage,A.siteConfig??this.cfg.defaultSiteConfig),Y=await this.cfg.siteBuilder.build({outputDir:A.outputDir,workingDir:A.workingDir,sharedImagesDir:this.cfg.sharedImagesDir,enableContentGeneration:$,environment:w,cleanBeforeBuild:!0,siteConfig:f,layouts:this.cfg.layouts,themeCSS:this.cfg.themeCSS,slots:this.cfg.slots,headScripts:this.cfg.getHeadScripts?.(),...this.cfg.staticAssets&&{staticAssets:this.cfg.staticAssets}},D.toCallback());if(await B.report({progress:100,total:100,message:`Site build completed: ${Y.routesBuilt} routes built`}),this.logger.debug("Site build job completed",{jobId:Q,environment:w,routesBuilt:Y.routesBuilt,success:Y.success}),Y.success){this.logger.info(`Emitting site:build:completed event for ${w} environment`);let X=w==="preview"?this.cfg.previewUrl??this.cfg.siteUrl:this.cfg.siteUrl;await this.sendMessage({type:"site:build:completed",payload:{outputDir:A.outputDir,environment:w,routesBuilt:Y.routesBuilt,siteConfig:{...f,url:X},generateEntityUrl:(H,W)=>s7.getInstance().generateUrl(H,W)},broadcast:!0})}return{success:Y.success,routesBuilt:Y.routesBuilt,outputDir:A.outputDir,environment:w,...Y.errors&&{errors:Y.errors},...Y.warnings&&{warnings:Y.warnings}}}catch(D){throw this.logger.error("Site build job failed",D),D}}summarizeDataForLog(A){return{environment:A.environment,outputDir:A.outputDir}}}K0();M5();var J7B=K.object({slot:K.enum(XN).optional().default("primary"),limit:K.number().optional()});class nl0{routeRegistry;logger;id="site:navigation";name="Site Navigation DataSource";description="Provides navigation items for site menus";constructor(A,Q){this.routeRegistry=A;this.logger=Q;this.logger.debug("NavigationDataSource initialized")}async fetch(A,Q,B){let w=J7B.parse(A??{});this.logger.debug("NavigationDataSource fetch called",{params:w});let $=this.routeRegistry.getNavigationItems(w.slot),D=w.limit?$.slice(0,w.limit):$,f=D.map((X)=>({label:X.label,href:X.href}));this.logger.debug("NavigationDataSource returning",{slot:w.slot,itemCount:D.length,items:f});let Y={navigation:f};return Q.parse(Y)}}M5();p0();K0();var L7B=K.object({environment:K.enum(["preview","production"]).optional().describe("Build environment (defaults to production, or preview if configured)")});function Yp1(A,Q){return[BB(A,"build-site","Build a static site from registered routes. Call this for every user build/rebuild request, including repeated requests like 'build it again' or 'one more build'.",L7B,async(B)=>{return Q(B.environment),{success:!0,message:`Site build requested${B.environment?` for ${B.environment}`:""} (debounced)`,data:{}}},{cli:{name:"build"}})]}K0();M5();var Xp1=K.object({previewOutputDir:K.string().describe("Output directory for preview builds").default("./dist/site-preview"),productionOutputDir:K.string().describe("Output directory for production builds").default("./dist/site-production"),sharedImagesDir:K.string().describe("Shared directory for optimized images (used by both preview and production)").default("./dist/images"),workingDir:K.string().optional().describe("Working directory for builds").default("./.preact-work"),siteInfo:qY.default({title:"Brain",description:"A knowledge management system"}),themeCSS:K.string().describe("Custom CSS theme overrides to inject into builds").optional(),analyticsScript:K.string().describe("Analytics tracking script to inject into page head (e.g., Cloudflare Web Analytics)").optional(),templates:K.any().optional().describe("Template definitions to register"),routes:K.array(HN).optional().describe("Routes to register"),layouts:K.record(K.any()).optional().describe("Layout components (at least 'default' required)"),autoRebuild:K.boolean().default(!0).describe("Automatically rebuild site when content changes"),rebuildDebounce:K.number().min(100).describe("Debounce time in ms before triggering site rebuild after content changes").default(5000),entityDisplay:K.record(K.object({label:K.string().describe("Display label for entity type (e.g., 'Essay')"),pluralName:K.string().optional().describe("URL path segment (defaults to label.toLowerCase() + 's')"),layout:K.string().optional().describe("Layout name for this entity type's generated routes (defaults to 'default')"),paginate:K.boolean().optional().describe("Enable pagination for list pages"),pageSize:K.number().optional().describe("Items per page (default: 10)"),navigation:K.object({show:K.boolean().optional().describe("Show in navigation"),slot:K.enum(XN).optional().describe("Navigation slot (primary or secondary)"),priority:K.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:K.record(K.string()).optional().describe("Static files to write to the output directory at build time. Keys are output paths (e.g. '/canvases/tree.js'), values are file contents as strings. Typically supplied by a SitePackage via text imports.")});var Hp1={name:"@brains/site-builder-plugin",private:!0,version:"0.2.0-alpha.129",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/image":"workspace:*","@brains/plugins":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-engine":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*","@tailwindcss/typography":"^0.5.19",preact:"^10.27.2","preact-render-to-string":"^6.3.1"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"^1.1.14",eslint:"^8.56.0",typescript:"^5.3.3"}};class rl0 extends pQ{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 Q=A.layouts??{};super("site-builder",Hp1,{...A,layouts:Q},Xp1);this.layouts=Q}async onRegister(A){if(this.pluginContext=A,this._routeRegistry=new z40(A.logger),this._slotRegistry=new r70,A.messaging.subscribe("plugin:site-builder:slot:register",async(B)=>{let{slotName:w,pluginId:$,render:D,priority:f}=B.payload;return this._slotRegistry?.register(w,{pluginId:$,render:D,...f!==void 0&&{priority:f}}),{success:!0}}),A.messaging.subscribe("plugin:site-builder:head-script:register",async(B)=>{let{pluginId:w,script:$}=B.payload;return this.headScripts.set(w,$),{success:!0}}),A.entities.registerDataSource(new nl0(this._routeRegistry,A.logger.child("NavigationDataSource"))),this.profileService=t4.getInstance(A.entityService,A.logger),Bp1(A,this._routeRegistry,this.logger),this.config.templates)A.templates.register(this.config.templates);if(this.config.routes)F40(this.config.routes,this.id,this.routeRegistry);let Q={entityService:A.entityService,sendMessage:A.messaging.send,resolveTemplateContent:(B,w)=>A.templates.resolve(B,w),getViewTemplate:(B)=>A.views.get(B),listViewTemplateNames:()=>A.views.list().map((B)=>B.name)};if(this.siteBuilder=NX.getInstance(A.logger.child("SiteBuilder"),Q,this.routeRegistry,this.profileService,this.config.entityDisplay),A.jobs.registerHandler("site-build",new dl0(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 il0(this.config,A,this.id,this.logger),this.config.autoRebuild)this.logger.debug("Auto-rebuild enabled"),this.rebuildManager.setupAutoRebuild();A.messaging.subscribe(lT,async()=>{let B=await this.getInstructions();if(B)A.registerInstructions(B);return{success:!0}}),Dp1({context:A,routeRegistry:this._routeRegistry,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 Yp1(this.id,(Q)=>A.requestBuild(Q))}async getResources(){let A=this.getContext();return[{uri:"brain://site",name:"Site Metadata",description:"Site metadata \u2014 title, description, domain, URLs",mimeType:"application/json",handler:async()=>{let Q=await Dr(A.messaging.send,this.config.siteInfo);return{contents:[{uri:"brain://site",mimeType:"application/json",text:JSON.stringify({...Q,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 Q=this.routeRegistry.list();return{contents:[{uri:"site://routes",mimeType:"application/json",text:JSON.stringify(Q.map((B)=>({id:B.id,path:B.path,title:B.title,description:B.description,sections:B.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 Q=A.views.list();return{contents:[{uri:"site://templates",mimeType:"application/json",text:JSON.stringify(Q.map((B)=>({name:B.name,description:B.description,hasWebRenderer:!!B.renderers.web})),null,2)}]}}}]}getSiteBuilder(){return this.siteBuilder}getSlotRegistry(){return this._slotRegistry}async getInstructions(){let A=this.getContext(),Q="## Site Builder Actions\n- When the user asks to build, rebuild, publish, or build the website/site again, call `site-builder_build-site` immediately.\n- Every repeated build request requires a fresh `site-builder_build-site` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.",B=await Dr(A.messaging.send,this.config.siteInfo);return`## Your Site
|
|
5887
5887
|
${[`**Title:** ${B.title}`,`**Description:** ${B.description}`,A.domain&&`**Domain:** ${A.domain}`,A.siteUrl&&`**URL:** ${A.siteUrl}`].filter(Boolean).join(`
|
|
5888
5888
|
`)}
|
|
5889
5889
|
|
|
5890
5890
|
## Site Builder Actions
|
|
5891
5891
|
- When the user asks to build, rebuild, publish, or build the website/site again, call \`site-builder_build-site\` immediately.
|
|
5892
|
-
- Every repeated build request requires a fresh \`site-builder_build-site\` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.`}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),this.rebuildManager?.dispose(),NX.resetInstance(),this.logger.debug("Cleaned up all event subscriptions")}}function $P(A={}){return new rl0(A)}p0();M5();K0();p0();M5();var Wp1=K.object({}),fr=o1.extend({id:K.literal("site-info"),entityType:K.literal("site-info"),metadata:Wp1}),ol0=pt,ny=qY.omit({url:!0,analyticsScript:!0});p0();class SG extends V2{constructor(){super({entityType:"site-info",schema:fr,frontmatterSchema:ny,isSingleton:!0,hasBody:!1})}createSiteInfoContent(A){let Q=ny.parse(A);return this.buildMarkdown("",Q)}parseSiteInfoBody(A){return this.parseFrontmatter(A)}fromMarkdown(A){return{content:A,entityType:"site-info"}}extractMetadata(A){return{}}generateFrontMatter(A){let Q=this.parseFrontmatter(A.content);return this.buildMarkdown("",Q)}}class mG{static instance=null;logger;entityService;adapter;defaultSiteInfo;static getDefaultSiteInfo(){return{title:"Brain",description:"A knowledge management system"}}static getInstance(A,Q,B){return mG.instance??=new mG(A,Q,B),mG.instance}static resetInstance(){mG.instance=null}static createFresh(A,Q,B){return new mG(A,Q,B)}constructor(A,Q,B){this.entityService=A,this.logger=Q.child("SiteInfoService"),this.adapter=new SG;let w=mG.getDefaultSiteInfo();this.defaultSiteInfo={...w,...B}}async initialize(){try{if(!await this.entityService.getEntity({entityType:"site-info",id:"site-info"})){if(await this.entityService.getEntity({entityType:"site-info",id:"site-info"}))return;this.logger.info("No site info found, creating default site info");let B=this.adapter.createSiteInfoContent(this.defaultSiteInfo);await this.entityService.createEntity({entity:{id:"site-info",entityType:"site-info",content:B,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({entityType:"site-info",id:"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 N7B=new SG;class I40{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,Q,B){let{entityService:w}=B,$;try{let Y=await w.getEntity({entityType:"site-info",id:"site-info"});$=Y?N7B.parseSiteInfoBody(Y.content):{title:"Brain",description:"A knowledge management system"}}catch{$={title:"Brain",description:"A knowledge management system"}}let D;try{let Y=await w.getEntity({entityType:"anchor-profile",id:"anchor-profile"});if(Y)D=Y.metadata.socialLinks}catch{}let f={...$,socialLinks:D,copyright:$.copyright??"Powered by Rizom"};return this.logger.debug("SiteInfoDataSource returning",{title:f.title,hasSocialLinks:!!f.socialLinks}),Q.parse(f)}}var Zp1={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.128",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/site-composition":"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 _7B=new SG;class sl0 extends PQ{entityType="site-info";schema=fr;adapter=_7B;defaultSiteInfo;constructor(A){super("site-info",Zp1);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new I40(this.logger.child("SiteInfoDataSource"))]}async onRegister(A){let Q=mG.createFresh(A.entityService,this.logger,this.defaultSiteInfo);A.messaging.subscribe(cT,async()=>{return{success:!0,data:await Q.getSiteInfo()}}),A.messaging.subscribe("entity:updated",async(B)=>{if(B.payload.entityType==="site-info"){let $=await Q.getSiteInfo();await A.messaging.send({type:lT,payload:$,broadcast:!0})}return{success:!0}}),A.messaging.subscribe("sync:initial:completed",async()=>{return await Q.initialize(),{success:!0}})}}function DP(A){return new sl0(A)}var M7B=new SG;async function Yr(A){let B=(await A.listEntities({entityType:"site-info",options:{limit:1}}))[0];if(!B)throw Error("Site info not found \u2014 create a site-info entity");return M7B.parseSiteInfoBody(B.content)}K0();var P7B=ny.extend({navigation:K.object({primary:K.array(K.object({label:K.string(),href:K.string(),priority:K.number()})),secondary:K.array(K.object({label:K.string(),href:K.string(),priority:K.number()}))}),copyright:K.string(),socialLinks:K.array(K.object({platform:K.enum(["github","instagram","linkedin","email","website"]).describe("Social media platform"),url:K.string().describe("Profile or contact URL"),label:K.string().optional().describe("Optional display label")})).optional().describe("Social media links from profile entity")});p0();K0();var Kp1={lexicon:1,id:"ai.rizom.brain.card",defs:{main:{type:"record",description:"Public discovery card for a Rizom brain. The operational A2A Agent Card is conventionally served at /.well-known/agent-card.json under siteUrl.",key:"literal:self",record:{type:"object",required:["siteUrl","brain","anchor","skills","model","version","createdAt"],properties:{siteUrl:{type:"string",format:"uri",description:"Public site URL. Consumers derive the A2A Agent Card URL from this base."},brain:{type:"object",description:"Brain identity described by this discovery card.",required:["did","name","role","purpose","values"],properties:{did:{type:"string",description:"Public DID for the brain identity."},name:{type:"string",maxLength:200,description:"Human-readable brain name."},role:{type:"string",maxLength:500,description:"Brain role or persona."},purpose:{type:"string",maxLength:2000,description:"Short public description of what this brain is for."},values:{type:"array",description:"Public values or principles for this brain.",items:{type:"string",maxLength:200},maxLength:50}}},anchor:{type:"object",description:"Minimal owner/operator snapshot for discovery grouping and display.",required:["did","name","kind"],properties:{did:{type:"string",description:"Public DID for the owner/operator anchor identity."},name:{type:"string",maxLength:200,description:"Human-readable anchor name."},kind:{type:"string",knownValues:["professional","team","collective"],description:"Anchor type."}}},skills:{type:"array",description:"User-facing skills this brain advertises for discovery.",items:{type:"object",required:["id","name","description"],properties:{id:{type:"string",maxLength:200},name:{type:"string",maxLength:200},description:{type:"string",maxLength:2000},tags:{type:"array",items:{type:"string"},maxLength:50},examples:{type:"array",items:{type:"string"},maxLength:20}}},maxLength:100},model:{type:"string",description:"Rizom brain model identifier."},version:{type:"string",description:"Brain runtime/model implementation version."},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Up1={lexicon:1,id:"ai.rizom.brain.deck",defs:{main:{type:"record",description:"Public presentation deck from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},slug:{type:"string"},description:{type:"string",maxLength:2000},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},author:{type:"string"},event:{type:"string"},publishedAt:{type:"string",format:"datetime"},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Gp1={lexicon:1,id:"ai.rizom.brain.link",defs:{main:{type:"record",description:"Public curated link from a Rizom brain.",key:"any",record:{type:"object",required:["title","url","createdAt"],properties:{title:{type:"string",maxLength:500},url:{type:"string",format:"uri"},description:{type:"string",maxLength:2000},summary:{type:"string",maxLength:1e5},domain:{type:"string"},capturedAt:{type:"string",format:"datetime"},source:{type:"object",required:["ref","label"],properties:{ref:{type:"string"},label:{type:"string"}}},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var zp1={lexicon:1,id:"ai.rizom.brain.note",defs:{main:{type:"record",description:"Public knowledge note from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var qp1={lexicon:1,id:"ai.rizom.brain.post",defs:{main:{type:"record",description:"Markdown blog post distributed by a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},summary:{type:"string",maxLength:2000},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},brainDid:{type:"string"},anchorDid:{type:"string"},canonicalUrl:{type:"string",format:"uri"},topics:{type:"array",items:{type:"string"},maxLength:50},coverImage:{type:"object",required:["blob"],properties:{blob:{type:"blob"},alt:{type:"string",maxLength:1000},width:{type:"integer"},height:{type:"integer"}}},series:{type:"string",maxLength:200},seriesIndex:{type:"integer"},sourceEntityType:{type:"string",knownValues:["post"]},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},publishedAt:{type:"string",format:"datetime"}}}}}};var Fp1={lexicon:1,id:"ai.rizom.brain.project",defs:{main:{type:"record",description:"Public project or case study from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","year","createdAt"],properties:{title:{type:"string",maxLength:300},slug:{type:"string"},description:{type:"string",maxLength:2000},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},year:{type:"integer"},url:{type:"string",format:"uri"},publishedAt:{type:"string",format:"datetime"},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Ip1={lexicon:1,id:"ai.rizom.brain.series",defs:{main:{type:"record",description:"Public content series from a Rizom brain.",key:"any",record:{type:"object",required:["title","createdAt"],properties:{title:{type:"string",maxLength:300},slug:{type:"string"},description:{type:"string",maxLength:1e4},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Vp1={lexicon:1,id:"ai.rizom.brain.socialPost",defs:{main:{type:"record",description:"Semantic local social-post entity from a Rizom brain; not a Bluesky feed post.",key:"any",record:{type:"object",required:["title","platform","body","createdAt"],properties:{title:{type:"string",maxLength:300},platform:{type:"string"},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},status:{type:"string"},publishedAt:{type:"string",format:"datetime"},platformPostId:{type:"string"},sourceLocalEntityType:{type:"string"},sourceLocalEntityId:{type:"string"},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Jp1={lexicon:1,id:"ai.rizom.brain.topic",defs:{main:{type:"record",description:"Public topic page from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var g7B=K.object({type:K.string()}).catchall(K.unknown()),T7B=K.object({lexicon:K.literal(1),id:K.string(),defs:K.object({main:K.object({type:K.literal("record"),key:K.string().min(1),record:K.object({type:K.literal("object"),required:K.array(K.string()).optional(),properties:K.record(g7B)})})})});function uG(A){return T7B.parse(A)}var _w={"ai.rizom.brain.card":uG(Kp1),"ai.rizom.brain.deck":uG(Up1),"ai.rizom.brain.link":uG(Gp1),"ai.rizom.brain.note":uG(zp1),"ai.rizom.brain.post":uG(qp1),"ai.rizom.brain.project":uG(Fp1),"ai.rizom.brain.series":uG(Ip1),"ai.rizom.brain.socialPost":uG(Vp1),"ai.rizom.brain.topic":uG(Jp1)},S7B="Additive optional fields are compatible; required-field, type, or constraint changes require a migration plan or new NSID.";function DF(A){return{status:"approved",version:"1.0.0",revision:1,owner:"Rizom",steward:"Rizom protocol registry",projectionPackage:A,compatibility:S7B}}var m7B={"ai.rizom.brain.card":DF("@brains/atproto"),"ai.rizom.brain.deck":DF("@brains/decks"),"ai.rizom.brain.link":DF("@brains/link"),"ai.rizom.brain.note":DF("@brains/note"),"ai.rizom.brain.post":DF("@brains/blog"),"ai.rizom.brain.project":DF("@brains/portfolio"),"ai.rizom.brain.series":DF("@brains/series"),"ai.rizom.brain.socialPost":DF("@brains/social-media"),"ai.rizom.brain.topic":DF("@brains/topics")};function fP(){return Object.values(_w)}function el0(A){return _w[A]}function Ap0(){return Object.entries(m7B).map(([A,Q])=>({id:A,...Q}))}function tl0(A){return typeof A==="object"&&A!==null&&!Array.isArray(A)}var u7B=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;function c7B(A){let Q=K.string(),B=A.maxLength!==void 0?Q.max(A.maxLength):Q;if(A.knownValues)B=B.refine((w)=>A.knownValues?.includes(w),{message:`expected one of ${A.knownValues.join(", ")}`});if(A.format==="datetime")B=B.refine((w)=>u7B.test(w)&&!Number.isNaN(Date.parse(w)),{message:"expected datetime"});if(A.format==="uri")B=B.refine((w)=>{try{return new URL(w),!0}catch{return!1}},{message:"expected uri"});return B}function Lp1(A){switch(A.type){case"string":return c7B(A);case"integer":return K.number().int();case"boolean":return K.boolean();case"array":{let Q=A.items?Lp1(A.items):K.unknown(),B=K.array(Q);if(A.maxLength!==void 0)B=B.max(A.maxLength);return B}case"object":return l7B(A);case"blob":return K.custom(tl0,{message:"expected blob"});default:return K.unknown()}}function bp1(A){let Q=new Set(A.required??[]),B={};for(let[w,$]of Object.entries(A.properties??{})){let D=Lp1($);B[w]=Q.has(w)?D:D.optional()}return B}function l7B(A){return K.object(bp1(A)).passthrough()}function al0(A,Q,B,w=[]){let $=Object.keys(A).filter((D)=>!Q.has(D));if($.length===0)return;B.addIssue({code:K.ZodIssueCode.custom,path:w,message:`unrecognized field(s): ${$.join(", ")}`})}function p7B(A,Q){if(al0(A,new Set(["$type","siteUrl","brain","anchor","skills","model","version","createdAt","updatedAt"]),Q),tl0(A.brain))al0(A.brain,new Set(["did","name","role","purpose","values"]),Q,["brain"]);if(tl0(A.anchor))al0(A.anchor,new Set(["did","name","kind"]),Q,["anchor"])}function cG(A){let Q=K.object({...bp1(A.defs.main.record),$type:K.literal(A.id).optional()}).passthrough();return A.id==="ai.rizom.brain.card"?Q.superRefine(p7B):Q}var i7B={"ai.rizom.brain.card":cG(_w["ai.rizom.brain.card"]),"ai.rizom.brain.deck":cG(_w["ai.rizom.brain.deck"]),"ai.rizom.brain.link":cG(_w["ai.rizom.brain.link"]),"ai.rizom.brain.note":cG(_w["ai.rizom.brain.note"]),"ai.rizom.brain.post":cG(_w["ai.rizom.brain.post"]),"ai.rizom.brain.project":cG(_w["ai.rizom.brain.project"]),"ai.rizom.brain.series":cG(_w["ai.rizom.brain.series"]),"ai.rizom.brain.socialPost":cG(_w["ai.rizom.brain.socialPost"]),"ai.rizom.brain.topic":cG(_w["ai.rizom.brain.topic"])};function d7B(A,Q,B){let w=B.path.join(".");if(w==="$type")return`AT Protocol record $type must match lexicon id: ${String(Q.$type)} !== ${A.id}`;if(B.code==="invalid_type"&&B.received==="undefined")return`Missing required AT Protocol record field: ${w}`;if(B.code==="invalid_type")return`Invalid AT Protocol record field ${w}: expected ${B.expected}`;if(B.code==="too_big")return`Invalid AT Protocol record field ${w}: exceeds maxLength ${B.maximum}`;if(B.code==="custom")return`Invalid AT Protocol record field ${w}: ${B.message}`;if(B.code==="unrecognized_keys")return`Unrecognized AT Protocol record field(s): ${B.keys.join(", ")}`;return`Invalid AT Protocol record field ${w}: ${B.message}`}function FL(A,Q){let B=cG(A).safeParse(Q);if(B.success)return;let w=B.error.issues[0];if(!w)throw B.error;throw Error(d7B(A,Q,w))}var V40="atproto:brain-card-discovered",Np1="atproto:brain-discovered",jp1="atproto:brain-card-refreshed",_p1=K.object({repoDid:K.string().min(1),uri:K.string().min(1),cid:K.string().min(1),record:i7B["ai.rizom.brain.card"]}).strict(),zg8=K.object({agentId:K.string().min(1),name:K.string().min(1),url:K.string().url(),status:K.enum(["discovered","approved"]),repoDid:K.string().min(1).optional(),brainDid:K.string().min(1).optional(),anchorDid:K.string().min(1).optional(),cardUri:K.string().min(1).optional(),cardCid:K.string().min(1).optional()}).strict();class U5{static instance;projections=new Map;registrationCounts=new Map;static getInstance(){return this.instance??=new U5,this.instance}static createFresh(){return new U5}static resetInstance(){this.instance=void 0}register(A){this.validateProjection(A);let Q=this.projections.get(A.entityType);if(Q){if(!this.isEquivalentProjection(Q,A))throw Error(`AT Protocol projection already registered for entity type ${A.entityType}`);return this.registrationCounts.set(A.entityType,(this.registrationCounts.get(A.entityType)??1)+1),this.createUnregister(A.entityType)}return this.projections.set(A.entityType,A),this.registrationCounts.set(A.entityType,1),this.createUnregister(A.entityType)}get(A){return this.projections.get(A)}has(A){return this.projections.has(A)}list(){return Array.from(this.projections.values())}listLexicons(){return this.list().map((A)=>A.lexicon)}createUnregister(A){let Q=!0;return()=>{if(!Q)return;Q=!1;let B=this.registrationCounts.get(A)??0;if(B<=1){this.registrationCounts.delete(A),this.projections.delete(A);return}this.registrationCounts.set(A,B-1)}}isEquivalentProjection(A,Q){return A.entityType===Q.entityType&&A.collection===Q.collection&&A.lexicon.id===Q.lexicon.id&&A.validate===Q.validate}validateProjection(A){if(A.collection!==A.lexicon.id)throw Error(`AT Protocol projection collection must match lexicon id: ${A.collection} !== ${A.lexicon.id}`);if(!A.lexicon.defs.main.key)throw Error(`AT Protocol projection lexicon must define a record key: ${A.collection}`)}}jX();oy();K0();var Qp0=K.object({defaultPrompt:K.string().default("Write a blog post about my recent work and insights"),paginate:K.boolean().default(!0),pageSize:K.number().default(10)});p0();K0();Cw();var o7B=K.object({prompt:K.string().optional(),title:K.string().optional(),content:K.string().optional(),excerpt:K.string().optional(),coverImageId:K.string().optional(),seriesName:K.string().optional(),seriesIndex:K.number().optional(),skipAi:K.boolean().optional()}),kg8=zY.extend({title:K.string().optional(),slug:K.string().optional()});class Bp0 extends A4{constructor(A,Q){super(A,Q,{schema:o7B,jobTypeName:"blog-generation",entityType:"post"})}async generate(A,Q){let{prompt:B,coverImageId:w,seriesName:$,seriesIndex:D,skipAi:f}=A,{title:Y,content:X,excerpt:H}=A;if(f){if(!Y)this.failEarly("Title is required when skipAi is true");X=X??`## Introduction
|
|
5892
|
+
- Every repeated build request requires a fresh \`site-builder_build-site\` call. Do not say a build was started, queued, or requested unless this turn invoked the tool.`}async onShutdown(){this.logger.debug("Shutting down site-builder plugin"),this.rebuildManager?.dispose(),NX.resetInstance(),this.logger.debug("Cleaned up all event subscriptions")}}function $P(A={}){return new rl0(A)}p0();M5();K0();p0();M5();var Wp1=K.object({}),fr=o1.extend({id:K.literal("site-info"),entityType:K.literal("site-info"),metadata:Wp1}),ol0=pt,ny=qY.omit({url:!0,analyticsScript:!0});p0();class SG extends V2{constructor(){super({entityType:"site-info",schema:fr,frontmatterSchema:ny,isSingleton:!0,hasBody:!1})}createSiteInfoContent(A){let Q=ny.parse(A);return this.buildMarkdown("",Q)}parseSiteInfoBody(A){return this.parseFrontmatter(A)}fromMarkdown(A){return{content:A,entityType:"site-info"}}extractMetadata(A){return{}}generateFrontMatter(A){let Q=this.parseFrontmatter(A.content);return this.buildMarkdown("",Q)}}class mG{static instance=null;logger;entityService;adapter;defaultSiteInfo;static getDefaultSiteInfo(){return{title:"Brain",description:"A knowledge management system"}}static getInstance(A,Q,B){return mG.instance??=new mG(A,Q,B),mG.instance}static resetInstance(){mG.instance=null}static createFresh(A,Q,B){return new mG(A,Q,B)}constructor(A,Q,B){this.entityService=A,this.logger=Q.child("SiteInfoService"),this.adapter=new SG;let w=mG.getDefaultSiteInfo();this.defaultSiteInfo={...w,...B}}async initialize(){try{if(!await this.entityService.getEntity({entityType:"site-info",id:"site-info"})){if(await this.entityService.getEntity({entityType:"site-info",id:"site-info"}))return;this.logger.info("No site info found, creating default site info");let B=this.adapter.createSiteInfoContent(this.defaultSiteInfo);await this.entityService.createEntity({entity:{id:"site-info",entityType:"site-info",content:B,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({entityType:"site-info",id:"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 N7B=new SG;class I40{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,Q,B){let{entityService:w}=B,$;try{let Y=await w.getEntity({entityType:"site-info",id:"site-info"});$=Y?N7B.parseSiteInfoBody(Y.content):{title:"Brain",description:"A knowledge management system"}}catch{$={title:"Brain",description:"A knowledge management system"}}let D;try{let Y=await w.getEntity({entityType:"anchor-profile",id:"anchor-profile"});if(Y)D=Y.metadata.socialLinks}catch{}let f={...$,socialLinks:D,copyright:$.copyright??"Powered by Rizom"};return this.logger.debug("SiteInfoDataSource returning",{title:f.title,hasSocialLinks:!!f.socialLinks}),Q.parse(f)}}var Zp1={name:"@brains/site-info",private:!0,version:"0.2.0-alpha.129",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/site-composition":"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 _7B=new SG;class sl0 extends PQ{entityType="site-info";schema=fr;adapter=_7B;defaultSiteInfo;constructor(A){super("site-info",Zp1);this.defaultSiteInfo=A?.siteInfo??{}}getEntityTypeConfig(){return{embeddable:!1}}getDataSources(){return[new I40(this.logger.child("SiteInfoDataSource"))]}async onRegister(A){let Q=mG.createFresh(A.entityService,this.logger,this.defaultSiteInfo);A.messaging.subscribe(cT,async()=>{return{success:!0,data:await Q.getSiteInfo()}}),A.messaging.subscribe("entity:updated",async(B)=>{if(B.payload.entityType==="site-info"){let $=await Q.getSiteInfo();await A.messaging.send({type:lT,payload:$,broadcast:!0})}return{success:!0}}),A.messaging.subscribe("sync:initial:completed",async()=>{return await Q.initialize(),{success:!0}})}}function DP(A){return new sl0(A)}var M7B=new SG;async function Yr(A){let B=(await A.listEntities({entityType:"site-info",options:{limit:1}}))[0];if(!B)throw Error("Site info not found \u2014 create a site-info entity");return M7B.parseSiteInfoBody(B.content)}K0();var P7B=ny.extend({navigation:K.object({primary:K.array(K.object({label:K.string(),href:K.string(),priority:K.number()})),secondary:K.array(K.object({label:K.string(),href:K.string(),priority:K.number()}))}),copyright:K.string(),socialLinks:K.array(K.object({platform:K.enum(["github","instagram","linkedin","email","website"]).describe("Social media platform"),url:K.string().describe("Profile or contact URL"),label:K.string().optional().describe("Optional display label")})).optional().describe("Social media links from profile entity")});p0();K0();var Kp1={lexicon:1,id:"ai.rizom.brain.card",defs:{main:{type:"record",description:"Public discovery card for a Rizom brain. The operational A2A Agent Card is conventionally served at /.well-known/agent-card.json under siteUrl.",key:"literal:self",record:{type:"object",required:["siteUrl","brain","anchor","skills","model","version","createdAt"],properties:{siteUrl:{type:"string",format:"uri",description:"Public site URL. Consumers derive the A2A Agent Card URL from this base."},brain:{type:"object",description:"Brain identity described by this discovery card.",required:["did","name","role","purpose","values"],properties:{did:{type:"string",description:"Public DID for the brain identity."},name:{type:"string",maxLength:200,description:"Human-readable brain name."},role:{type:"string",maxLength:500,description:"Brain role or persona."},purpose:{type:"string",maxLength:2000,description:"Short public description of what this brain is for."},values:{type:"array",description:"Public values or principles for this brain.",items:{type:"string",maxLength:200},maxLength:50}}},anchor:{type:"object",description:"Minimal owner/operator snapshot for discovery grouping and display.",required:["did","name","kind"],properties:{did:{type:"string",description:"Public DID for the owner/operator anchor identity."},name:{type:"string",maxLength:200,description:"Human-readable anchor name."},kind:{type:"string",knownValues:["professional","team","collective"],description:"Anchor type."}}},skills:{type:"array",description:"User-facing skills this brain advertises for discovery.",items:{type:"object",required:["id","name","description"],properties:{id:{type:"string",maxLength:200},name:{type:"string",maxLength:200},description:{type:"string",maxLength:2000},tags:{type:"array",items:{type:"string"},maxLength:50},examples:{type:"array",items:{type:"string"},maxLength:20}}},maxLength:100},model:{type:"string",description:"Rizom brain model identifier."},version:{type:"string",description:"Brain runtime/model implementation version."},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Up1={lexicon:1,id:"ai.rizom.brain.deck",defs:{main:{type:"record",description:"Public presentation deck from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},slug:{type:"string"},description:{type:"string",maxLength:2000},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},author:{type:"string"},event:{type:"string"},publishedAt:{type:"string",format:"datetime"},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Gp1={lexicon:1,id:"ai.rizom.brain.link",defs:{main:{type:"record",description:"Public curated link from a Rizom brain.",key:"any",record:{type:"object",required:["title","url","createdAt"],properties:{title:{type:"string",maxLength:500},url:{type:"string",format:"uri"},description:{type:"string",maxLength:2000},summary:{type:"string",maxLength:1e5},domain:{type:"string"},capturedAt:{type:"string",format:"datetime"},source:{type:"object",required:["ref","label"],properties:{ref:{type:"string"},label:{type:"string"}}},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var zp1={lexicon:1,id:"ai.rizom.brain.note",defs:{main:{type:"record",description:"Public knowledge note from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var qp1={lexicon:1,id:"ai.rizom.brain.post",defs:{main:{type:"record",description:"Markdown blog post distributed by a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},summary:{type:"string",maxLength:2000},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},brainDid:{type:"string"},anchorDid:{type:"string"},canonicalUrl:{type:"string",format:"uri"},topics:{type:"array",items:{type:"string"},maxLength:50},coverImage:{type:"object",required:["blob"],properties:{blob:{type:"blob"},alt:{type:"string",maxLength:1000},width:{type:"integer"},height:{type:"integer"}}},series:{type:"string",maxLength:200},seriesIndex:{type:"integer"},sourceEntityType:{type:"string",knownValues:["post"]},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},publishedAt:{type:"string",format:"datetime"}}}}}};var Fp1={lexicon:1,id:"ai.rizom.brain.project",defs:{main:{type:"record",description:"Public project or case study from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","year","createdAt"],properties:{title:{type:"string",maxLength:300},slug:{type:"string"},description:{type:"string",maxLength:2000},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},year:{type:"integer"},url:{type:"string",format:"uri"},publishedAt:{type:"string",format:"datetime"},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Ip1={lexicon:1,id:"ai.rizom.brain.series",defs:{main:{type:"record",description:"Public content series from a Rizom brain.",key:"any",record:{type:"object",required:["title","createdAt"],properties:{title:{type:"string",maxLength:300},slug:{type:"string"},description:{type:"string",maxLength:1e4},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Vp1={lexicon:1,id:"ai.rizom.brain.socialPost",defs:{main:{type:"record",description:"Semantic local social-post entity from a Rizom brain; not a Bluesky feed post.",key:"any",record:{type:"object",required:["title","platform","body","createdAt"],properties:{title:{type:"string",maxLength:300},platform:{type:"string"},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},status:{type:"string"},publishedAt:{type:"string",format:"datetime"},platformPostId:{type:"string"},sourceLocalEntityType:{type:"string"},sourceLocalEntityId:{type:"string"},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var Jp1={lexicon:1,id:"ai.rizom.brain.topic",defs:{main:{type:"record",description:"Public topic page from a Rizom brain.",key:"any",record:{type:"object",required:["title","body","createdAt"],properties:{title:{type:"string",maxLength:300},body:{type:"string",maxLength:1e5},format:{type:"string",knownValues:["text/markdown"]},brainDid:{type:"string"},anchorDid:{type:"string"},sourceEntityType:{type:"string"},sourceEntityId:{type:"string"},createdAt:{type:"string",format:"datetime"},updatedAt:{type:"string",format:"datetime"}}}}}};var g7B=K.object({type:K.string()}).catchall(K.unknown()),T7B=K.object({lexicon:K.literal(1),id:K.string(),defs:K.object({main:K.object({type:K.literal("record"),key:K.string().min(1),record:K.object({type:K.literal("object"),required:K.array(K.string()).optional(),properties:K.record(g7B)})})})});function uG(A){return T7B.parse(A)}var _w={"ai.rizom.brain.card":uG(Kp1),"ai.rizom.brain.deck":uG(Up1),"ai.rizom.brain.link":uG(Gp1),"ai.rizom.brain.note":uG(zp1),"ai.rizom.brain.post":uG(qp1),"ai.rizom.brain.project":uG(Fp1),"ai.rizom.brain.series":uG(Ip1),"ai.rizom.brain.socialPost":uG(Vp1),"ai.rizom.brain.topic":uG(Jp1)},S7B="Additive optional fields are compatible; required-field, type, or constraint changes require a migration plan or new NSID.";function DF(A){return{status:"approved",version:"1.0.0",revision:1,owner:"Rizom",steward:"Rizom protocol registry",projectionPackage:A,compatibility:S7B}}var m7B={"ai.rizom.brain.card":DF("@brains/atproto"),"ai.rizom.brain.deck":DF("@brains/decks"),"ai.rizom.brain.link":DF("@brains/link"),"ai.rizom.brain.note":DF("@brains/note"),"ai.rizom.brain.post":DF("@brains/blog"),"ai.rizom.brain.project":DF("@brains/portfolio"),"ai.rizom.brain.series":DF("@brains/series"),"ai.rizom.brain.socialPost":DF("@brains/social-media"),"ai.rizom.brain.topic":DF("@brains/topics")};function fP(){return Object.values(_w)}function el0(A){return _w[A]}function Ap0(){return Object.entries(m7B).map(([A,Q])=>({id:A,...Q}))}function tl0(A){return typeof A==="object"&&A!==null&&!Array.isArray(A)}var u7B=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;function c7B(A){let Q=K.string(),B=A.maxLength!==void 0?Q.max(A.maxLength):Q;if(A.knownValues)B=B.refine((w)=>A.knownValues?.includes(w),{message:`expected one of ${A.knownValues.join(", ")}`});if(A.format==="datetime")B=B.refine((w)=>u7B.test(w)&&!Number.isNaN(Date.parse(w)),{message:"expected datetime"});if(A.format==="uri")B=B.refine((w)=>{try{return new URL(w),!0}catch{return!1}},{message:"expected uri"});return B}function Lp1(A){switch(A.type){case"string":return c7B(A);case"integer":return K.number().int();case"boolean":return K.boolean();case"array":{let Q=A.items?Lp1(A.items):K.unknown(),B=K.array(Q);if(A.maxLength!==void 0)B=B.max(A.maxLength);return B}case"object":return l7B(A);case"blob":return K.custom(tl0,{message:"expected blob"});default:return K.unknown()}}function bp1(A){let Q=new Set(A.required??[]),B={};for(let[w,$]of Object.entries(A.properties??{})){let D=Lp1($);B[w]=Q.has(w)?D:D.optional()}return B}function l7B(A){return K.object(bp1(A)).passthrough()}function al0(A,Q,B,w=[]){let $=Object.keys(A).filter((D)=>!Q.has(D));if($.length===0)return;B.addIssue({code:K.ZodIssueCode.custom,path:w,message:`unrecognized field(s): ${$.join(", ")}`})}function p7B(A,Q){if(al0(A,new Set(["$type","siteUrl","brain","anchor","skills","model","version","createdAt","updatedAt"]),Q),tl0(A.brain))al0(A.brain,new Set(["did","name","role","purpose","values"]),Q,["brain"]);if(tl0(A.anchor))al0(A.anchor,new Set(["did","name","kind"]),Q,["anchor"])}function cG(A){let Q=K.object({...bp1(A.defs.main.record),$type:K.literal(A.id).optional()}).passthrough();return A.id==="ai.rizom.brain.card"?Q.superRefine(p7B):Q}var i7B={"ai.rizom.brain.card":cG(_w["ai.rizom.brain.card"]),"ai.rizom.brain.deck":cG(_w["ai.rizom.brain.deck"]),"ai.rizom.brain.link":cG(_w["ai.rizom.brain.link"]),"ai.rizom.brain.note":cG(_w["ai.rizom.brain.note"]),"ai.rizom.brain.post":cG(_w["ai.rizom.brain.post"]),"ai.rizom.brain.project":cG(_w["ai.rizom.brain.project"]),"ai.rizom.brain.series":cG(_w["ai.rizom.brain.series"]),"ai.rizom.brain.socialPost":cG(_w["ai.rizom.brain.socialPost"]),"ai.rizom.brain.topic":cG(_w["ai.rizom.brain.topic"])};function d7B(A,Q,B){let w=B.path.join(".");if(w==="$type")return`AT Protocol record $type must match lexicon id: ${String(Q.$type)} !== ${A.id}`;if(B.code==="invalid_type"&&B.received==="undefined")return`Missing required AT Protocol record field: ${w}`;if(B.code==="invalid_type")return`Invalid AT Protocol record field ${w}: expected ${B.expected}`;if(B.code==="too_big")return`Invalid AT Protocol record field ${w}: exceeds maxLength ${B.maximum}`;if(B.code==="custom")return`Invalid AT Protocol record field ${w}: ${B.message}`;if(B.code==="unrecognized_keys")return`Unrecognized AT Protocol record field(s): ${B.keys.join(", ")}`;return`Invalid AT Protocol record field ${w}: ${B.message}`}function FL(A,Q){let B=cG(A).safeParse(Q);if(B.success)return;let w=B.error.issues[0];if(!w)throw B.error;throw Error(d7B(A,Q,w))}var V40="atproto:brain-card-discovered",Np1="atproto:brain-discovered",jp1="atproto:brain-card-refreshed",_p1=K.object({repoDid:K.string().min(1),uri:K.string().min(1),cid:K.string().min(1),record:i7B["ai.rizom.brain.card"]}).strict(),zg8=K.object({agentId:K.string().min(1),name:K.string().min(1),url:K.string().url(),status:K.enum(["discovered","approved"]),repoDid:K.string().min(1).optional(),brainDid:K.string().min(1).optional(),anchorDid:K.string().min(1).optional(),cardUri:K.string().min(1).optional(),cardCid:K.string().min(1).optional()}).strict();class U5{static instance;projections=new Map;registrationCounts=new Map;static getInstance(){return this.instance??=new U5,this.instance}static createFresh(){return new U5}static resetInstance(){this.instance=void 0}register(A){this.validateProjection(A);let Q=this.projections.get(A.entityType);if(Q){if(!this.isEquivalentProjection(Q,A))throw Error(`AT Protocol projection already registered for entity type ${A.entityType}`);return this.registrationCounts.set(A.entityType,(this.registrationCounts.get(A.entityType)??1)+1),this.createUnregister(A.entityType)}return this.projections.set(A.entityType,A),this.registrationCounts.set(A.entityType,1),this.createUnregister(A.entityType)}get(A){return this.projections.get(A)}has(A){return this.projections.has(A)}list(){return Array.from(this.projections.values())}listLexicons(){return this.list().map((A)=>A.lexicon)}createUnregister(A){let Q=!0;return()=>{if(!Q)return;Q=!1;let B=this.registrationCounts.get(A)??0;if(B<=1){this.registrationCounts.delete(A),this.projections.delete(A);return}this.registrationCounts.set(A,B-1)}}isEquivalentProjection(A,Q){return A.entityType===Q.entityType&&A.collection===Q.collection&&A.lexicon.id===Q.lexicon.id&&A.validate===Q.validate}validateProjection(A){if(A.collection!==A.lexicon.id)throw Error(`AT Protocol projection collection must match lexicon id: ${A.collection} !== ${A.lexicon.id}`);if(!A.lexicon.defs.main.key)throw Error(`AT Protocol projection lexicon must define a record key: ${A.collection}`)}}jX();oy();K0();var Qp0=K.object({defaultPrompt:K.string().default("Write a blog post about my recent work and insights"),paginate:K.boolean().default(!0),pageSize:K.number().default(10)});p0();K0();Cw();var o7B=K.object({prompt:K.string().optional(),title:K.string().optional(),content:K.string().optional(),excerpt:K.string().optional(),coverImageId:K.string().optional(),seriesName:K.string().optional(),seriesIndex:K.number().optional(),skipAi:K.boolean().optional()}),kg8=zY.extend({title:K.string().optional(),slug:K.string().optional()});class Bp0 extends A4{constructor(A,Q){super(A,Q,{schema:o7B,jobTypeName:"blog-generation",entityType:"post"})}async generate(A,Q){let{prompt:B,coverImageId:w,seriesName:$,seriesIndex:D,skipAi:f}=A,{title:Y,content:X,excerpt:H}=A;if(f){if(!Y)this.failEarly("Title is required when skipAi is true");X=X??`## Introduction
|
|
5893
5893
|
|
|
5894
5894
|
Add your introduction here.
|
|
5895
5895
|
|
|
@@ -6109,7 +6109,7 @@ ${B.content}`,templateName:"blog:excerpt"})})}p0();oy();jX();function I4B(A){let
|
|
|
6109
6109
|
letter-spacing: 0.02em;
|
|
6110
6110
|
}
|
|
6111
6111
|
.printable-footer a { color: inherit; text-decoration: none; overflow-wrap: anywhere; }
|
|
6112
|
-
`}},void 0,!1,void 0,this),k7("header",{className:"printable-hero",children:[k7("div",{className:"printable-masthead",children:Q.brandLabel&&k7("p",{className:"printable-kicker",children:Q.brandLabel},void 0,!1,void 0,this)},void 0,!1,void 0,this),k7("div",{children:[k7("h1",{className:"printable-title",children:Q.title},void 0,!1,void 0,this),Q.excerpt&&k7("p",{className:"printable-excerpt",children:Q.excerpt},void 0,!1,void 0,this),k7("div",{className:"printable-meta",children:[Q.author&&k7("span",{children:["By ",Q.author]},void 0,!0,void 0,this),B&&k7("span",{children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q.coverImageUrl&&k7("figure",{className:"printable-cover-wrap",children:k7("img",{className:"printable-cover",src:Q.coverImageUrl,alt:""},void 0,!1,void 0,this)},void 0,!1,void 0,this),k7(f9,{markdown:Q.body,className:"printable-body"},void 0,!1,void 0,this),(Q.canonicalUrl||Q.brandLabel)&&k7("footer",{className:"printable-footer",children:[k7("span",{children:Q.brandLabel??"Printable PDF"},void 0,!1,void 0,this),Q.canonicalUrl&&k7("a",{href:Q.canonicalUrl,children:Q.canonicalUrl},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var ADB=26214400,QDB=60000;class Up0{context;renderPdf;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK}async resolve(A){if(A.sourceEntityType!=="post"||A.attachmentType!==N40)return;let Q=await this.context.entityService.getEntity({entityType:"post",id:A.sourceEntityId});if(!Q)return;let B=BDB(Q,{brandLabel:this.resolveBrandLabel(),coverImageUrl:await this.resolveCoverImageUrl(Q)}),w=await s4B(e4B(t4B(),"brain-blog-printable-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/printable/post/${Q.id}`,template:pp1,format:"pdf",content:B,siteConfig:{title:B.title,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"document",data:await this.renderPdf(D.urlFor($.urlPath),{maxBytes:ADB,timeoutMs:QDB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${wDB(Q)}-printable.pdf`}}finally{await D.close()}}finally{await a4B(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){let{frontmatter:Q}=lB(A.content),B=y8.parse(Q);if(!B.coverImageId)return;let w=await this.context.entityService.getEntity({entityType:"image",id:B.coverImageId});return w?.content.startsWith("data:image/")?w.content:void 0}}function BDB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=y8.parse(B);return{title:$.title,body:w,...$.excerpt?{excerpt:$.excerpt}:{},...$.author?{author:$.author}:{},...$.publishedAt?{publishedAt:$.publishedAt}:{},...$.canonicalUrl?{canonicalUrl:$.canonicalUrl}:{},...Q.coverImageUrl?{coverImageUrl:Q.coverImageUrl}:{},...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function wDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}import{mkdtemp as XDB,rm as HDB}from"fs/promises";import{tmpdir as WDB}from"os";import{join as ZDB}from"path";K0();jX();K0();import{jsxDEV as YDB}from"preact/jsx-dev-runtime";var Gr="og-image",$DB="blog:og-image",ip1=K.object({title:K.string().min(1),excerpt:K.string().optional(),author:K.string().optional(),publishedAt:K.string().optional(),brandLabel:K.string().optional(),coverImageUrl:K.string().optional()}),dp1={name:$DB,pluginId:"blog",schema:ip1,renderers:{image:fDB}};function DDB(A){if(!A)return;let Q=new Date(A);if(Number.isNaN(Q.getTime()))return;return Q.toLocaleDateString("en-GB",{year:"numeric",month:"short",day:"2-digit"})}function fDB(A){let Q=ip1.parse(A);return YDB(c3,{brandLabel:Q.brandLabel??Q.title,eyebrow:"Journal",title:Q.title,subtitle:Q.excerpt,meta:[Q.author],tag:DDB(Q.publishedAt)},void 0,!1,void 0,this)}var KDB={width:1200,height:630},UDB=60000;class Gp0{context;screenshotPng;constructor(A,Q={}){this.context=A;this.screenshotPng=Q.screenshotPng??Ur}async resolve(A){if(A.sourceEntityType!=="post"||A.attachmentType!==Gr)return;let Q=await this.context.entityService.getEntity({entityType:"post",id:A.sourceEntityId});if(!Q)return;let B=GDB(Q,{brandLabel:this.resolveBrandLabel(),coverImageUrl:await this.resolveCoverImageUrl(Q)}),w=await XDB(ZDB(WDB(),"brain-blog-og-image-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/og/post/${Q.id}`,template:dp1,format:"image",content:B,siteConfig:{title:B.title,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"image",data:await this.screenshotPng(D.urlFor($.urlPath),KDB,{timeoutMs:UDB,fullPage:!1,omitBackground:!1}),mimeType:"image/png",filename:`${zDB(Q)}-og.png`}}finally{await D.close()}}finally{await HDB(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){let{frontmatter:Q}=lB(A.content),B=y8.parse(Q);if(!B.coverImageId)return;let w=await this.context.entityService.getEntity({entityType:"image",id:B.coverImageId});return w?.content.startsWith("data:image/")?w.content:void 0}}function GDB(A,Q={}){let{frontmatter:B}=lB(A.content),w=y8.parse(B);return{title:w.title,...w.excerpt?{excerpt:w.excerpt}:{},...w.author?{author:w.author}:{},...w.publishedAt?{publishedAt:w.publishedAt}:{},...Q.coverImageUrl?{coverImageUrl:Q.coverImageUrl}:{},...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function zDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}var np1={name:"@brains/blog",private:!0,version:"0.2.0-alpha.128",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/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class zp0 extends PQ{entityType=YF.entityType;schema=ry;adapter=YF;unregisterAtprotoProjection;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(A={}){super("blog",np1,A,Qp0)}getEntityTypeConfig(){return{weight:2,publish:{publishStatuses:["queued","published"]}}}createGenerationHandler(A){return new Bp0(this.logger.child("BlogGenerationJobHandler"),A)}getTemplates(){return xp1()}getDataSources(){return[new $p0(this.logger.child("BlogDataSource"))]}async onRegister(A){let{RSSDataSource:Q}=await Promise.resolve().then(() => (sp1(),op1));A.entities.registerDataSource(new Q(this.logger.child("RSSDataSource"))),Rp1(A,this.logger),vp1(A,this.logger),Cp1(A,this.logger),yp1(A),this.unregisterPrintableAttachmentProvider=A.attachments.register("post",N40,new Up0(A)),this.unregisterOgImageAttachmentProvider=A.attachments.register("post",Gr,new Gp0(A)),this.deferPublishAssetRegistration(A),this.unregisterAtprotoProjection=U5.getInstance().register(Yp0()),this.logger.info("Blog plugin registered (routes auto-generated at /posts/)")}deferPublishAssetRegistration(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"publish-assets:register",payload:{entityType:"post",attachmentType:Gr,mediaEntityType:"image",targetEntityField:{location:"frontmatter",field:"ogImageId"},requiredWhen:{status:"published"},autoGenerate:!0,jobType:"image:image-render-source"}}),{success:!0}})}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function qp0(A={}){return new zp0(A)}jX();oy();p0();K0();K0();p$();p0();var BW=K.object({title:K.string(),slug:K.string(),coverImageId:K.string().optional()}),ap1=BW.pick({title:!0,slug:!0}),IL=o1.extend({metadata:ap1}),j40=IL.extend({frontmatter:BW}),_40=j40.extend({description:K.string().optional(),postCount:K.number(),coverImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()}),tp1=K.object({description:K.string().optional()});function HP(A){return new pB(tp1,{title:A,mappings:[{key:"description",label:"Description",type:"string"}]})}p0();class Fp0 extends V2{constructor(){super({entityType:"series",schema:IL,frontmatterSchema:BW,supportsCoverImage:!0,bodyFormatter:HP("")})}toMarkdown(A){let Q,B={};try{Q=this.parseFrontMatter(A.content,BW).coverImageId,B=HP(A.metadata.title).parse(this.extractBody(A.content))}catch{}let w={title:A.metadata.title,slug:A.metadata.slug,...Q&&{coverImageId:Q}},D=HP(A.metadata.title).format(B);return this.buildMarkdown(D,w)}fromMarkdown(A){let Q=this.parseFrontMatter(A,BW);return{content:A,entityType:"series",metadata:{title:Q.title,slug:Q.slug}}}parseBody(A){try{let Q=this.parseFrontMatter(A,BW);return HP(Q.title).parse(this.extractBody(A))}catch{return{}}}generateFrontMatter(){return""}}var VL=new Fp0;p0();K0();bY();K0();var IDB=K.object({seriesName:K.string().optional(),seriesIndex:K.number().optional()});function M40(A){let Q=IDB.safeParse(A);return Q.success?Q.data:{}}function WP(A){return M40(A.metadata).seriesName}function ep1(A){return M40(A.metadata).seriesIndex}function Ai1(A,Q){let B=ep1(A)??Number.MAX_SAFE_INTEGER,w=ep1(Q)??Number.MAX_SAFE_INTEGER;return B-w}class Ip0{entityService;logger;constructor(A,Q){this.entityService=A;this.logger=Q}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 Q=await this.entityService.listEntities({entityType:"series"}),B=new Map(Q.map(($)=>[$.id,$])),w=new Set;for(let $ of A){let D=Y1($);w.add(D);let f=B.get(D),Y=f?.content??this.createSeriesContent($),X=RB(Y);if(f?.contentHash===X)continue;let H={id:D,entityType:"series",content:Y,contentHash:X,created:f?.created??new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:$,slug:Y1($)}};await this.entityService.upsertEntity({entity:H}),this.logger.debug(`Upserted series: ${$}`)}for(let $ of Q)if(!w.has($.id))await this.entityService.deleteEntity({entityType:"series",id:$.id}),this.logger.debug(`Deleted orphaned series: ${$.id}`)}async handleEntityChange(A,Q){let B=WP(A);if(B)await this.ensureSeriesExists(B);if(Q&&Q!==B)await this.cleanupOrphanedSeries(Q)}async handleEntityDeleted(){await this.syncAllSeries()}async ensureSeriesExists(A){let Q=Y1(A);if(await this.entityService.getEntity({entityType:"series",id:Q}))return;let w=this.createSeriesContent(A),$={id:Q,entityType:"series",content:w,contentHash:RB(w),created:new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:A,slug:Y1(A)}};await this.entityService.upsertEntity({entity:$}),this.logger.debug(`Created series: ${A}`)}async cleanupOrphanedSeries(A){let Q=Y1(A);if(!await this.entityService.getEntity({entityType:"series",id:Q}))return;if(!await this.hasSeriesReferences(A))await this.entityService.deleteEntity({entityType:"series",id:Q}),this.logger.debug(`Deleted orphaned series: ${A}`)}async hasSeriesReferences(A){let Q=this.entityService.getEntityTypes();for(let B of Q){if(B==="series")continue;if((await this.entityService.listEntities({entityType:B,options:{filter:{metadata:{seriesName:A}},limit:1}})).length>0)return!0}return!1}async collectSeriesNames(){let A=new Set,Q=this.entityService.getEntityTypes();for(let B of Q){if(B==="series")continue;let w=await this.entityService.listEntities({entityType:B});for(let $ of w){let D=WP($);if(D)A.add(D)}}return A}createSeriesContent(A){let Q={title:A,slug:Y1(A)};return X7("",Q)}}p0();K0();var VDB=K.object({entityType:K.literal("series"),query:K.object({id:K.string().optional(),limit:K.number().optional(),page:K.number().optional(),pageSize:K.number().optional()}).passthrough()}),JDB=K.object({type:K.enum(["list","detail"]),seriesName:K.string().optional()});function LDB(A){let Q=JDB.safeParse(A);if(Q.success)return{type:Q.data.type,seriesName:Q.data.seriesName};let B=VDB.safeParse(A);if(B.success){let{query:w}=B.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 Qi1(A){let Q=h2(A.content,BW);return j40.parse({...A,frontmatter:Q.metadata})}class Vp0{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(A){this.logger=A}async fetch(A,Q,B){let w=LDB(A),$=B.entityService;if(w.type==="list")return this.fetchSeriesList(Q,$);if(w.seriesName)return this.fetchSeriesDetail(w.seriesName,Q,$);if(w.seriesSlug)return this.fetchSeriesDetailBySlug(w.seriesSlug,Q,$);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(A,Q){let B=await Q.listEntities({entityType:"series"}),w=await this.countEntitiesPerSeries(Q),$=B.map((D)=>{let f=Qi1(D),Y=VL.parseBody(D.content);return{...f,description:Y.description,postCount:w.get(D.metadata.title)??0}});return this.logger.debug(`Found ${$.length} series entities`),A.parse({series:$})}async fetchSeriesDetail(A,Q,B,w){if(!w)w=(await B.listEntities({entityType:"series",options:{filter:{metadata:{title:A}}}}))[0];if(!w)throw Error(`Series not found: ${A}`);let $=Qi1(w),D=VL.parseBody(w.content),f=await this.getSeriesMembers(A,B);return this.logger.debug(`Found ${f.length} entities in series "${A}"`),Q.parse({seriesName:A,posts:f,series:{...$,description:D.description,postCount:f.length},description:D.description})}async fetchSeriesDetailBySlug(A,Q,B){let $=(await B.listEntities({entityType:"series",options:{filter:{metadata:{slug:A}}}}))[0];if(!$)throw Error(`Series not found with slug: ${A}`);return this.fetchSeriesDetail($.metadata.title,Q,B,$)}async countEntitiesPerSeries(A){let Q=new Map,B=A.getEntityTypes();for(let w of B){if(w==="series")continue;let $=await A.listEntities({entityType:w});for(let D of $){let f=WP(D);if(f)Q.set(f,(Q.get(f)??0)+1)}}return Q}async getSeriesMembers(A,Q){let B=[],w=Q.getEntityTypes();for(let $ of w){if($==="series")continue;let D=await Q.listEntities({entityType:$,options:{filter:{metadata:{seriesName:A}}}});B.push(...D)}return B.sort(Ai1),B}}p0();K0();bY();var bDB=K.object({prompt:K.string().optional(),title:K.string().optional(),seriesId:K.string().optional()}),NDB=K.object({title:K.string().optional(),excerpt:K.string().optional()});class P40{logger;context;constructor(A,Q){this.logger=A;this.context=Q}async process(A){let Q=A.seriesId??A.title;if(!Q)return{success:!1,error:"seriesId or title required"};let B=await this.context.entityService.getEntity({entityType:"series",id:Q});if(!B)return{success:!1,error:`Series not found: ${Q}`};let w=await this.gatherMemberSummaries(B.metadata.title);if(w.length===0)return{success:!1,error:`No members found in series: ${B.metadata.title}`};let $=A.prompt??`Series name: ${B.metadata.title}
|
|
6112
|
+
`}},void 0,!1,void 0,this),k7("header",{className:"printable-hero",children:[k7("div",{className:"printable-masthead",children:Q.brandLabel&&k7("p",{className:"printable-kicker",children:Q.brandLabel},void 0,!1,void 0,this)},void 0,!1,void 0,this),k7("div",{children:[k7("h1",{className:"printable-title",children:Q.title},void 0,!1,void 0,this),Q.excerpt&&k7("p",{className:"printable-excerpt",children:Q.excerpt},void 0,!1,void 0,this),k7("div",{className:"printable-meta",children:[Q.author&&k7("span",{children:["By ",Q.author]},void 0,!0,void 0,this),B&&k7("span",{children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q.coverImageUrl&&k7("figure",{className:"printable-cover-wrap",children:k7("img",{className:"printable-cover",src:Q.coverImageUrl,alt:""},void 0,!1,void 0,this)},void 0,!1,void 0,this),k7(f9,{markdown:Q.body,className:"printable-body"},void 0,!1,void 0,this),(Q.canonicalUrl||Q.brandLabel)&&k7("footer",{className:"printable-footer",children:[k7("span",{children:Q.brandLabel??"Printable PDF"},void 0,!1,void 0,this),Q.canonicalUrl&&k7("a",{href:Q.canonicalUrl,children:Q.canonicalUrl},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var ADB=26214400,QDB=60000;class Up0{context;renderPdf;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK}async resolve(A){if(A.sourceEntityType!=="post"||A.attachmentType!==N40)return;let Q=await this.context.entityService.getEntity({entityType:"post",id:A.sourceEntityId});if(!Q)return;let B=BDB(Q,{brandLabel:this.resolveBrandLabel(),coverImageUrl:await this.resolveCoverImageUrl(Q)}),w=await s4B(e4B(t4B(),"brain-blog-printable-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/printable/post/${Q.id}`,template:pp1,format:"pdf",content:B,siteConfig:{title:B.title,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"document",data:await this.renderPdf(D.urlFor($.urlPath),{maxBytes:ADB,timeoutMs:QDB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${wDB(Q)}-printable.pdf`}}finally{await D.close()}}finally{await a4B(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){let{frontmatter:Q}=lB(A.content),B=y8.parse(Q);if(!B.coverImageId)return;let w=await this.context.entityService.getEntity({entityType:"image",id:B.coverImageId});return w?.content.startsWith("data:image/")?w.content:void 0}}function BDB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=y8.parse(B);return{title:$.title,body:w,...$.excerpt?{excerpt:$.excerpt}:{},...$.author?{author:$.author}:{},...$.publishedAt?{publishedAt:$.publishedAt}:{},...$.canonicalUrl?{canonicalUrl:$.canonicalUrl}:{},...Q.coverImageUrl?{coverImageUrl:Q.coverImageUrl}:{},...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function wDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}import{mkdtemp as XDB,rm as HDB}from"fs/promises";import{tmpdir as WDB}from"os";import{join as ZDB}from"path";K0();jX();K0();import{jsxDEV as YDB}from"preact/jsx-dev-runtime";var Gr="og-image",$DB="blog:og-image",ip1=K.object({title:K.string().min(1),excerpt:K.string().optional(),author:K.string().optional(),publishedAt:K.string().optional(),brandLabel:K.string().optional(),coverImageUrl:K.string().optional()}),dp1={name:$DB,pluginId:"blog",schema:ip1,renderers:{image:fDB}};function DDB(A){if(!A)return;let Q=new Date(A);if(Number.isNaN(Q.getTime()))return;return Q.toLocaleDateString("en-GB",{year:"numeric",month:"short",day:"2-digit"})}function fDB(A){let Q=ip1.parse(A);return YDB(c3,{brandLabel:Q.brandLabel??Q.title,eyebrow:"Journal",title:Q.title,subtitle:Q.excerpt,meta:[Q.author],tag:DDB(Q.publishedAt)},void 0,!1,void 0,this)}var KDB={width:1200,height:630},UDB=60000;class Gp0{context;screenshotPng;constructor(A,Q={}){this.context=A;this.screenshotPng=Q.screenshotPng??Ur}async resolve(A){if(A.sourceEntityType!=="post"||A.attachmentType!==Gr)return;let Q=await this.context.entityService.getEntity({entityType:"post",id:A.sourceEntityId});if(!Q)return;let B=GDB(Q,{brandLabel:this.resolveBrandLabel(),coverImageUrl:await this.resolveCoverImageUrl(Q)}),w=await XDB(ZDB(WDB(),"brain-blog-og-image-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/og/post/${Q.id}`,template:dp1,format:"image",content:B,siteConfig:{title:B.title,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"image",data:await this.screenshotPng(D.urlFor($.urlPath),KDB,{timeoutMs:UDB,fullPage:!1,omitBackground:!1}),mimeType:"image/png",filename:`${zDB(Q)}-og.png`}}finally{await D.close()}}finally{await HDB(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){let{frontmatter:Q}=lB(A.content),B=y8.parse(Q);if(!B.coverImageId)return;let w=await this.context.entityService.getEntity({entityType:"image",id:B.coverImageId});return w?.content.startsWith("data:image/")?w.content:void 0}}function GDB(A,Q={}){let{frontmatter:B}=lB(A.content),w=y8.parse(B);return{title:w.title,...w.excerpt?{excerpt:w.excerpt}:{},...w.author?{author:w.author}:{},...w.publishedAt?{publishedAt:w.publishedAt}:{},...Q.coverImageUrl?{coverImageUrl:Q.coverImageUrl}:{},...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function zDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}var np1={name:"@brains/blog",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class zp0 extends PQ{entityType=YF.entityType;schema=ry;adapter=YF;unregisterAtprotoProjection;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(A={}){super("blog",np1,A,Qp0)}getEntityTypeConfig(){return{weight:2,publish:{publishStatuses:["queued","published"]}}}createGenerationHandler(A){return new Bp0(this.logger.child("BlogGenerationJobHandler"),A)}getTemplates(){return xp1()}getDataSources(){return[new $p0(this.logger.child("BlogDataSource"))]}async onRegister(A){let{RSSDataSource:Q}=await Promise.resolve().then(() => (sp1(),op1));A.entities.registerDataSource(new Q(this.logger.child("RSSDataSource"))),Rp1(A,this.logger),vp1(A,this.logger),Cp1(A,this.logger),yp1(A),this.unregisterPrintableAttachmentProvider=A.attachments.register("post",N40,new Up0(A)),this.unregisterOgImageAttachmentProvider=A.attachments.register("post",Gr,new Gp0(A)),this.deferPublishAssetRegistration(A),this.unregisterAtprotoProjection=U5.getInstance().register(Yp0()),this.logger.info("Blog plugin registered (routes auto-generated at /posts/)")}deferPublishAssetRegistration(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"publish-assets:register",payload:{entityType:"post",attachmentType:Gr,mediaEntityType:"image",targetEntityField:{location:"frontmatter",field:"ogImageId"},requiredWhen:{status:"published"},autoGenerate:!0,jobType:"image:image-render-source"}}),{success:!0}})}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function qp0(A={}){return new zp0(A)}jX();oy();p0();K0();K0();p$();p0();var BW=K.object({title:K.string(),slug:K.string(),coverImageId:K.string().optional()}),ap1=BW.pick({title:!0,slug:!0}),IL=o1.extend({metadata:ap1}),j40=IL.extend({frontmatter:BW}),_40=j40.extend({description:K.string().optional(),postCount:K.number(),coverImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()}),tp1=K.object({description:K.string().optional()});function HP(A){return new pB(tp1,{title:A,mappings:[{key:"description",label:"Description",type:"string"}]})}p0();class Fp0 extends V2{constructor(){super({entityType:"series",schema:IL,frontmatterSchema:BW,supportsCoverImage:!0,bodyFormatter:HP("")})}toMarkdown(A){let Q,B={};try{Q=this.parseFrontMatter(A.content,BW).coverImageId,B=HP(A.metadata.title).parse(this.extractBody(A.content))}catch{}let w={title:A.metadata.title,slug:A.metadata.slug,...Q&&{coverImageId:Q}},D=HP(A.metadata.title).format(B);return this.buildMarkdown(D,w)}fromMarkdown(A){let Q=this.parseFrontMatter(A,BW);return{content:A,entityType:"series",metadata:{title:Q.title,slug:Q.slug}}}parseBody(A){try{let Q=this.parseFrontMatter(A,BW);return HP(Q.title).parse(this.extractBody(A))}catch{return{}}}generateFrontMatter(){return""}}var VL=new Fp0;p0();K0();bY();K0();var IDB=K.object({seriesName:K.string().optional(),seriesIndex:K.number().optional()});function M40(A){let Q=IDB.safeParse(A);return Q.success?Q.data:{}}function WP(A){return M40(A.metadata).seriesName}function ep1(A){return M40(A.metadata).seriesIndex}function Ai1(A,Q){let B=ep1(A)??Number.MAX_SAFE_INTEGER,w=ep1(Q)??Number.MAX_SAFE_INTEGER;return B-w}class Ip0{entityService;logger;constructor(A,Q){this.entityService=A;this.logger=Q}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 Q=await this.entityService.listEntities({entityType:"series"}),B=new Map(Q.map(($)=>[$.id,$])),w=new Set;for(let $ of A){let D=Y1($);w.add(D);let f=B.get(D),Y=f?.content??this.createSeriesContent($),X=RB(Y);if(f?.contentHash===X)continue;let H={id:D,entityType:"series",content:Y,contentHash:X,created:f?.created??new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:$,slug:Y1($)}};await this.entityService.upsertEntity({entity:H}),this.logger.debug(`Upserted series: ${$}`)}for(let $ of Q)if(!w.has($.id))await this.entityService.deleteEntity({entityType:"series",id:$.id}),this.logger.debug(`Deleted orphaned series: ${$.id}`)}async handleEntityChange(A,Q){let B=WP(A);if(B)await this.ensureSeriesExists(B);if(Q&&Q!==B)await this.cleanupOrphanedSeries(Q)}async handleEntityDeleted(){await this.syncAllSeries()}async ensureSeriesExists(A){let Q=Y1(A);if(await this.entityService.getEntity({entityType:"series",id:Q}))return;let w=this.createSeriesContent(A),$={id:Q,entityType:"series",content:w,contentHash:RB(w),created:new Date().toISOString(),updated:new Date().toISOString(),visibility:"public",metadata:{title:A,slug:Y1(A)}};await this.entityService.upsertEntity({entity:$}),this.logger.debug(`Created series: ${A}`)}async cleanupOrphanedSeries(A){let Q=Y1(A);if(!await this.entityService.getEntity({entityType:"series",id:Q}))return;if(!await this.hasSeriesReferences(A))await this.entityService.deleteEntity({entityType:"series",id:Q}),this.logger.debug(`Deleted orphaned series: ${A}`)}async hasSeriesReferences(A){let Q=this.entityService.getEntityTypes();for(let B of Q){if(B==="series")continue;if((await this.entityService.listEntities({entityType:B,options:{filter:{metadata:{seriesName:A}},limit:1}})).length>0)return!0}return!1}async collectSeriesNames(){let A=new Set,Q=this.entityService.getEntityTypes();for(let B of Q){if(B==="series")continue;let w=await this.entityService.listEntities({entityType:B});for(let $ of w){let D=WP($);if(D)A.add(D)}}return A}createSeriesContent(A){let Q={title:A,slug:Y1(A)};return X7("",Q)}}p0();K0();var VDB=K.object({entityType:K.literal("series"),query:K.object({id:K.string().optional(),limit:K.number().optional(),page:K.number().optional(),pageSize:K.number().optional()}).passthrough()}),JDB=K.object({type:K.enum(["list","detail"]),seriesName:K.string().optional()});function LDB(A){let Q=JDB.safeParse(A);if(Q.success)return{type:Q.data.type,seriesName:Q.data.seriesName};let B=VDB.safeParse(A);if(B.success){let{query:w}=B.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 Qi1(A){let Q=h2(A.content,BW);return j40.parse({...A,frontmatter:Q.metadata})}class Vp0{logger;id="series:entities";name="Series DataSource";description="Fetches series list and detail data";constructor(A){this.logger=A}async fetch(A,Q,B){let w=LDB(A),$=B.entityService;if(w.type==="list")return this.fetchSeriesList(Q,$);if(w.seriesName)return this.fetchSeriesDetail(w.seriesName,Q,$);if(w.seriesSlug)return this.fetchSeriesDetailBySlug(w.seriesSlug,Q,$);throw Error("Invalid series query: must specify seriesName or slug for detail")}async fetchSeriesList(A,Q){let B=await Q.listEntities({entityType:"series"}),w=await this.countEntitiesPerSeries(Q),$=B.map((D)=>{let f=Qi1(D),Y=VL.parseBody(D.content);return{...f,description:Y.description,postCount:w.get(D.metadata.title)??0}});return this.logger.debug(`Found ${$.length} series entities`),A.parse({series:$})}async fetchSeriesDetail(A,Q,B,w){if(!w)w=(await B.listEntities({entityType:"series",options:{filter:{metadata:{title:A}}}}))[0];if(!w)throw Error(`Series not found: ${A}`);let $=Qi1(w),D=VL.parseBody(w.content),f=await this.getSeriesMembers(A,B);return this.logger.debug(`Found ${f.length} entities in series "${A}"`),Q.parse({seriesName:A,posts:f,series:{...$,description:D.description,postCount:f.length},description:D.description})}async fetchSeriesDetailBySlug(A,Q,B){let $=(await B.listEntities({entityType:"series",options:{filter:{metadata:{slug:A}}}}))[0];if(!$)throw Error(`Series not found with slug: ${A}`);return this.fetchSeriesDetail($.metadata.title,Q,B,$)}async countEntitiesPerSeries(A){let Q=new Map,B=A.getEntityTypes();for(let w of B){if(w==="series")continue;let $=await A.listEntities({entityType:w});for(let D of $){let f=WP(D);if(f)Q.set(f,(Q.get(f)??0)+1)}}return Q}async getSeriesMembers(A,Q){let B=[],w=Q.getEntityTypes();for(let $ of w){if($==="series")continue;let D=await Q.listEntities({entityType:$,options:{filter:{metadata:{seriesName:A}}}});B.push(...D)}return B.sort(Ai1),B}}p0();K0();bY();var bDB=K.object({prompt:K.string().optional(),title:K.string().optional(),seriesId:K.string().optional()}),NDB=K.object({title:K.string().optional(),excerpt:K.string().optional()});class P40{logger;context;constructor(A,Q){this.logger=A;this.context=Q}async process(A){let Q=A.seriesId??A.title;if(!Q)return{success:!1,error:"seriesId or title required"};let B=await this.context.entityService.getEntity({entityType:"series",id:Q});if(!B)return{success:!1,error:`Series not found: ${Q}`};let w=await this.gatherMemberSummaries(B.metadata.title);if(w.length===0)return{success:!1,error:`No members found in series: ${B.metadata.title}`};let $=A.prompt??`Series name: ${B.metadata.title}
|
|
6113
6113
|
|
|
6114
6114
|
Content in this series:
|
|
6115
6115
|
${w.join(`
|
|
@@ -6121,7 +6121,7 @@ Your task is to write a series description (2-3 sentences) that:
|
|
|
6121
6121
|
3. Is engaging and makes readers want to explore the content
|
|
6122
6122
|
4. Works well as a series overview on a website
|
|
6123
6123
|
|
|
6124
|
-
Be concise and focus on what makes this series unique and valuable.`});async function Xi1({entity:A,config:Q}){let B=IL.parse(A),w=VL.parseBody(B.content);return{$type:"ai.rizom.brain.series",title:B.metadata.title,slug:B.metadata.slug,...w.description&&{description:w.description},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"series",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function Jp0(){return{entityType:"series",collection:"ai.rizom.brain.series",lexicon:_w["ai.rizom.brain.series"],validate:!1,buildRecord:Xi1}}var Hi1={name:"@brains/series",private:!0,version:"0.2.0-alpha.
|
|
6124
|
+
Be concise and focus on what makes this series unique and valuable.`});async function Xi1({entity:A,config:Q}){let B=IL.parse(A),w=VL.parseBody(B.content);return{$type:"ai.rizom.brain.series",title:B.metadata.title,slug:B.metadata.slug,...w.description&&{description:w.description},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"series",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function Jp0(){return{entityType:"series",collection:"ai.rizom.brain.series",lexicon:_w["ai.rizom.brain.series"],validate:!1,buildRecord:Xi1}}var Hi1={name:"@brains/series",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/entity-service":"workspace:*","@brains/job-queue":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Wi1=K.discriminatedUnion("mode",[K.object({mode:K.literal("derive"),reason:K.string().optional()}),K.object({mode:K.literal("source"),entityId:K.string(),entityType:K.string(),seriesName:K.string().optional(),previousSeriesName:K.string().optional()})]);class Lp0 extends PQ{entityType="series";schema=IL;adapter=VL;manager;unregisterAtprotoProjection;constructor(){super("series",Hi1)}getEntityTypeConfig(){return{weight:0.5}}createGenerationHandler(A){return new P40(this.logger.child("SeriesGenerationHandler"),A)}getTemplates(){return{...fi1(),description:Yi1}}getDataSources(){return[new Vp0(this.logger.child("SeriesDataSource"))]}getDerivedEntityProjections(A){return[{id:"series-projection",targetType:"series",job:{type:"series:project",handler:this.createSeriesProjectionHandler(A)},initialSync:{jobData:{mode:"derive",reason:"initial-sync"},jobOptions:this.getSyncProjectionJobOptions("initial-sync")},sourceChange:{sourceTypes:["*"],events:["entity:created","entity:updated","entity:deleted"],requireInitialSync:!0,jobData:(Q)=>{if(Q.entityType==="series")return null;if(!Q.entity)return null;let B=WP(Q.entity),w=M40(Q.previousMetadata).seriesName;if(!B&&!w)return null;return{mode:"source",entityId:Q.entity.id,entityType:Q.entity.entityType,...B?{seriesName:B}:{},...w&&w!==B?{previousSeriesName:w}:{}}},jobOptions:(Q)=>{if(!Q.entity)return;return this.getSourceProjectionJobOptions(Q.entity)}}}]}async onRegister(A){this.manager=new Ip0(A.entityService,this.logger.child("SeriesManager")),this.unregisterAtprotoProjection=U5.getInstance().register(Jp0())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}createSeriesProjectionHandler(A){return{process:async(Q)=>{let B=Wi1.parse(Q);if(B.mode==="derive")return await this.projectAll(A),{success:!0};let w=await A.entityService.getEntity({entityType:B.entityType,id:B.entityId});if(w)await this.projectSource(w,B.previousSeriesName);else{let $=this.requireManager();for(let D of[B.seriesName,B.previousSeriesName])if(D)await $.cleanupOrphanedSeries(D)}return{success:!0}},validateAndParse:(Q)=>{let B=Wi1.safeParse(Q??{});return B.success?B.data:null}}}requireManager(){if(!this.manager)throw Error("SeriesPlugin not registered");return this.manager}getSyncProjectionJobOptions(A){return{source:this.id,deduplication:"coalesce",deduplicationKey:`series-sync:${A}`,metadata:{operationType:"data_processing",operationTarget:"series"}}}getSourceProjectionJobOptions(A){return{source:this.id,deduplication:"coalesce",deduplicationKey:`series-source:${A.entityType}:${A.id}`,metadata:{operationType:"data_processing",operationTarget:`series:${A.entityType}:${A.id}`}}}async projectSource(A,Q){await this.requireManager().handleEntityChange(A,Q)}async projectAll(A){await this.requireManager().syncAllSeries();let Q=new P40(this.logger.child("SeriesGenerationHandler"),A),B=await A.entityService.listEntities({entityType:"series"});for(let w of B)try{if(!this.adapter.parseBody(w.content).description)this.logger.info(`Generating description for series: ${w.metadata.title}`),await Q.process({seriesId:w.id})}catch($){this.logger.error(`Failed to generate description for series: ${w.id}`,{error:$})}}}function bp0(){return new Lp0}p0();K0();p0();K0();K0();p0();var kDB=K.enum(["generating","draft","queued","published","failed"]),Zi1="publishedAt is required when deck status is published",Ki1=(A)=>A.status==="published"&&!A.publishedAt,Np0=(A)=>{if(Ki1(A))throw Error(Zi1)},wW=K.object({title:K.string(),slug:K.string().optional(),description:K.string().optional(),author:K.string().optional(),status:kDB,publishedAt:K.string().datetime().optional(),event:K.string().optional(),coverImageId:K.string().optional(),ogImageId:K.string().optional()}),ODB=wW.pick({title:!0,description:!0,status:!0,publishedAt:!0,coverImageId:!0}).extend({slug:K.string(),error:K.string().optional()}).superRefine((A,Q)=>{if(!Ki1(A))return;Q.addIssue({code:K.ZodIssueCode.custom,path:["publishedAt"],message:Zi1})}),ay=o1.extend({entityType:K.literal("deck"),metadata:ODB}),k40=ay.extend({frontmatter:wW,body:K.string(),ogImageUrl:K.string().optional()}),ZP=k40.extend({url:K.string().optional(),typeLabel:K.string().optional(),listUrl:K.string().optional(),listLabel:K.string().optional(),coverImageUrl:K.string().optional(),ogImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()});class jp0 extends V2{constructor(){super({entityType:"deck",schema:ay,frontmatterSchema:wW,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 Q=this.extractBody(A.content);this.validateSlideStructure(Q);let B=this.parseFrontMatter(A.content,wW);Np0(B);let w={...B,slug:B.slug??A.metadata.slug};return this.buildMarkdown(Q,w)}fromMarkdown(A){let Q=this.parseFrontmatter(A),B=this.extractBody(A);Np0(Q),this.validateSlideStructure(B);let w=Q.slug??Y1(Q.title),$=Q.status;return{entityType:"deck",content:A,metadata:{slug:w,title:Q.title,description:Q.description,status:$,publishedAt:Q.publishedAt,coverImageId:Q.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)}buildStub(A){let Q={title:A.title,slug:A.id,status:"generating"};return{content:this.buildMarkdown(`---
|
|
6125
6125
|
`,Q),metadata:{title:A.title,slug:A.id,status:"generating"}}}}var zr=new jp0;K0();Jw();var xDB=K.object({markdown:K.string().describe("Markdown content with slide separators (---)"),deck:ZP.optional()}),_p0=R1({name:"deck-detail",description:"Render a presentation deck as Reveal.js slides",schema:xDB,dataSourceId:"decks:entities",requiredPermission:"public",layout:{component:Zu0,fullscreen:!0}});Jw();K0();var Mp0=K.object({decks:K.array(k40)}),Pp0=K.object({decks:K.array(ZP),pageTitle:K.string().optional(),pageLabel:K.string().optional()});import{jsxDEV as kp0}from"preact/jsx-dev-runtime";var RDB="Presentations",Op0=({decks:A,pageLabel:Q})=>{let B=A.map(($)=>({id:$.id,url:$.url,title:$.frontmatter.title,date:$.frontmatter.publishedAt??$.created,description:$.frontmatter.description}));return kp0("div",{className:"deck-list bg-theme",children:kp0("div",{className:"container mx-auto max-w-[1100px] px-6 py-16 md:px-12 md:py-24",children:kp0(Hn,{label:Q&&Q!=="Decks"?Q:RDB,items:B},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)};p$();class O40 extends pB{constructor(){super(Mp0,{title:"Deck List",mappings:[{key:"decks",label:"Decks",type:"array",itemType:"object"}]})}}var xp0=R1({name:"deck-list",description:"List view of all presentation decks",schema:Pp0,dataSourceId:"decks:entities",requiredPermission:"public",formatter:new O40,layout:{component:Op0}});K0();p0();var vDB=K.object({title:K.string().max(80).describe("A short, punchy title (2-5 words) that's memorable and evocative"),content:K.string().describe("Full slide deck content in markdown format with slide separators (---). Each slide should have a header and focused content."),description:K.string().describe("A concise 1-2 sentence summary that captures the essence of the talk")}),Ui1=R1({name:"decks:generation",description:"Template for AI to generate complete slide decks from prompts",schema:vDB,dataSourceId:"shell:ai-content",requiredPermission:"public",useKnowledgeContext:!0,basePrompt:`You are creating slide decks in a distinctive voice that blends philosophy, technology, and culture.
|
|
6126
6126
|
|
|
6127
6127
|
Your task is to generate a complete slide deck based on the user's prompt.
|
|
@@ -6429,14 +6429,14 @@ ${Y}`,templateName:"decks:description"})).description,await this.reportProgress(
|
|
|
6429
6429
|
color: var(--carousel-accent);
|
|
6430
6430
|
font-weight: 600;
|
|
6431
6431
|
}
|
|
6432
|
-
`}},void 0,!1,void 0,this),$.map((H,W)=>_4("section",{className:`deck-carousel-slide${W===0?" is-cover":""}`,children:[_4("header",{className:"deck-carousel-header",children:_4("span",{className:"deck-carousel-wordmark","aria-label":B??Q,children:[_4("span",{className:"wm-primary",children:D.primary},void 0,!1,void 0,this),D.secondary!==void 0&&_4(TDB,{children:[_4("span",{className:"wm-dot",children:"."},void 0,!1,void 0,this),_4("span",{className:"wm-secondary",children:D.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),_4("div",{className:"deck-carousel-body",children:_4("div",{className:"deck-carousel-content",dangerouslySetInnerHTML:{__html:X(H.markdown)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),_4("footer",{className:"deck-carousel-footer",children:[_4("span",{className:"deck-carousel-footer-meta",children:w??Q},void 0,!1,void 0,this),_4("span",{className:"deck-carousel-counter","aria-label":`Slide ${W+1} of ${f}`,children:[_4("span",{className:"deck-carousel-counter-current",children:String(W+1).padStart(2,"0")},void 0,!1,void 0,this)," / ",_4("span",{children:Y},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},W,!0,void 0,this))]},void 0,!0,void 0,this)}import{mkdtemp as SDB,rm as mDB}from"fs/promises";import{tmpdir as uDB}from"os";import{join as cDB}from"path";K0();var lDB=26214400,pDB=60000,Ii1=20;class hp0{context;renderPdf;getThemeMode;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK,this.getThemeMode=Q.getThemeMode??(async()=>"dark")}async resolve(A){if(A.sourceEntityType!=="deck")return;let Q=await this.context.entityService.getEntity({entityType:"deck",id:A.sourceEntityId});if(!Q)return;let B=iDB(Q,{brandLabel:this.resolveBrandLabel()});if(B.slides.length>Ii1)throw Error(`Refusing to render carousel with ${B.slides.length} slides; maxSlides=${Ii1}`);let w=await this.getThemeMode(),$=await SDB(cDB(uDB(),"brain-deck-carousel-"));try{let D=await MX({outputDir:$,mediaPath:`/_media/carousel/${Q.id}`,template:Fi1,format:"pdf",content:B,siteConfig:{title:B.title,themeMode:w},themeCSS:this.context.themeCSS}),f=await PX({rootDir:$});try{return{type:"document",data:await this.renderPdf(f.urlFor(D.urlPath),{maxBytes:lDB,timeoutMs:pDB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${dDB(Q)}-carousel.pdf`}}finally{await f.close()}}finally{await mDB($,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name;return Q.length>0?Q:void 0}}function iDB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=typeof B.title==="string"?B.title:A.metadata.title,D=typeof B.event==="string"&&B.event.length>0?B.event:void 0,f=w.split(/^---$/gm).map((Y)=>Y.trim()).filter((Y)=>Y.length>0).map((Y)=>({markdown:Y}));return{title:$,slides:f,...Q.brandLabel?{brandLabel:Q.brandLabel}:{},...D?{eyebrow:D}:{}}}function dDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}K0();import{jsxDEV as oDB}from"preact/jsx-dev-runtime";var x40="og-image",nDB="decks:og-image",Vi1=K.object({title:K.string().min(1),description:K.string().optional(),event:K.string().optional(),brandLabel:K.string().optional(),slideCount:K.number().int().positive().optional(),coverImageUrl:K.string().optional()}),Ji1={name:nDB,pluginId:"decks",schema:Vi1,renderers:{image:rDB}};function rDB(A){let Q=Vi1.parse(A),B=Q.slideCount?`${Q.slideCount} slide${Q.slideCount===1?"":"s"}`:void 0;return oDB(c3,{brandLabel:Q.brandLabel??Q.title,eyebrow:"Deck",title:Q.title,subtitle:Q.description,meta:[Q.event],tag:B},void 0,!1,void 0,this)}K0();class Cp0{context;deps;constructor(A,Q={}){this.context=A;this.deps=Q}async resolve(A){if(A.sourceEntityType!=="deck"||A.attachmentType!==x40)return;let Q=await this.context.entityService.getEntity({entityType:"deck",id:A.sourceEntityId});if(!Q)return;let{frontmatter:B,content:w}=lB(Q.content),$=wW.parse(B),D=sDB(w),f=this.resolveBrandLabel(),Y=await this.resolveCoverImageUrl($.coverImageId),X={title:$.title,...$.description?{description:$.description}:{},...$.event?{event:$.event}:{},...D?{slideCount:D}:{},...Y?{coverImageUrl:Y}:{},...f?{brandLabel:f}:{}};return{type:"image",data:await XP({mediaPath:`/_media/og/deck/${Q.id}`,template:Ji1,content:X,title:X.title,themeMode:"dark",themeCSS:this.context.themeCSS,tmpPrefix:"brain-deck-og-image-",...this.deps.screenshotPng&&{screenshotPng:this.deps.screenshotPng}}),mimeType:"image/png",filename:`${aDB(Q)}-og.png`}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){if(!A)return;let Q=await this.context.entityService.getEntity({entityType:"image",id:A});return Q?.content.startsWith("data:image/")?Q.content:void 0}}function sDB(A){return A.split(/^---$/gm).map((Q)=>Q.trim()).filter((Q)=>Q.length>0).length}function aDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}p0();async function Li1({entity:A,config:Q}){let B=ay.parse(A),w=h2(B.content,wW),$=w.metadata;return{$type:"ai.rizom.brain.deck",title:$.title,...$.slug&&{slug:$.slug},...$.description&&{description:$.description},body:w.content,format:"text/markdown",...$.author&&{author:$.author},...$.event&&{event:$.event},...$.publishedAt&&{publishedAt:$.publishedAt},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"deck",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function yp0(){return{entityType:"deck",collection:"ai.rizom.brain.deck",lexicon:_w["ai.rizom.brain.deck"],validate:!1,buildRecord:Li1}}var bi1={name:"@brains/decks",private:!0,version:"0.2.0-alpha.
|
|
6432
|
+
`}},void 0,!1,void 0,this),$.map((H,W)=>_4("section",{className:`deck-carousel-slide${W===0?" is-cover":""}`,children:[_4("header",{className:"deck-carousel-header",children:_4("span",{className:"deck-carousel-wordmark","aria-label":B??Q,children:[_4("span",{className:"wm-primary",children:D.primary},void 0,!1,void 0,this),D.secondary!==void 0&&_4(TDB,{children:[_4("span",{className:"wm-dot",children:"."},void 0,!1,void 0,this),_4("span",{className:"wm-secondary",children:D.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),_4("div",{className:"deck-carousel-body",children:_4("div",{className:"deck-carousel-content",dangerouslySetInnerHTML:{__html:X(H.markdown)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),_4("footer",{className:"deck-carousel-footer",children:[_4("span",{className:"deck-carousel-footer-meta",children:w??Q},void 0,!1,void 0,this),_4("span",{className:"deck-carousel-counter","aria-label":`Slide ${W+1} of ${f}`,children:[_4("span",{className:"deck-carousel-counter-current",children:String(W+1).padStart(2,"0")},void 0,!1,void 0,this)," / ",_4("span",{children:Y},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},W,!0,void 0,this))]},void 0,!0,void 0,this)}import{mkdtemp as SDB,rm as mDB}from"fs/promises";import{tmpdir as uDB}from"os";import{join as cDB}from"path";K0();var lDB=26214400,pDB=60000,Ii1=20;class hp0{context;renderPdf;getThemeMode;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK,this.getThemeMode=Q.getThemeMode??(async()=>"dark")}async resolve(A){if(A.sourceEntityType!=="deck")return;let Q=await this.context.entityService.getEntity({entityType:"deck",id:A.sourceEntityId});if(!Q)return;let B=iDB(Q,{brandLabel:this.resolveBrandLabel()});if(B.slides.length>Ii1)throw Error(`Refusing to render carousel with ${B.slides.length} slides; maxSlides=${Ii1}`);let w=await this.getThemeMode(),$=await SDB(cDB(uDB(),"brain-deck-carousel-"));try{let D=await MX({outputDir:$,mediaPath:`/_media/carousel/${Q.id}`,template:Fi1,format:"pdf",content:B,siteConfig:{title:B.title,themeMode:w},themeCSS:this.context.themeCSS}),f=await PX({rootDir:$});try{return{type:"document",data:await this.renderPdf(f.urlFor(D.urlPath),{maxBytes:lDB,timeoutMs:pDB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${dDB(Q)}-carousel.pdf`}}finally{await f.close()}}finally{await mDB($,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name;return Q.length>0?Q:void 0}}function iDB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=typeof B.title==="string"?B.title:A.metadata.title,D=typeof B.event==="string"&&B.event.length>0?B.event:void 0,f=w.split(/^---$/gm).map((Y)=>Y.trim()).filter((Y)=>Y.length>0).map((Y)=>({markdown:Y}));return{title:$,slides:f,...Q.brandLabel?{brandLabel:Q.brandLabel}:{},...D?{eyebrow:D}:{}}}function dDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}K0();import{jsxDEV as oDB}from"preact/jsx-dev-runtime";var x40="og-image",nDB="decks:og-image",Vi1=K.object({title:K.string().min(1),description:K.string().optional(),event:K.string().optional(),brandLabel:K.string().optional(),slideCount:K.number().int().positive().optional(),coverImageUrl:K.string().optional()}),Ji1={name:nDB,pluginId:"decks",schema:Vi1,renderers:{image:rDB}};function rDB(A){let Q=Vi1.parse(A),B=Q.slideCount?`${Q.slideCount} slide${Q.slideCount===1?"":"s"}`:void 0;return oDB(c3,{brandLabel:Q.brandLabel??Q.title,eyebrow:"Deck",title:Q.title,subtitle:Q.description,meta:[Q.event],tag:B},void 0,!1,void 0,this)}K0();class Cp0{context;deps;constructor(A,Q={}){this.context=A;this.deps=Q}async resolve(A){if(A.sourceEntityType!=="deck"||A.attachmentType!==x40)return;let Q=await this.context.entityService.getEntity({entityType:"deck",id:A.sourceEntityId});if(!Q)return;let{frontmatter:B,content:w}=lB(Q.content),$=wW.parse(B),D=sDB(w),f=this.resolveBrandLabel(),Y=await this.resolveCoverImageUrl($.coverImageId),X={title:$.title,...$.description?{description:$.description}:{},...$.event?{event:$.event}:{},...D?{slideCount:D}:{},...Y?{coverImageUrl:Y}:{},...f?{brandLabel:f}:{}};return{type:"image",data:await XP({mediaPath:`/_media/og/deck/${Q.id}`,template:Ji1,content:X,title:X.title,themeMode:"dark",themeCSS:this.context.themeCSS,tmpPrefix:"brain-deck-og-image-",...this.deps.screenshotPng&&{screenshotPng:this.deps.screenshotPng}}),mimeType:"image/png",filename:`${aDB(Q)}-og.png`}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){if(!A)return;let Q=await this.context.entityService.getEntity({entityType:"image",id:A});return Q?.content.startsWith("data:image/")?Q.content:void 0}}function sDB(A){return A.split(/^---$/gm).map((Q)=>Q.trim()).filter((Q)=>Q.length>0).length}function aDB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}p0();async function Li1({entity:A,config:Q}){let B=ay.parse(A),w=h2(B.content,wW),$=w.metadata;return{$type:"ai.rizom.brain.deck",title:$.title,...$.slug&&{slug:$.slug},...$.description&&{description:$.description},body:w.content,format:"text/markdown",...$.author&&{author:$.author},...$.event&&{event:$.event},...$.publishedAt&&{publishedAt:$.publishedAt},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"deck",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function yp0(){return{entityType:"deck",collection:"ai.rizom.brain.deck",lexicon:_w["ai.rizom.brain.deck"],validate:!1,buildRecord:Li1}}var bi1={name:"@brains/decks",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/image":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/site-info":"workspace:*","@brains/ui-library":"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 Ep0 extends PQ{deps;entityType=zr.entityType;schema=zr.schema;adapter=zr;unregisterCarouselAttachmentProvider;unregisterOgImageAttachmentProvider;unregisterAtprotoProjection;constructor(A={}){super("decks",bi1);this.deps=A}createGenerationHandler(A){return new vp0(this.logger.child("DeckGenerationJobHandler"),A)}getTemplates(){return{"deck-detail":_p0,"deck-list":xp0,generation:Ui1,description:Gi1}}getDataSources(){return[new Rp0(this.logger)]}getEntityTypeConfig(){return{weight:1.5}}async onRegister(A){this.deferPublishRegistration(A),this.subscribeToPublishExecute(A),this.registerCarouselAttachmentProvider(A),this.registerOgImageAttachmentProvider(A),this.registerEvalHandlers(A),this.unregisterAtprotoProjection=U5.getInstance().register(yp0()),this.logger.info("Decks plugin registered")}async onShutdown(){this.unregisterCarouselAttachmentProvider?.(),this.unregisterCarouselAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}deferPublishRegistration(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"publish:register",payload:{entityType:"deck",provider:{name:"internal",publish:async()=>({id:"internal"})},config:{executionMode:"provider"}}}),{success:!0}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(Q)=>{let{entityType:B,entityId:w}=Q.payload;if(B!=="deck")return{success:!0};try{let $=await A.entityService.getEntity({entityType:"deck",id:w});if(!$)return await A.messaging.send({type:"publish:report:failure",payload:{entityType:B,entityId:w,error:`Deck not found: ${w}`}}),{success:!0};if($.metadata.status==="published")return{success:!0};let D=new Date().toISOString(),f={...$,metadata:{...$.metadata,status:"published",publishedAt:D}};await A.entityService.updateEntity({entity:{...f,content:this.adapter.toMarkdown(f)}}),await A.messaging.send({type:"publish:report:success",payload:{entityType:B,entityId:w,result:{id:w}}})}catch($){await A.messaging.send({type:"publish:report:failure",payload:{entityType:B,entityId:w,error:hA($)}})}return{success:!0}})}registerCarouselAttachmentProvider(A){let Q={...this.deps,getThemeMode:this.deps.getThemeMode??(async()=>{try{return(await Yr(A.entityService)).themeMode??"dark"}catch{return"dark"}})};this.unregisterCarouselAttachmentProvider=A.attachments.register("deck",zi1,new hp0(A,Q))}registerOgImageAttachmentProvider(A){this.unregisterOgImageAttachmentProvider=A.attachments.register("deck",x40,new Cp0(A))}registerEvalHandlers(A){A.eval.registerHandler("generateDeck",async(Q)=>{let B=K.object({prompt:K.string(),event:K.string().optional()}).parse(Q);return A.ai.generate({prompt:`${B.prompt}${B.event?`
|
|
6433
6433
|
|
|
6434
6434
|
Note: This presentation is for "${B.event}".`:""}`,templateName:"decks:generation"})}),A.eval.registerHandler("generateDescription",async(Q)=>{let B=K.object({title:K.string(),content:K.string()}).parse(Q);return A.ai.generate({prompt:`Title: ${B.title}
|
|
6435
6435
|
|
|
6436
6436
|
Content:
|
|
6437
6437
|
${B.content}`,templateName:"decks:description"})})}}function Fr(){return new Ep0}p0();K0();K0();W8();var gp0=K.literal("application/pdf"),Ni1=K.enum(["pending","draft","failed"]),Tp0=K.object({title:K.string().optional(),mimeType:gp0,filename:K.string().min(1),pageCount:K.number().int().min(0).optional(),status:Ni1.optional(),processingJobId:K.string().optional(),processingError:K.string().optional(),sourceEntityType:K.string().min(1).optional(),sourceEntityId:K.string().min(1).optional(),sourceUploadId:K.string().optional(),sourceFilename:K.string().optional(),sourceMediaType:K.string().optional(),attachmentType:K.string().min(1).optional(),dedupKey:K.string().min(1).optional()}),ty=o1.extend({entityType:K.literal("document"),content:K.string().regex(/^data:application\/pdf;base64,.+$/),metadata:Tp0});function Ir(A){let Q=A.match(/^data:(application\/pdf);base64,(.+)$/i);if(!Q?.[1]||!Q[2])throw Error("Invalid PDF document data URL");return{mimeType:"application/pdf",base64:Q[2]}}function R40(A){return`data:application/pdf;base64,${Buffer.from(A).toString("base64")}`}function Sp0(A){let Q=Buffer.from(A).toString("latin1"),B=0,w=/\/Type\s*\/Pages\b[^]*?\/Count\s+(\d+)|\/Count\s+(\d+)[^]*?\/Type\s*\/Pages\b/g;for(let D of Q.matchAll(w)){let f=parseInt(D[1]??D[2]??"0",10);if(f>B)B=f}if(B>0)return B;return Q.match(/\/Type\s*\/Page(?!\w)/g)?.length??0}class v40{entityType="document";schema=ty;toMarkdown(A){return A.content}fromMarkdown(A){return Ir(A),{entityType:"document",content:A}}extractMetadata(A){return A.metadata}parseFrontMatter(A,Q){return Q.parse({})}generateFrontMatter(A){return""}getBodyTemplate(){return""}createDocumentEntity(A){let{dataUrl:Q,...B}=A,{mimeType:w}=Ir(Q);return{entityType:"document",content:Q,metadata:{mimeType:w,...B}}}}var XF=new v40;async function Ni0(A,Q={}){let B=Q.maxBytes??5000000;if(A.byteLength>B)throw Error(`Uploaded PDF is too large for synchronous markdown extraction (${A.byteLength} bytes; max ${B} bytes)`);let $=await(await Promise.resolve().then(() => (vn1(),Rn1))).getDocument({data:new Uint8Array(A),disableFontFace:!1,useSystemFonts:!0,useWorkerFetch:!1}).promise;try{let D=Q.maxPages??50;if($.numPages>D)throw Error(`Uploaded PDF has ${$.numPages} pages; maximum supported for synchronous markdown extraction is ${D}`);let f=[];for(let X=1;X<=$.numPages;X+=1){let Z=(await(await $.getPage(X)).getTextContent()).items.flatMap((G)=>("str"in G)?[G.str]:[]).join(" ").replace(/\s+/g," ").trim();if(Z.length>0)f.push(Z)}let Y=f.join(`
|
|
6438
6438
|
|
|
6439
|
-
`).trim();if(!Y)throw Error("Could not extract text from the uploaded PDF");return Y}finally{await $.destroy()}}p0();K0();import{createHash as yfB}from"crypto";var EfB=26214400,gfB=20,TfB=60000,hn1=80,SfB=10,VD0=K.object({renderUrl:K.string().url().optional(),sourceEntityType:K.string().min(1),sourceEntityId:K.string().min(1),attachmentType:K.string().min(1),documentId:K.string().min(1).optional(),title:K.string().min(1).optional(),filename:K.string().min(1).optional(),dedupKey:K.string().min(1).optional(),replace:K.boolean().optional(),pageCount:K.number().int().min(0).optional(),maxPageCount:K.number().int().positive().optional(),maxBytes:K.number().int().positive().optional(),timeoutMs:K.number().int().positive().optional(),width:K.union([K.string(),K.number()]).optional(),height:K.union([K.string(),K.number()]).optional(),format:K.string().optional(),targetEntityType:K.string().min(1).optional(),targetEntityId:K.string().min(1).optional()}),KE=VD0.refine((A)=>A.targetEntityType===void 0&&A.targetEntityId===void 0||A.targetEntityType!==void 0&&A.targetEntityId!==void 0,{message:"targetEntityType and targetEntityId must be provided together",path:["targetEntityId"]});class JD0 extends PB{context;renderPdf;constructor(A,Q,B={}){super(A,{schema:KE,jobTypeName:"document-generate"});this.context=Q;this.renderPdf=B.renderPdf??IK}async getDedupKey(A){if(A.dedupKey!==void 0)return A.dedupKey;if(A.renderUrl!==void 0)return`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:${A.renderUrl}`;let Q=`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:resolved-attachment`,B=await this.context.entityService.getEntity({entityType:A.sourceEntityType,id:A.sourceEntityId});return B?`${Q}:${B.contentHash}`:Q}async process(A,Q,B){this.logger.debug("Starting document generation job",{jobId:Q,sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType});let w=A.maxPageCount??gfB,$=A.maxBytes??EfB,D=A.timeoutMs??TfB;if(A.pageCount!==void 0&&A.pageCount>w)throw Error(`Refusing to render ${A.pageCount} page PDF; maxPageCount=${w}`);let f=await this.getDedupKey(A),Y=pr(A,f),X=A.documentId!==void 0||A.filename!==void 0;if(A.replace!==!0){let H=await this.findDocumentByDedupKey(f,X?Y:void 0);if(H&&(!X||H.id===Y)){if(A.targetEntityType&&A.targetEntityId)await this.attachDocumentToTarget(A.targetEntityType,A.targetEntityId,H.id,A);return await this.reportProgress(B,{progress:100,message:"Reusing existing generated document"}),{success:!0,documentId:H.id,reused:!0}}}await this.reportProgress(B,{progress:20,message:"Rendering PDF document"});try{let H=await this.resolveDocumentAttachment(A,Y,{timeoutMs:D,maxBytes:$}),W=H.data;if(W.byteLength>$)throw Error(`Rendered PDF exceeds maxBytes=${$}: ${W.byteLength} bytes`);let Z=Sp0(W);if(Z>w)throw Error(`Rendered PDF has ${Z} pages, exceeding maxPageCount=${w}`);let G=Z>0?Z:A.pageCount;await this.reportProgress(B,{progress:70,message:"Storing PDF document"});let F=A.filename??(A.renderUrl===void 0?H.filename:`${Y}.pdf`),I=XF.createDocumentEntity({dataUrl:R40(W),filename:F,...A.title&&{title:A.title},...G!==void 0&&{pageCount:G},status:"draft",sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType,dedupKey:f});if(await jY({entityService:this.context.entityService,entity:{...I,id:Y}}),A.targetEntityType&&A.targetEntityId)await this.attachDocumentToTarget(A.targetEntityType,A.targetEntityId,Y,A);return await this.reportProgress(B,{progress:100,message:"PDF document generation complete"}),{success:!0,documentId:Y,reused:!1}}catch(H){let W=hA(H);throw this.logger.error("Document generation failed",{jobId:Q,error:W}),await UU({entityService:this.context.entityService,entityType:"document",id:Y,error:W}),H}}async resolveDocumentAttachment(A,Q,B){if(A.renderUrl!==void 0)return{type:"document",data:await this.renderPdf(A.renderUrl,{timeoutMs:B.timeoutMs,maxBytes:B.maxBytes,printBackground:!0,preferCSSPageSize:!0,...A.width!==void 0&&{width:A.width},...A.height!==void 0&&{height:A.height},...A.format!==void 0&&{format:A.format}}),mimeType:"application/pdf",filename:A.filename??`${Q}.pdf`};let w=await this.context.attachments.resolve({sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType});if(!w)throw Error(`No attachment provider found for ${A.sourceEntityType}/${A.attachmentType}`);if(w.type!=="document")throw Error(`Attachment provider returned ${w.type}; expected document`);return w}async findDocumentByDedupKey(A,Q){let B=await this.context.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:A}}}});if(B.length>1)this.logger.warn("Multiple documents share dedupKey; using first",{dedupKey:A,count:B.length,ids:B.map(($)=>$.id),preferredDocumentId:Q});let w=B.filter(($)=>$.metadata.status!=="pending"&&$.metadata.status!=="failed");return w.find(($)=>$.id===Q)??w[0]}async attachDocumentToTarget(A,Q,B,w){let $=await this.context.entityService.getEntity({entityType:A,id:Q});if(!$)throw Error(`Target entity not found: ${A}/${Q}`);let{frontmatter:D}=lB($.content),f=Array.isArray(D.documents)?D.documents.filter(ufB):[],Y=w.replace?await this.removeReferencesForSameSourceAttachment(f,B,w):f,X=Y.some((H)=>H.id===B)?Y:[...Y,{id:B}];await this.context.entityService.updateEntity({entity:{...$,content:n4($.content,"documents",X)}})}async removeReferencesForSameSourceAttachment(A,Q,B){let w=[];for(let $ of A){if($.id===Q){w.push($);continue}let D=await this.context.entityService.getEntity({entityType:"document",id:$.id});if(!D||!cfB(D,B))w.push($)}return w}}function pr(A,Q){let B=`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:${A.renderUrl??"resolved-attachment"}`,w=A.documentId??A.filename?.replace(/\.pdf$/i,"")??Q??B,$=A.replace===!0&&A.documentId===void 0?`${w}-${Date.now()}`:w;return mfB($)}function mfB(A){let Q=Y1(A.replace(/[/:]+/g," "))||`document-${Cn1(A)}`;if(Q.length<=hn1)return Q;let B=`-${Cn1(A)}`;return`${Q.slice(0,hn1-B.length).replace(/-+$/g,"")}${B}`}function Cn1(A){return yfB("sha256").update(A).digest("hex").slice(0,SfB)}function ufB(A){return typeof A==="object"&&A!==null&&"id"in A&&typeof A.id==="string"&&A.id.length>0}function cfB(A,Q){return A.metadata.sourceEntityType===Q.sourceEntityType&&A.metadata.sourceEntityId===Q.sourceEntityId&&A.metadata.attachmentType===Q.attachmentType}p0();function ji0(A,Q){return[BB(A,"generate",'Preview or prepare a PDF document attachment from a source attachment or render URL. For save/regenerate durable document requests, including deck carousel PDFs and printable post/project/product PDFs, prefer system_create with entityType: "document" and source: { kind: "attachment", sourceEntityType, sourceEntityId, attachmentType }.',VD0,async(B,w)=>{let $=KE.safeParse(B);if(!$.success)return u$($.error.message);let D=pr($.data),f=await Q({...$.data,documentId:D},w),Y=$.data.filename??`${D}.pdf`;return b8({jobId:f,documentId:D,attachment:{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${encodeURIComponent(D)}`,downloadUrl:`/api/chat/attachments/document?id=${encodeURIComponent(D)}&download=1`,filename:Y,source:{entityType:"document",entityId:D,attachmentType:$.data.attachmentType}}})},{cli:{name:"document-generate"}})]}var yn1={name:"@brains/document-plugin",private:!0,version:"0.2.0-alpha.
|
|
6439
|
+
`).trim();if(!Y)throw Error("Could not extract text from the uploaded PDF");return Y}finally{await $.destroy()}}p0();K0();import{createHash as yfB}from"crypto";var EfB=26214400,gfB=20,TfB=60000,hn1=80,SfB=10,VD0=K.object({renderUrl:K.string().url().optional(),sourceEntityType:K.string().min(1),sourceEntityId:K.string().min(1),attachmentType:K.string().min(1),documentId:K.string().min(1).optional(),title:K.string().min(1).optional(),filename:K.string().min(1).optional(),dedupKey:K.string().min(1).optional(),replace:K.boolean().optional(),pageCount:K.number().int().min(0).optional(),maxPageCount:K.number().int().positive().optional(),maxBytes:K.number().int().positive().optional(),timeoutMs:K.number().int().positive().optional(),width:K.union([K.string(),K.number()]).optional(),height:K.union([K.string(),K.number()]).optional(),format:K.string().optional(),targetEntityType:K.string().min(1).optional(),targetEntityId:K.string().min(1).optional()}),KE=VD0.refine((A)=>A.targetEntityType===void 0&&A.targetEntityId===void 0||A.targetEntityType!==void 0&&A.targetEntityId!==void 0,{message:"targetEntityType and targetEntityId must be provided together",path:["targetEntityId"]});class JD0 extends PB{context;renderPdf;constructor(A,Q,B={}){super(A,{schema:KE,jobTypeName:"document-generate"});this.context=Q;this.renderPdf=B.renderPdf??IK}async getDedupKey(A){if(A.dedupKey!==void 0)return A.dedupKey;if(A.renderUrl!==void 0)return`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:${A.renderUrl}`;let Q=`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:resolved-attachment`,B=await this.context.entityService.getEntity({entityType:A.sourceEntityType,id:A.sourceEntityId});return B?`${Q}:${B.contentHash}`:Q}async process(A,Q,B){this.logger.debug("Starting document generation job",{jobId:Q,sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType});let w=A.maxPageCount??gfB,$=A.maxBytes??EfB,D=A.timeoutMs??TfB;if(A.pageCount!==void 0&&A.pageCount>w)throw Error(`Refusing to render ${A.pageCount} page PDF; maxPageCount=${w}`);let f=await this.getDedupKey(A),Y=pr(A,f),X=A.documentId!==void 0||A.filename!==void 0;if(A.replace!==!0){let H=await this.findDocumentByDedupKey(f,X?Y:void 0);if(H&&(!X||H.id===Y)){if(A.targetEntityType&&A.targetEntityId)await this.attachDocumentToTarget(A.targetEntityType,A.targetEntityId,H.id,A);return await this.reportProgress(B,{progress:100,message:"Reusing existing generated document"}),{success:!0,documentId:H.id,reused:!0}}}await this.reportProgress(B,{progress:20,message:"Rendering PDF document"});try{let H=await this.resolveDocumentAttachment(A,Y,{timeoutMs:D,maxBytes:$}),W=H.data;if(W.byteLength>$)throw Error(`Rendered PDF exceeds maxBytes=${$}: ${W.byteLength} bytes`);let Z=Sp0(W);if(Z>w)throw Error(`Rendered PDF has ${Z} pages, exceeding maxPageCount=${w}`);let G=Z>0?Z:A.pageCount;await this.reportProgress(B,{progress:70,message:"Storing PDF document"});let F=A.filename??(A.renderUrl===void 0?H.filename:`${Y}.pdf`),I=XF.createDocumentEntity({dataUrl:R40(W),filename:F,...A.title&&{title:A.title},...G!==void 0&&{pageCount:G},status:"draft",sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType,dedupKey:f});if(await jY({entityService:this.context.entityService,entity:{...I,id:Y}}),A.targetEntityType&&A.targetEntityId)await this.attachDocumentToTarget(A.targetEntityType,A.targetEntityId,Y,A);return await this.reportProgress(B,{progress:100,message:"PDF document generation complete"}),{success:!0,documentId:Y,reused:!1}}catch(H){let W=hA(H);throw this.logger.error("Document generation failed",{jobId:Q,error:W}),await UU({entityService:this.context.entityService,entityType:"document",id:Y,error:W}),H}}async resolveDocumentAttachment(A,Q,B){if(A.renderUrl!==void 0)return{type:"document",data:await this.renderPdf(A.renderUrl,{timeoutMs:B.timeoutMs,maxBytes:B.maxBytes,printBackground:!0,preferCSSPageSize:!0,...A.width!==void 0&&{width:A.width},...A.height!==void 0&&{height:A.height},...A.format!==void 0&&{format:A.format}}),mimeType:"application/pdf",filename:A.filename??`${Q}.pdf`};let w=await this.context.attachments.resolve({sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:A.attachmentType});if(!w)throw Error(`No attachment provider found for ${A.sourceEntityType}/${A.attachmentType}`);if(w.type!=="document")throw Error(`Attachment provider returned ${w.type}; expected document`);return w}async findDocumentByDedupKey(A,Q){let B=await this.context.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:A}}}});if(B.length>1)this.logger.warn("Multiple documents share dedupKey; using first",{dedupKey:A,count:B.length,ids:B.map(($)=>$.id),preferredDocumentId:Q});let w=B.filter(($)=>$.metadata.status!=="pending"&&$.metadata.status!=="failed");return w.find(($)=>$.id===Q)??w[0]}async attachDocumentToTarget(A,Q,B,w){let $=await this.context.entityService.getEntity({entityType:A,id:Q});if(!$)throw Error(`Target entity not found: ${A}/${Q}`);let{frontmatter:D}=lB($.content),f=Array.isArray(D.documents)?D.documents.filter(ufB):[],Y=w.replace?await this.removeReferencesForSameSourceAttachment(f,B,w):f,X=Y.some((H)=>H.id===B)?Y:[...Y,{id:B}];await this.context.entityService.updateEntity({entity:{...$,content:n4($.content,"documents",X)}})}async removeReferencesForSameSourceAttachment(A,Q,B){let w=[];for(let $ of A){if($.id===Q){w.push($);continue}let D=await this.context.entityService.getEntity({entityType:"document",id:$.id});if(!D||!cfB(D,B))w.push($)}return w}}function pr(A,Q){let B=`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:${A.renderUrl??"resolved-attachment"}`,w=A.documentId??A.filename?.replace(/\.pdf$/i,"")??Q??B,$=A.replace===!0&&A.documentId===void 0?`${w}-${Date.now()}`:w;return mfB($)}function mfB(A){let Q=Y1(A.replace(/[/:]+/g," "))||`document-${Cn1(A)}`;if(Q.length<=hn1)return Q;let B=`-${Cn1(A)}`;return`${Q.slice(0,hn1-B.length).replace(/-+$/g,"")}${B}`}function Cn1(A){return yfB("sha256").update(A).digest("hex").slice(0,SfB)}function ufB(A){return typeof A==="object"&&A!==null&&"id"in A&&typeof A.id==="string"&&A.id.length>0}function cfB(A,Q){return A.metadata.sourceEntityType===Q.sourceEntityType&&A.metadata.sourceEntityId===Q.sourceEntityId&&A.metadata.attachmentType===Q.attachmentType}p0();function ji0(A,Q){return[BB(A,"generate",'Preview or prepare a PDF document attachment from a source attachment or render URL. For save/regenerate durable document requests, including deck carousel PDFs and printable post/project/product PDFs, prefer system_create with entityType: "document" and source: { kind: "attachment", sourceEntityType, sourceEntityId, attachmentType }.',VD0,async(B,w)=>{let $=KE.safeParse(B);if(!$.success)return u$($.error.message);let D=pr($.data),f=await Q({...$.data,documentId:D},w),Y=$.data.filename??`${D}.pdf`;return b8({jobId:f,documentId:D,attachment:{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${encodeURIComponent(D)}`,downloadUrl:`/api/chat/attachments/document?id=${encodeURIComponent(D)}&download=1`,filename:Y,source:{entityType:"document",entityId:D,attachmentType:$.data.attachmentType}}})},{cli:{name:"document-generate"}})]}var yn1={name:"@brains/document-plugin",private:!0,version:"0.2.0-alpha.129",description:"Document entity type for generated PDFs and publishable document attachments",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/contracts":"workspace:*","@brains/document":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/typescript-config":"workspace:*","bun-types":"latest",typescript:"^5.3.3"}};var pfB=`data:application/pdf;base64,${Buffer.from(`%PDF-1.4
|
|
6440
6440
|
% Pending document placeholder
|
|
6441
6441
|
%%EOF
|
|
6442
6442
|
`).toString("base64")}`,ifB=K.object({}),_i0={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};function dfB(A,Q){let B=A.title?.trim();if(B)return B;return Q.replace(/\.[^.]+$/,"").trim()||Q}function nfB(A,Q){return`data:${A};base64,${Q.toString("base64")}`}function rfB(A){let Q=encodeURIComponent(A.entityId);return{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${Q}`,downloadUrl:`/api/chat/attachments/document?id=${Q}&download=1`,filename:A.filename,source:{entityType:"document",entityId:A.entityId,attachmentType:"uploaded"}}}class Mi0 extends pQ{entityType=XF.entityType;schema=ty;adapter=XF;pluginContext;constructor(){super("document",yn1,{},ifB)}async onRegister(A){this.pluginContext=A,A.entities.register(this.entityType,this.schema,this.adapter,{embeddable:!1}),A.entities.registerCreateInterceptor(this.entityType,(Q)=>this.interceptCreate(Q)),A.entities.registerUploadSaveHandler({entityType:this.entityType,mediaTypes:["application/pdf"],handler:async(Q)=>{let B=await this.promoteUpload({entityType:this.entityType,...Q.title!==void 0?{title:Q.title}:{},from:Q.upload},A);return B.kind==="handled"?B.result:{success:!1,error:"Document upload save was not handled"}}}),A.jobs.registerHandler("generate",new JD0(this.logger.child("DocumentGenerationJobHandler"),A))}async interceptCreate(A){let Q=this.pluginContext;if(A.from?.kind===_i0.refKind){if(!Q)return{kind:"handled",result:{success:!1,error:"Plugin context not initialized"}};return this.promoteUpload(A,Q)}if(!A.from||A.from.kind!=="entity-attachment")return{kind:"continue",input:A};if(!Q)return{kind:"handled",result:{success:!1,error:"Plugin context not initialized"}};let B=KE.parse({sourceEntityType:A.from.sourceEntityType,sourceEntityId:A.from.sourceEntityId,attachmentType:A.from.attachmentType,...A.title&&{title:A.title},...A.replace===!0&&{replace:!0},...A.targetEntityType&&{targetEntityType:A.targetEntityType},...A.targetEntityId&&{targetEntityId:A.targetEntityId}}),w=await this.getDedupKey(B,Q),$=B.replace===!0?void 0:await this.findExistingDocument(w,Q),D=$?.id??pr(B,w);if(!$)await this.createPendingDocument(Q,{id:D,title:B.title??D,filename:`${D}.pdf`,sourceEntityType:B.sourceEntityType,sourceEntityId:B.sourceEntityId,attachmentType:B.attachmentType,dedupKey:w});let f=await Q.jobs.enqueue({type:"generate",data:{...B,dedupKey:w,documentId:D}}),Y=`${D}.pdf`;return{kind:"handled",result:{success:!0,data:{entityId:D,jobId:f,status:"generating",attachment:{mediaType:"application/pdf",url:`/api/chat/attachments/document?id=${encodeURIComponent(D)}`,downloadUrl:`/api/chat/attachments/document?id=${encodeURIComponent(D)}&download=1`,filename:Y,source:{entityType:"document",entityId:D,attachmentType:B.attachmentType}}}}}}async promoteUpload(A,Q){let B=A.from;if(B?.kind!==_i0.refKind)return{kind:"handled",result:{success:!1,error:"Unsupported upload ref kind"}};let w;try{w=await Q.uploads.scoped(_i0).read(B.id)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}if(w.record.mediaType!=="application/pdf")return{kind:"handled",result:{success:!1,error:"Only PDF uploads can be promoted to document entities"}};let $=dfB(A,w.record.filename),D=Y1($);if(!D)return{kind:"handled",result:{success:!1,error:"Could not derive a document id from the uploaded filename. Provide a title."}};let f=new Date().toISOString(),Y=XF.createDocumentEntity({dataUrl:nfB(w.record.mediaType,w.content),filename:w.record.filename,title:$,status:"draft",sourceUploadId:B.id,sourceFilename:w.record.filename,sourceMediaType:w.record.mediaType,attachmentType:"uploaded",dedupKey:`upload:${B.kind}:${B.id}`}),X=await Q.entityService.createEntity({entity:{id:D,...Y,created:f,updated:f},options:{deduplicateId:!0}});return{kind:"handled",result:{success:!0,data:{entityId:X.entityId,status:"created",attachment:rfB({entityId:X.entityId,filename:w.record.filename})}}}}async createPendingDocument(A,Q){let B=new Date().toISOString(),w=XF.createDocumentEntity({dataUrl:pfB,filename:Q.filename,title:Q.title,status:"pending",sourceEntityType:Q.sourceEntityType,sourceEntityId:Q.sourceEntityId,attachmentType:Q.attachmentType,dedupKey:Q.dedupKey});await qN({entityService:A.entityService,entity:{id:Q.id,...w,created:B,updated:B}})}async getDedupKey(A,Q){if(A.dedupKey!==void 0)return A.dedupKey;if(A.renderUrl!==void 0)return`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:${A.renderUrl}`;let B=`${A.attachmentType}:${A.sourceEntityType}:${A.sourceEntityId}:resolved-attachment`,w=await Q.entityService.getEntity({entityType:A.sourceEntityType,id:A.sourceEntityId});return w?`${B}:${w.contentHash}`:B}async findExistingDocument(A,Q){return(await Q.entityService.listEntities({entityType:"document",options:{filter:{metadata:{dedupKey:A}}}}))[0]}async getInstructions(){return'For durable raw PDF saves/promotions from uploaded PDFs, call system_upload_save with the exact upload object shown in the current turn or conversation "Available upload refs" hint. Do this only after the user explicitly asks to save/import/promote the raw PDF as a document. If that hint is absent, omit upload entirely; never invent upload IDs or placeholder upload refs. Uploaded PDFs are not decks; raw upload promotion preserves the PDF as a document. Do not use entityType: "note" with source kind "upload" and transform "extract-markdown" unless the user asks to turn the upload into a note/markdown. For generated/source-derived PDFs, call system_create with entityType: "document" and source: { kind: "attachment", sourceEntityType, sourceEntityId, attachmentType }. Deck carousel PDFs use attachmentType: "carousel" with sourceEntityType: "deck". Printable PDFs for blog posts, projects, and products use attachmentType: "printable" and sourceEntityType "post", "project", or "product". Omit upload and attachment sources entirely for ordinary direct document creates that use text, generate, or url sources. Include targetEntityType/targetEntityId when the user asks to attach the saved document to another entity. Use replace: true when they ask to regenerate or replace a saved PDF. Only use document_generate for explicit preview/prepare requests where they need an immediate PDF attachment. Do not use generic attachment types like "document".'}async getTools(){let A=this.pluginContext;if(!A)throw Error("Plugin context not initialized");return ji0(this.id,(Q,B)=>A.jobs.enqueue({type:"generate",data:Q,toolContext:B}))}}function Pi0(){return new Mi0}p0();K0();K0();p0();var ofB=K.enum(["generating","failed"]),UF=K.object({title:K.string().optional(),status:ofB.optional(),error:K.string().optional()}),En1=UF.pick({title:!0,status:!0,error:!0}).extend({title:K.string()}),_L=o1.extend({entityType:K.literal("note"),metadata:En1}),sfB=_L.extend({frontmatter:UF,body:K.string()});p0();K0();class ki0 extends V2{constructor(){super({entityType:"note",schema:_L,frontmatterSchema:UF})}toMarkdown(A){let Q=this.extractBody(A.content);try{let B=this.parseFrontMatter(A.content,UF);if(B.title)return this.buildMarkdown(Q,B)}catch{}return Q}fromMarkdown(A){let Q=this.parseMarkdownFrontmatter(A),B=Q.title??this.extractH1(A)??"Untitled";return{content:A,entityType:"note",metadata:{title:B,...Q.status&&{status:Q.status},...Q.error&&{error:Q.error}}}}parseNoteFrontmatter(A){return this.parseMarkdownFrontmatter(A.content)}parseMarkdownFrontmatter(A){try{return this.parseFrontMatter(A,UF)}catch{return{}}}buildStub(A){let Q={title:A.title,status:"generating"};return{content:this.buildMarkdown("",Q),metadata:{title:A.title,status:"generating"}}}createNoteContent(A,Q){try{let B=this.parseFrontMatter(Q,K.record(K.unknown()));if(Object.keys(B).length===0)return Q;let w={...B,title:B.title??A},$=this.extractBody(Q);return this.buildMarkdown($,w)}catch{return Q}}extractH1(A){return A.match(/^#\s+(.+)$/m)?.[1]?.trim()??null}}var ML=new ki0;K0();var Oi0=K.object({defaultPrompt:K.string().default("Create a note summarizing key concepts from my knowledge base")});K0();p0();var gn1=K.object({title:K.string().max(80).describe("A clear, descriptive title for the note (3-8 words)"),body:K.string().describe("Note content in markdown format with clear organization and structure")}),xi0=R1({name:"note:generation",description:"Template for AI to generate notes from prompts",schema:gn1,dataSourceId:"shell:ai-content",requiredPermission:"public",useKnowledgeContext:!0,basePrompt:`You are helping to create personal knowledge notes for research and reference.
|
|
@@ -6454,7 +6454,7 @@ title: ${JSON.stringify(A)}
|
|
|
6454
6454
|
---
|
|
6455
6455
|
|
|
6456
6456
|
${Q.trim()}
|
|
6457
|
-
`}var QYB={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"},BYB=K.object({uploadId:K.string().min(1),title:K.string().optional()});class vi0 extends PB{context;constructor(A,Q){super(A,{schema:BYB,jobTypeName:"upload-import"});this.context=Q}async process(A,Q,B){await this.reportProgress(B,{progress:10,message:"Reading uploaded file"});let w=await this.context.uploads.scoped(QYB).read(A.uploadId);await this.reportProgress(B,{progress:35,message:"Extracting markdown from upload"});let $=await un1({upload:w,...A.title!==void 0?{title:A.title}:{}});await this.reportProgress(B,{progress:80,message:"Saving imported note"});let D=new Date().toISOString(),f=ML.fromMarkdown($.content),Y=await this.context.entityService.createEntity({entity:{id:$.id,entityType:"note",content:$.content,metadata:{title:$.title,...f.metadata},created:D,updated:D},options:{deduplicateId:!0}});return await this.reportProgress(B,{progress:100,message:"Upload imported as markdown note"}),{entityId:Y.entityId,status:"created"}}summarizeDataForLog(A){return{uploadId:A.uploadId,hasTitle:A.title!==void 0}}}p0();async function cn1({entity:A,config:Q}){let B=_L.parse(A),w=h2(B.content,UF);return{$type:"ai.rizom.brain.note",title:B.metadata.title,body:w.content,format:"text/markdown",...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"note",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function hi0(){return{entityType:"note",collection:"ai.rizom.brain.note",lexicon:_w["ai.rizom.brain.note"],validate:!1,buildRecord:cn1}}var ln1={name:"@brains/note",private:!0,version:"0.2.0-alpha.
|
|
6457
|
+
`}var QYB={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"},BYB=K.object({uploadId:K.string().min(1),title:K.string().optional()});class vi0 extends PB{context;constructor(A,Q){super(A,{schema:BYB,jobTypeName:"upload-import"});this.context=Q}async process(A,Q,B){await this.reportProgress(B,{progress:10,message:"Reading uploaded file"});let w=await this.context.uploads.scoped(QYB).read(A.uploadId);await this.reportProgress(B,{progress:35,message:"Extracting markdown from upload"});let $=await un1({upload:w,...A.title!==void 0?{title:A.title}:{}});await this.reportProgress(B,{progress:80,message:"Saving imported note"});let D=new Date().toISOString(),f=ML.fromMarkdown($.content),Y=await this.context.entityService.createEntity({entity:{id:$.id,entityType:"note",content:$.content,metadata:{title:$.title,...f.metadata},created:D,updated:D},options:{deduplicateId:!0}});return await this.reportProgress(B,{progress:100,message:"Upload imported as markdown note"}),{entityId:Y.entityId,status:"created"}}summarizeDataForLog(A){return{uploadId:A.uploadId,hasTitle:A.title!==void 0}}}p0();async function cn1({entity:A,config:Q}){let B=_L.parse(A),w=h2(B.content,UF);return{$type:"ai.rizom.brain.note",title:B.metadata.title,body:w.content,format:"text/markdown",...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"note",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function hi0(){return{entityType:"note",collection:"ai.rizom.brain.note",lexicon:_w["ai.rizom.brain.note"],validate:!1,buildRecord:cn1}}var ln1={name:"@brains/note",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@brains/document":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var pn1={namespace:"upload",refKind:"upload",routePath:"/api/chat/uploads"};class Ci0 extends PQ{entityType=ML.entityType;schema=_L;adapter=ML;unregisterAtprotoProjection;constructor(A={}){super("note",ln1,A,Oi0)}async interceptCreate(A,Q,B){if(A.from?.kind!==pn1.refKind)return{kind:"continue",input:A};if(A.transform!=="extract-markdown")return{kind:"handled",result:{success:!1,error:'Importing an upload as a note requires transform: "extract-markdown"'}};let w=A.from.id,$;try{$=await B.uploads.scoped(pn1).readRecord(w)}catch{return{kind:"handled",result:{success:!1,error:"Upload ref not found"}}}try{if(!mn1($.mediaType))return{kind:"handled",result:{success:!1,error:"Only text, JSON, and PDF uploads can be imported as markdown notes"}};let D=Ri0({filename:$.filename,...A.title!==void 0?{title:A.title}:{}}),f=await B.jobs.enqueue({type:"upload-import",data:{uploadId:w,...A.title!==void 0?{title:A.title}:{}}});return{kind:"handled",result:{success:!0,data:{entityId:D.id,status:"generating",jobId:f}}}}catch(D){return{kind:"handled",result:{success:!1,error:D instanceof Error?D.message:"Failed to import upload as markdown"}}}}createGenerationHandler(A){return new LD0(this.logger.child("NoteGenerationJobHandler"),A)}getTemplates(){return{generation:xi0}}async onRegister(A){A.jobs.registerHandler("upload-import",new vi0(this.logger.child("UploadMarkdownImportJobHandler"),A)),A.eval.registerHandler("generateNote",async(Q)=>{let B=K.object({prompt:K.string()}).parse(Q);return A.ai.generate({prompt:B.prompt,templateName:"note:generation"})}),this.unregisterAtprotoProjection=U5.getInstance().register(hi0())}async getInstructions(){return'To turn an uploaded text or PDF file into an editable markdown note, call system_create with entityType: "note" and source: { kind: "upload", upload: <exact upload object from the current turn or conversation upload refs hint>, transform: "extract-markdown" }. Use this only when the user explicitly asks to import, extract, or turn the upload into a note/markdown. Do not use this note-import pattern for raw file saves/promotions such as saving a PDF as a document or saving an image as an image; those use system_upload_save with the raw upload ref. Use source: { kind: "text", content } for ordinary direct note creates.'}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function FP(A={}){return new Ci0(A)}p0();K0();K0();p0();var in1=K.object({ref:K.string(),label:K.string()}),dn1=K.enum(["pending","draft","published"]),GF=K.object({status:dn1,title:K.string(),url:K.string().url(),description:K.string().optional(),domain:K.string(),capturedAt:K.string().datetime(),source:in1}),nn1=GF.pick({title:!0,status:!0}),IP=o1.extend({entityType:K.literal("link"),metadata:nn1}),yi0=K.object({enableSummarization:K.boolean().default(!0).describe("Generate AI summaries for captured links"),jinaApiKey:K.string().optional().describe("Jina Reader API key for higher rate limits (500 RPM vs 20 RPM without key)")});p0();class PL extends V2{constructor(){super({entityType:"link",schema:IP,frontmatterSchema:GF})}createLinkContent(A){let Q={status:A.status,title:A.title,url:A.url,description:A.description,domain:A.domain,capturedAt:A.capturedAt,source:A.source},B=A.summary??"";return this.buildMarkdown(B,Q)}parseLinkContent(A){return{frontmatter:this.parseFrontMatter(A,GF),summary:this.extractBody(A).trim()}}fromMarkdown(A){let{frontmatter:Q}=this.parseLinkContent(A);return{content:A,entityType:"link",metadata:{title:Q.title,status:Q.status}}}}var UE=new PL;p0();K0();var $YB=K.object({success:K.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:K.string().describe("If success is false, explain why content could not be extracted. Use an empty string when success is true."),title:K.string().max(80).describe("The page title - extract from the content or create a descriptive one. Leave empty string if success is false."),description:K.string().describe("A one-sentence description of what the page is about. Leave empty string if success is false."),summary:K.string().describe("A 1-2 paragraph summary of the main content. Leave empty string if success is false.")}),rn1=R1({name:"link:extraction",description:"Extract structured content from webpage markdown",dataSourceId:"shell:ai-content",schema:$YB,basePrompt:`You are an expert at extracting key information from webpage content.
|
|
6458
6458
|
|
|
6459
6459
|
You will receive webpage content in markdown format. Your job is to extract structured information from it.
|
|
6460
6460
|
|
|
@@ -6476,7 +6476,7 @@ Accuracy rules:
|
|
|
6476
6476
|
|
|
6477
6477
|
`))return{success:!1,error:f.trim(),errorType:"fetch_failed"};return{success:!0,content:f}}catch(B){return this.handleFetchError(B,A)}}handleHttpError(A,Q){if(A===400)return{success:!1,error:`Invalid or non-existent URL: ${Q}`,errorType:"url_not_found"};if(A===404)return{success:!1,error:`Page not found: ${Q}`,errorType:"url_not_found"};if(A>=500)return{success:!1,error:`Server error while fetching ${Q}`,errorType:"url_unreachable"};return{success:!1,error:`HTTP ${A} error while fetching ${Q}`,errorType:"fetch_failed"}}handleFetchError(A,Q){if(A instanceof Error){if(A.name==="AbortError")return{success:!1,error:`Request timeout while fetching ${Q}`,errorType:"url_unreachable"};if(A.message.includes("ENOTFOUND")||A.message.includes("getaddrinfo"))return{success:!1,error:`Domain not found: ${new URL(Q).hostname}`,errorType:"url_not_found"};if(A.message.includes("ECONNREFUSED")||A.message.includes("ETIMEDOUT"))return{success:!1,error:`Could not connect to ${Q}`,errorType:"url_unreachable"};return{success:!1,error:`Failed to fetch ${Q}: ${A.message}`,errorType:"fetch_failed"}}return{success:!1,error:`Unknown error fetching ${Q}`,errorType:"fetch_failed"}}}import{createHash as XYB}from"crypto";class kL{static URL_PATTERN=/https?:\/\/[^\s<>"{}|\\^`[\]]+?(?=[,;:\s]|$)/gi;static extractUrls(A){let Q=A.match(kL.URL_PATTERN)??[];return[...new Set(Q)]}static normalizeUrl(A){try{let Q=new URL(A),B=Q.pathname.replace(/\/$/,"")||"/";return`${Q.protocol}//${Q.host}${B}`}catch{return A}}static generateEntityId(A){let Q=this.normalizeUrl(A),B=XYB("sha256").update(Q).digest("hex");try{return`${new URL(Q).hostname.replace(/\./g,"-")}-${B.substring(0,6)}`}catch{return B.substring(0,12)}}static isValidUrl(A){try{let Q=new URL(A);return["http:","https:"].includes(Q.protocol)}catch{return!1}}}p0();K0();Cw();var HYB=K.object({url:K.string().url(),metadata:K.object({interfaceId:K.string().optional(),userId:K.string().optional(),channelId:K.string().optional(),channelName:K.string().optional(),timestamp:K.string().optional()}).optional()}),kd8=K.object({success:K.boolean(),entityId:K.string().optional(),title:K.string().optional(),url:K.string().optional(),status:K.enum(["pending","draft","published"]).optional(),error:K.string().optional()});class ND0 extends PB{context;linkAdapter;urlFetcher;constructor(A,Q,B){super(A,{schema:HYB,jobTypeName:"link-capture"});this.context=Q,this.linkAdapter=new PL,this.urlFetcher=new GE(B?.jinaApiKey?{jinaApiKey:B.jinaApiKey}:void 0)}async process(A,Q,B){let{url:w,metadata:$}=A;try{await B.report({progress:MQ.START,total:100,message:"Starting link capture"});let D=kL.generateEntityId(w);await B.report({progress:MQ.INIT,total:100,message:"Checking for existing link"});let f=await this.context.entityService.getEntity({entityType:"link",id:D});if(f){let{frontmatter:F}=this.linkAdapter.parseLinkContent(f.content),I=f.metadata.status;if(I!=="pending")return this.logger.info("Link already captured, returning existing",{url:w,entityId:D}),{success:!0,entityId:f.id,title:F.title,url:w,status:I};this.logger.info("Pending link exists, completing extraction",{url:w,entityId:D})}let Y=this.resolveSource($),X=new Date().toISOString();await B.report({progress:MQ.FETCH,total:100,message:"Fetching webpage content"});let H=await this.urlFetcher.fetch(w);if(!H.success){if(H.errorType==="url_not_found"||H.errorType==="url_unreachable"){this.logger.warn("Link URL not accessible",{url:w,errorType:H.errorType,error:H.error});let F=new URL(w).hostname,I=`Could not capture link: ${H.error}`,L=this.linkAdapter.createLinkContent({status:"pending",title:F,url:w,description:I,summary:I,domain:F,capturedAt:X,source:Y});return await jY({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:L,metadata:{status:"pending",title:F}}}),{success:!1,entityId:D,title:F,url:w,status:"pending",error:I}}}await B.report({progress:MQ.PROCESS,total:100,message:"Extracting content with AI"});let W=await this.context.ai.generate({templateName:"link:extraction",prompt:H.success?`Extract structured information from this webpage content:
|
|
6478
6478
|
|
|
6479
|
-
${H.content}`:`The URL ${w} could not be fetched. Return success: false with error: "${H.error}"`,data:{url:w,hasContent:H.success},interfacePermissionGrant:"public"});if(this.logger.debug("AI extraction result",{result:W}),await B.report({progress:MQ.EXTRACT,total:100,message:"Processing extraction results"}),W.success===!1||!W.title||!W.description||!W.summary){let F=W.title||new URL(w).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:w}),await B.report({progress:MQ.SAVE,total:100,message:"Saving link as pending"});let I=this.linkAdapter.createLinkContent({status:"pending",title:F,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:X,source:Y}),L=await jY({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:I,metadata:{status:"pending",title:F}}});return await B.report({progress:MQ.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:L.entityId,title:F,url:w,status:"pending"}}await B.report({progress:MQ.SAVE,total:100,message:`Saving link: "${W.title}"`});let Z=this.linkAdapter.createLinkContent({status:"draft",title:W.title,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:X,source:Y}),G=await jY({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:Z,metadata:{status:"draft",title:W.title}}});return await B.report({progress:MQ.COMPLETE,total:100,message:`Link captured: "${W.title}"`}),{success:!0,entityId:G.entityId,title:W.title,url:w,status:"draft"}}catch(D){return this.logger.error("Link capture job failed",{error:D,jobId:Q,data:A}),x6.failure(D)}}resolveSource(A){let Q=A?.channelId,B=A?.channelName;if(Q)return{ref:`matrix:${Q}`,label:B??Q};let w=A?.interfaceId??"cli";return{ref:`${w}:local`,label:w.toUpperCase()}}summarizeDataForLog(A){return{url:A.url,interfaceId:A.metadata?.interfaceId}}}async function an1({entity:A,config:Q}){let B=IP.parse(A),{frontmatter:w,summary:$}=UE.parseLinkContent(B.content);return{$type:"ai.rizom.brain.link",title:w.title,url:w.url,...w.description&&{description:w.description},...$&&{summary:$},domain:w.domain,capturedAt:w.capturedAt,source:w.source,...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"link",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function ui0(){return{entityType:"link",collection:"ai.rizom.brain.link",lexicon:_w["ai.rizom.brain.link"],validate:!1,buildRecord:an1}}var tn1={name:"@brains/link",private:!0,version:"0.2.0-alpha.
|
|
6479
|
+
${H.content}`:`The URL ${w} could not be fetched. Return success: false with error: "${H.error}"`,data:{url:w,hasContent:H.success},interfacePermissionGrant:"public"});if(this.logger.debug("AI extraction result",{result:W}),await B.report({progress:MQ.EXTRACT,total:100,message:"Processing extraction results"}),W.success===!1||!W.title||!W.description||!W.summary){let F=W.title||new URL(w).hostname;this.logger.info("Incomplete extraction, saving as pending",{url:w}),await B.report({progress:MQ.SAVE,total:100,message:"Saving link as pending"});let I=this.linkAdapter.createLinkContent({status:"pending",title:F,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:X,source:Y}),L=await jY({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:I,metadata:{status:"pending",title:F}}});return await B.report({progress:MQ.COMPLETE,total:100,message:"Link saved (pending)"}),{success:!0,entityId:L.entityId,title:F,url:w,status:"pending"}}await B.report({progress:MQ.SAVE,total:100,message:`Saving link: "${W.title}"`});let Z=this.linkAdapter.createLinkContent({status:"draft",title:W.title,url:w,description:W.description,summary:W.summary,domain:new URL(w).hostname,capturedAt:X,source:Y}),G=await jY({entityService:this.context.entityService,entity:{id:D,entityType:"link",content:Z,metadata:{status:"draft",title:W.title}}});return await B.report({progress:MQ.COMPLETE,total:100,message:`Link captured: "${W.title}"`}),{success:!0,entityId:G.entityId,title:W.title,url:w,status:"draft"}}catch(D){return this.logger.error("Link capture job failed",{error:D,jobId:Q,data:A}),x6.failure(D)}}resolveSource(A){let Q=A?.channelId,B=A?.channelName;if(Q)return{ref:`matrix:${Q}`,label:B??Q};let w=A?.interfaceId??"cli";return{ref:`${w}:local`,label:w.toUpperCase()}}summarizeDataForLog(A){return{url:A.url,interfaceId:A.metadata?.interfaceId}}}async function an1({entity:A,config:Q}){let B=IP.parse(A),{frontmatter:w,summary:$}=UE.parseLinkContent(B.content);return{$type:"ai.rizom.brain.link",title:w.title,url:w.url,...w.description&&{description:w.description},...$&&{summary:$},domain:w.domain,capturedAt:w.capturedAt,source:w.source,...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"link",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function ui0(){return{entityType:"link",collection:"ai.rizom.brain.link",lexicon:_w["ai.rizom.brain.link"],validate:!1,buildRecord:an1}}var tn1={name:"@brains/link",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};class ci0 extends PQ{entityType=UE.entityType;schema=IP;adapter=UE;shell;unregisterAtprotoProjection;constructor(A={}){super("link",tn1,A,yi0)}async register(A){this.shell=A;let Q=await super.register(A);if(!this.context)throw Error("LinkPlugin context was not initialized during register()");return A.getJobQueueService().registerHandler("link-capture",new ND0(this.logger.child("LinkCaptureJobHandler"),this.context,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0),this.id),Q}async interceptCreate(A,Q,B){if(A.content)try{let D=this.adapter.fromMarkdown(A.content).metadata,f=typeof D?.title==="string"?D.title:void 0,Y=typeof D?.status==="string"?D.status:void 0,X=this.extractFirstUrl(A.content);if(f&&Y&&X){let H=Y1(X)||Y1(f)||`${A.entityType}-${Date.now()}`,W=new Date().toISOString();return{kind:"handled",result:{success:!0,data:{entityId:(await B.entityService.createEntity({entity:{id:H,entityType:A.entityType,content:A.content,metadata:{title:f,status:Y},created:W,updated:W}})).entityId,status:"created"}}}}}catch{}let w=A.url??this.extractFirstUrl(A.content,A.prompt,A.title);if(w){if(!this.shell)throw Error("LinkPlugin shell was not initialized during register()");try{let $=await this.createPendingLink(w,A.title,Q,B),D=await this.shell.getJobQueueService().enqueue({type:"link-capture",data:{url:w,metadata:{interfaceId:Q.interfaceType,userId:Q.userId,...Q.channelId?{channelId:Q.channelId}:{},...Q.channelName?{channelName:Q.channelName}:{},timestamp:new Date().toISOString()}},options:{source:this.id,metadata:{operationType:"data_processing",pluginId:this.id,interfaceType:Q.interfaceType,...Q.channelId?{channelId:Q.channelId}:{}}}});return{kind:"handled",result:{success:!0,data:{entityId:$,status:"generating",jobId:D}}}}catch($){return{kind:"handled",result:{success:!1,error:$ instanceof Error?$.message:"Failed to queue link capture job"}}}}if(A.content)return{kind:"handled",result:{success:!1,error:"Direct link creation requires full link markdown/frontmatter, or provide a URL to capture."}};if(A.prompt)return{kind:"handled",result:{success:!1,error:"Link creation requires a URL in the prompt, content, or title, or full link markdown content for direct creation."}};return{kind:"continue",input:A}}createGenerationHandler(A){return new ND0(this.logger.child("LinkCaptureJobHandler"),A,this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0)}getTemplates(){return{extraction:rn1,"link-list":on1,"link-detail":sn1}}getDataSources(){return[new mi0(this.logger.child("LinksDataSource"))]}async onRegister(A){this.unregisterAtprotoProjection=U5.getInstance().register(ui0()),A.eval.registerHandler("extractContent",async(Q)=>{let{url:B}=K.object({url:K.string().url()}).parse(Q),$=await new GE(this.config.jinaApiKey?{jinaApiKey:this.config.jinaApiKey}:void 0).fetch(B);if(!$.success)return{success:!1,error:$.error,errorType:$.errorType};return A.ai.generate({templateName:"link:extraction",prompt:`Extract structured information from this webpage content:
|
|
6480
6480
|
|
|
6481
6481
|
${$.content}`,data:{url:B,hasContent:!0},interfacePermissionGrant:"public"})})}async createPendingLink(A,Q,B,w){let $=kL.generateEntityId(A),D=new URL(A),f=new Date().toISOString(),Y=Q?.trim()?Q.trim():D.hostname,X=this.adapter.createLinkContent({status:"pending",title:Y,url:A,description:"Link capture is in progress.",summary:`Pending link capture for ${A}.`,domain:D.hostname,capturedAt:f,source:this.resolveSource(B)});return(await qN({entityService:w.entityService,entity:{id:$,entityType:"link",content:X,metadata:{status:"pending",title:Y},created:f,updated:f}})).entityId}resolveSource(A){if(A.channelId)return{ref:`matrix:${A.channelId}`,label:A.channelName??A.channelId};return{ref:`${A.interfaceType}:local`,label:A.interfaceType.toUpperCase()}}extractFirstUrl(...A){for(let Q of A){if(!Q)continue;let[B]=kL.extractUrls(Q);if(B)return B}return}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}}function en1(A={}){return new ci0(A)}var VP=en1;K0();var An8=K.object({id:K.string().optional(),metadata:K.object({conversationId:K.string().optional(),interfaceId:K.string().optional(),userId:K.string().optional(),messageId:K.string().optional(),timestamp:K.string().optional()}).optional()});p0();K0();Jw();K0();p0();var Ar1=K.enum(["generating","draft","published","failed"]),W9=K.object({title:K.string(),slug:K.string().optional(),status:Ar1,publishedAt:K.string().datetime().optional(),description:K.string(),year:K.number(),coverImageId:K.string().optional(),ogImageId:K.string().optional(),url:K.string().url().optional()}),Qr1=W9.pick({title:!0,status:!0,publishedAt:!0,year:!0}).extend({slug:K.string(),error:K.string().optional()}),OL=o1.extend({entityType:K.literal("project"),metadata:Qr1}),jD0=K.object({context:K.string(),problem:K.string(),solution:K.string(),outcome:K.string()}),dr=OL.extend({frontmatter:W9,body:K.string(),structuredContent:jD0.optional(),coverImageUrl:K.string().optional(),ogImageUrl:K.string().optional()}),zE=dr.extend({url:K.string().optional(),typeLabel:K.string().optional(),coverImageUrl:K.string().optional(),ogImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()}),ZYB=dr.extend({url:K.string(),typeLabel:K.string(),coverImageUrl:K.string().optional(),ogImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()});p0();K0();p$();class li0 extends pB{constructor(){super(jD0,{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 pi0=new li0;class ii0 extends V2{constructor(){super({entityType:"project",schema:OL,frontmatterSchema:W9,supportsCoverImage:!0,bodyFormatter:pi0})}toMarkdown(A){let Q=this.extractBody(A.content);try{let B=this.parseFrontMatter(A.content,W9),w={...B,slug:B.slug??A.metadata.slug};return this.buildMarkdown(Q,w)}catch{return Q}}fromMarkdown(A){let Q=this.parseFrontMatter(A,W9),B=Q.slug??Y1(Q.title);return{content:A,entityType:"project",metadata:{title:Q.title,slug:B,status:Q.status,publishedAt:Q.publishedAt,year:Q.year}}}parseProjectFrontmatter(A){return this.parseFrontMatter(A.content,W9)}parseStructuredContent(A){return pi0.parse(this.extractBody(A.content))}createProjectContent(A,Q){let B=pi0.format(Q);return this.buildMarkdown(B,A)}buildStub(A){let Q=new Date().getUTCFullYear(),B={title:A.title,slug:A.id,status:"generating",description:"",year:Q};return{content:this.buildMarkdown("",B),metadata:{title:A.title,slug:A.id,status:"generating",year:Q}}}}var xL=new ii0;K0();var di0=K.object({});import{jsxDEV as hX,Fragment as UYB}from"preact/jsx-dev-runtime";var KYB=({project:A})=>{let{frontmatter:Q,url:B,coverImageUrl:w}=A;return hX(uB,{href:B,children:[w&&hX("img",{src:w,alt:Q.title,className:"w-full h-56 object-cover rounded-md mb-4"},void 0,!1,void 0,this),hX(i9,{children:Q.title},void 0,!1,void 0,this),hX("p",{className:"text-theme leading-relaxed",children:Q.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},ni0=({projects:A,pageTitle:Q,pagination:B,baseUrl:w="/projects"})=>{let $=Q??"Projects",D=B?.totalItems??A.length,f=`Browse all ${D} ${D===1?"project":"projects"}`;return hX(UYB,{children:[hX(NQ,{title:$,description:f},void 0,!1,void 0,this),hX("div",{className:"project-list bg-theme",children:hX("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[hX("h1",{className:"text-4xl font-bold text-heading mb-12",children:$},void 0,!1,void 0,this),hX("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-8",children:A.map((Y)=>hX(KYB,{project:Y},Y.id,!1,void 0,this))},void 0,!1,void 0,this),B&&B.totalPages>1&&hX("div",{className:"mt-12",children:hX(i3,{currentPage:B.currentPage,totalPages:B.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 zw,Fragment as Br1}from"preact/jsx-dev-runtime";var GYB=({prevProject:A,nextProject:Q})=>{if(!A&&!Q)return null;return zw("nav",{className:"pt-12 mt-12 border-t border-theme-muted",children:zw("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[A?zw(uB,{href:A.url,variant:"compact",children:[zw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Previous"},void 0,!1,void 0,this),zw("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):zw("div",{},void 0,!1,void 0,this),Q&&zw(uB,{href:Q.url,variant:"compact",className:"md:text-right",children:[zw("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Next"},void 0,!1,void 0,this),zw("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Q.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)},_D0=({title:A,content:Q})=>{if(!Q)return null;return zw("section",{className:"mb-12",children:[zw("h2",{className:"text-2xl font-bold text-heading mb-4",children:A},void 0,!1,void 0,this),zw(f9,{markdown:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},ri0=({project:A,prevProject:Q,nextProject:B})=>{let{frontmatter:w,structuredContent:$,metadata:D,coverImageUrl:f}=A,Y=A.ogImageUrl??f;return zw(Br1,{children:[zw(NQ,{title:w.title,description:w.description,...Y?{ogImage:Y}:{},ogType:"article"},void 0,!1,void 0,this),zw("article",{className:"project-detail",children:zw("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:zw("div",{className:"max-w-3xl mx-auto",children:[f&&A.coverImageWidth&&A.coverImageHeight&&zw(l3,{src:f,alt:w.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8 shadow-lg"},void 0,!1,void 0,this),zw("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),zw("div",{className:"flex flex-wrap items-center gap-4 text-theme-muted mb-8",children:[zw("span",{className:"text-sm",children:D.year},void 0,!1,void 0,this),w.url&&zw(Br1,{children:[zw("span",{className:"text-theme-muted",children:"|"},void 0,!1,void 0,this),zw("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),zw("p",{className:"text-lg text-theme mb-12 leading-relaxed",children:w.description},void 0,!1,void 0,this),$&&zw("div",{className:"case-study",children:[zw(_D0,{title:"Context",content:$.context},void 0,!1,void 0,this),zw(_D0,{title:"Problem",content:$.problem},void 0,!1,void 0,this),zw(_D0,{title:"Solution",content:$.solution},void 0,!1,void 0,this),zw(_D0,{title:"Outcome",content:$.outcome},void 0,!1,void 0,this)]},void 0,!0,void 0,this),zw(GYB,{prevProject:Q,nextProject:B},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)};K0();p0();var zYB=K.object({title:K.string().max(80).describe("A clear, compelling project title (3-8 words). Should capture the essence of the project."),description:K.string().describe("A 1-2 sentence summary of the project for portfolio cards. Focus on the core value delivered."),context:K.string().describe("Background information: Who was the client/user? What was the situation? What constraints existed? (2-4 paragraphs)"),problem:K.string().describe("The challenge: What specific problem needed solving? What were the pain points? (2-3 paragraphs)"),solution:K.string().describe("The approach: What was built? What technologies/methods were used? How did it work? (3-5 paragraphs)"),outcome:K.string().describe("The results: What impact did this have? What metrics improved? What was learned? (2-3 paragraphs)")}),oi0=R1({name:"portfolio:generation",description:"Template for AI to generate portfolio project case studies",schema:zYB,dataSourceId:"shell:ai-content",requiredPermission:"public",useKnowledgeContext:!0,basePrompt:`You are helping to create a professional portfolio case study based on REAL project information.
|
|
6482
6482
|
|
|
@@ -6652,7 +6652,7 @@ Use the project request as the primary source of truth. If retrieved knowledge c
|
|
|
6652
6652
|
font: 10px/1.45 var(--font-mono, "JetBrains Mono", ui-monospace, monospace);
|
|
6653
6653
|
}
|
|
6654
6654
|
.printable-footer a { color: inherit; text-decoration: none; overflow-wrap: anywhere; }
|
|
6655
|
-
`}},void 0,!1,void 0,this),Z9("section",{className:"project-shell",children:[Z9("header",{className:"project-hero",children:[Z9("div",{className:"project-index",children:[Q.brandLabel&&Z9("p",{className:"printable-kicker",children:Q.brandLabel},void 0,!1,void 0,this),Q.year&&Z9("span",{className:"project-year",children:Q.year},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Z9("div",{className:"project-title-panel",children:[Z9("span",{className:"printable-kind",children:"Case study dossier"},void 0,!1,void 0,this),Z9("h1",{className:"printable-title",children:Q.title},void 0,!1,void 0,this),Q.description&&Z9("p",{className:"printable-description",children:Q.description},void 0,!1,void 0,this),Z9("div",{className:"printable-meta",children:[Q.year&&Z9("span",{children:Q.year},void 0,!1,void 0,this),Q.url&&Z9("span",{children:Q.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q.coverImageUrl&&Z9("img",{className:"printable-cover",src:Q.coverImageUrl,alt:""},void 0,!1,void 0,this),Z9(f9,{markdown:Q.body,className:"printable-body"},void 0,!1,void 0,this),(Q.canonicalUrl||Q.url||Q.brandLabel)&&Z9("footer",{className:"printable-footer",children:[Z9("span",{children:Q.brandLabel??"Project printable"},void 0,!1,void 0,this),Q.canonicalUrl||Q.url?Z9("a",{href:Q.canonicalUrl??Q.url,children:Q.canonicalUrl??Q.url},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var jYB=26214400,_YB=60000;class ti0{context;renderPdf;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK}async resolve(A){if(A.sourceEntityType!=="project"||A.attachmentType!==kD0)return;let Q=await this.context.entityService.getEntity({entityType:"project",id:A.sourceEntityId});if(!Q)return;let B=MYB(Q,{brandLabel:this.resolveBrandLabel(),coverImageUrl:await this.resolveCoverImageUrl(Q)}),w=await JYB(NYB(bYB(),"brain-project-printable-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/printable/project/${Q.id}`,template:Dr1,format:"pdf",content:B,siteConfig:{title:B.title,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"document",data:await this.renderPdf(D.urlFor($.urlPath),{maxBytes:jYB,timeoutMs:_YB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${PYB(Q)}-printable.pdf`}}finally{await D.close()}}finally{await LYB(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){let{frontmatter:Q}=lB(A.content),B=W9.parse(Q);if(!B.coverImageId)return;let w=await this.context.entityService.getEntity({entityType:"image",id:B.coverImageId});return w?.content.startsWith("data:image/")?w.content:void 0}}function MYB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=W9.parse(B);return{title:$.title,body:w,...$.description?{description:$.description}:{},year:$.year,...$.publishedAt?{publishedAt:$.publishedAt}:{},...$.url?{url:$.url,canonicalUrl:$.url}:{},...Q.coverImageUrl?{coverImageUrl:Q.coverImageUrl}:{},...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function PYB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}K0();K0();import{jsxDEV as xYB}from"preact/jsx-dev-runtime";var OD0="og-image",kYB="portfolio:og-image",fr1=K.object({title:K.string().min(1),description:K.string().optional(),year:K.number().optional(),brandLabel:K.string().optional(),coverImageUrl:K.string().optional()}),Yr1={name:kYB,pluginId:"portfolio",schema:fr1,renderers:{image:OYB}};function OYB(A){let Q=fr1.parse(A);return xYB(c3,{brandLabel:Q.brandLabel??Q.title,eyebrow:"Project",title:Q.title,subtitle:Q.description,tag:Q.year},void 0,!1,void 0,this)}class ei0{context;deps;constructor(A,Q={}){this.context=A;this.deps=Q}async resolve(A){if(A.sourceEntityType!=="project"||A.attachmentType!==OD0)return;let Q=await this.context.entityService.getEntity({entityType:"project",id:A.sourceEntityId});if(!Q)return;let{frontmatter:B}=lB(Q.content),w=W9.parse(B),$=this.resolveBrandLabel(),D=await this.resolveCoverImageUrl(w.coverImageId),f={title:w.title,...w.description?{description:w.description}:{},year:w.year,...D?{coverImageUrl:D}:{},...$?{brandLabel:$}:{}};return{type:"image",data:await XP({mediaPath:`/_media/og/project/${Q.id}`,template:Yr1,content:f,title:f.title,themeMode:"light",themeCSS:this.context.themeCSS,tmpPrefix:"brain-project-og-image-",...this.deps.screenshotPng&&{screenshotPng:this.deps.screenshotPng}}),mimeType:"image/png",filename:`${RYB(Q)}-og.png`}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){if(!A)return;let Q=await this.context.entityService.getEntity({entityType:"image",id:A});return Q?.content.startsWith("data:image/")?Q.content:void 0}}function RYB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}var Xr1={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.128",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/media-renderer":"workspace:*","@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 hYB=K.object({projects:K.array(zE),pageTitle:K.string().optional(),pagination:e7.nullable(),baseUrl:K.string().optional()});function CYB(A,Q){for(let B of[A,Q]){let w=B?.match(/\b(19\d{2}|20\d{2})\b/);if(w?.[1])return Number(w[1])}return null}class Ad0 extends PQ{entityType=xL.entityType;schema=OL;adapter=xL;unregisterAtprotoProjection;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(A={}){super("portfolio",Xr1,A,di0)}async interceptCreate(A,Q,B){if(!A.prompt||A.content)return{kind:"continue",input:A};let w=CYB(A.title,A.prompt);if(!w)return{kind:"continue",input:A};return{kind:"handled",result:{success:!0,data:{status:"generating",jobId:await B.jobs.enqueue({type:"project:generation",data:{prompt:A.prompt,...A.title?{title:A.title}:{},year:w},toolContext:Q,options:{source:this.id,metadata:{operationType:"content_operations"}}})}}}}createGenerationHandler(A){return new MD0(this.logger.child("ProjectGenerationJobHandler"),A)}getTemplates(){return{"project-list":R1({name:"project-list",description:"Portfolio project list page template",schema:hYB,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:ni0}}),"project-detail":R1({name:"project-detail",description:"Individual project case study template",schema:K.object({project:zE,prevProject:zE.nullable(),nextProject:zE.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:ri0}}),generation:oi0}}getDataSources(){return[new PD0(this.logger.child("ProjectDataSource"))]}async onRegister(A){this.registerEvalHandlers(A),this.unregisterPrintableAttachmentProvider=A.attachments.register("project",kD0,new ti0(A)),this.unregisterOgImageAttachmentProvider=A.attachments.register("project",OD0,new ei0(A)),this.deferPublishRegistration(A),this.subscribeToPublishExecute(A),this.unregisterAtprotoProjection=U5.getInstance().register(ai0())}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}registerEvalHandlers(A){A.eval.registerHandler("generateProject",async(Q)=>{let B=K.object({prompt:K.string(),year:K.number()}).parse(Q);return A.ai.generate({prompt:si0(B),templateName:"portfolio:generation"})})}deferPublishRegistration(A){let Q={name:"internal",publish:async()=>({id:"internal"})};A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"publish:register",payload:{entityType:"project",provider:Q,config:{executionMode:"provider"}}}),{success:!0}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(Q)=>{let{entityType:B,entityId:w}=Q.payload;if(B!=="project")return{success:!0};try{let $=await A.entityService.getEntity({entityType:"project",id:w});if(!$)return await A.messaging.send({type:"publish:report:failure",payload:{entityType:B,entityId:w,error:`Project not found: ${w}`}}),{success:!0};if($.metadata.status==="published")return{success:!0};let D=h2($.content,W9),f=new Date().toISOString(),Y=X7(D.content,{...D.metadata,status:"published",publishedAt:f});await A.entityService.updateEntity({entity:{...$,content:Y,metadata:{...$.metadata,status:"published",publishedAt:f}}}),await A.messaging.send({type:"publish:report:success",payload:{entityType:B,entityId:w,publishedAt:f}})}catch($){await A.messaging.send({type:"publish:report:failure",payload:{entityType:B,entityId:w,error:hA($)}})}return{success:!0}})}}function Qd0(A={}){return new Ad0(A)}p0();K0();var yYB=K.enum(["public","shared","restricted"]),Hr1=K.object({includeEntityTypes:K.array(K.string()).default([]),minRelevanceScore:K.number().min(0).max(1).default(0.5),mergeSimilarityThreshold:K.number().min(0).max(1).default(0.85),autoMerge:K.boolean().default(!0),extractableStatuses:K.array(K.string()).default(["published"]),enableAutoExtraction:K.boolean().default(!0),extractionVisibility:yYB.default("public"),sourceChangeBatchDelayMs:K.number().int().min(0).default(1000)});p0();K0();p0();var EYB=K.object({}),qE=o1.extend({entityType:K.literal("topic"),metadata:EYB}),or8=K.object({content:K.string()}),Wr1=K.object({title:K.string().describe("Topic title")});var JP="topics",qw="topic",Bd0="topics-projection",Zr1="topic:project",xD0="topics-plugin",Kr1="topics:batch-completed",Ur1="topics-source-batch";class JK extends V2{constructor(){super({entityType:qw,schema:qE,frontmatterSchema:Wr1})}buildFrontmatter(A){return{title:A}}toMarkdown(A){let Q=this.parseTopicBody(A.content);return this.buildMarkdown(Q.content,this.buildFrontmatter(Q.title))}fromMarkdown(A){return{content:A,entityType:qw}}extractMetadata(A){return{}}generateFrontMatter(A){let Q=this.parseTopicBody(A.content),w=this.buildMarkdown("",this.buildFrontmatter(Q.title)).match(/^---\n[\s\S]*?\n---/);return w?w[0]:""}parseTopicBody(A){if(A.startsWith("---"))try{let Q=this.parseFrontmatter(A);return{content:this.extractBody(A).replace(/\n*## Sources[\s\S]*$/,"").trim(),formatted:A,title:Q.title}}catch{return{content:A,formatted:A,title:"Unknown Topic"}}return{content:A,formatted:A,title:"Unknown Topic"}}createTopicBody(A){return this.buildMarkdown(A.content,this.buildFrontmatter(A.title))}}p0();K0();K0();var gYB=K.object({title:K.string().max(100),content:K.string(),relevanceScore:K.number().min(0).max(1)}),Gr1=K.array(gYB);var TYB=K.object({topics:Gr1}),zr1=R1({name:"topics:extraction",description:"Extract topics from conversation text",dataSourceId:"shell:ai-content",schema:TYB,basePrompt:`You are an expert at analyzing content and extracting key topics.
|
|
6655
|
+
`}},void 0,!1,void 0,this),Z9("section",{className:"project-shell",children:[Z9("header",{className:"project-hero",children:[Z9("div",{className:"project-index",children:[Q.brandLabel&&Z9("p",{className:"printable-kicker",children:Q.brandLabel},void 0,!1,void 0,this),Q.year&&Z9("span",{className:"project-year",children:Q.year},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Z9("div",{className:"project-title-panel",children:[Z9("span",{className:"printable-kind",children:"Case study dossier"},void 0,!1,void 0,this),Z9("h1",{className:"printable-title",children:Q.title},void 0,!1,void 0,this),Q.description&&Z9("p",{className:"printable-description",children:Q.description},void 0,!1,void 0,this),Z9("div",{className:"printable-meta",children:[Q.year&&Z9("span",{children:Q.year},void 0,!1,void 0,this),Q.url&&Z9("span",{children:Q.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),Q.coverImageUrl&&Z9("img",{className:"printable-cover",src:Q.coverImageUrl,alt:""},void 0,!1,void 0,this),Z9(f9,{markdown:Q.body,className:"printable-body"},void 0,!1,void 0,this),(Q.canonicalUrl||Q.url||Q.brandLabel)&&Z9("footer",{className:"printable-footer",children:[Z9("span",{children:Q.brandLabel??"Project printable"},void 0,!1,void 0,this),Q.canonicalUrl||Q.url?Z9("a",{href:Q.canonicalUrl??Q.url,children:Q.canonicalUrl??Q.url},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var jYB=26214400,_YB=60000;class ti0{context;renderPdf;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK}async resolve(A){if(A.sourceEntityType!=="project"||A.attachmentType!==kD0)return;let Q=await this.context.entityService.getEntity({entityType:"project",id:A.sourceEntityId});if(!Q)return;let B=MYB(Q,{brandLabel:this.resolveBrandLabel(),coverImageUrl:await this.resolveCoverImageUrl(Q)}),w=await JYB(NYB(bYB(),"brain-project-printable-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/printable/project/${Q.id}`,template:Dr1,format:"pdf",content:B,siteConfig:{title:B.title,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"document",data:await this.renderPdf(D.urlFor($.urlPath),{maxBytes:jYB,timeoutMs:_YB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${PYB(Q)}-printable.pdf`}}finally{await D.close()}}finally{await LYB(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){let{frontmatter:Q}=lB(A.content),B=W9.parse(Q);if(!B.coverImageId)return;let w=await this.context.entityService.getEntity({entityType:"image",id:B.coverImageId});return w?.content.startsWith("data:image/")?w.content:void 0}}function MYB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=W9.parse(B);return{title:$.title,body:w,...$.description?{description:$.description}:{},year:$.year,...$.publishedAt?{publishedAt:$.publishedAt}:{},...$.url?{url:$.url,canonicalUrl:$.url}:{},...Q.coverImageUrl?{coverImageUrl:Q.coverImageUrl}:{},...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function PYB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}K0();K0();import{jsxDEV as xYB}from"preact/jsx-dev-runtime";var OD0="og-image",kYB="portfolio:og-image",fr1=K.object({title:K.string().min(1),description:K.string().optional(),year:K.number().optional(),brandLabel:K.string().optional(),coverImageUrl:K.string().optional()}),Yr1={name:kYB,pluginId:"portfolio",schema:fr1,renderers:{image:OYB}};function OYB(A){let Q=fr1.parse(A);return xYB(c3,{brandLabel:Q.brandLabel??Q.title,eyebrow:"Project",title:Q.title,subtitle:Q.description,tag:Q.year},void 0,!1,void 0,this)}class ei0{context;deps;constructor(A,Q={}){this.context=A;this.deps=Q}async resolve(A){if(A.sourceEntityType!=="project"||A.attachmentType!==OD0)return;let Q=await this.context.entityService.getEntity({entityType:"project",id:A.sourceEntityId});if(!Q)return;let{frontmatter:B}=lB(Q.content),w=W9.parse(B),$=this.resolveBrandLabel(),D=await this.resolveCoverImageUrl(w.coverImageId),f={title:w.title,...w.description?{description:w.description}:{},year:w.year,...D?{coverImageUrl:D}:{},...$?{brandLabel:$}:{}};return{type:"image",data:await XP({mediaPath:`/_media/og/project/${Q.id}`,template:Yr1,content:f,title:f.title,themeMode:"light",themeCSS:this.context.themeCSS,tmpPrefix:"brain-project-og-image-",...this.deps.screenshotPng&&{screenshotPng:this.deps.screenshotPng}}),mimeType:"image/png",filename:`${RYB(Q)}-og.png`}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}async resolveCoverImageUrl(A){if(!A)return;let Q=await this.context.entityService.getEntity({entityType:"image",id:A});return Q?.content.startsWith("data:image/")?Q.content:void 0}}function RYB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.title)}var Xr1={name:"@brains/portfolio",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/media-renderer":"workspace:*","@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 hYB=K.object({projects:K.array(zE),pageTitle:K.string().optional(),pagination:e7.nullable(),baseUrl:K.string().optional()});function CYB(A,Q){for(let B of[A,Q]){let w=B?.match(/\b(19\d{2}|20\d{2})\b/);if(w?.[1])return Number(w[1])}return null}class Ad0 extends PQ{entityType=xL.entityType;schema=OL;adapter=xL;unregisterAtprotoProjection;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(A={}){super("portfolio",Xr1,A,di0)}async interceptCreate(A,Q,B){if(!A.prompt||A.content)return{kind:"continue",input:A};let w=CYB(A.title,A.prompt);if(!w)return{kind:"continue",input:A};return{kind:"handled",result:{success:!0,data:{status:"generating",jobId:await B.jobs.enqueue({type:"project:generation",data:{prompt:A.prompt,...A.title?{title:A.title}:{},year:w},toolContext:Q,options:{source:this.id,metadata:{operationType:"content_operations"}}})}}}}createGenerationHandler(A){return new MD0(this.logger.child("ProjectGenerationJobHandler"),A)}getTemplates(){return{"project-list":R1({name:"project-list",description:"Portfolio project list page template",schema:hYB,dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:ni0}}),"project-detail":R1({name:"project-detail",description:"Individual project case study template",schema:K.object({project:zE,prevProject:zE.nullable(),nextProject:zE.nullable()}),dataSourceId:"portfolio:entities",requiredPermission:"public",layout:{component:ri0}}),generation:oi0}}getDataSources(){return[new PD0(this.logger.child("ProjectDataSource"))]}async onRegister(A){this.registerEvalHandlers(A),this.unregisterPrintableAttachmentProvider=A.attachments.register("project",kD0,new ti0(A)),this.unregisterOgImageAttachmentProvider=A.attachments.register("project",OD0,new ei0(A)),this.deferPublishRegistration(A),this.subscribeToPublishExecute(A),this.unregisterAtprotoProjection=U5.getInstance().register(ai0())}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0,this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}registerEvalHandlers(A){A.eval.registerHandler("generateProject",async(Q)=>{let B=K.object({prompt:K.string(),year:K.number()}).parse(Q);return A.ai.generate({prompt:si0(B),templateName:"portfolio:generation"})})}deferPublishRegistration(A){let Q={name:"internal",publish:async()=>({id:"internal"})};A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"publish:register",payload:{entityType:"project",provider:Q,config:{executionMode:"provider"}}}),{success:!0}})}subscribeToPublishExecute(A){A.messaging.subscribe("publish:execute",async(Q)=>{let{entityType:B,entityId:w}=Q.payload;if(B!=="project")return{success:!0};try{let $=await A.entityService.getEntity({entityType:"project",id:w});if(!$)return await A.messaging.send({type:"publish:report:failure",payload:{entityType:B,entityId:w,error:`Project not found: ${w}`}}),{success:!0};if($.metadata.status==="published")return{success:!0};let D=h2($.content,W9),f=new Date().toISOString(),Y=X7(D.content,{...D.metadata,status:"published",publishedAt:f});await A.entityService.updateEntity({entity:{...$,content:Y,metadata:{...$.metadata,status:"published",publishedAt:f}}}),await A.messaging.send({type:"publish:report:success",payload:{entityType:B,entityId:w,publishedAt:f}})}catch($){await A.messaging.send({type:"publish:report:failure",payload:{entityType:B,entityId:w,error:hA($)}})}return{success:!0}})}}function Qd0(A={}){return new Ad0(A)}p0();K0();var yYB=K.enum(["public","shared","restricted"]),Hr1=K.object({includeEntityTypes:K.array(K.string()).default([]),minRelevanceScore:K.number().min(0).max(1).default(0.5),mergeSimilarityThreshold:K.number().min(0).max(1).default(0.85),autoMerge:K.boolean().default(!0),extractableStatuses:K.array(K.string()).default(["published"]),enableAutoExtraction:K.boolean().default(!0),extractionVisibility:yYB.default("public"),sourceChangeBatchDelayMs:K.number().int().min(0).default(1000)});p0();K0();p0();var EYB=K.object({}),qE=o1.extend({entityType:K.literal("topic"),metadata:EYB}),or8=K.object({content:K.string()}),Wr1=K.object({title:K.string().describe("Topic title")});var JP="topics",qw="topic",Bd0="topics-projection",Zr1="topic:project",xD0="topics-plugin",Kr1="topics:batch-completed",Ur1="topics-source-batch";class JK extends V2{constructor(){super({entityType:qw,schema:qE,frontmatterSchema:Wr1})}buildFrontmatter(A){return{title:A}}toMarkdown(A){let Q=this.parseTopicBody(A.content);return this.buildMarkdown(Q.content,this.buildFrontmatter(Q.title))}fromMarkdown(A){return{content:A,entityType:qw}}extractMetadata(A){return{}}generateFrontMatter(A){let Q=this.parseTopicBody(A.content),w=this.buildMarkdown("",this.buildFrontmatter(Q.title)).match(/^---\n[\s\S]*?\n---/);return w?w[0]:""}parseTopicBody(A){if(A.startsWith("---"))try{let Q=this.parseFrontmatter(A);return{content:this.extractBody(A).replace(/\n*## Sources[\s\S]*$/,"").trim(),formatted:A,title:Q.title}}catch{return{content:A,formatted:A,title:"Unknown Topic"}}return{content:A,formatted:A,title:"Unknown Topic"}}createTopicBody(A){return this.buildMarkdown(A.content,this.buildFrontmatter(A.title))}}p0();K0();K0();var gYB=K.object({title:K.string().max(100),content:K.string(),relevanceScore:K.number().min(0).max(1)}),Gr1=K.array(gYB);var TYB=K.object({topics:Gr1}),zr1=R1({name:"topics:extraction",description:"Extract topics from conversation text",dataSourceId:"shell:ai-content",schema:TYB,basePrompt:`You are an expert at analyzing content and extracting key topics.
|
|
6656
6656
|
|
|
6657
6657
|
Analyze the provided content and extract meaningful topics discussed.
|
|
6658
6658
|
|
|
@@ -6755,13 +6755,13 @@ ${A.incomingTopic.content}`})}}function oYB(A){if(A.length===0)return"";return A
|
|
|
6755
6755
|
|
|
6756
6756
|
${Q.content}`}).join(`
|
|
6757
6757
|
|
|
6758
|
-
`)}async function LP(A,Q,B,w={}){if(A.length===0)return{created:0,merged:0,skipped:0,batches:0};let $=w.minRelevanceScore??0,D=w.autoMerge??!1,f=w.mergeSimilarityThreshold??0.85,Y=w.targetVisibility??"public",X=Mr1(A),H=new LK(Q.entityService,B),W=w.topicMergeSynthesizer??new Xd0(Q,B),Z=await yD0(Q.entityService,void 0,Y),G=new Map,F=0,I=0,L=0;for(let N of X){B.info(`Processing batch of ${N.length} entities`);let M=oYB(N),j=ED0({entityTitle:`Batch of ${N.length} entities`,entityType:"batch",content:M,existingTopicTitles:Z});try{let E=(await Q.ai.generate({prompt:j,templateName:"topics:extraction"})).topics.filter((y)=>y.relevanceScore>=$);for(let y of E)try{if(D){let S=await H.findMergeCandidate({incoming:y,threshold:f,additionalCandidates:Array.from(G.values()),targetVisibility:Y});if(S){let c=await W.synthesize({existingTopic:S.topic,incomingTopic:y}),m=await H.applySynthesizedMerge({existingId:S.topic.id,synthesized:{...c,title:S.title},visibility:Y});if(!m)throw Error(`Failed to merge topic: ${y.title}`);G.set(m.id,m),I++;continue}}let h=H.getTopicIdForTitle(y.title,Y);if(G.has(h)){L++;continue}let T=await H.createTopicOptimistic({title:y.title,content:y.content,visibility:Y});if(T.topic)G.set(T.topic.id,T.topic);if(T.created)F++;else L++}catch(h){B.error("Topic batch item failed",{title:y.title,error:hA(h)})}}catch(g){B.error("Batch topic extraction failed",{batchSize:N.length,promptChars:j.length,error:hA(g)})}}let b={created:F,merged:I,skipped:L,batches:X.length};if(F>0||I>0)await Q.messaging.send({type:Kr1,payload:b,broadcast:!0});return b}p0();K0();var sYB=K.discriminatedUnion("mode",[K.object({mode:K.literal("derive"),reason:K.string().optional()}),K.object({mode:K.literal("rebuild"),reason:K.string().optional()}),K.object({mode:K.literal("source-batch"),minRelevanceScore:K.number().min(0).max(1).optional()})]);class Hd0{refs=new Map;add(A){this.refs.set(`${A.entityType}:${A.entityId}`,A)}drain(){let A=Array.from(this.refs.values());return this.refs.clear(),A}}function vr1(A){let{context:Q,logger:B,config:w}=A;return{process:async($)=>{if($.mode==="derive")return await A.extractAllTopics(),{success:!0};if($.mode==="rebuild")return await A.rebuildAllTopics(),{success:!0};return aYB({context:Q,logger:B,config:w,sourceBatch:A.sourceBatch,isEntityPublished:A.isEntityPublished,minRelevanceScore:$.minRelevanceScore??w.minRelevanceScore})},validateAndParse:($)=>{let D=sYB.safeParse($??{});return D.success?D.data:null}}}async function aYB(A){let Q=A.sourceBatch.drain(),B=await Promise.all(Q.map(async(H)=>({ref:H,entity:await A.context.entityService.getEntity({entityType:H.entityType,id:H.entityId})}))),w=0,$=0,D=0,f=0,Y=[];for(let{ref:H,entity:W}of B){if(!W){$++;continue}if(W.contentHash!==H.contentHash){w++;continue}if(!A.isEntityPublished(W)){D++;continue}if(!uI(W.visibility,A.config.extractionVisibility)){f++;continue}Y.push(W)}if(Y.length===0)return{success:!0,sources:Q.length,created:0,merged:0,skipped:0,batches:0,stale:w,missing:$,unpublished:D,hidden:f};let X=await LP(Y,A.context,A.logger,{minRelevanceScore:A.minRelevanceScore,autoMerge:A.config.autoMerge,mergeSimilarityThreshold:A.config.mergeSimilarityThreshold,targetVisibility:A.config.extractionVisibility});return{success:!0,sources:Q.length,...X,stale:w,missing:$,unpublished:D,hidden:f}}function hr1(){return{priority:5,source:xD0,deduplication:"coalesce",deduplicationKey:"topics-initial-derivation",metadata:{operationType:"data_processing",operationTarget:"topics-initial-derivation",pluginId:JP}}}async function Cr1(A){let Q=await Er1(A);if(Q.length===0){A.logger.info("No entities to extract topics from");return}A.logger.info(`Batch topic extraction: ${Q.length} entities`);let B=await LP(Q,A.context,A.logger,{minRelevanceScore:A.config.minRelevanceScore,autoMerge:A.config.autoMerge,mergeSimilarityThreshold:A.config.mergeSimilarityThreshold,targetVisibility:A.config.extractionVisibility});A.logger.info("Batch topic extraction complete",B)}async function yr1(A){let Q=await Er1(A),B=await Wd0(Q,A.context,A.logger,A.config);A.logger.info("Topic rebuild complete",B)}async function Wd0(A,Q,B,w){let $=new LK(Q.entityService,B),D=await $.listTopics({visibility:w.extractionVisibility});for(let Y of D)await $.deleteTopic(Y.id);if(A.length===0)return{deleted:D.length,created:0,merged:0,skipped:0,batches:0};let f=await LP(A,Q,B,{minRelevanceScore:w.minRelevanceScore,autoMerge:w.autoMerge,mergeSimilarityThreshold:w.mergeSimilarityThreshold,targetVisibility:w.extractionVisibility});return{deleted:D.length,...f}}async function Er1(A){let Q=tYB(A),B=[];for(let w of Q){let $=await A.context.entityService.listEntities({entityType:w,options:{filter:{visibilityScope:A.config.extractionVisibility}}});for(let D of $){if(!A.isEntityPublished(D))continue;B.push(D)}}return B}function tYB(A){return A.context.entityService.getEntityTypes().filter((B)=>A.shouldProcessEntityType(B))}var VE=K.object({entityType:K.string(),content:K.string(),metadata:K.record(K.unknown()).optional()}),eYB=VE.extend({minRelevanceScore:K.number().optional()}),AXB=K.object({contentA:VE,contentB:VE,minRelevanceScore:K.number().optional(),threshold:K.number().min(0).max(1).optional()}),sr=K.object({title:K.string(),content:K.string()}),QXB=K.object({existingTopics:K.array(sr),incomingTopic:sr,threshold:K.number().optional()}),BXB=K.object({existingTopics:K.array(sr).default([]),incomingTopic:sr.extend({relevanceScore:K.number().min(0).max(1).optional()}),threshold:K.number().optional()}),wXB=K.object({entities:K.array(VE).min(1),minRelevanceScore:K.number().optional()}),$XB=K.object({existingTopics:K.array(sr).optional(),entities:K.array(VE)}),DXB=K.object({entities:K.array(VE)});function IE(A,Q=""){return{id:`eval${Q}-${Date.now()}`,entityType:A.entityType,content:A.content,contentHash:RB(A.content),visibility:"public",metadata:A.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}}function gr1(A){return{title:A.title,relevanceScore:A.relevanceScore}}function fXB(A){let Q=A.metadata.title;return typeof Q==="string"?Q:A.id}function YXB(A,Q){return{...A,sources:[{id:Q.id,type:Q.entityType,title:fXB(Q)}]}}async function bP(A){let Q=await A.entityService.listEntities({entityType:qw});await Promise.all(Q.map((B)=>A.entityService.deleteEntity({entityType:qw,id:B.id})))}async function XXB(A){for(;;){if((await A.jobs.getActiveJobs(["shell:embedding"])).length===0)return;await new Promise((B)=>setTimeout(B,100))}}function Tr1(A){let{context:Q,logger:B,config:w}=A,$=new Yd0(Q,B),D=async(f,Y,X="")=>{let H=IE(f,X);return $.extractFromEntity(H,Y)};Q.eval.registerHandler("extractFromEntity",async(f)=>{await bP(Q);let Y=eYB.parse(f),X=Y.minRelevanceScore??w.minRelevanceScore,H=IE(Y);return(await $.extractFromEntity(H,X)).map((Z)=>YXB(Z,H))}),Q.eval.registerHandler("checkMergeSimilarity",async(f)=>{await bP(Q);let Y=AXB.parse(f),X=Y.minRelevanceScore??w.minRelevanceScore,H=Y.threshold??w.mergeSimilarityThreshold,[W,Z]=await Promise.all([D(Y.contentA,X,"-a"),D(Y.contentB,X,"-b")]),G=new LK(Q.entityService,B),F=[];for(let b of W){let N=await G.createTopic(b);if(N)F.push(N)}let I=(await Promise.all(Z.map(async(b)=>{let N=await G.findMergeCandidate({incoming:b,threshold:H,additionalCandidates:F});if(!N)return null;return{incomingTitle:b.title,candidateTitle:N.title,candidateScore:N.score}}))).filter((b)=>b!==null),L=I.map((b)=>b.candidateTitle);return{topicsA:W.map(gr1),topicsB:Z.map(gr1),matchingTitles:L,mergeCandidates:I,wouldMerge:I.length>0}}),Q.eval.registerHandler("detectMergeCandidate",async(f)=>{await bP(Q);let Y=QXB.parse(f),X=Y.threshold??w.mergeSimilarityThreshold,H=new LK(Q.entityService,B),W=[];for(let G of Y.existingTopics){let F=await H.createTopic(G);if(F)W.push(F)}let Z=await H.findMergeCandidate({incoming:{title:Y.incomingTopic.title},threshold:X,additionalCandidates:W});return{found:Z!==null,candidateTitle:Z?.title,candidateScore:Z?.score}}),Q.eval.registerHandler("processTopicWithAutoMerge",async(f)=>{await bP(Q);let Y=BXB.parse(f),X=new LK(Q.entityService,B);for(let G of Y.existingTopics)await X.createTopic({title:G.title,content:G.content});await XXB(Q);let H=IE({entityType:"post",content:Y.incomingTopic.content,metadata:{title:Y.incomingTopic.title}},"-source"),W=await LP([H],Q,B,{minRelevanceScore:0,autoMerge:!0,mergeSimilarityThreshold:Y.threshold??w.mergeSimilarityThreshold}),Z=await Q.entityService.listEntities({entityType:qw});return{...W,topicCount:Z.length,topics:Z.map(Dd0)}}),Q.eval.registerHandler("rebuildTopics",async(f)=>{await bP(Q);let Y=$XB.parse(f),X=new LK(Q.entityService,B);for(let G of Y.existingTopics??[])await X.createTopic(G);let H=Y.entities.map((G,F)=>IE(G,`-rebuild-${F}`)),W=await Wd0(H,Q,B,w),Z=await Q.entityService.listEntities({entityType:qw});return{...W,topicCount:Z.length,topics:Z.map(Dd0)}}),Q.eval.registerHandler("extractSequentially",async(f)=>{await bP(Q);let Y=wXB.parse(f),X=Y.minRelevanceScore??w.minRelevanceScore,H=new LK(Q.entityService,B),W=[];for(let[G,F]of Y.entities.entries()){let I=IE(F,`-sequential-${G}`),L=await $.extractFromEntity(I,X);for(let b of L)await H.createTopic({title:b.title,content:b.content});W.push({extractedTitles:L.map((b)=>b.title)})}let Z=await Q.entityService.listEntities({entityType:qw});return{totalTopics:Z.length,perEntity:W,topics:Z.map(FE)}}),Q.eval.registerHandler("batchExtract",async(f)=>{await bP(Q);let X=DXB.parse(f).entities.map((Z,G)=>IE(Z,`-batch-${G}`)),H=await LP(X,Q,B,{minRelevanceScore:w.minRelevanceScore}),W=await Q.entityService.listEntities({entityType:qw});return{...H,topics:W.map(FE)}})}var HXB=new JK;async function Sr1({entity:A,config:Q}){let B=qE.parse(A),w=HXB.parseTopicBody(B.content);return{$type:"ai.rizom.brain.topic",title:w.title,body:w.content,format:"text/markdown",...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"topic",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function Zd0(){return{entityType:"topic",collection:"ai.rizom.brain.topic",lexicon:_w["ai.rizom.brain.topic"],validate:!1,buildRecord:Sr1}}var mr1={name:"@brains/topics",private:!0,version:"0.2.0-alpha.128",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"}};var ZXB=new JK;class ur1 extends PQ{entityType=qw;schema=qE;adapter=ZXB;unregisterAtprotoProjection;sourceBatch=new Hd0;constructor(A={}){super(JP,mr1,A,Hr1)}getEntityTypeConfig(){return{weight:0.5,projectionSource:!1}}getTemplates(){return{extraction:zr1,"merge-synthesis":qr1,"topic-list":Fr1,"topic-detail":Ir1}}getDataSources(){return[new fd0(this.logger.child("TopicsDataSource"))]}getDerivedEntityProjections(A){if(!this.config.enableAutoExtraction)return[];return[{id:Bd0,targetType:qw,job:{type:Zr1,handler:vr1({context:A,logger:this.logger,config:this.config,extractAllTopics:()=>this.extractAllTopics(A),rebuildAllTopics:()=>this.rebuildAllTopics(A),sourceBatch:this.sourceBatch,isEntityPublished:(Q)=>this.isEntityPublished(Q)})},initialSync:{shouldEnqueue:async()=>!await zN(A,qw,{visibility:this.config.extractionVisibility}),jobData:{mode:"derive",reason:"initial-sync"},jobOptions:hr1()},sourceChange:{sourceTypes:this.config.includeEntityTypes,requireInitialSync:!0,jobData:(Q)=>{let B=Q.entity;if(!B)return null;if(!this.shouldProcessEntityType(B.entityType,A.entityService))return null;if(!this.isEntityPublished(B))return null;if(!uI(B.visibility,this.config.extractionVisibility))return null;return this.sourceBatch.add({entityId:B.id,entityType:B.entityType,contentHash:B.contentHash}),{mode:"source-batch"}},jobOptions:()=>({priority:5,source:xD0,delayMs:this.config.sourceChangeBatchDelayMs,deduplication:"skip",deduplicationKey:Ur1,metadata:{operationType:"data_processing",operationTarget:"topic-source-batch",pluginId:JP}})}}]}async onRegister(A){A.insights.register("topic-distribution",Lr1()),br1({context:A,pluginId:this.id}),Tr1({context:A,logger:this.logger,config:this.config}),this.unregisterAtprotoProjection=U5.getInstance().register(Zd0())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}hasRunInitialDerivation(){return this.getDerivedEntityProjectionController(Bd0)?.hasQueuedInitialSync()??!1}shouldProcessEntityType(A,Q){if(A===qw)return!1;if(!this.config.includeEntityTypes.includes(A))return!1;return Q.getEntityTypeConfig(A).projectionSource!==!1}isEntityPublished(A){let B=A.metadata.status;if(B===void 0||B===null)return!0;if(typeof B!=="string")return!1;return this.config.extractableStatuses.includes(B)}async extractAllTopics(A){await Cr1({context:A,logger:this.logger,config:this.config,shouldProcessEntityType:(Q)=>this.shouldProcessEntityType(Q,A.entityService),isEntityPublished:(Q)=>this.isEntityPublished(Q)})}async rebuildAllTopics(A){await yr1({context:A,logger:this.logger,config:this.config,shouldProcessEntityType:(Q)=>this.shouldProcessEntityType(Q,A.entityService),isEntityPublished:(Q)=>this.isEntityPublished(Q)})}}function gD0(A){return new ur1(A)}p0();K0();p0();var Kd0=K.enum(["linkedin"]),Ud0=K.enum(["generating","draft","queued","published","failed"]),cr1=K.enum(["post","deck"]),lr1=K.object({id:K.string().min(1).describe("Document entity ID")}),YW=K.object({title:K.string().describe("Short descriptive title (3-6 words) for file naming"),platform:Kd0.describe("Target platform"),status:Ud0,coverImageId:K.string().optional().describe("Image entity ID for post image"),documents:K.array(lr1).optional().describe("Document attachments for publishing"),publishedAt:K.string().datetime().optional(),platformPostId:K.string().optional().describe("ID from platform after publishing"),sourceEntityId:K.string().optional().describe("Source entity ID if auto-generated"),sourceEntityType:cr1.optional().describe("Source entity type (post, deck)")}),pr1=YW.extend({platform:Kd0.optional(),status:Ud0.optional()}),ir1=YW.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:K.string().describe("URL-friendly identifier: {platform}-{title}"),error:K.string().optional()}),RL=o1.extend({entityType:K.literal("social-post"),metadata:ir1}),TD0=RL.extend({frontmatter:YW,body:K.string()}),SD0=TD0.extend({url:K.string().optional(),listUrl:K.string().optional(),listLabel:K.string().optional(),typeLabel:K.string().optional(),coverImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()});p0();K0();class Gd0 extends V2{constructor(){super({entityType:"social-post",schema:RL,frontmatterSchema:YW,supportsCoverImage:!0})}toMarkdown(A){let Q="",B={};try{B=this.parseFrontMatter(A.content,YW),Q=this.extractBody(A.content)}catch{Q=A.content}let w={...B,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(Q,w)}fromMarkdown(A){let Q=this.parseFrontMatter(A,pr1),B=Q.platform??"linkedin",w=Q.status??"draft",$=`${B}-${Y1(Q.title)}`;return{content:A,entityType:"social-post",metadata:{title:Q.title,slug:$,platform:B,status:w,publishedAt:Q.publishedAt,platformPostId:Q.platformPostId}}}parsePostFrontmatter(A){return this.parseFrontMatter(A.content,YW)}getPostContent(A){return this.extractBody(A.content)}createPostContent(A,Q){return this.buildMarkdown(Q,A)}buildStub(A){let B={title:A.title,platform:"linkedin",status:"generating"};return{content:this.buildMarkdown("",B),metadata:{title:A.title,slug:`linkedin-${Y1(A.title)}`,platform:"linkedin",status:"generating"}}}}var x7=new Gd0;p0();p0();K0();var KXB=qU.extend({platform:K.enum(["linkedin"]).optional(),status:K.enum(["generating","draft","queued","published","failed"]).optional(),sortByQueue:K.boolean().optional(),nextInQueue:K.boolean().optional()}),UXB=FU.extend({query:KXB.optional()});function dr1(A){let Q=h2(A.content,YW);return TD0.parse({...A,frontmatter:Q.metadata,body:Q.content})}class mD0 extends W${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 Q=UXB.parse(A);return{entityType:Q.entityType??this.config.entityType,query:Q.query??{}}}transformEntity(A){return dr1(A)}buildDetailResult(A,Q){return{post:A}}buildListResult(A,Q,B){return{posts:A,totalCount:Q?.totalItems??A.length,pagination:Q,baseUrl:B.baseUrl}}async fetch(A,Q,B){let{query:w}=this.parseQuery(A),$=B.entityService;if(w.nextInQueue)return this.fetchNextInQueue(Q,$);if(w.id){let{item:W}=await this.fetchDetail(w.id,$);return Q.parse(this.buildDetailResult(W,null))}let D={};if(w.platform)D.platform=w.platform;if(w.status)D.status=w.status;let f=Object.keys(D).length>0,Y=w.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:X,pagination:H}=await this.fetchList(w,$,{...f&&{filter:{metadata:D}},sortFields:Y});return Q.parse(this.buildListResult(X,H,w))}async fetchNextInQueue(A,Q){let w=(await Q.listEntities({entityType:this.config.entityType,options:{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}}))[0],$=w?dr1(w):null;return A.parse({post:$})}}K0();var nr1=K.object({accessToken:K.string().optional(),refreshToken:K.string().optional(),organizationId:K.string().optional(),apiVersion:K.string().regex(/^\d{6}$/).optional()}),zd0=K.object({linkedin:nr1.optional(),publishInterval:K.number().default(3600000),enabled:K.boolean().default(!0),defaultPrompt:K.string().default("Create an engaging social media post that drives engagement"),maxRetries:K.number().default(3),autoGenerateOnBlogPublish:K.boolean().default(!1)});p0();K0();Cw();Fd0();import{jsxDEV as c5,Fragment as qXB}from"preact/jsx-dev-runtime";function GXB(A,Q){if(A.length<=Q)return A;return A.slice(0,Q).trim()+"..."}function zXB(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var cD0=({posts:A,pageTitle:Q,pagination:B,baseUrl:w="/social-posts"})=>{let $=Q??"Social Posts",D=B?.totalItems??A.length,f=`Browse all ${D} social ${D===1?"post":"posts"}`;return c5(qXB,{children:[c5(NQ,{title:$,description:f},void 0,!1,void 0,this),c5("div",{className:"social-post-list bg-theme",children:c5("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[c5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:$},void 0,!1,void 0,this),A.length===0?c5("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):c5("ul",{className:"space-y-6",children:A.map((Y)=>c5("li",{children:c5(uB,{href:Y.url,variant:"horizontal",children:c5("div",{className:"flex flex-col sm:flex-row gap-4",children:[Y.coverImageUrl&&c5("img",{src:Y.coverImageUrl,alt:Y.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),c5("div",{className:"flex-1 min-w-0",children:[c5("div",{className:"flex items-start justify-between gap-4 mb-2",children:[c5("h2",{className:"text-lg font-semibold text-heading",children:Y.frontmatter.title},void 0,!1,void 0,this),c5("time",{className:"text-sm text-theme-muted shrink-0",children:zXB(Y.frontmatter.publishedAt??Y.created)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c5("div",{className:"flex items-center gap-2 mb-3",children:[c5(hf,{status:Y.frontmatter.status},void 0,!1,void 0,this),c5("span",{className:"text-xs text-theme-muted uppercase",children:Y.frontmatter.platform},void 0,!1,void 0,this),c5("span",{className:"text-xs text-theme-muted font-mono",children:Y.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c5("p",{className:"text-theme leading-relaxed",children:GXB(Y.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)},Y.id,!1,void 0,this))},void 0,!1,void 0,this),B&&B.totalPages>1&&c5(i3,{currentPage:B.currentPage,totalPages:B.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 l5,Fragment as FXB}from"preact/jsx-dev-runtime";function rr1(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var lD0=({post:A})=>{let Q=`Social Post - ${A.frontmatter.platform}`,B=A.body.slice(0,160),w=[{label:"Home",href:"/"},{label:A.listLabel??"Social Posts",href:A.listUrl??"/social-posts"},{label:A.frontmatter.platform}];return l5(FXB,{children:[l5(NQ,{title:Q,description:B},void 0,!1,void 0,this),l5("section",{className:"social-post-detail",children:l5("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:l5("div",{className:"max-w-3xl mx-auto",children:[l5(PG,{items:w},void 0,!1,void 0,this),l5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:A.frontmatter.title},void 0,!1,void 0,this),l5("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[l5(hf,{status:A.frontmatter.status},void 0,!1,void 0,this),l5("span",{className:"text-sm text-theme-muted uppercase",children:A.frontmatter.platform},void 0,!1,void 0,this),l5("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&&l5(l3,{src:A.coverImageUrl,alt:A.frontmatter.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),l5(uB,{className:"p-8 mb-8",children:l5("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),l5("div",{className:"space-y-4 text-sm text-theme-muted",children:[l5("div",{children:[l5("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",rr1(A.created)]},void 0,!0,void 0,this),A.frontmatter.publishedAt&&l5("div",{children:[l5("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",rr1(A.frontmatter.publishedAt)]},void 0,!0,void 0,this),A.frontmatter.platformPostId&&l5("div",{children:l5("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 ar(A){return`social-media:${A}`}var IXB=K.union([K.boolean(),K.object({generate:K.boolean().optional(),prompt:K.string().optional()})]),Id0=K.object({prompt:K.string().optional(),platform:K.enum(["linkedin"]).optional(),sourceEntityType:K.enum(["post","deck"]).optional(),sourceEntityId:K.string().optional(),title:K.string().optional().describe("Required when content is provided directly"),content:K.string().optional(),addToQueue:K.boolean().optional(),generateImage:K.boolean().optional().describe("Auto-generate cover image for post"),coverImage:IXB.optional().describe("Generic cover image generation request")}),VXB=zY.extend({slug:K.string().optional()});class NP extends A4{constructor(A,Q){super(A,Q,{schema:Id0,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(A,Q){let B=A.platform??"linkedin",w=A.addToQueue??!1,{prompt:$,sourceEntityType:D,sourceEntityId:f}=A,{content:Y,title:X}=A;if(Y&&X)await this.reportProgress(Q,{progress:50,message:"Using provided content"});else if(Y&&!X){await this.reportProgress(Q,{progress:10,message:"Shaping content with AI"});let b=await this.context.ai.generate({prompt:Y,templateName:ar(B)});X=b.title,Y=b.content,await this.reportProgress(Q,{progress:50,message:"Social post shaped from content"})}else if(f&&D){await this.reportProgress(Q,{progress:10,message:`Fetching source ${D}`});let b=await this.context.entityService.getEntity({entityType:D,id:f});if(!b)this.failEarly(`Source entity not found: ${D}/${f}`);await this.reportProgress(Q,{progress:30,message:"Generating social post from source content"});let M=K.object({slug:K.string()}).safeParse(b.metadata),j=M.success?M.data.slug:f,g=await this.context.ai.generate({prompt:`Create an engaging ${B} post to promote this ${D}:
|
|
6758
|
+
`)}async function LP(A,Q,B,w={}){if(A.length===0)return{created:0,merged:0,skipped:0,batches:0};let $=w.minRelevanceScore??0,D=w.autoMerge??!1,f=w.mergeSimilarityThreshold??0.85,Y=w.targetVisibility??"public",X=Mr1(A),H=new LK(Q.entityService,B),W=w.topicMergeSynthesizer??new Xd0(Q,B),Z=await yD0(Q.entityService,void 0,Y),G=new Map,F=0,I=0,L=0;for(let N of X){B.info(`Processing batch of ${N.length} entities`);let M=oYB(N),j=ED0({entityTitle:`Batch of ${N.length} entities`,entityType:"batch",content:M,existingTopicTitles:Z});try{let E=(await Q.ai.generate({prompt:j,templateName:"topics:extraction"})).topics.filter((y)=>y.relevanceScore>=$);for(let y of E)try{if(D){let S=await H.findMergeCandidate({incoming:y,threshold:f,additionalCandidates:Array.from(G.values()),targetVisibility:Y});if(S){let c=await W.synthesize({existingTopic:S.topic,incomingTopic:y}),m=await H.applySynthesizedMerge({existingId:S.topic.id,synthesized:{...c,title:S.title},visibility:Y});if(!m)throw Error(`Failed to merge topic: ${y.title}`);G.set(m.id,m),I++;continue}}let h=H.getTopicIdForTitle(y.title,Y);if(G.has(h)){L++;continue}let T=await H.createTopicOptimistic({title:y.title,content:y.content,visibility:Y});if(T.topic)G.set(T.topic.id,T.topic);if(T.created)F++;else L++}catch(h){B.error("Topic batch item failed",{title:y.title,error:hA(h)})}}catch(g){B.error("Batch topic extraction failed",{batchSize:N.length,promptChars:j.length,error:hA(g)})}}let b={created:F,merged:I,skipped:L,batches:X.length};if(F>0||I>0)await Q.messaging.send({type:Kr1,payload:b,broadcast:!0});return b}p0();K0();var sYB=K.discriminatedUnion("mode",[K.object({mode:K.literal("derive"),reason:K.string().optional()}),K.object({mode:K.literal("rebuild"),reason:K.string().optional()}),K.object({mode:K.literal("source-batch"),minRelevanceScore:K.number().min(0).max(1).optional()})]);class Hd0{refs=new Map;add(A){this.refs.set(`${A.entityType}:${A.entityId}`,A)}drain(){let A=Array.from(this.refs.values());return this.refs.clear(),A}}function vr1(A){let{context:Q,logger:B,config:w}=A;return{process:async($)=>{if($.mode==="derive")return await A.extractAllTopics(),{success:!0};if($.mode==="rebuild")return await A.rebuildAllTopics(),{success:!0};return aYB({context:Q,logger:B,config:w,sourceBatch:A.sourceBatch,isEntityPublished:A.isEntityPublished,minRelevanceScore:$.minRelevanceScore??w.minRelevanceScore})},validateAndParse:($)=>{let D=sYB.safeParse($??{});return D.success?D.data:null}}}async function aYB(A){let Q=A.sourceBatch.drain(),B=await Promise.all(Q.map(async(H)=>({ref:H,entity:await A.context.entityService.getEntity({entityType:H.entityType,id:H.entityId})}))),w=0,$=0,D=0,f=0,Y=[];for(let{ref:H,entity:W}of B){if(!W){$++;continue}if(W.contentHash!==H.contentHash){w++;continue}if(!A.isEntityPublished(W)){D++;continue}if(!uI(W.visibility,A.config.extractionVisibility)){f++;continue}Y.push(W)}if(Y.length===0)return{success:!0,sources:Q.length,created:0,merged:0,skipped:0,batches:0,stale:w,missing:$,unpublished:D,hidden:f};let X=await LP(Y,A.context,A.logger,{minRelevanceScore:A.minRelevanceScore,autoMerge:A.config.autoMerge,mergeSimilarityThreshold:A.config.mergeSimilarityThreshold,targetVisibility:A.config.extractionVisibility});return{success:!0,sources:Q.length,...X,stale:w,missing:$,unpublished:D,hidden:f}}function hr1(){return{priority:5,source:xD0,deduplication:"coalesce",deduplicationKey:"topics-initial-derivation",metadata:{operationType:"data_processing",operationTarget:"topics-initial-derivation",pluginId:JP}}}async function Cr1(A){let Q=await Er1(A);if(Q.length===0){A.logger.info("No entities to extract topics from");return}A.logger.info(`Batch topic extraction: ${Q.length} entities`);let B=await LP(Q,A.context,A.logger,{minRelevanceScore:A.config.minRelevanceScore,autoMerge:A.config.autoMerge,mergeSimilarityThreshold:A.config.mergeSimilarityThreshold,targetVisibility:A.config.extractionVisibility});A.logger.info("Batch topic extraction complete",B)}async function yr1(A){let Q=await Er1(A),B=await Wd0(Q,A.context,A.logger,A.config);A.logger.info("Topic rebuild complete",B)}async function Wd0(A,Q,B,w){let $=new LK(Q.entityService,B),D=await $.listTopics({visibility:w.extractionVisibility});for(let Y of D)await $.deleteTopic(Y.id);if(A.length===0)return{deleted:D.length,created:0,merged:0,skipped:0,batches:0};let f=await LP(A,Q,B,{minRelevanceScore:w.minRelevanceScore,autoMerge:w.autoMerge,mergeSimilarityThreshold:w.mergeSimilarityThreshold,targetVisibility:w.extractionVisibility});return{deleted:D.length,...f}}async function Er1(A){let Q=tYB(A),B=[];for(let w of Q){let $=await A.context.entityService.listEntities({entityType:w,options:{filter:{visibilityScope:A.config.extractionVisibility}}});for(let D of $){if(!A.isEntityPublished(D))continue;B.push(D)}}return B}function tYB(A){return A.context.entityService.getEntityTypes().filter((B)=>A.shouldProcessEntityType(B))}var VE=K.object({entityType:K.string(),content:K.string(),metadata:K.record(K.unknown()).optional()}),eYB=VE.extend({minRelevanceScore:K.number().optional()}),AXB=K.object({contentA:VE,contentB:VE,minRelevanceScore:K.number().optional(),threshold:K.number().min(0).max(1).optional()}),sr=K.object({title:K.string(),content:K.string()}),QXB=K.object({existingTopics:K.array(sr),incomingTopic:sr,threshold:K.number().optional()}),BXB=K.object({existingTopics:K.array(sr).default([]),incomingTopic:sr.extend({relevanceScore:K.number().min(0).max(1).optional()}),threshold:K.number().optional()}),wXB=K.object({entities:K.array(VE).min(1),minRelevanceScore:K.number().optional()}),$XB=K.object({existingTopics:K.array(sr).optional(),entities:K.array(VE)}),DXB=K.object({entities:K.array(VE)});function IE(A,Q=""){return{id:`eval${Q}-${Date.now()}`,entityType:A.entityType,content:A.content,contentHash:RB(A.content),visibility:"public",metadata:A.metadata??{},created:new Date().toISOString(),updated:new Date().toISOString()}}function gr1(A){return{title:A.title,relevanceScore:A.relevanceScore}}function fXB(A){let Q=A.metadata.title;return typeof Q==="string"?Q:A.id}function YXB(A,Q){return{...A,sources:[{id:Q.id,type:Q.entityType,title:fXB(Q)}]}}async function bP(A){let Q=await A.entityService.listEntities({entityType:qw});await Promise.all(Q.map((B)=>A.entityService.deleteEntity({entityType:qw,id:B.id})))}async function XXB(A){for(;;){if((await A.jobs.getActiveJobs(["shell:embedding"])).length===0)return;await new Promise((B)=>setTimeout(B,100))}}function Tr1(A){let{context:Q,logger:B,config:w}=A,$=new Yd0(Q,B),D=async(f,Y,X="")=>{let H=IE(f,X);return $.extractFromEntity(H,Y)};Q.eval.registerHandler("extractFromEntity",async(f)=>{await bP(Q);let Y=eYB.parse(f),X=Y.minRelevanceScore??w.minRelevanceScore,H=IE(Y);return(await $.extractFromEntity(H,X)).map((Z)=>YXB(Z,H))}),Q.eval.registerHandler("checkMergeSimilarity",async(f)=>{await bP(Q);let Y=AXB.parse(f),X=Y.minRelevanceScore??w.minRelevanceScore,H=Y.threshold??w.mergeSimilarityThreshold,[W,Z]=await Promise.all([D(Y.contentA,X,"-a"),D(Y.contentB,X,"-b")]),G=new LK(Q.entityService,B),F=[];for(let b of W){let N=await G.createTopic(b);if(N)F.push(N)}let I=(await Promise.all(Z.map(async(b)=>{let N=await G.findMergeCandidate({incoming:b,threshold:H,additionalCandidates:F});if(!N)return null;return{incomingTitle:b.title,candidateTitle:N.title,candidateScore:N.score}}))).filter((b)=>b!==null),L=I.map((b)=>b.candidateTitle);return{topicsA:W.map(gr1),topicsB:Z.map(gr1),matchingTitles:L,mergeCandidates:I,wouldMerge:I.length>0}}),Q.eval.registerHandler("detectMergeCandidate",async(f)=>{await bP(Q);let Y=QXB.parse(f),X=Y.threshold??w.mergeSimilarityThreshold,H=new LK(Q.entityService,B),W=[];for(let G of Y.existingTopics){let F=await H.createTopic(G);if(F)W.push(F)}let Z=await H.findMergeCandidate({incoming:{title:Y.incomingTopic.title},threshold:X,additionalCandidates:W});return{found:Z!==null,candidateTitle:Z?.title,candidateScore:Z?.score}}),Q.eval.registerHandler("processTopicWithAutoMerge",async(f)=>{await bP(Q);let Y=BXB.parse(f),X=new LK(Q.entityService,B);for(let G of Y.existingTopics)await X.createTopic({title:G.title,content:G.content});await XXB(Q);let H=IE({entityType:"post",content:Y.incomingTopic.content,metadata:{title:Y.incomingTopic.title}},"-source"),W=await LP([H],Q,B,{minRelevanceScore:0,autoMerge:!0,mergeSimilarityThreshold:Y.threshold??w.mergeSimilarityThreshold}),Z=await Q.entityService.listEntities({entityType:qw});return{...W,topicCount:Z.length,topics:Z.map(Dd0)}}),Q.eval.registerHandler("rebuildTopics",async(f)=>{await bP(Q);let Y=$XB.parse(f),X=new LK(Q.entityService,B);for(let G of Y.existingTopics??[])await X.createTopic(G);let H=Y.entities.map((G,F)=>IE(G,`-rebuild-${F}`)),W=await Wd0(H,Q,B,w),Z=await Q.entityService.listEntities({entityType:qw});return{...W,topicCount:Z.length,topics:Z.map(Dd0)}}),Q.eval.registerHandler("extractSequentially",async(f)=>{await bP(Q);let Y=wXB.parse(f),X=Y.minRelevanceScore??w.minRelevanceScore,H=new LK(Q.entityService,B),W=[];for(let[G,F]of Y.entities.entries()){let I=IE(F,`-sequential-${G}`),L=await $.extractFromEntity(I,X);for(let b of L)await H.createTopic({title:b.title,content:b.content});W.push({extractedTitles:L.map((b)=>b.title)})}let Z=await Q.entityService.listEntities({entityType:qw});return{totalTopics:Z.length,perEntity:W,topics:Z.map(FE)}}),Q.eval.registerHandler("batchExtract",async(f)=>{await bP(Q);let X=DXB.parse(f).entities.map((Z,G)=>IE(Z,`-batch-${G}`)),H=await LP(X,Q,B,{minRelevanceScore:w.minRelevanceScore}),W=await Q.entityService.listEntities({entityType:qw});return{...H,topics:W.map(FE)}})}var HXB=new JK;async function Sr1({entity:A,config:Q}){let B=qE.parse(A),w=HXB.parseTopicBody(B.content);return{$type:"ai.rizom.brain.topic",title:w.title,body:w.content,format:"text/markdown",...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"topic",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function Zd0(){return{entityType:"topic",collection:"ai.rizom.brain.topic",lexicon:_w["ai.rizom.brain.topic"],validate:!1,buildRecord:Sr1}}var mr1={name:"@brains/topics",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","@types/node":"^20.0.0",typescript:"^5.3.3"}};var ZXB=new JK;class ur1 extends PQ{entityType=qw;schema=qE;adapter=ZXB;unregisterAtprotoProjection;sourceBatch=new Hd0;constructor(A={}){super(JP,mr1,A,Hr1)}getEntityTypeConfig(){return{weight:0.5,projectionSource:!1}}getTemplates(){return{extraction:zr1,"merge-synthesis":qr1,"topic-list":Fr1,"topic-detail":Ir1}}getDataSources(){return[new fd0(this.logger.child("TopicsDataSource"))]}getDerivedEntityProjections(A){if(!this.config.enableAutoExtraction)return[];return[{id:Bd0,targetType:qw,job:{type:Zr1,handler:vr1({context:A,logger:this.logger,config:this.config,extractAllTopics:()=>this.extractAllTopics(A),rebuildAllTopics:()=>this.rebuildAllTopics(A),sourceBatch:this.sourceBatch,isEntityPublished:(Q)=>this.isEntityPublished(Q)})},initialSync:{shouldEnqueue:async()=>!await zN(A,qw,{visibility:this.config.extractionVisibility}),jobData:{mode:"derive",reason:"initial-sync"},jobOptions:hr1()},sourceChange:{sourceTypes:this.config.includeEntityTypes,requireInitialSync:!0,jobData:(Q)=>{let B=Q.entity;if(!B)return null;if(!this.shouldProcessEntityType(B.entityType,A.entityService))return null;if(!this.isEntityPublished(B))return null;if(!uI(B.visibility,this.config.extractionVisibility))return null;return this.sourceBatch.add({entityId:B.id,entityType:B.entityType,contentHash:B.contentHash}),{mode:"source-batch"}},jobOptions:()=>({priority:5,source:xD0,delayMs:this.config.sourceChangeBatchDelayMs,deduplication:"skip",deduplicationKey:Ur1,metadata:{operationType:"data_processing",operationTarget:"topic-source-batch",pluginId:JP}})}}]}async onRegister(A){A.insights.register("topic-distribution",Lr1()),br1({context:A,pluginId:this.id}),Tr1({context:A,logger:this.logger,config:this.config}),this.unregisterAtprotoProjection=U5.getInstance().register(Zd0())}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}hasRunInitialDerivation(){return this.getDerivedEntityProjectionController(Bd0)?.hasQueuedInitialSync()??!1}shouldProcessEntityType(A,Q){if(A===qw)return!1;if(!this.config.includeEntityTypes.includes(A))return!1;return Q.getEntityTypeConfig(A).projectionSource!==!1}isEntityPublished(A){let B=A.metadata.status;if(B===void 0||B===null)return!0;if(typeof B!=="string")return!1;return this.config.extractableStatuses.includes(B)}async extractAllTopics(A){await Cr1({context:A,logger:this.logger,config:this.config,shouldProcessEntityType:(Q)=>this.shouldProcessEntityType(Q,A.entityService),isEntityPublished:(Q)=>this.isEntityPublished(Q)})}async rebuildAllTopics(A){await yr1({context:A,logger:this.logger,config:this.config,shouldProcessEntityType:(Q)=>this.shouldProcessEntityType(Q,A.entityService),isEntityPublished:(Q)=>this.isEntityPublished(Q)})}}function gD0(A){return new ur1(A)}p0();K0();p0();var Kd0=K.enum(["linkedin"]),Ud0=K.enum(["generating","draft","queued","published","failed"]),cr1=K.enum(["post","deck"]),lr1=K.object({id:K.string().min(1).describe("Document entity ID")}),YW=K.object({title:K.string().describe("Short descriptive title (3-6 words) for file naming"),platform:Kd0.describe("Target platform"),status:Ud0,coverImageId:K.string().optional().describe("Image entity ID for post image"),documents:K.array(lr1).optional().describe("Document attachments for publishing"),publishedAt:K.string().datetime().optional(),platformPostId:K.string().optional().describe("ID from platform after publishing"),sourceEntityId:K.string().optional().describe("Source entity ID if auto-generated"),sourceEntityType:cr1.optional().describe("Source entity type (post, deck)")}),pr1=YW.extend({platform:Kd0.optional(),status:Ud0.optional()}),ir1=YW.pick({title:!0,platform:!0,status:!0,publishedAt:!0,platformPostId:!0}).extend({slug:K.string().describe("URL-friendly identifier: {platform}-{title}"),error:K.string().optional()}),RL=o1.extend({entityType:K.literal("social-post"),metadata:ir1}),TD0=RL.extend({frontmatter:YW,body:K.string()}),SD0=TD0.extend({url:K.string().optional(),listUrl:K.string().optional(),listLabel:K.string().optional(),typeLabel:K.string().optional(),coverImageUrl:K.string().optional(),coverImageWidth:K.number().optional(),coverImageHeight:K.number().optional()});p0();K0();class Gd0 extends V2{constructor(){super({entityType:"social-post",schema:RL,frontmatterSchema:YW,supportsCoverImage:!0})}toMarkdown(A){let Q="",B={};try{B=this.parseFrontMatter(A.content,YW),Q=this.extractBody(A.content)}catch{Q=A.content}let w={...B,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(Q,w)}fromMarkdown(A){let Q=this.parseFrontMatter(A,pr1),B=Q.platform??"linkedin",w=Q.status??"draft",$=`${B}-${Y1(Q.title)}`;return{content:A,entityType:"social-post",metadata:{title:Q.title,slug:$,platform:B,status:w,publishedAt:Q.publishedAt,platformPostId:Q.platformPostId}}}parsePostFrontmatter(A){return this.parseFrontMatter(A.content,YW)}getPostContent(A){return this.extractBody(A.content)}createPostContent(A,Q){return this.buildMarkdown(Q,A)}buildStub(A){let B={title:A.title,platform:"linkedin",status:"generating"};return{content:this.buildMarkdown("",B),metadata:{title:A.title,slug:`linkedin-${Y1(A.title)}`,platform:"linkedin",status:"generating"}}}}var x7=new Gd0;p0();p0();K0();var KXB=qU.extend({platform:K.enum(["linkedin"]).optional(),status:K.enum(["generating","draft","queued","published","failed"]).optional(),sortByQueue:K.boolean().optional(),nextInQueue:K.boolean().optional()}),UXB=FU.extend({query:KXB.optional()});function dr1(A){let Q=h2(A.content,YW);return TD0.parse({...A,frontmatter:Q.metadata,body:Q.content})}class mD0 extends W${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 Q=UXB.parse(A);return{entityType:Q.entityType??this.config.entityType,query:Q.query??{}}}transformEntity(A){return dr1(A)}buildDetailResult(A,Q){return{post:A}}buildListResult(A,Q,B){return{posts:A,totalCount:Q?.totalItems??A.length,pagination:Q,baseUrl:B.baseUrl}}async fetch(A,Q,B){let{query:w}=this.parseQuery(A),$=B.entityService;if(w.nextInQueue)return this.fetchNextInQueue(Q,$);if(w.id){let{item:W}=await this.fetchDetail(w.id,$);return Q.parse(this.buildDetailResult(W,null))}let D={};if(w.platform)D.platform=w.platform;if(w.status)D.status=w.status;let f=Object.keys(D).length>0,Y=w.sortByQueue?[{field:"queueOrder",direction:"asc"}]:this.config.defaultSort,{items:X,pagination:H}=await this.fetchList(w,$,{...f&&{filter:{metadata:D}},sortFields:Y});return Q.parse(this.buildListResult(X,H,w))}async fetchNextInQueue(A,Q){let w=(await Q.listEntities({entityType:this.config.entityType,options:{filter:{metadata:{status:"queued"}},sortFields:[{field:"queueOrder",direction:"asc"}],limit:1}}))[0],$=w?dr1(w):null;return A.parse({post:$})}}K0();var nr1=K.object({accessToken:K.string().optional(),refreshToken:K.string().optional(),organizationId:K.string().optional(),apiVersion:K.string().regex(/^\d{6}$/).optional()}),zd0=K.object({linkedin:nr1.optional(),publishInterval:K.number().default(3600000),enabled:K.boolean().default(!0),defaultPrompt:K.string().default("Create an engaging social media post that drives engagement"),maxRetries:K.number().default(3),autoGenerateOnBlogPublish:K.boolean().default(!1)});p0();K0();Cw();Fd0();import{jsxDEV as c5,Fragment as qXB}from"preact/jsx-dev-runtime";function GXB(A,Q){if(A.length<=Q)return A;return A.slice(0,Q).trim()+"..."}function zXB(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}var cD0=({posts:A,pageTitle:Q,pagination:B,baseUrl:w="/social-posts"})=>{let $=Q??"Social Posts",D=B?.totalItems??A.length,f=`Browse all ${D} social ${D===1?"post":"posts"}`;return c5(qXB,{children:[c5(NQ,{title:$,description:f},void 0,!1,void 0,this),c5("div",{className:"social-post-list bg-theme",children:c5("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[c5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:$},void 0,!1,void 0,this),A.length===0?c5("p",{className:"text-theme-muted italic",children:"No social posts yet."},void 0,!1,void 0,this):c5("ul",{className:"space-y-6",children:A.map((Y)=>c5("li",{children:c5(uB,{href:Y.url,variant:"horizontal",children:c5("div",{className:"flex flex-col sm:flex-row gap-4",children:[Y.coverImageUrl&&c5("img",{src:Y.coverImageUrl,alt:Y.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),c5("div",{className:"flex-1 min-w-0",children:[c5("div",{className:"flex items-start justify-between gap-4 mb-2",children:[c5("h2",{className:"text-lg font-semibold text-heading",children:Y.frontmatter.title},void 0,!1,void 0,this),c5("time",{className:"text-sm text-theme-muted shrink-0",children:zXB(Y.frontmatter.publishedAt??Y.created)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c5("div",{className:"flex items-center gap-2 mb-3",children:[c5(hf,{status:Y.frontmatter.status},void 0,!1,void 0,this),c5("span",{className:"text-xs text-theme-muted uppercase",children:Y.frontmatter.platform},void 0,!1,void 0,this),c5("span",{className:"text-xs text-theme-muted font-mono",children:Y.id},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c5("p",{className:"text-theme leading-relaxed",children:GXB(Y.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)},Y.id,!1,void 0,this))},void 0,!1,void 0,this),B&&B.totalPages>1&&c5(i3,{currentPage:B.currentPage,totalPages:B.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 l5,Fragment as FXB}from"preact/jsx-dev-runtime";function rr1(A){return new Date(A).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}var lD0=({post:A})=>{let Q=`Social Post - ${A.frontmatter.platform}`,B=A.body.slice(0,160),w=[{label:"Home",href:"/"},{label:A.listLabel??"Social Posts",href:A.listUrl??"/social-posts"},{label:A.frontmatter.platform}];return l5(FXB,{children:[l5(NQ,{title:Q,description:B},void 0,!1,void 0,this),l5("section",{className:"social-post-detail",children:l5("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:l5("div",{className:"max-w-3xl mx-auto",children:[l5(PG,{items:w},void 0,!1,void 0,this),l5("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-4",children:A.frontmatter.title},void 0,!1,void 0,this),l5("div",{className:"flex flex-wrap items-center gap-3 mb-6",children:[l5(hf,{status:A.frontmatter.status},void 0,!1,void 0,this),l5("span",{className:"text-sm text-theme-muted uppercase",children:A.frontmatter.platform},void 0,!1,void 0,this),l5("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&&l5(l3,{src:A.coverImageUrl,alt:A.frontmatter.title,width:A.coverImageWidth,height:A.coverImageHeight,className:"mb-8"},void 0,!1,void 0,this),l5(uB,{className:"p-8 mb-8",children:l5("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),l5("div",{className:"space-y-4 text-sm text-theme-muted",children:[l5("div",{children:[l5("span",{className:"font-medium",children:"Created:"},void 0,!1,void 0,this)," ",rr1(A.created)]},void 0,!0,void 0,this),A.frontmatter.publishedAt&&l5("div",{children:[l5("span",{className:"font-medium",children:"Published:"},void 0,!1,void 0,this)," ",rr1(A.frontmatter.publishedAt)]},void 0,!0,void 0,this),A.frontmatter.platformPostId&&l5("div",{children:l5("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 ar(A){return`social-media:${A}`}var IXB=K.union([K.boolean(),K.object({generate:K.boolean().optional(),prompt:K.string().optional()})]),Id0=K.object({prompt:K.string().optional(),platform:K.enum(["linkedin"]).optional(),sourceEntityType:K.enum(["post","deck"]).optional(),sourceEntityId:K.string().optional(),title:K.string().optional().describe("Required when content is provided directly"),content:K.string().optional(),addToQueue:K.boolean().optional(),generateImage:K.boolean().optional().describe("Auto-generate cover image for post"),coverImage:IXB.optional().describe("Generic cover image generation request")}),VXB=zY.extend({slug:K.string().optional()});class NP extends A4{constructor(A,Q){super(A,Q,{schema:Id0,jobTypeName:"social-post-generation",entityType:"social-post"})}async generate(A,Q){let B=A.platform??"linkedin",w=A.addToQueue??!1,{prompt:$,sourceEntityType:D,sourceEntityId:f}=A,{content:Y,title:X}=A;if(Y&&X)await this.reportProgress(Q,{progress:50,message:"Using provided content"});else if(Y&&!X){await this.reportProgress(Q,{progress:10,message:"Shaping content with AI"});let b=await this.context.ai.generate({prompt:Y,templateName:ar(B)});X=b.title,Y=b.content,await this.reportProgress(Q,{progress:50,message:"Social post shaped from content"})}else if(f&&D){await this.reportProgress(Q,{progress:10,message:`Fetching source ${D}`});let b=await this.context.entityService.getEntity({entityType:D,id:f});if(!b)this.failEarly(`Source entity not found: ${D}/${f}`);await this.reportProgress(Q,{progress:30,message:"Generating social post from source content"});let M=K.object({slug:K.string()}).safeParse(b.metadata),j=M.success?M.data.slug:f,g=await this.context.ai.generate({prompt:`Create an engaging ${B} post to promote this ${D}:
|
|
6759
6759
|
|
|
6760
6760
|
Source: ${D}/${j}
|
|
6761
6761
|
|
|
6762
6762
|
${b.content}`,templateName:ar(B)});X=g.title,Y=g.content,await this.reportProgress(Q,{progress:50,message:"Social post generated from source"})}else if($){await this.reportProgress(Q,{progress:10,message:"Generating social post with AI"});let b=await this.context.ai.generate({prompt:$,templateName:ar(B)});X=b.title,Y=b.content,await this.reportProgress(Q,{progress:50,message:"Social post generated"})}else this.failEarly("No content source provided (prompt, sourceEntityId, or content)");if(!Y||!X)this.failEarly("Content or title was not generated");let W={title:X,platform:B,status:w?"queued":"draft",...f&&{sourceEntityId:f},...D&&{sourceEntityType:D}},Z=x7.createPostContent(W,Y),F=x7.fromMarkdown(Z).metadata;if(!F)this.failEarly("Failed to parse social post metadata");let I=await Gq({entityType:"social-post",title:X,deriveId:(b)=>`${B}-${Y1(b)}`,regeneratePrompt:"Generate a different social media post title on the same topic.",context:this.context}),L=Z;if(I!==X){F.title=I,F.slug=`${B}-${Y1(I)}`;let b={...W,title:I};L=x7.createPostContent(b,Y)}return{id:F.slug,content:L,metadata:F,title:I,resultExtras:{slug:F.slug},createOptions:{deduplicateId:!0}}}async onGenerationFailure(A,Q){await this.context.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:Q}})}async afterCreate(A,Q,B,w){if(A.generateImage){await this.reportProgress(B,{progress:90,message:"Queueing image generation"});let $=w.title??"Social Post";await this.context.jobs.enqueue({type:"image:image-generate",data:{prompt:`Social media graphic for: ${$}`,title:`${$} Image`,aspectRatio:"16:9",targetEntityType:"social-post",targetEntityId:Q},toolContext:{interfaceType:"job",userId:"system"}})}await this.context.messaging.send({type:"generate:report:success",payload:{entityType:"social-post",entityId:Q}})}summarizeDataForLog(A){return{platform:A.platform??"linkedin",hasPrompt:!!A.prompt,sourceEntityType:A.sourceEntityType,addToQueue:A.addToQueue??!1,generateImage:A.generateImage??!1,coverImage:!!A.coverImage}}}function tr(A){if(A.length<=200)return A;return`${A.slice(0,200)}\u2026 (truncated, ${A.length} bytes)`}function JXB(A){let Q={status:"READY",media:A.urn};if(A.title)Q.title={text:A.title};return Q}function LXB(A){if(!Vd0(A))return null;let Q=pD0(A,"value");if(!Q)return null;let B=pD0(Q,"uploadMechanism");if(!B)return null;let w=pD0(B,"com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest");if(!w)return null;let $=w.uploadUrl,D=Q.asset;if(typeof $!=="string"||typeof D!=="string")return null;return{uploadUrl:$,assetUrn:D}}function bXB(A){if(!Vd0(A))return null;let Q=pD0(A,"value");if(!Q)return null;let{uploadUrl:B,document:w}=Q;if(typeof B!=="string"||typeof w!=="string")return null;return{uploadUrl:B,documentUrn:w}}function pD0(A,Q){let B=A[Q];return Vd0(B)?B:null}function Vd0(A){return typeof A==="object"&&A!==null}var NXB="202604";class Jd0{config;logger;name="linkedin";apiBaseUrl="https://api.linkedin.com/v2";restApiBaseUrl="https://api.linkedin.com/rest";fetch;cachedUserId=null;constructor(A,Q,B={}){this.config=A;this.logger=Q;this.fetch=B.fetch??globalThis.fetch.bind(globalThis)}async publish(A,Q,B,w){if(!this.config.accessToken)throw Error("LinkedIn access token not configured");let $=await this.getAuthor(),D=w?.[0];if(w&&w.length>1)this.logger.warn("LinkedIn document publishing supports one PDF",{count:w.length});let f=null;if(D){let Z=await this.uploadDocument($,D);return this.publishDocumentPost($,A,Z,D.filename)}else if(B){let Z=await this.uploadImage($,B);if(Z)f={category:"IMAGE",urn:Z}}let Y={shareCommentary:{text:A},shareMediaCategory:f?.category??"NONE",...f&&{media:[JXB(f)]}},X=await this.fetch(`${this.apiBaseUrl}/ugcPosts`,{method:"POST",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0"},body:JSON.stringify({author:$,lifecycleState:"PUBLISHED",specificContent:{"com.linkedin.ugc.ShareContent":Y},visibility:{"com.linkedin.ugc.MemberNetworkVisibility":"PUBLIC"}})});if(!X.ok){let Z=tr(await X.text());throw this.logger.error("LinkedIn API error",{status:X.status,error:Z}),Error(`LinkedIn API error: ${X.status} - ${Z}`)}let H=X.headers.get("X-RestLi-Id")??"";this.logger.info("LinkedIn post created",{postId:H,mediaCategory:f?.category??"NONE"});let W={id:H};if(H)W.url=`https://www.linkedin.com/feed/update/${H}`;return W}getRestHeaders(){return{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json","Linkedin-Version":this.config.apiVersion??NXB,"X-Restli-Protocol-Version":"2.0.0"}}async uploadImage(A,Q){try{let B=await this.fetch(`${this.apiBaseUrl}/assets?action=registerUpload`,{method:"POST",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":"application/json","X-Restli-Protocol-Version":"2.0.0"},body:JSON.stringify({registerUploadRequest:{recipes:["urn:li:digitalmediaRecipe:feedshare-image"],owner:A,serviceRelationships:[{relationshipType:"OWNER",identifier:"urn:li:userGeneratedContent"}]}})});if(!B.ok){let Y=tr(await B.text());return this.logger.warn("LinkedIn image upload registration failed",{status:B.status,error:Y}),null}let w=LXB(await B.json());if(!w)return this.logger.warn("LinkedIn image upload registration was malformed"),null;let{uploadUrl:$,assetUrn:D}=w,f=await this.fetch($,{method:"PUT",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":Q.mimeType},body:new Uint8Array(Q.data)});if(!f.ok)return this.logger.warn("LinkedIn image binary upload failed",{status:f.status}),null;return this.logger.info("LinkedIn image uploaded",{assetUrn:D}),D}catch(B){return this.logger.warn("LinkedIn image upload error",{error:B}),null}}async uploadDocument(A,Q){let B=await this.fetch(`${this.restApiBaseUrl}/documents?action=initializeUpload`,{method:"POST",headers:this.getRestHeaders(),body:JSON.stringify({initializeUploadRequest:{owner:A}})});if(!B.ok){let D=tr(await B.text());throw Error(`LinkedIn document upload initialization failed: ${B.status} - ${D}`)}let w=bXB(await B.json());if(!w)throw Error("LinkedIn document upload initialization was malformed");let $=await this.fetch(w.uploadUrl,{method:"PUT",headers:{Authorization:`Bearer ${this.config.accessToken}`,"Content-Type":Q.mimeType},body:new Uint8Array(Q.data)});if(!$.ok)throw Error(`LinkedIn document binary upload failed: ${$.status}`);return this.logger.info("LinkedIn document uploaded",{documentUrn:w.documentUrn,filename:Q.filename}),w.documentUrn}async publishDocumentPost(A,Q,B,w){let $=await this.fetch(`${this.restApiBaseUrl}/posts`,{method:"POST",headers:this.getRestHeaders(),body:JSON.stringify({author:A,commentary:Q,visibility:"PUBLIC",distribution:{feedDistribution:"MAIN_FEED",targetEntities:[],thirdPartyDistributionChannels:[]},content:{media:{id:B,title:w}},lifecycleState:"PUBLISHED",isReshareDisabledByAuthor:!1})});if(!$.ok){let Y=tr(await $.text());throw this.logger.error("LinkedIn document post API error",{status:$.status,error:Y}),Error(`LinkedIn document post API error: ${$.status} - ${Y}`)}let D=$.headers.get("X-RestLi-Id")??"";this.logger.info("LinkedIn document post created",{postId:D,documentUrn:B});let f={id:D};if(D)f.url=`https://www.linkedin.com/feed/update/${D}`;return f}async validateCredentials(){if(!this.config.accessToken)return!1;try{if(this.config.organizationId)return(await this.fetch(`${this.apiBaseUrl}/organizations/${this.config.organizationId}`,{headers:{Authorization:`Bearer ${this.config.accessToken}`}})).ok;return await this.getUserId(),!0}catch{return!1}}async getAuthor(){if(this.config.organizationId)return`urn:li:organization:${this.config.organizationId}`;return this.getUserId()}async getUserId(){if(this.cachedUserId)return this.cachedUserId;if(!this.config.accessToken)throw Error("LinkedIn access token not configured");try{let B=await this.fetch("https://api.linkedin.com/v2/userinfo",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(B.ok){let w=await B.json();return this.cachedUserId=`urn:li:person:${w.sub}`,this.cachedUserId}}catch{}let A=await this.fetch("https://api.linkedin.com/v2/me",{headers:{Authorization:`Bearer ${this.config.accessToken}`}});if(!A.ok){let B=tr(await A.text());throw Error(`Failed to get LinkedIn user ID: ${A.status} - ${B}`)}let Q=await A.json();return this.cachedUserId=`urn:li:person:${Q.id}`,this.cachedUserId}}function Ld0(A,Q,B={}){return new Jd0(A,Q,B)}p0();K0();Jw();Fd0();var jXB=K.object({posts:K.array(SD0),totalCount:K.number().optional(),pagination:e7.nullable(),baseUrl:K.string().optional()}),_XB=K.object({post:SD0});function or1(){return{linkedin:uD0,"social-post-list":R1({name:"social-post-list",description:"Social post list page template",schema:jXB,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:cD0}}),"social-post-detail":R1({name:"social-post-detail",description:"Individual social post template",schema:_XB,dataSourceId:"social-media:posts",requiredPermission:"public",layout:{component:lD0}})}}K0();var MXB=K.object({prompt:K.string().optional(),content:K.string().optional(),platform:K.enum(["linkedin"]).default("linkedin")}),PXB=K.object({prompt:K.string().optional(),content:K.string().optional(),title:K.string().optional(),platform:K.enum(["linkedin"]).optional()});function sr1(A){A.eval.registerHandler("generation",async(Q)=>{let B=MXB.parse(Q),w=B.content?`Create an engaging LinkedIn post to share this content:
|
|
6763
6763
|
|
|
6764
|
-
${B.content}`:B.prompt??"Write an engaging LinkedIn post";return A.ai.generate({prompt:w,templateName:`social-media:${B.platform}`})}),A.eval.registerHandler("create",async(Q)=>{let B=PXB.parse(Q),w=[],$=D7.from(async(H)=>{let W={progress:H.progress};if(H.message!==void 0)W.message=H.message;w.push(W)});if(!$)throw Error("Failed to create progress reporter");let f=await new NP(A.logger,A).process(B,`eval-${Date.now()}`,$),Y=!1,X;if(f.success&&f.entityId){let H=await A.entityService.getEntity({entityType:"social-post",id:f.entityId});Y=!!H,X=H?.content.slice(0,300)}return{...f,entityExists:Y,entityPreview:X,progressSteps:w}})}K0();p0();class er{sendMessage;logger;entityService;providers;permissions;resolveAttachment;constructor(A){this.sendMessage=A.sendMessage,this.logger=A.logger,this.entityService=A.entityService,this.providers=A.providers,this.permissions=A.permissions,this.resolveAttachment=A.resolveAttachment}async handle(A){let{entityType:Q,entityId:B}=A;if(Q!=="social-post")return;this.permissions.assertEntityActionAllowed(Q,"publish",A.authContext??{userPermissionLevel:"anchor"}),this.logger.debug("Handling publish:execute",{entityId:B});try{let w=await this.entityService.getEntity({entityType:"social-post",id:B});if(!w){await this.reportFailure(Q,B,`Post not found: ${B}`);return}let $=w;if($.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:B});return}let D=$.metadata.platform,f=this.providers.get(D);if(!f){await this.reportFailure(Q,B,`No provider configured for platform: ${D}`);return}let Y=h2($.content,YW),X;if(Y.metadata.coverImageId)X=await this.fetchImageData(Y.metadata.coverImageId);let H=Y.metadata.documents??[],W=await this.fetchDocumentData(H);try{if(H.length>0&&W.length===0)throw Error(`Refusing to publish: ${H.length} document(s) referenced but none could be fetched`);let Z=H.length===0?await this.resolveSourceAttachment(Y.metadata):[],G=W.length>0?W:Z,F=G.length?await f.publish(Y.content,$.metadata,X,G):await f.publish(Y.content,$.metadata,X),I=new Date().toISOString(),L=F.id||void 0,b={...Y.metadata,status:"published",publishedAt:I,...L&&{platformPostId:L}},N=x7.createPostContent(b,Y.content);await this.entityService.updateEntity({entity:{...$,content:N,metadata:{...$.metadata,status:"published",publishedAt:I,platformPostId:L}}}),await this.reportSuccess(Q,B,F.id),this.logger.info(`Post published successfully: ${B}`,{platform:D,platformPostId:L})}catch(Z){let G=Z instanceof Error?Z.message:String(Z),F={...Y.metadata,status:"failed"},I=x7.createPostContent(F,Y.content);await this.entityService.updateEntity({entity:{...$,content:I,metadata:{...$.metadata,status:"failed"}}}),await this.reportFailure(Q,B,G),this.logger.error(`Post publish failed: ${B}`,{platform:D,error:G})}}catch(w){let $=hA(w);this.logger.error("Unexpected error in publish handler",{entityId:B,error:$}),await this.reportFailure(Q,B,$)}}async reportSuccess(A,Q,B){await this.sendMessage({type:"publish:report:success",payload:{entityType:A,entityId:Q,result:{id:B}}})}async reportFailure(A,Q,B){await this.sendMessage({type:"publish:report:failure",payload:{entityType:A,entityId:Q,error:B}})}async resolveSourceAttachment(A){if(!this.resolveAttachment||!A.sourceEntityType||!A.sourceEntityId)return[];let Q=await this.resolveAttachment({sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:"carousel"});return Q?[Q]:[]}async fetchDocumentData(A){if(!A?.length)return[];let Q=[];for(let B of A){let w=await this.fetchSingleDocumentData(B.id);if(w)Q.push(w)}return Q}async fetchSingleDocumentData(A){try{let Q=await this.entityService.getEntity({entityType:"document",id:A});if(!Q){this.logger.warn("Document not found",{documentId:A});return}let B=Q.content.match(/^data:application\/pdf;base64,(.+)$/);if(!B?.[1]){this.logger.warn("Invalid document data URL format",{documentId:A});return}let w=typeof Q.metadata.filename==="string"?Q.metadata.filename:`${A}.pdf`;return{type:"document",data:Buffer.from(B[1],"base64"),mimeType:"application/pdf",filename:w}}catch(Q){this.logger.warn("Failed to fetch document",{documentId:A,error:Q});return}}async fetchImageData(A){try{let Q=await this.entityService.getEntity({entityType:"image",id:A});if(!Q){this.logger.warn("Cover image not found",{imageId:A});return}let w=Q.content.match(/^data:([^;]+);base64,(.+)$/);if(!w?.[1]||!w[2]){this.logger.warn("Invalid image data URL format",{imageId:A});return}let $=w[1],D=w[2];return{data:Buffer.from(D,"base64"),mimeType:$}}catch(Q){this.logger.warn("Failed to fetch cover image",{imageId:A,error:Q});return}}}function ar1(A,Q,B){if(Q.size===0){B.debug("No providers configured, skipping publish-pipeline registration");return}A.messaging.subscribe("system:plugins:ready",async()=>{let w=Q.values().next().value;return await A.messaging.send({type:"publish:register",payload:{entityType:"social-post",provider:w,config:{publishResultIdField:"platformPostId"}}}),B.info("Registered social-post with publish-pipeline"),{success:!0}})}function tr1(A,Q,B){let w=new er({sendMessage:A.messaging.send,logger:B.child("PublishExecuteHandler"),entityService:A.entityService,providers:Q,permissions:A.permissions,resolveAttachment:A.attachments.resolve});A.messaging.subscribe("publish:execute",async($)=>{return await w.handle($.payload),{success:!0}}),B.debug("Subscribed to publish:execute messages")}K0();function er1(A,Q){A.messaging.subscribe("entity:updated",async(B)=>{let{entityType:w,entityId:$,entity:D}=B.payload;if(w!=="post")return{success:!0};if(D.metadata?.status!=="queued")return{success:!0};try{if((await A.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:$}},limit:1}})).length>0)return Q.debug(`Social post already exists for ${$}, skipping auto-generate`),{success:!0};return await A.messaging.send({type:"social:auto-generate",payload:{sourceEntityType:w,sourceEntityId:$,platform:"linkedin"}}),Q.info(`Auto-generate social post triggered for queued post ${$}`),{success:!0}}catch(Y){let X=hA(Y);return Q.error(`Failed to trigger auto-generate for ${$}:`,{error:X}),{success:!0}}}),Q.debug("Subscribed to entity:updated for auto-generation")}function Ao1(A,Q){A.messaging.subscribe("social:auto-generate",async(B)=>{let{sourceEntityType:w,sourceEntityId:$,platform:D}=B.payload;try{let f=await A.jobs.enqueue({type:`${x7.entityType}:generation`,data:{sourceEntityType:w,sourceEntityId:$,platform:D,addToQueue:!1},toolContext:{interfaceType:"job",userId:"system"}});return Q.info(`Social post generation job enqueued for ${w}/${$}`,{jobId:f}),{success:!0,jobId:f}}catch(f){let Y=hA(f);return Q.error(`Failed to enqueue social post generation for ${$}:`,{error:Y}),{success:!1}}}),Q.debug("Subscribed to social:auto-generate messages")}function Qo1(A,Q){A.messaging.subscribe("generate:execute",async(B)=>{let{entityType:w}=B.payload;if(w!=="social-post")return{success:!0};Q.info("Received generate:execute for social-post");try{let $=await A.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:5}});if($.length===0)return Q.info("No published posts found for social post generation"),await A.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:"No published posts available for social post generation"}}),{success:!0};let D=null;for(let Y of $)if((await A.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:Y.id}},limit:1}})).length===0){D=Y;break}if(!D)return Q.info("All recent posts already have social posts"),await A.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:"All recent posts already have social posts generated"}}),{success:!0};let f=await A.jobs.enqueue({type:`${x7.entityType}:generation`,data:{sourceEntityType:"post",sourceEntityId:D.id,platform:"linkedin",addToQueue:!1},toolContext:{interfaceType:"job",userId:"system"}});return Q.info("Social post generation job queued",{jobId:f,sourcePostId:D.id}),{success:!0}}catch($){let D=hA($);return Q.error("Failed to handle generate:execute:",{error:D}),await A.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:D}}),{success:!0}}}),Q.debug("Subscribed to generate:execute messages")}async function Bo1({entity:A,config:Q}){let B=RL.parse(A),w=x7.parsePostFrontmatter(B),$=x7.getPostContent(B);return{$type:"ai.rizom.brain.socialPost",title:w.title,platform:w.platform,body:$,format:"text/markdown",status:w.status,...w.publishedAt&&{publishedAt:w.publishedAt},...w.platformPostId&&{platformPostId:w.platformPostId},...w.sourceEntityType&&{sourceLocalEntityType:w.sourceEntityType},...w.sourceEntityId&&{sourceLocalEntityId:w.sourceEntityId},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"social-post",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function bd0(){return{entityType:"social-post",collection:"ai.rizom.brain.socialPost",lexicon:_w["ai.rizom.brain.socialPost"],validate:!1,buildRecord:Bo1}}var wo1={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.128",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/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@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 Nd0 extends PQ{entityType=x7.entityType;schema=RL;adapter=x7;providers=new Map;unregisterAtprotoProjection;constructor(A){super("social-media",wo1,A,zd0)}createGenerationHandler(A){return new NP(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return or1()}getDataSources(){return[new mD0(this.logger.child("SocialPostDataSource"))]}getEntityTypeConfig(){return{publish:{publishStatuses:["queued","published","failed"]}}}async onRegister(A){if(this.initializeProviders(),ar1(A,this.providers,this.logger),tr1(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)er1(A,this.logger),Ao1(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");Qo1(A,this.logger),sr1(A),this.unregisterAtprotoProjection=U5.getInstance().register(bd0()),this.logger.info("Social media plugin registered successfully")}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}initializeProviders(){if(this.config.linkedin?.accessToken){let A=Ld0(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function Ao(A){return new Nd0(A)}K0();var OXB=K.enum(["draft","queued","published","failed"]),$o1=K.object({status:OXB.default("draft"),queueOrder:K.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:K.string().datetime().optional()});class jd0{name="internal";async publish(A,Q){return{id:"internal"}}}var Qo={interfaceType:"system",userId:"system",userPermissionLevel:"anchor",authorization:"system"},xD={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",QUEUED:"publish:queued",COMPLETED:"publish:completed",FAILED:"publish:failed",LIST_RESPONSE:"publish:list:response"},vL={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"},Do1={REGISTER:"publish-assets:register"};K0();var xXB=K.enum(["provider"]),fo1=K.object({executionMode:xXB.optional(),publishResultIdField:K.string().min(1).optional(),publishTimestampField:K.string().min(1).optional(),enabled:K.boolean().optional()}).strict();var RXB=K.object({skipIfDraftExists:K.boolean().optional(),minSourceEntities:K.number().optional(),maxUnpublishedDrafts:K.number().optional(),sourceEntityType:K.string().optional()}),Yo1=K.object({entitySchedules:K.record(K.string(),K.string()).optional(),generationSchedules:K.record(K.string(),K.string()).optional(),generationConditions:K.record(K.string(),RXB).optional()});class aG{static instance=null;queues=new Map;static getInstance(){return aG.instance??=new aG,aG.instance}static resetInstance(){aG.instance=null}static createFresh(){return new aG}constructor(){}async add(A,Q,B=Qo){let w=this.getOrCreateQueue(A),$=w.find((Y)=>Y.entityId===Q);if($)return{position:$.position};let D=w.length+1,f={entityId:Q,entityType:A,position:D,queuedAt:new Date().toISOString(),authContext:{...B}};return w.push(f),{position:D}}async remove(A,Q){let B=this.queues.get(A);if(!B)return;let w=B.findIndex(($)=>$.entityId===Q);if(w===-1)return;B.splice(w,1),this.recalculatePositions(B)}async reorder(A,Q,B){let w=this.queues.get(A);if(!w)return;let $=w.findIndex((Y)=>Y.entityId===Q);if($===-1)return;let[D]=w.splice($,1);if(!D)return;let f=Math.max(0,Math.min(B-1,w.length));w.splice(f,0,D),this.recalculatePositions(w)}async list(A){let Q=this.queues.get(A);if(!Q)return[];return[...Q]}async getNext(A){let Q=this.queues.get(A);if(!Q||Q.length===0)return null;return Q[0]??null}async getNextAcrossTypes(){let A=null;for(let Q of this.queues.values()){let B=Q[0];if(!B)continue;if(!A||B.queuedAt<A.queuedAt)A=B}return A}async popNext(A){let Q=this.queues.get(A);if(!Q||Q.length===0)return null;let B=Q.shift()??null;if(B)this.recalculatePositions(Q);return B}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let A=[];for(let[Q,B]of this.queues.entries())if(B.length>0)A.push(Q);return A}getOrCreateQueue(A){let Q=this.queues.get(A);if(!Q)Q=[],this.queues.set(A,Q);return Q}recalculatePositions(A){A.forEach((Q,B)=>{Q.position=B+1})}}class tG{static instance=null;providers=new Map;executionModes=new Map;publishResultIdFields=new Map;publishTimestampFields=new Map;defaultProvider=new jd0;static getInstance(){return tG.instance??=new tG,tG.instance}static resetInstance(){tG.instance=null}static createFresh(){return new tG}constructor(){}register(A,Q,B){let w=this.providers.get(A);if(w&&w.name!=="internal"&&Q.name==="internal")return;if(this.providers.set(A,Q),this.executionModes.set(A,B?.executionMode??"provider"),B?.publishResultIdField)this.publishResultIdFields.set(A,B.publishResultIdField);else this.publishResultIdFields.delete(A);if(B?.publishTimestampField)this.publishTimestampFields.set(A,B.publishTimestampField);else this.publishTimestampFields.delete(A)}get(A){return this.providers.get(A)??this.defaultProvider}getExecutionMode(A){return this.executionModes.get(A)??"provider"}getPublishResultIdField(A){return this.publishResultIdFields.get(A)}getPublishTimestampField(A){return this.publishTimestampFields.get(A)}has(A){return this.providers.has(A)}unregister(A){this.providers.delete(A),this.executionModes.delete(A),this.publishResultIdFields.delete(A),this.publishTimestampFields.delete(A)}getRegisteredTypes(){return Array.from(this.providers.keys())}}K0();K0();async function Xo1(A,Q){if(!Q.publishExecutor){Q.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:"Publish executor not configured",retryCount:0,willRetry:!1});return}await vXB(A,Q)}async function vXB(A,Q){if(!Q.publishExecutor)return;try{let B=await Q.publishExecutor.publish({entityType:A.entityType,id:A.entityId});if("error"in B){let w={entityType:A.entityType,entityId:A.entityId,error:B.error,retryCount:0,willRetry:!1};if(Q.messageBus)await Q.messageBus.send({type:xD.FAILED,payload:w,sender:"publish-service"});Q.onFailed?.(w);return}_d0(A.entityType,A.entityId,B.result,Q)}catch(B){let w=hA(B);Q.retryTracker.recordFailure(A.entityId,w);let $=Q.retryTracker.getRetryInfo(A.entityId);Q.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:w,retryCount:$?.retryCount??1,willRetry:!1})}}function _d0(A,Q,B,w){if(w.retryTracker.clearRetries(Q),w.messageBus)w.messageBus.send({type:xD.COMPLETED,payload:{entityType:A,entityId:Q,result:B},sender:"publish-service"});w.onPublish?.({entityType:A,entityId:Q,result:B})}function Ho1(A,Q,B,w){w.retryTracker.recordFailure(Q,B);let $=w.retryTracker.getRetryInfo(Q),D={entityType:A,entityId:Q,error:B,retryCount:$?.retryCount??1,willRetry:!1};if(w.messageBus)w.messageBus.send({type:xD.FAILED,payload:D,sender:"publish-service"});w.onFailed?.(D)}async function Wo1(A,Q){let B=Q.generationConditions[A];if(B&&Q.onCheckGenerationConditions){let $=await Q.onCheckGenerationConditions(A,B);if(!$.shouldGenerate){if(Q.messageBus)Q.messageBus.send({type:vL.SKIPPED,payload:{entityType:A,reason:$.reason??"Conditions not met"},sender:"content-pipeline"});return}}let w={entityType:A};if(Q.messageBus)await Q.messageBus.send({type:vL.EXECUTE,payload:w,sender:"content-pipeline"});Q.onGenerate?.(w)}function Zo1(A,Q,B){if(B)B.send({type:vL.COMPLETED,payload:{entityType:A,entityId:Q},sender:"content-pipeline"})}function Ko1(A,Q,B){if(B)B.send({type:vL.FAILED,payload:{entityType:A,error:Q},sender:"content-pipeline"})}var hXB=1000;class Md0{deps;publishJobs=new Map;immediateIntervalJob=null;constructor(A){this.deps=A}start(){for(let[A,Q]of Object.entries(this.entitySchedules)){let B=this.deps.config.backend.scheduleCron(Q,()=>this.processEntityType(A));this.publishJobs.set(A,B)}this.immediateIntervalJob=this.deps.config.backend.scheduleInterval(hXB,()=>this.processUnscheduledTypes())}stop(){if(CXB(this.publishJobs),this.immediateIntervalJob)this.immediateIntervalJob.stop(),this.immediateIntervalJob=null}async processEntityType(A){if(!this.deps.isRunning())return;try{let Q=await this.deps.config.queueManager.getNext(A);if(Q)await this.processEntry(Q)}catch(Q){this.deps.config.logger.error(`Scheduler error for ${A}:`,Q)}}async processUnscheduledTypes(){if(!this.deps.isRunning())return;try{let A=await this.deps.config.queueManager.getQueuedEntityTypes();for(let Q of A)if(!this.entitySchedules[Q]){let B=await this.deps.config.queueManager.getNext(Q);if(B){await this.processEntry(B);break}}}catch(A){this.deps.config.logger.error("Scheduler error for unscheduled types:",A)}}async processEntry(A){await this.deps.config.queueManager.remove(A.entityType,A.entityId);let Q=this.deps.getPublishDeps();await Xo1(A,Q)}get entitySchedules(){return this.deps.config.entitySchedules}}function CXB(A){for(let Q of A.values())Q.stop();A.clear()}class Pd0{deps;generationJobs=new Map;constructor(A){this.deps=A}start(){for(let[A,Q]of Object.entries(this.generationSchedules)){let B=this.deps.config.backend.scheduleCron(Q,()=>this.handleTriggerGeneration(A));this.generationJobs.set(A,B)}}stop(){yXB(this.generationJobs)}async handleTriggerGeneration(A){if(!this.deps.isRunning())return;try{await Wo1(A,this.deps.getGenerationDeps())}catch(Q){this.deps.config.logger.error(`Generation trigger error for ${A}:`,Q)}}get generationSchedules(){return this.deps.config.generationSchedules}}function yXB(A){for(let Q of A.values())Q.stop();A.clear()}class bK{static instance=null;config;publishRunner;generationRunner;running=!1;static getInstance(A){return bK.instance??=new bK(A),bK.instance}static resetInstance(){if(bK.instance)bK.instance.stop();bK.instance=null}static createFresh(A){return new bK(A)}constructor(A){this.config={...A,entitySchedules:A.entitySchedules??{},generationSchedules:A.generationSchedules??{},generationConditions:A.generationConditions??{}},this.validateCronExpressions(),this.publishRunner=new Md0({config:this.config,getPublishDeps:()=>this.publishDeps,isRunning:()=>this.running}),this.generationRunner=new Pd0({config:this.config,getGenerationDeps:()=>this.generationDeps,isRunning:()=>this.running})}async start(){if(this.running)return;this.running=!0,this.publishRunner.start(),this.generationRunner.start()}async stop(){this.running=!1,this.publishRunner.stop(),this.generationRunner.stop()}isRunning(){return this.running}completePublish(A,Q,B){_d0(A,Q,B,this.publishDeps)}failPublish(A,Q,B){Ho1(A,Q,B,this.publishDeps)}completeGeneration(A,Q){Zo1(A,Q,this.config.messageBus)}failGeneration(A,Q){Ko1(A,Q,this.config.messageBus)}get entitySchedules(){return this.config.entitySchedules}get generationSchedules(){return this.config.generationSchedules}get publishDeps(){return{retryTracker:this.config.retryTracker,messageBus:this.config.messageBus,publishExecutor:this.config.publishExecutor,onPublish:this.config.onPublish,onFailed:this.config.onFailed}}get generationDeps(){return{logger:this.config.logger,messageBus:this.config.messageBus,generationConditions:this.config.generationConditions,onCheckGenerationConditions:this.config.onCheckGenerationConditions,onGenerate:this.config.onGenerate}}validateCronExpressions(){for(let[A,Q]of Object.entries(this.entitySchedules))this.validateCronExpression(A,Q,"publish");for(let[A,Q]of Object.entries(this.generationSchedules))this.validateCronExpression(A,Q,"generation")}validateCronExpression(A,Q,B){try{this.config.backend.validateCron(Q)}catch(w){throw Error(`Invalid ${B} cron expression for ${A}: "${Q}" - ${hA(w)}`)}}}class eG{static instance=null;retries=new Map;static getInstance(){return eG.instance??=new eG,eG.instance}static resetInstance(){eG.instance=null}static createFresh(){return new eG}constructor(){}recordFailure(A,Q){let w=(this.retries.get(A)?.retryCount??0)+1;this.retries.set(A,{entityId:A,retryCount:w,lastError:Q})}clearRetries(A){this.retries.delete(A)}getRetryInfo(A){let Q=this.retries.get(A);if(!Q)return null;return{entityId:Q.entityId,retryCount:Q.retryCount,lastError:Q.lastError}}}function M4(A,Q,B,w,$,D,f,Y){return M4.fromTZ(M4.tp(A,Q,B,w,$,D,f),Y)}M4.fromTZISO=(A,Q,B)=>M4.fromTZ(EXB(A,Q),B);M4.fromTZ=function(A,Q){let B=new Date(Date.UTC(A.y,A.m-1,A.d,A.h,A.i,A.s)),w=kd0(A.tz,B),$=new Date(B.getTime()-w),D=kd0(A.tz,$);if(D-w===0)return $;{let f=new Date(B.getTime()-D),Y=kd0(A.tz,f);if(Y-D===0)return f;if(!Q&&Y-D>0)return f;if(Q)throw Error("Invalid date passed to fromTZ()");return $}};M4.toTZ=function(A,Q){let B=A.toLocaleString("en-US",{timeZone:Q}).replace(/[\u202f]/," "),w=new Date(B);return{y:w.getFullYear(),m:w.getMonth()+1,d:w.getDate(),h:w.getHours(),i:w.getMinutes(),s:w.getSeconds(),tz:Q}};M4.tp=(A,Q,B,w,$,D,f)=>({y:A,m:Q,d:B,h:w,i:$,s:D,tz:f});function kd0(A,Q=new Date){let B=Q.toLocaleString("en-US",{timeZone:A,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],w=Q.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${w} GMT`)-Date.parse(`${w} ${B}`)}function EXB(A,Q){let B=new Date(Date.parse(A));if(isNaN(B))throw Error("minitz: Invalid ISO8601 passed to parser.");let w=A.substring(9);return A.includes("Z")||w.includes("-")||w.includes("+")?M4.tp(B.getUTCFullYear(),B.getUTCMonth()+1,B.getUTCDate(),B.getUTCHours(),B.getUTCMinutes(),B.getUTCSeconds(),"Etc/UTC"):M4.tp(B.getFullYear(),B.getMonth()+1,B.getDate(),B.getHours(),B.getMinutes(),B.getSeconds(),Q)}M4.minitz=M4;var Od0=32,wo=31|Od0,qo1=[1,2,4,8,16],Uo1=class{pattern;timezone;second;minute;hour;day;month;dayOfWeek;lastDayOfMonth;starDOM;starDOW;constructor(A,Q){this.pattern=A,this.timezone=Q,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 Q=new XW(new Date,this.timezone).getDate(!0);A[0]=A[0].replace("?",Q.getSeconds().toString()),A[1]=A[1].replace("?",Q.getMinutes().toString()),A[2]=A[2].replace("?",Q.getHours().toString()),this.starDOM||(A[3]=A[3].replace("?",Q.getDate().toString())),A[4]=A[4].replace("?",(Q.getMonth()+1).toString()),this.starDOW||(A[5]=A[5].replace("?",Q.getDay().toString()))}this.throwAtIllegalCharacters(A),this.partToArray("second",A[0],0,1),this.partToArray("minute",A[1],0,1),this.partToArray("hour",A[2],0,1),this.partToArray("day",A[3],-1,1),this.partToArray("month",A[4],-1,1),this.partToArray("dayOfWeek",A[5],0,wo),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(A,Q,B,w){let $=this[A],D=A==="day"&&this.lastDayOfMonth;if(Q===""&&!D)throw TypeError("CronPattern: configuration entry "+A+" ("+Q+") is empty, check for trailing spaces.");if(Q==="*")return $.fill(w);let f=Q.split(",");if(f.length>1)for(let Y=0;Y<f.length;Y++)this.partToArray(A,f[Y],B,w);else Q.indexOf("-")!==-1&&Q.indexOf("/")!==-1?this.handleRangeWithStepping(Q,A,B,w):Q.indexOf("-")!==-1?this.handleRange(Q,A,B,w):Q.indexOf("/")!==-1?this.handleStepping(Q,A,B,w):Q!==""&&this.handleNumber(Q,A,B,w)}throwAtIllegalCharacters(A){for(let Q=0;Q<A.length;Q++)if((Q===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(A[Q]))throw TypeError("CronPattern: configuration entry "+Q+" ("+A[Q]+") contains illegal characters.")}handleNumber(A,Q,B,w){let $=this.extractNth(A,Q),D=parseInt($[0],10)+B;if(isNaN(D))throw TypeError("CronPattern: "+Q+" is not a number: '"+A+"'");this.setPart(Q,D,$[1]||w)}setPart(A,Q,B){if(!Object.prototype.hasOwnProperty.call(this,A))throw TypeError("CronPattern: Invalid part specified: "+A);if(A==="dayOfWeek"){if(Q===7&&(Q=0),Q<0||Q>6)throw RangeError("CronPattern: Invalid value for dayOfWeek: "+Q);this.setNthWeekdayOfMonth(Q,B);return}if(A==="second"||A==="minute"){if(Q<0||Q>=60)throw RangeError("CronPattern: Invalid value for "+A+": "+Q)}else if(A==="hour"){if(Q<0||Q>=24)throw RangeError("CronPattern: Invalid value for "+A+": "+Q)}else if(A==="day"){if(Q<0||Q>=31)throw RangeError("CronPattern: Invalid value for "+A+": "+Q)}else if(A==="month"&&(Q<0||Q>=12))throw RangeError("CronPattern: Invalid value for "+A+": "+Q);this[A][Q]=B}handleRangeWithStepping(A,Q,B,w){let $=this.extractNth(A,Q),D=$[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(D===null)throw TypeError("CronPattern: Syntax error, illegal range with stepping: '"+A+"'");let[,f,Y,X]=D,H=parseInt(f,10)+B,W=parseInt(Y,10)+B,Z=parseInt(X,10);if(isNaN(H))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(W))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(Z))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(Z===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(Z>this[Q].length)throw TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[Q].length+")");if(H>W)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let G=H;G<=W;G+=Z)this.setPart(Q,G,$[1]||w)}extractNth(A,Q){let B=A,w;if(B.includes("#")){if(Q!=="dayOfWeek")throw Error("CronPattern: nth (#) only allowed in day-of-week field");w=B.split("#")[1],B=B.split("#")[0]}return[B,w]}handleRange(A,Q,B,w){let $=this.extractNth(A,Q),D=$[0].split("-");if(D.length!==2)throw TypeError("CronPattern: Syntax error, illegal range: '"+A+"'");let f=parseInt(D[0],10)+B,Y=parseInt(D[1],10)+B;if(isNaN(f))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(Y))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(f>Y)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let X=f;X<=Y;X++)this.setPart(Q,X,$[1]||w)}handleStepping(A,Q,B,w){let $=this.extractNth(A,Q),D=$[0].split("/");if(D.length!==2)throw TypeError("CronPattern: Syntax error, illegal stepping: '"+A+"'");D[0]===""&&(D[0]="*");let f=0;D[0]!=="*"&&(f=parseInt(D[0],10)+B);let Y=parseInt(D[1],10);if(isNaN(Y))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(Y===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(Y>this[Q].length)throw TypeError("CronPattern: Syntax error, max steps for part is ("+this[Q].length+")");for(let X=f;X<this[Q].length;X+=Y)this.setPart(Q,X,$[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 Q=A.trim().toLowerCase();return Q==="@yearly"||Q==="@annually"?"0 0 1 1 *":Q==="@monthly"?"0 0 1 * *":Q==="@weekly"?"0 0 * * 0":Q==="@daily"?"0 0 * * *":Q==="@hourly"?"0 * * * *":A}setNthWeekdayOfMonth(A,Q){if(typeof Q!="number"&&Q==="L")this.dayOfWeek[A]=this.dayOfWeek[A]|Od0;else if(Q===wo)this.dayOfWeek[A]=wo;else if(Q<6&&Q>0)this.dayOfWeek[A]=this.dayOfWeek[A]|qo1[Q-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${Q}, Type: ${typeof Q}`)}},Go1=[31,28,31,30,31,30,31,31,30,31,30,31],zF=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],XW=class A{tz;ms;second;minute;hour;day;month;year;constructor(Q,B){if(this.tz=B,Q&&Q instanceof Date)if(!isNaN(Q))this.fromDate(Q);else throw TypeError("CronDate: Invalid date passed to CronDate constructor");else if(Q===void 0)this.fromDate(new Date);else if(Q&&typeof Q=="string")this.fromString(Q);else if(Q instanceof A)this.fromCronDate(Q);else throw TypeError("CronDate: Invalid type ("+typeof Q+") passed to CronDate constructor")}isNthWeekdayOfMonth(Q,B,w,$){let D=new Date(Date.UTC(Q,B,w)).getUTCDay(),f=0;for(let Y=1;Y<=w;Y++)new Date(Date.UTC(Q,B,Y)).getUTCDay()===D&&f++;if($&wo&&qo1[f-1]&$)return!0;if($&Od0){let Y=new Date(Date.UTC(Q,B+1,0)).getUTCDate();for(let X=w+1;X<=Y;X++)if(new Date(Date.UTC(Q,B,X)).getUTCDay()===D)return!1;return!0}return!1}fromDate(Q){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=Q.getUTCMilliseconds(),this.second=Q.getUTCSeconds(),this.minute=Q.getUTCMinutes()+this.tz,this.hour=Q.getUTCHours(),this.day=Q.getUTCDate(),this.month=Q.getUTCMonth(),this.year=Q.getUTCFullYear(),this.apply();else{let B=M4.toTZ(Q,this.tz);this.ms=Q.getMilliseconds(),this.second=B.s,this.minute=B.i,this.hour=B.h,this.day=B.d,this.month=B.m-1,this.year=B.y}else this.ms=Q.getMilliseconds(),this.second=Q.getSeconds(),this.minute=Q.getMinutes(),this.hour=Q.getHours(),this.day=Q.getDate(),this.month=Q.getMonth(),this.year=Q.getFullYear()}fromCronDate(Q){this.tz=Q.tz,this.year=Q.year,this.month=Q.month,this.day=Q.day,this.hour=Q.hour,this.minute=Q.minute,this.second=Q.second,this.ms=Q.ms}apply(){if(this.month>11||this.day>Go1[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let Q=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return 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(),!0}else return!1}fromString(Q){if(typeof this.tz=="number"){let B=M4.fromTZISO(Q);this.ms=B.getUTCMilliseconds(),this.second=B.getUTCSeconds(),this.minute=B.getUTCMinutes(),this.hour=B.getUTCHours(),this.day=B.getUTCDate(),this.month=B.getUTCMonth(),this.year=B.getUTCFullYear(),this.apply()}else return this.fromDate(M4.fromTZISO(Q,this.tz))}findNext(Q,B,w,$){let D=this[B],f;w.lastDayOfMonth&&(this.month!==1?f=Go1[this.month]:f=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let Y=!w.starDOW&&B=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let X=this[B]+$;X<w[B].length;X++){let H=w[B][X];if(B==="day"&&w.lastDayOfMonth&&X-$==f&&(H=1),B==="day"&&!w.starDOW){let W=w.dayOfWeek[(Y+(X-$-1))%7];if(W&&W&wo)W=this.isNthWeekdayOfMonth(this.year,this.month,X-$,W)?1:0;else if(W)throw Error(`CronDate: Invalid value for dayOfWeek encountered. ${W}`);Q.legacyMode&&!w.starDOM?H=H||W:H=H&&W}if(H)return this[B]=X-$,D!==this[B]?2:1}return 3}recurse(Q,B,w){let $=this.findNext(B,zF[w][0],Q,zF[w][2]);if($>1){let D=w+1;for(;D<zF.length;)this[zF[D][0]]=-zF[D][2],D++;if($===3)return this[zF[w][1]]++,this[zF[w][0]]=-zF[w][2],this.apply(),this.recurse(Q,B,0);if(this.apply())return this.recurse(Q,B,w-1)}return w+=1,w>=zF.length?this:this.year>=3000?null:this.recurse(Q,B,w)}increment(Q,B,w){return this.second+=B.interval!==void 0&&B.interval>1&&w?B.interval:1,this.ms=0,this.apply(),this.recurse(Q,B,0)}getDate(Q){return Q||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)):M4.fromTZ(M4.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function gXB(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 XW(A.startAt,A.timezone)),A.stopAt&&(A.stopAt=new XW(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 Bo(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function TXB(A){return Bo(A)}function SXB(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var zo1=30000,iD0=[],xd0=class{name;options;_states;fn;constructor(A,Q,B){let w,$;if(Bo(Q))$=Q;else if(typeof Q=="object")w=Q;else if(Q!==void 0)throw Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(Bo(B))$=B;else if(typeof B=="object")w=B;else if(B!==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=gXB(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 Uo1("* * * * *")},A&&(A instanceof Date||typeof A=="string"&&A.indexOf(":")>0)?this._states.once=new XW(A,this.options.timezone||this.options.utcOffset):this._states.pattern=new Uo1(A,this.options.timezone),this.name){if(iD0.find((D)=>D.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");iD0.push(this)}return $!==void 0&&TXB($)&&(this.fn=$,this.schedule()),this}nextRun(A){let Q=this._next(A);return Q?Q.getDate(!1):null}nextRuns(A,Q){this._states.maxRuns!==void 0&&A>this._states.maxRuns&&(A=this._states.maxRuns);let B=[],w=Q||this._states.currentRun||void 0;for(;A--&&(w=this.nextRun(w));)B.push(w);return B}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let A=this.nextRun(this._states.currentRun),Q=!this._states.paused,B=this.fn!==void 0,w=!this._states.kill;return Q&&B&&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 Q=this._next(A);return Q?A instanceof XW||A instanceof Date?Q.getTime()-A.getTime():Q.getTime()-new XW(A).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let A=iD0.indexOf(this);A>=0&&iD0.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 Q=this.msToNext(),B=this.nextRun(this._states.currentRun);return Q==null||isNaN(Q)||B===null?this:(Q>zo1&&(Q=zo1),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(B),Q),this._states.currentTimeout&&this.options.unref&&SXB(this._states.currentTimeout),this)}async _trigger(A){if(this._states.blocking=!0,this._states.currentRun=new XW(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{this.fn!==void 0&&await this.fn(this,this.options.context)}catch(Q){Bo(this.options.catch)&&this.options.catch(Q,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new XW(A,this.options.timezone||this.options.utcOffset),this._states.blocking=!1}async trigger(){await this._trigger()}runsLeft(){return this._states.maxRuns}_checkTrigger(A){let Q=new Date,B=!this._states.paused&&Q.getTime()>=A.getTime(),w=this._states.blocking&&this.options.protect;B&&!w?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):B&&w&&Bo(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(A){let Q=!!(A||this._states.currentRun),B=!1;!A&&this.options.startAt&&this.options.interval&&([A,Q]=this._calculatePreviousRun(A,Q),B=!A),A=new XW(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 XW(A,this.options.timezone||this.options.utcOffset);return!B&&w!==this._states.once&&(w=w.increment(this._states.pattern,this.options,Q)),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,Q){let B=new XW(void 0,this.options.timezone||this.options.utcOffset),w=A;if(this.options.startAt.getTime()<=B.getTime()){w=this.options.startAt;let $=w.getTime()+this.options.interval*1000;for(;$<=B.getTime();)w=new XW(w,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),$=w.getTime()+this.options.interval*1000;Q=!0}return w===null&&(w=void 0),[w,Q]}};class dD0{scheduleCron(A,Q){let B=new xd0(A,()=>{Q()});return{stop:()=>B.stop()}}scheduleInterval(A,Q){let B=setInterval(()=>{Q()},A);return{stop:()=>clearInterval(B)}}validateCron(A){new xd0(A).stop()}}K0();var Fo1=K.union([K.string().min(1),K.object({location:K.enum(["metadata","frontmatter"]),field:K.string().min(1)})]),nD0=K.object({entityType:K.string().min(1),attachmentType:K.string().min(1),mediaEntityType:K.enum(["image","document"]),targetEntityField:Fo1.optional(),requiredWhen:K.object({status:K.string().min(1).optional(),visibility:K.string().min(1).optional()}).optional(),autoGenerate:K.boolean().optional(),requiredForPublish:K.boolean().optional(),jobType:K.string().min(1).optional()});function Rd0(A){return`${A.entityType}:${A.attachmentType}`}class Az{static instance=null;definitions=new Map;static getInstance(){return Az.instance??=new Az,Az.instance}static resetInstance(){Az.instance=null}static createFresh(){return new Az}constructor(){}register(A){let Q=nD0.parse(A),B=Rd0(Q);return this.definitions.set(B,Q),()=>this.unregister(Q.entityType,Q.attachmentType)}get(A,Q){return this.definitions.get(Rd0({entityType:A,attachmentType:Q}))}list(A){let Q=Array.from(this.definitions.values());return A?Q.filter((B)=>B.entityType===A):Q}has(A,Q){return this.get(A,Q)!==void 0}unregister(A,Q){this.definitions.delete(Rd0({entityType:A,attachmentType:Q}))}clear(){this.definitions.clear()}}K0();class rD0{deps;constructor(A){this.deps=A}async ensureForEntity(A,Q={}){let B=this.deps.registry.list(A.entityType).filter(($)=>$.autoGenerate===!0).filter(($)=>!Q.attachmentType||$.attachmentType===Q.attachmentType),w={checked:B.length,enqueued:0,skipped:0};for(let $ of B)if(await this.ensureDefinition(A,$))w.enqueued+=1;else w.skipped+=1;return w}async ensureDefinition(A,Q){if(!this.matchesPolicy(A,Q))return!1;if(this.hasTargetField(A,Q.targetEntityField))return!1;if(!this.deps.context.attachments.hasProvider(A.entityType,Q.attachmentType))return!1;let B=this.resolveJobType(Q);if(!B)return!1;let w=this.getPredictedMediaId(A,Q),$=this.getDeduplicationKey(A,Q);return await this.deps.context.jobs.enqueue({type:B,data:{sourceEntityType:A.entityType,sourceEntityId:A.id,attachmentType:Q.attachmentType,imageId:w,dedupKey:$,targetEntityType:A.entityType,targetEntityId:A.id,...this.getTargetImageFieldData(Q.targetEntityField)},options:{source:"content-pipeline",metadata:{operationType:"content_operations"},deduplication:"skip",deduplicationKey:$}}),this.deps.context.logger.debug("Queued publish asset generation",{entityType:A.entityType,entityId:A.id,attachmentType:Q.attachmentType,jobType:B}),!0}matchesPolicy(A,Q){let{requiredWhen:B}=Q;if(!B)return!0;if(B.status&&A.metadata.status!==B.status)return!1;if(B.visibility&&A.visibility!==B.visibility)return!1;return!0}hasTargetField(A,Q){if(!Q)return!1;if(typeof Q==="string")return vd0(A.metadata[Q]);if(Q.location==="metadata")return vd0(A.metadata[Q.field]);let{frontmatter:B}=lB(A.content);return vd0(B[Q.field])}resolveJobType(A){if(A.jobType)return A.jobType;if(A.mediaEntityType==="image")return"image:image-render-source";return}getPredictedMediaId(A,Q){let B=Q.attachmentType==="og-image"?"og":Q.attachmentType;return Y1(`${B}-${A.entityType}-${A.id}`)}getDeduplicationKey(A,Q){return`publish-asset:${Q.attachmentType}:${A.entityType}:${A.id}`}getTargetImageFieldData(A){let Q=typeof A==="string"?A:A?.field;if(Q==="coverImageId"||Q==="ogImageId")return{targetImageField:Q};return{}}}function vd0(A){return typeof A==="string"?A.length>0:A!==void 0}p0();K0();var mXB=K.object({id:K.string().min(1)});async function Vo1(A,Q){let{bodyContent:B,coverImageId:w,documents:$,sourceEntityType:D,sourceEntityId:f}=uXB(Q.content),Y=w?await pXB(A,w):void 0,X;if($&&$.length>0){let W=await iXB(A,$);if(W.length>0)X=W}X??=await lXB(A,D,f);let H={bodyContent:B};if(Y)H.imageData=Y;if(X&&X.length>0)H.documentData=X;return H}function uXB(A){try{let Q=h2(A,K.record(K.unknown())),B=Q.metadata.coverImageId,w=typeof B==="string"?B:void 0,$=cXB(Q.metadata.documents),D=Io1(Q.metadata.sourceEntityType),f=Io1(Q.metadata.sourceEntityId);return{bodyContent:Q.content,...w&&{coverImageId:w},...$.length>0&&{documents:$},...D&&{sourceEntityType:D},...f&&{sourceEntityId:f}}}catch{return{bodyContent:A}}}function cXB(A){if(!Array.isArray(A))return[];return A.flatMap((Q)=>{let B=mXB.safeParse(Q);return B.success?[B.data]:[]})}function Io1(A){return typeof A==="string"&&A.length>0?A:void 0}async function lXB(A,Q,B){if(!Q||!B)return;let w=await A.attachments.resolve({sourceEntityType:Q,sourceEntityId:B,attachmentType:"carousel"});return w?[w]:void 0}async function pXB(A,Q){let B=await A.entityService.getEntity({entityType:"image",id:Q});if(!B?.content)return;let w=Jo1(B.content);if(!w?.mimeType.startsWith("image/"))return;return{data:w.data,mimeType:w.mimeType}}async function iXB(A,Q){return(await Promise.all(Q.map((w)=>dXB(A,w)))).filter((w)=>w!==void 0)}async function dXB(A,Q){let B=await A.entityService.getEntity({entityType:"document",id:Q.id});if(!B?.content)return;let w=Jo1(B.content);if(w?.mimeType!=="application/pdf")return;return{type:"document",data:w.data,mimeType:"application/pdf",filename:nXB(B,Q.id)}}function Jo1(A){let Q=A.match(/^data:([^;]+);base64,(.+)$/);if(!Q?.[1]||!Q[2])return;return{mimeType:Q[1],data:Buffer.from(Q[2],"base64")}}function nXB(A,Q){let B=A.metadata.filename;return typeof B==="string"&&B.length>0?B:`${Q}.pdf`}K0();var rXB=/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/;async function hd0(A,Q,B,w={}){let $=w.publishedAt??new Date().toISOString(),D=w.publishTimestampField??"publishedAt",f={...Q.metadata,status:"published",[D]:$,platformId:B.id,...oXB(B.id,w.publishResultIdField)},Y={...Q,content:Lo1(Q.content,$,B.id,w.publishResultIdField,D),metadata:f};return await A.entityService.updateEntity({entity:Y}),Y}function Lo1(A,Q,B,w,$="publishedAt"){if(!rXB.test(A))return A;let D=n4(n4(A,"status","published"),$,Q);if(!B||!w)return D;return n4(D,w,B)}function oXB(A,Q){if(!Q||Q==="platformId")return{};return{[Q]:A}}class JE{deps;constructor(A){this.deps=A}async resolveCandidate(A){let{entityType:Q,id:B,slug:w}=A;if(!B&&!w)return{error:"Either 'id' or 'slug' must be provided"};let $=await this.findPublishableEntity(Q,B,w);if(!$)return{error:`Entity not found: ${Q}:${B??w}`};if($.visibility!=="public")return{error:`Cannot publish ${Q}:${$.id} to a public provider because visibility is ${$.visibility}`};if($.metadata.status==="published")return{error:"Entity is already published"};if(!this.deps.providerRegistry.has(Q))return{error:`No publish provider registered for ${Q}. Check that the required credentials are configured.`};return{entity:$}}async publish(A){let Q=await this.resolveCandidate(A);if("error"in Q)return Q;let{entity:B}=Q,{entityType:w}=A,$=this.deps.providerRegistry.get(w),{bodyContent:D,imageData:f,documentData:Y}=await Vo1(this.deps.context,B),X=await $.publish(D,B.metadata,f,Y),H=this.deps.providerRegistry.getPublishResultIdField(w),W=this.deps.providerRegistry.getPublishTimestampField(w),Z=await hd0(this.deps.context,B,X,{...H?{publishResultIdField:H}:{},...W?{publishTimestampField:W}:{}});return await this.runPublishAssetPreflight(Z),{entity:Z,result:X}}async runPublishAssetPreflight(A){if(!this.deps.publishAssetPreflight)return;try{await this.deps.publishAssetPreflight.ensureForEntity(A)}catch(Q){this.deps.context.logger.warn("Publish asset preflight failed",{entityType:A.entityType,entityId:A.id,error:Q instanceof Error?Q.message:String(Q)})}}async findPublishableEntity(A,Q,B){if(Q)return this.deps.context.entityService.getEntity({entityType:A,id:Q});if(!B)return null;return(await this.deps.context.entityService.listEntities({entityType:A,options:{filter:{metadata:{slug:B}},limit:1}}))[0]??null}}p0();K0();var Cd0=K.object({action:K.enum(["list","add","remove","reorder"]).describe("Queue action to perform"),entityType:K.string().optional().describe("Entity type (required for add/remove/reorder, optional for list)"),entityId:K.string().optional().describe("Entity ID (required for add/remove/reorder)"),position:K.number().optional().describe("New position for reorder action (1-based)")}),yd0=K.object({position:K.number(),entityType:K.string(),entityId:K.string(),queuedAt:K.string()}),sXB=K.object({success:K.literal(!0),message:K.string().optional(),data:K.object({queue:K.array(yd0).optional(),entityType:K.string().optional(),entityId:K.string().optional(),position:K.number().optional()}).optional()}),aXB=K.object({success:K.literal(!1),error:K.string(),code:K.string().optional()}),Ed0=K.union([sXB,aXB]);function oD0(A,Q,B){return{...BB(Q,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",Cd0,async($,D)=>{let{action:f,entityType:Y,entityId:X,position:H}=$;switch(f){case"list":return tXB(B,Y);case"add":return eXB(A,B,Y,X,D);case"remove":return AHB(A,B,Y,X,D);case"reorder":return QHB(A,B,Y,X,H,D);default:return{success:!1,error:`Unknown action: ${f}`}}}),outputSchema:Ed0}}async function tXB(A,Q){let B=[];if(Q)B=await A.list(Q);else{let $=A.getRegisteredTypes();for(let D of $){let f=await A.list(D);B.push(...f)}B.sort((D,f)=>new Date(D.queuedAt).getTime()-new Date(f.queuedAt).getTime())}if(B.length===0)return{success:!0,data:{queue:[]},message:"No items in queue"};return{success:!0,data:{queue:B.map(($,D)=>({position:D+1,entityType:$.entityType,entityId:$.entityId,queuedAt:$.queuedAt}))},message:`${B.length} items in queue`}}async function eXB(A,Q,B,w,$){let D=gd0("add",B,w);if(!D.success)return D.error;A.permissions.assertEntityActionAllowed(D.entityType,"publish",$??{});let f=await Q.add(D.entityType,D.entityId,{...$,authorization:"user"});return{success:!0,data:{entityType:D.entityType,entityId:D.entityId,position:f.position},message:`Added to queue at position ${f.position}`}}async function AHB(A,Q,B,w,$){let D=gd0("remove",B,w);if(!D.success)return D.error;return A.permissions.assertEntityActionAllowed(D.entityType,"update",$??{}),await Q.remove(D.entityType,D.entityId),{success:!0,data:{entityType:D.entityType,entityId:D.entityId},message:"Removed from queue"}}async function QHB(A,Q,B,w,$,D){let f=gd0("reorder",B,w);if(!f.success)return f.error;let Y=BHB($);if(!Y.success)return Y.error;return A.permissions.assertEntityActionAllowed(f.entityType,"update",D??{}),await Q.reorder(f.entityType,f.entityId,Y.position),{success:!0,data:{entityType:f.entityType,entityId:f.entityId,position:Y.position},message:`Moved to position ${Y.position}`}}function gd0(A,Q,B){if(!Q)return{success:!1,error:{success:!1,error:`entityType is required for ${A} action`}};if(!B)return{success:!1,error:{success:!1,error:`entityId is required for ${A} action`}};return{success:!0,entityType:Q,entityId:B}}function BHB(A){if(A===void 0)return{success:!1,error:{success:!1,error:"position is required for reorder action"}};if(A<1)return{success:!1,error:{success:!1,error:"position must be a positive number"}};return{success:!0,position:A}}K0();import{createHash as wHB}from"crypto";var sD0=K.object({entityType:K.string().describe("Entity type to publish (e.g., social-post, post, deck)"),id:K.string().optional().describe("Entity ID to publish"),slug:K.string().optional().describe("Entity slug to publish"),confirmed:K.boolean().optional(),confirmationToken:K.string().optional(),contentHash:K.string().optional(),expiresAt:K.string().datetime().optional()}),$HB=K.object({success:K.literal(!0),message:K.string().optional(),data:K.object({entityType:K.string().optional(),entityId:K.string().optional(),platformId:K.string().optional(),url:K.string().optional()}).optional()}),DHB=K.object({success:K.literal(!1),error:K.string(),code:K.string().optional()}),fHB=K.object({success:K.literal(!1).optional(),error:K.string().optional(),needsConfirmation:K.literal(!0),toolName:K.string(),summary:K.string(),preview:K.string().optional(),args:K.unknown()}),Td0=K.union([$HB,DHB,fHB]),YHB=900000;function aD0(A,Q,B,w){let $=w??new JE({context:A,providerRegistry:B}),D=`${Q}_publish`;return{name:D,description:"Publish an entity directly to its platform. Call this when the user asks to publish; the tool will request confirmation itself. Works with any registered entity type (social-post, post, deck, etc.)",inputSchema:sD0.shape,outputSchema:Td0,visibility:"anchor",handler:async(f,Y)=>{let X=sD0.safeParse(f);if(!X.success)return{success:!1,error:`Invalid input: ${X.error.errors.map((L)=>`${L.path.join(".")}: ${L.message}`).join(", ")}`};let H=X.data,{entityType:W,id:Z,slug:G}=H;try{A.permissions.assertEntityActionAllowed(W,"publish",Y)}catch(L){return{success:!1,error:L instanceof Error?L.message:String(L)}}let F=await $.resolveCandidate({entityType:W,id:Z,slug:G});if("error"in F)return{success:!1,error:F.error};let{entity:I}=F;if(H.confirmed){let L=HHB(D,H,I);if(L!==null)return L;let b;try{b=await $.publish({entityType:W,id:I.id})}catch(j){return{success:!1,error:j instanceof Error?j.message:String(j)}}if("error"in b)return{success:!1,error:b.error};let{entity:N,result:M}=b;return{success:!0,data:{entityType:W,entityId:N.id,platformId:M.id,url:M.url},message:`Published ${W}:${N.id}`}}return XHB(D,H,I)}}}function XHB(A,Q,B){let w=new Date(Date.now()+YHB).toISOString(),$=bo1(A,B,w),D=WHB(B);return{needsConfirmation:!0,toolName:A,summary:`Publish "${D}"?`,preview:`This will publish ${B.entityType}:${B.id} to its registered public publish provider.`,args:{...Q,id:B.id,slug:void 0,confirmed:!0,confirmationToken:$,contentHash:B.contentHash,expiresAt:w}}}function HHB(A,Q,B){let{confirmationToken:w,contentHash:$,expiresAt:D}=Q;if(!w||!D)return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};let f=Date.parse(D);if(Number.isNaN(f))return{success:!1,error:"Invalid publish confirmation expiry. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};if(f<=Date.now())return{success:!1,error:"Publish confirmation expired. Request confirmation again before publishing.",code:"EXPIRED_CONFIRMATION_TOKEN"};if($&&$!==B.contentHash)return{success:!1,error:`Cannot publish ${B.entityType}:${B.id} because it changed after confirmation. Review it and try again.`};if(w!==bo1(A,B,D))return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};return null}function bo1(A,Q,B){return wHB("sha256").update(A).update("\x00").update(Q.entityType).update("\x00").update(Q.id).update("\x00").update(Q.contentHash).update("\x00").update(B).digest("hex")}function WHB(A){let Q=A.metadata.title;if(typeof Q==="string"&&Q.length>0)return Q;let B=A.metadata.subject;if(typeof B==="string"&&B.length>0)return B;let w=A.metadata.slug;if(typeof w==="string"&&w.length>0)return w;return A.id}p0();K0();var Sd0=K.object({entityType:K.string().min(1).describe("Entity type to reconcile"),status:K.string().min(1).optional().describe("Optional metadata status filter, e.g. published"),assetType:K.string().min(1).optional().describe("Optional attachment type filter, e.g. og-image")}),md0=K.object({success:K.literal(!0),data:K.object({entityType:K.string(),assetType:K.string().optional(),checkedEntities:K.number(),checkedAssets:K.number(),enqueued:K.number(),skipped:K.number()}),message:K.string().optional()});function tD0(A,Q,B,w){return{...BB(Q,"ensure-assets","Reconcile configured publish assets for existing entities, queueing missing generated assets such as OG images.",Sd0,async(D,f)=>{if(A.permissions.assertEntityActionAllowed(D.entityType,"publish",f),B.list(D.entityType).filter((G)=>G.autoGenerate===!0).filter((G)=>!D.assetType||G.attachmentType===D.assetType).length===0)return{success:!0,data:{entityType:D.entityType,...D.assetType&&{assetType:D.assetType},checkedEntities:0,checkedAssets:0,enqueued:0,skipped:0},message:`No publish assets configured for ${D.entityType}`};let X=await A.entityService.listEntities({entityType:D.entityType,options:{...D.status&&{filter:{metadata:{status:D.status}}}}}),H=0,W=0,Z=0;for(let G of X){let F=await w.ensureForEntity(G,{...D.assetType&&{attachmentType:D.assetType}});H+=F.checked,W+=F.enqueued,Z+=F.skipped}return{success:!0,data:{entityType:D.entityType,...D.assetType&&{assetType:D.assetType},checkedEntities:X.length,checkedAssets:H,enqueued:W,skipped:Z},message:`Queued ${W} publish asset job(s)`}}),outputSchema:md0}}p0();K0();function No1(A,Q){ZHB(A,Q),KHB(A,Q),UHB(A,Q),GHB(A,Q)}function ZHB(A,Q){A.messaging.subscribe(xD.REGISTER,async(B)=>zHB(Q,B.payload)),A.messaging.subscribe(xD.QUEUE,async(B)=>VHB(A,Q,B.payload)),A.messaging.subscribe(xD.DIRECT,async(B)=>JHB(A,Q,B.payload)),A.messaging.subscribe(xD.REMOVE,async(B)=>LHB(Q,B.payload)),A.messaging.subscribe(xD.REORDER,async(B)=>bHB(Q,B.payload)),A.messaging.subscribe(xD.LIST,async(B)=>NHB(A,Q,B.payload)),A.messaging.subscribe(xD.REPORT_SUCCESS,async(B)=>jHB(Q,B.payload)),A.messaging.subscribe(xD.REPORT_FAILURE,async(B)=>_HB(Q,B.payload)),Q.logger.debug("Subscribed to publish messages")}function KHB(A,Q){A.messaging.subscribe(vL.REPORT_SUCCESS,async(B)=>MHB(Q,B.payload)),A.messaging.subscribe(vL.REPORT_FAILURE,async(B)=>PHB(Q,B.payload)),Q.logger.debug("Subscribed to generation messages")}function UHB(A,Q){A.messaging.subscribe(Do1.REGISTER,async(B)=>qHB(Q,B.payload)),Q.logger.debug("Subscribed to publish asset messages")}function GHB(A,Q){let B=async(w)=>FHB(A,Q,w.payload);A.messaging.subscribe("entity:created",B),A.messaging.subscribe("entity:updated",B),Q.logger.debug("Subscribed to entity change messages for publish assets")}async function zHB(A,Q){let{entityType:B,provider:w,config:$}=Q;try{let D=$?fo1.safeParse($):void 0;if(D&&!D.success)return A.logger.warn("Invalid publish provider config",{entityType:B,error:D.error.message}),{success:!1};if(w)A.providerRegistry.register(B,w,D?.data),A.logger.info(`Registered provider for entity type: ${B}`,{providerName:w.name,executionMode:A.providerRegistry.getExecutionMode(B)});return{success:!0}}catch(D){let f=hA(D);return A.logger.error(`Failed to register provider: ${f}`),{success:!1}}}async function qHB(A,Q){let B=nD0.safeParse(Q);if(!B.success)return A.logger.warn("Invalid publish asset registration",{error:B.error.message}),{success:!1};return A.publishAssetRegistry.register(B.data),A.logger.info("Registered publish asset",{entityType:B.data.entityType,attachmentType:B.data.attachmentType,mediaEntityType:B.data.mediaEntityType}),{success:!0}}async function FHB(A,Q,B){try{if(Q.publishAssetRegistry.list(B.entityType).length===0)return{success:!0};let w=B.entity??await A.entityService.getEntity({entityType:B.entityType,id:B.entityId});if(!IHB(w))return{success:!0};return await Q.publishAssetPreflight.ensureForEntity(w),{success:!0}}catch(w){return Q.logger.warn("Failed to run publish asset preflight for entity event",{entityType:B.entityType,entityId:B.entityId,error:hA(w)}),{success:!1}}}function IHB(A){if(!A)return!1;let Q=$o1.safeParse(A.metadata);return Q.success&&Q.data.status==="published"}async function VHB(A,Q,B){let{entityType:w,entityId:$}=B;try{let D=B.authContext??Qo;A.permissions.assertEntityActionAllowed(w,"publish",D);let f=await Q.queueManager.add(w,$,D);return await A.messaging.send({type:xD.QUEUED,payload:{entityType:w,entityId:$,position:f.position}}),Q.logger.debug(`Entity queued: ${$}`,{entityType:w,position:f.position}),{success:!0}}catch(D){let f=hA(D);return Q.logger.error(`Failed to queue entity: ${f}`),{success:!1}}}async function JHB(A,Q,B){let{entityType:w,entityId:$}=B,D=B.authContext??Qo;try{if(A.permissions.assertEntityActionAllowed(w,"publish",D),!Q.providerRegistry.has(w))return Q.scheduler.failPublish(w,$,`No publish provider registered for ${w}`),{success:!1};let f=await Q.publishExecutor.publish({entityType:w,id:$});if("error"in f)return Q.scheduler.failPublish(w,$,f.error),{success:!1};return Q.scheduler.completePublish(w,$,f.result),Q.logger.debug(`Direct publish completed: ${$}`,{entityType:w}),{success:!0}}catch(f){let Y=hA(f);return Q.logger.error(`Failed direct publish request: ${Y}`),{success:!1}}}async function LHB(A,Q){let{entityType:B,entityId:w}=Q;try{return await A.queueManager.remove(B,w),A.logger.debug(`Entity removed from queue: ${w}`,{entityType:B}),{success:!0}}catch($){let D=hA($);return A.logger.error(`Failed to remove entity: ${D}`),{success:!1}}}async function bHB(A,Q){let{entityType:B,entityId:w,position:$}=Q;try{return await A.queueManager.reorder(B,w,$),A.logger.debug(`Entity reordered: ${w}`,{entityType:B,newPosition:$}),{success:!0}}catch(D){let f=hA(D);return A.logger.error(`Failed to reorder entity: ${f}`),{success:!1}}}async function NHB(A,Q,B){let{entityType:w}=B;try{let $=await Q.queueManager.list(w);return await A.messaging.send({type:xD.LIST_RESPONSE,payload:{entityType:w,queue:$.map((D)=>({entityId:D.entityId,position:D.position,queuedAt:D.queuedAt}))}}),{success:!0}}catch($){let D=hA($);return Q.logger.error(`Failed to list queue: ${D}`),{success:!1}}}async function jHB(A,Q){let{entityType:B,entityId:w,result:$}=Q;return A.scheduler.completePublish(B,w,$),A.logger.info(`Publish reported success: ${w}`,{entityType:B}),{success:!0}}async function _HB(A,Q){let{entityType:B,entityId:w,error:$}=Q;A.scheduler.failPublish(B,w,$);let D=A.retryTracker.getRetryInfo(w);return A.logger.info(`Publish reported failure: ${w}`,{entityType:B,error:$,retryCount:D?.retryCount}),{success:!0}}async function MHB(A,Q){let{entityType:B,entityId:w}=Q;return A.scheduler.completeGeneration(B,w),A.logger.info("Generation completed",{entityType:B,entityId:w}),{success:!0}}async function PHB(A,Q){let{entityType:B,error:w}=Q;return A.scheduler.failGeneration(B,w),A.logger.warn("Generation failed",{entityType:B,error:w}),{success:!0}}K0();async function jo1(A,Q,B,w){try{if(w.skipIfDraftExists!==!1){if((await A.listEntities({entityType:B,options:{filter:{metadata:{status:"draft"}},limit:1}})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(w.maxUnpublishedDrafts!==void 0){let $=await A.listEntities({entityType:B,options:{filter:{metadata:{status:"draft"}},limit:w.maxUnpublishedDrafts+1}});if($.length>=w.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${$.length}/${w.maxUnpublishedDrafts})`}}if(w.minSourceEntities!==void 0&&w.sourceEntityType){let $=await A.listEntities({entityType:w.sourceEntityType,options:{publishedOnly:!0,limit:w.minSourceEntities}});if($.length<w.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${$.length}/${w.minSourceEntities} ${w.sourceEntityType})`}}return{shouldGenerate:!0}}catch($){return Q.error("Failed to check generation conditions",{entityType:B,error:hA($)}),{shouldGenerate:!1,reason:`Condition check failed: ${hA($)}`}}}function _o1(A){let{context:Q,config:B,queueManager:w,providerRegistry:$,retryTracker:D,publishExecutor:f,logger:Y}=A,X=kHB(Q);return bK.createFresh({queueManager:w,providerRegistry:$,retryTracker:D,logger:Y,backend:new dD0,...B.entitySchedules&&{entitySchedules:B.entitySchedules},...B.generationSchedules&&{generationSchedules:B.generationSchedules},...B.generationConditions&&{generationConditions:B.generationConditions},messageBus:X,publishExecutor:f,onCheckGenerationConditions:(H,W)=>jo1(Q.entityService,Y,H,W)})}function kHB(A){return{send:async($)=>{return A.messaging.send({type:$.type,payload:$.payload,...$.target!==void 0?{target:$.target}:{},...$.metadata!==void 0?{metadata:$.metadata}:{},...$.broadcast!==void 0?{broadcast:$.broadcast}:{}})},subscribe:()=>()=>{},unsubscribe:()=>{}}}async function Mo1(A,Q,B){let w=A.getEntityTypes();for(let D of w){let f=await A.listEntities({entityType:D,options:{filter:{metadata:{status:"queued"}}}});for(let Y of f)await Q.add(Y.entityType,Y.id)}let $=0;for(let D of w){let f=await Q.list(D);$+=f.length}if($>0)B.info(`Rebuilt queue with ${$} queued entities`)}var OHB=["draft","queued","published","failed"];async function Po1(A,Q){await A.messaging.send({type:"dashboard:register-widget",payload:{id:"publication-pipeline",pluginId:Q,title:"Publication Pipeline",section:"secondary",priority:100,rendererName:"PipelineWidget",visibility:"anchor",dataProvider:()=>xHB(A)}})}async function xHB(A){let Q=A.entityService.getEntityTypes(),B=[],w={draft:0,queued:0,published:0,failed:0};for(let $ of Q){let D=await A.entityService.listEntities({entityType:$});for(let f of D){let Y=RHB(f.metadata.status);if(!Y)continue;w[Y]++,B.push({id:f.id,title:vHB(f.id,f.metadata.title),type:$,status:Y})}}return{summary:w,items:B}}function RHB(A){return OHB.find((Q)=>Q===A)}function vHB(A,Q){return typeof Q==="string"?Q:A}var ko1={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.128",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/contracts":"workspace:*","@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 ud0 extends pQ{pluginContext;queueManager;providerRegistry;retryTracker;publishExecutor;publishAssetRegistry;publishAssetPreflight;scheduler;constructor(A){super("content-pipeline",ko1,A??{},Yo1)}async onRegister(A){this.pluginContext=A,this.queueManager=aG.createFresh(),this.providerRegistry=tG.createFresh(),this.retryTracker=eG.createFresh(),this.publishAssetRegistry=Az.createFresh(),this.publishAssetPreflight=new rD0({context:A,registry:this.publishAssetRegistry}),this.publishExecutor=new JE({context:A,providerRegistry:this.providerRegistry,publishAssetPreflight:this.publishAssetPreflight}),this.scheduler=_o1({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,logger:this.logger}),No1(A,{queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,publishAssetRegistry:this.publishAssetRegistry,publishAssetPreflight:this.publishAssetPreflight,scheduler:this.scheduler,logger:this.logger})}async onReady(A){await Mo1(A.entityService,this.queueManager,this.logger),await Po1(A,this.id),await this.scheduler.start(),this.logger.info("Content pipeline plugin started")}async getTools(){if(!this.pluginContext)throw Error("Plugin context not initialized");return[oD0(this.pluginContext,this.id,this.queueManager),aD0(this.pluginContext,this.id,this.providerRegistry,this.publishExecutor),tD0(this.pluginContext,this.id,this.publishAssetRegistry,this.publishAssetPreflight)]}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). This tool has its own confirmation flow; call it without `confirmed` when the user asks to publish instead of asking for plain-text confirmation.\n- Use `content-pipeline_ensure-assets` to reconcile missing publish assets such as generated OG images for already-published content.\n- When users ask about their "publish queue", "publishing queue", or "what\'s queued", use `content-pipeline_queue`.'}getQueueManager(){return this.queueManager}getProviderRegistry(){return this.providerRegistry}getRetryTracker(){return this.retryTracker}getPublishAssetRegistry(){return this.publishAssetRegistry}getScheduler(){return this.scheduler}async onShutdown(){await this.scheduler.stop(),aG.resetInstance(),tG.resetInstance(),eG.resetInstance(),Az.resetInstance()}}function cd0(A){return new ud0(A)}p0();K0();var Oo1=K.object({accountId:K.string().describe("Cloudflare account ID"),apiToken:K.string().describe("Cloudflare API token with Analytics:Read permission"),siteTag:K.string().describe("Cloudflare Web Analytics site tag")}),ld0=K.object({cloudflare:Oo1.optional()});p0();K0();var CHB=K.object({date:K.string().describe("Single date in YYYY-MM-DD format").optional(),days:K.number().min(1).max(365).describe("Number of days back from yesterday (e.g., 7 for last week)").optional(),startDate:K.string().describe("Start date in YYYY-MM-DD format (use with endDate)").optional(),endDate:K.string().describe("End date in YYYY-MM-DD format (use with startDate)").optional(),limit:K.number().min(1).max(100).default(20).describe("Maximum items for breakdowns (pages, referrers, countries)")});function yHB(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 xo1(A,Q,B){let w=[];if(!B)return w;return w.push(BB(A,"query",`Query website analytics from Cloudflare.
|
|
6764
|
+
${B.content}`:B.prompt??"Write an engaging LinkedIn post";return A.ai.generate({prompt:w,templateName:`social-media:${B.platform}`})}),A.eval.registerHandler("create",async(Q)=>{let B=PXB.parse(Q),w=[],$=D7.from(async(H)=>{let W={progress:H.progress};if(H.message!==void 0)W.message=H.message;w.push(W)});if(!$)throw Error("Failed to create progress reporter");let f=await new NP(A.logger,A).process(B,`eval-${Date.now()}`,$),Y=!1,X;if(f.success&&f.entityId){let H=await A.entityService.getEntity({entityType:"social-post",id:f.entityId});Y=!!H,X=H?.content.slice(0,300)}return{...f,entityExists:Y,entityPreview:X,progressSteps:w}})}K0();p0();class er{sendMessage;logger;entityService;providers;permissions;resolveAttachment;constructor(A){this.sendMessage=A.sendMessage,this.logger=A.logger,this.entityService=A.entityService,this.providers=A.providers,this.permissions=A.permissions,this.resolveAttachment=A.resolveAttachment}async handle(A){let{entityType:Q,entityId:B}=A;if(Q!=="social-post")return;this.permissions.assertEntityActionAllowed(Q,"publish",A.authContext??{userPermissionLevel:"anchor"}),this.logger.debug("Handling publish:execute",{entityId:B});try{let w=await this.entityService.getEntity({entityType:"social-post",id:B});if(!w){await this.reportFailure(Q,B,`Post not found: ${B}`);return}let $=w;if($.metadata.status==="published"){this.logger.debug("Post already published, skipping",{entityId:B});return}let D=$.metadata.platform,f=this.providers.get(D);if(!f){await this.reportFailure(Q,B,`No provider configured for platform: ${D}`);return}let Y=h2($.content,YW),X;if(Y.metadata.coverImageId)X=await this.fetchImageData(Y.metadata.coverImageId);let H=Y.metadata.documents??[],W=await this.fetchDocumentData(H);try{if(H.length>0&&W.length===0)throw Error(`Refusing to publish: ${H.length} document(s) referenced but none could be fetched`);let Z=H.length===0?await this.resolveSourceAttachment(Y.metadata):[],G=W.length>0?W:Z,F=G.length?await f.publish(Y.content,$.metadata,X,G):await f.publish(Y.content,$.metadata,X),I=new Date().toISOString(),L=F.id||void 0,b={...Y.metadata,status:"published",publishedAt:I,...L&&{platformPostId:L}},N=x7.createPostContent(b,Y.content);await this.entityService.updateEntity({entity:{...$,content:N,metadata:{...$.metadata,status:"published",publishedAt:I,platformPostId:L}}}),await this.reportSuccess(Q,B,F.id),this.logger.info(`Post published successfully: ${B}`,{platform:D,platformPostId:L})}catch(Z){let G=Z instanceof Error?Z.message:String(Z),F={...Y.metadata,status:"failed"},I=x7.createPostContent(F,Y.content);await this.entityService.updateEntity({entity:{...$,content:I,metadata:{...$.metadata,status:"failed"}}}),await this.reportFailure(Q,B,G),this.logger.error(`Post publish failed: ${B}`,{platform:D,error:G})}}catch(w){let $=hA(w);this.logger.error("Unexpected error in publish handler",{entityId:B,error:$}),await this.reportFailure(Q,B,$)}}async reportSuccess(A,Q,B){await this.sendMessage({type:"publish:report:success",payload:{entityType:A,entityId:Q,result:{id:B}}})}async reportFailure(A,Q,B){await this.sendMessage({type:"publish:report:failure",payload:{entityType:A,entityId:Q,error:B}})}async resolveSourceAttachment(A){if(!this.resolveAttachment||!A.sourceEntityType||!A.sourceEntityId)return[];let Q=await this.resolveAttachment({sourceEntityType:A.sourceEntityType,sourceEntityId:A.sourceEntityId,attachmentType:"carousel"});return Q?[Q]:[]}async fetchDocumentData(A){if(!A?.length)return[];let Q=[];for(let B of A){let w=await this.fetchSingleDocumentData(B.id);if(w)Q.push(w)}return Q}async fetchSingleDocumentData(A){try{let Q=await this.entityService.getEntity({entityType:"document",id:A});if(!Q){this.logger.warn("Document not found",{documentId:A});return}let B=Q.content.match(/^data:application\/pdf;base64,(.+)$/);if(!B?.[1]){this.logger.warn("Invalid document data URL format",{documentId:A});return}let w=typeof Q.metadata.filename==="string"?Q.metadata.filename:`${A}.pdf`;return{type:"document",data:Buffer.from(B[1],"base64"),mimeType:"application/pdf",filename:w}}catch(Q){this.logger.warn("Failed to fetch document",{documentId:A,error:Q});return}}async fetchImageData(A){try{let Q=await this.entityService.getEntity({entityType:"image",id:A});if(!Q){this.logger.warn("Cover image not found",{imageId:A});return}let w=Q.content.match(/^data:([^;]+);base64,(.+)$/);if(!w?.[1]||!w[2]){this.logger.warn("Invalid image data URL format",{imageId:A});return}let $=w[1],D=w[2];return{data:Buffer.from(D,"base64"),mimeType:$}}catch(Q){this.logger.warn("Failed to fetch cover image",{imageId:A,error:Q});return}}}function ar1(A,Q,B){if(Q.size===0){B.debug("No providers configured, skipping publish-pipeline registration");return}A.messaging.subscribe("system:plugins:ready",async()=>{let w=Q.values().next().value;return await A.messaging.send({type:"publish:register",payload:{entityType:"social-post",provider:w,config:{publishResultIdField:"platformPostId"}}}),B.info("Registered social-post with publish-pipeline"),{success:!0}})}function tr1(A,Q,B){let w=new er({sendMessage:A.messaging.send,logger:B.child("PublishExecuteHandler"),entityService:A.entityService,providers:Q,permissions:A.permissions,resolveAttachment:A.attachments.resolve});A.messaging.subscribe("publish:execute",async($)=>{return await w.handle($.payload),{success:!0}}),B.debug("Subscribed to publish:execute messages")}K0();function er1(A,Q){A.messaging.subscribe("entity:updated",async(B)=>{let{entityType:w,entityId:$,entity:D}=B.payload;if(w!=="post")return{success:!0};if(D.metadata?.status!=="queued")return{success:!0};try{if((await A.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:$}},limit:1}})).length>0)return Q.debug(`Social post already exists for ${$}, skipping auto-generate`),{success:!0};return await A.messaging.send({type:"social:auto-generate",payload:{sourceEntityType:w,sourceEntityId:$,platform:"linkedin"}}),Q.info(`Auto-generate social post triggered for queued post ${$}`),{success:!0}}catch(Y){let X=hA(Y);return Q.error(`Failed to trigger auto-generate for ${$}:`,{error:X}),{success:!0}}}),Q.debug("Subscribed to entity:updated for auto-generation")}function Ao1(A,Q){A.messaging.subscribe("social:auto-generate",async(B)=>{let{sourceEntityType:w,sourceEntityId:$,platform:D}=B.payload;try{let f=await A.jobs.enqueue({type:`${x7.entityType}:generation`,data:{sourceEntityType:w,sourceEntityId:$,platform:D,addToQueue:!1},toolContext:{interfaceType:"job",userId:"system"}});return Q.info(`Social post generation job enqueued for ${w}/${$}`,{jobId:f}),{success:!0,jobId:f}}catch(f){let Y=hA(f);return Q.error(`Failed to enqueue social post generation for ${$}:`,{error:Y}),{success:!1}}}),Q.debug("Subscribed to social:auto-generate messages")}function Qo1(A,Q){A.messaging.subscribe("generate:execute",async(B)=>{let{entityType:w}=B.payload;if(w!=="social-post")return{success:!0};Q.info("Received generate:execute for social-post");try{let $=await A.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:5}});if($.length===0)return Q.info("No published posts found for social post generation"),await A.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:"No published posts available for social post generation"}}),{success:!0};let D=null;for(let Y of $)if((await A.entityService.listEntities({entityType:"social-post",options:{filter:{metadata:{sourceEntityType:"post",sourceEntityId:Y.id}},limit:1}})).length===0){D=Y;break}if(!D)return Q.info("All recent posts already have social posts"),await A.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:"All recent posts already have social posts generated"}}),{success:!0};let f=await A.jobs.enqueue({type:`${x7.entityType}:generation`,data:{sourceEntityType:"post",sourceEntityId:D.id,platform:"linkedin",addToQueue:!1},toolContext:{interfaceType:"job",userId:"system"}});return Q.info("Social post generation job queued",{jobId:f,sourcePostId:D.id}),{success:!0}}catch($){let D=hA($);return Q.error("Failed to handle generate:execute:",{error:D}),await A.messaging.send({type:"generate:report:failure",payload:{entityType:"social-post",error:D}}),{success:!0}}}),Q.debug("Subscribed to generate:execute messages")}async function Bo1({entity:A,config:Q}){let B=RL.parse(A),w=x7.parsePostFrontmatter(B),$=x7.getPostContent(B);return{$type:"ai.rizom.brain.socialPost",title:w.title,platform:w.platform,body:$,format:"text/markdown",status:w.status,...w.publishedAt&&{publishedAt:w.publishedAt},...w.platformPostId&&{platformPostId:w.platformPostId},...w.sourceEntityType&&{sourceLocalEntityType:w.sourceEntityType},...w.sourceEntityId&&{sourceLocalEntityId:w.sourceEntityId},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},sourceEntityType:"social-post",sourceEntityId:B.id,createdAt:B.created,...B.updated&&{updatedAt:B.updated}}}function bd0(){return{entityType:"social-post",collection:"ai.rizom.brain.socialPost",lexicon:_w["ai.rizom.brain.socialPost"],validate:!1,buildRecord:Bo1}}var wo1={name:"@brains/social-media",private:!0,version:"0.2.0-alpha.129",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/atproto-contracts":"workspace:*","@brains/contracts":"workspace:*","@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 Nd0 extends PQ{entityType=x7.entityType;schema=RL;adapter=x7;providers=new Map;unregisterAtprotoProjection;constructor(A){super("social-media",wo1,A,zd0)}createGenerationHandler(A){return new NP(this.logger.child("GenerationJobHandler"),A)}getTemplates(){return or1()}getDataSources(){return[new mD0(this.logger.child("SocialPostDataSource"))]}getEntityTypeConfig(){return{publish:{publishStatuses:["queued","published","failed"]}}}async onRegister(A){if(this.initializeProviders(),ar1(A,this.providers,this.logger),tr1(A,this.providers,this.logger),this.config.autoGenerateOnBlogPublish)er1(A,this.logger),Ao1(A,this.logger),this.logger.info("Auto-generate on blog publish enabled");Qo1(A,this.logger),sr1(A),this.unregisterAtprotoProjection=U5.getInstance().register(bd0()),this.logger.info("Social media plugin registered successfully")}async onShutdown(){this.unregisterAtprotoProjection?.(),this.unregisterAtprotoProjection=void 0}initializeProviders(){if(this.config.linkedin?.accessToken){let A=Ld0(this.config.linkedin,this.logger.child("LinkedInClient"));this.providers.set("linkedin",A),this.logger.info("LinkedIn provider initialized")}}}function Ao(A){return new Nd0(A)}K0();var OXB=K.enum(["draft","queued","published","failed"]),$o1=K.object({status:OXB.default("draft"),queueOrder:K.number().optional().describe("Position in publish queue (lower = sooner)"),publishedAt:K.string().datetime().optional()});class jd0{name="internal";async publish(A,Q){return{id:"internal"}}}var Qo={interfaceType:"system",userId:"system",userPermissionLevel:"anchor",authorization:"system"},xD={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",QUEUED:"publish:queued",COMPLETED:"publish:completed",FAILED:"publish:failed",LIST_RESPONSE:"publish:list:response"},vL={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"},Do1={REGISTER:"publish-assets:register"};K0();var xXB=K.enum(["provider"]),fo1=K.object({executionMode:xXB.optional(),publishResultIdField:K.string().min(1).optional(),publishTimestampField:K.string().min(1).optional(),enabled:K.boolean().optional()}).strict();var RXB=K.object({skipIfDraftExists:K.boolean().optional(),minSourceEntities:K.number().optional(),maxUnpublishedDrafts:K.number().optional(),sourceEntityType:K.string().optional()}),Yo1=K.object({entitySchedules:K.record(K.string(),K.string()).optional(),generationSchedules:K.record(K.string(),K.string()).optional(),generationConditions:K.record(K.string(),RXB).optional()});class aG{static instance=null;queues=new Map;static getInstance(){return aG.instance??=new aG,aG.instance}static resetInstance(){aG.instance=null}static createFresh(){return new aG}constructor(){}async add(A,Q,B=Qo){let w=this.getOrCreateQueue(A),$=w.find((Y)=>Y.entityId===Q);if($)return{position:$.position};let D=w.length+1,f={entityId:Q,entityType:A,position:D,queuedAt:new Date().toISOString(),authContext:{...B}};return w.push(f),{position:D}}async remove(A,Q){let B=this.queues.get(A);if(!B)return;let w=B.findIndex(($)=>$.entityId===Q);if(w===-1)return;B.splice(w,1),this.recalculatePositions(B)}async reorder(A,Q,B){let w=this.queues.get(A);if(!w)return;let $=w.findIndex((Y)=>Y.entityId===Q);if($===-1)return;let[D]=w.splice($,1);if(!D)return;let f=Math.max(0,Math.min(B-1,w.length));w.splice(f,0,D),this.recalculatePositions(w)}async list(A){let Q=this.queues.get(A);if(!Q)return[];return[...Q]}async getNext(A){let Q=this.queues.get(A);if(!Q||Q.length===0)return null;return Q[0]??null}async getNextAcrossTypes(){let A=null;for(let Q of this.queues.values()){let B=Q[0];if(!B)continue;if(!A||B.queuedAt<A.queuedAt)A=B}return A}async popNext(A){let Q=this.queues.get(A);if(!Q||Q.length===0)return null;let B=Q.shift()??null;if(B)this.recalculatePositions(Q);return B}getRegisteredTypes(){return Array.from(this.queues.keys())}async getQueuedEntityTypes(){let A=[];for(let[Q,B]of this.queues.entries())if(B.length>0)A.push(Q);return A}getOrCreateQueue(A){let Q=this.queues.get(A);if(!Q)Q=[],this.queues.set(A,Q);return Q}recalculatePositions(A){A.forEach((Q,B)=>{Q.position=B+1})}}class tG{static instance=null;providers=new Map;executionModes=new Map;publishResultIdFields=new Map;publishTimestampFields=new Map;defaultProvider=new jd0;static getInstance(){return tG.instance??=new tG,tG.instance}static resetInstance(){tG.instance=null}static createFresh(){return new tG}constructor(){}register(A,Q,B){let w=this.providers.get(A);if(w&&w.name!=="internal"&&Q.name==="internal")return;if(this.providers.set(A,Q),this.executionModes.set(A,B?.executionMode??"provider"),B?.publishResultIdField)this.publishResultIdFields.set(A,B.publishResultIdField);else this.publishResultIdFields.delete(A);if(B?.publishTimestampField)this.publishTimestampFields.set(A,B.publishTimestampField);else this.publishTimestampFields.delete(A)}get(A){return this.providers.get(A)??this.defaultProvider}getExecutionMode(A){return this.executionModes.get(A)??"provider"}getPublishResultIdField(A){return this.publishResultIdFields.get(A)}getPublishTimestampField(A){return this.publishTimestampFields.get(A)}has(A){return this.providers.has(A)}unregister(A){this.providers.delete(A),this.executionModes.delete(A),this.publishResultIdFields.delete(A),this.publishTimestampFields.delete(A)}getRegisteredTypes(){return Array.from(this.providers.keys())}}K0();K0();async function Xo1(A,Q){if(!Q.publishExecutor){Q.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:"Publish executor not configured",retryCount:0,willRetry:!1});return}await vXB(A,Q)}async function vXB(A,Q){if(!Q.publishExecutor)return;try{let B=await Q.publishExecutor.publish({entityType:A.entityType,id:A.entityId});if("error"in B){let w={entityType:A.entityType,entityId:A.entityId,error:B.error,retryCount:0,willRetry:!1};if(Q.messageBus)await Q.messageBus.send({type:xD.FAILED,payload:w,sender:"publish-service"});Q.onFailed?.(w);return}_d0(A.entityType,A.entityId,B.result,Q)}catch(B){let w=hA(B);Q.retryTracker.recordFailure(A.entityId,w);let $=Q.retryTracker.getRetryInfo(A.entityId);Q.onFailed?.({entityType:A.entityType,entityId:A.entityId,error:w,retryCount:$?.retryCount??1,willRetry:!1})}}function _d0(A,Q,B,w){if(w.retryTracker.clearRetries(Q),w.messageBus)w.messageBus.send({type:xD.COMPLETED,payload:{entityType:A,entityId:Q,result:B},sender:"publish-service"});w.onPublish?.({entityType:A,entityId:Q,result:B})}function Ho1(A,Q,B,w){w.retryTracker.recordFailure(Q,B);let $=w.retryTracker.getRetryInfo(Q),D={entityType:A,entityId:Q,error:B,retryCount:$?.retryCount??1,willRetry:!1};if(w.messageBus)w.messageBus.send({type:xD.FAILED,payload:D,sender:"publish-service"});w.onFailed?.(D)}async function Wo1(A,Q){let B=Q.generationConditions[A];if(B&&Q.onCheckGenerationConditions){let $=await Q.onCheckGenerationConditions(A,B);if(!$.shouldGenerate){if(Q.messageBus)Q.messageBus.send({type:vL.SKIPPED,payload:{entityType:A,reason:$.reason??"Conditions not met"},sender:"content-pipeline"});return}}let w={entityType:A};if(Q.messageBus)await Q.messageBus.send({type:vL.EXECUTE,payload:w,sender:"content-pipeline"});Q.onGenerate?.(w)}function Zo1(A,Q,B){if(B)B.send({type:vL.COMPLETED,payload:{entityType:A,entityId:Q},sender:"content-pipeline"})}function Ko1(A,Q,B){if(B)B.send({type:vL.FAILED,payload:{entityType:A,error:Q},sender:"content-pipeline"})}var hXB=1000;class Md0{deps;publishJobs=new Map;immediateIntervalJob=null;constructor(A){this.deps=A}start(){for(let[A,Q]of Object.entries(this.entitySchedules)){let B=this.deps.config.backend.scheduleCron(Q,()=>this.processEntityType(A));this.publishJobs.set(A,B)}this.immediateIntervalJob=this.deps.config.backend.scheduleInterval(hXB,()=>this.processUnscheduledTypes())}stop(){if(CXB(this.publishJobs),this.immediateIntervalJob)this.immediateIntervalJob.stop(),this.immediateIntervalJob=null}async processEntityType(A){if(!this.deps.isRunning())return;try{let Q=await this.deps.config.queueManager.getNext(A);if(Q)await this.processEntry(Q)}catch(Q){this.deps.config.logger.error(`Scheduler error for ${A}:`,Q)}}async processUnscheduledTypes(){if(!this.deps.isRunning())return;try{let A=await this.deps.config.queueManager.getQueuedEntityTypes();for(let Q of A)if(!this.entitySchedules[Q]){let B=await this.deps.config.queueManager.getNext(Q);if(B){await this.processEntry(B);break}}}catch(A){this.deps.config.logger.error("Scheduler error for unscheduled types:",A)}}async processEntry(A){await this.deps.config.queueManager.remove(A.entityType,A.entityId);let Q=this.deps.getPublishDeps();await Xo1(A,Q)}get entitySchedules(){return this.deps.config.entitySchedules}}function CXB(A){for(let Q of A.values())Q.stop();A.clear()}class Pd0{deps;generationJobs=new Map;constructor(A){this.deps=A}start(){for(let[A,Q]of Object.entries(this.generationSchedules)){let B=this.deps.config.backend.scheduleCron(Q,()=>this.handleTriggerGeneration(A));this.generationJobs.set(A,B)}}stop(){yXB(this.generationJobs)}async handleTriggerGeneration(A){if(!this.deps.isRunning())return;try{await Wo1(A,this.deps.getGenerationDeps())}catch(Q){this.deps.config.logger.error(`Generation trigger error for ${A}:`,Q)}}get generationSchedules(){return this.deps.config.generationSchedules}}function yXB(A){for(let Q of A.values())Q.stop();A.clear()}class bK{static instance=null;config;publishRunner;generationRunner;running=!1;static getInstance(A){return bK.instance??=new bK(A),bK.instance}static resetInstance(){if(bK.instance)bK.instance.stop();bK.instance=null}static createFresh(A){return new bK(A)}constructor(A){this.config={...A,entitySchedules:A.entitySchedules??{},generationSchedules:A.generationSchedules??{},generationConditions:A.generationConditions??{}},this.validateCronExpressions(),this.publishRunner=new Md0({config:this.config,getPublishDeps:()=>this.publishDeps,isRunning:()=>this.running}),this.generationRunner=new Pd0({config:this.config,getGenerationDeps:()=>this.generationDeps,isRunning:()=>this.running})}async start(){if(this.running)return;this.running=!0,this.publishRunner.start(),this.generationRunner.start()}async stop(){this.running=!1,this.publishRunner.stop(),this.generationRunner.stop()}isRunning(){return this.running}completePublish(A,Q,B){_d0(A,Q,B,this.publishDeps)}failPublish(A,Q,B){Ho1(A,Q,B,this.publishDeps)}completeGeneration(A,Q){Zo1(A,Q,this.config.messageBus)}failGeneration(A,Q){Ko1(A,Q,this.config.messageBus)}get entitySchedules(){return this.config.entitySchedules}get generationSchedules(){return this.config.generationSchedules}get publishDeps(){return{retryTracker:this.config.retryTracker,messageBus:this.config.messageBus,publishExecutor:this.config.publishExecutor,onPublish:this.config.onPublish,onFailed:this.config.onFailed}}get generationDeps(){return{logger:this.config.logger,messageBus:this.config.messageBus,generationConditions:this.config.generationConditions,onCheckGenerationConditions:this.config.onCheckGenerationConditions,onGenerate:this.config.onGenerate}}validateCronExpressions(){for(let[A,Q]of Object.entries(this.entitySchedules))this.validateCronExpression(A,Q,"publish");for(let[A,Q]of Object.entries(this.generationSchedules))this.validateCronExpression(A,Q,"generation")}validateCronExpression(A,Q,B){try{this.config.backend.validateCron(Q)}catch(w){throw Error(`Invalid ${B} cron expression for ${A}: "${Q}" - ${hA(w)}`)}}}class eG{static instance=null;retries=new Map;static getInstance(){return eG.instance??=new eG,eG.instance}static resetInstance(){eG.instance=null}static createFresh(){return new eG}constructor(){}recordFailure(A,Q){let w=(this.retries.get(A)?.retryCount??0)+1;this.retries.set(A,{entityId:A,retryCount:w,lastError:Q})}clearRetries(A){this.retries.delete(A)}getRetryInfo(A){let Q=this.retries.get(A);if(!Q)return null;return{entityId:Q.entityId,retryCount:Q.retryCount,lastError:Q.lastError}}}function M4(A,Q,B,w,$,D,f,Y){return M4.fromTZ(M4.tp(A,Q,B,w,$,D,f),Y)}M4.fromTZISO=(A,Q,B)=>M4.fromTZ(EXB(A,Q),B);M4.fromTZ=function(A,Q){let B=new Date(Date.UTC(A.y,A.m-1,A.d,A.h,A.i,A.s)),w=kd0(A.tz,B),$=new Date(B.getTime()-w),D=kd0(A.tz,$);if(D-w===0)return $;{let f=new Date(B.getTime()-D),Y=kd0(A.tz,f);if(Y-D===0)return f;if(!Q&&Y-D>0)return f;if(Q)throw Error("Invalid date passed to fromTZ()");return $}};M4.toTZ=function(A,Q){let B=A.toLocaleString("en-US",{timeZone:Q}).replace(/[\u202f]/," "),w=new Date(B);return{y:w.getFullYear(),m:w.getMonth()+1,d:w.getDate(),h:w.getHours(),i:w.getMinutes(),s:w.getSeconds(),tz:Q}};M4.tp=(A,Q,B,w,$,D,f)=>({y:A,m:Q,d:B,h:w,i:$,s:D,tz:f});function kd0(A,Q=new Date){let B=Q.toLocaleString("en-US",{timeZone:A,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],w=Q.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${w} GMT`)-Date.parse(`${w} ${B}`)}function EXB(A,Q){let B=new Date(Date.parse(A));if(isNaN(B))throw Error("minitz: Invalid ISO8601 passed to parser.");let w=A.substring(9);return A.includes("Z")||w.includes("-")||w.includes("+")?M4.tp(B.getUTCFullYear(),B.getUTCMonth()+1,B.getUTCDate(),B.getUTCHours(),B.getUTCMinutes(),B.getUTCSeconds(),"Etc/UTC"):M4.tp(B.getFullYear(),B.getMonth()+1,B.getDate(),B.getHours(),B.getMinutes(),B.getSeconds(),Q)}M4.minitz=M4;var Od0=32,wo=31|Od0,qo1=[1,2,4,8,16],Uo1=class{pattern;timezone;second;minute;hour;day;month;dayOfWeek;lastDayOfMonth;starDOM;starDOW;constructor(A,Q){this.pattern=A,this.timezone=Q,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 Q=new XW(new Date,this.timezone).getDate(!0);A[0]=A[0].replace("?",Q.getSeconds().toString()),A[1]=A[1].replace("?",Q.getMinutes().toString()),A[2]=A[2].replace("?",Q.getHours().toString()),this.starDOM||(A[3]=A[3].replace("?",Q.getDate().toString())),A[4]=A[4].replace("?",(Q.getMonth()+1).toString()),this.starDOW||(A[5]=A[5].replace("?",Q.getDay().toString()))}this.throwAtIllegalCharacters(A),this.partToArray("second",A[0],0,1),this.partToArray("minute",A[1],0,1),this.partToArray("hour",A[2],0,1),this.partToArray("day",A[3],-1,1),this.partToArray("month",A[4],-1,1),this.partToArray("dayOfWeek",A[5],0,wo),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(A,Q,B,w){let $=this[A],D=A==="day"&&this.lastDayOfMonth;if(Q===""&&!D)throw TypeError("CronPattern: configuration entry "+A+" ("+Q+") is empty, check for trailing spaces.");if(Q==="*")return $.fill(w);let f=Q.split(",");if(f.length>1)for(let Y=0;Y<f.length;Y++)this.partToArray(A,f[Y],B,w);else Q.indexOf("-")!==-1&&Q.indexOf("/")!==-1?this.handleRangeWithStepping(Q,A,B,w):Q.indexOf("-")!==-1?this.handleRange(Q,A,B,w):Q.indexOf("/")!==-1?this.handleStepping(Q,A,B,w):Q!==""&&this.handleNumber(Q,A,B,w)}throwAtIllegalCharacters(A){for(let Q=0;Q<A.length;Q++)if((Q===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(A[Q]))throw TypeError("CronPattern: configuration entry "+Q+" ("+A[Q]+") contains illegal characters.")}handleNumber(A,Q,B,w){let $=this.extractNth(A,Q),D=parseInt($[0],10)+B;if(isNaN(D))throw TypeError("CronPattern: "+Q+" is not a number: '"+A+"'");this.setPart(Q,D,$[1]||w)}setPart(A,Q,B){if(!Object.prototype.hasOwnProperty.call(this,A))throw TypeError("CronPattern: Invalid part specified: "+A);if(A==="dayOfWeek"){if(Q===7&&(Q=0),Q<0||Q>6)throw RangeError("CronPattern: Invalid value for dayOfWeek: "+Q);this.setNthWeekdayOfMonth(Q,B);return}if(A==="second"||A==="minute"){if(Q<0||Q>=60)throw RangeError("CronPattern: Invalid value for "+A+": "+Q)}else if(A==="hour"){if(Q<0||Q>=24)throw RangeError("CronPattern: Invalid value for "+A+": "+Q)}else if(A==="day"){if(Q<0||Q>=31)throw RangeError("CronPattern: Invalid value for "+A+": "+Q)}else if(A==="month"&&(Q<0||Q>=12))throw RangeError("CronPattern: Invalid value for "+A+": "+Q);this[A][Q]=B}handleRangeWithStepping(A,Q,B,w){let $=this.extractNth(A,Q),D=$[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(D===null)throw TypeError("CronPattern: Syntax error, illegal range with stepping: '"+A+"'");let[,f,Y,X]=D,H=parseInt(f,10)+B,W=parseInt(Y,10)+B,Z=parseInt(X,10);if(isNaN(H))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(W))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(Z))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(Z===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(Z>this[Q].length)throw TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[Q].length+")");if(H>W)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let G=H;G<=W;G+=Z)this.setPart(Q,G,$[1]||w)}extractNth(A,Q){let B=A,w;if(B.includes("#")){if(Q!=="dayOfWeek")throw Error("CronPattern: nth (#) only allowed in day-of-week field");w=B.split("#")[1],B=B.split("#")[0]}return[B,w]}handleRange(A,Q,B,w){let $=this.extractNth(A,Q),D=$[0].split("-");if(D.length!==2)throw TypeError("CronPattern: Syntax error, illegal range: '"+A+"'");let f=parseInt(D[0],10)+B,Y=parseInt(D[1],10)+B;if(isNaN(f))throw TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(Y))throw TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(f>Y)throw TypeError("CronPattern: From value is larger than to value: '"+A+"'");for(let X=f;X<=Y;X++)this.setPart(Q,X,$[1]||w)}handleStepping(A,Q,B,w){let $=this.extractNth(A,Q),D=$[0].split("/");if(D.length!==2)throw TypeError("CronPattern: Syntax error, illegal stepping: '"+A+"'");D[0]===""&&(D[0]="*");let f=0;D[0]!=="*"&&(f=parseInt(D[0],10)+B);let Y=parseInt(D[1],10);if(isNaN(Y))throw TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(Y===0)throw TypeError("CronPattern: Syntax error, illegal stepping: 0");if(Y>this[Q].length)throw TypeError("CronPattern: Syntax error, max steps for part is ("+this[Q].length+")");for(let X=f;X<this[Q].length;X+=Y)this.setPart(Q,X,$[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 Q=A.trim().toLowerCase();return Q==="@yearly"||Q==="@annually"?"0 0 1 1 *":Q==="@monthly"?"0 0 1 * *":Q==="@weekly"?"0 0 * * 0":Q==="@daily"?"0 0 * * *":Q==="@hourly"?"0 * * * *":A}setNthWeekdayOfMonth(A,Q){if(typeof Q!="number"&&Q==="L")this.dayOfWeek[A]=this.dayOfWeek[A]|Od0;else if(Q===wo)this.dayOfWeek[A]=wo;else if(Q<6&&Q>0)this.dayOfWeek[A]=this.dayOfWeek[A]|qo1[Q-1];else throw TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${Q}, Type: ${typeof Q}`)}},Go1=[31,28,31,30,31,30,31,31,30,31,30,31],zF=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],XW=class A{tz;ms;second;minute;hour;day;month;year;constructor(Q,B){if(this.tz=B,Q&&Q instanceof Date)if(!isNaN(Q))this.fromDate(Q);else throw TypeError("CronDate: Invalid date passed to CronDate constructor");else if(Q===void 0)this.fromDate(new Date);else if(Q&&typeof Q=="string")this.fromString(Q);else if(Q instanceof A)this.fromCronDate(Q);else throw TypeError("CronDate: Invalid type ("+typeof Q+") passed to CronDate constructor")}isNthWeekdayOfMonth(Q,B,w,$){let D=new Date(Date.UTC(Q,B,w)).getUTCDay(),f=0;for(let Y=1;Y<=w;Y++)new Date(Date.UTC(Q,B,Y)).getUTCDay()===D&&f++;if($&wo&&qo1[f-1]&$)return!0;if($&Od0){let Y=new Date(Date.UTC(Q,B+1,0)).getUTCDate();for(let X=w+1;X<=Y;X++)if(new Date(Date.UTC(Q,B,X)).getUTCDay()===D)return!1;return!0}return!1}fromDate(Q){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=Q.getUTCMilliseconds(),this.second=Q.getUTCSeconds(),this.minute=Q.getUTCMinutes()+this.tz,this.hour=Q.getUTCHours(),this.day=Q.getUTCDate(),this.month=Q.getUTCMonth(),this.year=Q.getUTCFullYear(),this.apply();else{let B=M4.toTZ(Q,this.tz);this.ms=Q.getMilliseconds(),this.second=B.s,this.minute=B.i,this.hour=B.h,this.day=B.d,this.month=B.m-1,this.year=B.y}else this.ms=Q.getMilliseconds(),this.second=Q.getSeconds(),this.minute=Q.getMinutes(),this.hour=Q.getHours(),this.day=Q.getDate(),this.month=Q.getMonth(),this.year=Q.getFullYear()}fromCronDate(Q){this.tz=Q.tz,this.year=Q.year,this.month=Q.month,this.day=Q.day,this.hour=Q.hour,this.minute=Q.minute,this.second=Q.second,this.ms=Q.ms}apply(){if(this.month>11||this.day>Go1[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let Q=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return 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(),!0}else return!1}fromString(Q){if(typeof this.tz=="number"){let B=M4.fromTZISO(Q);this.ms=B.getUTCMilliseconds(),this.second=B.getUTCSeconds(),this.minute=B.getUTCMinutes(),this.hour=B.getUTCHours(),this.day=B.getUTCDate(),this.month=B.getUTCMonth(),this.year=B.getUTCFullYear(),this.apply()}else return this.fromDate(M4.fromTZISO(Q,this.tz))}findNext(Q,B,w,$){let D=this[B],f;w.lastDayOfMonth&&(this.month!==1?f=Go1[this.month]:f=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let Y=!w.starDOW&&B=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let X=this[B]+$;X<w[B].length;X++){let H=w[B][X];if(B==="day"&&w.lastDayOfMonth&&X-$==f&&(H=1),B==="day"&&!w.starDOW){let W=w.dayOfWeek[(Y+(X-$-1))%7];if(W&&W&wo)W=this.isNthWeekdayOfMonth(this.year,this.month,X-$,W)?1:0;else if(W)throw Error(`CronDate: Invalid value for dayOfWeek encountered. ${W}`);Q.legacyMode&&!w.starDOM?H=H||W:H=H&&W}if(H)return this[B]=X-$,D!==this[B]?2:1}return 3}recurse(Q,B,w){let $=this.findNext(B,zF[w][0],Q,zF[w][2]);if($>1){let D=w+1;for(;D<zF.length;)this[zF[D][0]]=-zF[D][2],D++;if($===3)return this[zF[w][1]]++,this[zF[w][0]]=-zF[w][2],this.apply(),this.recurse(Q,B,0);if(this.apply())return this.recurse(Q,B,w-1)}return w+=1,w>=zF.length?this:this.year>=3000?null:this.recurse(Q,B,w)}increment(Q,B,w){return this.second+=B.interval!==void 0&&B.interval>1&&w?B.interval:1,this.ms=0,this.apply(),this.recurse(Q,B,0)}getDate(Q){return Q||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)):M4.fromTZ(M4.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function gXB(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 XW(A.startAt,A.timezone)),A.stopAt&&(A.stopAt=new XW(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 Bo(A){return Object.prototype.toString.call(A)==="[object Function]"||typeof A=="function"||A instanceof Function}function TXB(A){return Bo(A)}function SXB(A){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(A):A&&typeof A.unref<"u"&&A.unref()}var zo1=30000,iD0=[],xd0=class{name;options;_states;fn;constructor(A,Q,B){let w,$;if(Bo(Q))$=Q;else if(typeof Q=="object")w=Q;else if(Q!==void 0)throw Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(Bo(B))$=B;else if(typeof B=="object")w=B;else if(B!==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=gXB(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 Uo1("* * * * *")},A&&(A instanceof Date||typeof A=="string"&&A.indexOf(":")>0)?this._states.once=new XW(A,this.options.timezone||this.options.utcOffset):this._states.pattern=new Uo1(A,this.options.timezone),this.name){if(iD0.find((D)=>D.name===this.name))throw Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");iD0.push(this)}return $!==void 0&&TXB($)&&(this.fn=$,this.schedule()),this}nextRun(A){let Q=this._next(A);return Q?Q.getDate(!1):null}nextRuns(A,Q){this._states.maxRuns!==void 0&&A>this._states.maxRuns&&(A=this._states.maxRuns);let B=[],w=Q||this._states.currentRun||void 0;for(;A--&&(w=this.nextRun(w));)B.push(w);return B}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let A=this.nextRun(this._states.currentRun),Q=!this._states.paused,B=this.fn!==void 0,w=!this._states.kill;return Q&&B&&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 Q=this._next(A);return Q?A instanceof XW||A instanceof Date?Q.getTime()-A.getTime():Q.getTime()-new XW(A).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let A=iD0.indexOf(this);A>=0&&iD0.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 Q=this.msToNext(),B=this.nextRun(this._states.currentRun);return Q==null||isNaN(Q)||B===null?this:(Q>zo1&&(Q=zo1),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(B),Q),this._states.currentTimeout&&this.options.unref&&SXB(this._states.currentTimeout),this)}async _trigger(A){if(this._states.blocking=!0,this._states.currentRun=new XW(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{this.fn!==void 0&&await this.fn(this,this.options.context)}catch(Q){Bo(this.options.catch)&&this.options.catch(Q,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new XW(A,this.options.timezone||this.options.utcOffset),this._states.blocking=!1}async trigger(){await this._trigger()}runsLeft(){return this._states.maxRuns}_checkTrigger(A){let Q=new Date,B=!this._states.paused&&Q.getTime()>=A.getTime(),w=this._states.blocking&&this.options.protect;B&&!w?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):B&&w&&Bo(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(A){let Q=!!(A||this._states.currentRun),B=!1;!A&&this.options.startAt&&this.options.interval&&([A,Q]=this._calculatePreviousRun(A,Q),B=!A),A=new XW(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 XW(A,this.options.timezone||this.options.utcOffset);return!B&&w!==this._states.once&&(w=w.increment(this._states.pattern,this.options,Q)),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,Q){let B=new XW(void 0,this.options.timezone||this.options.utcOffset),w=A;if(this.options.startAt.getTime()<=B.getTime()){w=this.options.startAt;let $=w.getTime()+this.options.interval*1000;for(;$<=B.getTime();)w=new XW(w,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),$=w.getTime()+this.options.interval*1000;Q=!0}return w===null&&(w=void 0),[w,Q]}};class dD0{scheduleCron(A,Q){let B=new xd0(A,()=>{Q()});return{stop:()=>B.stop()}}scheduleInterval(A,Q){let B=setInterval(()=>{Q()},A);return{stop:()=>clearInterval(B)}}validateCron(A){new xd0(A).stop()}}K0();var Fo1=K.union([K.string().min(1),K.object({location:K.enum(["metadata","frontmatter"]),field:K.string().min(1)})]),nD0=K.object({entityType:K.string().min(1),attachmentType:K.string().min(1),mediaEntityType:K.enum(["image","document"]),targetEntityField:Fo1.optional(),requiredWhen:K.object({status:K.string().min(1).optional(),visibility:K.string().min(1).optional()}).optional(),autoGenerate:K.boolean().optional(),requiredForPublish:K.boolean().optional(),jobType:K.string().min(1).optional()});function Rd0(A){return`${A.entityType}:${A.attachmentType}`}class Az{static instance=null;definitions=new Map;static getInstance(){return Az.instance??=new Az,Az.instance}static resetInstance(){Az.instance=null}static createFresh(){return new Az}constructor(){}register(A){let Q=nD0.parse(A),B=Rd0(Q);return this.definitions.set(B,Q),()=>this.unregister(Q.entityType,Q.attachmentType)}get(A,Q){return this.definitions.get(Rd0({entityType:A,attachmentType:Q}))}list(A){let Q=Array.from(this.definitions.values());return A?Q.filter((B)=>B.entityType===A):Q}has(A,Q){return this.get(A,Q)!==void 0}unregister(A,Q){this.definitions.delete(Rd0({entityType:A,attachmentType:Q}))}clear(){this.definitions.clear()}}K0();class rD0{deps;constructor(A){this.deps=A}async ensureForEntity(A,Q={}){let B=this.deps.registry.list(A.entityType).filter(($)=>$.autoGenerate===!0).filter(($)=>!Q.attachmentType||$.attachmentType===Q.attachmentType),w={checked:B.length,enqueued:0,skipped:0};for(let $ of B)if(await this.ensureDefinition(A,$))w.enqueued+=1;else w.skipped+=1;return w}async ensureDefinition(A,Q){if(!this.matchesPolicy(A,Q))return!1;if(this.hasTargetField(A,Q.targetEntityField))return!1;if(!this.deps.context.attachments.hasProvider(A.entityType,Q.attachmentType))return!1;let B=this.resolveJobType(Q);if(!B)return!1;let w=this.getPredictedMediaId(A,Q),$=this.getDeduplicationKey(A,Q);return await this.deps.context.jobs.enqueue({type:B,data:{sourceEntityType:A.entityType,sourceEntityId:A.id,attachmentType:Q.attachmentType,imageId:w,dedupKey:$,targetEntityType:A.entityType,targetEntityId:A.id,...this.getTargetImageFieldData(Q.targetEntityField)},options:{source:"content-pipeline",metadata:{operationType:"content_operations"},deduplication:"skip",deduplicationKey:$}}),this.deps.context.logger.debug("Queued publish asset generation",{entityType:A.entityType,entityId:A.id,attachmentType:Q.attachmentType,jobType:B}),!0}matchesPolicy(A,Q){let{requiredWhen:B}=Q;if(!B)return!0;if(B.status&&A.metadata.status!==B.status)return!1;if(B.visibility&&A.visibility!==B.visibility)return!1;return!0}hasTargetField(A,Q){if(!Q)return!1;if(typeof Q==="string")return vd0(A.metadata[Q]);if(Q.location==="metadata")return vd0(A.metadata[Q.field]);let{frontmatter:B}=lB(A.content);return vd0(B[Q.field])}resolveJobType(A){if(A.jobType)return A.jobType;if(A.mediaEntityType==="image")return"image:image-render-source";return}getPredictedMediaId(A,Q){let B=Q.attachmentType==="og-image"?"og":Q.attachmentType;return Y1(`${B}-${A.entityType}-${A.id}`)}getDeduplicationKey(A,Q){return`publish-asset:${Q.attachmentType}:${A.entityType}:${A.id}`}getTargetImageFieldData(A){let Q=typeof A==="string"?A:A?.field;if(Q==="coverImageId"||Q==="ogImageId")return{targetImageField:Q};return{}}}function vd0(A){return typeof A==="string"?A.length>0:A!==void 0}p0();K0();var mXB=K.object({id:K.string().min(1)});async function Vo1(A,Q){let{bodyContent:B,coverImageId:w,documents:$,sourceEntityType:D,sourceEntityId:f}=uXB(Q.content),Y=w?await pXB(A,w):void 0,X;if($&&$.length>0){let W=await iXB(A,$);if(W.length>0)X=W}X??=await lXB(A,D,f);let H={bodyContent:B};if(Y)H.imageData=Y;if(X&&X.length>0)H.documentData=X;return H}function uXB(A){try{let Q=h2(A,K.record(K.unknown())),B=Q.metadata.coverImageId,w=typeof B==="string"?B:void 0,$=cXB(Q.metadata.documents),D=Io1(Q.metadata.sourceEntityType),f=Io1(Q.metadata.sourceEntityId);return{bodyContent:Q.content,...w&&{coverImageId:w},...$.length>0&&{documents:$},...D&&{sourceEntityType:D},...f&&{sourceEntityId:f}}}catch{return{bodyContent:A}}}function cXB(A){if(!Array.isArray(A))return[];return A.flatMap((Q)=>{let B=mXB.safeParse(Q);return B.success?[B.data]:[]})}function Io1(A){return typeof A==="string"&&A.length>0?A:void 0}async function lXB(A,Q,B){if(!Q||!B)return;let w=await A.attachments.resolve({sourceEntityType:Q,sourceEntityId:B,attachmentType:"carousel"});return w?[w]:void 0}async function pXB(A,Q){let B=await A.entityService.getEntity({entityType:"image",id:Q});if(!B?.content)return;let w=Jo1(B.content);if(!w?.mimeType.startsWith("image/"))return;return{data:w.data,mimeType:w.mimeType}}async function iXB(A,Q){return(await Promise.all(Q.map((w)=>dXB(A,w)))).filter((w)=>w!==void 0)}async function dXB(A,Q){let B=await A.entityService.getEntity({entityType:"document",id:Q.id});if(!B?.content)return;let w=Jo1(B.content);if(w?.mimeType!=="application/pdf")return;return{type:"document",data:w.data,mimeType:"application/pdf",filename:nXB(B,Q.id)}}function Jo1(A){let Q=A.match(/^data:([^;]+);base64,(.+)$/);if(!Q?.[1]||!Q[2])return;return{mimeType:Q[1],data:Buffer.from(Q[2],"base64")}}function nXB(A,Q){let B=A.metadata.filename;return typeof B==="string"&&B.length>0?B:`${Q}.pdf`}K0();var rXB=/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/;async function hd0(A,Q,B,w={}){let $=w.publishedAt??new Date().toISOString(),D=w.publishTimestampField??"publishedAt",f={...Q.metadata,status:"published",[D]:$,platformId:B.id,...oXB(B.id,w.publishResultIdField)},Y={...Q,content:Lo1(Q.content,$,B.id,w.publishResultIdField,D),metadata:f};return await A.entityService.updateEntity({entity:Y}),Y}function Lo1(A,Q,B,w,$="publishedAt"){if(!rXB.test(A))return A;let D=n4(n4(A,"status","published"),$,Q);if(!B||!w)return D;return n4(D,w,B)}function oXB(A,Q){if(!Q||Q==="platformId")return{};return{[Q]:A}}class JE{deps;constructor(A){this.deps=A}async resolveCandidate(A){let{entityType:Q,id:B,slug:w}=A;if(!B&&!w)return{error:"Either 'id' or 'slug' must be provided"};let $=await this.findPublishableEntity(Q,B,w);if(!$)return{error:`Entity not found: ${Q}:${B??w}`};if($.visibility!=="public")return{error:`Cannot publish ${Q}:${$.id} to a public provider because visibility is ${$.visibility}`};if($.metadata.status==="published")return{error:"Entity is already published"};if(!this.deps.providerRegistry.has(Q))return{error:`No publish provider registered for ${Q}. Check that the required credentials are configured.`};return{entity:$}}async publish(A){let Q=await this.resolveCandidate(A);if("error"in Q)return Q;let{entity:B}=Q,{entityType:w}=A,$=this.deps.providerRegistry.get(w),{bodyContent:D,imageData:f,documentData:Y}=await Vo1(this.deps.context,B),X=await $.publish(D,B.metadata,f,Y),H=this.deps.providerRegistry.getPublishResultIdField(w),W=this.deps.providerRegistry.getPublishTimestampField(w),Z=await hd0(this.deps.context,B,X,{...H?{publishResultIdField:H}:{},...W?{publishTimestampField:W}:{}});return await this.runPublishAssetPreflight(Z),{entity:Z,result:X}}async runPublishAssetPreflight(A){if(!this.deps.publishAssetPreflight)return;try{await this.deps.publishAssetPreflight.ensureForEntity(A)}catch(Q){this.deps.context.logger.warn("Publish asset preflight failed",{entityType:A.entityType,entityId:A.id,error:Q instanceof Error?Q.message:String(Q)})}}async findPublishableEntity(A,Q,B){if(Q)return this.deps.context.entityService.getEntity({entityType:A,id:Q});if(!B)return null;return(await this.deps.context.entityService.listEntities({entityType:A,options:{filter:{metadata:{slug:B}},limit:1}}))[0]??null}}p0();K0();var Cd0=K.object({action:K.enum(["list","add","remove","reorder"]).describe("Queue action to perform"),entityType:K.string().optional().describe("Entity type (required for add/remove/reorder, optional for list)"),entityId:K.string().optional().describe("Entity ID (required for add/remove/reorder)"),position:K.number().optional().describe("New position for reorder action (1-based)")}),yd0=K.object({position:K.number(),entityType:K.string(),entityId:K.string(),queuedAt:K.string()}),sXB=K.object({success:K.literal(!0),message:K.string().optional(),data:K.object({queue:K.array(yd0).optional(),entityType:K.string().optional(),entityId:K.string().optional(),position:K.number().optional()}).optional()}),aXB=K.object({success:K.literal(!1),error:K.string(),code:K.string().optional()}),Ed0=K.union([sXB,aXB]);function oD0(A,Q,B){return{...BB(Q,"queue","Manage the publish queue for all entity types (list, add, remove, reorder)",Cd0,async($,D)=>{let{action:f,entityType:Y,entityId:X,position:H}=$;switch(f){case"list":return tXB(B,Y);case"add":return eXB(A,B,Y,X,D);case"remove":return AHB(A,B,Y,X,D);case"reorder":return QHB(A,B,Y,X,H,D);default:return{success:!1,error:`Unknown action: ${f}`}}}),outputSchema:Ed0}}async function tXB(A,Q){let B=[];if(Q)B=await A.list(Q);else{let $=A.getRegisteredTypes();for(let D of $){let f=await A.list(D);B.push(...f)}B.sort((D,f)=>new Date(D.queuedAt).getTime()-new Date(f.queuedAt).getTime())}if(B.length===0)return{success:!0,data:{queue:[]},message:"No items in queue"};return{success:!0,data:{queue:B.map(($,D)=>({position:D+1,entityType:$.entityType,entityId:$.entityId,queuedAt:$.queuedAt}))},message:`${B.length} items in queue`}}async function eXB(A,Q,B,w,$){let D=gd0("add",B,w);if(!D.success)return D.error;A.permissions.assertEntityActionAllowed(D.entityType,"publish",$??{});let f=await Q.add(D.entityType,D.entityId,{...$,authorization:"user"});return{success:!0,data:{entityType:D.entityType,entityId:D.entityId,position:f.position},message:`Added to queue at position ${f.position}`}}async function AHB(A,Q,B,w,$){let D=gd0("remove",B,w);if(!D.success)return D.error;return A.permissions.assertEntityActionAllowed(D.entityType,"update",$??{}),await Q.remove(D.entityType,D.entityId),{success:!0,data:{entityType:D.entityType,entityId:D.entityId},message:"Removed from queue"}}async function QHB(A,Q,B,w,$,D){let f=gd0("reorder",B,w);if(!f.success)return f.error;let Y=BHB($);if(!Y.success)return Y.error;return A.permissions.assertEntityActionAllowed(f.entityType,"update",D??{}),await Q.reorder(f.entityType,f.entityId,Y.position),{success:!0,data:{entityType:f.entityType,entityId:f.entityId,position:Y.position},message:`Moved to position ${Y.position}`}}function gd0(A,Q,B){if(!Q)return{success:!1,error:{success:!1,error:`entityType is required for ${A} action`}};if(!B)return{success:!1,error:{success:!1,error:`entityId is required for ${A} action`}};return{success:!0,entityType:Q,entityId:B}}function BHB(A){if(A===void 0)return{success:!1,error:{success:!1,error:"position is required for reorder action"}};if(A<1)return{success:!1,error:{success:!1,error:"position must be a positive number"}};return{success:!0,position:A}}K0();import{createHash as wHB}from"crypto";var sD0=K.object({entityType:K.string().describe("Entity type to publish (e.g., social-post, post, deck)"),id:K.string().optional().describe("Entity ID to publish"),slug:K.string().optional().describe("Entity slug to publish"),confirmed:K.boolean().optional(),confirmationToken:K.string().optional(),contentHash:K.string().optional(),expiresAt:K.string().datetime().optional()}),$HB=K.object({success:K.literal(!0),message:K.string().optional(),data:K.object({entityType:K.string().optional(),entityId:K.string().optional(),platformId:K.string().optional(),url:K.string().optional()}).optional()}),DHB=K.object({success:K.literal(!1),error:K.string(),code:K.string().optional()}),fHB=K.object({success:K.literal(!1).optional(),error:K.string().optional(),needsConfirmation:K.literal(!0),toolName:K.string(),summary:K.string(),preview:K.string().optional(),args:K.unknown()}),Td0=K.union([$HB,DHB,fHB]),YHB=900000;function aD0(A,Q,B,w){let $=w??new JE({context:A,providerRegistry:B}),D=`${Q}_publish`;return{name:D,description:"Publish an entity directly to its platform. Call this when the user asks to publish; the tool will request confirmation itself. Works with any registered entity type (social-post, post, deck, etc.)",inputSchema:sD0.shape,outputSchema:Td0,visibility:"anchor",handler:async(f,Y)=>{let X=sD0.safeParse(f);if(!X.success)return{success:!1,error:`Invalid input: ${X.error.errors.map((L)=>`${L.path.join(".")}: ${L.message}`).join(", ")}`};let H=X.data,{entityType:W,id:Z,slug:G}=H;try{A.permissions.assertEntityActionAllowed(W,"publish",Y)}catch(L){return{success:!1,error:L instanceof Error?L.message:String(L)}}let F=await $.resolveCandidate({entityType:W,id:Z,slug:G});if("error"in F)return{success:!1,error:F.error};let{entity:I}=F;if(H.confirmed){let L=HHB(D,H,I);if(L!==null)return L;let b;try{b=await $.publish({entityType:W,id:I.id})}catch(j){return{success:!1,error:j instanceof Error?j.message:String(j)}}if("error"in b)return{success:!1,error:b.error};let{entity:N,result:M}=b;return{success:!0,data:{entityType:W,entityId:N.id,platformId:M.id,url:M.url},message:`Published ${W}:${N.id}`}}return XHB(D,H,I)}}}function XHB(A,Q,B){let w=new Date(Date.now()+YHB).toISOString(),$=bo1(A,B,w),D=WHB(B);return{needsConfirmation:!0,toolName:A,summary:`Publish "${D}"?`,preview:`This will publish ${B.entityType}:${B.id} to its registered public publish provider.`,args:{...Q,id:B.id,slug:void 0,confirmed:!0,confirmationToken:$,contentHash:B.contentHash,expiresAt:w}}}function HHB(A,Q,B){let{confirmationToken:w,contentHash:$,expiresAt:D}=Q;if(!w||!D)return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};let f=Date.parse(D);if(Number.isNaN(f))return{success:!1,error:"Invalid publish confirmation expiry. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};if(f<=Date.now())return{success:!1,error:"Publish confirmation expired. Request confirmation again before publishing.",code:"EXPIRED_CONFIRMATION_TOKEN"};if($&&$!==B.contentHash)return{success:!1,error:`Cannot publish ${B.entityType}:${B.id} because it changed after confirmation. Review it and try again.`};if(w!==bo1(A,B,D))return{success:!1,error:"Invalid publish confirmation token. Request confirmation again and retry with the returned confirmation args.",code:"INVALID_CONFIRMATION_TOKEN"};return null}function bo1(A,Q,B){return wHB("sha256").update(A).update("\x00").update(Q.entityType).update("\x00").update(Q.id).update("\x00").update(Q.contentHash).update("\x00").update(B).digest("hex")}function WHB(A){let Q=A.metadata.title;if(typeof Q==="string"&&Q.length>0)return Q;let B=A.metadata.subject;if(typeof B==="string"&&B.length>0)return B;let w=A.metadata.slug;if(typeof w==="string"&&w.length>0)return w;return A.id}p0();K0();var Sd0=K.object({entityType:K.string().min(1).describe("Entity type to reconcile"),status:K.string().min(1).optional().describe("Optional metadata status filter, e.g. published"),assetType:K.string().min(1).optional().describe("Optional attachment type filter, e.g. og-image")}),md0=K.object({success:K.literal(!0),data:K.object({entityType:K.string(),assetType:K.string().optional(),checkedEntities:K.number(),checkedAssets:K.number(),enqueued:K.number(),skipped:K.number()}),message:K.string().optional()});function tD0(A,Q,B,w){return{...BB(Q,"ensure-assets","Reconcile configured publish assets for existing entities, queueing missing generated assets such as OG images.",Sd0,async(D,f)=>{if(A.permissions.assertEntityActionAllowed(D.entityType,"publish",f),B.list(D.entityType).filter((G)=>G.autoGenerate===!0).filter((G)=>!D.assetType||G.attachmentType===D.assetType).length===0)return{success:!0,data:{entityType:D.entityType,...D.assetType&&{assetType:D.assetType},checkedEntities:0,checkedAssets:0,enqueued:0,skipped:0},message:`No publish assets configured for ${D.entityType}`};let X=await A.entityService.listEntities({entityType:D.entityType,options:{...D.status&&{filter:{metadata:{status:D.status}}}}}),H=0,W=0,Z=0;for(let G of X){let F=await w.ensureForEntity(G,{...D.assetType&&{attachmentType:D.assetType}});H+=F.checked,W+=F.enqueued,Z+=F.skipped}return{success:!0,data:{entityType:D.entityType,...D.assetType&&{assetType:D.assetType},checkedEntities:X.length,checkedAssets:H,enqueued:W,skipped:Z},message:`Queued ${W} publish asset job(s)`}}),outputSchema:md0}}p0();K0();function No1(A,Q){ZHB(A,Q),KHB(A,Q),UHB(A,Q),GHB(A,Q)}function ZHB(A,Q){A.messaging.subscribe(xD.REGISTER,async(B)=>zHB(Q,B.payload)),A.messaging.subscribe(xD.QUEUE,async(B)=>VHB(A,Q,B.payload)),A.messaging.subscribe(xD.DIRECT,async(B)=>JHB(A,Q,B.payload)),A.messaging.subscribe(xD.REMOVE,async(B)=>LHB(Q,B.payload)),A.messaging.subscribe(xD.REORDER,async(B)=>bHB(Q,B.payload)),A.messaging.subscribe(xD.LIST,async(B)=>NHB(A,Q,B.payload)),A.messaging.subscribe(xD.REPORT_SUCCESS,async(B)=>jHB(Q,B.payload)),A.messaging.subscribe(xD.REPORT_FAILURE,async(B)=>_HB(Q,B.payload)),Q.logger.debug("Subscribed to publish messages")}function KHB(A,Q){A.messaging.subscribe(vL.REPORT_SUCCESS,async(B)=>MHB(Q,B.payload)),A.messaging.subscribe(vL.REPORT_FAILURE,async(B)=>PHB(Q,B.payload)),Q.logger.debug("Subscribed to generation messages")}function UHB(A,Q){A.messaging.subscribe(Do1.REGISTER,async(B)=>qHB(Q,B.payload)),Q.logger.debug("Subscribed to publish asset messages")}function GHB(A,Q){let B=async(w)=>FHB(A,Q,w.payload);A.messaging.subscribe("entity:created",B),A.messaging.subscribe("entity:updated",B),Q.logger.debug("Subscribed to entity change messages for publish assets")}async function zHB(A,Q){let{entityType:B,provider:w,config:$}=Q;try{let D=$?fo1.safeParse($):void 0;if(D&&!D.success)return A.logger.warn("Invalid publish provider config",{entityType:B,error:D.error.message}),{success:!1};if(w)A.providerRegistry.register(B,w,D?.data),A.logger.info(`Registered provider for entity type: ${B}`,{providerName:w.name,executionMode:A.providerRegistry.getExecutionMode(B)});return{success:!0}}catch(D){let f=hA(D);return A.logger.error(`Failed to register provider: ${f}`),{success:!1}}}async function qHB(A,Q){let B=nD0.safeParse(Q);if(!B.success)return A.logger.warn("Invalid publish asset registration",{error:B.error.message}),{success:!1};return A.publishAssetRegistry.register(B.data),A.logger.info("Registered publish asset",{entityType:B.data.entityType,attachmentType:B.data.attachmentType,mediaEntityType:B.data.mediaEntityType}),{success:!0}}async function FHB(A,Q,B){try{if(Q.publishAssetRegistry.list(B.entityType).length===0)return{success:!0};let w=B.entity??await A.entityService.getEntity({entityType:B.entityType,id:B.entityId});if(!IHB(w))return{success:!0};return await Q.publishAssetPreflight.ensureForEntity(w),{success:!0}}catch(w){return Q.logger.warn("Failed to run publish asset preflight for entity event",{entityType:B.entityType,entityId:B.entityId,error:hA(w)}),{success:!1}}}function IHB(A){if(!A)return!1;let Q=$o1.safeParse(A.metadata);return Q.success&&Q.data.status==="published"}async function VHB(A,Q,B){let{entityType:w,entityId:$}=B;try{let D=B.authContext??Qo;A.permissions.assertEntityActionAllowed(w,"publish",D);let f=await Q.queueManager.add(w,$,D);return await A.messaging.send({type:xD.QUEUED,payload:{entityType:w,entityId:$,position:f.position}}),Q.logger.debug(`Entity queued: ${$}`,{entityType:w,position:f.position}),{success:!0}}catch(D){let f=hA(D);return Q.logger.error(`Failed to queue entity: ${f}`),{success:!1}}}async function JHB(A,Q,B){let{entityType:w,entityId:$}=B,D=B.authContext??Qo;try{if(A.permissions.assertEntityActionAllowed(w,"publish",D),!Q.providerRegistry.has(w))return Q.scheduler.failPublish(w,$,`No publish provider registered for ${w}`),{success:!1};let f=await Q.publishExecutor.publish({entityType:w,id:$});if("error"in f)return Q.scheduler.failPublish(w,$,f.error),{success:!1};return Q.scheduler.completePublish(w,$,f.result),Q.logger.debug(`Direct publish completed: ${$}`,{entityType:w}),{success:!0}}catch(f){let Y=hA(f);return Q.logger.error(`Failed direct publish request: ${Y}`),{success:!1}}}async function LHB(A,Q){let{entityType:B,entityId:w}=Q;try{return await A.queueManager.remove(B,w),A.logger.debug(`Entity removed from queue: ${w}`,{entityType:B}),{success:!0}}catch($){let D=hA($);return A.logger.error(`Failed to remove entity: ${D}`),{success:!1}}}async function bHB(A,Q){let{entityType:B,entityId:w,position:$}=Q;try{return await A.queueManager.reorder(B,w,$),A.logger.debug(`Entity reordered: ${w}`,{entityType:B,newPosition:$}),{success:!0}}catch(D){let f=hA(D);return A.logger.error(`Failed to reorder entity: ${f}`),{success:!1}}}async function NHB(A,Q,B){let{entityType:w}=B;try{let $=await Q.queueManager.list(w);return await A.messaging.send({type:xD.LIST_RESPONSE,payload:{entityType:w,queue:$.map((D)=>({entityId:D.entityId,position:D.position,queuedAt:D.queuedAt}))}}),{success:!0}}catch($){let D=hA($);return Q.logger.error(`Failed to list queue: ${D}`),{success:!1}}}async function jHB(A,Q){let{entityType:B,entityId:w,result:$}=Q;return A.scheduler.completePublish(B,w,$),A.logger.info(`Publish reported success: ${w}`,{entityType:B}),{success:!0}}async function _HB(A,Q){let{entityType:B,entityId:w,error:$}=Q;A.scheduler.failPublish(B,w,$);let D=A.retryTracker.getRetryInfo(w);return A.logger.info(`Publish reported failure: ${w}`,{entityType:B,error:$,retryCount:D?.retryCount}),{success:!0}}async function MHB(A,Q){let{entityType:B,entityId:w}=Q;return A.scheduler.completeGeneration(B,w),A.logger.info("Generation completed",{entityType:B,entityId:w}),{success:!0}}async function PHB(A,Q){let{entityType:B,error:w}=Q;return A.scheduler.failGeneration(B,w),A.logger.warn("Generation failed",{entityType:B,error:w}),{success:!0}}K0();async function jo1(A,Q,B,w){try{if(w.skipIfDraftExists!==!1){if((await A.listEntities({entityType:B,options:{filter:{metadata:{status:"draft"}},limit:1}})).length>0)return{shouldGenerate:!1,reason:"Draft already exists"}}if(w.maxUnpublishedDrafts!==void 0){let $=await A.listEntities({entityType:B,options:{filter:{metadata:{status:"draft"}},limit:w.maxUnpublishedDrafts+1}});if($.length>=w.maxUnpublishedDrafts)return{shouldGenerate:!1,reason:`Max unpublished drafts reached (${$.length}/${w.maxUnpublishedDrafts})`}}if(w.minSourceEntities!==void 0&&w.sourceEntityType){let $=await A.listEntities({entityType:w.sourceEntityType,options:{publishedOnly:!0,limit:w.minSourceEntities}});if($.length<w.minSourceEntities)return{shouldGenerate:!1,reason:`Not enough source entities (${$.length}/${w.minSourceEntities} ${w.sourceEntityType})`}}return{shouldGenerate:!0}}catch($){return Q.error("Failed to check generation conditions",{entityType:B,error:hA($)}),{shouldGenerate:!1,reason:`Condition check failed: ${hA($)}`}}}function _o1(A){let{context:Q,config:B,queueManager:w,providerRegistry:$,retryTracker:D,publishExecutor:f,logger:Y}=A,X=kHB(Q);return bK.createFresh({queueManager:w,providerRegistry:$,retryTracker:D,logger:Y,backend:new dD0,...B.entitySchedules&&{entitySchedules:B.entitySchedules},...B.generationSchedules&&{generationSchedules:B.generationSchedules},...B.generationConditions&&{generationConditions:B.generationConditions},messageBus:X,publishExecutor:f,onCheckGenerationConditions:(H,W)=>jo1(Q.entityService,Y,H,W)})}function kHB(A){return{send:async($)=>{return A.messaging.send({type:$.type,payload:$.payload,...$.target!==void 0?{target:$.target}:{},...$.metadata!==void 0?{metadata:$.metadata}:{},...$.broadcast!==void 0?{broadcast:$.broadcast}:{}})},subscribe:()=>()=>{},unsubscribe:()=>{}}}async function Mo1(A,Q,B){let w=A.getEntityTypes();for(let D of w){let f=await A.listEntities({entityType:D,options:{filter:{metadata:{status:"queued"}}}});for(let Y of f)await Q.add(Y.entityType,Y.id)}let $=0;for(let D of w){let f=await Q.list(D);$+=f.length}if($>0)B.info(`Rebuilt queue with ${$} queued entities`)}var OHB=["draft","queued","published","failed"];async function Po1(A,Q){await A.messaging.send({type:"dashboard:register-widget",payload:{id:"publication-pipeline",pluginId:Q,title:"Publication Pipeline",section:"secondary",priority:100,rendererName:"PipelineWidget",visibility:"anchor",dataProvider:()=>xHB(A)}})}async function xHB(A){let Q=A.entityService.getEntityTypes(),B=[],w={draft:0,queued:0,published:0,failed:0};for(let $ of Q){let D=await A.entityService.listEntities({entityType:$});for(let f of D){let Y=RHB(f.metadata.status);if(!Y)continue;w[Y]++,B.push({id:f.id,title:vHB(f.id,f.metadata.title),type:$,status:Y})}}return{summary:w,items:B}}function RHB(A){return OHB.find((Q)=>Q===A)}function vHB(A,Q){return typeof Q==="string"?Q:A}var ko1={name:"@brains/content-pipeline",private:!0,version:"0.2.0-alpha.129",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/contracts":"workspace:*","@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 ud0 extends pQ{pluginContext;queueManager;providerRegistry;retryTracker;publishExecutor;publishAssetRegistry;publishAssetPreflight;scheduler;constructor(A){super("content-pipeline",ko1,A??{},Yo1)}async onRegister(A){this.pluginContext=A,this.queueManager=aG.createFresh(),this.providerRegistry=tG.createFresh(),this.retryTracker=eG.createFresh(),this.publishAssetRegistry=Az.createFresh(),this.publishAssetPreflight=new rD0({context:A,registry:this.publishAssetRegistry}),this.publishExecutor=new JE({context:A,providerRegistry:this.providerRegistry,publishAssetPreflight:this.publishAssetPreflight}),this.scheduler=_o1({context:A,config:this.config,queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,logger:this.logger}),No1(A,{queueManager:this.queueManager,providerRegistry:this.providerRegistry,retryTracker:this.retryTracker,publishExecutor:this.publishExecutor,publishAssetRegistry:this.publishAssetRegistry,publishAssetPreflight:this.publishAssetPreflight,scheduler:this.scheduler,logger:this.logger})}async onReady(A){await Mo1(A.entityService,this.queueManager,this.logger),await Po1(A,this.id),await this.scheduler.start(),this.logger.info("Content pipeline plugin started")}async getTools(){if(!this.pluginContext)throw Error("Plugin context not initialized");return[oD0(this.pluginContext,this.id,this.queueManager),aD0(this.pluginContext,this.id,this.providerRegistry,this.publishExecutor),tD0(this.pluginContext,this.id,this.publishAssetRegistry,this.publishAssetPreflight)]}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). This tool has its own confirmation flow; call it without `confirmed` when the user asks to publish instead of asking for plain-text confirmation.\n- Use `content-pipeline_ensure-assets` to reconcile missing publish assets such as generated OG images for already-published content.\n- When users ask about their "publish queue", "publishing queue", or "what\'s queued", use `content-pipeline_queue`.'}getQueueManager(){return this.queueManager}getProviderRegistry(){return this.providerRegistry}getRetryTracker(){return this.retryTracker}getPublishAssetRegistry(){return this.publishAssetRegistry}getScheduler(){return this.scheduler}async onShutdown(){await this.scheduler.stop(),aG.resetInstance(),tG.resetInstance(),eG.resetInstance(),Az.resetInstance()}}function cd0(A){return new ud0(A)}p0();K0();var Oo1=K.object({accountId:K.string().describe("Cloudflare account ID"),apiToken:K.string().describe("Cloudflare API token with Analytics:Read permission"),siteTag:K.string().describe("Cloudflare Web Analytics site tag")}),ld0=K.object({cloudflare:Oo1.optional()});p0();K0();var CHB=K.object({date:K.string().describe("Single date in YYYY-MM-DD format").optional(),days:K.number().min(1).max(365).describe("Number of days back from yesterday (e.g., 7 for last week)").optional(),startDate:K.string().describe("Start date in YYYY-MM-DD format (use with endDate)").optional(),endDate:K.string().describe("End date in YYYY-MM-DD format (use with startDate)").optional(),limit:K.number().min(1).max(100).default(20).describe("Maximum items for breakdowns (pages, referrers, countries)")});function yHB(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 xo1(A,Q,B){let w=[];if(!B)return w;return w.push(BB(A,"query",`Query website analytics from Cloudflare.
|
|
6765
6765
|
|
|
6766
6766
|
Date range options (use only one):
|
|
6767
6767
|
- No params: yesterday only
|
|
@@ -6899,7 +6899,7 @@ Returns pageviews, visitors, top pages, referrers, devices, and countries.`,CHB,
|
|
|
6899
6899
|
}
|
|
6900
6900
|
}
|
|
6901
6901
|
}
|
|
6902
|
-
`,variables:B})});if(!w.ok){let f=await w.text();throw Error(`Cloudflare API error: ${w.status} - ${f}`)}let $=await w.json();if($.errors&&$.errors.length>0)throw Error(`Cloudflare GraphQL error: ${$.errors.map((f)=>f.message).join(", ")}`);return($.data.viewer.accounts[0]?.rumPageloadEventsAdaptiveGroups??[]).map((f)=>({country:f.dimensions.countryName,visits:f.sum.visits}))}}K0();var id0=7,EHB=10;function vo1(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let Q=YO(),B=Ut(id0),w=_I(B),$=_I(Q);try{let[D,f]=await Promise.all([A.getWebsiteStats({startDate:w,endDate:$}),A.getTopPages({startDate:w,endDate:$,limit:EHB})]);return{days:id0,startDate:w,endDate:$,pageviews:D.pageviews,visitors:D.visitors,topPages:f}}catch(D){return{error:D instanceof Error?D.message:"Failed to fetch analytics",days:id0}}}}var ho1={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.
|
|
6902
|
+
`,variables:B})});if(!w.ok){let f=await w.text();throw Error(`Cloudflare API error: ${w.status} - ${f}`)}let $=await w.json();if($.errors&&$.errors.length>0)throw Error(`Cloudflare GraphQL error: ${$.errors.map((f)=>f.message).join(", ")}`);return($.data.viewer.accounts[0]?.rumPageloadEventsAdaptiveGroups??[]).map((f)=>({country:f.dimensions.countryName,visits:f.sum.visits}))}}K0();var id0=7,EHB=10;function vo1(A){return async()=>{if(!A)return{unavailable:!0,reason:"Cloudflare analytics not configured"};let Q=YO(),B=Ut(id0),w=_I(B),$=_I(Q);try{let[D,f]=await Promise.all([A.getWebsiteStats({startDate:w,endDate:$}),A.getTopPages({startDate:w,endDate:$,limit:EHB})]);return{days:id0,startDate:w,endDate:$,pageviews:D.pageviews,visitors:D.visitors,topPages:f}}catch(D){return{error:D instanceof Error?D.message:"Failed to fetch analytics",days:id0}}}}var ho1={name:"@brains/analytics",private:!0,version:"0.2.0-alpha.129",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 Co1 extends pQ{cloudflareClient;constructor(A={}){super("analytics",ho1,A,ld0)}async onRegister(A){this.cloudflareClient=this.config.cloudflare?new pd0(this.config.cloudflare):void 0,A.insights.register("traffic-overview",vo1(this.cloudflareClient))}async onReady(A){let Q=this.config.cloudflare?.siteTag;if(!Q)return;await A.messaging.send({type:"plugin:site-builder:head-script:register",payload:{pluginId:this.id,script:Ro1(Q)}})}async getTools(){return xo1(this.id,this.getContext(),this.cloudflareClient)}}function THB(A={}){return new Co1(A)}var eD0=THB;import{randomBytes as pHB}from"crypto";p0();K0();W8();var SHB=new Set(["description","excerpt","summary","tagline","story"]);function mHB(A){if(A.endsWith("s"))return A;return GY(A)}function dd0(A,Q=!1,B){let w=A._def.typeName;if(w==="ZodOptional"||w==="ZodNullable")return dd0(A._def.innerType,!0,B);if(w==="ZodDefault")return dd0(A._def.innerType,Q,A._def.defaultValue());return{inner:A,isOptional:Q,defaultValue:B}}function nd0(A,Q){let{inner:B,isOptional:w,defaultValue:$}=dd0(Q),D=B._def.typeName,f={name:A,label:DU(A),widget:"string",...w&&{required:!1},...$!==void 0&&{default:$}};switch(D){case"ZodString":{if((B._def.checks??[]).some((X)=>X.kind==="datetime"))return{...f,widget:"datetime"};if(SHB.has(A))return{...f,widget:"text"};return{...f,widget:"string"}}case"ZodNumber":return{...f,widget:"number"};case"ZodBoolean":return{...f,widget:"boolean"};case"ZodEnum":{let Y=B._def.values;return{...f,widget:"select",options:Y}}case"ZodArray":{let Y=B._def.type,X=nd0("item",Y);if(X.widget==="object"&&X.fields)return{...f,widget:"list",fields:X.fields};return{...f,widget:"list",field:{name:A,label:DU(A),widget:X.widget}}}case"ZodObject":{let Y=B.shape,X=Object.entries(Y).map(([H,W])=>nd0(H,W));return{...f,widget:"object",fields:X}}default:return{...f,widget:"string"}}}function yo1(A,Q){let B=Object.entries(A.shape).map(([w,$])=>nd0(w,$));if(Q)B.push({name:"body",label:"Body",widget:"markdown"});return B}function Eo1(A){let Q=[],B=[];for(let w of A.entityTypes){let $=A.getFrontmatterSchema(w);if(!$)continue;let D=A.getAdapter(w),f=D?.hasBody!==!1,Y=A.entityDisplay?.[w],X=w===je?"Note":DU(w),H=Y?.label??X,W=Y?.pluralName??mHB(H);if(D?.isSingleton){B.push({name:w,label:H,file:`${w}/${w}.md`,fields:yo1($,f)});continue}if(w===je){Q.push({name:w,label:W,folder:".",create:!0,extension:"md",format:"raw",fields:[{name:"body",label:"Body",widget:"markdown"}]});continue}Q.push({name:w,label:W,folder:w,create:!0,extension:"md",format:"frontmatter",fields:yo1($,f)})}if(B.length>0)Q.push({name:"settings",label:"Settings",files:B});return{backend:{name:"github",repo:A.repo,branch:A.branch,...A.baseUrl&&{base_url:A.baseUrl},...A.authEndpoint&&{auth_endpoint:A.authEndpoint}},media_folder:"image",public_folder:"/images",collections:Q}}var uHB=new RegExp("[<>&\\u2028\\u2029]","g");function LE(A){return JSON.stringify(A).replace(uHB,(Q)=>`\\u${Q.charCodeAt(0).toString(16).padStart(4,"0")}`)}var go1="https://unpkg.com/@sveltia/cms@0.165.1/dist/sveltia-cms.js";function Af0(A){let Q=`<script src="${go1}"></script>`;return`<!doctype html>
|
|
6903
6903
|
<html>
|
|
6904
6904
|
<head>
|
|
6905
6905
|
<meta charset="utf-8" />
|
|
@@ -6938,7 +6938,7 @@ Returns pageviews, visitors, top pages, referrers, devices, and countries.`,CHB,
|
|
|
6938
6938
|
showError(error instanceof Error ? error.message : String(error));
|
|
6939
6939
|
}
|
|
6940
6940
|
})();
|
|
6941
|
-
`}K0();var To1={name:"@brains/cms",private:!0,version:"0.2.0-alpha.
|
|
6941
|
+
`}K0();var To1={name:"@brains/cms",private:!0,version:"0.2.0-alpha.129",description:"CMS plugin for config and browser authoring routes",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/auth-service":"workspace:*","@brains/cms-config":"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 od0="brains_cms_oauth_state",iHB=600,dHB="auth",nHB=K.object({label:K.string().optional(),pluralName:K.string().optional()}).passthrough(),rHB=K.object({clientId:K.string().optional(),clientSecret:K.string().optional(),scope:K.string().optional()}),oHB=K.object({contentRepoToken:K.string().optional()}),sHB=K.object({entityDisplay:K.record(nHB).optional(),routePath:K.string().default("/cms"),githubOAuth:rHB.optional(),passkeyLogin:oHB.optional()}).refine((A)=>{let Q=Boolean(jP(A.githubOAuth?.clientId)&&jP(A.githubOAuth?.clientSecret)),B=Boolean(jP(A.passkeyLogin?.contentRepoToken));return!(Q&&B)},{message:"CMS login supports a single method per brain: configure githubOAuth or passkeyLogin, not both."});function aHB(A){return`${A.endsWith("/")?A:`${A}/`}config.yml`}function jP(A){if(!A)return;let Q=A.trim();return Q.length>0?Q:void 0}function tHB(A){let Q=jP(A.githubOAuth?.clientId),B=jP(A.githubOAuth?.clientSecret),w=jP(A.passkeyLogin?.contentRepoToken);return{...Q&&B?{githubOAuth:{clientId:Q,clientSecret:B,scope:jP(A.githubOAuth?.scope)??"repo"}}:{},...w?{passkeyLogin:{contentRepoToken:w}}:{}}}function eHB(A){return Boolean(A.githubOAuth??A.passkeyLogin)}function AWB(A,Q,B){let w=A.entityDisplay??B?.entityDisplay;return{...w?{entityDisplay:w}:{},...eHB(Q)?{authEndpoint:dHB}:{}}}async function QWB(A){let Q=await A.messaging.send({type:"git-sync:get-repo-info",payload:{}});if("noop"in Q||!Q.success||!Q.data)throw Error("CMS config unavailable: git-sync repo info unavailable");let{repo:B,branch:w}=Q.data;if(!B||!w)throw Error("CMS config unavailable: git-sync repo info incomplete");return{repo:B,branch:w}}async function BWB(A,Q={}){let{repo:B,branch:w}=await QWB(A);return Eo1({repo:B,branch:w,...Q.baseUrl&&{baseUrl:Q.baseUrl},...Q.authEndpoint&&{authEndpoint:Q.authEndpoint},entityTypes:A.entityService.getEntityTypes(),getFrontmatterSchema:($)=>A.entities.getEffectiveFrontmatterSchema($),getAdapter:($)=>A.entities.getAdapter($),...Q.entityDisplay&&{entityDisplay:Q.entityDisplay}})}async function uo1(A,Q={}){return $U(await BWB(A,Q))}class sd0 extends pQ{constructor(A={}){super("cms",To1,A,sHB)}async onRegister(A){await super.onRegister(A),A.endpoints.register({label:"CMS",url:this.config.routePath,priority:40,visibility:"anchor"}),A.interactions.register({id:"cms",label:"CMS",description:"Edit and manage content through the browser CMS.",href:this.config.routePath,kind:"admin",priority:40,visibility:"anchor"})}getWebRoutes(){let A=aHB(this.config.routePath),Q=tHB(this.config),B=[];if(Q.githubOAuth||Q.passkeyLogin)B.push({path:"/auth",method:"GET",public:!0,handler:async(w)=>this.handleAuth(w,Q)});if(Q.githubOAuth){let w=Q.githubOAuth;B.push({path:"/auth/callback",method:"GET",public:!0,handler:async($)=>this.handleGitHubCallback($,w)})}if(Q.passkeyLogin){let w=Q.passkeyLogin;B.push({path:"/auth/cms-token",method:"POST",public:!0,handler:async($)=>this.handleCmsToken($,w)})}return[{path:this.config.routePath,method:"GET",public:!0,handler:async(w)=>{if(Q.passkeyLogin){if(!await mo1(w))return new Response(null,{status:302,headers:{Location:`/login?return_to=${encodeURIComponent(this.config.routePath)}`,"Cache-Control":"no-store"}});return Do(Af0({cmsConfigPath:A,authTokenEndpoint:"/auth/cms-token"}))}return Do(Af0({cmsConfigPath:A}))}},{path:A,method:"GET",public:!0,handler:async(w)=>{try{let $=AWB(this.config,Q,this.getContext()),D=await uo1(this.getContext(),{...$,...$.authEndpoint?{baseUrl:$o(this.getContext(),w)}:{}});return new Response(D,{headers:{"Content-Type":"application/yaml; charset=utf-8"}})}catch($){return new Response($ instanceof Error?$.message:"CMS unavailable",{status:503,headers:{"Content-Type":"text/plain; charset=utf-8"}})}}},...B]}async handleAuth(A,Q){if(Q.githubOAuth)return this.redirectToGitHub(A,Q.githubOAuth);if(Q.passkeyLogin){let B=await mo1(A)?HWB:XWB;return Do(B($o(this.getContext(),A)))}return YWB("CMS login is not enabled",404)}redirectToGitHub(A,Q){let B=pHB(32).toString("base64url"),w=`${$o(this.getContext(),A)}/auth/callback`,$=new URL("https://github.com/login/oauth/authorize");return $.searchParams.set("client_id",Q.clientId),$.searchParams.set("redirect_uri",w),$.searchParams.set("scope",Q.scope),$.searchParams.set("state",B),new Response(null,{status:302,headers:{Location:$.toString(),"Set-Cookie":DWB(B,A),"Cache-Control":"no-store"}})}async handleGitHubCallback(A,Q){let B=new URL(A.url),w=B.searchParams.get("error");if(w){let H=B.searchParams.get("error_description")??w;return Qf0(`GitHub OAuth failed: ${H}`)}let $=B.searchParams.get("state"),D=fWB(A.headers.get("cookie"),od0);if(!$||!D||$!==D)return Qf0("GitHub OAuth state did not match");let f=B.searchParams.get("code");if(!f)return Qf0("GitHub OAuth callback did not include a code");let Y=`${$o(this.getContext(),A)}/auth/callback`,X=await wWB(Q,f,Y);if(!X.success)return Qf0(X.error);return Do(WWB(X.token,$o(this.getContext(),A)),200,{"Set-Cookie":lo1()})}async handleCmsToken(A,Q){if(!await gH()?.getOperatorSession(A))return So1({error:"Operator session required"},401);return So1({token:Q.contentRepoToken,provider:"github"},200,{"Cache-Control":"no-store"})}}function _P(A){return new sd0(A)}async function wWB(A,Q,B){let w=new URLSearchParams({client_id:A.clientId,client_secret:A.clientSecret,code:Q,redirect_uri:B}),$=await fetch("https://github.com/login/oauth/access_token",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/x-www-form-urlencoded"},body:w}),D;try{D=await $.json()}catch{return{success:!1,error:"GitHub token response was not JSON"}}if(!$.ok)return{success:!1,error:$WB(D)??"GitHub token exchange failed"};if(rd0(D)&&typeof D.error==="string")return{success:!1,error:typeof D.error_description==="string"?D.error_description:D.error};let f=rd0(D)?D.access_token:void 0;if(typeof f!=="string"||f.length===0)return{success:!1,error:"GitHub token response omitted token"};return{success:!0,token:f}}function $WB(A){if(!rd0(A))return;if(typeof A.error_description==="string")return A.error_description;return typeof A.error==="string"?A.error:void 0}function rd0(A){return Boolean(A&&typeof A==="object"&&!Array.isArray(A))}function $o(A,Q){let B=new URL(Q.url).origin;if(co1(B))return B;return A.siteUrl??B}function co1(A){let{hostname:Q}=new URL(A);return Q==="localhost"||Q==="127.0.0.1"||Q==="::1"||Q==="[::1]"}function DWB(A,Q){let B=co1(new URL(Q.url).origin)?"":"; Secure";return`${od0}=${A}; Path=/auth; HttpOnly; SameSite=Lax; Max-Age=${iHB}${B}`}function lo1(){return`${od0}=; Path=/auth; HttpOnly; SameSite=Lax; Max-Age=0`}function fWB(A,Q){if(!A)return;for(let B of A.split(";")){let[w,...$]=B.trim().split("=");if(w===Q)return $.join("=")}return}function Do(A,Q=200,B={}){return new Response(A,{status:Q,headers:{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store",...B}})}function YWB(A,Q=200){return new Response(A,{status:Q,headers:{"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-store"}})}function So1(A,Q=200,B={}){return new Response(JSON.stringify(A),{status:Q,headers:{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store",...B}})}function Qf0(A){return Do(`<!doctype html><html><body><h1>CMS login failed</h1><p>${UWB(A)}</p></body></html>`,400,{"Set-Cookie":lo1()})}async function mo1(A){return Boolean(await gH()?.getOperatorSession(A))}function XWB(A){return`<!doctype html>
|
|
6942
6942
|
<html lang="en">
|
|
6943
6943
|
<head>
|
|
6944
6944
|
<meta charset="utf-8" />
|
|
@@ -8343,7 +8343,7 @@ ${io1}`;import{jsxDEV as NK,Fragment as ro1}from"preact/jsx-dev-runtime";functio
|
|
|
8343
8343
|
}
|
|
8344
8344
|
});
|
|
8345
8345
|
})();`;function rWB({input:A}){let Q=A.appInfo.entities,B=A.appInfo.entityCounts,w=iWB(A.widgets),$=Boolean(A.character.role)||Boolean(A.character.purpose)||A.character.values.length>0,D=A.appInfo.interactions,f=`layout${$?" has-identity":""}`,Y=A.operatorAccess&&!A.operatorAccess.isOperator&&A.operatorAccess.hiddenWidgetCount>0,X=new Date;return NB("html",{lang:"en","data-theme":"dark",children:[NB("head",{children:[NB("meta",{charSet:"utf-8"},void 0,!1,void 0,this),NB("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"},void 0,!1,void 0,this),NB("title",{children:A.title},void 0,!1,void 0,this),NB("link",{rel:"preconnect",href:"https://fonts.googleapis.com"},void 0,!1,void 0,this),NB("link",{rel:"preconnect",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"},void 0,!1,void 0,this),NB("link",{href:pWB,rel:"stylesheet"},void 0,!1,void 0,this),A.themeCSS!==void 0&&NB("style",{"data-dashboard-theme":!0,dangerouslySetInnerHTML:{__html:A.themeCSS}},void 0,!1,void 0,this),NB("style",{"data-dashboard-styles":!0,dangerouslySetInnerHTML:{__html:no1}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),NB("body",{children:[NB("main",{class:"console","data-component":"dashboard:dashboard",children:[NB(oo1,{title:A.title,tagline:A.profile.description,operatorAccess:A.operatorAccess},void 0,!1,void 0,this),NB("section",{class:f,children:[$&&NB("div",{class:"identity-column",children:[NB(ao1,{character:A.character},void 0,!1,void 0,this),NB(An0,{interactions:D,baseUrl:A.baseUrl},void 0,!1,void 0,this),Y&&A.operatorAccess&&NB($s1,{hiddenWidgetCount:A.operatorAccess.hiddenWidgetCount,loginUrl:A.operatorAccess.loginUrl},void 0,!1,void 0,this)]},void 0,!0,void 0,this),NB("div",{class:"main-column",children:[NB(so1,{total:Q,entityCounts:B},void 0,!1,void 0,this),!$&&Y&&A.operatorAccess&&NB($s1,{hiddenWidgetCount:A.operatorAccess.hiddenWidgetCount,loginUrl:A.operatorAccess.loginUrl},void 0,!1,void 0,this),w.primary.map((H)=>NB(Df0,{widget:H},`${H.widget.pluginId}:${H.widget.id}`,!1,void 0,this)),w.secondary.map((H)=>NB(Df0,{widget:H},`${H.widget.pluginId}:${H.widget.id}`,!1,void 0,this))]},void 0,!0,void 0,this),NB("div",{class:"sidebar-column",children:[!$&&NB(An0,{interactions:D,baseUrl:A.baseUrl},void 0,!1,void 0,this),w.sidebar.map((H)=>NB(Df0,{widget:H},`${H.widget.pluginId}:${H.widget.id}`,!1,void 0,this)),NB(to1,{endpoints:A.appInfo.endpoints,baseUrl:A.baseUrl},void 0,!1,void 0,this),NB(Bs1,{appInfo:A.appInfo,now:X},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),NB(ws1,{title:A.title,appInfo:A.appInfo,baseUrl:A.baseUrl},void 0,!1,void 0,this)]},void 0,!0,void 0,this),NB("script",{dangerouslySetInnerHTML:{__html:dWB}},void 0,!1,void 0,this),NB("script",{dangerouslySetInnerHTML:{__html:nWB}},void 0,!1,void 0,this),A.widgetScripts.map((H,W)=>NB("script",{dangerouslySetInnerHTML:{__html:H}},`widget-script:${W}`,!1,void 0,this))]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function Ds1(A){return`<!doctype html>
|
|
8346
|
-
${lWB(NB(rWB,{input:A},void 0,!1,void 0,this))}`}function fs1(A,Q){let B={},w=new Set;for(let[$,D]of Object.entries(A)){let f=Q?.get(D.widget.pluginId,D.widget.id);if(B[$]={...D,...f?.component?{component:f.component}:{}},f?.clientScript)w.add(f.clientScript)}return{widgets:B,widgetScripts:Array.from(w)}}var Ys1={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.
|
|
8346
|
+
${lWB(NB(rWB,{input:A},void 0,!1,void 0,this))}`}function fs1(A,Q){let B={},w=new Set;for(let[$,D]of Object.entries(A)){let f=Q?.get(D.widget.pluginId,D.widget.id);if(B[$]={...D,...f?.component?{component:f.component}:{}},f?.clientScript)w.add(f.clientScript)}return{widgets:B,widgetScripts:Array.from(w)}}var Ys1={name:"@brains/dashboard",private:!0,version:"0.2.0-alpha.129",description:"Dashboard plugin with extensible widget system",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/auth-service":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2","preact-render-to-string":"^6.3.1"},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 sWB=K.object({version:K.string().default("1.0.0"),routePath:K.string().default("/dashboard"),themeCSS:K.string().optional()}),aWB=K.object({id:K.string(),pluginId:K.string(),title:K.string(),description:K.string().optional(),priority:K.number().default(50),section:K.enum(["primary","secondary","sidebar"]).default("primary"),rendererName:K.string(),visibility:r4.default("public"),component:K.custom().optional(),clientScript:K.string().optional(),dataProvider:K.function().returns(K.promise(K.unknown()))}).superRefine((A,Q)=>{if(!ed0(A.rendererName)&&!A.component)Q.addIssue({code:K.ZodIssueCode.custom,message:"Custom dashboard widgets must register a Preact component.",path:["component"]})}),tWB=K.object({pluginId:K.string(),widgetId:K.string().optional()});function eWB(A){return{id:A.id,pluginId:A.pluginId,title:A.title,...A.description?{description:A.description}:{},priority:A.priority,section:A.section,rendererName:A.rendererName,visibility:A.visibility,...A.component?{component:A.component}:{},...A.clientScript?{clientScript:A.clientScript}:{},dataProvider:A.dataProvider}}class Bn0 extends pQ{widgetRegistry=null;datasource=null;siteUrl;ctx;constructor(A){super("dashboard",Ys1,A??{},sWB)}async onRegister(A){this.siteUrl=A.siteUrl,this.ctx=A,this.widgetRegistry=new wf0(this.logger),this.datasource=new $f0(this.widgetRegistry,this.logger),A.entities.registerDataSource(this.datasource),A.endpoints.register({label:"Dashboard",url:this.config.routePath,priority:30,visibility:"public"}),A.interactions.register({id:"dashboard",label:"Dashboard",description:"Inspect runtime status, endpoints, and dashboard widgets.",href:this.config.routePath,kind:"admin",priority:30,visibility:"public"}),A.messaging.subscribe("dashboard:register-widget",async(Q)=>{try{let B=aWB.parse(Q.payload),w=eWB(B);return this.widgetRegistry?.register(w),this.logger.debug("Widget registered via messaging",{widgetId:B.id,pluginId:B.pluginId,rendererName:B.rendererName,builtIn:Bf0.includes(B.rendererName)}),{success:!0}}catch(B){return this.logger.error("Failed to register widget",{error:hA(B),payload:Q.payload}),{success:!1,error:"Widget registration failed"}}}),A.messaging.subscribe("dashboard:unregister-widget",async(Q)=>{let B=tWB.parse(Q.payload);return this.widgetRegistry?.unregister(B.pluginId,B.widgetId),this.logger.debug("Widget unregistered via messaging",{pluginId:B.pluginId,widgetId:B.widgetId}),{success:!0}}),this.logger.info("Dashboard plugin registered")}getWebRoutes(){return[{path:this.config.routePath,method:"GET",public:!0,handler:async(A)=>{if(!this.datasource||!this.ctx)return new Response("Dashboard unavailable",{status:503,headers:{"Content-Type":"text/plain; charset=utf-8"}});let Q=this.ctx,B=await gH()?.getOperatorSession(A),w=Boolean(B),$=w?"anchor":"public",D=this.widgetRegistry?.list({permissionLevel:"anchor"})??[],f=D.filter((g)=>m$.hasPermission($,g.visibility)),Y=D.length-f.length,[X,H]=await Promise.all([this.datasource.getDashboardData({permissionLevel:$,widgets:f}),Q.appInfo()]),W=Q.identity.get(),Z=Q.identity.getProfile(),G=this.siteUrl??(()=>{try{return new URL(A.url).origin}catch{return}})(),F={...H,endpoints:H.endpoints.filter((g)=>m$.hasPermission($,g.visibility)),interactions:H.interactions.filter((g)=>m$.hasPermission($,g.visibility))},I=Z.name||H.model||"Brain Dashboard",L=new URL(A.url),b=`${L.pathname}${L.search}`,N=encodeURIComponent(b),M=fs1(X.widgets,this.widgetRegistry),j={title:I,baseUrl:G,widgets:M.widgets,widgetScripts:M.widgetScripts,character:W,profile:Z,appInfo:F,...this.config.themeCSS!==void 0&&{themeCSS:this.config.themeCSS},operatorAccess:{isOperator:w,hiddenWidgetCount:Y,loginUrl:`/login?return_to=${N}`,logoutUrl:`/logout?return_to=${N}`}};return new Response(Ds1(j),{headers:{"Content-Type":"text/html; charset=utf-8"}})}}]}async getTools(){return[]}getWidgetRegistry(){return this.widgetRegistry}}function CL(A){return new Bn0(A)}p0();K0();var AZB=K.object({id:K.string(),pluginId:K.string(),title:K.string(),description:K.string().optional(),priority:K.number(),section:K.enum(["primary","secondary","sidebar"]),rendererName:K.string(),visibility:r4,component:K.custom().optional()}),QZB=K.object({widget:AZB,data:K.unknown()}),BZB=K.object({widgets:K.record(QZB)});K0();p0();K0();import{h as qZB}from"preact";K0();bY();p0();var bE=K.enum(["generating","draft","queued","published","failed"]),Yo=K.object({subject:K.string(),status:bE,entityIds:K.array(K.string()).optional(),scheduledFor:K.string().datetime().optional(),sentAt:K.string().datetime().optional(),buttondownId:K.string().optional(),sourceEntityType:K.string().optional()}),Xs1=Yo.pick({subject:!0,status:!0,entityIds:!0,scheduledFor:!0,sentAt:!0,buttondownId:!0,sourceEntityType:!0}).extend({error:K.string().optional()}),Xo=o1.extend({entityType:K.literal("newsletter"),metadata:Xs1});p0();class Hs1 extends V2{constructor(){super({entityType:"newsletter",schema:Xo,frontmatterSchema:Yo})}toMarkdown(A){let Q=this.extractBody(A.content);return this.buildMarkdown(Q,A.metadata)}fromMarkdown(A){let Q=this.parseFrontmatter(A);return{entityType:"newsletter",content:A,metadata:Q}}buildStub(A){let Q={subject:A.title,status:"generating"};return{content:this.buildMarkdown("",Q),metadata:Q}}}var Ws1=new Hs1;p0();p0();K0();var wZB=qU.extend({status:K.enum(["generating","draft","queued","published","failed"]).optional()}),$ZB=FU.extend({query:wZB.optional()});function Zs1(A){try{let{content:Q}=h2(A.content,Yo);return Q}catch{return A.content}}class wn0 extends W${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 Q=$ZB.parse(A);return{entityType:Q.entityType??this.config.entityType,query:Q.query??{}}}transformEntity(A){let Q=Zs1(A),B={id:A.id,subject:A.metadata.subject,status:A.metadata.status,excerpt:r7(Q,150),created:A.created,url:`/newsletters/${A.id}`};if(A.metadata.sentAt)B.sentAt=A.metadata.sentAt;return B}buildListResult(A,Q,B){return{newsletters:A,totalCount:Q?.totalItems??A.length,pagination:Q}}async fetch(A,Q,B){let{query:w}=this.parseQuery(A),$=B.entityService;if(w.id)return this.fetchSingleNewsletter(w.id,Q,$);let D=w.status,f=D?{filter:{metadata:{status:D}}}:void 0,{items:Y,pagination:X}=await this.fetchList(w,$,f);return Q.parse(this.buildListResult(Y,X,w))}async fetchSingleNewsletter(A,Q,B){let w=await B.getEntity({entityType:this.config.entityType,id:A});if(!w)throw Error(`Newsletter not found: ${A}`);let $=await this.resolveNavigation(w,B),D=[];if(w.metadata.entityIds?.length){let X=w.metadata.sourceEntityType??"post";D=(await Promise.all(w.metadata.entityIds.map(async(W)=>{let Z=await B.getEntity({entityType:X,id:W});if(Z){let G=Z.metadata;return{id:W,title:G.title??W,url:`/${X}s/${G.slug??W}`}}return null}))).filter((W)=>W!==null)}let f=Zs1(w),Y={id:w.id,subject:w.metadata.subject,status:w.metadata.status,content:f,created:w.created,updated:w.updated,sentAt:w.metadata.sentAt,scheduledFor:w.metadata.scheduledFor,newsletter:w,prevNewsletter:$.prev?{id:$.prev.id,subject:$.prev.subject,url:$.prev.url}:null,nextNewsletter:$.next?{id:$.next.id,subject:$.next.subject,url:$.next.url}:null,sourceEntities:D.length>0?D:void 0};return Q.parse(Y)}}p0();K0();var DZB=K.object({prompt:K.string().optional().describe("AI generation prompt"),sourceEntityIds:K.array(K.string()).optional().describe("Entity IDs to include in newsletter (e.g., blog posts)"),sourceEntityType:K.enum(["post"]).optional().describe("Type of source entities"),content:K.string().optional().describe("Direct content (skip AI)"),subject:K.string().optional().describe("Newsletter subject (AI-generated if not provided)"),addToQueue:K.boolean().optional().describe("Create as queued (true) or draft (false)")});class $n0 extends A4{constructor(A,Q){super(A,Q,{schema:DZB,jobTypeName:"newsletter:generation",entityType:"newsletter"})}async generate(A,Q){let B=A.addToQueue??!1,{prompt:w,sourceEntityIds:$,sourceEntityType:D}=A,{content:f,subject:Y}=A;if(f){if(!Y)this.failEarly("Subject is required when providing content directly");await this.reportProgress(Q,{progress:50,message:"Using provided content"})}else if($&&$.length>0){let G=D??"post";await this.reportProgress(Q,{progress:10,message:`Fetching ${$.length} source entities`});let I=(await Promise.all($.map((j)=>this.context.entityService.getEntity({entityType:G,id:j})))).filter((j)=>j!=null);if(I.length===0)this.failEarly(`No source entities found for IDs: ${$.join(", ")}`);await this.reportProgress(Q,{progress:30,message:`Generating newsletter from ${I.length} posts`});let b=`Create an engaging newsletter that highlights these blog posts:
|
|
8347
8347
|
|
|
8348
8348
|
${I.map((j)=>`## ${j.metadata.title}
|
|
8349
8349
|
|
|
@@ -8412,17 +8412,17 @@ Newsletter-specific guidelines:
|
|
|
8412
8412
|
- "Reply and let me know..."
|
|
8413
8413
|
- "Until next time..."
|
|
8414
8414
|
|
|
8415
|
-
The goal is to build a relationship with readers through valuable, authentic content.`});K0();p0();import{jsxDEV as RD,Fragment as WZB}from"preact/jsx-dev-runtime";var YZB=K.object({id:K.string(),subject:K.string(),status:bE,excerpt:K.string(),created:K.string(),sentAt:K.string().optional(),url:K.string()}),XZB=K.object({newsletters:K.array(YZB),totalCount:K.number(),pagination:e7.nullable()}),HZB=({newsletters:A,totalCount:Q,pageTitle:B,pagination:w,baseUrl:$="/newsletters"})=>{let D=B??"Newsletters",f=`Browse all ${Q} ${Q===1?"newsletter":"newsletters"}`;return RD(WZB,{children:[RD(NQ,{title:D,description:f},void 0,!1,void 0,this),RD("div",{className:"newsletter-list bg-theme",children:RD("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[RD("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:D},void 0,!1,void 0,this),A.length===0?RD("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):RD("div",{className:"space-y-4",children:A.map((Y)=>RD(uB,{href:Y.url,children:[RD(i9,{className:"text-lg",children:Y.subject},void 0,!1,void 0,this),RD(b7,{children:RD("div",{className:"flex items-center gap-3",children:[RD(hf,{status:Y.status},void 0,!1,void 0,this),RD("span",{className:"text-sm text-theme-muted",children:Z5(Y.sentAt??Y.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Y.excerpt&&RD("p",{className:"text-theme-muted line-clamp-2",children:Y.excerpt},void 0,!1,void 0,this)]},Y.id,!0,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&RD(i3,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:$},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},Us1=R1({name:"newsletter-list",description:"Newsletter list page template",schema:XZB,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:HZB}});K0();p0();import{jsxDEV as E8,Fragment as GZB}from"preact/jsx-dev-runtime";var ZZB=K.object({id:K.string(),title:K.string(),url:K.string()}),Gs1=K.object({id:K.string(),subject:K.string(),url:K.string()}),KZB=K.object({id:K.string(),subject:K.string(),status:bE,content:K.string(),created:K.string(),updated:K.string(),sentAt:K.string().optional(),scheduledFor:K.string().optional(),sourceEntities:K.array(ZZB).optional(),prevNewsletter:Gs1.nullable().optional(),nextNewsletter:Gs1.nullable().optional()}),UZB=({subject:A,status:Q,content:B,created:w,sentAt:$,scheduledFor:D,sourceEntities:f,prevNewsletter:Y,nextNewsletter:X})=>{let H=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:A}],W=$??w,Z=$?"Sent":"Created";return E8(GZB,{children:[E8(NQ,{title:A,description:`Newsletter: ${A}`},void 0,!1,void 0,this),E8("section",{className:"newsletter-detail-section",children:E8("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:E8("div",{className:"max-w-3xl mx-auto",children:[E8(PG,{items:H},void 0,!1,void 0,this),E8("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),E8("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[E8(hf,{status:Q},void 0,!1,void 0,this),E8("span",{children:[Z,": ",Z5(W,{style:"long"})]},void 0,!0,void 0,this),D&&Q==="queued"&&E8("span",{children:["Scheduled for: ",Z5(D,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),f&&f.length>0&&E8(uB,{variant:"compact",className:"mb-8",children:[E8("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),E8("ul",{className:"space-y-1",children:f.map((G)=>E8("li",{children:E8("a",{href:G.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:G.title},void 0,!1,void 0,this)},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),E8(f9,{markdown:B},void 0,!1,void 0,this),(Y??X)&&E8("nav",{className:"mt-12 pt-8 border-t border-theme",children:E8("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[Y?E8(uB,{href:Y.url,variant:"compact",children:[E8("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),E8("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Y.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this):E8("div",{},void 0,!1,void 0,this),X&&E8(uB,{href:X.url,variant:"compact",className:"md:text-right",children:[E8("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),E8("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:X.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)},zs1=R1({name:"newsletter-detail",description:"Individual newsletter detail template",schema:KZB,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:UZB}});var qs1={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.
|
|
8415
|
+
The goal is to build a relationship with readers through valuable, authentic content.`});K0();p0();import{jsxDEV as RD,Fragment as WZB}from"preact/jsx-dev-runtime";var YZB=K.object({id:K.string(),subject:K.string(),status:bE,excerpt:K.string(),created:K.string(),sentAt:K.string().optional(),url:K.string()}),XZB=K.object({newsletters:K.array(YZB),totalCount:K.number(),pagination:e7.nullable()}),HZB=({newsletters:A,totalCount:Q,pageTitle:B,pagination:w,baseUrl:$="/newsletters"})=>{let D=B??"Newsletters",f=`Browse all ${Q} ${Q===1?"newsletter":"newsletters"}`;return RD(WZB,{children:[RD(NQ,{title:D,description:f},void 0,!1,void 0,this),RD("div",{className:"newsletter-list bg-theme",children:RD("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-16 md:py-24",children:[RD("h1",{className:"text-3xl md:text-4xl font-bold text-heading mb-8",children:D},void 0,!1,void 0,this),A.length===0?RD("p",{className:"text-theme-muted italic",children:"No newsletters yet."},void 0,!1,void 0,this):RD("div",{className:"space-y-4",children:A.map((Y)=>RD(uB,{href:Y.url,children:[RD(i9,{className:"text-lg",children:Y.subject},void 0,!1,void 0,this),RD(b7,{children:RD("div",{className:"flex items-center gap-3",children:[RD(hf,{status:Y.status},void 0,!1,void 0,this),RD("span",{className:"text-sm text-theme-muted",children:Z5(Y.sentAt??Y.created,{style:"long"})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Y.excerpt&&RD("p",{className:"text-theme-muted line-clamp-2",children:Y.excerpt},void 0,!1,void 0,this)]},Y.id,!0,void 0,this))},void 0,!1,void 0,this),w&&w.totalPages>1&&RD(i3,{currentPage:w.currentPage,totalPages:w.totalPages,baseUrl:$},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},Us1=R1({name:"newsletter-list",description:"Newsletter list page template",schema:XZB,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:HZB}});K0();p0();import{jsxDEV as E8,Fragment as GZB}from"preact/jsx-dev-runtime";var ZZB=K.object({id:K.string(),title:K.string(),url:K.string()}),Gs1=K.object({id:K.string(),subject:K.string(),url:K.string()}),KZB=K.object({id:K.string(),subject:K.string(),status:bE,content:K.string(),created:K.string(),updated:K.string(),sentAt:K.string().optional(),scheduledFor:K.string().optional(),sourceEntities:K.array(ZZB).optional(),prevNewsletter:Gs1.nullable().optional(),nextNewsletter:Gs1.nullable().optional()}),UZB=({subject:A,status:Q,content:B,created:w,sentAt:$,scheduledFor:D,sourceEntities:f,prevNewsletter:Y,nextNewsletter:X})=>{let H=[{label:"Home",href:"/"},{label:"Newsletters",href:"/newsletters"},{label:A}],W=$??w,Z=$?"Sent":"Created";return E8(GZB,{children:[E8(NQ,{title:A,description:`Newsletter: ${A}`},void 0,!1,void 0,this),E8("section",{className:"newsletter-detail-section",children:E8("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:E8("div",{className:"max-w-3xl mx-auto",children:[E8(PG,{items:H},void 0,!1,void 0,this),E8("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),E8("div",{className:"flex flex-wrap items-center gap-3 mb-8 text-sm text-theme-muted",children:[E8(hf,{status:Q},void 0,!1,void 0,this),E8("span",{children:[Z,": ",Z5(W,{style:"long"})]},void 0,!0,void 0,this),D&&Q==="queued"&&E8("span",{children:["Scheduled for: ",Z5(D,{style:"long"})]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),f&&f.length>0&&E8(uB,{variant:"compact",className:"mb-8",children:[E8("h3",{className:"text-sm font-medium text-heading mb-2",children:"Related Content"},void 0,!1,void 0,this),E8("ul",{className:"space-y-1",children:f.map((G)=>E8("li",{children:E8("a",{href:G.url,className:"text-sm text-brand hover:text-brand-dark transition-colors",children:G.title},void 0,!1,void 0,this)},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),E8(f9,{markdown:B},void 0,!1,void 0,this),(Y??X)&&E8("nav",{className:"mt-12 pt-8 border-t border-theme",children:E8("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[Y?E8(uB,{href:Y.url,variant:"compact",children:[E8("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Newer"},void 0,!1,void 0,this),E8("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:Y.subject},void 0,!1,void 0,this)]},void 0,!0,void 0,this):E8("div",{},void 0,!1,void 0,this),X&&E8(uB,{href:X.url,variant:"compact",className:"md:text-right",children:[E8("span",{className:"text-xs text-theme-muted uppercase tracking-wide",children:"Older"},void 0,!1,void 0,this),E8("span",{className:"block mt-1 font-medium text-heading group-hover:text-brand transition-colors truncate",children:X.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)},zs1=R1({name:"newsletter-detail",description:"Individual newsletter detail template",schema:KZB,dataSourceId:"newsletter:entities",requiredPermission:"public",layout:{component:UZB}});var qs1={name:"@brains/newsletter-entity",private:!0,version:"0.2.0-alpha.129",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/contracts":"workspace:*","@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 FZB=K.object({});class Dn0 extends PQ{entityType="newsletter";schema=Xo;adapter=Ws1;constructor(A={}){super("newsletter",qs1,A,FZB)}getEntityTypeConfig(){return{publish:{publishStatuses:["queued","published","failed"]}}}createGenerationHandler(A){return new $n0(this.logger,A)}getTemplates(){return{generation:Ks1,"newsletter-list":Us1,"newsletter-detail":zs1}}getDataSources(){return[new wn0(this.logger.child("NewsletterDataSource"))]}async onRegister(A){this.deferPublishRegistration(A),this.subscribeToGenerateExecute(A),this.registerEvalHandlers(A),A.messaging.subscribe("system:plugins:ready",async()=>{let Q=await A.messaging.send({type:"buttondown:is-configured",payload:{}});if(!("noop"in Q)&&Q.success)await A.messaging.send({type:"plugin:site-builder:slot:register",payload:{pluginId:this.id,slotName:"footer-top",render:()=>qZB(hu0,{variant:"inline"})}});return{success:!0}}),this.logger.debug("Newsletter plugin registered")}deferPublishRegistration(A){let Q={name:"internal",publish:async(B,w)=>{let $=typeof w.subject==="string"?w.subject:"",D=await A.messaging.send({type:"buttondown:send",payload:{entityId:"",subject:$,content:B}});return{id:!("noop"in D)&&D.data?.emailId?D.data.emailId:"internal"}}};A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"publish:register",payload:{entityType:"newsletter",provider:Q,config:{publishResultIdField:"buttondownId",publishTimestampField:"sentAt"}}}),{success:!0}})}subscribeToGenerateExecute(A){A.messaging.subscribe("generate:execute",async(Q)=>{if(Q.payload.entityType!=="newsletter")return{success:!0};try{let B=await A.entityService.listEntities({entityType:"post",options:{filter:{metadata:{status:"published"}},limit:10}});if(B.length===0)return await A.messaging.send({type:"generate:report:failure",payload:{entityType:"newsletter",error:"No published posts available for newsletter"}}),{success:!0};return await A.jobs.enqueue({type:"newsletter:generation",data:{sourceEntityIds:B.map((w)=>w.id),sourceEntityType:"post",addToQueue:!1},toolContext:{interfaceType:"job",userId:"system"}}),{success:!0}}catch(B){return await A.messaging.send({type:"generate:report:failure",payload:{entityType:"newsletter",error:hA(B)}}),{success:!0}}})}registerEvalHandlers(A){let Q=K.object({prompt:K.string().optional(),content:K.string().optional()});A.eval.registerHandler("generation",async(B)=>{let w=Q.parse(B),$=w.content?`Create an engaging newsletter based on this content:
|
|
8416
8416
|
|
|
8417
|
-
${w.content}`:w.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:$,templateName:"newsletter:generation"})})}}function fn0(A={}){return new Dn0(A)}p0();K0();class NE{config;logger;constructor(A,Q){this.config=A;this.logger=Q}async request(A,Q={}){let B=`https://api.buttondown.email/v1${A}`;this.logger.debug("Buttondown API request",{endpoint:A,method:Q.method??"GET"});let w=await fetch(B,{...Q,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...Q.headers}});if(!w.ok){let $=await w.json().catch(()=>({})),D=$.detail??$.message??`HTTP ${w.status}`;throw this.logger.error("Buttondown API error",{endpoint:A,status:w.status,error:D}),Error(`Buttondown API error: ${D}`)}return w.json()}async createSubscriber(A){let Q={email_address:A.email,type:this.config.doubleOptIn?"unactivated":"regular"};if(A.name)Q.metadata={name:A.name};if(A.tags&&A.tags.length>0)Q.tags=A.tags;this.logger.info("Creating subscriber",{email:A.email});try{return await this.request("/subscribers",{method:"POST",body:JSON.stringify(Q)})}catch(B){if(B instanceof Error&&B.message.includes("already subscribed")){let w=B.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 B}}async unsubscribe(A){this.logger.info("Unsubscribing",{email:A}),await this.request(`/subscribers/${encodeURIComponent(A)}`,{method:"DELETE"})}async listSubscribers(A){let Q=new URLSearchParams;if(A?.type)Q.set("type",A.type);if(A?.limit)Q.set("page_size",String(A.limit));let B=Q.toString(),w=B?`/subscribers?${B}`:"/subscribers";return this.request(w)}async createEmail(A){let Q={subject:A.subject,body:A.body,status:A.status??"draft"};if(A.publish_date)Q.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(Q)})}async getEmail(A){return this.request(`/emails/${A}`)}async validateCredentials(){try{return await this.request("/subscribers?page_size=1"),!0}catch{return!1}}}p0();K0();var IZB=K.object({email:K.string().email().describe("Email address to subscribe"),name:K.string().optional().describe("Subscriber name (optional)"),tags:K.array(K.string()).optional().describe("Tags to apply to subscriber (optional)")}),VZB=K.object({email:K.string().email().describe("Email address to unsubscribe")}),JZB=K.object({type:K.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:K.number().optional().describe("Maximum number of results")});function Fs1(A,Q,B){let w=new NE(Q,B);return[BB(A,"subscribe","Subscribe an email address to the newsletter. Uses double opt-in by default.",IZB,async($)=>{try{let D=await w.createSubscriber({email:$.email,...$.name&&{name:$.name},...$.tags&&{tags:$.tags}}),f=D.subscriber_type==="already_subscribed";return b8({subscriberId:D.id,email:D.email,status:D.subscriber_type,message:f?"already_subscribed":"subscribed"},f?`${$.email} is already subscribed`:`Subscribed ${$.email} successfully`)}catch(D){return u$(hA(D))}}),BB(A,"unsubscribe","Unsubscribe an email address from the newsletter.",VZB,async($)=>{try{return await w.unsubscribe($.email),b8({email:$.email},`Unsubscribed ${$.email} successfully`)}catch(D){return u$(hA(D))}}),BB(A,"list_subscribers","List newsletter subscribers with optional filtering by status.",JZB,async($)=>{try{let D=await w.listSubscribers({...$.type&&{type:$.type},...$.limit&&{limit:$.limit}});return b8({subscribers:D.results.map((f)=>({id:f.id,email:f.email,status:f.subscriber_type})),count:D.count},`Found ${D.count} subscribers`)}catch(D){return u$(hA(D))}})]}K0();async function Is1(A,Q,B,w){if(A.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let $=await B.getEntity({entityType:"post",id:A.entityId});if(!$)return{success:!1,error:`Post ${A.entityId} not found`};w.info("Auto-sending newsletter for published post",{postId:$.id,title:$.metadata.title});try{let D=await Q.createEmail({subject:$.metadata.title,body:$.content,status:"about_to_send"});return w.info("Newsletter sent for post",{postId:$.id,emailId:D.id}),{success:!0,emailId:D.id}}catch(D){let f=hA(D);return w.error("Failed to send newsletter for post",{postId:$.id,error:f}),{success:!1,error:f}}}var Vs1={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.
|
|
8417
|
+
${w.content}`:w.prompt??"Write an engaging newsletter";return A.ai.generate({prompt:$,templateName:"newsletter:generation"})})}}function fn0(A={}){return new Dn0(A)}p0();K0();class NE{config;logger;constructor(A,Q){this.config=A;this.logger=Q}async request(A,Q={}){let B=`https://api.buttondown.email/v1${A}`;this.logger.debug("Buttondown API request",{endpoint:A,method:Q.method??"GET"});let w=await fetch(B,{...Q,headers:{Authorization:`Token ${this.config.apiKey}`,"Content-Type":"application/json",...Q.headers}});if(!w.ok){let $=await w.json().catch(()=>({})),D=$.detail??$.message??`HTTP ${w.status}`;throw this.logger.error("Buttondown API error",{endpoint:A,status:w.status,error:D}),Error(`Buttondown API error: ${D}`)}return w.json()}async createSubscriber(A){let Q={email_address:A.email,type:this.config.doubleOptIn?"unactivated":"regular"};if(A.name)Q.metadata={name:A.name};if(A.tags&&A.tags.length>0)Q.tags=A.tags;this.logger.info("Creating subscriber",{email:A.email});try{return await this.request("/subscribers",{method:"POST",body:JSON.stringify(Q)})}catch(B){if(B instanceof Error&&B.message.includes("already subscribed")){let w=B.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 B}}async unsubscribe(A){this.logger.info("Unsubscribing",{email:A}),await this.request(`/subscribers/${encodeURIComponent(A)}`,{method:"DELETE"})}async listSubscribers(A){let Q=new URLSearchParams;if(A?.type)Q.set("type",A.type);if(A?.limit)Q.set("page_size",String(A.limit));let B=Q.toString(),w=B?`/subscribers?${B}`:"/subscribers";return this.request(w)}async createEmail(A){let Q={subject:A.subject,body:A.body,status:A.status??"draft"};if(A.publish_date)Q.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(Q)})}async getEmail(A){return this.request(`/emails/${A}`)}async validateCredentials(){try{return await this.request("/subscribers?page_size=1"),!0}catch{return!1}}}p0();K0();var IZB=K.object({email:K.string().email().describe("Email address to subscribe"),name:K.string().optional().describe("Subscriber name (optional)"),tags:K.array(K.string()).optional().describe("Tags to apply to subscriber (optional)")}),VZB=K.object({email:K.string().email().describe("Email address to unsubscribe")}),JZB=K.object({type:K.enum(["unactivated","regular","unsubscribed"]).optional().describe("Filter by subscriber status"),limit:K.number().optional().describe("Maximum number of results")});function Fs1(A,Q,B){let w=new NE(Q,B);return[BB(A,"subscribe","Subscribe an email address to the newsletter. Uses double opt-in by default.",IZB,async($)=>{try{let D=await w.createSubscriber({email:$.email,...$.name&&{name:$.name},...$.tags&&{tags:$.tags}}),f=D.subscriber_type==="already_subscribed";return b8({subscriberId:D.id,email:D.email,status:D.subscriber_type,message:f?"already_subscribed":"subscribed"},f?`${$.email} is already subscribed`:`Subscribed ${$.email} successfully`)}catch(D){return u$(hA(D))}}),BB(A,"unsubscribe","Unsubscribe an email address from the newsletter.",VZB,async($)=>{try{return await w.unsubscribe($.email),b8({email:$.email},`Unsubscribed ${$.email} successfully`)}catch(D){return u$(hA(D))}}),BB(A,"list_subscribers","List newsletter subscribers with optional filtering by status.",JZB,async($)=>{try{let D=await w.listSubscribers({...$.type&&{type:$.type},...$.limit&&{limit:$.limit}});return b8({subscribers:D.results.map((f)=>({id:f.id,email:f.email,status:f.subscriber_type})),count:D.count},`Found ${D.count} subscribers`)}catch(D){return u$(hA(D))}})]}K0();async function Is1(A,Q,B,w){if(A.entityType!=="post")return{success:!0,skipped:!0,reason:"Only post entity types trigger auto-send"};let $=await B.getEntity({entityType:"post",id:A.entityId});if(!$)return{success:!1,error:`Post ${A.entityId} not found`};w.info("Auto-sending newsletter for published post",{postId:$.id,title:$.metadata.title});try{let D=await Q.createEmail({subject:$.metadata.title,body:$.content,status:"about_to_send"});return w.info("Newsletter sent for post",{postId:$.id,emailId:D.id}),{success:!0,emailId:D.id}}catch(D){let f=hA(D);return w.error("Failed to send newsletter for post",{postId:$.id,error:f}),{success:!1,error:f}}}var Vs1={name:"@brains/buttondown",private:!0,version:"0.2.0-alpha.129",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 bZB=K.object({apiKey:K.string().optional().describe("Buttondown API key"),doubleOptIn:K.boolean().default(!0).describe("Require email confirmation for new subscribers"),autoSendOnPublish:K.boolean().default(!1).describe("Automatically send newsletter when a blog post is published")});class Yn0 extends pQ{constructor(A={}){super("buttondown",Vs1,A,bZB)}async onRegister(A){if(A.messaging.subscribe("buttondown:is-configured",async()=>{return{success:!!this.config.apiKey}}),this.config.apiKey){let Q=new NE({apiKey:this.config.apiKey,doubleOptIn:this.config.doubleOptIn},this.logger);if(A.messaging.subscribe("buttondown:send",async(B)=>{try{return{success:!0,data:{emailId:(await Q.createEmail({subject:B.payload.subject,body:B.payload.content,status:"about_to_send"})).id}}}catch(w){return this.logger.error("Buttondown send failed",{error:hA(w)}),{success:!1}}}),this.config.autoSendOnPublish)A.messaging.subscribe("publish:completed",async(B)=>{return await Is1(B.payload,Q,A.entityService,this.logger),{success:!0}}),this.logger.info("Buttondown auto-send on publish enabled")}}async getTools(){if(!this.config.apiKey)return[];return Fs1(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 Xn0(A={}){return new Yn0(A)}var NZB=K.object({apiKey:K.string().optional().describe("Buttondown API key"),doubleOptIn:K.boolean().optional().describe("Require email confirmation for new subscribers"),autoSendOnPublish:K.boolean().optional().describe("Automatically send newsletter when a blog post is published")});function Js1(A={}){let Q=NZB.parse(A);return[fn0({}),Xn0({...Q.apiKey!==void 0&&{apiKey:Q.apiKey},...Q.doubleOptIn!==void 0&&{doubleOptIn:Q.doubleOptIn},...Q.autoSendOnPublish!==void 0&&{autoSendOnPublish:Q.autoSendOnPublish}})]}p0();K0();import{existsSync as yZB,mkdirSync as EZB,writeFileSync as gZB}from"fs";import{join as FF}from"path";K0();var Hn0=K.object({baseFolder:K.string().default("_obsidian")});K0();function jZB(A){let Q=A,B=!0,w=void 0,$=!1,D=!0;while(D){if(D=!1,Q instanceof K.ZodOptional)B=!1,Q=Q._def.innerType,D=!0;if(Q instanceof K.ZodDefault)B=!1,$=!0,w=Q._def.defaultValue(),Q=Q._def.innerType,D=!0;if(Q instanceof K.ZodNullable)B=!1,Q=Q._def.innerType,D=!0}let f={inner:Q,required:B};if($)f.defaultValue=w;return f}function _ZB(A){if(A instanceof K.ZodEnum)return{type:"enum",enumValues:A._def.values};if(A instanceof K.ZodLiteral)return{type:"string",defaultValue:A._def.value};if(A instanceof K.ZodString)return{type:"string"};if(A instanceof K.ZodNumber)return{type:"number"};if(A instanceof K.ZodBoolean)return{type:"boolean"};if(A instanceof K.ZodArray)return{type:"array"};if(A instanceof K.ZodDate)return{type:"date"};if(A instanceof K.ZodPipeline){if(A._def.out instanceof K.ZodDate)return{type:"date"}}return{type:"unknown"}}function Ls1(A){let Q=A.shape,B=[];for(let[w,$]of Object.entries(Q)){let{inner:D,required:f,defaultValue:Y}=jZB($),X=_ZB(D),H={name:w,type:X.type,required:f},W=Y!==void 0?Y:X.defaultValue;if(W!==void 0)H.defaultValue=W;if(X.enumValues)H.enumValues=X.enumValues;B.push(H)}return B}function MZB(A,Q){if(A.name==="entityType")return String(A.defaultValue??Q);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 bs1(A,Q,B=""){let w=["---"];for(let $ of Q){let D=MZB($,A);if(D==="")w.push(`${$.name}:`);else w.push(`${$.name}: ${D}`)}if(w.push("---"),w.push(""),B)w.push(B);else w.push("<!-- Write your content here -->"),w.push("");return w.join(`
|
|
8418
8418
|
`)}K0();var PZB={string:"Input",number:"Number",boolean:"Boolean",date:"Date",enum:"Select",array:"Multi",unknown:"Input"};function kZB(A){let Q={name:A.name,id:A.name,type:PZB[A.type]};if(A.type==="enum"&&A.enumValues){let B={};A.enumValues.forEach((w,$)=>{B[String($)]=w}),Q.options=B}return Q}function Ns1(A,Q){let B={filesPaths:A,fields:Q.map(kZB)};return`---
|
|
8419
8419
|
${$U(B)}---
|
|
8420
|
-
`}K0();var OZB=new Set(["entityType"]),xZB={base:"Notes"},RZB=new Set(["note"]);function vZB(A){let Q=["file.name"];for(let B of A)if(!OZB.has(B.name))Q.push(B.name);return Q}function hZB(A){return A.some((Q)=>Q.name==="status"&&Q.type==="enum")}function js1(A,Q){let B=xZB[A]??Zt(A),w=hZB(Q),$=vZB(Q),D=[{type:"table",name:`All ${B}`,order:$}];if(w)D.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:$});let Y={filters:{and:[RZB.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:D};return{filename:`${B}.base`,content:$U(Y),hasStatus:w}}function _s1(A){if(A.length===0)return null;let Q=A.map((w)=>`file.inFolder("${w}")`),B={filters:{and:[Q.length===1?Q[0]:{or:Q}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return $U(B)}function Ms1(A){if(A.length===0)return null;let Q=A.map((w)=>`file.inFolder("${w.entityType}")`),B={filters:{and:[Q.length===1?Q[0]:{or:Q},'status != "published"']},views:[{type:"table",name:"Pipeline",groupBy:{property:"status",direction:"ASC"},order:["file.name","file.folder","status"]}]};return $U(B)}var Ps1={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.
|
|
8420
|
+
`}K0();var OZB=new Set(["entityType"]),xZB={base:"Notes"},RZB=new Set(["note"]);function vZB(A){let Q=["file.name"];for(let B of A)if(!OZB.has(B.name))Q.push(B.name);return Q}function hZB(A){return A.some((Q)=>Q.name==="status"&&Q.type==="enum")}function js1(A,Q){let B=xZB[A]??Zt(A),w=hZB(Q),$=vZB(Q),D=[{type:"table",name:`All ${B}`,order:$}];if(w)D.push({type:"table",name:"By Status",groupBy:{property:"status",direction:"ASC"},order:$});let Y={filters:{and:[RZB.has(A)?'file.folder == "/"':`file.inFolder("${A}")`]},views:D};return{filename:`${B}.base`,content:$U(Y),hasStatus:w}}function _s1(A){if(A.length===0)return null;let Q=A.map((w)=>`file.inFolder("${w}")`),B={filters:{and:[Q.length===1?Q[0]:{or:Q}]},views:[{type:"table",name:"Settings",order:["file.name","file.folder"]}]};return $U(B)}function Ms1(A){if(A.length===0)return null;let Q=A.map((w)=>`file.inFolder("${w.entityType}")`),B={filters:{and:[Q.length===1?Q[0]:{or:Q},'status != "published"']},views:[{type:"table",name:"Pipeline",groupBy:{property:"status",direction:"ASC"},order:["file.name","file.folder","status"]}]};return $U(B)}var Ps1={name:"@brains/obsidian-vault",private:!0,version:"0.2.0-alpha.129",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 TZB={mkdir:EZB,writeFile:gZB,existsFile:yZB},SZB=K.object({entityTypes:K.array(K.string()).optional().describe("Entity types to generate templates for (default: all)")});class Wn0 extends pQ{deps;constructor(A={},Q={}){super("obsidian-vault",Ps1,A,Hn0);this.deps={...TZB,...Q}}async onReady(A){this.logger.info("Auto-syncing Obsidian templates, fileClasses, and bases"),await this.sync(A)}async getTools(){let A=this.getContext();return[BB(this.id,"sync-templates","Generate Obsidian templates, Metadata Menu fileClass definitions, and Bases views for all registered entity types.",SZB,async(Q)=>{return this.sync(A,Q.entityTypes)})]}async sync(A,Q){try{let B=A.entityService.getEntityTypes(),w=Q?B.filter((b)=>Q.includes(b)):B,$=FF(A.dataDir,this.config.baseFolder),D=FF($,"templates"),f=FF($,"fileClasses"),Y=FF($,"bases");this.deps.mkdir(D,{recursive:!0}),this.deps.mkdir(f,{recursive:!0}),this.deps.mkdir(Y,{recursive:!0});let X=[],H=[],W=[],Z=[],G=[],F=[];for(let b of w){let N=A.entities.getEffectiveFrontmatterSchema(b);if(!N){this.logger.debug(`Skipping ${b}: no frontmatter schema`),H.push(b);continue}let M=Ls1(N),j=A.entities.getAdapter(b),g=j?.isSingleton===!0,E=Ns1(b,M);if(this.deps.writeFile(FF(f,`${b}.md`),E),W.push(b),g){G.push(b),this.logger.debug(`Generated fileClass (singleton): ${b}`);continue}let y=j?.getBodyTemplate()??"",h=bs1(b,M,y);this.deps.writeFile(FF(D,`${b}.md`),h),X.push(b);let T=js1(b,M),S=FF(Y,T.filename);if(!this.deps.existsFile(S))this.deps.writeFile(S,T.content),Z.push(b),this.logger.debug(`Generated base: ${T.filename}`);if(T.hasStatus)F.push({entityType:b,fields:M});this.logger.debug(`Generated template + fileClass: ${b}`)}let I=_s1(G);if(I){let b=FF(Y,"Settings.base");if(!this.deps.existsFile(b))this.deps.writeFile(b,I),Z.push("Settings"),this.logger.debug("Generated Settings.base")}let L=Ms1(F);if(L){let b=FF(Y,"Pipeline.base");if(!this.deps.existsFile(b))this.deps.writeFile(b,L),Z.push("Pipeline"),this.logger.debug("Generated Pipeline.base")}return this.logger.info(`Synced ${X.length} templates, ${W.length} fileClasses, ${Z.length} bases (${H.length} skipped)`),b8({generated:X,skipped:H,fileClasses:W,bases:Z})}catch(B){return this.logger.error("Failed to sync",{error:B}),u$(B instanceof Error?B.message:"Unknown error")}}}function Zn0(A,Q){return new Wn0(A,Q)}p0();p0();K0();p$();p0();K0();var Kn0=K.enum(["draft","active","archived"]),Un0=K.enum(["anchor","trusted","public"]),Gn0=K.enum(["agent-confirmed","manual"]),mf=K.preprocess((A)=>typeof A==="string"&&A.trim().length===0?void 0:A,K.string().min(1).optional()),ks1=K.object({event:K.string().min(1),target:K.string().min(1),operatorAction:K.boolean().optional(),label:mf,description:mf,operatorDescription:mf}),Os1=K.object({id:K.string().min(1),title:K.string().min(1),prompt:mf,instructions:K.array(K.string().min(1)).default([]),doneWhen:K.array(K.string().min(1)).default([]),transitions:K.array(ks1).default([])}),zn0=K.object({purpose:K.string().min(1),operatingRules:K.array(K.string().min(1)).default([]),initialState:K.string().min(1),states:K.array(Os1).min(1),finalStates:K.array(K.string().min(1)).min(1),nextPrompts:K.array(K.string().min(1)).default([])}),Ho=K.object({title:K.string(),status:Kn0.default("active"),audience:Un0.default("anchor"),trigger:mf,lifecycle:mf,once:K.boolean().optional(),starterText:mf,description:mf,starterPrompt:mf,completionMode:Gn0.default("agent-confirmed")}),xs1=K.object({title:K.string(),status:Kn0,audience:Un0,trigger:mf,lifecycle:mf,once:K.boolean().optional(),starterText:mf,description:mf,starterPrompt:mf,completionMode:Gn0}),Wo=o1.extend({entityType:K.literal("playbook"),metadata:xs1}),qn0=K.object({});class Vn0 extends pB{constructor(){super(zn0,{title:"Playbook",mappings:[{key:"purpose",label:"Purpose",type:"string"},{key:"operatingRules",label:"Operating Rules",type:"array",itemType:"string"},{key:"initialState",label:"Initial State",type:"string"},{key:"states",label:"States",type:"array",itemType:"object",itemMappings:[{key:"id",label:"ID",type:"string"},{key:"title",label:"Title",type:"string"},{key:"prompt",label:"Prompt",type:"custom",formatter:Fn0,parser:In0},{key:"instructions",label:"Instructions",type:"array",itemType:"string"},{key:"doneWhen",label:"Done When",type:"array",itemType:"string"},{key:"transitions",label:"Transitions",type:"array",itemType:"object",itemMappings:[{key:"event",label:"Event",type:"string"},{key:"target",label:"Target",type:"string"},{key:"operatorAction",label:"User Choice",type:"custom",formatter:mZB,parser:uZB},{key:"label",label:"Label",type:"custom",formatter:Fn0,parser:In0},{key:"description",label:"Description",type:"string"},{key:"operatorDescription",label:"Operator Description",type:"custom",formatter:Fn0,parser:In0}]}]},{key:"finalStates",label:"Final States",type:"array",itemType:"string"},{key:"nextPrompts",label:"Next Prompts",type:"array",itemType:"string"}]})}}var ff0=new Vn0;function Fn0(A){return typeof A==="string"?A:""}function In0(A){let Q=A.trim();return Q.length>0?Q:void 0}function mZB(A){return typeof A==="boolean"?String(A):""}function uZB(A){let Q=A.trim().toLowerCase();if(Q==="true")return!0;if(Q==="false")return!1;return}function Rs1(A){let Q=[],B=new Set,w=new Set;for(let $ of A.states){if(B.has($.id))w.add($.id);B.add($.id)}if(!B.has(A.initialState))Q.push(`Playbook initial state '${A.initialState}' is not defined.`);for(let $ of w)Q.push(`Duplicate playbook state id '${$}'.`);for(let $ of A.finalStates)if(!B.has($))Q.push(`Playbook final state '${$}' is not defined.`);for(let $ of A.states)for(let D of $.transitions)if(!B.has(D.target))Q.push(`Playbook transition '${$.id}' -> '${D.target}' targets an undefined state.`);for(let $ of cZB(A,B))Q.push(`Playbook state '${$}' is unreachable.`);return{valid:Q.length===0,errors:Q}}function Zo(A){let Q=Rs1(A);if(!Q.valid)throw Error(Q.errors.join(`
|
|
8421
8421
|
`))}function cZB(A,Q){if(!Q.has(A.initialState))return[];let B=new Set,w=[A.initialState];while(w.length>0){let $=w.shift();if(!$||B.has($))continue;B.add($);let D=A.states.find((f)=>f.id===$);if(!D)continue;for(let f of D.transitions)if(Q.has(f.target)&&!B.has(f.target))w.push(f.target)}return A.states.map(($)=>$.id).filter(($)=>!B.has($))}class Ln0 extends V2{constructor(){super({entityType:"playbook",schema:Wo,frontmatterSchema:Ho})}createPlaybookContent(A,Q){return this.buildMarkdown(ff0.format(Q),A)}parsePlaybookContent(A){let Q=this.parseFrontMatter(A,Ho),B=this.extractBody(A).trim(),w=lZB(B)?pZB(B):ff0.parse(B);return Zo(w),{frontmatter:Ho.parse(Q),body:w,bodyMarkdown:B}}fromMarkdown(A){let{frontmatter:Q}=this.parsePlaybookContent(A);return{content:A,entityType:"playbook",metadata:{title:Q.title,status:Q.status,audience:Q.audience,...Q.trigger?{trigger:Q.trigger}:{},...Q.lifecycle?{lifecycle:Q.lifecycle}:{},...Q.once!==void 0?{once:Q.once}:{},...Q.starterText?{starterText:Q.starterText}:{},...Q.description?{description:Q.description}:{},...Q.starterPrompt?{starterPrompt:Q.starterPrompt}:{},completionMode:Q.completionMode}}}}var MP=new Ln0;function lZB(A){return/^##\s+Steps\s*$/im.test(A)}function pZB(A){let Q=iZB(bn0(A,"Steps"));if(Q.length===0)throw Error("Playbook must declare at least one step.");let B=Q.map((w,$)=>{let D=$===Q.length-1;if(!D&&w.doneWhen.length===0&&w.choices.length===0&&!w.skip)throw Error(`Playbook step '${w.title}' must declare Done when, Choices, or Skip.`);return{id:w.id,title:w.title,...w.prompt?{prompt:w.prompt}:{},instructions:w.instructions,doneWhen:w.doneWhen,transitions:[...w.doneWhen.length>0&&!D?[{event:"NEXT",target:Q[$+1]?.id??w.id}]:[],...w.choices.map((f,Y)=>({event:`CHOICE_${Y+1}`,target:Y1(f.target),operatorAction:!0,label:f.label})),...w.skip?[{event:"SKIP",target:Y1(w.skip.target),operatorAction:!0,label:w.skip.label}]:[]]}});return{purpose:dZB(A,"Purpose"),operatingRules:vs1(A,"Operating Rules"),initialState:Q[0]?.id??"",states:B,finalStates:[Q.at(-1)?.id??""],nextPrompts:vs1(A,"Next Prompts")}}function iZB(A){let Q=[],B;for(let w of A.split(/\r?\n/)){let $=/^###\s+(.+?)\s*$/.exec(w);if($){B={title:$[1]??"",content:[]},Q.push(B);continue}B?.content.push(w)}return Q.map((w)=>{let $=w.content.join(`
|
|
8422
8422
|
`);return{title:w.title,id:Y1(w.title),...hs1($,"Say")?{prompt:hs1($,"Say")}:{},instructions:Jn0($,"To do"),doneWhen:Jn0($,"Done when"),choices:nZB($,"Choices"),...Cs1($)?{skip:Cs1($)}:{}}})}function bn0(A,Q){let B=A.split(/\r?\n/),w=B.findIndex((D)=>D.trim().toLowerCase()===`## ${Q.toLowerCase()}`);if(w===-1)return"";let $=[];for(let D of B.slice(w+1)){if(/^##\s+/.test(D))break;$.push(D)}return $.join(`
|
|
8423
8423
|
`).trim()}function dZB(A,Q){return bn0(A,Q).split(/\r?\n/).map((B)=>B.trim()).filter((B)=>B.length>0&&!B.startsWith("#")).join(`
|
|
8424
8424
|
`).trim()}function vs1(A,Q){return ys1(bn0(A,Q))}function hs1(A,Q){return new RegExp(`^${oZB(Q)}:\\s*(.+?)\\s*$`,"im").exec(A)?.[1]?.trim()}function Jn0(A,Q){let B=A.split(/\r?\n/),w=B.findIndex((D)=>D.trim().toLowerCase()===`${Q.toLowerCase()}:`);if(w===-1)return[];let $=[];for(let D of B.slice(w+1)){let f=D.trim();if(f.length===0)continue;if(/^[A-Za-z][A-Za-z ]+:/.test(f)||/^#{1,6}\s+/.test(f))break;$.push(D)}return ys1($.join(`
|
|
8425
|
-
`))}function nZB(A,Q){return Jn0(A,Q).map(rZB)}function rZB(A){let Q=/^(.+?)\s*(?:\u2192|->)\s*(.+)$/.exec(A);if(!Q)throw Error(`Invalid playbook choice '${A}'. Expected "Label \u2192 Step".`);return{label:Q[1]?.trim()??"",target:Q[2]?.trim()??""}}function Cs1(A){let Q=/^Skip:\s*(.+?)\s*(?:\u2192|->)\s*(.+?)\s*$/im.exec(A);if(!Q)return;return{label:Q[1]?.trim()??"",target:Q[2]?.trim()??""}}function ys1(A){return A.split(/\r?\n/).map((Q)=>/^-\s+(.+?)\s*$/.exec(Q)?.[1]?.trim()).filter((Q)=>Boolean(Q))}function oZB(A){return A.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Es1={name:"@brains/playbook",private:!0,version:"0.2.0-alpha.128",description:"Playbook entity for durable guided agent workflows",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/content-formatters":"workspace:*","@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 gs1 extends PQ{entityType=MP.entityType;schema=Wo;adapter=MP;constructor(A={}){super("playbook",Es1,A,qn0)}async getInstructions(){return"Playbook entities describe durable, editable guided workflows for the agent. Use them as operating guidance when a playbook run is active; do not treat them as content to publish unless the user explicitly asks."}}function Ts1(A={}){return new gs1(A)}Cw();p0();K0();bY();U10();var Ss1={name:"@brains/playbooks",private:!0,version:"0.2.0-alpha.128",description:"Runtime orchestration for chat-native playbook runs",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/contracts":"workspace:*","@brains/playbook":"workspace:*","@brains/plugins":"workspace:*","@brains/runtime-state":"workspace:*","@brains/utils":"workspace:*",xstate:"^5.28.0"},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"}};K0();var us1=K.enum(["offered","active","completed","dismissed"]),Yf0=K.object({id:K.string().min(1),kind:K.enum(["entity_event"]),stateId:K.string().min(1).optional(),observedAt:K.string().datetime(),data:K.record(K.string(),K.unknown())}).strict(),cs1=K.object({stateId:K.string().min(1),goal:K.array(K.string().min(1)),met:K.boolean(),reason:K.string().min(1),evaluatedAt:K.string().datetime()}).strict(),PP=K.object({id:K.string().min(1),playbookId:K.string().min(1),playbookVersion:K.string().min(1),lifecycle:K.string().min(1).optional(),status:us1,conversationId:K.string().min(1).optional(),currentState:K.string().min(1),completedStates:K.array(K.string().min(1)).default([]),snapshot:K.unknown().optional(),context:K.record(K.string(),K.unknown()).default({}),evidence:K.array(Yf0).default([]),gateVerdicts:K.array(cs1).default([]),startedAt:K.string().datetime().optional(),completedAt:K.string().datetime().optional(),updatedAt:K.string().datetime()}).strict(),tZB="playbooks.runs",eZB=PP;class Xf0{store;writeQueue=Promise.resolve();constructor(A){this.store=A.scoped({namespace:tZB,schema:eZB})}async list(){return await this.waitForWrites(),(await this.store.list()).map((Q)=>Q.value)}async findById(A){return await this.store.get(A)??void 0}async findActiveByPlaybook(A){return(await this.list()).find((Q)=>Q.playbookId===A&&(Q.status==="active"||Q.status==="offered"))}async findByLifecycle(A){return(await this.list()).find((Q)=>Q.lifecycle===A)}async findActiveByConversation(A){return(await this.listActiveByConversation(A))[0]}async listActiveByConversation(A){return(await this.list()).filter((Q)=>Q.conversationId===A&&(Q.status==="active"||Q.status==="offered"))}async upsert(A){return this.enqueueMutation(async()=>{let Q=await this.store.get(A.id),B=PP.parse({...A,evidence:ms1(Q?.evidence??[],A.evidence),gateVerdicts:AKB(Q?.gateVerdicts??[],A.gateVerdicts),updatedAt:new Date().toISOString()});return await this.store.set(B.id,B),B})}async appendEvidence(A,Q){return this.enqueueMutation(async()=>{let B=await this.store.get(A);if(!B)throw Error(`Playbook run not found: ${A}`);let w=PP.parse({...B,evidence:ms1(B.evidence,[Q]),updatedAt:new Date().toISOString()});return await this.store.set(w.id,w),w})}async reset(A){await this.enqueueMutation(async()=>{if(!A){await this.store.clear();return}await this.store.delete(A)})}async enqueueMutation(A){let Q=this.writeQueue,B=()=>{};this.writeQueue=new Promise((w)=>{B=w}),await Q;try{return await A()}finally{B()}}async waitForWrites(){await this.writeQueue}}function Nn0(A){let Q=new Date().toISOString();return PP.parse({id:bI("playbook_run"),playbookId:A.playbookId,playbookVersion:A.playbookVersion,...A.lifecycle?{lifecycle:A.lifecycle}:{},status:A.status??"active",...A.conversationId?{conversationId:A.conversationId}:{},currentState:A.initialState,completedStates:[],...A.snapshot!==void 0?{snapshot:A.snapshot}:{},context:{},evidence:[],gateVerdicts:[],...A.status==="active"||A.status===void 0?{startedAt:Q}:{},updatedAt:Q})}function ms1(A,Q){let B=new Map;for(let w of[...A,...Q])B.set(w.id,w);return Array.from(B.values())}function AKB(A,Q){let B=new Map;for(let w of[...A,...Q])B.set(QKB(w),w);return Array.from(B.values())}function QKB(A){return[A.stateId,...A.goal].join("\x00")}var es1="playbooks:lifecycle-starters",BKB=K.object({trigger:K.string().min(1),playbookId:K.string().min(1),once:K.boolean().default(!0),starterText:K.string().min(1),description:K.string().min(1).optional(),starterPrompt:K.string().min(1)}).strict(),wKB=K.object({lifecycle:K.record(K.string(),BKB).default({}),triggers:K.record(K.string(),K.boolean()).default({})}).strict(),$KB=K.object({lifecycle:K.string().min(1).optional(),interfaceType:K.string().min(1),userPermissionLevel:K.enum(["anchor","trusted","public"])}).strict(),ls1=K.object({id:K.string().min(1),entityType:K.literal("playbook"),content:K.string().min(1),metadata:K.object({title:K.string().min(1),status:K.enum(["draft","active","archived"]),audience:K.enum(["anchor","trusted","public"]),trigger:K.string().min(1).optional(),lifecycle:K.string().min(1).optional(),once:K.boolean().optional(),starterText:K.string().min(1).optional(),description:K.string().min(1).optional(),starterPrompt:K.string().min(1).optional(),completionMode:K.enum(["agent-confirmed","manual"])}).passthrough()}).passthrough(),ps1={runId:K.string().min(1).optional(),playbookId:K.string().min(1).optional(),lifecycle:K.string().min(1).optional()},is1={playbookId:K.string().min(1),lifecycle:K.string().min(1).optional()},ds1={runId:K.string().min(1).optional(),event:K.string().min(1),context:K.record(K.string(),K.unknown()).optional()},DKB=K.object({met:K.boolean(),reason:K.string().min(1)}).strict(),fKB=K.object({event:K.string().min(1),target:K.string().min(1),operatorAction:K.boolean().optional(),label:K.string().min(1).optional(),description:K.string().min(1).optional(),operatorDescription:K.string().min(1).optional()}).strict(),YKB=K.object({id:K.string().min(1),title:K.string().min(1),instructions:K.array(K.string().min(1)),doneWhen:K.array(K.string().min(1)).default([]),transitions:K.array(fKB).default([])}).passthrough(),XKB=K.object({run:PP,state:YKB,goal:K.array(K.string().min(1)),evidence:K.array(Yf0).default([])}).strict();class Mn0 extends pQ{store;ctx;goalCheck;injectedGoalCheck;startLocks=new Map;constructor(A={},Q={}){super("playbooks",Ss1,A,wKB);this.injectedGoalCheck=Q.goalCheck,this.goalCheck=Q.goalCheck??LKB}async onRegister(A){await super.onRegister(A),this.ctx=A,this.store=new Xf0(A.runtimeState),this.goalCheck=this.injectedGoalCheck??FKB(A),A.registerInstructions(this.buildInstructions()),A.eval.registerHandler("goalCheck",async(Q)=>this.goalCheck.evaluate(XKB.parse(Q))),A.messaging.subscribe(es1,async(Q)=>{let B=$KB.parse(Q.payload);return{success:!0,data:{starters:await this.resolveLifecycleStarters(B)}}}),A.messaging.subscribe(BN,async(Q)=>{let B=TT.parse(Q.payload),w=await this.buildAgentContextItem(B.conversationId);return{success:!0,data:{items:w?[w]:[]}}}),A.messaging.subscribe(ET,async(Q)=>{let B=jZ0.parse(Q.payload),w=await this.handleAgentAction(B);return w?{success:!0,data:w}:{success:!1}}),A.messaging.subscribe("entity:created",async(Q)=>({success:!0,data:await this.recordEntityEventEvidence("created",Q.payload)})),A.messaging.subscribe("entity:updated",async(Q)=>({success:!0,data:await this.recordEntityEventEvidence("updated",Q.payload)}))}async getTools(){return[{name:"playbook_status",description:"Get playbook lifecycle config, active runs, current state, valid events, and parsed playbook body. After meaningful tool actions, use the reported current state as source of truth. Do not send an extra NEXT after runtime evidence already advanced the run. Do not claim the playbook is finished unless the run has reached a final state.",inputSchema:ps1,visibility:"anchor",handler:async(A,Q)=>{let B=K.object(ps1).parse(A);try{return{success:!0,data:await this.getStatus({...B,conversationId:Q.conversationId})}}catch(w){return{success:!1,error:jn0(w)}}}},{name:"playbook_start",description:"Start a playbook run, or resume an existing active run. If the operator asks to start a playbook by title, use the stable slug/id form when known (for example lowercase words joined by hyphens) instead of claiming it is unavailable without calling this tool. Do not call this to continue an already active playbook; use playbook_status and playbook_send_event with a valid event instead.",inputSchema:is1,visibility:"anchor",handler:async(A,Q)=>{let B=K.object(is1).parse(A),w=Q.conversationId,$=w?`${w}:${B.playbookId}`:`playbook:${B.playbookId}`;return this.withStartLock($,async()=>{let D=await this.requirePlaybook(B.playbookId);Zo(D.body);let f=D.entity.metadata.lifecycle??B.lifecycle,Y=w?(await this.store.listActiveByConversation(w)).find((W)=>W.playbookId===B.playbookId):await this.store.findActiveByPlaybook(B.playbookId),X=Y?await this.store.upsert({...Y,status:"active",...w?{conversationId:w}:{},...Y.startedAt?{}:{startedAt:new Date().toISOString()}}):await this.createStartedRun({playbookId:B.playbookId,playbookVersion:D.version,body:D.body,lifecycle:f,conversationId:w});return{success:!0,data:await this.getStatus({runId:X.id})}})}},{name:"playbook_send_event",description:"Send an event to a playbook run state machine and persist the resulting state. Invalid events return an error. Only use this when the operator positively selects a valid event/action or when a gated Done When condition is actually met. For durable gated states, user-provided details are not enough; do not send NEXT until the required system_create/system_update/system_delete tool has succeeded or current run evidence already shows the Done When condition is met. Operator actions and choices are not generic continuation events; do not use this for generic next/continue to select an operator action, even if only one operator action is currently valid. Do not use this when the operator explicitly says they have not chosen, selected, asked for, or used the available action. Skip-style events require a positive request to skip. This tool only changes playbook state; it does not retrieve, show, save, create, update, or transform domain entities. When the operator message only selects a playbook action, call this tool without unrelated domain mutation tools such as system_create or system_update. If the operator also asks to find/show/retrieve content, call system_get or system_search before answering.",inputSchema:ds1,visibility:"anchor",handler:async(A,Q)=>{let B=K.object(ds1).parse(A),w=await this.resolveScopedRunResponse({runId:B.runId,conversationId:Q.conversationId});if(!w.success)return w;let $=await this.sendEventForRun(w.data,B.event,B.context);return $.success?{success:!0,data:$.data}:{success:!1,error:$.error}}}]}async withStartLock(A,Q){let B=this.startLocks.get(A);if(B)return B;let w=Q().finally(()=>{this.startLocks.delete(A)});return this.startLocks.set(A,w),w}async handleAgentAction(A){if(A.userPermissionLevel!=="anchor")return;let Q=await this.resolveScopedRunResponse({conversationId:A.conversationId});if(!Q.success)return;let B=await this.sendEventForRun(Q.data,A.action.event);if(!B.success)return{text:`I couldn't continue the playbook: ${B.error}`,toolResults:[{toolName:"playbook_send_event",args:{runId:Q.data.id,event:A.action.event}}],usage:rs1()};let w=this.getCurrentRunState(B.data);return{text:KKB(w),...B.data.cards?{cards:B.data.cards}:{},toolResults:[{toolName:"playbook_send_event",args:{runId:Q.data.id,event:A.action.event},data:B.data}],usage:rs1()}}getCurrentRunState(A){return A.currentState}async sendEventForRun(A,Q,B){let w=await this.requirePlaybook(A.playbookId);if(A.playbookVersion!==w.version)return{success:!1,error:`Playbook definition changed for '${A.playbookId}'. Run version ${A.playbookVersion} does not match current version ${w.version}.`};let $=this.getState(w.body,A.currentState),D=$?.transitions.find((W)=>W.event===Q),f=await this.transitionRun(A,w.body,Q);if(!f.success){if(f.gateVerdicts)await this.store.upsert({...A,gateVerdicts:f.gateVerdicts});return{success:!1,error:f.error}}let Y=w.body.finalStates.includes(f.currentState),X=await this.store.upsert({...A,currentState:f.currentState,completedStates:os1(A.completedStates,A.currentState),snapshot:f.snapshot,gateVerdicts:f.gateVerdicts,context:{...A.context,...B??{}},...Y?{status:"completed",completedAt:new Date().toISOString()}:{}}),H=await this.getStatus({runId:X.id});return{success:!0,data:$&&D?.operatorAction===!0?HKB(H,$,D):H}}async createStartedRun(A){let Q=Nn0({playbookId:A.playbookId,playbookVersion:A.playbookVersion,initialState:A.body.initialState,lifecycle:A.lifecycle,conversationId:A.conversationId}),B=this.buildMachine(A.playbookId,A.body,Q),w=E1.createActor(B);w.start();let $=w.getPersistedSnapshot();return w.stop(),this.store.upsert({...Q,snapshot:$})}async transitionRun(A,Q,B){let w=this.getState(Q,A.currentState);if(!w)return{success:!1,error:`Playbook state not found: ${A.currentState}`};let $=await this.prepareGateVerdicts(A,w,B);if(!$.success)return $;let D={...A,gateVerdicts:$.gateVerdicts},f=this.buildMachine(A.playbookId,Q,D),Y=E1.createActor(f,{...A.snapshot?{snapshot:A.snapshot}:{}});Y.start();let X=Y.getSnapshot(),H={type:B};if(!X.can(H))return Y.stop(),{success:!1,error:`Invalid playbook event '${B}' from state '${A.currentState}'.`,gateVerdicts:$.gateVerdicts};Y.send(H);let W=Y.getSnapshot(),Z=String(W.value),G=w.transitions.find((I)=>I.event===B)?.target;if(G&&Z!==G)return Y.stop(),{success:!1,error:`Playbook event '${B}' is blocked from state '${A.currentState}'. Complete the state's Done When conditions before sending this event.`,gateVerdicts:$.gateVerdicts};let F=Y.getPersistedSnapshot();return Y.stop(),{success:!0,currentState:Z,snapshot:F,gateVerdicts:$.gateVerdicts}}async prepareGateVerdicts(A,Q,B){if(!this.transitionRequiresGateVerdict(Q,B))return{success:!0,gateVerdicts:A.gateVerdicts};if(this.hasSatisfiedGateVerdicts(Q,A))return{success:!0,gateVerdicts:A.gateVerdicts};let w=this.evidenceForState(A,Q.id),$;try{$=await this.goalCheck.evaluate({run:A,state:Q,goal:Q.doneWhen,evidence:w})}catch(Y){$={met:!1,reason:`Playbook goal check failed: ${jn0(Y)}`}}let D={stateId:Q.id,goal:Q.doneWhen,met:$.met,reason:$.reason,evaluatedAt:new Date().toISOString()};return{success:!0,gateVerdicts:GKB(A.gateVerdicts,[D])}}evidenceForState(A,Q){return A.evidence.filter((B)=>!B.stateId||B.stateId===Q)}buildMachine(A,Q,B){return E1.createMachine({id:A,initial:Q.initialState,states:Object.fromEntries(Q.states.map((w)=>{let $=Q.finalStates.includes(w.id);return[w.id,{...$?{type:"final"}:{},...$?{}:{on:Object.fromEntries(w.transitions.map((D)=>[D.event,{target:D.target,...this.transitionRequiresGateVerdict(w,D.event)?{guard:()=>this.hasSatisfiedGateVerdicts(w,B)}:{}}]))}}]}))})}async resolveLifecycleStarters(A){if(A.interfaceType!=="web-chat"||A.userPermissionLevel!=="anchor")return[];let Q=[],B=new Set,w=Object.entries(this.config.lifecycle).filter(([D])=>!A.lifecycle||D===A.lifecycle);for(let[D,f]of w){let Y=await this.resolveConfiguredLifecycleStarter(D,f);if(!Y)continue;Q.push(Y),B.add(D)}let $=new Set(Object.entries(this.config.triggers).filter(([,D])=>D).map(([D])=>D));if($.size===0)return Q;for(let D of await this.listPlaybooks()){let f=D.entity.metadata;if(f.status!=="active"||f.audience!=="anchor")continue;let Y=f.trigger;if(!Y||!$.has(Y))continue;let X=f.lifecycle??D.entity.id;if(B.has(X))continue;if(A.lifecycle&&X!==A.lifecycle)continue;let H=await this.store.findByLifecycle(X);if((f.once??!0)&&(H?.status==="completed"||H?.status==="dismissed"))continue;Q.push({id:X,title:f.starterText??f.title,...f.description??D.body.purpose?{description:f.description??D.body.purpose}:{},playbookId:D.entity.id,lifecycle:X,starterPrompt:f.starterPrompt??`Start the ${f.title} playbook.`}),B.add(X)}return Q}async resolveConfiguredLifecycleStarter(A,Q){let B=await this.store.findByLifecycle(A);if(Q.once&&(B?.status==="completed"||B?.status==="dismissed"))return;if((await this.getPlaybook(Q.playbookId))?.entity.metadata.status!=="active")return;return{id:A,title:Q.starterText,...Q.description?{description:Q.description}:{},playbookId:Q.playbookId,lifecycle:A,starterPrompt:Q.starterPrompt}}async listPlaybooks(){if(!this.ctx)return[];return(await this.ctx.entityService.listEntities({entityType:"playbook"})).flatMap((Q)=>{let B=ls1.safeParse(Q);if(!B.success)return[];let{body:w}=MP.parsePlaybookContent(B.data.content);return[{entity:B.data,body:w,version:RB(B.data.content)}]})}async getStatus(A){let Q=await this.store.list(),B=A.conversationId?Q.filter((L)=>L.conversationId===A.conversationId):[],w=B.filter((L)=>L.status==="active"||L.status==="offered"),$=UKB(B.filter((L)=>(!A.playbookId||L.playbookId===A.playbookId)&&(!A.lifecycle||L.lifecycle===A.lifecycle))),D=A.runId?Q.find((L)=>L.id===A.runId)??$:A.conversationId&&A.lifecycle?w.find((L)=>L.lifecycle===A.lifecycle)??$:A.conversationId&&A.playbookId?w.find((L)=>L.playbookId===A.playbookId)??$:A.conversationId?w.length>0?await this.requireScopedRun({conversationId:A.conversationId}):$:A.lifecycle?Q.find((L)=>L.lifecycle===A.lifecycle):A.playbookId?Q.find((L)=>L.playbookId===A.playbookId):void 0;if(A.conversationId&&!D&&!A.runId&&!A.playbookId&&!A.lifecycle)throw Error(`No active or completed playbook run for conversation '${A.conversationId}'.`);let f=A.playbookId??D?.playbookId??(A.lifecycle?this.config.lifecycle[A.lifecycle]?.playbookId:void 0),Y=f?await this.getPlaybook(f):void 0,X=Y&&D?this.getState(Y.body,D.currentState):void 0,H=X&&D&&Y?this.getValidTransitions(D,Y.body,X):X?.transitions??[],W=H.filter((L)=>L.operatorAction!==!0),Z=H.filter((L)=>L.operatorAction===!0),G=X&&D&&Y?this.getBlockedTransitions(D,Y.body,X):[],F=X&&D&&Y?this.buildStateGuidance(D,Y.body,X):void 0,I=D&&Y&&Z.length>0?ZKB({run:D,title:Y.entity.metadata.title,transitions:Z}):void 0;return{runs:(A.conversationId?B:Q).map(ns1),...D?{activeRun:ns1(D)}:{},...Y?{playbook:Y.entity}:{},...Y?{body:Y.body}:{},...X?{currentState:X}:{},...W.length>0?{validEvents:W}:{},...Z.length>0?{operatorActions:Z}:{},...G.length>0?{blockedEvents:G}:{},...F?{guidance:F}:{},...I?{cards:[I]}:{},lifecycle:this.config.lifecycle}}buildStateGuidance(A,Q,B){let w=this.getValidTransitions(A,Q,B),$=w.filter((X)=>X.operatorAction!==!0),D=w.filter((X)=>X.operatorAction===!0),f=this.getBlockedTransitions(A,Q,B),Y=A.gateVerdicts.find((X)=>X.stateId===B.id&&_n0(X.goal,B.doneWhen));return[`Current state: ${B.id} (${B.title})`,"Instructions:",...B.instructions.map((X)=>`- ${X}`),"Done When:",...B.doneWhen.length>0?B.doneWhen.map((X)=>`- ${X}`):["- none"],"Goal status:",Y?`- ${Y.met?"Met":"Not yet met"}: ${Y.reason}`:"- Not checked yet.","Current-state information rules:","- If this state asks the operator for information, ask the operator for the missing current-run information.","- If the current operator message partially answers the state's prompt, do not repeat the original prompt; ask only for the next missing detail required by the state instructions.","- Do not answer the state's operator-facing prompt from memory, existing durable records, profile data, search, or retrieval tools.","- Setup facts must come from current-run evidence or current operator input, not ambient records.","Event selection rules:","- Blocked events are not valid events; do not call playbook_send_event with a blocked event.","- For gated durable states, operator-provided details are not enough to send NEXT; first complete the required system_create/system_update/system_delete action or use existing current-run evidence that the Done When condition has already been met.","- If the operator explicitly says they have not chosen, selected, asked for, or used one of the available actions, do not send any event.",'- Operator actions and choices are not generic continuation events; even if only one operator action is available, generic continuation like "yes", "next", or "continue" is not a valid selection.',"- If multiple events are available, ask the operator to pick one labeled action.","- A Skip-style operator action is never a default continuation; send it only when the operator positively selects or asks to skip.","Valid continuation events:",...$.length>0?$.map((X)=>this.formatTransition(X)):["- none"],"Available operator actions:",...D.length>0?D.map((X)=>this.formatTransition(X)):["- none"],"Blocked events:",...f.length>0?f.map((X)=>this.formatTransition(X)):["- none"]].join(`
|
|
8425
|
+
`))}function nZB(A,Q){return Jn0(A,Q).map(rZB)}function rZB(A){let Q=/^(.+?)\s*(?:\u2192|->)\s*(.+)$/.exec(A);if(!Q)throw Error(`Invalid playbook choice '${A}'. Expected "Label \u2192 Step".`);return{label:Q[1]?.trim()??"",target:Q[2]?.trim()??""}}function Cs1(A){let Q=/^Skip:\s*(.+?)\s*(?:\u2192|->)\s*(.+?)\s*$/im.exec(A);if(!Q)return;return{label:Q[1]?.trim()??"",target:Q[2]?.trim()??""}}function ys1(A){return A.split(/\r?\n/).map((Q)=>/^-\s+(.+?)\s*$/.exec(Q)?.[1]?.trim()).filter((Q)=>Boolean(Q))}function oZB(A){return A.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Es1={name:"@brains/playbook",private:!0,version:"0.2.0-alpha.129",description:"Playbook entity for durable guided agent workflows",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/content-formatters":"workspace:*","@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 gs1 extends PQ{entityType=MP.entityType;schema=Wo;adapter=MP;constructor(A={}){super("playbook",Es1,A,qn0)}async getInstructions(){return"Playbook entities describe durable, editable guided workflows for the agent. Use them as operating guidance when a playbook run is active; do not treat them as content to publish unless the user explicitly asks."}}function Ts1(A={}){return new gs1(A)}Cw();p0();K0();bY();U10();var Ss1={name:"@brains/playbooks",private:!0,version:"0.2.0-alpha.129",description:"Runtime orchestration for chat-native playbook runs",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/contracts":"workspace:*","@brains/playbook":"workspace:*","@brains/plugins":"workspace:*","@brains/runtime-state":"workspace:*","@brains/utils":"workspace:*",xstate:"^5.28.0"},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"}};K0();var us1=K.enum(["offered","active","completed","dismissed"]),Yf0=K.object({id:K.string().min(1),kind:K.enum(["entity_event"]),stateId:K.string().min(1).optional(),observedAt:K.string().datetime(),data:K.record(K.string(),K.unknown())}).strict(),cs1=K.object({stateId:K.string().min(1),goal:K.array(K.string().min(1)),met:K.boolean(),reason:K.string().min(1),evaluatedAt:K.string().datetime()}).strict(),PP=K.object({id:K.string().min(1),playbookId:K.string().min(1),playbookVersion:K.string().min(1),lifecycle:K.string().min(1).optional(),status:us1,conversationId:K.string().min(1).optional(),currentState:K.string().min(1),completedStates:K.array(K.string().min(1)).default([]),snapshot:K.unknown().optional(),context:K.record(K.string(),K.unknown()).default({}),evidence:K.array(Yf0).default([]),gateVerdicts:K.array(cs1).default([]),startedAt:K.string().datetime().optional(),completedAt:K.string().datetime().optional(),updatedAt:K.string().datetime()}).strict(),tZB="playbooks.runs",eZB=PP;class Xf0{store;writeQueue=Promise.resolve();constructor(A){this.store=A.scoped({namespace:tZB,schema:eZB})}async list(){return await this.waitForWrites(),(await this.store.list()).map((Q)=>Q.value)}async findById(A){return await this.store.get(A)??void 0}async findActiveByPlaybook(A){return(await this.list()).find((Q)=>Q.playbookId===A&&(Q.status==="active"||Q.status==="offered"))}async findByLifecycle(A){return(await this.list()).find((Q)=>Q.lifecycle===A)}async findActiveByConversation(A){return(await this.listActiveByConversation(A))[0]}async listActiveByConversation(A){return(await this.list()).filter((Q)=>Q.conversationId===A&&(Q.status==="active"||Q.status==="offered"))}async upsert(A){return this.enqueueMutation(async()=>{let Q=await this.store.get(A.id),B=PP.parse({...A,evidence:ms1(Q?.evidence??[],A.evidence),gateVerdicts:AKB(Q?.gateVerdicts??[],A.gateVerdicts),updatedAt:new Date().toISOString()});return await this.store.set(B.id,B),B})}async appendEvidence(A,Q){return this.enqueueMutation(async()=>{let B=await this.store.get(A);if(!B)throw Error(`Playbook run not found: ${A}`);let w=PP.parse({...B,evidence:ms1(B.evidence,[Q]),updatedAt:new Date().toISOString()});return await this.store.set(w.id,w),w})}async reset(A){await this.enqueueMutation(async()=>{if(!A){await this.store.clear();return}await this.store.delete(A)})}async enqueueMutation(A){let Q=this.writeQueue,B=()=>{};this.writeQueue=new Promise((w)=>{B=w}),await Q;try{return await A()}finally{B()}}async waitForWrites(){await this.writeQueue}}function Nn0(A){let Q=new Date().toISOString();return PP.parse({id:bI("playbook_run"),playbookId:A.playbookId,playbookVersion:A.playbookVersion,...A.lifecycle?{lifecycle:A.lifecycle}:{},status:A.status??"active",...A.conversationId?{conversationId:A.conversationId}:{},currentState:A.initialState,completedStates:[],...A.snapshot!==void 0?{snapshot:A.snapshot}:{},context:{},evidence:[],gateVerdicts:[],...A.status==="active"||A.status===void 0?{startedAt:Q}:{},updatedAt:Q})}function ms1(A,Q){let B=new Map;for(let w of[...A,...Q])B.set(w.id,w);return Array.from(B.values())}function AKB(A,Q){let B=new Map;for(let w of[...A,...Q])B.set(QKB(w),w);return Array.from(B.values())}function QKB(A){return[A.stateId,...A.goal].join("\x00")}var es1="playbooks:lifecycle-starters",BKB=K.object({trigger:K.string().min(1),playbookId:K.string().min(1),once:K.boolean().default(!0),starterText:K.string().min(1),description:K.string().min(1).optional(),starterPrompt:K.string().min(1)}).strict(),wKB=K.object({lifecycle:K.record(K.string(),BKB).default({}),triggers:K.record(K.string(),K.boolean()).default({})}).strict(),$KB=K.object({lifecycle:K.string().min(1).optional(),interfaceType:K.string().min(1),userPermissionLevel:K.enum(["anchor","trusted","public"])}).strict(),ls1=K.object({id:K.string().min(1),entityType:K.literal("playbook"),content:K.string().min(1),metadata:K.object({title:K.string().min(1),status:K.enum(["draft","active","archived"]),audience:K.enum(["anchor","trusted","public"]),trigger:K.string().min(1).optional(),lifecycle:K.string().min(1).optional(),once:K.boolean().optional(),starterText:K.string().min(1).optional(),description:K.string().min(1).optional(),starterPrompt:K.string().min(1).optional(),completionMode:K.enum(["agent-confirmed","manual"])}).passthrough()}).passthrough(),ps1={runId:K.string().min(1).optional(),playbookId:K.string().min(1).optional(),lifecycle:K.string().min(1).optional()},is1={playbookId:K.string().min(1),lifecycle:K.string().min(1).optional()},ds1={runId:K.string().min(1).optional(),event:K.string().min(1),context:K.record(K.string(),K.unknown()).optional()},DKB=K.object({met:K.boolean(),reason:K.string().min(1)}).strict(),fKB=K.object({event:K.string().min(1),target:K.string().min(1),operatorAction:K.boolean().optional(),label:K.string().min(1).optional(),description:K.string().min(1).optional(),operatorDescription:K.string().min(1).optional()}).strict(),YKB=K.object({id:K.string().min(1),title:K.string().min(1),instructions:K.array(K.string().min(1)),doneWhen:K.array(K.string().min(1)).default([]),transitions:K.array(fKB).default([])}).passthrough(),XKB=K.object({run:PP,state:YKB,goal:K.array(K.string().min(1)),evidence:K.array(Yf0).default([])}).strict();class Mn0 extends pQ{store;ctx;goalCheck;injectedGoalCheck;startLocks=new Map;constructor(A={},Q={}){super("playbooks",Ss1,A,wKB);this.injectedGoalCheck=Q.goalCheck,this.goalCheck=Q.goalCheck??LKB}async onRegister(A){await super.onRegister(A),this.ctx=A,this.store=new Xf0(A.runtimeState),this.goalCheck=this.injectedGoalCheck??FKB(A),A.registerInstructions(this.buildInstructions()),A.eval.registerHandler("goalCheck",async(Q)=>this.goalCheck.evaluate(XKB.parse(Q))),A.messaging.subscribe(es1,async(Q)=>{let B=$KB.parse(Q.payload);return{success:!0,data:{starters:await this.resolveLifecycleStarters(B)}}}),A.messaging.subscribe(BN,async(Q)=>{let B=TT.parse(Q.payload),w=await this.buildAgentContextItem(B.conversationId);return{success:!0,data:{items:w?[w]:[]}}}),A.messaging.subscribe(ET,async(Q)=>{let B=jZ0.parse(Q.payload),w=await this.handleAgentAction(B);return w?{success:!0,data:w}:{success:!1}}),A.messaging.subscribe("entity:created",async(Q)=>({success:!0,data:await this.recordEntityEventEvidence("created",Q.payload)})),A.messaging.subscribe("entity:updated",async(Q)=>({success:!0,data:await this.recordEntityEventEvidence("updated",Q.payload)}))}async getTools(){return[{name:"playbook_status",description:"Get playbook lifecycle config, active runs, current state, valid events, and parsed playbook body. After meaningful tool actions, use the reported current state as source of truth. Do not send an extra NEXT after runtime evidence already advanced the run. Do not claim the playbook is finished unless the run has reached a final state.",inputSchema:ps1,visibility:"anchor",handler:async(A,Q)=>{let B=K.object(ps1).parse(A);try{return{success:!0,data:await this.getStatus({...B,conversationId:Q.conversationId})}}catch(w){return{success:!1,error:jn0(w)}}}},{name:"playbook_start",description:"Start a playbook run, or resume an existing active run. If the operator asks to start a playbook by title, use the stable slug/id form when known (for example lowercase words joined by hyphens) instead of claiming it is unavailable without calling this tool. Do not call this to continue an already active playbook; use playbook_status and playbook_send_event with a valid event instead.",inputSchema:is1,visibility:"anchor",handler:async(A,Q)=>{let B=K.object(is1).parse(A),w=Q.conversationId,$=w?`${w}:${B.playbookId}`:`playbook:${B.playbookId}`;return this.withStartLock($,async()=>{let D=await this.requirePlaybook(B.playbookId);Zo(D.body);let f=D.entity.metadata.lifecycle??B.lifecycle,Y=w?(await this.store.listActiveByConversation(w)).find((W)=>W.playbookId===B.playbookId):await this.store.findActiveByPlaybook(B.playbookId),X=Y?await this.store.upsert({...Y,status:"active",...w?{conversationId:w}:{},...Y.startedAt?{}:{startedAt:new Date().toISOString()}}):await this.createStartedRun({playbookId:B.playbookId,playbookVersion:D.version,body:D.body,lifecycle:f,conversationId:w});return{success:!0,data:await this.getStatus({runId:X.id})}})}},{name:"playbook_send_event",description:"Send an event to a playbook run state machine and persist the resulting state. Invalid events return an error. Only use this when the operator positively selects a valid event/action or when a gated Done When condition is actually met. For durable gated states, user-provided details are not enough; do not send NEXT until the required system_create/system_update/system_delete tool has succeeded or current run evidence already shows the Done When condition is met. Operator actions and choices are not generic continuation events; do not use this for generic next/continue to select an operator action, even if only one operator action is currently valid. Do not use this when the operator explicitly says they have not chosen, selected, asked for, or used the available action. Skip-style events require a positive request to skip. This tool only changes playbook state; it does not retrieve, show, save, create, update, or transform domain entities. When the operator message only selects a playbook action, call this tool without unrelated domain mutation tools such as system_create or system_update. If the operator also asks to find/show/retrieve content, call system_get or system_search before answering.",inputSchema:ds1,visibility:"anchor",handler:async(A,Q)=>{let B=K.object(ds1).parse(A),w=await this.resolveScopedRunResponse({runId:B.runId,conversationId:Q.conversationId});if(!w.success)return w;let $=await this.sendEventForRun(w.data,B.event,B.context);return $.success?{success:!0,data:$.data}:{success:!1,error:$.error}}}]}async withStartLock(A,Q){let B=this.startLocks.get(A);if(B)return B;let w=Q().finally(()=>{this.startLocks.delete(A)});return this.startLocks.set(A,w),w}async handleAgentAction(A){if(A.userPermissionLevel!=="anchor")return;let Q=await this.resolveScopedRunResponse({conversationId:A.conversationId});if(!Q.success)return;let B=await this.sendEventForRun(Q.data,A.action.event);if(!B.success)return{text:`I couldn't continue the playbook: ${B.error}`,toolResults:[{toolName:"playbook_send_event",args:{runId:Q.data.id,event:A.action.event}}],usage:rs1()};let w=this.getCurrentRunState(B.data);return{text:KKB(w),...B.data.cards?{cards:B.data.cards}:{},toolResults:[{toolName:"playbook_send_event",args:{runId:Q.data.id,event:A.action.event},data:B.data}],usage:rs1()}}getCurrentRunState(A){return A.currentState}async sendEventForRun(A,Q,B){let w=await this.requirePlaybook(A.playbookId);if(A.playbookVersion!==w.version)return{success:!1,error:`Playbook definition changed for '${A.playbookId}'. Run version ${A.playbookVersion} does not match current version ${w.version}.`};let $=this.getState(w.body,A.currentState),D=$?.transitions.find((W)=>W.event===Q),f=await this.transitionRun(A,w.body,Q);if(!f.success){if(f.gateVerdicts)await this.store.upsert({...A,gateVerdicts:f.gateVerdicts});return{success:!1,error:f.error}}let Y=w.body.finalStates.includes(f.currentState),X=await this.store.upsert({...A,currentState:f.currentState,completedStates:os1(A.completedStates,A.currentState),snapshot:f.snapshot,gateVerdicts:f.gateVerdicts,context:{...A.context,...B??{}},...Y?{status:"completed",completedAt:new Date().toISOString()}:{}}),H=await this.getStatus({runId:X.id});return{success:!0,data:$&&D?.operatorAction===!0?HKB(H,$,D):H}}async createStartedRun(A){let Q=Nn0({playbookId:A.playbookId,playbookVersion:A.playbookVersion,initialState:A.body.initialState,lifecycle:A.lifecycle,conversationId:A.conversationId}),B=this.buildMachine(A.playbookId,A.body,Q),w=E1.createActor(B);w.start();let $=w.getPersistedSnapshot();return w.stop(),this.store.upsert({...Q,snapshot:$})}async transitionRun(A,Q,B){let w=this.getState(Q,A.currentState);if(!w)return{success:!1,error:`Playbook state not found: ${A.currentState}`};let $=await this.prepareGateVerdicts(A,w,B);if(!$.success)return $;let D={...A,gateVerdicts:$.gateVerdicts},f=this.buildMachine(A.playbookId,Q,D),Y=E1.createActor(f,{...A.snapshot?{snapshot:A.snapshot}:{}});Y.start();let X=Y.getSnapshot(),H={type:B};if(!X.can(H))return Y.stop(),{success:!1,error:`Invalid playbook event '${B}' from state '${A.currentState}'.`,gateVerdicts:$.gateVerdicts};Y.send(H);let W=Y.getSnapshot(),Z=String(W.value),G=w.transitions.find((I)=>I.event===B)?.target;if(G&&Z!==G)return Y.stop(),{success:!1,error:`Playbook event '${B}' is blocked from state '${A.currentState}'. Complete the state's Done When conditions before sending this event.`,gateVerdicts:$.gateVerdicts};let F=Y.getPersistedSnapshot();return Y.stop(),{success:!0,currentState:Z,snapshot:F,gateVerdicts:$.gateVerdicts}}async prepareGateVerdicts(A,Q,B){if(!this.transitionRequiresGateVerdict(Q,B))return{success:!0,gateVerdicts:A.gateVerdicts};if(this.hasSatisfiedGateVerdicts(Q,A))return{success:!0,gateVerdicts:A.gateVerdicts};let w=this.evidenceForState(A,Q.id),$;try{$=await this.goalCheck.evaluate({run:A,state:Q,goal:Q.doneWhen,evidence:w})}catch(Y){$={met:!1,reason:`Playbook goal check failed: ${jn0(Y)}`}}let D={stateId:Q.id,goal:Q.doneWhen,met:$.met,reason:$.reason,evaluatedAt:new Date().toISOString()};return{success:!0,gateVerdicts:GKB(A.gateVerdicts,[D])}}evidenceForState(A,Q){return A.evidence.filter((B)=>!B.stateId||B.stateId===Q)}buildMachine(A,Q,B){return E1.createMachine({id:A,initial:Q.initialState,states:Object.fromEntries(Q.states.map((w)=>{let $=Q.finalStates.includes(w.id);return[w.id,{...$?{type:"final"}:{},...$?{}:{on:Object.fromEntries(w.transitions.map((D)=>[D.event,{target:D.target,...this.transitionRequiresGateVerdict(w,D.event)?{guard:()=>this.hasSatisfiedGateVerdicts(w,B)}:{}}]))}}]}))})}async resolveLifecycleStarters(A){if(A.interfaceType!=="web-chat"||A.userPermissionLevel!=="anchor")return[];let Q=[],B=new Set,w=Object.entries(this.config.lifecycle).filter(([D])=>!A.lifecycle||D===A.lifecycle);for(let[D,f]of w){let Y=await this.resolveConfiguredLifecycleStarter(D,f);if(!Y)continue;Q.push(Y),B.add(D)}let $=new Set(Object.entries(this.config.triggers).filter(([,D])=>D).map(([D])=>D));if($.size===0)return Q;for(let D of await this.listPlaybooks()){let f=D.entity.metadata;if(f.status!=="active"||f.audience!=="anchor")continue;let Y=f.trigger;if(!Y||!$.has(Y))continue;let X=f.lifecycle??D.entity.id;if(B.has(X))continue;if(A.lifecycle&&X!==A.lifecycle)continue;let H=await this.store.findByLifecycle(X);if((f.once??!0)&&(H?.status==="completed"||H?.status==="dismissed"))continue;Q.push({id:X,title:f.starterText??f.title,...f.description??D.body.purpose?{description:f.description??D.body.purpose}:{},playbookId:D.entity.id,lifecycle:X,starterPrompt:f.starterPrompt??`Start the ${f.title} playbook.`}),B.add(X)}return Q}async resolveConfiguredLifecycleStarter(A,Q){let B=await this.store.findByLifecycle(A);if(Q.once&&(B?.status==="completed"||B?.status==="dismissed"))return;if((await this.getPlaybook(Q.playbookId))?.entity.metadata.status!=="active")return;return{id:A,title:Q.starterText,...Q.description?{description:Q.description}:{},playbookId:Q.playbookId,lifecycle:A,starterPrompt:Q.starterPrompt}}async listPlaybooks(){if(!this.ctx)return[];return(await this.ctx.entityService.listEntities({entityType:"playbook"})).flatMap((Q)=>{let B=ls1.safeParse(Q);if(!B.success)return[];let{body:w}=MP.parsePlaybookContent(B.data.content);return[{entity:B.data,body:w,version:RB(B.data.content)}]})}async getStatus(A){let Q=await this.store.list(),B=A.conversationId?Q.filter((L)=>L.conversationId===A.conversationId):[],w=B.filter((L)=>L.status==="active"||L.status==="offered"),$=UKB(B.filter((L)=>(!A.playbookId||L.playbookId===A.playbookId)&&(!A.lifecycle||L.lifecycle===A.lifecycle))),D=A.runId?Q.find((L)=>L.id===A.runId)??$:A.conversationId&&A.lifecycle?w.find((L)=>L.lifecycle===A.lifecycle)??$:A.conversationId&&A.playbookId?w.find((L)=>L.playbookId===A.playbookId)??$:A.conversationId?w.length>0?await this.requireScopedRun({conversationId:A.conversationId}):$:A.lifecycle?Q.find((L)=>L.lifecycle===A.lifecycle):A.playbookId?Q.find((L)=>L.playbookId===A.playbookId):void 0;if(A.conversationId&&!D&&!A.runId&&!A.playbookId&&!A.lifecycle)throw Error(`No active or completed playbook run for conversation '${A.conversationId}'.`);let f=A.playbookId??D?.playbookId??(A.lifecycle?this.config.lifecycle[A.lifecycle]?.playbookId:void 0),Y=f?await this.getPlaybook(f):void 0,X=Y&&D?this.getState(Y.body,D.currentState):void 0,H=X&&D&&Y?this.getValidTransitions(D,Y.body,X):X?.transitions??[],W=H.filter((L)=>L.operatorAction!==!0),Z=H.filter((L)=>L.operatorAction===!0),G=X&&D&&Y?this.getBlockedTransitions(D,Y.body,X):[],F=X&&D&&Y?this.buildStateGuidance(D,Y.body,X):void 0,I=D&&Y&&Z.length>0?ZKB({run:D,title:Y.entity.metadata.title,transitions:Z}):void 0;return{runs:(A.conversationId?B:Q).map(ns1),...D?{activeRun:ns1(D)}:{},...Y?{playbook:Y.entity}:{},...Y?{body:Y.body}:{},...X?{currentState:X}:{},...W.length>0?{validEvents:W}:{},...Z.length>0?{operatorActions:Z}:{},...G.length>0?{blockedEvents:G}:{},...F?{guidance:F}:{},...I?{cards:[I]}:{},lifecycle:this.config.lifecycle}}buildStateGuidance(A,Q,B){let w=this.getValidTransitions(A,Q,B),$=w.filter((X)=>X.operatorAction!==!0),D=w.filter((X)=>X.operatorAction===!0),f=this.getBlockedTransitions(A,Q,B),Y=A.gateVerdicts.find((X)=>X.stateId===B.id&&_n0(X.goal,B.doneWhen));return[`Current state: ${B.id} (${B.title})`,"Instructions:",...B.instructions.map((X)=>`- ${X}`),"Done When:",...B.doneWhen.length>0?B.doneWhen.map((X)=>`- ${X}`):["- none"],"Goal status:",Y?`- ${Y.met?"Met":"Not yet met"}: ${Y.reason}`:"- Not checked yet.","Current-state information rules:","- If this state asks the operator for information, ask the operator for the missing current-run information.","- If the current operator message partially answers the state's prompt, do not repeat the original prompt; ask only for the next missing detail required by the state instructions.","- Do not answer the state's operator-facing prompt from memory, existing durable records, profile data, search, or retrieval tools.","- Setup facts must come from current-run evidence or current operator input, not ambient records.","Event selection rules:","- Blocked events are not valid events; do not call playbook_send_event with a blocked event.","- For gated durable states, operator-provided details are not enough to send NEXT; first complete the required system_create/system_update/system_delete action or use existing current-run evidence that the Done When condition has already been met.","- If the operator explicitly says they have not chosen, selected, asked for, or used one of the available actions, do not send any event.",'- Operator actions and choices are not generic continuation events; even if only one operator action is available, generic continuation like "yes", "next", or "continue" is not a valid selection.',"- If multiple events are available, ask the operator to pick one labeled action.","- A Skip-style operator action is never a default continuation; send it only when the operator positively selects or asks to skip.","Valid continuation events:",...$.length>0?$.map((X)=>this.formatTransition(X)):["- none"],"Available operator actions:",...D.length>0?D.map((X)=>this.formatTransition(X)):["- none"],"Blocked events:",...f.length>0?f.map((X)=>this.formatTransition(X)):["- none"]].join(`
|
|
8426
8426
|
`)}async recordEntityEventEvidence(A,Q){let B=jE(Q,"entityType"),w=jE(Q,"entityId");if(!B||!w)return{recorded:!1};let $=jE(Q,"runId"),D=jE(Q,"conversationId"),f=$?await this.store.findById($):D?await this.store.findActiveByConversation(D):void 0;if(f?.status!=="active")return{recorded:!1};let Y={id:bI("playbook_evidence"),kind:"entity_event",stateId:f.currentState,observedAt:new Date().toISOString(),data:{entityType:B,entityId:w,operation:A,...zKB(Q),...D?{conversationId:D}:{},...jE(Q,"toolCallId")?{toolCallId:jE(Q,"toolCallId")}:{}}},X=await this.store.appendEvidence(f.id,Y);return await this.evaluateGateAfterEvidence(X),{recorded:!0}}async evaluateGateAfterEvidence(A){if(this.hasSatisfiedGateForCurrentState(A))return;let Q=await this.getPlaybook(A.playbookId);if(A.playbookVersion!==Q?.version)return;let B=this.getState(Q.body,A.currentState);if(!B?.doneWhen.length)return;if(B.transitions.filter((X)=>X.event==="NEXT").length!==1)return;let $=await this.prepareGateVerdicts(A,B,"NEXT");if(!$.success)return;let D={...A,gateVerdicts:$.gateVerdicts};if(!this.hasSatisfiedGateVerdicts(B,D)){await this.store.upsert(D);return}let f=await this.transitionRun(D,Q.body,"NEXT");if(!f.success){await this.store.upsert(D);return}let Y=Q.body.finalStates.includes(f.currentState);await this.store.upsert({...D,currentState:f.currentState,completedStates:os1(D.completedStates,D.currentState),snapshot:f.snapshot,gateVerdicts:f.gateVerdicts,...Y?{status:"completed",completedAt:new Date().toISOString()}:{}})}hasSatisfiedGateForCurrentState(A){return A.gateVerdicts.some((Q)=>Q.stateId===A.currentState&&Q.met)}async getPlaybook(A){if(!this.ctx)return;let Q=await this.ctx.entityService.getEntity({entityType:"playbook",id:A,visibilityScope:p8("anchor")}),B=ls1.safeParse(Q);if(!B.success)return;let{body:w}=MP.parsePlaybookContent(B.data.content);return{entity:B.data,body:w,version:RB(B.data.content)}}async requirePlaybook(A){let Q=await this.getPlaybook(A);if(!Q)throw Error(`Playbook not found: ${A}`);return Q}async requireRun(A){let Q=await this.store.findById(A);if(!Q)throw Error(`Playbook run not found: ${A}`);return Q}async resolveScopedRunResponse(A){try{return{success:!0,data:await this.requireScopedRun(A)}}catch(Q){return{success:!1,error:jn0(Q)}}}async requireScopedRun(A){if(A.runId)return this.requireRun(A.runId);let Q=A.conversationId;if(!Q)throw Error("Missing runId and no active conversation id.");let B=await this.store.listActiveByConversation(Q);if(B.length===0)throw Error(`No active playbook run for conversation '${Q}'.`);if(B.length>1)throw Error(`Multiple active playbook runs for conversation '${Q}'. Provide runId explicitly.`);let w=B[0];if(!w)throw Error(`No active playbook run for conversation '${Q}'.`);return w}transitionRequiresGateVerdict(A,Q){return Q==="NEXT"&&A.doneWhen.length>0}hasSatisfiedGateVerdicts(A,Q){return Q.gateVerdicts.some((B)=>B.stateId===A.id&&_n0(B.goal,A.doneWhen)&&B.met)}getValidTransitions(A,Q,B){return B.transitions.filter((w)=>this.canTransition(A,Q,w.event))}getBlockedTransitions(A,Q,B){let w=new Set(this.getValidTransitions(A,Q,B).map(($)=>`${$.event}\x00${$.target}`));return B.transitions.filter(($)=>!w.has(`${$.event}\x00${$.target}`))}canTransition(A,Q,B){let w=this.buildMachine(A.playbookId,Q,A),$=E1.createActor(w,{...A.snapshot?{snapshot:A.snapshot}:{}});$.start();let D=$.getSnapshot().can({type:B});return $.stop(),D}formatTransition(A){let Q=A.operatorDescription??A.description??A.label;return Q?`- ${A.event} -> ${A.target}: ${Q}`:`- ${A.event} -> ${A.target}`}getState(A,Q){return A.states.find((B)=>B.id===Q)}formatVerifierStatus(A,Q){if(Q.doneWhen.length===0)return"- no gated Done When conditions";let B=A.gateVerdicts.find((w)=>w.stateId===Q.id&&_n0(w.goal,Q.doneWhen));if(!B)return`- Not yet met: ${Q.doneWhen.join("; ")}`;return B.met?`- Met: ${B.reason}`:`- Not yet met: ${B.reason}`}async buildAgentContextItem(A){let Q=await this.store.findActiveByConversation(A);if(!Q)return;let B=await this.getPlaybook(Q.playbookId);if(!B)return;let w=this.getState(B.body,Q.currentState);if(!w)return;let $=this.getValidTransitions(Q,B.body,w),D=$.filter((L)=>L.operatorAction!==!0),f=$.filter((L)=>L.operatorAction===!0),Y=new Set($.map((L)=>`${L.event}\x00${L.target}`)),X=w.transitions.filter((L)=>!Y.has(`${L.event}\x00${L.target}`)),H=D.map((L)=>this.formatTransition(L)).join(`
|
|
8427
8427
|
`),W=f.map((L)=>this.formatTransition(L)).join(`
|
|
8428
8428
|
`),Z=X.map((L)=>this.formatTransition(L)).join(`
|
|
@@ -8491,9 +8491,9 @@ ${Object.entries(this.config.lifecycle).map(([Q,B])=>`- ${Q}: playbookId=${B.pla
|
|
|
8491
8491
|
${A.guidance}`:$}}function ns1(A){return{...A,evidence:A.evidence.map((Q)=>({...Q,data:WKB(Q.data)}))}}function WKB(A){return Object.fromEntries(["entityType","entityId","operation"].flatMap((Q)=>A[Q]!==void 0?[[Q,A[Q]]]:[]))}function ZKB(A){return{kind:"actions",id:`actions:playbook:${A.run.id}`,title:A.title,defaultOpen:!0,actions:A.transitions.map((Q)=>({type:"event",id:`playbook:${A.run.id}:${Q.event}`,label:Q.label??Q.operatorDescription??Q.description??Q.event,event:Q.event,...Q.operatorDescription??Q.description?{description:Q.operatorDescription??Q.description}:{}}))}}function KKB(A){if(!A)return"Continuing.";return A.prompt??`Continuing to ${A.title}.`}function rs1(){return{promptTokens:0,completionTokens:0,totalTokens:0}}function os1(A,Q){return A.includes(Q)?A:[...A,Q]}function UKB(A){return[...A].sort((Q,B)=>(B.completedAt??B.updatedAt).localeCompare(Q.completedAt??Q.updatedAt))[0]}function jn0(A){return A instanceof Error?A.message:String(A)}function _n0(A,Q){return A.length===Q.length&&A.every((B,w)=>B===Q[w])}function GKB(A,Q){let B=new Set(Q.map(ss1));return[...A.filter((w)=>!B.has(ss1(w))),...Q]}function ss1(A){return[A.stateId,...A.goal].join("\x00")}function jE(A,Q){let B=A[Q];return typeof B==="string"&&B.length>0?B:void 0}function zKB(A){let Q=as1(A.entity);if(!Q)return{};let B=as1(Q.metadata),w=ts1(B?.title,B?.name,Q.title),$=ts1(Q.content),D=$?qKB($):void 0;return{...w?{title:w}:{},...D?{contentPreview:D}:{}}}function as1(A){if(typeof A!=="object"||A===null||Array.isArray(A))return;return A}function ts1(...A){return A.find((Q)=>typeof Q==="string"&&Q.trim().length>0)?.trim()}function qKB(A){let Q=A.replace(/\s+/g," ").trim();return Q.length>500?`${Q.slice(0,497)}...`:Q}function FKB(A){return{async evaluate(Q){let B=Q.goal.join(`
|
|
8492
8492
|
`),w=await A.entityService.search({query:B,options:{limit:8,excludeTypes:["playbook"],visibilityScope:p8("anchor")}}),$=IKB(Q,w),{verdict:D}=await A.judge({instruction:"Decide whether the playbook goal is satisfied by the supplied current-run runtime evidence and KB excerpts. Current-run runtime evidence is authoritative for playbook completion; use KB excerpts as supporting context, not to override clear runtime evidence from this run. Return met=true only when the outcome clearly holds. If evidence is missing or ambiguous, return met=false with a short reason.",material:$,schema:DKB});return D}}}function IKB(A,Q){return["## Playbook run",`runId: ${A.run.id}`,`playbookId: ${A.run.playbookId}`,`currentState: ${A.state.id} (${A.state.title})`,"","## State instructions",...A.state.instructions.map((B)=>`- ${B}`),"","## Done When goal",...A.goal.map((B)=>`- ${B}`),"","## Runtime evidence",...A.evidence.length>0?A.evidence.map((B,w)=>VKB(w+1,B)):["No runtime evidence collected for this state."],"","## KB excerpts",...Q.length>0?Q.map((B,w)=>JKB(w+1,B)):["No relevant KB excerpts found."]].join(`
|
|
8493
8493
|
`)}function VKB(A,Q){return`${A}. ${Q.kind} at ${Q.observedAt}: ${Aa1(Q.data)}`}function JKB(A,Q){return[`${A}. ${Q.entity.entityType}/${Q.entity.id} (score ${Q.score})`,`Excerpt: ${Q.excerpt}`,`Content: ${Qa1(Q.entity.content,1200)}`,`Metadata: ${Aa1(Q.entity.metadata)}`].join(`
|
|
8494
|
-
`)}function Aa1(A){try{return Qa1(JSON.stringify(A),1200)}catch{return"[unserializable]"}}function Qa1(A,Q){return A.length>Q?`${A.slice(0,Q)}\u2026`:A}var LKB={async evaluate(){return{met:!1,reason:"No playbook goal check is configured."}}};function Pn0(A={},Q={}){return new Mn0(A,Q)}p0();K0();p0();var kn0=K.enum(["new","planned","in-progress","done","declined"]),On0=K.enum(["low","medium","high","critical"]),Ko=K.object({title:K.string(),status:kn0,priority:On0.default("medium"),requested:K.number().int().default(1),declinedReason:K.string().optional()}),Ba1=K.object({title:K.string(),status:kn0,priority:On0,requested:K.number().int(),slug:K.string()}),Uo=o1.extend({entityType:K.literal("wish"),metadata:Ba1}),xn0=K.object({});p0();K0();class Go extends V2{constructor(){super({entityType:"wish",schema:Uo,frontmatterSchema:Ko})}createWishContent(A,Q){return this.buildMarkdown(Q,A)}parseWishContent(A){let Q=this.parseFrontMatter(A,Ko);return{frontmatter:Ko.parse(Q),description:this.extractBody(A).trim()}}fromMarkdown(A){let{frontmatter:Q}=this.parseWishContent(A),B=Y1(Q.title);return{content:A,entityType:"wish",metadata:{title:Q.title,status:Q.status,priority:Q.priority,requested:Q.requested,slug:B}}}}var Rn0=new Go;K0();K0();async function wa1(A,Q){let B=`${Q.title}: ${Q.description}`,$=(await A.search({query:B,options:{types:["wish"],limit:1}}))[0];if($&&$.score>=A.similarityThreshold)return $.entity;let D=Y1(Q.title);return A.getEntity({entityType:"wish",id:D})}class Hf0{logger;context;adapter=new Go;constructor(A,Q){this.logger=A;this.context=Q}async process(A,Q,B){let w=A.title??A.prompt??"Untitled wish",$=A.content??A.prompt??"",D=await wa1({search:(H)=>this.context.entityService.search(H),getEntity:(H)=>this.context.entityService.getEntity(H),similarityThreshold:0.85},{title:w,description:$});if(D){let{frontmatter:H,description:W}=this.adapter.parseWishContent(D.content),Z=H.requested+1,G=this.adapter.createWishContent({...H,requested:Z},W);return await this.context.entityService.updateEntity({entity:{...D,content:G,metadata:{...D.metadata,requested:Z}}}),this.logger.info("Incremented wish request count",{id:D.id,requested:Z}),{success:!0,entityId:D.id,existed:!0,requested:Z}}let f=Y1(w),Y=A.options?.priority??"medium",X=this.adapter.createWishContent({title:w,status:"new",priority:Y,requested:1},$);return await this.context.entityService.createEntity({entity:{id:f,entityType:"wish",content:X,metadata:{title:w,status:"new",priority:Y,requested:1,slug:f}}}),this.logger.info("Created new wish",{id:f,title:w}),{success:!0,entityId:f,existed:!1,requested:1}}}var $a1={critical:0,high:1,medium:2,low:3};function Da1(A){A.sort((Q,B)=>{let w=B.metadata.requested-Q.metadata.requested;if(w!==0)return w;return $a1[Q.metadata.priority]-$a1[B.metadata.priority]})}var fa1={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.128",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 Ya1 extends PQ{entityType=Rn0.entityType;schema=Uo;adapter=Rn0;constructor(A={}){super("wishlist",fa1,A,xn0)}async interceptCreate(A,Q,B){let w=await new Hf0(this.logger,B).process({...A.title?{title:A.title}:{},...A.prompt?{prompt:A.prompt}:{},...A.content?{content:A.content}:{}},`wish-create-${Date.now()}`,{});if(!w.success)return{kind:"handled",result:{success:!1,error:w.error??"Failed to create wish"}};return{kind:"handled",result:{success:!0,data:{...w.entityId?{entityId:w.entityId}:{},status:w.existed?"updated":"created"}}}}async onRegister(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"dashboard:register-widget",payload:{id:"top-wishes",pluginId:this.id,title:"Top Wishes",section:"secondary",priority:30,rendererName:"ListWidget",dataProvider:async()=>{let B=await A.entityService.listEntities({entityType:"wish",options:{limit:10}});return Da1(B),{items:B.map((w)=>({id:w.id,name:w.metadata.title,count:w.metadata.requested,priority:w.metadata.priority,status:w.metadata.status}))}}}}),{success:!0}});let Q=new Hf0(this.logger,A);A.jobs.registerHandler("wish:create",{process:Q.process.bind(Q),validateAndParse:(B)=>B})}async getInstructions(){return"**CRITICAL \u2014 Wishlist exclusions**: A2A agent-contact requests are never wishlist cases. "+'If a request asks you to ask, message, contact, call, or reach out to an agent, and the target is missing, ambiguous, archived, URL-only, unsaved-domain, or not-yet-saved in the local agent directory, do not call any create tool for a wish. Tell the user to add/save or clarify the agent first. This includes requests that contain a full agent URL, a bare domain like unknown-agent.io, or phrasing like "message this agent URL for me". Only create or save an agent entry if the user explicitly asks you to add or save that agent. '+"**CRITICAL \u2014 Unfulfilled requests**: For other unfulfillable requests, ALWAYS call `system_create` with entityType "+`"wish" BEFORE responding when you cannot fulfill a user's request. This applies to physical actions, non-agent missing integrations, and any non-agent capability `+"you lack. Physical-world requests like making food, driving somewhere, or doing chores are always wishlist cases. Do NOT just explain you can't do it \u2014 create the wish first, THEN respond. "+"Never claim the request was added to the wishlist unless you actually called system_create for the wish. In your response, tell the user their request has been added to the wishlist."}}function NKB(A={}){return new Ya1(A)}var Wf0=NKB;p0();K0();p0();var zo=K.object({title:K.string(),target:K.string()}),Xa1=K.object({title:K.string(),target:K.string(),slug:K.string().optional()}),qo=o1.extend({entityType:K.literal("prompt"),metadata:Xa1});p0();K0();class vn0 extends V2{constructor(){super({entityType:"prompt",schema:qo,frontmatterSchema:zo})}toMarkdown(A){let Q=this.extractBody(A.content),B=this.parseFrontMatter(A.content,zo);return this.buildMarkdown(Q,B)}fromMarkdown(A){let Q=this.parseFrontMatter(A,zo),B=Y1(Q.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:Q.title,target:Q.target,slug:B}}}}var Zf0=new vn0;var Ha1={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.128",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 hn0 extends PQ{entityType=Zf0.entityType;schema=qo;adapter=Zf0;constructor(){super("prompt",Ha1,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function kP(){return new hn0}p0();K0();class Kf0{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(A,Q){this.apiKey=A,this.fetchFn=Q}async searchPhotos(A,Q){let B=new URL(`${this.baseUrl}/search/photos`);B.searchParams.set("query",A),B.searchParams.set("page",String(Q.page)),B.searchParams.set("per_page",String(Q.perPage));let w=await this.fetchFn(B.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!w.ok)throw Error(`Unsplash API error: ${w.status} ${w.statusText}`);let $=await w.json();return{photos:$.results.map(_KB),total:$.total,totalPages:$.total_pages,page:Q.page}}async triggerDownload(A){try{await this.fetchFn(A,{headers:{Authorization:`Client-ID ${this.apiKey}`}})}catch{}}}function _KB(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}}K0();var Wa1={query:K.string().describe("Search terms for stock photos"),perPage:K.number().min(1).max(30).default(10).describe("Results per page (1-30)"),page:K.number().min(1).default(1).describe("Page number")},Za1={photoId:K.string().describe("Photo ID from search results"),downloadLocation:K.string().url().describe("Download tracking URL (required by provider ToS)"),photographerName:K.string().describe("Photographer name for attribution"),photographerUrl:K.string().url().describe("Photographer profile URL for attribution"),sourceUrl:K.string().url().describe("Photo page URL on provider"),imageUrl:K.string().url().describe("Image URL to download"),title:K.string().optional().describe("Image entity title"),alt:K.string().optional().describe("Alt text for the image"),targetEntityType:K.string().optional().describe("Entity type to set cover image on"),targetEntityId:K.string().optional().describe("Entity ID to set cover image on")};function Ka1(A,Q){return[MKB(A,Q),PKB(A,Q)]}function MKB(A,Q){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:Wa1,handler:async(B)=>{let w=K.object(Wa1).safeParse(B);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};try{return{success:!0,data:await Q.provider.searchPhotos(w.data.query,{page:w.data.page,perPage:w.data.perPage})}}catch($){return{success:!1,error:$ instanceof Error?$.message:"Search failed"}}}}}function PKB(A,Q){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:Za1,handler:async(B)=>{let w=K.object(Za1).safeParse(B);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};let{photoId:$,downloadLocation:D,photographerName:f,photographerUrl:Y,sourceUrl:X,imageUrl:H,title:W,alt:Z,targetEntityType:G,targetEntityId:F}=w.data,I={photographerName:f,photographerUrl:Y,sourceUrl:X},L=await Q.entityService.listEntities({entityType:"image",options:{limit:1,filter:{metadata:{sourceUrl:H}}}});if(L[0]){let M={imageEntityId:L[0].id,alreadyExisted:!0,attribution:I};if(G&&F)await kKB(Q.entityService,G,F,L[0].id),M.coverSet=!0;return{success:!0,data:M}}let b=await Q.jobs.enqueue({type:"select-photo",data:{photoId:$,downloadLocation:D,photographerName:f,photographerUrl:Y,sourceUrl:X,imageUrl:H,...W!==void 0?{title:W}:{},...Z!==void 0?{alt:Z}:{},...G!==void 0?{targetEntityType:G}:{},...F!==void 0?{targetEntityId:F}:{}}}),N={imageEntityId:$,alreadyExisted:!1,attribution:I,jobId:b,status:"generating"};if(G&&F)N.coverSet=!0;return{success:!0,data:N}}}}async function kKB(A,Q,B,w){let $=await A.getEntity({entityType:Q,id:B});if(!$)return;await A.updateEntity({entity:{...$,metadata:{...$.metadata,coverImageId:w}}})}p0();K0();D4();var OKB=K.object({photoId:K.string(),downloadLocation:K.string().url(),photographerName:K.string(),photographerUrl:K.string().url(),sourceUrl:K.string().url(),imageUrl:K.string().url(),title:K.string().optional(),alt:K.string().optional(),targetEntityType:K.string().optional(),targetEntityId:K.string().optional()});class Cn0 extends PB{deps;constructor(A,Q){super(A,{schema:OKB,jobTypeName:"select-photo"});this.deps=Q}async process(A,Q,B){await this.reportProgress(B,{progress:10,message:"Tracking stock photo download"}),await this.deps.provider.triggerDownload(A.downloadLocation),await this.reportProgress(B,{progress:35,message:"Downloading stock photo"});let w=await this.deps.fetchImage(A.imageUrl),$=A.title??`Stock photo ${A.photoId}`,D=CY.createImageEntity({dataUrl:w,title:$,alt:A.alt??$});await this.reportProgress(B,{progress:75,message:"Saving stock photo"});let{entityId:f}=await this.deps.entityService.createEntity({entity:{id:A.photoId,...D,metadata:{...D.metadata,sourceUrl:A.imageUrl}}}),Y={imageEntityId:f,alreadyExisted:!1};if(A.targetEntityType&&A.targetEntityId)await xKB(this.deps.entityService,A.targetEntityType,A.targetEntityId,f),Y.coverSet=!0;return await this.reportProgress(B,{progress:100,message:"Stock photo selected"}),Y}summarizeDataForLog(A){return{photoId:A.photoId,hasTarget:A.targetEntityType!==void 0}}}async function xKB(A,Q,B,w){let $=await A.getEntity({entityType:Q,id:B});if(!$)return;await A.updateEntity({entity:{...$,metadata:{...$.metadata,coverImageId:w}}})}D4();var Ua1={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.128",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 vKB=K.object({provider:K.enum(["unsplash"]).default("unsplash"),apiKey:K.string().optional().describe("Stock photo provider API key")});class yn0 extends pQ{deps;cachedTools=null;constructor(A={},Q={}){super("stock-photo",Ua1,A,vKB);this.deps=Q}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),Q=this.createProvider();return this.cachedTools=Ka1(this.id,{provider:Q,entityService:A.entityService,fetchImage:this.deps.fetchImage??NH,jobs:A.jobs}),this.cachedTools}async registerJobHandlers(){if(!this.config.apiKey)return;let A=this.getContext();A.jobs.registerHandler("select-photo",new Cn0(this.logger.child("SelectPhotoJobHandler"),{provider:this.createProvider(),entityService:A.entityService,fetchImage:this.deps.fetchImage??NH}))}createProvider(){return new Kf0(this.config.apiKey??"",this.deps.fetch??globalThis.fetch)}}function En0(A={},Q={}){return new yn0(A,Q)}p0();K0();p0();p0();K0();var Ga1=K.enum(["ai","foundation","work"]),za1=K.object({suffix:Ga1,title:K.string(),body:K.string(),linkLabel:K.string(),linkHref:K.string()}),Fo=K.object({eyebrow:K.string(),headline:K.string(),cards:K.array(za1).min(1)}),Uf0=K.object({title:K.string(),slug:K.string(),status:K.enum(["draft","published"])}),Io=o1.extend({entityType:K.literal("ecosystem-section"),metadata:Uf0});class qa1 extends V2{constructor(){super({entityType:"ecosystem-section",schema:Io,frontmatterSchema:Uf0})}fromMarkdown(A){return{content:A,entityType:"ecosystem-section",metadata:this.parseFrontmatter(A)}}}var gn0=new qa1;K0();function hKB(A){return A.replace(/^---\n[\s\S]*?\n---\n?/,"")}function Tn0(A,Q){return new RegExp(`(?:^|\\n)## ${Q}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`).exec(A)?.[1]?.trim()??""}function Vo(A,Q){return new RegExp(`(?:^|\\n)#### ${Q}\\s*\\n([\\s\\S]*?)(?=\\n#### |\\n### |$)`).exec(A)?.[1]?.trim()??""}function Gf0(A){let Q=hKB(A),w=Tn0(Q,"Cards").split(/^### Card \d+\s*$/m).map(($)=>$.trim()).filter(Boolean);return Fo.parse({eyebrow:Tn0(Q,"Eyebrow"),headline:Tn0(Q,"Headline"),cards:w.map(($)=>({suffix:Vo($,"Suffix"),title:Vo($,"Title"),body:Vo($,"Body"),linkLabel:Vo($,"Link Label"),linkHref:Vo($,"Link Href")}))})}function Fa1(A){return["# Ecosystem Section","","## Eyebrow",A.eyebrow,"","## Headline",A.headline,"","## Cards","",...A.cards.flatMap((Q,B)=>[`### Card ${B+1}`,"","#### Suffix",Q.suffix,"","#### Title",Q.title,"","#### Body",Q.body,"","#### Link Label",Q.linkLabel,"","#### Link Href",Q.linkHref,""])].join(`
|
|
8494
|
+
`)}function Aa1(A){try{return Qa1(JSON.stringify(A),1200)}catch{return"[unserializable]"}}function Qa1(A,Q){return A.length>Q?`${A.slice(0,Q)}\u2026`:A}var LKB={async evaluate(){return{met:!1,reason:"No playbook goal check is configured."}}};function Pn0(A={},Q={}){return new Mn0(A,Q)}p0();K0();p0();var kn0=K.enum(["new","planned","in-progress","done","declined"]),On0=K.enum(["low","medium","high","critical"]),Ko=K.object({title:K.string(),status:kn0,priority:On0.default("medium"),requested:K.number().int().default(1),declinedReason:K.string().optional()}),Ba1=K.object({title:K.string(),status:kn0,priority:On0,requested:K.number().int(),slug:K.string()}),Uo=o1.extend({entityType:K.literal("wish"),metadata:Ba1}),xn0=K.object({});p0();K0();class Go extends V2{constructor(){super({entityType:"wish",schema:Uo,frontmatterSchema:Ko})}createWishContent(A,Q){return this.buildMarkdown(Q,A)}parseWishContent(A){let Q=this.parseFrontMatter(A,Ko);return{frontmatter:Ko.parse(Q),description:this.extractBody(A).trim()}}fromMarkdown(A){let{frontmatter:Q}=this.parseWishContent(A),B=Y1(Q.title);return{content:A,entityType:"wish",metadata:{title:Q.title,status:Q.status,priority:Q.priority,requested:Q.requested,slug:B}}}}var Rn0=new Go;K0();K0();async function wa1(A,Q){let B=`${Q.title}: ${Q.description}`,$=(await A.search({query:B,options:{types:["wish"],limit:1}}))[0];if($&&$.score>=A.similarityThreshold)return $.entity;let D=Y1(Q.title);return A.getEntity({entityType:"wish",id:D})}class Hf0{logger;context;adapter=new Go;constructor(A,Q){this.logger=A;this.context=Q}async process(A,Q,B){let w=A.title??A.prompt??"Untitled wish",$=A.content??A.prompt??"",D=await wa1({search:(H)=>this.context.entityService.search(H),getEntity:(H)=>this.context.entityService.getEntity(H),similarityThreshold:0.85},{title:w,description:$});if(D){let{frontmatter:H,description:W}=this.adapter.parseWishContent(D.content),Z=H.requested+1,G=this.adapter.createWishContent({...H,requested:Z},W);return await this.context.entityService.updateEntity({entity:{...D,content:G,metadata:{...D.metadata,requested:Z}}}),this.logger.info("Incremented wish request count",{id:D.id,requested:Z}),{success:!0,entityId:D.id,existed:!0,requested:Z}}let f=Y1(w),Y=A.options?.priority??"medium",X=this.adapter.createWishContent({title:w,status:"new",priority:Y,requested:1},$);return await this.context.entityService.createEntity({entity:{id:f,entityType:"wish",content:X,metadata:{title:w,status:"new",priority:Y,requested:1,slug:f}}}),this.logger.info("Created new wish",{id:f,title:w}),{success:!0,entityId:f,existed:!1,requested:1}}}var $a1={critical:0,high:1,medium:2,low:3};function Da1(A){A.sort((Q,B)=>{let w=B.metadata.requested-Q.metadata.requested;if(w!==0)return w;return $a1[Q.metadata.priority]-$a1[B.metadata.priority]})}var fa1={name:"@brains/wishlist",private:!0,version:"0.2.0-alpha.129",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 Ya1 extends PQ{entityType=Rn0.entityType;schema=Uo;adapter=Rn0;constructor(A={}){super("wishlist",fa1,A,xn0)}async interceptCreate(A,Q,B){let w=await new Hf0(this.logger,B).process({...A.title?{title:A.title}:{},...A.prompt?{prompt:A.prompt}:{},...A.content?{content:A.content}:{}},`wish-create-${Date.now()}`,{});if(!w.success)return{kind:"handled",result:{success:!1,error:w.error??"Failed to create wish"}};return{kind:"handled",result:{success:!0,data:{...w.entityId?{entityId:w.entityId}:{},status:w.existed?"updated":"created"}}}}async onRegister(A){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"dashboard:register-widget",payload:{id:"top-wishes",pluginId:this.id,title:"Top Wishes",section:"secondary",priority:30,rendererName:"ListWidget",dataProvider:async()=>{let B=await A.entityService.listEntities({entityType:"wish",options:{limit:10}});return Da1(B),{items:B.map((w)=>({id:w.id,name:w.metadata.title,count:w.metadata.requested,priority:w.metadata.priority,status:w.metadata.status}))}}}}),{success:!0}});let Q=new Hf0(this.logger,A);A.jobs.registerHandler("wish:create",{process:Q.process.bind(Q),validateAndParse:(B)=>B})}async getInstructions(){return"**CRITICAL \u2014 Wishlist exclusions**: A2A agent-contact requests are never wishlist cases. "+'If a request asks you to ask, message, contact, call, or reach out to an agent, and the target is missing, ambiguous, archived, URL-only, unsaved-domain, or not-yet-saved in the local agent directory, do not call any create tool for a wish. Tell the user to add/save or clarify the agent first. This includes requests that contain a full agent URL, a bare domain like unknown-agent.io, or phrasing like "message this agent URL for me". Only create or save an agent entry if the user explicitly asks you to add or save that agent. '+"**CRITICAL \u2014 Unfulfilled requests**: For other unfulfillable requests, ALWAYS call `system_create` with entityType "+`"wish" BEFORE responding when you cannot fulfill a user's request. This applies to physical actions, non-agent missing integrations, and any non-agent capability `+"you lack. Physical-world requests like making food, driving somewhere, or doing chores are always wishlist cases. Do NOT just explain you can't do it \u2014 create the wish first, THEN respond. "+"Never claim the request was added to the wishlist unless you actually called system_create for the wish. In your response, tell the user their request has been added to the wishlist."}}function NKB(A={}){return new Ya1(A)}var Wf0=NKB;p0();K0();p0();var zo=K.object({title:K.string(),target:K.string()}),Xa1=K.object({title:K.string(),target:K.string(),slug:K.string().optional()}),qo=o1.extend({entityType:K.literal("prompt"),metadata:Xa1});p0();K0();class vn0 extends V2{constructor(){super({entityType:"prompt",schema:qo,frontmatterSchema:zo})}toMarkdown(A){let Q=this.extractBody(A.content),B=this.parseFrontMatter(A.content,zo);return this.buildMarkdown(Q,B)}fromMarkdown(A){let Q=this.parseFrontMatter(A,zo),B=Y1(Q.target.replace(/:/g,"-"));return{content:A,entityType:"prompt",metadata:{title:Q.title,target:Q.target,slug:B}}}}var Zf0=new vn0;var Ha1={name:"@brains/prompt",private:!0,version:"0.2.0-alpha.129",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 hn0 extends PQ{entityType=Zf0.entityType;schema=qo;adapter=Zf0;constructor(){super("prompt",Ha1,{},void 0)}getEntityTypeConfig(){return{embeddable:!1}}}function kP(){return new hn0}p0();K0();class Kf0{apiKey;fetchFn;baseUrl="https://api.unsplash.com";constructor(A,Q){this.apiKey=A,this.fetchFn=Q}async searchPhotos(A,Q){let B=new URL(`${this.baseUrl}/search/photos`);B.searchParams.set("query",A),B.searchParams.set("page",String(Q.page)),B.searchParams.set("per_page",String(Q.perPage));let w=await this.fetchFn(B.toString(),{headers:{Authorization:`Client-ID ${this.apiKey}`}});if(!w.ok)throw Error(`Unsplash API error: ${w.status} ${w.statusText}`);let $=await w.json();return{photos:$.results.map(_KB),total:$.total,totalPages:$.total_pages,page:Q.page}}async triggerDownload(A){try{await this.fetchFn(A,{headers:{Authorization:`Client-ID ${this.apiKey}`}})}catch{}}}function _KB(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}}K0();var Wa1={query:K.string().describe("Search terms for stock photos"),perPage:K.number().min(1).max(30).default(10).describe("Results per page (1-30)"),page:K.number().min(1).default(1).describe("Page number")},Za1={photoId:K.string().describe("Photo ID from search results"),downloadLocation:K.string().url().describe("Download tracking URL (required by provider ToS)"),photographerName:K.string().describe("Photographer name for attribution"),photographerUrl:K.string().url().describe("Photographer profile URL for attribution"),sourceUrl:K.string().url().describe("Photo page URL on provider"),imageUrl:K.string().url().describe("Image URL to download"),title:K.string().optional().describe("Image entity title"),alt:K.string().optional().describe("Alt text for the image"),targetEntityType:K.string().optional().describe("Entity type to set cover image on"),targetEntityId:K.string().optional().describe("Entity ID to set cover image on")};function Ka1(A,Q){return[MKB(A,Q),PKB(A,Q)]}function MKB(A,Q){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:Wa1,handler:async(B)=>{let w=K.object(Wa1).safeParse(B);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};try{return{success:!0,data:await Q.provider.searchPhotos(w.data.query,{page:w.data.page,perPage:w.data.perPage})}}catch($){return{success:!1,error:$ instanceof Error?$.message:"Search failed"}}}}}function PKB(A,Q){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:Za1,handler:async(B)=>{let w=K.object(Za1).safeParse(B);if(!w.success)return{success:!1,error:`Invalid input: ${w.error.message}`};let{photoId:$,downloadLocation:D,photographerName:f,photographerUrl:Y,sourceUrl:X,imageUrl:H,title:W,alt:Z,targetEntityType:G,targetEntityId:F}=w.data,I={photographerName:f,photographerUrl:Y,sourceUrl:X},L=await Q.entityService.listEntities({entityType:"image",options:{limit:1,filter:{metadata:{sourceUrl:H}}}});if(L[0]){let M={imageEntityId:L[0].id,alreadyExisted:!0,attribution:I};if(G&&F)await kKB(Q.entityService,G,F,L[0].id),M.coverSet=!0;return{success:!0,data:M}}let b=await Q.jobs.enqueue({type:"select-photo",data:{photoId:$,downloadLocation:D,photographerName:f,photographerUrl:Y,sourceUrl:X,imageUrl:H,...W!==void 0?{title:W}:{},...Z!==void 0?{alt:Z}:{},...G!==void 0?{targetEntityType:G}:{},...F!==void 0?{targetEntityId:F}:{}}}),N={imageEntityId:$,alreadyExisted:!1,attribution:I,jobId:b,status:"generating"};if(G&&F)N.coverSet=!0;return{success:!0,data:N}}}}async function kKB(A,Q,B,w){let $=await A.getEntity({entityType:Q,id:B});if(!$)return;await A.updateEntity({entity:{...$,metadata:{...$.metadata,coverImageId:w}}})}p0();K0();D4();var OKB=K.object({photoId:K.string(),downloadLocation:K.string().url(),photographerName:K.string(),photographerUrl:K.string().url(),sourceUrl:K.string().url(),imageUrl:K.string().url(),title:K.string().optional(),alt:K.string().optional(),targetEntityType:K.string().optional(),targetEntityId:K.string().optional()});class Cn0 extends PB{deps;constructor(A,Q){super(A,{schema:OKB,jobTypeName:"select-photo"});this.deps=Q}async process(A,Q,B){await this.reportProgress(B,{progress:10,message:"Tracking stock photo download"}),await this.deps.provider.triggerDownload(A.downloadLocation),await this.reportProgress(B,{progress:35,message:"Downloading stock photo"});let w=await this.deps.fetchImage(A.imageUrl),$=A.title??`Stock photo ${A.photoId}`,D=CY.createImageEntity({dataUrl:w,title:$,alt:A.alt??$});await this.reportProgress(B,{progress:75,message:"Saving stock photo"});let{entityId:f}=await this.deps.entityService.createEntity({entity:{id:A.photoId,...D,metadata:{...D.metadata,sourceUrl:A.imageUrl}}}),Y={imageEntityId:f,alreadyExisted:!1};if(A.targetEntityType&&A.targetEntityId)await xKB(this.deps.entityService,A.targetEntityType,A.targetEntityId,f),Y.coverSet=!0;return await this.reportProgress(B,{progress:100,message:"Stock photo selected"}),Y}summarizeDataForLog(A){return{photoId:A.photoId,hasTarget:A.targetEntityType!==void 0}}}async function xKB(A,Q,B,w){let $=await A.getEntity({entityType:Q,id:B});if(!$)return;await A.updateEntity({entity:{...$,metadata:{...$.metadata,coverImageId:w}}})}D4();var Ua1={name:"@brains/stock-photo",private:!0,version:"0.2.0-alpha.129",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 vKB=K.object({provider:K.enum(["unsplash"]).default("unsplash"),apiKey:K.string().optional().describe("Stock photo provider API key")});class yn0 extends pQ{deps;cachedTools=null;constructor(A={},Q={}){super("stock-photo",Ua1,A,vKB);this.deps=Q}async getTools(){if(!this.config.apiKey)return[];if(this.cachedTools)return this.cachedTools;let A=this.getContext(),Q=this.createProvider();return this.cachedTools=Ka1(this.id,{provider:Q,entityService:A.entityService,fetchImage:this.deps.fetchImage??NH,jobs:A.jobs}),this.cachedTools}async registerJobHandlers(){if(!this.config.apiKey)return;let A=this.getContext();A.jobs.registerHandler("select-photo",new Cn0(this.logger.child("SelectPhotoJobHandler"),{provider:this.createProvider(),entityService:A.entityService,fetchImage:this.deps.fetchImage??NH}))}createProvider(){return new Kf0(this.config.apiKey??"",this.deps.fetch??globalThis.fetch)}}function En0(A={},Q={}){return new yn0(A,Q)}p0();K0();p0();p0();K0();var Ga1=K.enum(["ai","foundation","work"]),za1=K.object({suffix:Ga1,title:K.string(),body:K.string(),linkLabel:K.string(),linkHref:K.string()}),Fo=K.object({eyebrow:K.string(),headline:K.string(),cards:K.array(za1).min(1)}),Uf0=K.object({title:K.string(),slug:K.string(),status:K.enum(["draft","published"])}),Io=o1.extend({entityType:K.literal("ecosystem-section"),metadata:Uf0});class qa1 extends V2{constructor(){super({entityType:"ecosystem-section",schema:Io,frontmatterSchema:Uf0})}fromMarkdown(A){return{content:A,entityType:"ecosystem-section",metadata:this.parseFrontmatter(A)}}}var gn0=new qa1;K0();function hKB(A){return A.replace(/^---\n[\s\S]*?\n---\n?/,"")}function Tn0(A,Q){return new RegExp(`(?:^|\\n)## ${Q}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`).exec(A)?.[1]?.trim()??""}function Vo(A,Q){return new RegExp(`(?:^|\\n)#### ${Q}\\s*\\n([\\s\\S]*?)(?=\\n#### |\\n### |$)`).exec(A)?.[1]?.trim()??""}function Gf0(A){let Q=hKB(A),w=Tn0(Q,"Cards").split(/^### Card \d+\s*$/m).map(($)=>$.trim()).filter(Boolean);return Fo.parse({eyebrow:Tn0(Q,"Eyebrow"),headline:Tn0(Q,"Headline"),cards:w.map(($)=>({suffix:Vo($,"Suffix"),title:Vo($,"Title"),body:Vo($,"Body"),linkLabel:Vo($,"Link Label"),linkHref:Vo($,"Link Href")}))})}function Fa1(A){return["# Ecosystem Section","","## Eyebrow",A.eyebrow,"","## Headline",A.headline,"","## Cards","",...A.cards.flatMap((Q,B)=>[`### Card ${B+1}`,"","#### Suffix",Q.suffix,"","#### Title",Q.title,"","#### Body",Q.body,"","#### Link Label",Q.linkLabel,"","#### Link Href",Q.linkHref,""])].join(`
|
|
8495
8495
|
`)}var CKB=K.object({query:K.object({id:K.string().optional()}).optional()}).passthrough();class zf0{id="rizom-ecosystem:entities";name="Rizom Ecosystem";description="Fetches an ecosystem-section entity for rendering";async fetch(A,Q,B){let $=CKB.parse(A??{}).query?.id??"rizom-ecosystem",D=await B.entityService.getEntity({entityType:"ecosystem-section",id:$});if(!D)throw Error(`Ecosystem section not found: ${$}`);return Q.parse(Gf0(D.content))}}p0();var yKB=T$0({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 Qz(...A){return yKB(sC(A))}import{jsxDEV as Mw6}from"preact/jsx-dev-runtime";import{jsxDEV as xw6}from"preact/jsx-dev-runtime";import{jsxDEV as Cw6}from"preact/jsx-dev-runtime";import{jsxDEV as gKB}from"preact/jsx-dev-runtime";var Sn0="px-6 md:px-10 xl:px-20",EKB=`${Sn0} relative z-[1]`,mn0=({id:A,className:Q,children:B})=>gKB("section",{id:A,className:Qz(EKB,Q),children:B},void 0,!1,void 0,this);import{jsxDEV as qf0}from"preact/jsx-dev-runtime";var TKB=new Map([["work","text-accent"],["foundation","text-secondary"],["ai","text-accent-bright"]]),Jo=({name:A="rizom",brandSuffix:Q,className:B,dotClassName:w,suffixClassName:$})=>{let D=TKB.get(Q);return qf0("span",{className:Qz("inline-flex items-baseline gap-0 font-display font-medium tracking-[-0.015em] [font-variation-settings:'opsz'_24]",B),children:[qf0("span",{className:"text-theme",children:A},void 0,!1,void 0,this),qf0("span",{className:Qz(D??"text-accent",w),children:"."},void 0,!1,void 0,this),qf0("span",{className:Qz("italic font-normal text-theme-muted",$),children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as dw6}from"preact/jsx-dev-runtime";import{jsxDEV as sw6}from"preact/jsx-dev-runtime";import{jsxDEV as A86,Fragment as ew6}from"preact/jsx-dev-runtime";import{jsxDEV as w86}from"preact/jsx-dev-runtime";import{Fragment as un0}from"preact";import{jsxDEV as Lo}from"preact/jsx-dev-runtime";var SKB=/(\*[^*]+\*)/;function cn0(A,Q){let B=A.split(`
|
|
8496
|
-
`);return Lo(un0,{children:B.map((w,$)=>Lo(un0,{children:[$>0&&Lo("br",{},void 0,!1,void 0,this),w.split(SKB).map((D,f)=>{if(D.length>=3&&D.startsWith("*")&&D.endsWith("*"))return Lo("span",{className:Q,children:D.slice(1,-1)},f,!1,void 0,this);return Lo(un0,{children:D},f,!1,void 0,this)})]},$,!0,void 0,this))},void 0,!1,void 0,this)}import{jsxDEV as uf,Fragment as sKB}from"preact/jsx-dev-runtime";var mKB="italic text-accent font-normal",uKB="You are here",cKB={work:"text-accent",foundation:"text-secondary",ai:"text-accent-bright"},lKB={work:"border-t-accent/60",foundation:"border-t-secondary/60",ai:"border-t-accent-bright/60"},pKB={work:"hover:border-t-accent",foundation:"hover:border-t-secondary",ai:"hover:border-t-accent-bright"},iKB="font-label text-[10.5px] uppercase tracking-[0.26em] mt-1",dKB="font-body text-[15px] leading-[1.6] text-theme-muted mt-2",nKB="font-label text-[10.5px] uppercase tracking-[0.22em] text-theme-muted self-start mt-[18px] pb-1 border-b border-white/10 transition-colors hover:text-theme",rKB="font-label text-[10.5px] uppercase tracking-[0.22em] text-accent self-start mt-[18px] pb-1",oKB=({card:A})=>{let Q=A.linkLabel===uKB,B=A.linkHref.trim().length===0,w=uf(sKB,{children:[uf(Jo,{brandSuffix:A.suffix,className:"text-[clamp(28px,3vw,40px)] [font-variation-settings:'opsz'_96]"},void 0,!1,void 0,this),uf("span",{className:`${iKB} ${cKB[A.suffix]}`,children:A.title},void 0,!1,void 0,this),uf("p",{className:dKB,children:A.body},void 0,!1,void 0,this),Q?uf("span",{className:rKB,children:A.linkLabel},void 0,!1,void 0,this):uf("span",{className:nKB,children:A.linkLabel},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$=`flex flex-col gap-[14px] border-t pt-7 ${Q?lKB[A.suffix]:"border-white/10"}`;return Q||B?uf("div",{className:$,children:w},void 0,!1,void 0,this):uf("a",{href:A.linkHref,className:`${$} text-inherit no-underline transition-colors ${pKB[A.suffix]}`,children:w},void 0,!1,void 0,this)},ln0=({eyebrow:A,headline:Q,cards:B})=>uf(mn0,{id:"ecosystem",className:"pt-[112px] pb-[144px] border-t border-white/5",children:[uf("div",{className:"mx-auto mb-[88px] max-w-[1180px] text-center",children:[uf("span",{className:"font-label text-[11px] font-semibold uppercase tracking-[0.24em] text-accent",children:A},void 0,!1,void 0,this),uf("h2",{className:"mt-5 font-display text-[clamp(34px,4.4vw,60px)] font-[380] leading-[1.04] tracking-[-0.02em] text-heading [font-variation-settings:'opsz'_96]",children:cn0(Q,mKB)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),uf("div",{className:"mx-auto grid max-w-[1180px] grid-cols-3 gap-16 max-[768px]:grid-cols-1 max-[768px]:gap-7",children:B.map((w)=>uf(oKB,{card:w},w.suffix,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this);var aKB=[{suffix:"work",title:"The service",body:"Workshops and consulting that apply the methodology in live engagements.",linkLabel:"Visit rizom.work \u2192",linkHref:"https://rizom.work"},{suffix:"foundation",title:"The source",body:"The non-profit that holds the IP and stewards the methodology independently.",linkLabel:"Read the manifesto \u2192",linkHref:"https://rizom.foundation"},{suffix:"ai",title:"The tools",body:"Open-source AI agents built on the methodology, the technical layer underneath.",linkLabel:"See the platform \u2192",linkHref:"https://rizom.ai"}];function Ia1(A){return{eyebrow:"The Ecosystem",headline:"One practice. *Three faces.*",cards:aKB.map((Q)=>Q.suffix===A?{...Q,linkLabel:"You are here",linkHref:""}:Q)}}var tKB=Ia1();var pn0=R1({name:"ecosystem",description:"Rizom ecosystem sibling-site section",schema:Fo,formatter:{parse:Gf0,format:Fa1},dataSourceId:"rizom-ecosystem:entities",requiredPermission:"public",layout:{component:ln0}});var Va1={name:"@brains/rizom-ecosystem",private:!0,version:"0.2.0-alpha.
|
|
8496
|
+
`);return Lo(un0,{children:B.map((w,$)=>Lo(un0,{children:[$>0&&Lo("br",{},void 0,!1,void 0,this),w.split(SKB).map((D,f)=>{if(D.length>=3&&D.startsWith("*")&&D.endsWith("*"))return Lo("span",{className:Q,children:D.slice(1,-1)},f,!1,void 0,this);return Lo(un0,{children:D},f,!1,void 0,this)})]},$,!0,void 0,this))},void 0,!1,void 0,this)}import{jsxDEV as uf,Fragment as sKB}from"preact/jsx-dev-runtime";var mKB="italic text-accent font-normal",uKB="You are here",cKB={work:"text-accent",foundation:"text-secondary",ai:"text-accent-bright"},lKB={work:"border-t-accent/60",foundation:"border-t-secondary/60",ai:"border-t-accent-bright/60"},pKB={work:"hover:border-t-accent",foundation:"hover:border-t-secondary",ai:"hover:border-t-accent-bright"},iKB="font-label text-[10.5px] uppercase tracking-[0.26em] mt-1",dKB="font-body text-[15px] leading-[1.6] text-theme-muted mt-2",nKB="font-label text-[10.5px] uppercase tracking-[0.22em] text-theme-muted self-start mt-[18px] pb-1 border-b border-white/10 transition-colors hover:text-theme",rKB="font-label text-[10.5px] uppercase tracking-[0.22em] text-accent self-start mt-[18px] pb-1",oKB=({card:A})=>{let Q=A.linkLabel===uKB,B=A.linkHref.trim().length===0,w=uf(sKB,{children:[uf(Jo,{brandSuffix:A.suffix,className:"text-[clamp(28px,3vw,40px)] [font-variation-settings:'opsz'_96]"},void 0,!1,void 0,this),uf("span",{className:`${iKB} ${cKB[A.suffix]}`,children:A.title},void 0,!1,void 0,this),uf("p",{className:dKB,children:A.body},void 0,!1,void 0,this),Q?uf("span",{className:rKB,children:A.linkLabel},void 0,!1,void 0,this):uf("span",{className:nKB,children:A.linkLabel},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$=`flex flex-col gap-[14px] border-t pt-7 ${Q?lKB[A.suffix]:"border-white/10"}`;return Q||B?uf("div",{className:$,children:w},void 0,!1,void 0,this):uf("a",{href:A.linkHref,className:`${$} text-inherit no-underline transition-colors ${pKB[A.suffix]}`,children:w},void 0,!1,void 0,this)},ln0=({eyebrow:A,headline:Q,cards:B})=>uf(mn0,{id:"ecosystem",className:"pt-[112px] pb-[144px] border-t border-white/5",children:[uf("div",{className:"mx-auto mb-[88px] max-w-[1180px] text-center",children:[uf("span",{className:"font-label text-[11px] font-semibold uppercase tracking-[0.24em] text-accent",children:A},void 0,!1,void 0,this),uf("h2",{className:"mt-5 font-display text-[clamp(34px,4.4vw,60px)] font-[380] leading-[1.04] tracking-[-0.02em] text-heading [font-variation-settings:'opsz'_96]",children:cn0(Q,mKB)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),uf("div",{className:"mx-auto grid max-w-[1180px] grid-cols-3 gap-16 max-[768px]:grid-cols-1 max-[768px]:gap-7",children:B.map((w)=>uf(oKB,{card:w},w.suffix,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this);var aKB=[{suffix:"work",title:"The service",body:"Workshops and consulting that apply the methodology in live engagements.",linkLabel:"Visit rizom.work \u2192",linkHref:"https://rizom.work"},{suffix:"foundation",title:"The source",body:"The non-profit that holds the IP and stewards the methodology independently.",linkLabel:"Read the manifesto \u2192",linkHref:"https://rizom.foundation"},{suffix:"ai",title:"The tools",body:"Open-source AI agents built on the methodology, the technical layer underneath.",linkLabel:"See the platform \u2192",linkHref:"https://rizom.ai"}];function Ia1(A){return{eyebrow:"The Ecosystem",headline:"One practice. *Three faces.*",cards:aKB.map((Q)=>Q.suffix===A?{...Q,linkLabel:"You are here",linkHref:""}:Q)}}var tKB=Ia1();var pn0=R1({name:"ecosystem",description:"Rizom ecosystem sibling-site section",schema:Fo,formatter:{parse:Gf0,format:Fa1},dataSourceId:"rizom-ecosystem:entities",requiredPermission:"public",layout:{component:ln0}});var Va1={name:"@brains/rizom-ecosystem",private:!0,version:"0.2.0-alpha.129",description:"Entity-backed Rizom ecosystem section",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/plugins":"workspace:*","@brains/utils":"workspace:*","@rizom/ui":"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 in0 extends PQ{entityType="ecosystem-section";schema=Io;adapter=gn0;constructor(A={}){super("rizom-ecosystem",Va1,A,K.object({}).default({}))}getTemplates(){return{ecosystem:pn0}}getDataSources(){return[new zf0]}}function OP(A={}){return new in0(A)}K0();p0();p0();K0();p$();K0();p0();var R7="agent",Ja1="agent-discovery",La1="agent:generation",ba1="agent-network",Na1="AgentNetworkWidget",bo="agent-discovery:entities",dn0="agent-list",nn0="agent-detail",z5="skill",ja1="skill",Ff0="skill-derivation",_a1="skill:project",Ma1="skill-derivation",Pa1="skill:skill-derivation",ka1="skills";var _E=K.object({name:K.string(),description:K.string(),tags:K.array(K.string())}),HW=K.enum(["discovered","approved"]).describe("Discovered for review or approved for calling"),jK=AZ.pick({name:!0,kind:!0,organization:!0}).extend({brainName:K.string().describe("Name of the brain instance"),url:K.string().url().describe("Brain endpoint URL"),did:K.string().optional().describe("Decentralized identifier (public)"),repoDid:K.string().optional().describe("ATProto repo DID"),brainDid:K.string().optional().describe("ATProto brain DID"),anchorDid:K.string().optional().describe("ATProto anchor DID"),cardUri:K.string().optional().describe("ATProto brain card URI"),cardCid:K.string().optional().describe("ATProto brain card CID"),a2aEndpoint:K.string().url().optional().describe("A2A endpoint URL"),status:HW,discoveredAt:K.string().datetime().describe("When this agent was first discovered")}),Oa1=jK.pick({name:!0,url:!0,status:!0}).extend({discoveredAt:K.string().datetime().optional(),slug:K.string(),repoDid:K.string().optional(),brainDid:K.string().optional(),anchorDid:K.string().optional(),cardUri:K.string().optional(),cardCid:K.string().optional(),a2aEndpoint:K.string().url().optional()}),ME=o1.extend({entityType:K.literal(R7),metadata:Oa1}),No=ME.extend({frontmatter:jK,about:K.string(),skills:K.array(_E),notes:K.string()}),PE=No.extend({url:K.string().optional(),typeLabel:K.string().optional()}),AUB=No.extend({url:K.string(),typeLabel:K.string()});K0();var QUB=K.array(_E);function xa1(A){let Q=QUB.safeParse(A);if(!Q.success||Q.data.length===0)return"";return Q.data.map((B)=>{let w=B.tags.length>0?` [${B.tags.join(", ")}]`:"";return`- ${B.name}: ${B.description}${w}`}).join(`
|
|
8497
8497
|
`)}function Ra1(A){if(!A.trim())return[];let Q=[];for(let B of A.split(`
|
|
8498
8498
|
`)){let w=B.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/);if(!w)continue;let $=w[1]??"",D=w[2]??"",f=w[3],Y=f?f.split(",").map((X)=>X.trim()).filter(Boolean):[];Q.push({name:$,description:D,tags:Y})}return Q}var BUB=K.object({about:K.string(),skills:K.array(_E),notes:K.string()}),va1=new pB(BUB,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:xa1,parser:Ra1},{key:"notes",label:"Notes",type:"string"}]});class cf extends V2{constructor(){super({entityType:R7,schema:ME,frontmatterSchema:jK})}fromMarkdown(A){let Q=this.parseFrontMatter(A,jK),B=NI(Q.url);return{content:A,entityType:R7,metadata:{name:Q.name,url:Q.url,status:Q.status,discoveredAt:Q.discoveredAt,slug:B,...Q.repoDid&&{repoDid:Q.repoDid},...Q.brainDid&&{brainDid:Q.brainDid},...Q.anchorDid&&{anchorDid:Q.anchorDid},...Q.cardUri&&{cardUri:Q.cardUri},...Q.cardCid&&{cardCid:Q.cardCid},...Q.a2aEndpoint&&{a2aEndpoint:Q.a2aEndpoint}}}}createAgentContent(A){let Q={name:A.name,kind:A.kind,...A.organization&&{organization:A.organization},brainName:A.brainName,url:A.url,...A.did&&{did:A.did},...A.repoDid&&{repoDid:A.repoDid},...A.brainDid&&{brainDid:A.brainDid},...A.anchorDid&&{anchorDid:A.anchorDid},...A.cardUri&&{cardUri:A.cardUri},...A.cardCid&&{cardCid:A.cardCid},...A.a2aEndpoint&&{a2aEndpoint:A.a2aEndpoint},status:HW.parse(A.status),discoveredAt:A.discoveredAt},B=va1.format({about:A.about,skills:A.skills,notes:A.notes});return this.buildMarkdown(B,Q)}parseAgentContent(A){let Q=this.extractBody(A);if(!Q.trim())return{about:"",skills:[],notes:""};try{let B=va1.parse(Q);return{about:B.about,skills:B.skills,notes:B.notes}}catch{return{about:"",skills:[],notes:""}}}parseEntity(A){return{frontmatter:this.parseFrontMatter(A.content,jK),body:this.parseAgentContent(A.content)}}}p0();var wUB=new cf,$UB=qU.extend({status:HW.optional()}),DUB=FU.extend({query:$UB.optional()});function fUB(A){let Q=h2(A.content,jK),B=wUB.parseAgentContent(A.content);return No.parse({...A,frontmatter:Q.metadata,about:B.about,skills:B.skills,notes:B.notes})}class If0 extends W${id=bo;name="Agent Directory DataSource";description="Fetches and transforms agent entities for rendering";config={entityType:R7,defaultSort:[{field:"discoveredAt",direction:"desc"}],defaultLimit:50,lookupField:"slug",enableNavigation:!0};constructor(A){super(A)}transformEntity(A){return fUB(A)}buildDetailResult(A,Q){return{agent:A,prevAgent:Q?.prev??null,nextAgent:Q?.next??null}}parseQuery(A){let Q=DUB.parse(A);return{entityType:Q.entityType??this.config.entityType,query:Q.query??{}}}buildListResult(A,Q,B){let w=HW.safeParse(B.status);return{agents:A,pagination:Q,baseUrl:B.baseUrl,selectedStatus:w.success?w.data:"all"}}async fetch(A,Q,B){let{query:w}=this.parseQuery(A);if(w.id)return super.fetch(A,Q,B);let{items:$,pagination:D}=await this.fetchList(w,B.entityService,w.status?{filter:{metadata:{status:w.status}}}:void 0);return Q.parse(this.buildListResult($,D,w))}}p0();K0();Cw();p0();async function ha1(A,Q){let w=`${(A.startsWith("http")?A:`https://${A}`).replace(/\/$/,"")}/.well-known/agent-card.json`;try{let $=await Q(w);if(!$.ok)return null;let D=await $.json();return RS(D)}catch{return null}}function Vf0(A){let Q=A.trim();if(Q.startsWith("http://")||Q.startsWith("https://"))try{return new URL(Q).hostname}catch{return Q}let B=Q.match(/https?:\/\/[^\s]+?(?=[.,;:!?)]*(?:\s|$))/);if(B)try{return new URL(B[0]).hostname}catch{return B[0]}if(/^[^\s]+\.[^\s]+$/.test(Q))return Q;return""}K0();var YUB=new cf;function Ca1(A){return A.trim().toLowerCase().replace(/[_\s]+/g,"-")}function yL(A){let Q=new Set,B=[];for(let w of A){let $=Ca1(w);if(!$||Q.has($))continue;Q.add($),B.push($)}return B}function XUB(A,Q){if(Q.count!==A.count)return Q.count-A.count;return A.tag.localeCompare(Q.tag)}async function ya1(A,Q={}){let B=Q.minCount??1,w=Q.topN??12,$=Q.visibilityScope??"public",D=new Map,[f,Y]=await Promise.all([A.entityService.listEntities({entityType:z5,options:{filter:{visibilityScope:$}}}),A.entityService.listEntities({entityType:R7,options:{filter:{visibilityScope:$}}})]),X=(H)=>{for(let W of yL(H))D.set(W,(D.get(W)??0)+1)};for(let H of f)X(H.metadata.tags);for(let H of Y){let W=YUB.parseAgentContent(H.content);X(W.skills.flatMap((Z)=>Z.tags))}return Array.from(D.entries()).map(([H,W])=>({tag:H,count:W})).filter((H)=>H.count>=B).sort(XUB).slice(0,w)}function Ea1(A){if(A.length===0)return"";return["Current agent-directory tag vocabulary (reuse existing tags where they fit; propose new only when nothing does):",...A.map(({tag:Q,count:B})=>`- ${Q} (${B})`)].join(`
|
|
8499
8499
|
`)}var HUB=new cf;function ga1(A,Q={}){let B=A.anchor?.name??A.brainName,w=A.anchor?.kind??"professional",$=[];if(A.anchor?.description)$.push(A.anchor.description);if(A.description)$.push(A.description);let D=Q.status??"discovered",f=new Date().toISOString();return{content:HUB.createAgentContent({name:B,kind:w,...A.anchor?.organization&&{organization:A.anchor.organization},brainName:A.brainName,url:A.url,status:D,discoveredAt:f,about:$.join(`
|
|
@@ -8594,7 +8594,7 @@ ${A.guidance}`:$}}function ns1(A){return{...A,evidence:A.evidence.map((Q)=>({...
|
|
|
8594
8594
|
setTagFilter("all");
|
|
8595
8595
|
});
|
|
8596
8596
|
})();`;import{jsxDEV as AB}from"preact/jsx-dev-runtime";function IUB({item:A}){return AB("li",{class:"list-item",children:[AB("div",{class:"list-main",children:[AB("span",{class:"list-name",children:A.name},void 0,!1,void 0,this),AB("span",{class:"list-desc",children:A.description},void 0,!1,void 0,this),A.tags.length>0&&AB("div",{class:"list-tags",children:A.tags.map((Q)=>AB("span",{class:"tag",children:Q},`${A.id}:${Q}`,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),AB("div",{class:"list-meta",children:A.status==="discovered"&&AB("span",{class:"pill pill--warn",children:"review"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function VUB({item:A}){return AB("li",{class:"list-item agent-network-skill-row","data-agent-network-skill-row":!0,"data-agent-network-tags":JSON.stringify(A.tags),children:[AB("div",{class:"list-main",children:AB("span",{class:"list-name",children:A.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),AB("div",{class:"list-meta",children:AB("span",{class:`agent-network-source${A.sourceType==="brain"?" is-brain":""}`,children:A.sourceLabel},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function JUB({kind:A,items:Q,active:B}){return AB("div",{class:`agent-network-panel${B?" is-active":""}`,"data-agent-network-panel":A,children:Q.length>0?AB("ul",{class:"list agent-network-list",children:Q.map((w)=>AB(IUB,{item:w},w.id,!1,void 0,this))},void 0,!1,void 0,this):AB("p",{class:"agent-network-empty",children:"Nothing to show yet."},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function LUB({skills:A,count:Q,filters:B}){return AB("div",{class:"agent-network-panel","data-agent-network-panel":"skills",children:[AB("div",{class:"agent-network-filter-row",role:"tablist","aria-label":"Filter skills by tag",children:[AB("button",{class:"agent-network-filter is-active",type:"button","data-agent-network-tag-filter":"all","aria-pressed":"true",children:[AB("span",{class:"count",children:Q},void 0,!1,void 0,this),AB("span",{class:"label",children:"all"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),B.map((w)=>AB("button",{class:`agent-network-filter${w.variant==="gap"?" is-gap":""}`,type:"button","data-agent-network-tag-filter":w.tag,"aria-pressed":"false",children:[AB("span",{class:"count",children:w.count},void 0,!1,void 0,this),AB("span",{class:"label",children:w.tag},void 0,!1,void 0,this)]},w.tag,!0,void 0,this))]},void 0,!0,void 0,this),A.length>0?AB("ul",{class:"list agent-network-list agent-network-skills-list",children:A.map((w)=>AB(VUB,{item:w},w.id,!1,void 0,this))},void 0,!1,void 0,this):AB("p",{class:"agent-network-empty",children:"Nothing to show yet."},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function sn0({data:A}){let Q=la1.safeParse(A);if(!Q.success)return AB("p",{class:"muted",children:"Nothing to show yet."},void 0,!1,void 0,this);let B=Q.data;return AB("div",{"data-agent-network-widget":!0,"data-agent-network-view":"agents",children:[AB("div",{class:"agent-network-view-tabs",role:"tablist","aria-label":"Browse the agent network",children:[AB("button",{class:"agent-network-view-tab is-active",type:"button","data-agent-network-view-tab":"agents","aria-pressed":"true",children:["Agents",AB("span",{class:"agent-network-view-count",children:B.counts.agents},void 0,!1,void 0,this)]},void 0,!0,void 0,this),AB("button",{class:"agent-network-view-tab",type:"button","data-agent-network-view-tab":"skills","aria-pressed":"false",children:["Skills",AB("span",{class:"agent-network-view-count",children:B.counts.skills},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),AB("div",{class:"agent-network-kind-tabs",role:"tablist","aria-label":"Filter agents by kind",children:on0.map((w)=>{let $=w==="all";return AB("button",{class:`agent-network-kind-tab${$?" is-active":""}`,type:"button","data-agent-network-kind-tab":w,"aria-pressed":$?"true":"false",children:[AB("span",{class:"agent-network-kind-count",children:B.agents[w].length},void 0,!1,void 0,this),AB("span",{class:"agent-network-kind-label",children:w},void 0,!1,void 0,this)]},w,!0,void 0,this)})},void 0,!1,void 0,this),on0.map((w)=>AB(JUB,{kind:w,items:B.agents[w],active:w==="all"},w,!1,void 0,this)),AB(LUB,{skills:B.skills,count:B.counts.skills,filters:B.skillFilters},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function ia1(A,Q){A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"dashboard:register-widget",payload:{id:ba1,pluginId:Q,title:"Agent Network",section:"secondary",priority:15,rendererName:Na1,component:sn0,clientScript:Lf0,dataProvider:async()=>pa1(A)}}),{success:!0}})}K0();var da1=new cf;function bUB(A){return A.skills.map((Q)=>({name:Q.name,description:Q.description,tags:Q.tags??[]}))}function NUB(A){return new URL(A).hostname}function jUB(A){return[`ATProto card: ${A.uri}`,`ATProto card CID: ${A.cid}`,`ATProto repo DID: ${A.repoDid}`].join(`
|
|
8597
|
-
`)}function _UB(A){let Q=A.record.brain.did,B=A.record.anchor.did;return{agentId:A.agent.id,name:A.agent.metadata.name,url:A.agent.metadata.url,status:A.agent.metadata.status,repoDid:A.repoDid,...Q&&{brainDid:Q},...B&&{anchorDid:B},cardUri:A.uri,cardCid:A.cid}}async function MUB(A,Q,B){await A.messaging.send({type:Q,payload:B,broadcast:!0})}async function PUB(A,Q,B=new Date().toISOString()){let{record:w}=Q,$=NUB(w.siteUrl),D=await A.entityService.getEntity({entityType:"agent",id:$}),f=D?da1.parseEntity(D):void 0,Y=w.brain.did,X=w.anchor.did,H=bUB(w),W=D?.metadata.status??"discovered",Z=D?.metadata.url??w.siteUrl,G=D?.metadata.slug??NI(Z),F=D?.metadata.name??w.anchor.name,I=f?.frontmatter.kind??w.anchor.kind,L=D?.metadata.discoveredAt??B,b=w.brain.purpose||f?.body.about||"",N=H.length>0?H:f?.body.skills??[],M={...D?.metadata??{},name:F,url:Z,status:W,discoveredAt:L,slug:G,repoDid:Q.repoDid,...Y&&{brainDid:Y},...X&&{anchorDid:X},cardUri:Q.uri,cardCid:Q.cid},j=da1.createAgentContent({name:F,kind:I,...f?.frontmatter.organization&&{organization:f.frontmatter.organization},brainName:w.brain.name,url:Z,...Y&&{did:Y,brainDid:Y},...X&&{anchorDid:X},repoDid:Q.repoDid,cardUri:Q.uri,cardCid:Q.cid,...f?.frontmatter.a2aEndpoint&&{a2aEndpoint:f.frontmatter.a2aEndpoint},status:W,discoveredAt:L,about:b,skills:N,notes:jUB({repoDid:Q.repoDid,uri:Q.uri,cid:Q.cid})});if(D){let E={...D,content:j,metadata:M,updated:B};return await A.entityService.updateEntity({entity:E}),{agent:E,created:!1}}let g={id:$,entityType:"agent",content:j,metadata:M,contentHash:"",visibility:"public",created:B,updated:B};return await A.entityService.createEntity({entity:g}),{agent:g,created:!0}}function na1(A){A.messaging.subscribe(V40,async(Q)=>{let B=_p1.parse(Q.payload),w=await PUB(A,B),$=_UB({agent:w.agent,repoDid:B.repoDid,uri:B.uri,cid:B.cid,record:B.record});return await MUB(A,w.created?Np1:jp1,$),{success:!0,data:$}})}function ra1(){return'## Agent directory\n\nThese rules govern the local `agent` directory and agent-contact requests. They override the general wishlist rule and the general "always attempt tool calls" rule.\n\n### Directory CRUD\n- Add a new agent contact with `system_create` using `entityType: "agent"` and pass the domain or URL as `source: { kind: "url", url }`.\n- List saved agents with `system_list` using `entityType: "agent"`.\n- Approve a discovered agent with `system_update` on the `agent` entity using `fields` (for example `fields: { status: "approved" }`). Do not replace the full content just to change status.\n- When the user explicitly says `approve`, `approve it`, `yes approve`, or `approve <agent-id>`, call `system_update` immediately with `fields: { status: "approved" }` and let the standard confirmation flow ask the user to confirm. Never pass `confirmed: true` on the initial approval request.\n- If the previous turn identified one specific discovered agent, treat a short follow-up like `approve`, `approve it`, or `yes approve` as referring to that same agent id.\n- If `system_update` succeeds for an approval request, answer plainly that the agent is now approved. Do not say the operation failed, and do not ask to retry, unless the tool actually failed.\n- If `system_update` says to use `fields`, or says full content replacement is invalid/empty, retry once immediately with `fields` instead of surfacing that error to the user.\n- If the user gives an exact saved agent id like `old-agent.io`, call that single `system_update` directly instead of listing/searching first.\n\n### Contact requests (ask / talk to / what does X say)\n- Treat phrases like `what does <agent> have to say`, `what would <agent> say/think`, and asking a saved agent for its own skills/capabilities as contact requests. For an exact saved local agent id such as `yeehaa.io` or `docs.rizom.ai`, use `a2a_call` rather than answering from local saved agent metadata, unless the user explicitly asks for directory/profile details.\n- If a previous turn contacted an exact saved agent id with `a2a_call`, a follow-up like `what skills does it have`, `what does it say about X`, or `tell me more` is another contact request to the same saved agent. Call `a2a_call` again with that id, even if the previous remote response was a refusal or error. Do not inspect or summarize local `agent` metadata for these follow-ups.\n- If the user uses a display/contact name like `Brain` rather than an exact saved id, first inspect saved agents with `system_list({ entityType: "agent" })`. If multiple saved agents could match, ask which one and do not call any tool. Never choose the first match.\n- If a saved agent is archived/removed, do not call it and do not create a wish. Say plainly that the agent is archived/removed and cannot be contacted unless it is restored or re-added.\n\n### Save-first for unsaved agents\n- Calling and saving agents are separate actions. If the user asks to `call`, `talk to`, `ask`, message, contact, or reach out to an unsaved agent domain/URL, do **not** call `system_create` or `a2a_call` on that first request. Tell the user the agent is not yet in the local agent **directory** and ask them to **add/save it first**. The reply must include both the word **directory** (to be clear about what\'s missing) and the phrase **add/save it first**.\n- This applies equally to full URLs (`https://unknown-agent.io/a2a`) and bare domains/ids (`unknown-agent.io`) when the user is trying to contact an agent. A URL-based or unsaved-domain agent contact request is a save-first directory case, not a wishlist case.\n- Explicit link or bookmark saves like `save this link: https://example.com/page` are not agent-contact requests, even when the URL is a domain-like agent-looking URL or fetch would fail. For save/bookmark/capture-link requests, use `system_create({ entityType: "link", source: { kind: "url", url: "https://example.com/page" } })`; separate "should save a link" from "did fetching that URL succeed" and let the link create tool report unreachable URLs.\n- When refusing, cite the agent domain/URL **by name** in your reply (e.g. "you\'ll need to add/save `unknown-agent.io` first") \u2014 do not say "that agent" without naming it. This anchors the domain for any affirmative follow-up.\n- The save-first refusal turn must have **no tool calls**. Do not create a wish, note, reminder, task, or backlog item to remember the blocked contact request. Specifically: never call `system_create` with `entityType: "wish"` for an agent-contact request, and never create any other fallback entity for a missing, archived/removed, or ambiguous agent unless the user explicitly asks you to add/save/unarchive it.\n- In the user-facing save-first refusal, say only that the agent must be in the local directory and ask them to add/save it first. Do not mention wishes, wishlist, backlog, or fallback entities in that response.\n\n### Affirmative follow-up after save-first refusal\n- If a recent user message named exactly one unsaved agent domain/URL and you told them to add/save it first, treat a short affirmative follow-up like `yes`, `yes please`, `please do`, `go ahead`, `do that`, or `save it` as consent to save that same agent immediately with `system_create({ entityType: "agent", source: { kind: "url", url: "that-domain" } })`. The trigger is the user\'s prior reference to the domain, not whether your refusal echoed it back.\n- A bare affirmative follow-up is enough. For example, after `Can you talk to save-first-followup.example for me?` and your save-first refusal, `Yes please` means call `system_create({ entityType: "agent", source: { kind: "url", url: "save-first-followup.example" } })` immediately.\n- Do **not** repeat the save-first instruction, ask for a description, ask for the domain again, or return an empty response after such an affirmative follow-up; just call `system_create`.\n\n### Examples\n- User: "Ask https://unknown-agent.io about X" \u2192 do **not** call `a2a_call` and do **not** call `system_create` for a wish. Tell them to add/save `unknown-agent.io` first.\n- User: "Can you message this agent URL for me: https://unknown-agent.io/a2a?" \u2192 do **not** create a wish. Tell them the agent must be saved first.\n- User: "Ask Brain about X" with both `yeehaa.io` and `brain-labs.io` saved as "Brain" \u2192 ask the user to choose between those two saved ids and do not call `a2a_call`.'}p0();Jw();K0();import{jsxDEV as oa1}from"preact/jsx-dev-runtime";function bf0(A){try{return new URL(A).hostname}catch{return A}}var Nf0=({name:A,className:Q=""})=>{let B=A.charAt(0).toUpperCase(),w=0;for(let D=0;D<A.length;D++)w=A.charCodeAt(D)+((w<<5)-w);let $=Math.abs(w)%360;return oa1("div",{className:`flex items-center justify-center rounded-full text-white font-bold flex-shrink-0 ${Q}`,style:{backgroundColor:`hsl(${$}, 55%, 45%)`},children:B},void 0,!1,void 0,this)},jf0=({kind:A,size:Q="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 oa1("span",{className:`inline-flex items-center rounded-full font-medium ${Q==="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 j2,Fragment as xUB}from"preact/jsx-dev-runtime";var kUB=({skills:A})=>{if(A.length===0)return null;return j2("div",{className:"flex gap-1.5 flex-wrap mt-2",children:A.map((Q)=>j2("span",{className:"text-[11px] px-2 py-0.5 bg-theme-subtle rounded-md text-theme-muted",children:Q.name},Q.name,!1,void 0,this))},void 0,!1,void 0,this)};function OUB(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}function sa1(A,Q,B){let w=new URLSearchParams({status:Q});if(B>1)w.set("page",String(B));return`${A}?${w.toString()}`}var an0=({agent:A})=>{let{frontmatter:Q,about:B,skills:w,url:$}=A,D=Q.status==="approved";return j2("a",{href:$,className:`flex items-start gap-5 p-6 rounded-xl border border-theme bg-theme-subtle hover:shadow-lg transition-shadow ${D?"":"opacity-70"}`,children:[j2(Nf0,{name:Q.name,className:"w-12 h-12 text-lg"},void 0,!1,void 0,this),j2("div",{className:"flex-1 min-w-0",children:[j2("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[j2("span",{className:"text-lg font-semibold text-heading",children:Q.name},void 0,!1,void 0,this),j2(jf0,{kind:Q.kind,size:"sm"},void 0,!1,void 0,this),Q.organization&&j2("span",{className:"text-xs text-theme-muted",children:["\xB7 ",Q.organization]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"text-sm text-theme-muted mb-1",children:Q.brainName},void 0,!1,void 0,this),B&&j2("p",{className:"text-sm text-theme-muted line-clamp-2 mb-0",children:B},void 0,!1,void 0,this),D&&j2(kUB,{skills:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col items-end gap-1 flex-shrink-0 text-right",children:[j2("span",{className:"text-xs text-theme-muted",children:bf0(Q.url)},void 0,!1,void 0,this),j2("span",{className:"text-[11px] text-theme-muted opacity-60",children:D?`Discovered ${OUB(Q.discoveredAt)}`:"Discovered \xB7 approve before calling"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},aa1=({agents:A,pageTitle:Q,pagination:B,baseUrl:w="/agents",selectedStatus:$})=>{let D=Q??"Agent Directory",f=B?.totalItems??A.length,Y=A.filter((G)=>G.frontmatter.status==="approved"),X=A.filter((G)=>G.frontmatter.status==="discovered"),H=Y.length,W=X.length,Z=`Your network of ${f} ${f===1?"brain":"brains"} and their anchors`;return j2(xUB,{children:[j2(NQ,{title:D,description:Z},void 0,!1,void 0,this),j2("div",{className:"agent-list bg-theme",children:j2("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[j2("div",{className:"mb-8 pb-6 border-b border-theme",children:[j2("h1",{className:"text-4xl font-bold text-heading mb-2",children:D},void 0,!1,void 0,this),j2("p",{className:"text-theme-muted mb-4",children:Z},void 0,!1,void 0,this),j2("div",{className:"flex flex-wrap gap-2 text-sm mb-4",children:[j2("span",{className:"px-3 py-1 rounded-full bg-theme-subtle text-heading",children:[f," total"]},void 0,!0,void 0,this),j2("span",{className:"px-3 py-1 rounded-full bg-theme-subtle text-status-success",children:[H," approved"]},void 0,!0,void 0,this),j2("span",{className:"px-3 py-1 rounded-full bg-theme-subtle text-theme-muted",children:[W," discovered"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-wrap gap-2 text-sm",children:[j2("a",{href:w,className:`px-3 py-1 rounded-full border transition-colors ${$==="all"?"border-theme text-heading bg-theme-subtle":"border-theme text-theme-muted hover:text-heading"}`,children:"All"},void 0,!1,void 0,this),j2("a",{href:`${w}?status=approved`,className:`px-3 py-1 rounded-full border transition-colors ${$==="approved"?"border-theme text-heading bg-theme-subtle":"border-theme text-theme-muted hover:text-heading"}`,children:"Approved"},void 0,!1,void 0,this),j2("a",{href:`${w}?status=discovered`,className:`px-3 py-1 rounded-full border transition-colors ${$==="discovered"?"border-theme text-heading bg-theme-subtle":"border-theme text-theme-muted hover:text-heading"}`,children:"Discovered"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),$==="all"&&Y.length>0&&j2("section",{className:"mb-10",children:[j2("div",{className:"flex items-center justify-between mb-4",children:[j2("h2",{className:"text-lg font-semibold text-heading",children:"Approved brains"},void 0,!1,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:Y.length},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col gap-4",children:Y.map((G)=>j2(an0,{agent:G},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$==="all"&&X.length>0&&j2("section",{children:[j2("div",{className:"flex items-center justify-between mb-4",children:[j2("div",{children:[j2("h2",{className:"text-lg font-semibold text-heading",children:"Discovered brains"},void 0,!1,void 0,this),j2("p",{className:"text-sm text-theme-muted",children:"Review and approve these before calling them."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:X.length},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col gap-4",children:X.map((G)=>j2(an0,{agent:G},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$!=="all"&&A.length>0&&j2("section",{children:[j2("div",{className:"flex items-center justify-between mb-4",children:[j2("h2",{className:"text-lg font-semibold text-heading",children:$==="approved"?"Approved brains":"Discovered brains"},void 0,!1,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:A.length},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col gap-4",children:A.map((G)=>j2(an0,{agent:G},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.length===0&&j2("p",{className:"text-center text-theme-muted py-16",children:"No agents in your directory yet."},void 0,!1,void 0,this),B&&B.totalPages>1&&$==="all"&&j2("div",{className:"mt-12",children:j2(i3,{currentPage:B.currentPage,totalPages:B.totalPages,baseUrl:w},void 0,!1,void 0,this)},void 0,!1,void 0,this),B&&B.totalPages>1&&$!=="all"&&j2("nav",{"aria-label":"Pagination",className:"flex items-center justify-center gap-3 mt-12",children:[B.hasPrevPage?j2("a",{href:sa1(w,$,B.currentPage-1),className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted hover:text-heading transition-colors",children:"\u2190 Prev"},void 0,!1,void 0,this):j2("span",{className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted opacity-50",children:"\u2190 Prev"},void 0,!1,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:["Page ",B.currentPage," of ",B.totalPages]},void 0,!0,void 0,this),B.hasNextPage?j2("a",{href:sa1(w,$,B.currentPage+1),className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted hover:text-heading transition-colors",children:"Next \u2192"},void 0,!1,void 0,this):j2("span",{className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted opacity-50",children:"Next \u2192"},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)};import{jsxDEV as U2,Fragment as CUB}from"preact/jsx-dev-runtime";function RUB(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var jo=({children:A})=>U2("h2",{className:"text-sm font-semibold text-theme-muted uppercase tracking-wide mb-3",children:A},void 0,!1,void 0,this),vUB=({skill:A})=>U2("div",{className:"flex items-start gap-3 px-4 py-3 bg-theme-subtle rounded-lg",children:[U2("div",{className:"flex-1",children:[U2("div",{className:"text-sm font-semibold text-heading",children:A.name},void 0,!1,void 0,this),U2("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&&U2("div",{className:"flex gap-1 flex-shrink-0",children:A.tags.map((Q)=>U2("span",{className:"text-[11px] px-2 py-0.5 bg-theme rounded-md text-theme-muted",children:Q},Q,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),hUB=({label:A,value:Q,valueClassName:B})=>U2("div",{className:"flex justify-between text-[13px]",children:[U2("span",{className:"text-theme-muted",children:A},void 0,!1,void 0,this),U2("span",{className:B??"text-heading",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ta1=({agent:A,prevAgent:Q,nextAgent:B})=>{let{frontmatter:w,about:$,skills:D,notes:f}=A,Y=bf0(w.url),X=w.status==="approved";return U2(CUB,{children:[U2(NQ,{title:w.name,description:$||`Agent profile for ${w.name}`},void 0,!1,void 0,this),U2("article",{className:"agent-detail",children:U2("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:[U2("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),U2("div",{className:"flex items-start gap-6 mb-8",children:[U2(Nf0,{name:w.name,className:"w-[72px] h-[72px] text-3xl"},void 0,!1,void 0,this),U2("div",{children:[U2("div",{className:"flex items-center gap-3 mb-1",children:[U2("h1",{className:"text-3xl md:text-4xl font-bold text-heading",children:w.name},void 0,!1,void 0,this),U2(jf0,{kind:w.kind},void 0,!1,void 0,this)]},void 0,!0,void 0,this),U2("div",{className:"text-base text-theme-muted mb-2",children:w.brainName},void 0,!1,void 0,this),U2("div",{className:"flex items-center gap-3 text-theme-muted",children:[w.organization&&U2("span",{className:"text-[15px]",children:w.organization},void 0,!1,void 0,this),w.organization&&U2("span",{className:"text-theme-muted opacity-40",children:"\xB7"},void 0,!1,void 0,this),U2("span",{className:"text-sm",children:["Discovered ",RUB(w.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),U2("div",{className:"border-b border-theme mb-8"},void 0,!1,void 0,this),!X&&U2("div",{className:"mb-8 rounded-xl border border-theme bg-theme-subtle px-5 py-4",children:[U2("div",{className:"text-sm font-semibold text-heading mb-1",children:"Saved for review"},void 0,!1,void 0,this),U2("p",{className:"text-sm text-theme-muted",children:"This brain is discovered but not approved yet, so it cannot be called until you approve it."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),U2("div",{className:"flex flex-col md:flex-row gap-12",children:[U2("div",{className:"flex-[2] min-w-0",children:[$&&U2("section",{className:"mb-8",children:[U2(jo,{children:"About"},void 0,!1,void 0,this),U2("p",{className:"text-[15px] text-theme leading-relaxed",children:$},void 0,!1,void 0,this)]},void 0,!0,void 0,this),D.length>0&&U2("section",{className:"mb-8",children:[U2(jo,{children:"Skills"},void 0,!1,void 0,this),U2("div",{className:"flex flex-col gap-2.5",children:D.map((H)=>U2(vUB,{skill:H},H.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),f&&U2("section",{className:"mb-8",children:[U2(jo,{children:"Notes"},void 0,!1,void 0,this),U2("p",{className:"text-[15px] text-theme leading-relaxed",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U2("aside",{className:"flex-1 md:pl-8 md:border-l border-theme-muted/20",children:[U2("section",{className:"mb-8",children:[U2(jo,{children:"Brain"},void 0,!1,void 0,this),U2("div",{className:"p-4 bg-theme-subtle rounded-xl",children:[U2("div",{className:"text-[15px] font-semibold text-heading mb-1",children:w.brainName},void 0,!1,void 0,this),w.did&&U2("div",{className:"text-xs text-theme-muted font-mono",children:w.did},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U2("section",{className:"mb-8",children:[U2(jo,{children:"Connection"},void 0,!1,void 0,this),U2("div",{className:"flex flex-col gap-3",children:[U2("div",{children:[U2("div",{className:"text-[13px] text-theme-muted mb-0.5",children:"Endpoint"},void 0,!1,void 0,this),U2("div",{className:"text-xs text-heading font-mono",children:w.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this),U2(hUB,{label:"Status",value:w.status==="approved"?"Approved":"Discovered",valueClassName:w.status==="approved"?"text-status-success font-medium":"text-theme-muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U2("a",{href:w.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 ",Y," \u2197"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),(Q??B)&&U2("nav",{className:"mt-12 pt-6 border-t border-theme flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[U2("div",{className:"min-h-[1px]",children:Q&&U2("a",{href:Q.url,className:"inline-flex flex-col text-sm text-theme-muted hover:text-heading transition-colors",children:[U2("span",{children:"\u2190 Previous"},void 0,!1,void 0,this),U2("span",{className:"text-heading font-medium",children:Q.frontmatter.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),U2("div",{className:"min-h-[1px] md:text-right",children:B&&U2("a",{href:B.url,className:"inline-flex flex-col text-sm text-theme-muted hover:text-heading transition-colors",children:[U2("span",{children:"Next \u2192"},void 0,!1,void 0,this),U2("span",{className:"text-heading font-medium",children:B.frontmatter.name},void 0,!1,void 0,this)]},void 0,!0,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,!0,void 0,this)};var yUB=K.object({agents:K.array(PE),pageTitle:K.string().optional(),pagination:e7.nullable(),baseUrl:K.string().optional(),selectedStatus:K.union([K.literal("all"),HW])});function ea1(){return{[dn0]:R1({name:dn0,description:"Agent directory list page template",schema:yUB,dataSourceId:bo,requiredPermission:"public",layout:{component:aa1}}),[nn0]:R1({name:nn0,description:"Individual agent profile template",schema:K.object({agent:PE,prevAgent:PE.nullable(),nextAgent:PE.nullable()}),dataSourceId:bo,requiredPermission:"public",layout:{component:ta1}})}}var _f0={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.128",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,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var gUB=new cf;class tn0 extends PQ{entityType=R7;schema=ME;adapter=gUB;constructor(){super(Ja1,_f0)}interceptCreate(A,Q,B){return Ta1(A,Q,B,this.id)}createGenerationHandler(A){return new rn0(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return ea1()}getDataSources(){return[new If0(this.logger.child("AgentDataSource"))]}async onRegister(A){na1(A),ia1(A,this.id)}async getInstructions(){return ra1()}}function en0(){return new tn0}p0();K0();p0();var kE=_Y,At1=_Y,_o=o1.extend({entityType:K.literal(z5),metadata:At1});p0();class OE extends V2{constructor(){super({entityType:z5,schema:_o,frontmatterSchema:kE})}fromMarkdown(A){let Q=this.parseFrontMatter(A,kE);return{content:A,entityType:z5,metadata:Q}}createSkillContent(A){return this.buildMarkdown("",A)}}p0();K0();var TUB=K.object({skills:K.array(kE).max(8)}),Qt1=R1({name:"skill:skill-derivation",description:"Derive skills from topic titles and brain capabilities",dataSourceId:"shell:ai-content",schema:TUB,useKnowledgeContext:!0,basePrompt:`You are analyzing a brain's content to identify its high-level capabilities.
|
|
8597
|
+
`)}function _UB(A){let Q=A.record.brain.did,B=A.record.anchor.did;return{agentId:A.agent.id,name:A.agent.metadata.name,url:A.agent.metadata.url,status:A.agent.metadata.status,repoDid:A.repoDid,...Q&&{brainDid:Q},...B&&{anchorDid:B},cardUri:A.uri,cardCid:A.cid}}async function MUB(A,Q,B){await A.messaging.send({type:Q,payload:B,broadcast:!0})}async function PUB(A,Q,B=new Date().toISOString()){let{record:w}=Q,$=NUB(w.siteUrl),D=await A.entityService.getEntity({entityType:"agent",id:$}),f=D?da1.parseEntity(D):void 0,Y=w.brain.did,X=w.anchor.did,H=bUB(w),W=D?.metadata.status??"discovered",Z=D?.metadata.url??w.siteUrl,G=D?.metadata.slug??NI(Z),F=D?.metadata.name??w.anchor.name,I=f?.frontmatter.kind??w.anchor.kind,L=D?.metadata.discoveredAt??B,b=w.brain.purpose||f?.body.about||"",N=H.length>0?H:f?.body.skills??[],M={...D?.metadata??{},name:F,url:Z,status:W,discoveredAt:L,slug:G,repoDid:Q.repoDid,...Y&&{brainDid:Y},...X&&{anchorDid:X},cardUri:Q.uri,cardCid:Q.cid},j=da1.createAgentContent({name:F,kind:I,...f?.frontmatter.organization&&{organization:f.frontmatter.organization},brainName:w.brain.name,url:Z,...Y&&{did:Y,brainDid:Y},...X&&{anchorDid:X},repoDid:Q.repoDid,cardUri:Q.uri,cardCid:Q.cid,...f?.frontmatter.a2aEndpoint&&{a2aEndpoint:f.frontmatter.a2aEndpoint},status:W,discoveredAt:L,about:b,skills:N,notes:jUB({repoDid:Q.repoDid,uri:Q.uri,cid:Q.cid})});if(D){let E={...D,content:j,metadata:M,updated:B};return await A.entityService.updateEntity({entity:E}),{agent:E,created:!1}}let g={id:$,entityType:"agent",content:j,metadata:M,contentHash:"",visibility:"public",created:B,updated:B};return await A.entityService.createEntity({entity:g}),{agent:g,created:!0}}function na1(A){A.messaging.subscribe(V40,async(Q)=>{let B=_p1.parse(Q.payload),w=await PUB(A,B),$=_UB({agent:w.agent,repoDid:B.repoDid,uri:B.uri,cid:B.cid,record:B.record});return await MUB(A,w.created?Np1:jp1,$),{success:!0,data:$}})}function ra1(){return'## Agent directory\n\nThese rules govern the local `agent` directory and agent-contact requests. They override the general wishlist rule and the general "always attempt tool calls" rule.\n\n### Directory CRUD\n- Add a new agent contact with `system_create` using `entityType: "agent"` and pass the domain or URL as `source: { kind: "url", url }`.\n- List saved agents with `system_list` using `entityType: "agent"`.\n- Approve a discovered agent with `system_update` on the `agent` entity using `fields` (for example `fields: { status: "approved" }`). Do not replace the full content just to change status.\n- When the user explicitly says `approve`, `approve it`, `yes approve`, or `approve <agent-id>`, call `system_update` immediately with `fields: { status: "approved" }` and let the standard confirmation flow ask the user to confirm. Never pass `confirmed: true` on the initial approval request.\n- If the previous turn identified one specific discovered agent, treat a short follow-up like `approve`, `approve it`, or `yes approve` as referring to that same agent id.\n- If `system_update` succeeds for an approval request, answer plainly that the agent is now approved. Do not say the operation failed, and do not ask to retry, unless the tool actually failed.\n- If `system_update` says to use `fields`, or says full content replacement is invalid/empty, retry once immediately with `fields` instead of surfacing that error to the user.\n- If the user gives an exact saved agent id like `old-agent.io`, call that single `system_update` directly instead of listing/searching first.\n\n### Contact requests (ask / talk to / what does X say)\n- Treat phrases like `what does <agent> have to say`, `what would <agent> say/think`, and asking a saved agent for its own skills/capabilities as contact requests. For an exact saved local agent id such as `yeehaa.io` or `docs.rizom.ai`, use `a2a_call` rather than answering from local saved agent metadata, unless the user explicitly asks for directory/profile details.\n- If a previous turn contacted an exact saved agent id with `a2a_call`, a follow-up like `what skills does it have`, `what does it say about X`, or `tell me more` is another contact request to the same saved agent. Call `a2a_call` again with that id, even if the previous remote response was a refusal or error. Do not inspect or summarize local `agent` metadata for these follow-ups.\n- If the user uses a display/contact name like `Brain` rather than an exact saved id, first inspect saved agents with `system_list({ entityType: "agent" })`. If multiple saved agents could match, ask which one and do not call any tool. Never choose the first match.\n- If a saved agent is archived/removed, do not call it and do not create a wish. Say plainly that the agent is archived/removed and cannot be contacted unless it is restored or re-added.\n\n### Save-first for unsaved agents\n- Calling and saving agents are separate actions. If the user asks to `call`, `talk to`, `ask`, message, contact, or reach out to an unsaved agent domain/URL, do **not** call `system_create` or `a2a_call` on that first request. Tell the user the agent is not yet in the local agent **directory** and ask them to **add/save it first**. The reply must include both the word **directory** (to be clear about what\'s missing) and the phrase **add/save it first**.\n- This applies equally to full URLs (`https://unknown-agent.io/a2a`) and bare domains/ids (`unknown-agent.io`) when the user is trying to contact an agent. A URL-based or unsaved-domain agent contact request is a save-first directory case, not a wishlist case.\n- Explicit link or bookmark saves like `save this link: https://example.com/page` are not agent-contact requests, even when the URL is a domain-like agent-looking URL or fetch would fail. For save/bookmark/capture-link requests, use `system_create({ entityType: "link", source: { kind: "url", url: "https://example.com/page" } })`; separate "should save a link" from "did fetching that URL succeed" and let the link create tool report unreachable URLs.\n- When refusing, cite the agent domain/URL **by name** in your reply (e.g. "you\'ll need to add/save `unknown-agent.io` first") \u2014 do not say "that agent" without naming it. This anchors the domain for any affirmative follow-up.\n- The save-first refusal turn must have **no tool calls**. Do not create a wish, note, reminder, task, or backlog item to remember the blocked contact request. Specifically: never call `system_create` with `entityType: "wish"` for an agent-contact request, and never create any other fallback entity for a missing, archived/removed, or ambiguous agent unless the user explicitly asks you to add/save/unarchive it.\n- In the user-facing save-first refusal, say only that the agent must be in the local directory and ask them to add/save it first. Do not mention wishes, wishlist, backlog, or fallback entities in that response.\n\n### Affirmative follow-up after save-first refusal\n- If a recent user message named exactly one unsaved agent domain/URL and you told them to add/save it first, treat a short affirmative follow-up like `yes`, `yes please`, `please do`, `go ahead`, `do that`, or `save it` as consent to save that same agent immediately with `system_create({ entityType: "agent", source: { kind: "url", url: "that-domain" } })`. The trigger is the user\'s prior reference to the domain, not whether your refusal echoed it back.\n- A bare affirmative follow-up is enough. For example, after `Can you talk to save-first-followup.example for me?` and your save-first refusal, `Yes please` means call `system_create({ entityType: "agent", source: { kind: "url", url: "save-first-followup.example" } })` immediately.\n- Do **not** repeat the save-first instruction, ask for a description, ask for the domain again, or return an empty response after such an affirmative follow-up; just call `system_create`.\n\n### Examples\n- User: "Ask https://unknown-agent.io about X" \u2192 do **not** call `a2a_call` and do **not** call `system_create` for a wish. Tell them to add/save `unknown-agent.io` first.\n- User: "Can you message this agent URL for me: https://unknown-agent.io/a2a?" \u2192 do **not** create a wish. Tell them the agent must be saved first.\n- User: "Ask Brain about X" with both `yeehaa.io` and `brain-labs.io` saved as "Brain" \u2192 ask the user to choose between those two saved ids and do not call `a2a_call`.'}p0();Jw();K0();import{jsxDEV as oa1}from"preact/jsx-dev-runtime";function bf0(A){try{return new URL(A).hostname}catch{return A}}var Nf0=({name:A,className:Q=""})=>{let B=A.charAt(0).toUpperCase(),w=0;for(let D=0;D<A.length;D++)w=A.charCodeAt(D)+((w<<5)-w);let $=Math.abs(w)%360;return oa1("div",{className:`flex items-center justify-center rounded-full text-white font-bold flex-shrink-0 ${Q}`,style:{backgroundColor:`hsl(${$}, 55%, 45%)`},children:B},void 0,!1,void 0,this)},jf0=({kind:A,size:Q="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 oa1("span",{className:`inline-flex items-center rounded-full font-medium ${Q==="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 j2,Fragment as xUB}from"preact/jsx-dev-runtime";var kUB=({skills:A})=>{if(A.length===0)return null;return j2("div",{className:"flex gap-1.5 flex-wrap mt-2",children:A.map((Q)=>j2("span",{className:"text-[11px] px-2 py-0.5 bg-theme-subtle rounded-md text-theme-muted",children:Q.name},Q.name,!1,void 0,this))},void 0,!1,void 0,this)};function OUB(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric"})}function sa1(A,Q,B){let w=new URLSearchParams({status:Q});if(B>1)w.set("page",String(B));return`${A}?${w.toString()}`}var an0=({agent:A})=>{let{frontmatter:Q,about:B,skills:w,url:$}=A,D=Q.status==="approved";return j2("a",{href:$,className:`flex items-start gap-5 p-6 rounded-xl border border-theme bg-theme-subtle hover:shadow-lg transition-shadow ${D?"":"opacity-70"}`,children:[j2(Nf0,{name:Q.name,className:"w-12 h-12 text-lg"},void 0,!1,void 0,this),j2("div",{className:"flex-1 min-w-0",children:[j2("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[j2("span",{className:"text-lg font-semibold text-heading",children:Q.name},void 0,!1,void 0,this),j2(jf0,{kind:Q.kind,size:"sm"},void 0,!1,void 0,this),Q.organization&&j2("span",{className:"text-xs text-theme-muted",children:["\xB7 ",Q.organization]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"text-sm text-theme-muted mb-1",children:Q.brainName},void 0,!1,void 0,this),B&&j2("p",{className:"text-sm text-theme-muted line-clamp-2 mb-0",children:B},void 0,!1,void 0,this),D&&j2(kUB,{skills:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col items-end gap-1 flex-shrink-0 text-right",children:[j2("span",{className:"text-xs text-theme-muted",children:bf0(Q.url)},void 0,!1,void 0,this),j2("span",{className:"text-[11px] text-theme-muted opacity-60",children:D?`Discovered ${OUB(Q.discoveredAt)}`:"Discovered \xB7 approve before calling"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},aa1=({agents:A,pageTitle:Q,pagination:B,baseUrl:w="/agents",selectedStatus:$})=>{let D=Q??"Agent Directory",f=B?.totalItems??A.length,Y=A.filter((G)=>G.frontmatter.status==="approved"),X=A.filter((G)=>G.frontmatter.status==="discovered"),H=Y.length,W=X.length,Z=`Your network of ${f} ${f===1?"brain":"brains"} and their anchors`;return j2(xUB,{children:[j2(NQ,{title:D,description:Z},void 0,!1,void 0,this),j2("div",{className:"agent-list bg-theme",children:j2("div",{className:"container mx-auto px-6 md:px-12 max-w-5xl py-16 md:py-24",children:[j2("div",{className:"mb-8 pb-6 border-b border-theme",children:[j2("h1",{className:"text-4xl font-bold text-heading mb-2",children:D},void 0,!1,void 0,this),j2("p",{className:"text-theme-muted mb-4",children:Z},void 0,!1,void 0,this),j2("div",{className:"flex flex-wrap gap-2 text-sm mb-4",children:[j2("span",{className:"px-3 py-1 rounded-full bg-theme-subtle text-heading",children:[f," total"]},void 0,!0,void 0,this),j2("span",{className:"px-3 py-1 rounded-full bg-theme-subtle text-status-success",children:[H," approved"]},void 0,!0,void 0,this),j2("span",{className:"px-3 py-1 rounded-full bg-theme-subtle text-theme-muted",children:[W," discovered"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-wrap gap-2 text-sm",children:[j2("a",{href:w,className:`px-3 py-1 rounded-full border transition-colors ${$==="all"?"border-theme text-heading bg-theme-subtle":"border-theme text-theme-muted hover:text-heading"}`,children:"All"},void 0,!1,void 0,this),j2("a",{href:`${w}?status=approved`,className:`px-3 py-1 rounded-full border transition-colors ${$==="approved"?"border-theme text-heading bg-theme-subtle":"border-theme text-theme-muted hover:text-heading"}`,children:"Approved"},void 0,!1,void 0,this),j2("a",{href:`${w}?status=discovered`,className:`px-3 py-1 rounded-full border transition-colors ${$==="discovered"?"border-theme text-heading bg-theme-subtle":"border-theme text-theme-muted hover:text-heading"}`,children:"Discovered"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),$==="all"&&Y.length>0&&j2("section",{className:"mb-10",children:[j2("div",{className:"flex items-center justify-between mb-4",children:[j2("h2",{className:"text-lg font-semibold text-heading",children:"Approved brains"},void 0,!1,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:Y.length},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col gap-4",children:Y.map((G)=>j2(an0,{agent:G},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$==="all"&&X.length>0&&j2("section",{children:[j2("div",{className:"flex items-center justify-between mb-4",children:[j2("div",{children:[j2("h2",{className:"text-lg font-semibold text-heading",children:"Discovered brains"},void 0,!1,void 0,this),j2("p",{className:"text-sm text-theme-muted",children:"Review and approve these before calling them."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:X.length},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col gap-4",children:X.map((G)=>j2(an0,{agent:G},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),$!=="all"&&A.length>0&&j2("section",{children:[j2("div",{className:"flex items-center justify-between mb-4",children:[j2("h2",{className:"text-lg font-semibold text-heading",children:$==="approved"?"Approved brains":"Discovered brains"},void 0,!1,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:A.length},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j2("div",{className:"flex flex-col gap-4",children:A.map((G)=>j2(an0,{agent:G},G.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.length===0&&j2("p",{className:"text-center text-theme-muted py-16",children:"No agents in your directory yet."},void 0,!1,void 0,this),B&&B.totalPages>1&&$==="all"&&j2("div",{className:"mt-12",children:j2(i3,{currentPage:B.currentPage,totalPages:B.totalPages,baseUrl:w},void 0,!1,void 0,this)},void 0,!1,void 0,this),B&&B.totalPages>1&&$!=="all"&&j2("nav",{"aria-label":"Pagination",className:"flex items-center justify-center gap-3 mt-12",children:[B.hasPrevPage?j2("a",{href:sa1(w,$,B.currentPage-1),className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted hover:text-heading transition-colors",children:"\u2190 Prev"},void 0,!1,void 0,this):j2("span",{className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted opacity-50",children:"\u2190 Prev"},void 0,!1,void 0,this),j2("span",{className:"text-sm text-theme-muted",children:["Page ",B.currentPage," of ",B.totalPages]},void 0,!0,void 0,this),B.hasNextPage?j2("a",{href:sa1(w,$,B.currentPage+1),className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted hover:text-heading transition-colors",children:"Next \u2192"},void 0,!1,void 0,this):j2("span",{className:"px-3 py-2 rounded-md border border-theme text-sm text-theme-muted opacity-50",children:"Next \u2192"},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)};import{jsxDEV as U2,Fragment as CUB}from"preact/jsx-dev-runtime";function RUB(A){return new Date(A).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"})}var jo=({children:A})=>U2("h2",{className:"text-sm font-semibold text-theme-muted uppercase tracking-wide mb-3",children:A},void 0,!1,void 0,this),vUB=({skill:A})=>U2("div",{className:"flex items-start gap-3 px-4 py-3 bg-theme-subtle rounded-lg",children:[U2("div",{className:"flex-1",children:[U2("div",{className:"text-sm font-semibold text-heading",children:A.name},void 0,!1,void 0,this),U2("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&&U2("div",{className:"flex gap-1 flex-shrink-0",children:A.tags.map((Q)=>U2("span",{className:"text-[11px] px-2 py-0.5 bg-theme rounded-md text-theme-muted",children:Q},Q,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),hUB=({label:A,value:Q,valueClassName:B})=>U2("div",{className:"flex justify-between text-[13px]",children:[U2("span",{className:"text-theme-muted",children:A},void 0,!1,void 0,this),U2("span",{className:B??"text-heading",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ta1=({agent:A,prevAgent:Q,nextAgent:B})=>{let{frontmatter:w,about:$,skills:D,notes:f}=A,Y=bf0(w.url),X=w.status==="approved";return U2(CUB,{children:[U2(NQ,{title:w.name,description:$||`Agent profile for ${w.name}`},void 0,!1,void 0,this),U2("article",{className:"agent-detail",children:U2("div",{className:"container mx-auto px-6 md:px-8 py-12 md:py-20",children:[U2("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),U2("div",{className:"flex items-start gap-6 mb-8",children:[U2(Nf0,{name:w.name,className:"w-[72px] h-[72px] text-3xl"},void 0,!1,void 0,this),U2("div",{children:[U2("div",{className:"flex items-center gap-3 mb-1",children:[U2("h1",{className:"text-3xl md:text-4xl font-bold text-heading",children:w.name},void 0,!1,void 0,this),U2(jf0,{kind:w.kind},void 0,!1,void 0,this)]},void 0,!0,void 0,this),U2("div",{className:"text-base text-theme-muted mb-2",children:w.brainName},void 0,!1,void 0,this),U2("div",{className:"flex items-center gap-3 text-theme-muted",children:[w.organization&&U2("span",{className:"text-[15px]",children:w.organization},void 0,!1,void 0,this),w.organization&&U2("span",{className:"text-theme-muted opacity-40",children:"\xB7"},void 0,!1,void 0,this),U2("span",{className:"text-sm",children:["Discovered ",RUB(w.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),U2("div",{className:"border-b border-theme mb-8"},void 0,!1,void 0,this),!X&&U2("div",{className:"mb-8 rounded-xl border border-theme bg-theme-subtle px-5 py-4",children:[U2("div",{className:"text-sm font-semibold text-heading mb-1",children:"Saved for review"},void 0,!1,void 0,this),U2("p",{className:"text-sm text-theme-muted",children:"This brain is discovered but not approved yet, so it cannot be called until you approve it."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),U2("div",{className:"flex flex-col md:flex-row gap-12",children:[U2("div",{className:"flex-[2] min-w-0",children:[$&&U2("section",{className:"mb-8",children:[U2(jo,{children:"About"},void 0,!1,void 0,this),U2("p",{className:"text-[15px] text-theme leading-relaxed",children:$},void 0,!1,void 0,this)]},void 0,!0,void 0,this),D.length>0&&U2("section",{className:"mb-8",children:[U2(jo,{children:"Skills"},void 0,!1,void 0,this),U2("div",{className:"flex flex-col gap-2.5",children:D.map((H)=>U2(vUB,{skill:H},H.name,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),f&&U2("section",{className:"mb-8",children:[U2(jo,{children:"Notes"},void 0,!1,void 0,this),U2("p",{className:"text-[15px] text-theme leading-relaxed",children:f},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U2("aside",{className:"flex-1 md:pl-8 md:border-l border-theme-muted/20",children:[U2("section",{className:"mb-8",children:[U2(jo,{children:"Brain"},void 0,!1,void 0,this),U2("div",{className:"p-4 bg-theme-subtle rounded-xl",children:[U2("div",{className:"text-[15px] font-semibold text-heading mb-1",children:w.brainName},void 0,!1,void 0,this),w.did&&U2("div",{className:"text-xs text-theme-muted font-mono",children:w.did},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U2("section",{className:"mb-8",children:[U2(jo,{children:"Connection"},void 0,!1,void 0,this),U2("div",{className:"flex flex-col gap-3",children:[U2("div",{children:[U2("div",{className:"text-[13px] text-theme-muted mb-0.5",children:"Endpoint"},void 0,!1,void 0,this),U2("div",{className:"text-xs text-heading font-mono",children:w.url},void 0,!1,void 0,this)]},void 0,!0,void 0,this),U2(hUB,{label:"Status",value:w.status==="approved"?"Approved":"Discovered",valueClassName:w.status==="approved"?"text-status-success font-medium":"text-theme-muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),U2("a",{href:w.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 ",Y," \u2197"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),(Q??B)&&U2("nav",{className:"mt-12 pt-6 border-t border-theme flex flex-col gap-3 md:flex-row md:items-center md:justify-between",children:[U2("div",{className:"min-h-[1px]",children:Q&&U2("a",{href:Q.url,className:"inline-flex flex-col text-sm text-theme-muted hover:text-heading transition-colors",children:[U2("span",{children:"\u2190 Previous"},void 0,!1,void 0,this),U2("span",{className:"text-heading font-medium",children:Q.frontmatter.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),U2("div",{className:"min-h-[1px] md:text-right",children:B&&U2("a",{href:B.url,className:"inline-flex flex-col text-sm text-theme-muted hover:text-heading transition-colors",children:[U2("span",{children:"Next \u2192"},void 0,!1,void 0,this),U2("span",{className:"text-heading font-medium",children:B.frontmatter.name},void 0,!1,void 0,this)]},void 0,!0,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,!0,void 0,this)};var yUB=K.object({agents:K.array(PE),pageTitle:K.string().optional(),pagination:e7.nullable(),baseUrl:K.string().optional(),selectedStatus:K.union([K.literal("all"),HW])});function ea1(){return{[dn0]:R1({name:dn0,description:"Agent directory list page template",schema:yUB,dataSourceId:bo,requiredPermission:"public",layout:{component:aa1}}),[nn0]:R1({name:nn0,description:"Individual agent profile template",schema:K.object({agent:PE,prevAgent:PE.nullable(),nextAgent:PE.nullable()}),dataSourceId:bo,requiredPermission:"public",layout:{component:ta1}})}}var _f0={name:"@brains/agent-discovery",private:!0,version:"0.2.0-alpha.129",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,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/atproto-contracts":"workspace:*","@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var gUB=new cf;class tn0 extends PQ{entityType=R7;schema=ME;adapter=gUB;constructor(){super(Ja1,_f0)}interceptCreate(A,Q,B){return Ta1(A,Q,B,this.id)}createGenerationHandler(A){return new rn0(this.logger.child("AgentGenerationJobHandler"),A)}getTemplates(){return ea1()}getDataSources(){return[new If0(this.logger.child("AgentDataSource"))]}async onRegister(A){na1(A),ia1(A,this.id)}async getInstructions(){return ra1()}}function en0(){return new tn0}p0();K0();p0();var kE=_Y,At1=_Y,_o=o1.extend({entityType:K.literal(z5),metadata:At1});p0();class OE extends V2{constructor(){super({entityType:z5,schema:_o,frontmatterSchema:kE})}fromMarkdown(A){let Q=this.parseFrontMatter(A,kE);return{content:A,entityType:z5,metadata:Q}}createSkillContent(A){return this.buildMarkdown("",A)}}p0();K0();var TUB=K.object({skills:K.array(kE).max(8)}),Qt1=R1({name:"skill:skill-derivation",description:"Derive skills from topic titles and brain capabilities",dataSourceId:"shell:ai-content",schema:TUB,useKnowledgeContext:!0,basePrompt:`You are analyzing a brain's content to identify its high-level capabilities.
|
|
8598
8598
|
|
|
8599
8599
|
Given knowledge domains, CONSOLIDATE related topics into broader skills.
|
|
8600
8600
|
There should be FEWER skills than topics \u2014 combine related domains.
|
|
@@ -8744,9 +8744,9 @@ Context:
|
|
|
8744
8744
|
${JSON.stringify(w,null,2)}
|
|
8745
8745
|
|
|
8746
8746
|
Draft SWOT:
|
|
8747
|
-
${JSON.stringify(B,null,2)}`}function hf0(A){return A.map((Q)=>Q.detail===null?{title:Q.title}:{title:Q.title,detail:Q.detail})}function fGB(A,Q){let B=["strengths","weaknesses","opportunities","threats"];for(let w of B){let $=new Set(A[w].map((D)=>D.theme.trim().toLowerCase()));for(let D of Q[w]){let f=D.sourceTheme.trim().toLowerCase();if(!$.has(f))throw Error(`SWOT refinement invented theme "${D.sourceTheme}" in ${w}`)}}}class Cf0{logger;context;adapter=new IF;constructor(A,Q){this.logger=A;this.context=Q}validateAndParse(A){let Q=Br0.safeParse(A??{});return Q.success?Q.data:null}async process(A,Q,B){await B.report({progress:0.2,message:"Building SWOT context"});let w=await Yr0(this.context),$;if(w.summary.brainSkillCount+w.summary.approvedAgentCount+w.summary.discoveredAgentCount===0)$={strengths:[],weaknesses:[],opportunities:[],threats:[]};else{await B.report({progress:0.6,message:"Synthesizing SWOT analysis"});let{object:H}=await this.context.ai.generateObject(await wGB(this.context,w),wr0),W=wr0.parse(H);await B.report({progress:0.75,message:"Refining SWOT language"});let Z=await this.context.ai.generateObject(await DGB(this.context,w,W),xf0);$=xf0.parse(Z.object),fGB(W,$)}let f=new Date().toISOString(),Y=this.adapter.createSwotContent({strengths:hf0($.strengths),weaknesses:hf0($.weaknesses),opportunities:hf0($.opportunities),threats:hf0($.threats),derivedAt:f});await B.report({progress:0.9,message:"Saving SWOT entity"});let X=await this.context.entityService.getEntity({entityType:"swot",id:"swot"});if(X)await this.context.entityService.updateEntity({entity:{...X,content:Y,metadata:{derivedAt:f}}});else await this.context.entityService.createEntity({entity:{id:"swot",entityType:"swot",content:Y,metadata:{derivedAt:f}}});return this.logger.info("SWOT derivation complete",{derivedAt:f,brainSkillCount:w.summary.brainSkillCount,approvedAgentCount:w.summary.approvedAgentCount,discoveredAgentCount:w.summary.discoveredAgentCount}),{entityId:"swot"}}}K0();import{jsxDEV as P4}from"preact/jsx-dev-runtime";var yf0=K.object({title:K.string(),detail:K.string().optional()}),YGB=K.discriminatedUnion("status",[K.object({status:K.literal("generating")}),K.object({status:K.literal("ready"),strengths:K.array(yf0).default([]),weaknesses:K.array(yf0).default([]),opportunities:K.array(yf0).default([]),threats:K.array(yf0).default([]),derivedAt:K.string()})]);function XGB({items:A}){if(A.length===0)return P4("p",{class:"swot-empty",children:"\u2014"},void 0,!1,void 0,this);return P4("ul",{class:"swot-list",children:A.map((Q)=>P4("li",{class:"swot-item",children:[P4("b",{children:Q.title},void 0,!1,void 0,this),Q.detail?P4("span",{children:[" \u2014 ",Q.detail]},void 0,!0,void 0,this):null]},`${Q.title}:${Q.detail??""}`,!0,void 0,this))},void 0,!1,void 0,this)}function Ef0({title:A,tone:Q,items:B}){return P4("section",{class:`swot-cell is-${Q}`,children:[P4("div",{class:"swot-head",children:A},void 0,!1,void 0,this),P4(XGB,{items:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Wr0({data:A}){let Q=YGB.safeParse(A);if(!Q.success||Q.data.status==="generating")return P4("div",{"data-swot-widget":!0,children:P4("p",{class:"muted",children:"generating assessment\u2026"},void 0,!1,void 0,this)},void 0,!1,void 0,this);let B=Q.data;return P4("div",{"data-swot-widget":!0,children:P4("div",{class:"swot",role:"grid","aria-label":"SWOT analysis of agent network",children:[P4(Ef0,{title:"Strengths",tone:"s",items:B.strengths},void 0,!1,void 0,this),P4(Ef0,{title:"Weaknesses",tone:"w",items:B.weaknesses},void 0,!1,void 0,this),P4(Ef0,{title:"Opportunities",tone:"o",items:B.opportunities},void 0,!1,void 0,this),P4(Ef0,{title:"Threats",tone:"t",items:B.threats},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}K0();var Zr0={name:"@brains/assessment",private:!0,version:"0.2.0-alpha.
|
|
8747
|
+
${JSON.stringify(B,null,2)}`}function hf0(A){return A.map((Q)=>Q.detail===null?{title:Q.title}:{title:Q.title,detail:Q.detail})}function fGB(A,Q){let B=["strengths","weaknesses","opportunities","threats"];for(let w of B){let $=new Set(A[w].map((D)=>D.theme.trim().toLowerCase()));for(let D of Q[w]){let f=D.sourceTheme.trim().toLowerCase();if(!$.has(f))throw Error(`SWOT refinement invented theme "${D.sourceTheme}" in ${w}`)}}}class Cf0{logger;context;adapter=new IF;constructor(A,Q){this.logger=A;this.context=Q}validateAndParse(A){let Q=Br0.safeParse(A??{});return Q.success?Q.data:null}async process(A,Q,B){await B.report({progress:0.2,message:"Building SWOT context"});let w=await Yr0(this.context),$;if(w.summary.brainSkillCount+w.summary.approvedAgentCount+w.summary.discoveredAgentCount===0)$={strengths:[],weaknesses:[],opportunities:[],threats:[]};else{await B.report({progress:0.6,message:"Synthesizing SWOT analysis"});let{object:H}=await this.context.ai.generateObject(await wGB(this.context,w),wr0),W=wr0.parse(H);await B.report({progress:0.75,message:"Refining SWOT language"});let Z=await this.context.ai.generateObject(await DGB(this.context,w,W),xf0);$=xf0.parse(Z.object),fGB(W,$)}let f=new Date().toISOString(),Y=this.adapter.createSwotContent({strengths:hf0($.strengths),weaknesses:hf0($.weaknesses),opportunities:hf0($.opportunities),threats:hf0($.threats),derivedAt:f});await B.report({progress:0.9,message:"Saving SWOT entity"});let X=await this.context.entityService.getEntity({entityType:"swot",id:"swot"});if(X)await this.context.entityService.updateEntity({entity:{...X,content:Y,metadata:{derivedAt:f}}});else await this.context.entityService.createEntity({entity:{id:"swot",entityType:"swot",content:Y,metadata:{derivedAt:f}}});return this.logger.info("SWOT derivation complete",{derivedAt:f,brainSkillCount:w.summary.brainSkillCount,approvedAgentCount:w.summary.approvedAgentCount,discoveredAgentCount:w.summary.discoveredAgentCount}),{entityId:"swot"}}}K0();import{jsxDEV as P4}from"preact/jsx-dev-runtime";var yf0=K.object({title:K.string(),detail:K.string().optional()}),YGB=K.discriminatedUnion("status",[K.object({status:K.literal("generating")}),K.object({status:K.literal("ready"),strengths:K.array(yf0).default([]),weaknesses:K.array(yf0).default([]),opportunities:K.array(yf0).default([]),threats:K.array(yf0).default([]),derivedAt:K.string()})]);function XGB({items:A}){if(A.length===0)return P4("p",{class:"swot-empty",children:"\u2014"},void 0,!1,void 0,this);return P4("ul",{class:"swot-list",children:A.map((Q)=>P4("li",{class:"swot-item",children:[P4("b",{children:Q.title},void 0,!1,void 0,this),Q.detail?P4("span",{children:[" \u2014 ",Q.detail]},void 0,!0,void 0,this):null]},`${Q.title}:${Q.detail??""}`,!0,void 0,this))},void 0,!1,void 0,this)}function Ef0({title:A,tone:Q,items:B}){return P4("section",{class:`swot-cell is-${Q}`,children:[P4("div",{class:"swot-head",children:A},void 0,!1,void 0,this),P4(XGB,{items:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Wr0({data:A}){let Q=YGB.safeParse(A);if(!Q.success||Q.data.status==="generating")return P4("div",{"data-swot-widget":!0,children:P4("p",{class:"muted",children:"generating assessment\u2026"},void 0,!1,void 0,this)},void 0,!1,void 0,this);let B=Q.data;return P4("div",{"data-swot-widget":!0,children:P4("div",{class:"swot",role:"grid","aria-label":"SWOT analysis of agent network",children:[P4(Ef0,{title:"Strengths",tone:"s",items:B.strengths},void 0,!1,void 0,this),P4(Ef0,{title:"Weaknesses",tone:"w",items:B.weaknesses},void 0,!1,void 0,this),P4(Ef0,{title:"Opportunities",tone:"o",items:B.opportunities},void 0,!1,void 0,this),P4(Ef0,{title:"Threats",tone:"t",items:B.threats},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}K0();var Zr0={name:"@brains/assessment",private:!0,version:"0.2.0-alpha.129",description:"Assessment outputs and capability-profile analysis",type:"module",exports:{".":"./src/index.ts"},scripts:{typecheck:"tsc --noEmit",test:"bun test",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix",eval:"cd evals && bun run brain-eval"},dependencies:{"@brains/content-formatters":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var Kr0=new IF;class Ur0 extends PQ{entityType="swot";schema=xE;adapter=Kr0;initialSyncComplete=!1;constructor(){super("swot",Zr0)}async onRegister(A){let Q=new Cf0(this.logger.child("SwotDerivationHandler"),A);A.jobs.registerHandler("derive",Q),A.eval.registerHandler("deriveSwot",async()=>{let D=D7.from(async()=>{});if(!D)throw Error("Expected progress reporter to be created");await Q.process({reason:"eval"},"eval-swot-derive",D);let f=await A.entityService.getEntity({entityType:"swot",id:"swot"});if(!f)throw Error("Expected SWOT entity to be created during eval");return Kr0.parseSwotContent(f.content).frontmatter});let B=async(D)=>{try{return await A.jobs.enqueue({type:"derive",data:{reason:D},options:{source:this.id,priority:10,deduplication:"coalesce",deduplicationKey:"swot",metadata:{operationType:"data_processing",operationTarget:`swot:${D}`}}})}catch(f){return this.logger.error("Failed to queue SWOT derivation",{error:f,reason:D}),null}},w=async(D)=>{if(!await A.entityService.getEntity({entityType:"swot",id:"swot"}))await B(D)};A.messaging.subscribe("sync:initial:completed",async()=>{return this.initialSyncComplete=!0,await w("initial-missing-entity"),{success:!0}}),A.messaging.subscribe("system:plugins:ready",async()=>{return await A.messaging.send({type:"dashboard:register-widget",payload:{id:"swot",pluginId:this.id,title:"SWOT",section:"secondary",priority:14,rendererName:"SwotWidget",component:Wr0,dataProvider:async()=>{let D=await A.entityService.getEntity({entityType:"swot",id:"swot"});if(!D)return{status:"generating"};let{frontmatter:f}=Kr0.parseSwotContent(D.content);return{status:"ready",...f}}}}),{success:!0}});let $=async(D)=>{let{entityType:f}=D.payload;if(!this.initialSyncComplete)return{success:!0};if(f!=="agent"&&f!=="skill")return{success:!0};return await B("entity-change"),{success:!0}};A.messaging.subscribe("entity:created",$),A.messaging.subscribe("entity:updated",$),A.messaging.subscribe("entity:deleted",$)}}function Gr0(){return new Ur0}p0();p$();K0();var N96=new IF,zt1=K.object({name:K.string(),description:K.string(),tags:K.array(K.string())}),zr0=K.enum(["discovered","approved"]),WGB=K.object({name:K.string(),kind:K.enum(["professional","team","collective"]),organization:K.string().optional(),brainName:K.string(),url:K.string().url(),did:K.string().optional(),status:zr0,discoveredAt:K.string().datetime()}),ZGB=o1.extend({entityType:K.literal("agent"),metadata:K.object({name:K.string(),url:K.string().url(),status:zr0,slug:K.string()})}),KGB=o1.extend({entityType:K.literal("skill"),metadata:_Y}),UGB=K.object({about:K.string(),skills:K.array(zt1),notes:K.string()});function GGB(A){if(!Array.isArray(A)||A.length===0)return"";return A.map((B)=>{let w=B.tags.length>0?` [${B.tags.join(", ")}]`:"";return`- ${B.name}: ${B.description}${w}`}).join(`
|
|
8748
8748
|
`)}function zGB(A){if(!A.trim())return[];return A.split(`
|
|
8749
|
-
`).map((Q)=>Q.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/)).filter((Q)=>Q!==null).map((Q)=>({name:Q[1]??"",description:Q[2]??"",tags:Q[3]?Q[3].split(",").map((B)=>B.trim()).filter(Boolean):[]}))}var qGB=new pB(UGB,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:GGB,parser:zGB},{key:"notes",label:"Notes",type:"string"}]});class qt1 extends V2{constructor(){super({entityType:"agent",schema:ZGB,frontmatterSchema:WGB})}fromMarkdown(A){return{content:A,entityType:"agent"}}createAgentContent(A){let Q=qGB.format({about:A.about,skills:A.skills,notes:A.notes});return this.buildMarkdown(Q,{name:A.name,kind:A.kind,...A.organization?{organization:A.organization}:{},brainName:A.brainName,url:A.url,...A.did?{did:A.did}:{},status:A.status,discoveredAt:A.discoveredAt})}}class Ft1 extends V2{constructor(){super({entityType:"skill",schema:KGB,frontmatterSchema:_Y})}fromMarkdown(A){let Q=this.parseFrontMatter(A,_Y);return{content:A,entityType:"skill",metadata:Q}}createSkillContent(A){return this.buildMarkdown("",A)}}var j96=new qt1,_96=new Ft1,M96=K.object({skills:K.array(_Y),agents:K.array(K.object({id:K.string().optional(),name:K.string(),kind:K.enum(["professional","team","collective"]),organization:K.string().optional(),brainName:K.string(),url:K.string().url(),did:K.string().optional(),status:zr0,discoveredAt:K.string().datetime().optional(),about:K.string(),skills:K.array(zt1),notes:K.string().default("")}))});var FGB=K.object({}).strict();function gf0(A={}){return FGB.parse(A),[Gr0()]}p0();K0();K0();var qr0=K.object({enabled:K.boolean().default(!0),pdsEndpoint:K.string().url().default("https://bsky.social").describe("AT Protocol PDS service endpoint"),identifier:K.string().optional().describe("PDS login identifier, usually a handle or account DID"),repoDid:K.string().optional().describe("DID of the PDS repo that owns records"),appPassword:K.string().optional().describe("App password for prototype authentication; supply via ${ENV_VAR} interpolation, never a committed literal"),anchorDid:K.string().optional().describe("Optional human/operator DID referenced from records; defaults to did:web:<site-host>:anchor when omitted"),brainDid:K.string().optional().describe("Optional public brain DID referenced from records; defaults to did:web:<site-host> when omitted")});function IGB(A){return A.replace(/\/+$/,"")}var VGB=(A,Q)=>fetch(A,Q);async function Po(A){let Q=await A.json();if(!A.ok){let B=typeof Q==="object"&&Q!==null&&"message"in Q&&typeof Q.message==="string"?Q.message:`AT Protocol request failed with ${A.status}`;throw Error(B)}return Q}class ko{pdsEndpoint;identifier;appPassword;fetchFn;session;constructor(A){this.pdsEndpoint=IGB(A.pdsEndpoint),this.identifier=A.identifier,this.appPassword=A.appPassword,this.fetchFn=A.fetch??VGB}async createSession(){let A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.server.createSession`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({identifier:this.identifier,password:this.appPassword})}),Q=await Po(A);return this.session=Q,Q}async createRecord(A){let Q=await this.getSession(),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.createRecord`,{method:"POST",headers:{Authorization:`Bearer ${Q.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:A.repo,collection:A.collection,record:A.record,...A.rkey&&{rkey:A.rkey},...A.validate!==void 0&&{validate:A.validate}})});return Po(B)}async putRecord(A){let Q=await this.getSession(),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.putRecord`,{method:"POST",headers:{Authorization:`Bearer ${Q.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:A.repo,collection:A.collection,record:A.record,rkey:A.rkey,...A.validate!==void 0&&{validate:A.validate},...A.swapRecord!==void 0&&{swapRecord:A.swapRecord}})});return Po(B)}async getRecord(A){let Q=new URLSearchParams({repo:A.repo,collection:A.collection,rkey:A.rkey}),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.getRecord?${Q.toString()}`,{method:"GET"});return Po(B)}async uploadBlob(A){let Q=await this.getSession(),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.uploadBlob`,{method:"POST",headers:{Authorization:`Bearer ${Q.accessJwt}`,"Content-Type":A.mimeType},body:new Blob([new Uint8Array(A.data)],{type:A.mimeType})});return Po(B)}async getSession(){return this.session??=await this.createSession(),this.session}}function RP(A){return A?.startsWith("did:web:")??!1}function Tf0(A){if(!RP(A))return;let Q=A.slice(8);if(!Q)return;let[B]=Q.split(":");if(!B)return;try{return decodeURIComponent(B)}catch{return B}}function Vt1(A){if(!RP(A))return;let Q=A.slice(8);if(!Q)return;let[,...B]=Q.split(":");if(B.length===0)return"/.well-known/did.json";return`/${B.map(($)=>{try{return decodeURIComponent($)}catch{return $}}).join("/")}/did.json`}function Jt1(A){return A.replace(/\/+$/,"")}function Oo(A){return`did:web:${encodeURIComponent(A)}`}function Sf0(A){return`${Oo(A)}:anchor`}function Fr0(A){return{"@context":["https://www.w3.org/ns/did/v1"],id:A}}function Lt1(A,Q){let B=A.identifier?.startsWith("did:")?void 0:A.identifier?[`at://${A.identifier}`]:void 0;return{...Fr0(Q),...B&&{alsoKnownAs:B},service:[{id:"#atproto_pds",type:"AtprotoPersonalDataServer",serviceEndpoint:Jt1(A.pdsEndpoint)}]}}function bt1(A){if(!RP(A.brainDid))return null;return Lt1(A,A.brainDid)}function It1(A,Q){if(!A||!Q)return;let B=Tf0(A),w=Vt1(A);if(!B||!w)return;return{path:w,hostname:B,document:Q}}function mf0(A){let Q=[],B=It1(A.brainDid,bt1(A));if(B)Q.push(B);if(RP(A.anchorDid)&&A.anchorDid!==A.brainDid){let w=It1(A.anchorDid,Fr0(A.anchorDid));if(w)Q.push(w)}return Q}function Ir0(A,Q){let B=[];if(!A.brainDid){let w=Oo(Q);B.push({path:"/.well-known/did.json",hostname:Q,document:Lt1(A,w)})}if(!A.anchorDid){let w=Sf0(Q);B.push({path:"/anchor/did.json",hostname:Q,document:Fr0(w)})}return B}function JGB(A,Q){if(!A)return;try{return new URL(A,Q).toString()}catch{return}}function LGB(A){let Q=A.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,200);return Q.length>0?Q:"skill"}function Nt1(A,Q){let B=A[Q];return typeof B==="string"&&B.length>0?B:void 0}function jt1(A,Q){let B=A[Q];if(!Array.isArray(B))return;let w=B.filter(($)=>typeof $==="string"&&$.length>0);return w.length>0?w:void 0}function bGB(A){let Q=A.metadata,B=Nt1(Q,"name"),w=Nt1(Q,"description");if(!B||!w)return;let $=jt1(Q,"tags"),D=jt1(Q,"examples");return{id:LGB(B),name:B,description:w,...$&&{tags:$},...D&&{examples:D}}}async function NGB(A){if(!A.entityService.hasEntityType("skill"))return[];return(await A.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}})).map((B)=>bGB(B)).filter((B)=>B!==void 0).slice(0,100)}async function Vr0(A,Q,B=new Date){let w=A.identity.get(),$=A.identity.getProfile(),D=await A.identity.getAppInfo(),f=JGB(A.siteUrl??$.website,void 0);if(!f)throw Error("AT Protocol brain card publishing requires siteUrl");let Y=new URL(f).hostname,X=Q.brainDid??Oo(Y),H=Q.anchorDid??Sf0(Y);if(RP(X)){if(Tf0(X)!==Y)throw Error("AT Protocol brain card did:web host must match siteUrl host")}let W=await NGB(A);return{$type:"ai.rizom.brain.card",siteUrl:f,brain:{did:X,name:w.name,role:w.role,purpose:w.purpose,values:w.values},anchor:{did:H,name:$.name,kind:$.kind},skills:W,model:D.model,version:D.version,createdAt:B.toISOString(),updatedAt:B.toISOString()}}K0();var _t1={dryRun:K.boolean().default(!1).describe("Build and return the card record without writing to the PDS")},jGB={},Mt1={entityType:K.string().describe("Local entity type with a registered AT Protocol projection"),entityId:K.string().optional().describe("Local entity ID to publish"),slug:K.string().optional().describe("Local entity slug to publish"),dryRun:K.boolean().default(!1).describe("Build and return the record without writing to the PDS"),topics:K.array(K.string()).optional().describe("Optional topic labels to include in the AT Protocol record")},Pt1={repos:K.array(K.string().min(1)).min(1).max(50).describe("Candidate AT Protocol repo DIDs or handles to inspect")},kt1={entityId:K.string().optional().describe("Local blog post entity ID to publish"),slug:K.string().optional().describe("Local blog post slug to publish"),dryRun:K.boolean().default(!1).describe("Build and return the post record without writing to the PDS"),topics:K.array(K.string()).optional().describe("Optional topic labels to include in the AT Protocol record")};function Ot1(A,Q,B){return[_GB(A,Q),MGB(A,Q,B),PGB(A,Q,B),OGB(A,Q,B),kGB(A,Q,B)]}function _GB(A,Q){return{name:`${A}_validate_credentials`,description:"Validate AT Protocol PDS credentials without publishing records.",inputSchema:jGB,handler:async()=>{return{success:!0,data:{valid:await Q.validatePdsCredentials()}}}}}function MGB(A,Q,B){return{name:`${A}_publish_card`,description:"Publish this brain's AT Protocol discovery card to the configured PDS, or dry-run the record payload.",inputSchema:_t1,handler:async(w)=>{let $=K.object(_t1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{return{success:!0,data:await Q.publishBrainCard(B,{dryRun:$.data.dryRun})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Publish failed"}}}}}function PGB(A,Q,B){return{name:`${A}_publish_entity`,description:"Publish any public local entity with a registered AT Protocol projection, or dry-run the record payload.",inputSchema:Mt1,handler:async(w)=>{let $=K.object(Mt1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{if(!$.data.entityId&&!$.data.slug)return{success:!1,error:"Invalid input: entityId or slug is required"};return{success:!0,data:await Q.publishEntity(B,{entityType:$.data.entityType,...$.data.entityId&&{entityId:$.data.entityId},...$.data.slug&&{slug:$.data.slug},dryRun:$.data.dryRun,...$.data.topics&&{topics:$.data.topics}})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Publish failed"}}}}}function kGB(A,Q,B){return{name:`${A}_discover_brain_cards`,description:"Read public ai.rizom.brain.card/self records from candidate AT Protocol repo DIDs or handles and emit internal discovery events.",inputSchema:Pt1,handler:async(w)=>{let $=K.object(Pt1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{return{success:!0,data:await Q.discoverBrainCards(B,{repos:$.data.repos})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Discovery failed"}}}}}function OGB(A,Q,B){return{name:`${A}_publish_post`,description:"Publish a local blog post entity as an ai.rizom.brain.post AT Protocol record, or dry-run the record payload.",inputSchema:kt1,handler:async(w)=>{let $=K.object(kt1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{if(!$.data.entityId&&!$.data.slug)return{success:!1,error:"Invalid input: entityId or slug is required"};return{success:!0,data:await Q.publishPost(B,{...$.data.entityId&&{entityId:$.data.entityId},...$.data.slug&&{slug:$.data.slug},dryRun:$.data.dryRun,...$.data.topics&&{topics:$.data.topics}})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Publish failed"}}}}}var xt1={name:"@brains/atproto",private:!0,version:"0.2.0-alpha.128",description:"AT Protocol integration for identity, publishing, discovery, and feeds",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/atproto-contracts":"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 Rt1=_w["ai.rizom.brain.card"],RGB="ai.rizom.brain.card",vGB="self",vt1=50;class Jr0 extends pQ{deps;projectionRegistry;constructor(A={},Q={}){super("atproto",xt1,A,qr0);this.deps=Q,this.projectionRegistry=Q.projectionRegistry??U5.getInstance()}getWebRoutes(){if(!this.config.enabled)return[];let A=mf0(this.config),Q=[...!this.config.brainDid?["/.well-known/did.json"]:[],...!this.config.anchorDid?["/anchor/did.json"]:[]];return[...new Set([...A.map((w)=>w.path),...Q])].map((w)=>({path:w,method:"GET",public:!0,handler:($)=>{let D=new URL($.url).hostname,f=[...mf0(this.config),...Ir0(this.config,D)].filter((X)=>X.path===w),Y=f.find((X)=>X.hostname===D)??f[0];if(!Y)return new Response("Not found",{status:404});return new Response(JSON.stringify(Y.document),{headers:{"Content-Type":"application/did+json"}})}}))}async publishBrainCard(A,Q={}){let B=await Vr0(A,this.config);FL(Rt1,B);let w=this.config.repoDid;if(Q.dryRun)return{record:B,dryRun:!0,...w&&{repo:w}};let $=this.resolveAppPassword();if(!this.config.identifier||!$)throw Error("AT Protocol publishing requires identifier and app password configuration");let D=this.createPdsClient($),f=await D.createSession(),Y=w??f.did;if(!D.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let X=await D.putRecord({repo:Y,collection:"ai.rizom.brain.card",rkey:"self",validate:!1,record:B});return{record:B,repo:Y,uri:X.uri,cid:X.cid,dryRun:!1}}async publishEntity(A,Q){let B=this.projectionRegistry.get(Q.entityType);if(!B)throw Error(`No AT Protocol projection registered for ${Q.entityType}`);return this.publishProjectedEntity(A,Q,B)}async publishPost(A,Q){let B=this.projectionRegistry.get("post");if(!B)throw Error("No AT Protocol projection registered for post");return this.publishProjectedEntity(A,{entityType:"post",...Q},B)}async discoverBrainCards(A,Q){let B=[...new Set(Q.repos.map((D)=>D.trim()))].filter((D)=>D.length>0);if(B.length===0)throw Error("AT Protocol discovery requires at least one repo DID or handle");if(B.length>vt1)throw Error(`AT Protocol discovery accepts at most ${vt1} repos per batch`);let w=new Set,$=[];for(let D of B)try{let f=await this.resolveRepoPdsEndpoint(D),Y=this.createPublicPdsClient(f.pdsEndpoint);if(!Y.getRecord)throw Error("AT Protocol PDS client does not support record reads");let X=await Y.getRecord({repo:f.repoDid,collection:RGB,rkey:vGB});FL(Rt1,X.value);let H=CGB(X.uri)??f.repoDid,W=`${H}:${X.uri}:${X.cid}`;if(w.has(W)){$.push({repo:D,status:"skipped",repoDid:H,uri:X.uri,cid:X.cid,error:"Duplicate brain card in discovery batch"});continue}w.add(W),await A.messaging.send({type:V40,payload:{repoDid:H,uri:X.uri,cid:X.cid,record:X.value},broadcast:!0}),$.push({repo:D,status:"discovered",repoDid:H,uri:X.uri,cid:X.cid})}catch(f){$.push({repo:D,status:"skipped",error:hA(f)})}return{discovered:$.filter((D)=>D.status==="discovered").length,skipped:$.filter((D)=>D.status==="skipped").length,results:$}}async validatePdsCredentials(){let A=this.resolveAppPassword();if(!this.config.identifier||!A)return!1;try{return await this.createPdsClient(A).createSession(),!0}catch(Q){return this.logger.warn("AT Protocol PDS authentication failed",{error:hA(Q)}),!1}}async getTools(){if(!this.config.enabled)return[];return Ot1(this.id,this,this.getContext())}async getInstructions(){if(!this.config.enabled)return;return"## AT Protocol publishing\n- Use `atproto_validate_credentials` to check PDS credentials before publishing.\n- Use `atproto_publish_card` to publish or dry-run this brain's public discovery card.\n- Use `atproto_publish_entity` to publish any public entity with a registered AT Protocol projection.\n- Use `atproto_publish_post` for the blog-post convenience path by `entityId` or `slug`.\n- Use `atproto_discover_brain_cards` to read public `ai.rizom.brain.card/self` records from candidate repo DIDs or handles and emit internal discovery events.\n- Prefer `dryRun: true` first when publishing new AT Protocol records.\n- Only public posts and public cover images can be published."}async publishProjectedEntity(A,Q,B){let w=await this.findPublishEntity(A,Q),$=Q.entityId??Q.slug;if(!$)throw Error(`${Q.entityType} publish requires entityId or slug`);if(!w)throw Error(`${Q.entityType} not found: ${$}`);if(w.visibility!=="public")throw Error(`Cannot publish non-public ${Q.entityType}: ${$}`);let D=this.config.repoDid;if(Q.dryRun){let G=await B.buildRecord({entity:w,context:A,config:this.config,...Q.topics&&{topics:Q.topics},dryRun:!0});return FL(B.lexicon,G),{record:G,dryRun:!0,...D&&{repo:D}}}let f=this.resolveAppPassword();if(!this.config.identifier||!f)throw Error("AT Protocol publishing requires identifier and app password configuration");let Y=this.createPdsClient(f),X=await Y.createSession(),H=D??X.did,W=await B.buildRecord({entity:w,context:A,config:this.config,client:Y,...Q.topics&&{topics:Q.topics}});if(FL(B.lexicon,W),!Y.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let Z=await Y.putRecord({repo:H,collection:B.collection,rkey:hGB(w.id),...B.validate!==void 0&&{validate:B.validate},record:W});return await B.onPublished?.({entity:w,context:A,record:W,uri:Z.uri,cid:Z.cid}),{record:W,repo:H,uri:Z.uri,cid:Z.cid,dryRun:!1}}async findPublishEntity(A,Q){if(Q.entityId)return A.entityService.getEntity({entityType:Q.entityType,id:Q.entityId});if(Q.slug)return(await A.entityService.listEntities({entityType:Q.entityType,options:{filter:{metadata:{slug:Q.slug}}}}))[0]??null;return null}createPublicPdsClient(A){if(this.deps.createPdsClient)return this.deps.createPdsClient({pdsEndpoint:A,identifier:this.config.identifier??"",appPassword:this.config.appPassword??""});return new ko({pdsEndpoint:A,identifier:this.config.identifier??"",appPassword:this.config.appPassword??""})}async resolveRepoPdsEndpoint(A){let Q=A.startsWith("did:")?A:await this.resolveHandleToDid(A);if(!Q)throw Error(`Could not resolve AT Protocol repo: ${A}`);let B=await this.resolveDidToPdsEndpoint(Q);if(!B)throw Error(`Could not resolve AT Protocol PDS for repo: ${Q}`);return{repoDid:Q,pdsEndpoint:B}}async resolveHandleToDid(A){let Q=new URL("/xrpc/com.atproto.identity.resolveHandle",this.config.pdsEndpoint);Q.searchParams.set("handle",A);let B=await this.fetch(Q.toString());if(!B.ok)return;let w=await B.json();if(typeof w!=="object"||w===null||!("did"in w))return;return typeof w.did==="string"?w.did:void 0}async resolveDidToPdsEndpoint(A){let Q=A.startsWith("did:plc:")?await this.fetchJson(`https://plc.directory/${encodeURIComponent(A)}`):A.startsWith("did:web:")?await this.fetchJson(yGB(A)):void 0;if(typeof Q!=="object"||Q===null)return;let B=Q.service;if(!Array.isArray(B))return;let w=B.find(($)=>{return typeof $==="object"&&$!==null&&($.id==="#atproto_pds"||$.type==="AtprotoPersonalDataServer")});return typeof w?.serviceEndpoint==="string"?w.serviceEndpoint:void 0}async fetchJson(A){let Q=await this.fetch(A);if(!Q.ok)return;return Q.json()}fetch(A){return(this.deps.fetch??fetch)(A)}createPdsClient(A){if(this.deps.createPdsClient)return this.deps.createPdsClient({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:A});return new ko({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:A})}resolveAppPassword(){return this.config.appPassword}}function hGB(A){let Q=A.replace(/[^A-Za-z0-9._~:-]/g,"_").slice(0,512);return Q.length>0?Q:"self"}function CGB(A){return/^at:\/\/([^/]+)/.exec(A)?.[1]}function yGB(A){let Q=A.slice(8).split(":").map(decodeURIComponent),[B,...w]=Q;if(!B)throw Error(`Invalid did:web value: ${A}`);if(w.length===0)return`https://${B}/.well-known/did.json`;return`https://${B}/${w.join("/")}/did.json`}function uf0(A,Q){return new Jr0(A,Q)}p0();K0();var cf0={name:"@brains/rover",version:"0.2.0-alpha.128",type:"module",private:!0,main:"./src/index.ts",files:["src","brain.eval.yaml","env.schema.template"],scripts:{"build:web-chat":"turbo run build --filter=@brains/web-chat","start:core":"bun run build:web-chat && cd test-apps/core && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:default":"bun run build:web-chat && cd test-apps/default && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:full":"bun run build:web-chat && cd test-apps/full && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start",typecheck:"tsc --noEmit",eval:"brain-eval","eval:core":"brain-eval --suite core","eval:core:coverage":"brain-eval --suite core --tool-coverage","eval:default":"brain-eval --suite default","eval:default:coverage":"brain-eval --suite default --tool-coverage","eval:full":"brain-eval --suite full","eval:full:coverage":"brain-eval --suite full --tool-coverage",lint:"eslint .","lint:fix":"eslint . --fix"},dependencies:{"@brains/a2a":"workspace:*","@brains/agent-discovery":"workspace:*","@brains/analytics":"workspace:*","@brains/app":"workspace:*","@brains/assessment":"workspace:*","@brains/atproto":"workspace:*","@brains/auth-service":"workspace:*","@brains/blog":"workspace:*","@brains/chat":"workspace:*","@brains/cms":"workspace:*","@brains/content-pipeline":"workspace:*","@brains/dashboard":"workspace:*","@brains/decks":"workspace:*","@brains/directory-sync":"workspace:*","@brains/discord":"workspace:*","@brains/document-plugin":"workspace:*","@brains/email-resend":"workspace:*","@brains/image-plugin":"workspace:*","@brains/link":"workspace:*","@brains/mcp":"workspace:*","@brains/newsletter":"workspace:*","@brains/note":"workspace:*","@brains/notifications":"workspace:*","@brains/obsidian-vault":"workspace:*","@brains/playbook":"workspace:*","@brains/playbooks":"workspace:*","@brains/portfolio":"workspace:*","@brains/prompt":"workspace:*","@brains/rizom-ecosystem":"workspace:*","@brains/series":"workspace:*","@brains/site-builder-plugin":"workspace:*","@brains/site-default":"workspace:*","@brains/site-info":"workspace:*","@brains/social-media":"workspace:*","@brains/stock-photo":"workspace:*","@brains/theme-default":"workspace:*","@brains/topics":"workspace:*","@brains/web-chat":"workspace:*","@brains/webserver":"workspace:*","@brains/wishlist":"workspace:*"},devDependencies:{"@brains/ai-evaluation":"workspace:*","@brains/typescript-config":"workspace:*",typescript:"^5.3.3"}};var gGB=K.object({}).strict();class ht1 extends pQ{constructor(A={}){super("rover-profile",cf0,A,gGB)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",MN)}}function Ct1(A={}){return new ht1(A)}p0();K0();Jw();M5();p0();var EL=AZ.extend(MN.shape);p0();qq();K0();var TGB=new IU;class lf0{postsListUrl;decksListUrl;id="professional:homepage-list";name="Homepage List DataSource";description="Fetches profile, blog posts, and presentation decks for homepage";constructor(A,Q){this.postsListUrl=A;this.decksListUrl=Q}async fetch(A,Q,B){let w=B.entityService,[$,D,f,Y]=await Promise.all([fx(w),w.listEntities({entityType:"post",options:{limit:20}}),w.listEntities({entityType:"deck",options:{limit:20}}),Yr(w)]),X=TGB.parseProfileBody($,EL),H=D.sort(_T).slice(0,3).map(Wr),W=f.sort(_T).slice(0,3).map(qr);if(!Y.cta)throw Error("CTA not configured in site-info");let Z={profile:X,posts:H,decks:W,postsListUrl:this.postsListUrl,decksListUrl:this.decksListUrl,cta:Y.cta,sections:Y.sections??{}};return Q.parse(Z)}}p0();qq();var SGB=new IU;class pf0{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,Q,B){let w=await fx(B.entityService),D={profile:SGB.parseProfileBody(w,EL)};return Q.parse(D)}}import{jsxDEV as F8,Fragment as cGB}from"preact/jsx-dev-runtime";var mGB="grid md:grid-cols-[14rem_1px_1fr] gap-y-2 gap-x-0 md:gap-16 items-start",uGB="border-t md:border-t-0 md:border-l border-rule-strong md:self-stretch",Lr0=({number:A,title:Q,blurb:B,children:w})=>F8("section",{className:"py-20 border-b border-rule px-6 md:px-12",children:F8("div",{className:"max-w-6xl mx-auto",children:F8("div",{className:mGB,children:[F8(ku0,{title:Q,number:A,blurb:B},void 0,!1,void 0,this),F8("div",{className:uGB,"aria-hidden":"true"},void 0,!1,void 0,this),F8("div",{className:"mt-6 md:mt-0",children:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),br0=({profile:A,posts:Q,decks:B,postsListUrl:w,decksListUrl:$,cta:D,sections:f})=>{let Y=A.tagline||A.description,X=Q.map((F)=>({id:F.id,url:F.url,title:F.metadata.title,date:F.metadata.publishedAt||F.created,description:F.frontmatter.excerpt,series:F.frontmatter.seriesName&&F.frontmatter.seriesIndex?{name:F.frontmatter.seriesName,index:F.frontmatter.seriesIndex}:void 0})),H=B.map((F)=>({id:F.id,url:F.url,title:F.frontmatter.title||F.id,date:F.frontmatter.publishedAt??F.created,description:F.frontmatter.description})),W=A.name||"Home",Z=A.intro||A.description||Y||"Professional site",G=Boolean(A.description)||A.expertise!==void 0&&A.expertise.length>0;return F8(cGB,{children:[F8(NQ,{title:W,description:Z,ogType:"website"},void 0,!1,void 0,this),F8("div",{className:"homepage-list bg-theme",children:[F8("header",{className:"hero-bg-pattern relative w-full px-6 md:px-12 pt-28 pb-24 md:pt-28 md:pb-24 overflow-hidden border-b border-rule",children:F8("div",{className:"relative z-10 max-w-6xl mx-auto w-full",children:[A.name&&F8("div",{className:"flex items-center gap-[0.6rem] mb-6 font-mono text-[0.7rem] font-medium uppercase tracking-[0.22em] text-accent",children:[F8("span",{className:"w-[18px] h-px bg-accent","aria-hidden":"true"},void 0,!1,void 0,this),F8("span",{children:A.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Y&&F8("h1",{className:"font-heading text-[clamp(2.75rem,6.5vw,5.5rem)] font-normal text-heading leading-[1.02] tracking-[-0.025em] max-w-[18ch] [font-variation-settings:'opsz'_144,'SOFT'_30]",children:h90(Y,"italic font-normal text-accent [font-variation-settings:'opsz'_144,'SOFT'_80]")},void 0,!1,void 0,this),A.intro&&F8("p",{className:"font-heading font-light text-[clamp(1.1rem,1.8vw,1.4rem)] leading-[1.5] text-theme-muted max-w-[42ch] mt-8 [font-variation-settings:'opsz'_24]",children:h90(A.intro,"italic text-accent")},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),F8(Lr0,{number:"01",title:"Essays",blurb:f.essays?.blurb,children:F8(v90,{items:X,viewAllUrl:w,viewAllLabel:"View all essays"},void 0,!1,void 0,this)},void 0,!1,void 0,this),H.length>0&&F8(Lr0,{number:"02",title:"Presentations",blurb:f.presentations?.blurb,children:F8(v90,{items:H,viewAllUrl:$,viewAllLabel:"View all presentations"},void 0,!1,void 0,this)},void 0,!1,void 0,this),G&&F8(Lr0,{number:"03",title:"About",blurb:f.about?.blurb,children:F8("div",{className:"flex flex-col gap-8",children:[A.description&&F8("p",{className:"font-heading font-light text-[1.25rem] leading-[1.55] text-theme max-w-[55ch] [font-variation-settings:'opsz'_24,'SOFT'_50]",children:A.description},void 0,!1,void 0,this),A.expertise&&A.expertise.length>0&&F8(Ou0,{subjects:A.expertise},void 0,!1,void 0,this),F8("a",{href:"/about",className:"mt-6 inline-flex items-center gap-2 font-mono text-[0.7rem] font-medium uppercase tracking-[0.18em] text-accent pb-1 relative before:content-[''] before:absolute before:left-0 before:right-full before:bottom-0 before:h-px before:bg-accent before:transition-[right] before:duration-300 hover:before:right-0",children:["Learn more",F8("span",{"aria-hidden":"true",children:"\u2192"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),F8(Uu0,{cta:D,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 Pw,Fragment as lGB}from"preact/jsx-dev-runtime";var Nr0=({profile:A})=>{let Q=`About ${A.name||"Me"}`,B=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 Pw(lGB,{children:[Pw(NQ,{title:Q,description:B,ogType:"profile"},void 0,!1,void 0,this),Pw("div",{className:"about-page bg-theme",children:[Pw("header",{className:"hero-bg-pattern relative w-full py-16 md:py-24 px-6 md:px-12 bg-theme overflow-hidden",children:Pw("div",{className:"relative z-10 max-w-4xl mx-auto",children:[Pw("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&&Pw("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),Pw("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-12 md:py-16",children:[A.story&&Pw("section",{className:"content-section-reveal mb-20 md:mb-28",children:Pw(f9,{markdown:A.story},void 0,!1,void 0,this)},void 0,!1,void 0,this),w&&Pw("div",{className:"content-section-reveal grid md:grid-cols-2 gap-x-16 gap-y-12",children:[A.expertise&&A.expertise.length>0&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Expertise"},void 0,!1,void 0,this),Pw("ul",{className:"flex flex-wrap gap-3",children:A.expertise.map(($,D)=>Pw("li",{className:Xn({variant:"accent",size:"lg"}),children:$},D,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.currentFocus&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Current Focus"},void 0,!1,void 0,this),Pw("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&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Availability"},void 0,!1,void 0,this),Pw("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)&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Contact"},void 0,!1,void 0,this),Pw("div",{className:"space-y-4",children:[A.email&&Pw("p",{className:"text-lg",children:Pw("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&&Pw("p",{className:"text-lg",children:Pw("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&&Pw("div",{className:"flex flex-wrap gap-4 mt-4",children:A.socialLinks.map(($,D)=>Pw(D9,{href:$.url,external:!0,variant:"secondary",size:"md",children:$.label||$.platform},D,!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 k4,Fragment as yt1}from"preact/jsx-dev-runtime";var jr0=()=>{return k4(yt1,{children:[k4(NQ,{title:"Thanks for subscribing!",description:"You've successfully subscribed to the newsletter."},void 0,!1,void 0,this),k4("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:k4("div",{className:"text-center max-w-md",children:[k4("div",{className:"text-6xl mb-6",children:"\uD83C\uDF89"},void 0,!1,void 0,this),k4("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Thanks for subscribing!"},void 0,!1,void 0,this),k4("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),k4(D9,{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)},_r0=()=>{return k4(yt1,{children:[k4(NQ,{title:"Subscription failed",description:"There was a problem with your subscription."},void 0,!1,void 0,this),k4("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:k4("div",{className:"text-center max-w-md",children:[k4("div",{className:"text-6xl mb-6",children:"\uD83D\uDE22"},void 0,!1,void 0,this),k4("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Something went wrong"},void 0,!1,void 0,this),k4("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),k4(D9,{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)};K0();var Et1=K.object({label:K.string().describe("Display label for entity type (e.g., 'Essay')"),pluralName:K.string().optional().describe("URL path segment (defaults to label.toLowerCase() + 's')")}),gt1=K.object({entityDisplay:K.object({post:Et1,deck:Et1}).describe("Display metadata for post and deck entity types (required for homepage)")});var Tt1={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.128",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-composition":"workspace:*","@brains/site-engine":"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 Mr0 extends pQ{dependencies=["blog","decks"];constructor(A){super("professional-site",Tt1,A,gt1)}async onRegister(A){let Q=this.config.entityDisplay.post,B=this.config.entityDisplay.deck,w=`/${Q.pluralName??Q.label.toLowerCase()+"s"}`,$=`/${B.pluralName??B.label.toLowerCase()+"s"}`,D=new lf0(w,$);A.entities.registerDataSource(D);let f=new pf0;A.entities.registerDataSource(f);let Y=K.object({profile:EL,posts:K.array(fF),decks:K.array(ZP),postsListUrl:K.string(),decksListUrl:K.string(),cta:ol0,sections:K.record(K.string(),it)}),X=K.object({profile:EL}),H=K.object({});A.templates.register({"homepage-list":R1({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:Y,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:br0}}),about:R1({name:"about",description:"About page with full profile information",schema:X,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:Nr0}}),"subscribe-thanks":R1({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:H,requiredPermission:"public",layout:{component:jr0}}),"subscribe-error":R1({name:"subscribe-error",description:"Newsletter subscription error page",schema:H,requiredPermission:"public",layout:{component:_r0}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function St1(A){return new Mr0(A??{})}var mt1=[{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 if0}from"preact/jsx-dev-runtime";function ut1({sections:A,siteInfo:Q,slots:B,wordmark:w}){return if0("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[if0(Fu0,{title:Q.title,navigation:Q.navigation.primary,showThemeToggle:!0,...Q.logo!==void 0?{logo:Q.logo}:{},...w!==void 0?{wordmark:w}:{}},void 0,!1,void 0,this),if0("main",{className:"flex-grow flex flex-col bg-theme",children:A},void 0,!1,void 0,this),if0(zu0,{primaryNavigation:Q.navigation.primary,secondaryNavigation:Q.navigation.secondary,copyright:Q.copyright,socialLinks:Q.socialLinks,title:Q.title,tagline:Q.description,children:B?.getSlot("footer-top").map(($)=>$.render())},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var iGB={layouts:{default:ut1},routes:mt1,plugin:St1,entityDisplay:{post:{label:"Post"},deck:{label:"Deck"},project:{label:"Project"},series:{label:"Series",navigation:{slot:"secondary"}},topic:{label:"Topic",navigation:{slot:"secondary"}},link:{label:"Link",navigation:{slot:"secondary"}},base:{label:"Note",navigation:{show:!1}},"social-post":{label:"Social Post",pluralName:"social-posts",navigation:{slot:"secondary"}},newsletter:{label:"Newsletter",navigation:{slot:"secondary"}}}},xo=iGB;var ct1=`/*
|
|
8749
|
+
`).map((Q)=>Q.match(/^- (.+?): (.+?)(?:\s+\[(.+?)\])?$/)).filter((Q)=>Q!==null).map((Q)=>({name:Q[1]??"",description:Q[2]??"",tags:Q[3]?Q[3].split(",").map((B)=>B.trim()).filter(Boolean):[]}))}var qGB=new pB(UGB,{title:"Agent",mappings:[{key:"about",label:"About",type:"string"},{key:"skills",label:"Skills",type:"custom",formatter:GGB,parser:zGB},{key:"notes",label:"Notes",type:"string"}]});class qt1 extends V2{constructor(){super({entityType:"agent",schema:ZGB,frontmatterSchema:WGB})}fromMarkdown(A){return{content:A,entityType:"agent"}}createAgentContent(A){let Q=qGB.format({about:A.about,skills:A.skills,notes:A.notes});return this.buildMarkdown(Q,{name:A.name,kind:A.kind,...A.organization?{organization:A.organization}:{},brainName:A.brainName,url:A.url,...A.did?{did:A.did}:{},status:A.status,discoveredAt:A.discoveredAt})}}class Ft1 extends V2{constructor(){super({entityType:"skill",schema:KGB,frontmatterSchema:_Y})}fromMarkdown(A){let Q=this.parseFrontMatter(A,_Y);return{content:A,entityType:"skill",metadata:Q}}createSkillContent(A){return this.buildMarkdown("",A)}}var j96=new qt1,_96=new Ft1,M96=K.object({skills:K.array(_Y),agents:K.array(K.object({id:K.string().optional(),name:K.string(),kind:K.enum(["professional","team","collective"]),organization:K.string().optional(),brainName:K.string(),url:K.string().url(),did:K.string().optional(),status:zr0,discoveredAt:K.string().datetime().optional(),about:K.string(),skills:K.array(zt1),notes:K.string().default("")}))});var FGB=K.object({}).strict();function gf0(A={}){return FGB.parse(A),[Gr0()]}p0();K0();K0();var qr0=K.object({enabled:K.boolean().default(!0),pdsEndpoint:K.string().url().default("https://bsky.social").describe("AT Protocol PDS service endpoint"),identifier:K.string().optional().describe("PDS login identifier, usually a handle or account DID"),repoDid:K.string().optional().describe("DID of the PDS repo that owns records"),appPassword:K.string().optional().describe("App password for prototype authentication; supply via ${ENV_VAR} interpolation, never a committed literal"),anchorDid:K.string().optional().describe("Optional human/operator DID referenced from records; defaults to did:web:<site-host>:anchor when omitted"),brainDid:K.string().optional().describe("Optional public brain DID referenced from records; defaults to did:web:<site-host> when omitted")});function IGB(A){return A.replace(/\/+$/,"")}var VGB=(A,Q)=>fetch(A,Q);async function Po(A){let Q=await A.json();if(!A.ok){let B=typeof Q==="object"&&Q!==null&&"message"in Q&&typeof Q.message==="string"?Q.message:`AT Protocol request failed with ${A.status}`;throw Error(B)}return Q}class ko{pdsEndpoint;identifier;appPassword;fetchFn;session;constructor(A){this.pdsEndpoint=IGB(A.pdsEndpoint),this.identifier=A.identifier,this.appPassword=A.appPassword,this.fetchFn=A.fetch??VGB}async createSession(){let A=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.server.createSession`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({identifier:this.identifier,password:this.appPassword})}),Q=await Po(A);return this.session=Q,Q}async createRecord(A){let Q=await this.getSession(),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.createRecord`,{method:"POST",headers:{Authorization:`Bearer ${Q.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:A.repo,collection:A.collection,record:A.record,...A.rkey&&{rkey:A.rkey},...A.validate!==void 0&&{validate:A.validate}})});return Po(B)}async putRecord(A){let Q=await this.getSession(),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.putRecord`,{method:"POST",headers:{Authorization:`Bearer ${Q.accessJwt}`,"Content-Type":"application/json"},body:JSON.stringify({repo:A.repo,collection:A.collection,record:A.record,rkey:A.rkey,...A.validate!==void 0&&{validate:A.validate},...A.swapRecord!==void 0&&{swapRecord:A.swapRecord}})});return Po(B)}async getRecord(A){let Q=new URLSearchParams({repo:A.repo,collection:A.collection,rkey:A.rkey}),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.getRecord?${Q.toString()}`,{method:"GET"});return Po(B)}async uploadBlob(A){let Q=await this.getSession(),B=await this.fetchFn(`${this.pdsEndpoint}/xrpc/com.atproto.repo.uploadBlob`,{method:"POST",headers:{Authorization:`Bearer ${Q.accessJwt}`,"Content-Type":A.mimeType},body:new Blob([new Uint8Array(A.data)],{type:A.mimeType})});return Po(B)}async getSession(){return this.session??=await this.createSession(),this.session}}function RP(A){return A?.startsWith("did:web:")??!1}function Tf0(A){if(!RP(A))return;let Q=A.slice(8);if(!Q)return;let[B]=Q.split(":");if(!B)return;try{return decodeURIComponent(B)}catch{return B}}function Vt1(A){if(!RP(A))return;let Q=A.slice(8);if(!Q)return;let[,...B]=Q.split(":");if(B.length===0)return"/.well-known/did.json";return`/${B.map(($)=>{try{return decodeURIComponent($)}catch{return $}}).join("/")}/did.json`}function Jt1(A){return A.replace(/\/+$/,"")}function Oo(A){return`did:web:${encodeURIComponent(A)}`}function Sf0(A){return`${Oo(A)}:anchor`}function Fr0(A){return{"@context":["https://www.w3.org/ns/did/v1"],id:A}}function Lt1(A,Q){let B=A.identifier?.startsWith("did:")?void 0:A.identifier?[`at://${A.identifier}`]:void 0;return{...Fr0(Q),...B&&{alsoKnownAs:B},service:[{id:"#atproto_pds",type:"AtprotoPersonalDataServer",serviceEndpoint:Jt1(A.pdsEndpoint)}]}}function bt1(A){if(!RP(A.brainDid))return null;return Lt1(A,A.brainDid)}function It1(A,Q){if(!A||!Q)return;let B=Tf0(A),w=Vt1(A);if(!B||!w)return;return{path:w,hostname:B,document:Q}}function mf0(A){let Q=[],B=It1(A.brainDid,bt1(A));if(B)Q.push(B);if(RP(A.anchorDid)&&A.anchorDid!==A.brainDid){let w=It1(A.anchorDid,Fr0(A.anchorDid));if(w)Q.push(w)}return Q}function Ir0(A,Q){let B=[];if(!A.brainDid){let w=Oo(Q);B.push({path:"/.well-known/did.json",hostname:Q,document:Lt1(A,w)})}if(!A.anchorDid){let w=Sf0(Q);B.push({path:"/anchor/did.json",hostname:Q,document:Fr0(w)})}return B}function JGB(A,Q){if(!A)return;try{return new URL(A,Q).toString()}catch{return}}function LGB(A){let Q=A.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,200);return Q.length>0?Q:"skill"}function Nt1(A,Q){let B=A[Q];return typeof B==="string"&&B.length>0?B:void 0}function jt1(A,Q){let B=A[Q];if(!Array.isArray(B))return;let w=B.filter(($)=>typeof $==="string"&&$.length>0);return w.length>0?w:void 0}function bGB(A){let Q=A.metadata,B=Nt1(Q,"name"),w=Nt1(Q,"description");if(!B||!w)return;let $=jt1(Q,"tags"),D=jt1(Q,"examples");return{id:LGB(B),name:B,description:w,...$&&{tags:$},...D&&{examples:D}}}async function NGB(A){if(!A.entityService.hasEntityType("skill"))return[];return(await A.entityService.listEntities({entityType:"skill",options:{filter:{visibilityScope:"public"}}})).map((B)=>bGB(B)).filter((B)=>B!==void 0).slice(0,100)}async function Vr0(A,Q,B=new Date){let w=A.identity.get(),$=A.identity.getProfile(),D=await A.identity.getAppInfo(),f=JGB(A.siteUrl??$.website,void 0);if(!f)throw Error("AT Protocol brain card publishing requires siteUrl");let Y=new URL(f).hostname,X=Q.brainDid??Oo(Y),H=Q.anchorDid??Sf0(Y);if(RP(X)){if(Tf0(X)!==Y)throw Error("AT Protocol brain card did:web host must match siteUrl host")}let W=await NGB(A);return{$type:"ai.rizom.brain.card",siteUrl:f,brain:{did:X,name:w.name,role:w.role,purpose:w.purpose,values:w.values},anchor:{did:H,name:$.name,kind:$.kind},skills:W,model:D.model,version:D.version,createdAt:B.toISOString(),updatedAt:B.toISOString()}}K0();var _t1={dryRun:K.boolean().default(!1).describe("Build and return the card record without writing to the PDS")},jGB={},Mt1={entityType:K.string().describe("Local entity type with a registered AT Protocol projection"),entityId:K.string().optional().describe("Local entity ID to publish"),slug:K.string().optional().describe("Local entity slug to publish"),dryRun:K.boolean().default(!1).describe("Build and return the record without writing to the PDS"),topics:K.array(K.string()).optional().describe("Optional topic labels to include in the AT Protocol record")},Pt1={repos:K.array(K.string().min(1)).min(1).max(50).describe("Candidate AT Protocol repo DIDs or handles to inspect")},kt1={entityId:K.string().optional().describe("Local blog post entity ID to publish"),slug:K.string().optional().describe("Local blog post slug to publish"),dryRun:K.boolean().default(!1).describe("Build and return the post record without writing to the PDS"),topics:K.array(K.string()).optional().describe("Optional topic labels to include in the AT Protocol record")};function Ot1(A,Q,B){return[_GB(A,Q),MGB(A,Q,B),PGB(A,Q,B),OGB(A,Q,B),kGB(A,Q,B)]}function _GB(A,Q){return{name:`${A}_validate_credentials`,description:"Validate AT Protocol PDS credentials without publishing records.",inputSchema:jGB,handler:async()=>{return{success:!0,data:{valid:await Q.validatePdsCredentials()}}}}}function MGB(A,Q,B){return{name:`${A}_publish_card`,description:"Publish this brain's AT Protocol discovery card to the configured PDS, or dry-run the record payload.",inputSchema:_t1,handler:async(w)=>{let $=K.object(_t1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{return{success:!0,data:await Q.publishBrainCard(B,{dryRun:$.data.dryRun})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Publish failed"}}}}}function PGB(A,Q,B){return{name:`${A}_publish_entity`,description:"Publish any public local entity with a registered AT Protocol projection, or dry-run the record payload.",inputSchema:Mt1,handler:async(w)=>{let $=K.object(Mt1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{if(!$.data.entityId&&!$.data.slug)return{success:!1,error:"Invalid input: entityId or slug is required"};return{success:!0,data:await Q.publishEntity(B,{entityType:$.data.entityType,...$.data.entityId&&{entityId:$.data.entityId},...$.data.slug&&{slug:$.data.slug},dryRun:$.data.dryRun,...$.data.topics&&{topics:$.data.topics}})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Publish failed"}}}}}function kGB(A,Q,B){return{name:`${A}_discover_brain_cards`,description:"Read public ai.rizom.brain.card/self records from candidate AT Protocol repo DIDs or handles and emit internal discovery events.",inputSchema:Pt1,handler:async(w)=>{let $=K.object(Pt1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{return{success:!0,data:await Q.discoverBrainCards(B,{repos:$.data.repos})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Discovery failed"}}}}}function OGB(A,Q,B){return{name:`${A}_publish_post`,description:"Publish a local blog post entity as an ai.rizom.brain.post AT Protocol record, or dry-run the record payload.",inputSchema:kt1,handler:async(w)=>{let $=K.object(kt1).safeParse(w);if(!$.success)return{success:!1,error:`Invalid input: ${$.error.message}`};try{if(!$.data.entityId&&!$.data.slug)return{success:!1,error:"Invalid input: entityId or slug is required"};return{success:!0,data:await Q.publishPost(B,{...$.data.entityId&&{entityId:$.data.entityId},...$.data.slug&&{slug:$.data.slug},dryRun:$.data.dryRun,...$.data.topics&&{topics:$.data.topics}})}}catch(D){return{success:!1,error:D instanceof Error?D.message:"Publish failed"}}}}}var xt1={name:"@brains/atproto",private:!0,version:"0.2.0-alpha.129",description:"AT Protocol integration for identity, publishing, discovery, and feeds",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/atproto-contracts":"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 Rt1=_w["ai.rizom.brain.card"],RGB="ai.rizom.brain.card",vGB="self",vt1=50;class Jr0 extends pQ{deps;projectionRegistry;constructor(A={},Q={}){super("atproto",xt1,A,qr0);this.deps=Q,this.projectionRegistry=Q.projectionRegistry??U5.getInstance()}getWebRoutes(){if(!this.config.enabled)return[];let A=mf0(this.config),Q=[...!this.config.brainDid?["/.well-known/did.json"]:[],...!this.config.anchorDid?["/anchor/did.json"]:[]];return[...new Set([...A.map((w)=>w.path),...Q])].map((w)=>({path:w,method:"GET",public:!0,handler:($)=>{let D=new URL($.url).hostname,f=[...mf0(this.config),...Ir0(this.config,D)].filter((X)=>X.path===w),Y=f.find((X)=>X.hostname===D)??f[0];if(!Y)return new Response("Not found",{status:404});return new Response(JSON.stringify(Y.document),{headers:{"Content-Type":"application/did+json"}})}}))}async publishBrainCard(A,Q={}){let B=await Vr0(A,this.config);FL(Rt1,B);let w=this.config.repoDid;if(Q.dryRun)return{record:B,dryRun:!0,...w&&{repo:w}};let $=this.resolveAppPassword();if(!this.config.identifier||!$)throw Error("AT Protocol publishing requires identifier and app password configuration");let D=this.createPdsClient($),f=await D.createSession(),Y=w??f.did;if(!D.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let X=await D.putRecord({repo:Y,collection:"ai.rizom.brain.card",rkey:"self",validate:!1,record:B});return{record:B,repo:Y,uri:X.uri,cid:X.cid,dryRun:!1}}async publishEntity(A,Q){let B=this.projectionRegistry.get(Q.entityType);if(!B)throw Error(`No AT Protocol projection registered for ${Q.entityType}`);return this.publishProjectedEntity(A,Q,B)}async publishPost(A,Q){let B=this.projectionRegistry.get("post");if(!B)throw Error("No AT Protocol projection registered for post");return this.publishProjectedEntity(A,{entityType:"post",...Q},B)}async discoverBrainCards(A,Q){let B=[...new Set(Q.repos.map((D)=>D.trim()))].filter((D)=>D.length>0);if(B.length===0)throw Error("AT Protocol discovery requires at least one repo DID or handle");if(B.length>vt1)throw Error(`AT Protocol discovery accepts at most ${vt1} repos per batch`);let w=new Set,$=[];for(let D of B)try{let f=await this.resolveRepoPdsEndpoint(D),Y=this.createPublicPdsClient(f.pdsEndpoint);if(!Y.getRecord)throw Error("AT Protocol PDS client does not support record reads");let X=await Y.getRecord({repo:f.repoDid,collection:RGB,rkey:vGB});FL(Rt1,X.value);let H=CGB(X.uri)??f.repoDid,W=`${H}:${X.uri}:${X.cid}`;if(w.has(W)){$.push({repo:D,status:"skipped",repoDid:H,uri:X.uri,cid:X.cid,error:"Duplicate brain card in discovery batch"});continue}w.add(W),await A.messaging.send({type:V40,payload:{repoDid:H,uri:X.uri,cid:X.cid,record:X.value},broadcast:!0}),$.push({repo:D,status:"discovered",repoDid:H,uri:X.uri,cid:X.cid})}catch(f){$.push({repo:D,status:"skipped",error:hA(f)})}return{discovered:$.filter((D)=>D.status==="discovered").length,skipped:$.filter((D)=>D.status==="skipped").length,results:$}}async validatePdsCredentials(){let A=this.resolveAppPassword();if(!this.config.identifier||!A)return!1;try{return await this.createPdsClient(A).createSession(),!0}catch(Q){return this.logger.warn("AT Protocol PDS authentication failed",{error:hA(Q)}),!1}}async getTools(){if(!this.config.enabled)return[];return Ot1(this.id,this,this.getContext())}async getInstructions(){if(!this.config.enabled)return;return"## AT Protocol publishing\n- Use `atproto_validate_credentials` to check PDS credentials before publishing.\n- Use `atproto_publish_card` to publish or dry-run this brain's public discovery card.\n- Use `atproto_publish_entity` to publish any public entity with a registered AT Protocol projection.\n- Use `atproto_publish_post` for the blog-post convenience path by `entityId` or `slug`.\n- Use `atproto_discover_brain_cards` to read public `ai.rizom.brain.card/self` records from candidate repo DIDs or handles and emit internal discovery events.\n- Prefer `dryRun: true` first when publishing new AT Protocol records.\n- Only public posts and public cover images can be published."}async publishProjectedEntity(A,Q,B){let w=await this.findPublishEntity(A,Q),$=Q.entityId??Q.slug;if(!$)throw Error(`${Q.entityType} publish requires entityId or slug`);if(!w)throw Error(`${Q.entityType} not found: ${$}`);if(w.visibility!=="public")throw Error(`Cannot publish non-public ${Q.entityType}: ${$}`);let D=this.config.repoDid;if(Q.dryRun){let G=await B.buildRecord({entity:w,context:A,config:this.config,...Q.topics&&{topics:Q.topics},dryRun:!0});return FL(B.lexicon,G),{record:G,dryRun:!0,...D&&{repo:D}}}let f=this.resolveAppPassword();if(!this.config.identifier||!f)throw Error("AT Protocol publishing requires identifier and app password configuration");let Y=this.createPdsClient(f),X=await Y.createSession(),H=D??X.did,W=await B.buildRecord({entity:w,context:A,config:this.config,client:Y,...Q.topics&&{topics:Q.topics}});if(FL(B.lexicon,W),!Y.putRecord)throw Error("AT Protocol PDS client does not support record upserts");let Z=await Y.putRecord({repo:H,collection:B.collection,rkey:hGB(w.id),...B.validate!==void 0&&{validate:B.validate},record:W});return await B.onPublished?.({entity:w,context:A,record:W,uri:Z.uri,cid:Z.cid}),{record:W,repo:H,uri:Z.uri,cid:Z.cid,dryRun:!1}}async findPublishEntity(A,Q){if(Q.entityId)return A.entityService.getEntity({entityType:Q.entityType,id:Q.entityId});if(Q.slug)return(await A.entityService.listEntities({entityType:Q.entityType,options:{filter:{metadata:{slug:Q.slug}}}}))[0]??null;return null}createPublicPdsClient(A){if(this.deps.createPdsClient)return this.deps.createPdsClient({pdsEndpoint:A,identifier:this.config.identifier??"",appPassword:this.config.appPassword??""});return new ko({pdsEndpoint:A,identifier:this.config.identifier??"",appPassword:this.config.appPassword??""})}async resolveRepoPdsEndpoint(A){let Q=A.startsWith("did:")?A:await this.resolveHandleToDid(A);if(!Q)throw Error(`Could not resolve AT Protocol repo: ${A}`);let B=await this.resolveDidToPdsEndpoint(Q);if(!B)throw Error(`Could not resolve AT Protocol PDS for repo: ${Q}`);return{repoDid:Q,pdsEndpoint:B}}async resolveHandleToDid(A){let Q=new URL("/xrpc/com.atproto.identity.resolveHandle",this.config.pdsEndpoint);Q.searchParams.set("handle",A);let B=await this.fetch(Q.toString());if(!B.ok)return;let w=await B.json();if(typeof w!=="object"||w===null||!("did"in w))return;return typeof w.did==="string"?w.did:void 0}async resolveDidToPdsEndpoint(A){let Q=A.startsWith("did:plc:")?await this.fetchJson(`https://plc.directory/${encodeURIComponent(A)}`):A.startsWith("did:web:")?await this.fetchJson(yGB(A)):void 0;if(typeof Q!=="object"||Q===null)return;let B=Q.service;if(!Array.isArray(B))return;let w=B.find(($)=>{return typeof $==="object"&&$!==null&&($.id==="#atproto_pds"||$.type==="AtprotoPersonalDataServer")});return typeof w?.serviceEndpoint==="string"?w.serviceEndpoint:void 0}async fetchJson(A){let Q=await this.fetch(A);if(!Q.ok)return;return Q.json()}fetch(A){return(this.deps.fetch??fetch)(A)}createPdsClient(A){if(this.deps.createPdsClient)return this.deps.createPdsClient({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:A});return new ko({pdsEndpoint:this.config.pdsEndpoint,identifier:this.config.identifier??"",appPassword:A})}resolveAppPassword(){return this.config.appPassword}}function hGB(A){let Q=A.replace(/[^A-Za-z0-9._~:-]/g,"_").slice(0,512);return Q.length>0?Q:"self"}function CGB(A){return/^at:\/\/([^/]+)/.exec(A)?.[1]}function yGB(A){let Q=A.slice(8).split(":").map(decodeURIComponent),[B,...w]=Q;if(!B)throw Error(`Invalid did:web value: ${A}`);if(w.length===0)return`https://${B}/.well-known/did.json`;return`https://${B}/${w.join("/")}/did.json`}function uf0(A,Q){return new Jr0(A,Q)}p0();K0();var cf0={name:"@brains/rover",version:"0.2.0-alpha.129",type:"module",private:!0,main:"./src/index.ts",files:["src","brain.eval.yaml","env.schema.template"],scripts:{"build:web-chat":"turbo run build --filter=@brains/web-chat","start:core":"bun run build:web-chat && cd test-apps/core && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:default":"bun run build:web-chat && cd test-apps/default && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:full":"bun run build:web-chat && cd test-apps/full && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start",typecheck:"tsc --noEmit",eval:"brain-eval","eval:core":"brain-eval --suite core","eval:core:coverage":"brain-eval --suite core --tool-coverage","eval:default":"brain-eval --suite default","eval:default:coverage":"brain-eval --suite default --tool-coverage","eval:full":"brain-eval --suite full","eval:full:coverage":"brain-eval --suite full --tool-coverage",lint:"eslint .","lint:fix":"eslint . --fix"},dependencies:{"@brains/a2a":"workspace:*","@brains/agent-discovery":"workspace:*","@brains/analytics":"workspace:*","@brains/app":"workspace:*","@brains/assessment":"workspace:*","@brains/atproto":"workspace:*","@brains/auth-service":"workspace:*","@brains/blog":"workspace:*","@brains/chat":"workspace:*","@brains/cms":"workspace:*","@brains/content-pipeline":"workspace:*","@brains/dashboard":"workspace:*","@brains/decks":"workspace:*","@brains/directory-sync":"workspace:*","@brains/discord":"workspace:*","@brains/document-plugin":"workspace:*","@brains/email-resend":"workspace:*","@brains/image-plugin":"workspace:*","@brains/link":"workspace:*","@brains/mcp":"workspace:*","@brains/newsletter":"workspace:*","@brains/note":"workspace:*","@brains/notifications":"workspace:*","@brains/obsidian-vault":"workspace:*","@brains/playbook":"workspace:*","@brains/playbooks":"workspace:*","@brains/portfolio":"workspace:*","@brains/prompt":"workspace:*","@brains/rizom-ecosystem":"workspace:*","@brains/series":"workspace:*","@brains/site-builder-plugin":"workspace:*","@brains/site-default":"workspace:*","@brains/site-info":"workspace:*","@brains/social-media":"workspace:*","@brains/stock-photo":"workspace:*","@brains/theme-default":"workspace:*","@brains/topics":"workspace:*","@brains/web-chat":"workspace:*","@brains/webserver":"workspace:*","@brains/wishlist":"workspace:*"},devDependencies:{"@brains/ai-evaluation":"workspace:*","@brains/typescript-config":"workspace:*",typescript:"^5.3.3"}};var gGB=K.object({}).strict();class ht1 extends pQ{constructor(A={}){super("rover-profile",cf0,A,gGB)}async onRegister(A){A.entities.extendFrontmatterSchema("anchor-profile",MN)}}function Ct1(A={}){return new ht1(A)}p0();K0();Jw();M5();p0();var EL=AZ.extend(MN.shape);p0();qq();K0();var TGB=new IU;class lf0{postsListUrl;decksListUrl;id="professional:homepage-list";name="Homepage List DataSource";description="Fetches profile, blog posts, and presentation decks for homepage";constructor(A,Q){this.postsListUrl=A;this.decksListUrl=Q}async fetch(A,Q,B){let w=B.entityService,[$,D,f,Y]=await Promise.all([fx(w),w.listEntities({entityType:"post",options:{limit:20}}),w.listEntities({entityType:"deck",options:{limit:20}}),Yr(w)]),X=TGB.parseProfileBody($,EL),H=D.sort(_T).slice(0,3).map(Wr),W=f.sort(_T).slice(0,3).map(qr);if(!Y.cta)throw Error("CTA not configured in site-info");let Z={profile:X,posts:H,decks:W,postsListUrl:this.postsListUrl,decksListUrl:this.decksListUrl,cta:Y.cta,sections:Y.sections??{}};return Q.parse(Z)}}p0();qq();var SGB=new IU;class pf0{id="professional:about";name="About Page DataSource";description="Fetches full profile data for the about page";async fetch(A,Q,B){let w=await fx(B.entityService),D={profile:SGB.parseProfileBody(w,EL)};return Q.parse(D)}}import{jsxDEV as F8,Fragment as cGB}from"preact/jsx-dev-runtime";var mGB="grid md:grid-cols-[14rem_1px_1fr] gap-y-2 gap-x-0 md:gap-16 items-start",uGB="border-t md:border-t-0 md:border-l border-rule-strong md:self-stretch",Lr0=({number:A,title:Q,blurb:B,children:w})=>F8("section",{className:"py-20 border-b border-rule px-6 md:px-12",children:F8("div",{className:"max-w-6xl mx-auto",children:F8("div",{className:mGB,children:[F8(ku0,{title:Q,number:A,blurb:B},void 0,!1,void 0,this),F8("div",{className:uGB,"aria-hidden":"true"},void 0,!1,void 0,this),F8("div",{className:"mt-6 md:mt-0",children:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),br0=({profile:A,posts:Q,decks:B,postsListUrl:w,decksListUrl:$,cta:D,sections:f})=>{let Y=A.tagline||A.description,X=Q.map((F)=>({id:F.id,url:F.url,title:F.metadata.title,date:F.metadata.publishedAt||F.created,description:F.frontmatter.excerpt,series:F.frontmatter.seriesName&&F.frontmatter.seriesIndex?{name:F.frontmatter.seriesName,index:F.frontmatter.seriesIndex}:void 0})),H=B.map((F)=>({id:F.id,url:F.url,title:F.frontmatter.title||F.id,date:F.frontmatter.publishedAt??F.created,description:F.frontmatter.description})),W=A.name||"Home",Z=A.intro||A.description||Y||"Professional site",G=Boolean(A.description)||A.expertise!==void 0&&A.expertise.length>0;return F8(cGB,{children:[F8(NQ,{title:W,description:Z,ogType:"website"},void 0,!1,void 0,this),F8("div",{className:"homepage-list bg-theme",children:[F8("header",{className:"hero-bg-pattern relative w-full px-6 md:px-12 pt-28 pb-24 md:pt-28 md:pb-24 overflow-hidden border-b border-rule",children:F8("div",{className:"relative z-10 max-w-6xl mx-auto w-full",children:[A.name&&F8("div",{className:"flex items-center gap-[0.6rem] mb-6 font-mono text-[0.7rem] font-medium uppercase tracking-[0.22em] text-accent",children:[F8("span",{className:"w-[18px] h-px bg-accent","aria-hidden":"true"},void 0,!1,void 0,this),F8("span",{children:A.name},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Y&&F8("h1",{className:"font-heading text-[clamp(2.75rem,6.5vw,5.5rem)] font-normal text-heading leading-[1.02] tracking-[-0.025em] max-w-[18ch] [font-variation-settings:'opsz'_144,'SOFT'_30]",children:h90(Y,"italic font-normal text-accent [font-variation-settings:'opsz'_144,'SOFT'_80]")},void 0,!1,void 0,this),A.intro&&F8("p",{className:"font-heading font-light text-[clamp(1.1rem,1.8vw,1.4rem)] leading-[1.5] text-theme-muted max-w-[42ch] mt-8 [font-variation-settings:'opsz'_24]",children:h90(A.intro,"italic text-accent")},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),F8(Lr0,{number:"01",title:"Essays",blurb:f.essays?.blurb,children:F8(v90,{items:X,viewAllUrl:w,viewAllLabel:"View all essays"},void 0,!1,void 0,this)},void 0,!1,void 0,this),H.length>0&&F8(Lr0,{number:"02",title:"Presentations",blurb:f.presentations?.blurb,children:F8(v90,{items:H,viewAllUrl:$,viewAllLabel:"View all presentations"},void 0,!1,void 0,this)},void 0,!1,void 0,this),G&&F8(Lr0,{number:"03",title:"About",blurb:f.about?.blurb,children:F8("div",{className:"flex flex-col gap-8",children:[A.description&&F8("p",{className:"font-heading font-light text-[1.25rem] leading-[1.55] text-theme max-w-[55ch] [font-variation-settings:'opsz'_24,'SOFT'_50]",children:A.description},void 0,!1,void 0,this),A.expertise&&A.expertise.length>0&&F8(Ou0,{subjects:A.expertise},void 0,!1,void 0,this),F8("a",{href:"/about",className:"mt-6 inline-flex items-center gap-2 font-mono text-[0.7rem] font-medium uppercase tracking-[0.18em] text-accent pb-1 relative before:content-[''] before:absolute before:left-0 before:right-full before:bottom-0 before:h-px before:bg-accent before:transition-[right] before:duration-300 hover:before:right-0",children:["Learn more",F8("span",{"aria-hidden":"true",children:"\u2192"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),F8(Uu0,{cta:D,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 Pw,Fragment as lGB}from"preact/jsx-dev-runtime";var Nr0=({profile:A})=>{let Q=`About ${A.name||"Me"}`,B=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 Pw(lGB,{children:[Pw(NQ,{title:Q,description:B,ogType:"profile"},void 0,!1,void 0,this),Pw("div",{className:"about-page bg-theme",children:[Pw("header",{className:"hero-bg-pattern relative w-full py-16 md:py-24 px-6 md:px-12 bg-theme overflow-hidden",children:Pw("div",{className:"relative z-10 max-w-4xl mx-auto",children:[Pw("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&&Pw("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),Pw("div",{className:"container mx-auto px-6 md:px-12 max-w-4xl py-12 md:py-16",children:[A.story&&Pw("section",{className:"content-section-reveal mb-20 md:mb-28",children:Pw(f9,{markdown:A.story},void 0,!1,void 0,this)},void 0,!1,void 0,this),w&&Pw("div",{className:"content-section-reveal grid md:grid-cols-2 gap-x-16 gap-y-12",children:[A.expertise&&A.expertise.length>0&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Expertise"},void 0,!1,void 0,this),Pw("ul",{className:"flex flex-wrap gap-3",children:A.expertise.map(($,D)=>Pw("li",{className:Xn({variant:"accent",size:"lg"}),children:$},D,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A.currentFocus&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Current Focus"},void 0,!1,void 0,this),Pw("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&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Availability"},void 0,!1,void 0,this),Pw("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)&&Pw("section",{children:[Pw("h2",{className:"text-sm tracking-widest uppercase text-theme-muted mb-6",children:"Contact"},void 0,!1,void 0,this),Pw("div",{className:"space-y-4",children:[A.email&&Pw("p",{className:"text-lg",children:Pw("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&&Pw("p",{className:"text-lg",children:Pw("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&&Pw("div",{className:"flex flex-wrap gap-4 mt-4",children:A.socialLinks.map(($,D)=>Pw(D9,{href:$.url,external:!0,variant:"secondary",size:"md",children:$.label||$.platform},D,!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 k4,Fragment as yt1}from"preact/jsx-dev-runtime";var jr0=()=>{return k4(yt1,{children:[k4(NQ,{title:"Thanks for subscribing!",description:"You've successfully subscribed to the newsletter."},void 0,!1,void 0,this),k4("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:k4("div",{className:"text-center max-w-md",children:[k4("div",{className:"text-6xl mb-6",children:"\uD83C\uDF89"},void 0,!1,void 0,this),k4("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Thanks for subscribing!"},void 0,!1,void 0,this),k4("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),k4(D9,{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)},_r0=()=>{return k4(yt1,{children:[k4(NQ,{title:"Subscription failed",description:"There was a problem with your subscription."},void 0,!1,void 0,this),k4("div",{className:"min-h-[60vh] flex items-center justify-center px-6",children:k4("div",{className:"text-center max-w-md",children:[k4("div",{className:"text-6xl mb-6",children:"\uD83D\uDE22"},void 0,!1,void 0,this),k4("h1",{className:"text-3xl font-semibold mb-4 text-heading",children:"Something went wrong"},void 0,!1,void 0,this),k4("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),k4(D9,{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)};K0();var Et1=K.object({label:K.string().describe("Display label for entity type (e.g., 'Essay')"),pluralName:K.string().optional().describe("URL path segment (defaults to label.toLowerCase() + 's')")}),gt1=K.object({entityDisplay:K.object({post:Et1,deck:Et1}).describe("Display metadata for post and deck entity types (required for homepage)")});var Tt1={name:"@brains/site-professional",private:!0,version:"0.2.0-alpha.129",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-composition":"workspace:*","@brains/site-engine":"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 Mr0 extends pQ{dependencies=["blog","decks"];constructor(A){super("professional-site",Tt1,A,gt1)}async onRegister(A){let Q=this.config.entityDisplay.post,B=this.config.entityDisplay.deck,w=`/${Q.pluralName??Q.label.toLowerCase()+"s"}`,$=`/${B.pluralName??B.label.toLowerCase()+"s"}`,D=new lf0(w,$);A.entities.registerDataSource(D);let f=new pf0;A.entities.registerDataSource(f);let Y=K.object({profile:EL,posts:K.array(fF),decks:K.array(ZP),postsListUrl:K.string(),decksListUrl:K.string(),cta:ol0,sections:K.record(K.string(),it)}),X=K.object({profile:EL}),H=K.object({});A.templates.register({"homepage-list":R1({name:"homepage-list",description:"Professional homepage with essays and presentations",schema:Y,dataSourceId:"professional:homepage-list",requiredPermission:"public",layout:{component:br0}}),about:R1({name:"about",description:"About page with full profile information",schema:X,dataSourceId:"professional:about",requiredPermission:"public",layout:{component:Nr0}}),"subscribe-thanks":R1({name:"subscribe-thanks",description:"Newsletter subscription success page",schema:H,requiredPermission:"public",layout:{component:jr0}}),"subscribe-error":R1({name:"subscribe-error",description:"Newsletter subscription error page",schema:H,requiredPermission:"public",layout:{component:_r0}})}),this.logger.info("Professional site plugin registered successfully")}async getTools(){return[]}async getResources(){return[]}}function St1(A){return new Mr0(A??{})}var mt1=[{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 if0}from"preact/jsx-dev-runtime";function ut1({sections:A,siteInfo:Q,slots:B,wordmark:w}){return if0("div",{className:"flex flex-col min-h-screen bg-theme overflow-x-clip",children:[if0(Fu0,{title:Q.title,navigation:Q.navigation.primary,showThemeToggle:!0,...Q.logo!==void 0?{logo:Q.logo}:{},...w!==void 0?{wordmark:w}:{}},void 0,!1,void 0,this),if0("main",{className:"flex-grow flex flex-col bg-theme",children:A},void 0,!1,void 0,this),if0(zu0,{primaryNavigation:Q.navigation.primary,secondaryNavigation:Q.navigation.secondary,copyright:Q.copyright,socialLinks:Q.socialLinks,title:Q.title,tagline:Q.description,children:B?.getSlot("footer-top").map(($)=>$.render())},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var iGB={layouts:{default:ut1},routes:mt1,plugin:St1,entityDisplay:{post:{label:"Post"},deck:{label:"Deck"},project:{label:"Project"},series:{label:"Series",navigation:{slot:"secondary"}},topic:{label:"Topic",navigation:{slot:"secondary"}},link:{label:"Link",navigation:{slot:"secondary"}},base:{label:"Note",navigation:{show:!1}},"social-post":{label:"Social Post",pluralName:"social-posts",navigation:{slot:"secondary"}},newsletter:{label:"Newsletter",navigation:{slot:"secondary"}}}},xo=iGB;var ct1=`/*
|
|
8750
8750
|
* Default theme \u2014 simplified editorial base inspired by the Rizom family.
|
|
8751
8751
|
*
|
|
8752
8752
|
* This theme is intentionally less branded than @brains/theme-rizom. It
|
|
@@ -9134,8 +9134,8 @@ ${JSON.stringify(B,null,2)}`}function hf0(A){return A.map((Q)=>Q.detail===null?{
|
|
|
9134
9134
|
|
|
9135
9135
|
.btn-primary:disabled { opacity: 0.5; }
|
|
9136
9136
|
}
|
|
9137
|
-
`;var vE=ct1;import{join as nGB}from"path";var lt1=["prompt","rover-profile","image","document","note","link","wishlist","topics","directory-sync","atproto","agents","assessment","auth-service","notifications","playbook","playbooks","email-resend","cms","dashboard-root","mcp","webserver","web-chat","discord","a2a"],pt1=[...lt1.filter((A)=>A!=="dashboard-root"),"dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder"],rGB=[...pt1,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],oGB=["Rover is a personal professional knowledge and publishing brain for an independent professional. Prioritize personal knowledge management, professional website content, essays, projects, decks, newsletters, and social distribution workflows.",'Rover entity mappings: "blog post", "post", "essay", "article" \u2192 entityType: post; "case study", "portfolio piece", "project" \u2192 entityType: project; "presentation", "deck", "slides" \u2192 entityType: deck; "newsletter" \u2192 entityType: newsletter; "LinkedIn post", "social post" \u2192 entityType: social-post.',"When a user asks for a publishing/content overview, use the available publishing entity types directly instead of treating the request as generic team memory.","Draft blog posts are only post entities with status draft. If the user asks whether draft blog posts exist, call only system_list for entityType post with status draft; do not also list social-post, newsletter, deck, or other draft entity types."],it1=FV({name:"rover",version:cf0.version,model:"gpt-5.4-mini",site:xo,theme:vE,presets:{core:lt1,default:pt1,full:rGB},evalDisable:["discord","chat","webserver","web-chat","mcp","atproto","analytics","dashboard","dashboard-root","email-resend"],agentInstructions:oGB,capabilities:[["prompt",kP,void 0],["rover-profile",Ct1,{}],["image",Yc,void 0],["cms",_P,(A)=>({...A.CMS_CONTENT_REPO_PAT?{passkeyLogin:{contentRepoToken:A.CMS_CONTENT_REPO_PAT}}:{}})],["auth-service",tl,void 0],["notifications",pB0,void 0],["playbook",Ts1,{}],["playbooks",Pn0,{}],["email-resend",g$0,void 0],["dashboard",CL,void 0],["dashboard-root",CL,{routePath:"/"}],["blog",qp0,{}],["series",bp0,void 0],["decks",Fr,void 0],["document",Pi0,void 0],["note",FP,{}],["link",VP,{}],["portfolio",Qd0,{}],["topics",gD0,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",cd0,{generationSchedules:{newsletter:"0 9 * * 1","social-post":"0 10 * * *"},generationConditions:{newsletter:{skipIfDraftExists:!0,minSourceEntities:1,sourceEntityType:"post"},"social-post":{skipIfDraftExists:!0,maxUnpublishedDrafts:5}}}],["social-media",Ao,{autoGenerateOnBlogPublish:!0}],["newsletter",Js1,{doubleOptIn:!0}],["obsidian-vault",Zn0,{autoSync:!0}],["wishlist",Wf0,{}],["stock-photo",En0,{}],["agents",Pf0,void 0],["assessment",gf0,void 0],["atproto",uf0,(A)=>({...A.ATPROTO_APP_PASSWORD?{appPassword:A.ATPROTO_APP_PASSWORD}:{}})],["directory-sync",JM,()=>({seedContent:!0,seedContentPath:nGB(import.meta.dir,"..","seed-content-core"),initialSync:!0})],["analytics",eD0,{}],["rizom-ecosystem",OP,void 0],["site-info",DP,void 0],["site-builder",$P,{cms:{}}]],interfaces:[["mcp",tV,()=>({})],["discord",EJ,()=>({})],["chat",Z50,()=>({})],["webserver",mJ,()=>({})],["web-chat",CC,()=>({})],["a2a",yC,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"public"},{pattern:"discord:*",level:"public"},{pattern:"web-chat:*",level:"anchor"}],entityActions:{"*":{create:"anchor",update:"anchor",delete:"anchor",extract:"anchor"}}},deployment:{cdn:{enabled:!0,provider:"bunny"},dns:{enabled:!0,provider:"bunny"}}});JV();p0();K0();var dt1={name:"@brains/atproto-registry",private:!0,version:"0.2.0-alpha.
|
|
9138
|
-
`,{headers:{"Content-Type":"application/json"}})}class kr0 extends pQ{constructor(A={}){super("atproto-registry",dt1,A,rt1)}getWebRoutes(){if(!this.config.enabled)return[];return[{path:`${Pr0}/index.json`,method:"GET",public:!0,handler:()=>nt1(this.getIndex())},...fP().map((A)=>({path:`${Pr0}/${A.id}.json`,method:"GET",public:!0,handler:()=>nt1(A)}))]}getIndex(){return{lexicons:Ap0().map((A)=>({...A,path:`${Pr0}/${A.id}.json`}))}}getLexicon(A){return el0(A)}async getTools(){return[this.createListLexiconsTool(),this.createValidateLexiconTool(),this.createCheckContractsTool()]}createListLexiconsTool(){return{name:`${this.id}_list_lexicons`,description:"List canonical Rizom AT Protocol lexicons.",inputSchema:{},handler:async()=>({success:!0,data:this.getIndex()})}}createValidateLexiconTool(){return{name:`${this.id}_validate_lexicon`,description:"Validate a record payload against a canonical Rizom AT Protocol lexicon.",inputSchema:{nsid:K.string().describe("Canonical lexicon NSID"),record:K.record(K.unknown()).describe("Record payload to validate")},handler:async(A)=>{let Q=K.object({nsid:K.string(),record:K.record(K.unknown())}).safeParse(A);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};let B=this.getLexicon(Q.data.nsid);if(!B)return{success:!1,error:`Unknown AT Protocol lexicon: ${Q.data.nsid}`};try{return FL(B,Q.data.record),{success:!0,data:{valid:!0}}}catch(w){return{success:!0,data:{valid:!1,error:w instanceof Error?w.message:"Invalid record"}}}}}}createCheckContractsTool(){return{name:`${this.id}_check_contracts`,description:"Check that canonical Rizom AT Protocol lexicon contracts are available.",inputSchema:{},handler:async()=>({success:!0,data:{lexiconCount:fP().length,nsids:fP().map((A)=>A.id),metadata:Ap0()}})}}}function Or0(A={}){return new kr0(A)}p0();K0();K0();p0();var df0=K.object({routeId:K.string(),sectionId:K.string()}),Ro=o1.extend({entityType:K.literal("site-content"),template:K.string().optional(),content:K.string(),metadata:df0});p0();class ot1 extends V2{constructor(){super({entityType:"site-content",schema:Ro,frontmatterSchema:df0})}toMarkdown(A){let Q=this.extractBody(A.content);return this.buildMarkdown(Q,A.metadata)}fromMarkdown(A){return{content:A,entityType:"site-content",metadata:this.parseFrontmatter(A)}}}var xr0=new ot1;K0();var nf0=K.object({routeId:K.string().optional().describe("Optional: specific route filter"),sectionId:K.string().optional().describe("Optional: specific section filter"),dryRun:K.boolean().optional().default(!1).describe("Optional: preview changes without executing"),force:K.boolean().optional().default(!1).describe("Force regeneration even if content exists")}),RD6=K.object({jobs:K.array(K.object({jobId:K.string(),routeId:K.string(),sectionId:K.string()})),totalSections:K.number(),queuedSections:K.number(),skippedSections:K.number().optional(),batchId:K.string().optional()});class Rr0{context;constructor(A){this.context=A}createJobOptions(A,Q){if(!A)return;return{source:A.operationType??Q,rootJobId:A.rootJobId??`${Q}-${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({type:"site-builder:routes:list",payload:{}});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,Q,B){let w=this.context.logger.child("SiteContentOperations"),$=await this.fetchRoutes(),D=$;if(A.routeId){if(D=$.filter((W)=>W.id===A.routeId),D.length===0)throw Error(`Route not found: ${A.routeId}`)}let f=[];for(let W of D)for(let Z of W.sections){if(A.sectionId&&Z.id!==A.sectionId)continue;if(Z.content){w.debug("Section has static content, skipping",{routeId:W.id,sectionId:Z.id});continue}if(Z.template){let G=this.context.templates.getCapabilities(Z.template);if(!G){w.warn("Template not found, skipping section",{routeId:W.id,sectionId:Z.id,templateName:Z.template});continue}if(!G.canGenerate){w.debug("Template doesn't support generation, skipping",{routeId:W.id,sectionId:Z.id,templateName:Z.template,capabilities:G});continue}}else{w.debug("Section has no template, skipping",{routeId:W.id,sectionId:Z.id});continue}if(!A.force&&!A.dryRun){let G=`${W.id}:${Z.id}`;if(await this.context.entityService.getEntity({entityType:"site-content",id:G})){w.debug("Content already exists, skipping",{routeId:W.id,sectionId:Z.id});continue}}f.push({route:W,section:Z})}let Y=f.length;if(A.dryRun)return{jobs:[],totalSections:Y,queuedSections:Y,batchId:`dry-run-${Date.now()}`};let X=[],H=[];for(let{route:W,section:Z}of f){let G=`${W.id}:${Z.id}`,F=Z.template,I={routeId:W.id,sectionId:Z.id,entityId:G,entityType:"site-content",templateName:F,context:{prompt:typeof Z.content==="string"?Z.content:void 0,data:{routeId:W.id,sectionId:Z.id,routeTitle:W.title??Q?.title??"",routeDescription:W.description??Q?.description??"",sectionContent:Z.content},conversationId:"system"},siteConfig:Q};H.push({type:"shell:content-generation",data:I})}if(H.length>0){let W=this.createJobOptions(B,"site:content-generation"),Z=await this.context.jobs.enqueueBatch(H,W);for(let G=0;G<f.length;G++){let F=f[G];if(F)X.push({jobId:`${Z}-${G}`,routeId:F.route.id,sectionId:F.section.id})}return{jobs:X,totalSections:Y,queuedSections:X.length,batchId:Z}}return{jobs:[],totalSections:Y,queuedSections:0,batchId:`empty-${Date.now()}`}}}class vr0{siteConfig;operations;constructor(A,Q){this.siteConfig=Q;this.operations=new Rr0(A)}async generateContent(A,Q){let B=nf0.parse(A);return this.operations.generate(B,this.siteConfig,Q)}}p$();K0();function vo(A,Q){return Q?A.optional():A}function Cr0(A){switch(A.type){case"string":return vo(K.string(),A.optional);case"number":return vo(K.number(),A.optional);case"enum":{let Q=[...A.options];return vo(K.enum(Q),A.optional)}case"object":{let Q={};for(let[B,w]of Object.entries(A.fields))Q[B]=Cr0(w);return vo(K.object(Q),A.optional)}case"array":{let Q=K.array(aGB(A));if(A.minItems!==void 0)Q=Q.min(A.minItems);if(A.length!==void 0)Q=Q.length(A.length);return vo(Q,A.optional)}}}function aGB(A){let{items:Q}=A;switch(Q.type){case"string":return K.string();case"number":return K.number();case"enum":{let B=[...Q.options];return K.enum(B)}case"object":{let B={};for(let[w,$]of Object.entries(Q.fields))B[w]=Cr0($);return K.object(B)}}}function hr0(A,Q){switch(Q.type){case"string":case"enum":return{key:A,label:Q.label,type:"string"};case"number":return{key:A,label:Q.label,type:"number"};case"object":return{key:A,label:Q.label,type:"object",children:Object.entries(Q.fields).map(([B,w])=>hr0(B,w))};case"array":{let B={key:A,label:Q.label,type:"array"};switch(Q.items.type){case"string":case"enum":return B.itemType="string",B;case"number":return B.itemType="number",B;case"object":return B.itemType="object",B.itemMappings=Object.entries(Q.items.fields).map(([w,$])=>hr0(w,$)),B}}}}function tGB(A,Q){let B={};for(let[D,f]of Object.entries(Q.fields))B[D]=Cr0(f);let w=K.object(B),$=new pB(w,{title:Q.title,mappings:Object.entries(Q.fields).map(([D,f])=>hr0(D,f))});return{name:A,description:Q.description,schema:w,formatter:$,requiredPermission:Q.requiredPermission??"public",layout:{component:Q.layout,...Q.fullscreen!==void 0?{fullscreen:Q.fullscreen}:{}},...Q.runtimeScripts?{runtimeScripts:Q.runtimeScripts}:{}}}function yr0(A){return Object.fromEntries(Object.entries(A.sections).map(([Q,B])=>[Q,tGB(Q,B)]))}K0();var st1=K.object({namespace:K.string(),sections:K.record(K.any())}),at1=K.object({definitions:K.union([st1,K.array(st1)]).optional()});p0();function tt1(A,Q){return[BB(Q,"generate","Generate content for all routes, a specific route, or a specific section",nf0,async(B,w)=>{let $=A();if(!$)return{success:!1,error:"Site content service not initialized"};if(B.sectionId&&!B.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let D={rootJobId:`generate-${Date.now()}`,progressToken:w.progressToken,pluginId:Q,operationType:"content_operations",interfaceType:w.interfaceType,channelId:w.channelId},f=await $.generateContent(B,D);return{success:!0,message:`Generated ${f.queuedSections} of ${f.totalSections} sections. ${f.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:f.batchId,jobsQueued:f.queuedSections,totalSections:f.totalSections,jobs:f.jobs}}})]}var et1={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.128",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/content-formatters":"workspace:*","@brains/plugins":"workspace:*","@brains/site-info":"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 Er0 extends pQ{siteContentService;constructor(A={}){super("site-content",et1,A,at1)}async onRegister(A){A.entities.register("site-content",Ro,xr0);for(let Q of YU(this.config.definitions))A.templates.register(yr0(Q),Q.namespace);this.siteContentService=new vr0(A)}async getTools(){return tt1(()=>this.siteContentService,this.id)}}function ho(A={}){return new Er0(A)}p0();K0();Jw();K0();p0();var Ae1=K.enum(["available","early access","coming soon","planned"]),Qe1=K.object({title:K.string(),description:K.string()}),CX=K.object({name:K.string(),availability:Ae1,order:K.number(),ogImageId:K.string().optional()}),rf0=K.object({tagline:K.string(),promise:K.string(),role:K.string(),purpose:K.string(),audience:K.string(),values:K.array(K.string()).min(1),features:K.array(Qe1).min(1).max(6),story:K.string()}),AzB=CX.pick({name:!0,availability:!0,order:!0}).extend({slug:K.string()}),hE=o1.extend({entityType:K.literal("product"),metadata:AzB}),of0=hE.extend({frontmatter:CX,body:rf0,labels:K.record(K.string(),K.string()),ogImageUrl:K.string().optional()}),sf0=of0.extend({url:K.string().optional(),typeLabel:K.string().optional(),listUrl:K.string().optional(),listLabel:K.string().optional(),ogImageUrl:K.string().optional()});p0();K0();p$();class CE extends pB{constructor(){super(rf0,{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 gr0 extends V2{constructor(){super({entityType:"product",schema:hE,frontmatterSchema:CX,bodyFormatter:new CE})}toMarkdown(A){let Q=this.extractBody(A.content);try{let B=this.parseFrontMatter(A.content,CX);return this.buildMarkdown(Q,B)}catch{return Q}}fromMarkdown(A){let Q=this.parseFrontMatter(A,CX),B=Y1(Q.name);return{content:A,entityType:"product",metadata:{name:Q.name,slug:B,availability:Q.availability,order:Q.order}}}}var af0=new gr0;K0();p0();var Be1=K.object({title:K.string(),description:K.string()}),we1=K.object({title:K.string(),description:K.string()}),QzB=K.object({title:K.string(),description:K.string()}),$e1=K.object({heading:K.string(),buttonText:K.string(),link:K.string()}),VF=K.object({headline:K.string(),tagline:K.string()}),BzB=K.object({title:K.string(),description:K.string()}),tf0=K.object({vision:K.string(),pillars:K.array(Be1).min(1).max(6),approach:K.array(BzB).min(1).max(6),productsIntro:K.string(),technologies:K.array(QzB).min(1).max(6),benefits:K.array(we1).min(1).max(6),cta:$e1}),De1=VF.pick({headline:!0}).extend({slug:K.string()}),yE=o1.extend({entityType:K.literal("products-overview"),metadata:De1}),Co=yE.extend({frontmatter:VF,body:tf0,labels:K.record(K.string(),K.string())});p0();K0();p$();class EE extends pB{constructor(){super(tf0,{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 Tr0 extends V2{constructor(){super({entityType:"products-overview",schema:yE,frontmatterSchema:VF,bodyFormatter:new EE})}toMarkdown(A){let Q=this.extractBody(A.content);try{let B=this.parseFrontMatter(A.content,VF);return this.buildMarkdown(Q,B)}catch{return Q}}fromMarkdown(A){let Q=this.parseFrontMatter(A,VF),B=Y1(Q.headline);return{content:A,entityType:"products-overview",metadata:{headline:Q.headline,slug:B}}}}var Sr0=new Tr0;p0();K0();var wzB=K.object({entityType:K.string(),query:K.object({id:K.string().optional()}).optional()});function fe1(A,Q){let B=h2(A.content,CX),w=Q.parse(B.content),$=Q.getLabels();return of0.parse({...A,frontmatter:B.metadata,body:w,labels:$})}function Ye1(A,Q){let B=h2(A.content,VF),w=Q.parse(B.content),$=Q.getLabels();return Co.parse({...A,frontmatter:B.metadata,body:w,labels:$})}class ef0{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new EE;productFormatter=new CE;constructor(A){this.logger=A;this.logger.debug("ProductsDataSource initialized")}async fetch(A,Q,B){let w=wzB.parse(A),$=B.entityService;if(w.entityType==="products-overview"){let H=(await $.listEntities({entityType:"products-overview",options:{limit:1}}))[0];if(!H)throw Error("Products overview entity not found");let W=Ye1(H,this.overviewFormatter);return Q.parse(W)}if(w.query?.id){let H=(await $.listEntities({entityType:"product",options:{filter:{metadata:{slug:w.query.id}},limit:1}}))[0];if(!H)throw Error(`Product not found: ${w.query.id}`);return Q.parse({product:fe1(H,this.productFormatter)})}let[D,f]=await Promise.all([$.listEntities({entityType:"products-overview",options:{limit:1}}),$.listEntities({entityType:"product",options:{sortFields:[{field:"order",direction:"asc"}]}})]),Y=D[0];if(!Y)throw Error("Products overview entity not found");return Q.parse({overview:Ye1(Y,this.overviewFormatter),products:f.map((X)=>fe1(X,this.productFormatter))})}}import{jsxDEV as B1,Fragment as fzB}from"preact/jsx-dev-runtime";var Xe1=({overview:A,products:Q})=>{let{frontmatter:B,body:w,labels:$}=A;return B1(fzB,{children:[B1(NQ,{title:B.headline,description:B.tagline},void 0,!1,void 0,this),B1("header",{className:"relative w-full min-h-[80vh] flex items-end px-6 md:px-12 bg-brand-dark overflow-hidden",children:[B1("style",{children:`
|
|
9137
|
+
`;var vE=ct1;import{join as nGB}from"path";var lt1=["prompt","rover-profile","image","document","note","link","wishlist","topics","directory-sync","atproto","agents","assessment","auth-service","notifications","playbook","playbooks","email-resend","cms","dashboard-root","mcp","webserver","web-chat","discord","a2a"],pt1=[...lt1.filter((A)=>A!=="dashboard-root"),"dashboard","blog","series","decks","analytics","obsidian-vault","site-info","site-builder"],rGB=[...pt1,"portfolio","topics","content-pipeline","social-media","newsletter","stock-photo"],oGB=["Rover is a personal professional knowledge and publishing brain for an independent professional. Prioritize personal knowledge management, professional website content, essays, projects, decks, newsletters, and social distribution workflows.",'Rover entity mappings: "blog post", "post", "essay", "article" \u2192 entityType: post; "case study", "portfolio piece", "project" \u2192 entityType: project; "presentation", "deck", "slides" \u2192 entityType: deck; "newsletter" \u2192 entityType: newsletter; "LinkedIn post", "social post" \u2192 entityType: social-post.',"When a user asks for a publishing/content overview, use the available publishing entity types directly instead of treating the request as generic team memory.","Draft blog posts are only post entities with status draft. If the user asks whether draft blog posts exist, call only system_list for entityType post with status draft; do not also list social-post, newsletter, deck, or other draft entity types."],it1=FV({name:"rover",version:cf0.version,model:"gpt-5.4-mini",site:xo,theme:vE,presets:{core:lt1,default:pt1,full:rGB},evalDisable:["discord","chat","webserver","web-chat","mcp","atproto","analytics","dashboard","dashboard-root","email-resend"],agentInstructions:oGB,capabilities:[["prompt",kP,void 0],["rover-profile",Ct1,{}],["image",Yc,void 0],["cms",_P,(A)=>({...A.CMS_CONTENT_REPO_PAT?{passkeyLogin:{contentRepoToken:A.CMS_CONTENT_REPO_PAT}}:{}})],["auth-service",tl,void 0],["notifications",pB0,void 0],["playbook",Ts1,{}],["playbooks",Pn0,{}],["email-resend",g$0,void 0],["dashboard",CL,void 0],["dashboard-root",CL,{routePath:"/"}],["blog",qp0,{}],["series",bp0,void 0],["decks",Fr,void 0],["document",Pi0,void 0],["note",FP,{}],["link",VP,{}],["portfolio",Qd0,{}],["topics",gD0,{includeEntityTypes:["post","deck","project","link","anchor-profile"]}],["content-pipeline",cd0,{generationSchedules:{newsletter:"0 9 * * 1","social-post":"0 10 * * *"},generationConditions:{newsletter:{skipIfDraftExists:!0,minSourceEntities:1,sourceEntityType:"post"},"social-post":{skipIfDraftExists:!0,maxUnpublishedDrafts:5}}}],["social-media",Ao,{autoGenerateOnBlogPublish:!0}],["newsletter",Js1,{doubleOptIn:!0}],["obsidian-vault",Zn0,{autoSync:!0}],["wishlist",Wf0,{}],["stock-photo",En0,{}],["agents",Pf0,void 0],["assessment",gf0,void 0],["atproto",uf0,(A)=>({...A.ATPROTO_APP_PASSWORD?{appPassword:A.ATPROTO_APP_PASSWORD}:{}})],["directory-sync",JM,()=>({seedContent:!0,seedContentPath:nGB(import.meta.dir,"..","seed-content-core"),initialSync:!0})],["analytics",eD0,{}],["rizom-ecosystem",OP,void 0],["site-info",DP,void 0],["site-builder",$P,{cms:{}}]],interfaces:[["mcp",tV,()=>({})],["discord",EJ,()=>({})],["chat",Z50,()=>({})],["webserver",mJ,()=>({})],["web-chat",CC,()=>({})],["a2a",yC,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"public"},{pattern:"discord:*",level:"public"},{pattern:"web-chat:*",level:"anchor"}],entityActions:{"*":{create:"anchor",update:"anchor",delete:"anchor",extract:"anchor"}}},deployment:{cdn:{enabled:!0,provider:"bunny"},dns:{enabled:!0,provider:"bunny"}}});JV();p0();K0();var dt1={name:"@brains/atproto-registry",private:!0,version:"0.2.0-alpha.129",description:"Canonical Rizom AT Protocol lexicon registry",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/atproto-contracts":"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 rt1=K.object({enabled:K.boolean().default(!0)}),Pr0="/atproto/lexicons";function nt1(A){return new Response(`${JSON.stringify(A,null,2)}
|
|
9138
|
+
`,{headers:{"Content-Type":"application/json"}})}class kr0 extends pQ{constructor(A={}){super("atproto-registry",dt1,A,rt1)}getWebRoutes(){if(!this.config.enabled)return[];return[{path:`${Pr0}/index.json`,method:"GET",public:!0,handler:()=>nt1(this.getIndex())},...fP().map((A)=>({path:`${Pr0}/${A.id}.json`,method:"GET",public:!0,handler:()=>nt1(A)}))]}getIndex(){return{lexicons:Ap0().map((A)=>({...A,path:`${Pr0}/${A.id}.json`}))}}getLexicon(A){return el0(A)}async getTools(){return[this.createListLexiconsTool(),this.createValidateLexiconTool(),this.createCheckContractsTool()]}createListLexiconsTool(){return{name:`${this.id}_list_lexicons`,description:"List canonical Rizom AT Protocol lexicons.",inputSchema:{},handler:async()=>({success:!0,data:this.getIndex()})}}createValidateLexiconTool(){return{name:`${this.id}_validate_lexicon`,description:"Validate a record payload against a canonical Rizom AT Protocol lexicon.",inputSchema:{nsid:K.string().describe("Canonical lexicon NSID"),record:K.record(K.unknown()).describe("Record payload to validate")},handler:async(A)=>{let Q=K.object({nsid:K.string(),record:K.record(K.unknown())}).safeParse(A);if(!Q.success)return{success:!1,error:`Invalid input: ${Q.error.message}`};let B=this.getLexicon(Q.data.nsid);if(!B)return{success:!1,error:`Unknown AT Protocol lexicon: ${Q.data.nsid}`};try{return FL(B,Q.data.record),{success:!0,data:{valid:!0}}}catch(w){return{success:!0,data:{valid:!1,error:w instanceof Error?w.message:"Invalid record"}}}}}}createCheckContractsTool(){return{name:`${this.id}_check_contracts`,description:"Check that canonical Rizom AT Protocol lexicon contracts are available.",inputSchema:{},handler:async()=>({success:!0,data:{lexiconCount:fP().length,nsids:fP().map((A)=>A.id),metadata:Ap0()}})}}}function Or0(A={}){return new kr0(A)}p0();K0();K0();p0();var df0=K.object({routeId:K.string(),sectionId:K.string()}),Ro=o1.extend({entityType:K.literal("site-content"),template:K.string().optional(),content:K.string(),metadata:df0});p0();class ot1 extends V2{constructor(){super({entityType:"site-content",schema:Ro,frontmatterSchema:df0})}toMarkdown(A){let Q=this.extractBody(A.content);return this.buildMarkdown(Q,A.metadata)}fromMarkdown(A){return{content:A,entityType:"site-content",metadata:this.parseFrontmatter(A)}}}var xr0=new ot1;K0();var nf0=K.object({routeId:K.string().optional().describe("Optional: specific route filter"),sectionId:K.string().optional().describe("Optional: specific section filter"),dryRun:K.boolean().optional().default(!1).describe("Optional: preview changes without executing"),force:K.boolean().optional().default(!1).describe("Force regeneration even if content exists")}),RD6=K.object({jobs:K.array(K.object({jobId:K.string(),routeId:K.string(),sectionId:K.string()})),totalSections:K.number(),queuedSections:K.number(),skippedSections:K.number().optional(),batchId:K.string().optional()});class Rr0{context;constructor(A){this.context=A}createJobOptions(A,Q){if(!A)return;return{source:A.operationType??Q,rootJobId:A.rootJobId??`${Q}-${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({type:"site-builder:routes:list",payload:{}});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,Q,B){let w=this.context.logger.child("SiteContentOperations"),$=await this.fetchRoutes(),D=$;if(A.routeId){if(D=$.filter((W)=>W.id===A.routeId),D.length===0)throw Error(`Route not found: ${A.routeId}`)}let f=[];for(let W of D)for(let Z of W.sections){if(A.sectionId&&Z.id!==A.sectionId)continue;if(Z.content){w.debug("Section has static content, skipping",{routeId:W.id,sectionId:Z.id});continue}if(Z.template){let G=this.context.templates.getCapabilities(Z.template);if(!G){w.warn("Template not found, skipping section",{routeId:W.id,sectionId:Z.id,templateName:Z.template});continue}if(!G.canGenerate){w.debug("Template doesn't support generation, skipping",{routeId:W.id,sectionId:Z.id,templateName:Z.template,capabilities:G});continue}}else{w.debug("Section has no template, skipping",{routeId:W.id,sectionId:Z.id});continue}if(!A.force&&!A.dryRun){let G=`${W.id}:${Z.id}`;if(await this.context.entityService.getEntity({entityType:"site-content",id:G})){w.debug("Content already exists, skipping",{routeId:W.id,sectionId:Z.id});continue}}f.push({route:W,section:Z})}let Y=f.length;if(A.dryRun)return{jobs:[],totalSections:Y,queuedSections:Y,batchId:`dry-run-${Date.now()}`};let X=[],H=[];for(let{route:W,section:Z}of f){let G=`${W.id}:${Z.id}`,F=Z.template,I={routeId:W.id,sectionId:Z.id,entityId:G,entityType:"site-content",templateName:F,context:{prompt:typeof Z.content==="string"?Z.content:void 0,data:{routeId:W.id,sectionId:Z.id,routeTitle:W.title??Q?.title??"",routeDescription:W.description??Q?.description??"",sectionContent:Z.content},conversationId:"system"},siteConfig:Q};H.push({type:"shell:content-generation",data:I})}if(H.length>0){let W=this.createJobOptions(B,"site:content-generation"),Z=await this.context.jobs.enqueueBatch(H,W);for(let G=0;G<f.length;G++){let F=f[G];if(F)X.push({jobId:`${Z}-${G}`,routeId:F.route.id,sectionId:F.section.id})}return{jobs:X,totalSections:Y,queuedSections:X.length,batchId:Z}}return{jobs:[],totalSections:Y,queuedSections:0,batchId:`empty-${Date.now()}`}}}class vr0{siteConfig;operations;constructor(A,Q){this.siteConfig=Q;this.operations=new Rr0(A)}async generateContent(A,Q){let B=nf0.parse(A);return this.operations.generate(B,this.siteConfig,Q)}}p$();K0();function vo(A,Q){return Q?A.optional():A}function Cr0(A){switch(A.type){case"string":return vo(K.string(),A.optional);case"number":return vo(K.number(),A.optional);case"enum":{let Q=[...A.options];return vo(K.enum(Q),A.optional)}case"object":{let Q={};for(let[B,w]of Object.entries(A.fields))Q[B]=Cr0(w);return vo(K.object(Q),A.optional)}case"array":{let Q=K.array(aGB(A));if(A.minItems!==void 0)Q=Q.min(A.minItems);if(A.length!==void 0)Q=Q.length(A.length);return vo(Q,A.optional)}}}function aGB(A){let{items:Q}=A;switch(Q.type){case"string":return K.string();case"number":return K.number();case"enum":{let B=[...Q.options];return K.enum(B)}case"object":{let B={};for(let[w,$]of Object.entries(Q.fields))B[w]=Cr0($);return K.object(B)}}}function hr0(A,Q){switch(Q.type){case"string":case"enum":return{key:A,label:Q.label,type:"string"};case"number":return{key:A,label:Q.label,type:"number"};case"object":return{key:A,label:Q.label,type:"object",children:Object.entries(Q.fields).map(([B,w])=>hr0(B,w))};case"array":{let B={key:A,label:Q.label,type:"array"};switch(Q.items.type){case"string":case"enum":return B.itemType="string",B;case"number":return B.itemType="number",B;case"object":return B.itemType="object",B.itemMappings=Object.entries(Q.items.fields).map(([w,$])=>hr0(w,$)),B}}}}function tGB(A,Q){let B={};for(let[D,f]of Object.entries(Q.fields))B[D]=Cr0(f);let w=K.object(B),$=new pB(w,{title:Q.title,mappings:Object.entries(Q.fields).map(([D,f])=>hr0(D,f))});return{name:A,description:Q.description,schema:w,formatter:$,requiredPermission:Q.requiredPermission??"public",layout:{component:Q.layout,...Q.fullscreen!==void 0?{fullscreen:Q.fullscreen}:{}},...Q.runtimeScripts?{runtimeScripts:Q.runtimeScripts}:{}}}function yr0(A){return Object.fromEntries(Object.entries(A.sections).map(([Q,B])=>[Q,tGB(Q,B)]))}K0();var st1=K.object({namespace:K.string(),sections:K.record(K.any())}),at1=K.object({definitions:K.union([st1,K.array(st1)]).optional()});p0();function tt1(A,Q){return[BB(Q,"generate","Generate content for all routes, a specific route, or a specific section",nf0,async(B,w)=>{let $=A();if(!$)return{success:!1,error:"Site content service not initialized"};if(B.sectionId&&!B.routeId)return{success:!1,error:"sectionId requires routeId to be specified"};let D={rootJobId:`generate-${Date.now()}`,progressToken:w.progressToken,pluginId:Q,operationType:"content_operations",interfaceType:w.interfaceType,channelId:w.channelId},f=await $.generateContent(B,D);return{success:!0,message:`Generated ${f.queuedSections} of ${f.totalSections} sections. ${f.queuedSections>0?"Jobs are running in the background.":"No new content to generate."}`,data:{batchId:f.batchId,jobsQueued:f.queuedSections,totalSections:f.totalSections,jobs:f.jobs}}})]}var et1={name:"@brains/site-content",private:!0,version:"0.2.0-alpha.129",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/content-formatters":"workspace:*","@brains/plugins":"workspace:*","@brains/site-info":"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 Er0 extends pQ{siteContentService;constructor(A={}){super("site-content",et1,A,at1)}async onRegister(A){A.entities.register("site-content",Ro,xr0);for(let Q of YU(this.config.definitions))A.templates.register(yr0(Q),Q.namespace);this.siteContentService=new vr0(A)}async getTools(){return tt1(()=>this.siteContentService,this.id)}}function ho(A={}){return new Er0(A)}p0();K0();Jw();K0();p0();var Ae1=K.enum(["available","early access","coming soon","planned"]),Qe1=K.object({title:K.string(),description:K.string()}),CX=K.object({name:K.string(),availability:Ae1,order:K.number(),ogImageId:K.string().optional()}),rf0=K.object({tagline:K.string(),promise:K.string(),role:K.string(),purpose:K.string(),audience:K.string(),values:K.array(K.string()).min(1),features:K.array(Qe1).min(1).max(6),story:K.string()}),AzB=CX.pick({name:!0,availability:!0,order:!0}).extend({slug:K.string()}),hE=o1.extend({entityType:K.literal("product"),metadata:AzB}),of0=hE.extend({frontmatter:CX,body:rf0,labels:K.record(K.string(),K.string()),ogImageUrl:K.string().optional()}),sf0=of0.extend({url:K.string().optional(),typeLabel:K.string().optional(),listUrl:K.string().optional(),listLabel:K.string().optional(),ogImageUrl:K.string().optional()});p0();K0();p$();class CE extends pB{constructor(){super(rf0,{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 gr0 extends V2{constructor(){super({entityType:"product",schema:hE,frontmatterSchema:CX,bodyFormatter:new CE})}toMarkdown(A){let Q=this.extractBody(A.content);try{let B=this.parseFrontMatter(A.content,CX);return this.buildMarkdown(Q,B)}catch{return Q}}fromMarkdown(A){let Q=this.parseFrontMatter(A,CX),B=Y1(Q.name);return{content:A,entityType:"product",metadata:{name:Q.name,slug:B,availability:Q.availability,order:Q.order}}}}var af0=new gr0;K0();p0();var Be1=K.object({title:K.string(),description:K.string()}),we1=K.object({title:K.string(),description:K.string()}),QzB=K.object({title:K.string(),description:K.string()}),$e1=K.object({heading:K.string(),buttonText:K.string(),link:K.string()}),VF=K.object({headline:K.string(),tagline:K.string()}),BzB=K.object({title:K.string(),description:K.string()}),tf0=K.object({vision:K.string(),pillars:K.array(Be1).min(1).max(6),approach:K.array(BzB).min(1).max(6),productsIntro:K.string(),technologies:K.array(QzB).min(1).max(6),benefits:K.array(we1).min(1).max(6),cta:$e1}),De1=VF.pick({headline:!0}).extend({slug:K.string()}),yE=o1.extend({entityType:K.literal("products-overview"),metadata:De1}),Co=yE.extend({frontmatter:VF,body:tf0,labels:K.record(K.string(),K.string())});p0();K0();p$();class EE extends pB{constructor(){super(tf0,{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 Tr0 extends V2{constructor(){super({entityType:"products-overview",schema:yE,frontmatterSchema:VF,bodyFormatter:new EE})}toMarkdown(A){let Q=this.extractBody(A.content);try{let B=this.parseFrontMatter(A.content,VF);return this.buildMarkdown(Q,B)}catch{return Q}}fromMarkdown(A){let Q=this.parseFrontMatter(A,VF),B=Y1(Q.headline);return{content:A,entityType:"products-overview",metadata:{headline:Q.headline,slug:B}}}}var Sr0=new Tr0;p0();K0();var wzB=K.object({entityType:K.string(),query:K.object({id:K.string().optional()}).optional()});function fe1(A,Q){let B=h2(A.content,CX),w=Q.parse(B.content),$=Q.getLabels();return of0.parse({...A,frontmatter:B.metadata,body:w,labels:$})}function Ye1(A,Q){let B=h2(A.content,VF),w=Q.parse(B.content),$=Q.getLabels();return Co.parse({...A,frontmatter:B.metadata,body:w,labels:$})}class ef0{logger;id="products:entities";name="Products Entity DataSource";description="Fetches products and overview for the products page";overviewFormatter=new EE;productFormatter=new CE;constructor(A){this.logger=A;this.logger.debug("ProductsDataSource initialized")}async fetch(A,Q,B){let w=wzB.parse(A),$=B.entityService;if(w.entityType==="products-overview"){let H=(await $.listEntities({entityType:"products-overview",options:{limit:1}}))[0];if(!H)throw Error("Products overview entity not found");let W=Ye1(H,this.overviewFormatter);return Q.parse(W)}if(w.query?.id){let H=(await $.listEntities({entityType:"product",options:{filter:{metadata:{slug:w.query.id}},limit:1}}))[0];if(!H)throw Error(`Product not found: ${w.query.id}`);return Q.parse({product:fe1(H,this.productFormatter)})}let[D,f]=await Promise.all([$.listEntities({entityType:"products-overview",options:{limit:1}}),$.listEntities({entityType:"product",options:{sortFields:[{field:"order",direction:"asc"}]}})]),Y=D[0];if(!Y)throw Error("Products overview entity not found");return Q.parse({overview:Ye1(Y,this.overviewFormatter),products:f.map((X)=>fe1(X,this.productFormatter))})}}import{jsxDEV as B1,Fragment as fzB}from"preact/jsx-dev-runtime";var Xe1=({overview:A,products:Q})=>{let{frontmatter:B,body:w,labels:$}=A;return B1(fzB,{children:[B1(NQ,{title:B.headline,description:B.tagline},void 0,!1,void 0,this),B1("header",{className:"relative w-full min-h-[80vh] flex items-end px-6 md:px-12 bg-brand-dark overflow-hidden",children:[B1("style",{children:`
|
|
9139
9139
|
@keyframes wave-drift {
|
|
9140
9140
|
from { transform: translateX(0); }
|
|
9141
9141
|
to { transform: translateX(-50%); }
|
|
@@ -9330,7 +9330,7 @@ ${JSON.stringify(B,null,2)}`}function hf0(A){return A.map((Q)=>Q.detail===null?{
|
|
|
9330
9330
|
font: 10px/1.45 var(--font-mono, "JetBrains Mono", ui-monospace, monospace);
|
|
9331
9331
|
}
|
|
9332
9332
|
`}},void 0,!1,void 0,this),yX("section",{className:"product-shell",children:[yX("header",{className:"product-hero",children:[Q.brandLabel&&yX("p",{className:"printable-kicker",children:Q.brandLabel},void 0,!1,void 0,this),yX("h1",{className:"printable-title",children:Q.name},void 0,!1,void 0,this),Q.availability&&yX("div",{className:"printable-meta",children:yX("span",{children:Q.availability},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),yX("div",{className:"product-body-wrap",children:[yX("aside",{className:"product-rail","aria-hidden":"true",children:yX("p",{className:"product-rail-label",children:"Product brief / capabilities"},void 0,!1,void 0,this)},void 0,!1,void 0,this),yX(f9,{markdown:Q.body,className:"printable-body"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Q.brandLabel&&yX("footer",{className:"printable-footer",children:Q.brandLabel},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var GzB=26214400,zzB=60000;class ur0{context;renderPdf;constructor(A,Q={}){this.context=A;this.renderPdf=Q.renderPdf??IK}async resolve(A){if(A.sourceEntityType!=="product"||A.attachmentType!==AY0)return;let Q=await this.context.entityService.getEntity({entityType:"product",id:A.sourceEntityId});if(!Q)return;let B=qzB(Q,{brandLabel:this.resolveBrandLabel()}),w=await WzB(UzB(KzB(),"brain-product-printable-"));try{let $=await MX({outputDir:w,mediaPath:`/_media/printable/product/${Q.id}`,template:Ze1,format:"pdf",content:B,siteConfig:{title:B.name,themeMode:"light"},themeCSS:this.context.themeCSS}),D=await PX({rootDir:w});try{return{type:"document",data:await this.renderPdf(D.urlFor($.urlPath),{maxBytes:GzB,timeoutMs:zzB,printBackground:!0,preferCSSPageSize:!0}),mimeType:"application/pdf",filename:`${FzB(Q)}-printable.pdf`}}finally{await D.close()}}finally{await ZzB(w,{recursive:!0,force:!0})}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}}function qzB(A,Q={}){let{frontmatter:B,content:w}=lB(A.content),$=CX.parse(B);return{name:$.name,body:w,availability:$.availability,...Q.brandLabel?{brandLabel:Q.brandLabel}:{}}}function FzB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.name)}K0();K0();import{jsxDEV as JzB}from"preact/jsx-dev-runtime";var QY0="og-image",IzB="products:og-image",Ke1=K.object({name:K.string().min(1),tagline:K.string().optional(),availability:K.string().optional(),brandLabel:K.string().optional()}),Ue1={name:IzB,pluginId:"products",schema:Ke1,renderers:{image:VzB}};function VzB(A){let Q=Ke1.parse(A);return JzB(c3,{cover:!0,brandLabel:Q.brandLabel??Q.name,eyebrow:"Product",title:Q.name,subtitle:Q.tagline,tag:Q.availability},void 0,!1,void 0,this)}class cr0{context;deps;constructor(A,Q={}){this.context=A;this.deps=Q}async resolve(A){if(A.sourceEntityType!=="product"||A.attachmentType!==QY0)return;let Q=await this.context.entityService.getEntity({entityType:"product",id:A.sourceEntityId});if(!Q)return;let{frontmatter:B,content:w}=lB(Q.content),$=CX.parse(B),D=LzB(w,"Tagline"),f=this.resolveBrandLabel(),Y={name:$.name,availability:$.availability,...D?{tagline:D}:{},...f?{brandLabel:f}:{}};return{type:"image",data:await XP({mediaPath:`/_media/og/product/${Q.id}`,template:Ue1,content:Y,title:Y.name,themeMode:"light",themeCSS:this.context.themeCSS,tmpPrefix:"brain-product-og-image-",...this.deps.screenshotPng&&{screenshotPng:this.deps.screenshotPng}}),mimeType:"image/png",filename:`${bzB(Q)}-og.png`}}resolveBrandLabel(){let A=this.context.domain?.trim();if(A&&A.length>0)return A;let Q=this.context.identity.getProfile().name.trim();return Q.length>0?Q:void 0}}function LzB(A,Q){let B=A.split(/\r?\n/),w=B.findIndex((f)=>f.trim().toLowerCase()===`## ${Q.toLowerCase()}`);if(w===-1)return;let $=[];for(let f of B.slice(w+1)){if(f.trim().startsWith("## "))break;$.push(f)}let D=$.join(`
|
|
9333
|
-
`).trim();return D.length>0?D:void 0}function bzB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.name)}var Ge1={name:"@brains/products",private:!0,version:"0.2.0-alpha.
|
|
9333
|
+
`).trim();return D.length>0?D:void 0}function bzB(A){let Q=A.metadata.slug;return Q.length>0?Q:Y1(A.metadata.name)}var Ge1={name:"@brains/products",private:!0,version:"0.2.0-alpha.129",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/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/media-page-composer":"workspace:*","@brains/media-renderer":"workspace:*","@brains/plugins":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*"},devDependencies:{"@brains/app":"workspace:*","@brains/eslint-config":"workspace:*","@brains/typescript-config":"workspace:*","@types/bun":"latest","bun-types":"latest",eslint:"^8.56.0",typescript:"^5.3.3"}};var jzB=K.object({overview:Co,products:K.array(sf0)}),_zB=K.object({product:sf0});class lr0 extends PQ{entityType=af0.entityType;schema=hE;adapter=af0;unregisterPrintableAttachmentProvider;unregisterOgImageAttachmentProvider;constructor(A={}){super("products",Ge1,A,mr0)}getTemplates(){return{"product-list":R1({name:"product-list",description:"Products page \u2014 overview + brain model cards",schema:jzB,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:Xe1}}),"product-detail":R1({name:"product-detail",description:"Individual product detail page",schema:_zB,dataSourceId:"products:entities",requiredPermission:"public",layout:{component:He1}})}}getDataSources(){return[new ef0(this.logger.child("ProductsDataSource"))]}async onRegister(A){this.unregisterPrintableAttachmentProvider=A.attachments.register("product",AY0,new ur0(A)),this.unregisterOgImageAttachmentProvider=A.attachments.register("product",QY0,new cr0(A)),A.entities.register("products-overview",yE,Sr0)}async onShutdown(){this.unregisterPrintableAttachmentProvider?.(),this.unregisterPrintableAttachmentProvider=void 0,this.unregisterOgImageAttachmentProvider?.(),this.unregisterOgImageAttachmentProvider=void 0}}function pr0(A={}){return new lr0(A)}import{join as ezB}from"path";import{jsxDEV as BY0,Fragment as MzB}from"preact/jsx-dev-runtime";var gE=({children:A})=>BY0(MzB,{children:[BY0("div",{id:"bgCanvasWrap",className:"rizom-frame-canvas-wrap fixed top-0 left-0 w-full h-full pointer-events-none",children:BY0("canvas",{id:"heroCanvas",className:"w-full h-full block"},void 0,!1,void 0,this)},void 0,!1,void 0,this),BY0("div",{className:"max-w-[1440px] mx-auto relative overflow-x-clip",children:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this);import{jsxDEV as lY6}from"preact/jsx-dev-runtime";import{jsxDEV as kzB}from"preact/jsx-dev-runtime";var wY0="px-6 md:px-10 xl:px-20",PzB=`${wY0} relative z-[1]`,gL=({id:A,className:Q,children:B})=>kzB("section",{id:A,className:$2(PzB,Q),children:B},void 0,!1,void 0,this);import{jsxDEV as aY6}from"preact/jsx-dev-runtime";import{jsxDEV as AX6}from"preact/jsx-dev-runtime";import{jsxDEV as hzB}from"preact/jsx-dev-runtime";var OzB="inline-flex items-center justify-center cursor-pointer border border-solid transition-all [gap:var(--rizom-btn-gap)] [border-radius:var(--rizom-btn-radius)] [font-family:var(--rizom-btn-font-family)] [font-style:var(--rizom-btn-font-style)] [letter-spacing:var(--rizom-btn-letter-spacing)] [text-transform:var(--rizom-btn-text-transform)]",xzB={primary:"[font-weight:var(--rizom-btn-primary-font-weight)] [color:var(--rizom-btn-primary-color)] [background:var(--rizom-btn-primary-bg)] [border-color:var(--rizom-btn-primary-border-color)] [border-width:var(--rizom-btn-primary-border-width)] [box-shadow:var(--rizom-btn-primary-shadow)] hover:[color:var(--rizom-btn-primary-hover-color)] hover:[background:var(--rizom-btn-primary-hover-bg)] hover:[border-color:var(--rizom-btn-primary-hover-border-color)] hover:[border-width:var(--rizom-btn-primary-hover-border-width)] hover:[box-shadow:var(--rizom-btn-primary-hover-shadow)] hover:[transform:var(--rizom-btn-primary-hover-transform)]","primary-strong":"duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] [font-weight:var(--rizom-btn-primary-strong-font-weight)] [color:var(--rizom-btn-primary-strong-color)] [background:var(--rizom-btn-primary-strong-bg)] [border-color:var(--rizom-btn-primary-strong-border-color)] [border-width:var(--rizom-btn-primary-strong-border-width)] [box-shadow:var(--rizom-btn-primary-strong-shadow)] hover:[color:var(--rizom-btn-primary-strong-hover-color)] hover:[background:var(--rizom-btn-primary-strong-hover-bg)] hover:[border-color:var(--rizom-btn-primary-strong-hover-border-color)] hover:[border-width:var(--rizom-btn-primary-strong-hover-border-width)] hover:[box-shadow:var(--rizom-btn-primary-strong-hover-shadow)] hover:[transform:var(--rizom-btn-primary-strong-hover-transform)]",secondary:"[font-weight:var(--rizom-btn-secondary-font-weight)] [color:var(--rizom-btn-secondary-color)] [background:var(--rizom-btn-secondary-bg)] [border-color:var(--rizom-btn-secondary-border-color)] [border-width:var(--rizom-btn-secondary-border-width)] [box-shadow:var(--rizom-btn-secondary-shadow)] hover:[color:var(--rizom-btn-secondary-hover-color)] hover:[background:var(--rizom-btn-secondary-hover-bg)] hover:[border-color:var(--rizom-btn-secondary-hover-border-color)] hover:[border-width:var(--rizom-btn-secondary-hover-border-width)] hover:[box-shadow:var(--rizom-btn-secondary-hover-shadow)] hover:[transform:var(--rizom-btn-secondary-hover-transform)]"},RzB={md:"text-base [padding:var(--rizom-btn-md-padding)]",lg:"text-body-md md:text-body-lg [padding:var(--rizom-btn-lg-padding-mobile)] md:[padding:var(--rizom-btn-lg-padding-desktop)]"},vzB="w-full md:w-auto",vP=({href:A,variant:Q="primary",size:B="md",block:w=!1,className:$,children:D})=>hzB("a",{href:A,className:$2("rizom-btn",`rizom-btn-${Q}`,`rizom-btn-${B}`,w&&"rizom-btn-block",OzB,xzB[Q],RzB[B],w&&vzB,$),children:D},void 0,!1,void 0,this);import{jsxDEV as YX6}from"preact/jsx-dev-runtime";import{jsxDEV as ZX6}from"preact/jsx-dev-runtime";import{Fragment as GX6}from"preact";import{jsxDEV as qX6}from"preact/jsx-dev-runtime";import{jsxDEV as ze1}from"preact/jsx-dev-runtime";var $Y0=({sections:A})=>ze1(gE,{children:ze1("main",{children:A},void 0,!1,void 0,this)},void 0,!1,void 0,this);p0();K0();var qe1=`/*
|
|
9334
9334
|
* Shared globals + helpers used by tree / constellation / roots canvas
|
|
9335
9335
|
* scripts. Loaded as a shared static asset by the Rizom runtime package
|
|
9336
9336
|
* so the variant canvases
|
|
@@ -11820,7 +11820,7 @@ facts, owners, or tasks. Return only the required structured JSON.`});K0();var Z
|
|
|
11820
11820
|
`);return this.truncateContent(w||Q||dE(A))}truncateContent(A){if(A.length<=ee1)return A;let Q=A.slice(0,ee1-1),B=Q.search(/\s\S*$/);return`${(B>0?Q.slice(0,B):Q).trimEnd()}\u2026`}isSummaryEntity(A){return A.entityType===q5}isDecisionEntity(A){return A.entityType===EX}getEntitySpaceId(A){let Q=A.metadata;if("spaceId"in Q&&typeof Q.spaceId==="string")return Q.spaceId;return _K(Q)}}var EqB=5,gqB=3;function Ao0(A){A.messaging.subscribe(BN,async(Q)=>{let B=TT.parse(Q.payload);return{success:!0,data:await FY0(A,B)}})}async function FY0(A,Q){let B=p8(Q.userPermissionLevel);if(!Q.channelId)return A02(A,Q,{visibilityScope:B,reason:"no-channel-context",items:[]}),{items:[]};let w=new nE(A),$=await w.retrieve({query:Q.message,conversationId:Q.conversationId,interfaceType:Q.interfaceType,channelId:Q.channelId,limit:EqB,visibilityScope:B}),D=$.results.length===0?await w.retrieve({conversationId:Q.conversationId,interfaceType:Q.interfaceType,channelId:Q.channelId,limit:gqB,visibilityScope:B}):void 0,f=$.results.length>0,Y=f?$.results:D?.results??[];return A02(A,Q,{visibilityScope:B,spaceId:$.spaceId??D?.spaceId,reason:Y.length>0?"memory-injected":"no-same-space-memory",items:Y.map((X)=>TqB(X,f))}),{items:Y.map(SqB)}}function A02(A,Q,B){A.logger.info("Conversation memory agent context audit",{conversationId:Q.conversationId,interfaceType:Q.interfaceType,channelId:Q.channelId,channelName:Q.channelName,userPermissionLevel:Q.userPermissionLevel,visibilityScope:B.visibilityScope,spaceId:B.spaceId,reason:B.reason,itemCount:B.items.length,items:B.items})}function TqB(A,Q){return{id:A.id,entityType:A.entityType,conversationId:A.conversationId,spaceId:A.spaceId,visibility:A.visibility,score:A.score,updated:A.updated,eligibilityReason:Q?"same-space-query-match":"recent-same-space-memory"}}function SqB(A){let Q=A.channelName??A.channelId;return{id:A.id,source:"conversation-memory",title:`${A.entityType} from ${Q}`,content:A.content,provenance:{entityType:A.entityType,entityId:A.id,conversationId:A.conversationId,spaceId:A.spaceId,interfaceType:A.interfaceType,channelId:A.channelId,channelName:A.channelName,updated:A.updated,score:A.score,messageCount:A.messageCount,entryCount:A.entryCount,status:A.status}}}p0();Cw();K0();bY();var Bo0=K.object({role:Qq,content:K.string(),timestamp:K.string().datetime().optional(),actor:JN.optional(),source:LN.optional()}),mqB=K.object({conversationId:K.string().default("eval-conversation"),messages:K.array(Bo0)}),uqB=K.object({conversationId:K.string()}),cqB=K.object({conversationId:K.string().default("eval-conversation"),interfaceType:K.string().default("eval"),channelId:K.string().default("eval-channel"),channelName:K.string().optional(),projectionDecision:K.enum(["update","append"]).default("update"),existingSummary:K.string().optional(),existingMessageCount:K.number().int().min(0).default(0),messages:K.array(Bo0)}),IY0=K.object({actorId:K.string(),canonicalId:K.string().optional(),displayName:K.string().optional()}),lqB=IY0.extend({roles:K.array(K.enum(["user","assistant","system"])).default(["user"]),sourceActorIds:K.array(K.string()).optional()}),pqB=K.object({actorId:K.string().optional(),canonicalId:K.string().optional(),displayName:K.string()}),w02=K.object({id:K.string(),entityType:K.enum(["summary","decision","action-item"]),content:K.string(),excerpt:K.string().optional(),score:K.number().optional(),conversationId:K.string(),interfaceType:K.string(),channelId:K.string(),channelName:K.string().optional(),updated:K.string().datetime().optional(),visibility:Y7,status:K.string().optional(),participants:K.array(lqB).optional(),decidedBy:K.array(IY0).optional(),mentionedBy:K.array(IY0).optional(),assignedTo:K.array(pqB).optional(),requestedBy:K.array(IY0).optional()}),iqB=K.object({query:K.string().optional(),conversationId:K.string().optional(),interfaceType:K.string().optional(),channelId:K.string().optional(),limit:K.number().int().min(1).optional(),includeOtherSpaces:K.boolean().optional(),actorId:K.string().optional(),canonicalId:K.string().optional(),visibilityScope:Y7.optional(),memory:K.array(w02).optional()}),dqB=K.object({conversationId:K.string().default("eval-conversation"),message:K.string(),interfaceType:K.string().default("eval"),channelId:K.string().optional(),channelName:K.string().optional(),userPermissionLevel:K.enum(["anchor","trusted","public"]).default("trusted"),memory:K.array(w02).optional()}),nqB=K.object({conversationId:K.string().default("eval-conversation"),existingSummary:K.string().optional(),existingMessageCount:K.number().int().min(0).default(0),messages:K.array(Bo0)});function $02(A){let{context:Q,logger:B,config:w}=A;Q.eval.registerHandler("summarizeMessages",async($)=>{let D=mqB.parse($),f=Qo0(D.messages,D.conversationId),X=await new lE(Q,B,w).extract(f);return X.entries.map((H)=>{let W=X.decisions.filter((G)=>G.timeRange.start>=H.timeRange.start).filter((G)=>G.timeRange.end<=H.timeRange.end).map((G)=>G.text),Z=X.actionItems.filter((G)=>G.timeRange.start>=H.timeRange.start).filter((G)=>G.timeRange.end<=H.timeRange.end).map((G)=>G.text);return{...H,decisions:W,actionItems:Z,keyPointsText:H.keyPoints.join(`
|
|
11821
11821
|
`),decisionsText:W.join(`
|
|
11822
11822
|
`),actionItemsText:Z.join(`
|
|
11823
|
-
`)}})}),Q.eval.registerHandler("decideProjection",async($)=>{let D=nqB.parse($),f=Qo0(D.messages,D.conversationId),Y=D.existingSummary?Q02({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null;return new SL(Q,B,w).decideProjection(f,Y)}),Q.eval.registerHandler("retrieveMemory",async($)=>{let D=iqB.parse($),f=D.memory?B02(Q,D.memory):Q;return new nE(f).retrieve(D)}),Q.eval.registerHandler("buildAgentContext",async($)=>{let D=dqB.parse($),f=D.memory?B02(Q,D.memory):Q;return FY0(f,D)}),Q.eval.registerHandler("projectMessages",async($)=>{let D=cqB.parse($),f=Qo0(D.messages,D.conversationId),Y=rqB({conversationId:D.conversationId,interfaceType:D.interfaceType,channelId:D.channelId,channelName:D.channelName,messages:f}),X=D.existingSummary?Q02({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null,H=[],W=[],Z=oqB({context:Q,conversation:Y,messages:f,existing:X,upserted:H,deleted:W,projectionDecision:D.projectionDecision});return{result:await new SL(Z,B,w).projectConversation(D.conversationId),summaries:H.filter((I)=>I.entityType==="summary"),decisions:H.filter((I)=>I.entityType==="decision"),actionItems:H.filter((I)=>I.entityType==="action-item"),deleted:W}}),Q.eval.registerHandler("projectConversation",async($)=>{let D=uqB.parse($);return new SL(Q,B,w).projectConversation(D.conversationId)})}function Q02(A){return{id:A.conversationId,entityType:"summary",content:A.content,contentHash:"eval-existing-summary",visibility:A.visibility,created:"2026-01-01T00:00:00.000Z",updated:"2026-01-01T00:00:00.000Z",metadata:{conversationId:A.conversationId,channelId:"eval-channel",interfaceType:"eval",messageCount:A.messageCount,entryCount:1,sourceHash:"eval-source-hash",projectionVersion:A.projectionVersion}}}function Qo0(A,Q){return A.map((B,w)=>{let $=B.timestamp??new Date(Date.UTC(2026,0,1,0,w)).toISOString();return{id:`eval-message-${w+1}`,conversationId:Q,role:B.role,content:B.content,timestamp:$,metadata:{...B.actor?{actor:B.actor}:{},...B.source?{source:B.source}:{}}}})}function rqB(A){let Q=A.messages[0],B=A.messages[A.messages.length-1],w=Q?.timestamp??"2026-01-01T00:00:00.000Z",$=B?.timestamp??w;return{id:A.conversationId,sessionId:A.conversationId,interfaceType:A.interfaceType,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},startedAt:w,lastActiveAt:$,createdAt:w,updatedAt:$,metadata:{}}}function oqB(A){let Q=_K(A.conversation);return{...A.context,spaces:[Q],conversations:{...A.context.conversations,get:async()=>A.conversation,getMessages:async()=>A.messages},ai:{...A.context.ai,generateObject:async()=>({object:{decision:A.projectionDecision,rationale:"Forced by eval input"}})},entityService:{...A.context.entityService,getEntity:async({entityType:B})=>B==="summary"?A.existing:null,listEntities:async()=>[],deleteEntity:async(B)=>{return A.deleted.push(B),!0},upsertEntity:async({entity:B})=>{return A.upserted.push(B),{entityId:B.id,jobId:"eval-upsert",created:!0,skipped:!1}}}}}function B02(A,Q){let B=Q.map(sqB),w=B.map(($,D)=>({entity:$,score:Q[D]?.score??1,excerpt:Q[D]?.excerpt??dE($)}));return{...A,entityService:{...A.entityService,search:async()=>w,listEntities:async({entityType:$})=>B.filter((D)=>D.entityType===$)}}}function sqB(A){if(A.entityType==="summary")return aqB(A);if(A.entityType==="decision")return tqB(A);return eqB(A)}function wo0(A){let Q=A.updated??"2026-01-01T00:00:00.000Z";return{id:A.id,content:A.content,contentHash:RB(A.content),visibility:A.visibility,created:Q,updated:Q}}function aqB(A){return{...wo0(A),entityType:"summary",metadata:{conversationId:A.conversationId,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},interfaceType:A.interfaceType,messageCount:3,entryCount:1,sourceHash:`source-${A.id}`,projectionVersion:1,...A.participants?{participants:A.participants}:{}}}}function tqB(A){return{...wo0(A),entityType:"decision",metadata:{conversationId:A.conversationId,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},interfaceType:A.interfaceType,spaceId:_K(A),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:A.conversationId,sourceMessageCount:2,projectionVersion:1,status:A.status==="superseded"?"superseded":"active",...A.decidedBy?{decidedBy:A.decidedBy}:{},...A.mentionedBy?{mentionedBy:A.mentionedBy}:{}}}}function eqB(A){let Q=A.status==="done"||A.status==="dropped"?A.status:"open";return{...wo0(A),entityType:"action-item",metadata:{conversationId:A.conversationId,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},interfaceType:A.interfaceType,spaceId:_K(A),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:A.conversationId,sourceMessageCount:2,projectionVersion:1,status:Q,...A.assignedTo?{assignedTo:A.assignedTo}:{},...A.requestedBy?{requestedBy:A.requestedBy}:{}}}}var D02={name:"@brains/conversation-memory",private:!0,version:"0.2.0-alpha.128",description:"Plugin for deriving durable conversation memory",type:"module",main:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint src test --ext .ts,.tsx",eval:"cd evals && bun run brain-eval","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/conversation-service":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};var Q3B=new ZW,B3B=new mE,w3B=new uE,$3B=K.object({conversationId:K.string()});class $o0 extends PQ{entityType=q5;schema=Eo;adapter=Q3B;constructor(A={}){super(fY0,D02,A,rr0)}getConfig(){return this.config}getTemplates(){return{"summary-list":Re1,"summary-detail":ve1,"ai-response":he1}}getDataSources(){return[new er0(this.logger.child("SummaryDataSource"))]}getDerivedEntityProjections(A){if(!this.config.enableProjection)return[];return[{id:"conversation-memory-projection",targetType:q5,job:{type:je1,handler:new KY0(A,this.logger,this.config)},initialSync:{shouldEnqueue:async()=>A.spaces.length>0&&!await zN(A,q5,{outputVisibility:this.config.memoryVisibility}),jobData:{mode:"rebuild-all",reason:"initial-sync"},jobOptions:{source:nr0,deduplication:"coalesce",deduplicationKey:"conversation-memory:rebuild-all:initial-sync",metadata:{operationType:"data_processing",operationTarget:"conversation-memory:rebuild-all",pluginId:fY0}}},sourceChange:{sourceKind:qS,sourceTypes:[qS],shouldEnqueue:(Q)=>this.shouldEnqueueConversationProjection(A,Q),events:[rO],jobData:(Q)=>{let{conversationId:B}=this.parseConversationMessagePayload(Q);return{mode:"conversation",conversationId:B,reason:"message-added"}},jobOptions:(Q)=>{let{conversationId:B}=this.parseConversationMessagePayload(Q);return{priority:5,delayMs:this.config.projectionDelayMs,source:nr0,deduplication:"skip",deduplicationKey:`conversation-memory:${B}`,metadata:{operationType:"data_processing",operationTarget:`conversation-memory:${B}`,pluginId:fY0}}}}}]}parseConversationMessagePayload(A){return $3B.parse(A)}async shouldEnqueueConversationProjection(A,Q){let{conversationId:B}=this.parseConversationMessagePayload(Q),w=await A.conversations.get(B);if(!w)return!1;return yP({conversation:w,spaces:A.spaces}).eligible}async onRegister(A){A.entities.register(EX,go,B3B),A.entities.register(WW,To,w3B),Ee1({context:A,pluginId:this.id}),Te1({context:A,pluginId:this.id}),re1({context:A,pluginId:this.id}),ae1({context:A,pluginId:this.id,config:this.config}),Ao0(A),$02({context:A,logger:this.logger,config:this.config})}}function Do0(A){return new $o0(A)}p0();K0();p0();var JF=K.object({title:K.string(),section:K.string(),order:K.number().int(),sourcePath:K.string(),description:K.string().optional(),slug:K.string().optional()}),f02=JF.pick({title:!0,section:!0,order:!0,description:!0}).extend({slug:K.string()}),rE=o1.extend({entityType:K.literal("doc"),metadata:f02}),LF=rE.extend({frontmatter:JF,body:K.string()});p0();K0();class fo0 extends V2{constructor(){super({entityType:"doc",schema:rE,frontmatterSchema:JF})}toMarkdown(A){let Q=this.extractBody(A.content),B=this.parseFrontMatter(A.content,JF);return this.buildMarkdown(Q,B)}fromMarkdown(A){let Q=this.parseFrontMatter(A,JF),B=Q.slug??Y1(Q.title);return{content:A,entityType:"doc",metadata:{title:Q.title,section:Q.section,order:Q.order,slug:B,...Q.description?{description:Q.description}:{}}}}}var VY0=new fo0;p0();function Y02(A){return[...A].sort((Q,B)=>{let w=Q.metadata.order-B.metadata.order;if(w!==0)return w;return Q.metadata.title.localeCompare(B.metadata.title)})}function X02(A){let Q=h2(A.content,JF);return LF.parse({...A,frontmatter:Q.metadata,body:Q.content})}class JY0 extends W${id="docs:entities";name="Docs Entity DataSource";description="Fetches and transforms doc entities for rendering";config={entityType:"doc",defaultSort:[{field:"order",direction:"asc"},{field:"section",direction:"asc"},{field:"title",direction:"asc"}],defaultLimit:100,enableNavigation:!0};constructor(A){super(A)}transformEntity(A){return X02(A)}async fetch(A,Q,B){let w=this.parseQuery(A);if(!w.query.id){let W=await this.fetchList({...w.query,limit:1000,page:void 0,pageSize:void 0},B.entityService);return Q.parse(this.buildListResult(W.items,null,w.query))}let[$,D]=await Promise.all([this.fetchDetail(w.query.id,B.entityService),this.fetchList({limit:1000},B.entityService)]),f=Y02(D.items),Y=f.findIndex((W)=>W.id===$.item.id),X=Y>0?f[Y-1]:null,H=Y>=0&&Y<f.length-1?f[Y+1]:null;return Q.parse({doc:$.item,docs:f,prevDoc:X,nextDoc:H})}buildDetailResult(A,Q){return{doc:A,docs:[A],prevDoc:Q?.prev??null,nextDoc:Q?.next??null}}buildListResult(A,Q,B){return{docs:Y02(A),pagination:Q,baseUrl:B.baseUrl}}}p0();Jw();K0();import{jsxDEV as x$}from"preact/jsx-dev-runtime";var D3B=["I","II","III","IV","V","VI","VII","VIII","IX","X"];function uo(A){return[...A].sort((Q,B)=>{let w=Q.metadata.order-B.metadata.order;if(w!==0)return w;return Q.metadata.title.localeCompare(B.metadata.title)})}function LY0(A){let Q=new Map;for(let B of uo(A)){let w=B.metadata.section;Q.set(w,[...Q.get(w)??[],B])}return[...Q.entries()].map(([B,w])=>({section:B,docs:w}))}function oE(A){return`/docs/${A.metadata.slug}`}function bY0(A){return`section-${A+1}`}function sE(A){return D3B[A]??String(A+1)}var Z02="text-[var(--docs-text)] font-bold",K02="text-[var(--docs-accent)] font-bold",U02="text-[var(--docs-text-muted)]",f3B="docs-font-label text-xs uppercase tracking-[0.18em] text-[var(--docs-accent)]",Y3B="docs-font-display text-[var(--docs-heading)]",H02="inline-flex items-center justify-center rounded-lg border px-[18px] py-2.5 text-sm font-semibold transition-colors duration-150",W02="relative hidden py-1 text-[15px] text-[var(--docs-text-muted)] transition-colors duration-150 after:absolute after:bottom-0 after:left-0 after:h-px after:w-0 after:bg-[var(--docs-accent)] after:transition-[width] after:duration-300 hover:text-[var(--docs-text)] hover:after:w-full min-[861px]:inline-block",Yo0="docs-font-label text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:text-[var(--docs-text)]",Bz={wrap:"mx-auto max-w-6xl px-6 pt-20 md:px-12 md:pt-24",label:f3B,display:Y3B,button:`${H02} border-[var(--docs-text)] text-[var(--docs-text)] hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)]`,primaryButton:`${H02} border-[var(--docs-accent)] bg-[var(--docs-accent)] text-white hover:bg-transparent hover:text-[var(--docs-accent)]`},G02=()=>x$("nav",{className:"docs-header fixed inset-x-0 top-0 z-[100] flex items-center justify-between px-6 py-4 md:px-10 md:py-5 xl:px-20",children:[x$("a",{href:"/docs",className:"docs-font-body text-xl font-bold","aria-label":"Brains docs",children:[x$("span",{className:Z02,children:"brains"},void 0,!1,void 0,this),x$("span",{className:K02,children:"."},void 0,!1,void 0,this),x$("span",{className:U02,children:"docs"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x$("div",{className:"docs-header__nav flex items-center gap-4 md:gap-8",children:[x$("a",{className:W02,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),x$("a",{className:W02,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),x$("a",{href:"https://rizom.ai",className:"inline-flex items-center justify-center rounded-lg border border-[var(--docs-text)] px-4 py-2 text-[13px] font-semibold text-[var(--docs-text)] transition-colors duration-150 hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)] md:px-6 md:py-2.5 md:text-[15px]",children:"Get Brains"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z02=()=>x$("footer",{className:"flex flex-col items-center justify-between gap-4 border-t border-[var(--docs-border-light)] py-8 text-center md:flex-row md:gap-6 md:py-6 md:text-left",children:[x$("a",{href:"https://rizom.ai",className:"docs-font-body text-[15px] font-bold",children:[x$("span",{className:Z02,children:"rizom"},void 0,!1,void 0,this),x$("span",{className:K02,children:"."},void 0,!1,void 0,this),x$("span",{className:U02,children:"ai"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x$("div",{className:"flex flex-wrap items-center justify-center gap-6 md:justify-end",children:[x$("a",{className:Yo0,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),x$("a",{className:Yo0,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),x$("a",{className:Yo0,href:"https://rizom.ai",children:"Rizom"},void 0,!1,void 0,this),x$("button",{id:"themeToggle",className:"docs-font-label cursor-pointer rounded-md border border-[var(--docs-text-light)] bg-transparent px-2.5 py-1.5 text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:border-[var(--docs-text)] hover:text-[var(--docs-text)]",type:"button",children:"\u2600 Light"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),X3B=`
|
|
11823
|
+
`)}})}),Q.eval.registerHandler("decideProjection",async($)=>{let D=nqB.parse($),f=Qo0(D.messages,D.conversationId),Y=D.existingSummary?Q02({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null;return new SL(Q,B,w).decideProjection(f,Y)}),Q.eval.registerHandler("retrieveMemory",async($)=>{let D=iqB.parse($),f=D.memory?B02(Q,D.memory):Q;return new nE(f).retrieve(D)}),Q.eval.registerHandler("buildAgentContext",async($)=>{let D=dqB.parse($),f=D.memory?B02(Q,D.memory):Q;return FY0(f,D)}),Q.eval.registerHandler("projectMessages",async($)=>{let D=cqB.parse($),f=Qo0(D.messages,D.conversationId),Y=rqB({conversationId:D.conversationId,interfaceType:D.interfaceType,channelId:D.channelId,channelName:D.channelName,messages:f}),X=D.existingSummary?Q02({conversationId:D.conversationId,content:D.existingSummary,messageCount:D.existingMessageCount,projectionVersion:w.projectionVersion,visibility:w.memoryVisibility}):null,H=[],W=[],Z=oqB({context:Q,conversation:Y,messages:f,existing:X,upserted:H,deleted:W,projectionDecision:D.projectionDecision});return{result:await new SL(Z,B,w).projectConversation(D.conversationId),summaries:H.filter((I)=>I.entityType==="summary"),decisions:H.filter((I)=>I.entityType==="decision"),actionItems:H.filter((I)=>I.entityType==="action-item"),deleted:W}}),Q.eval.registerHandler("projectConversation",async($)=>{let D=uqB.parse($);return new SL(Q,B,w).projectConversation(D.conversationId)})}function Q02(A){return{id:A.conversationId,entityType:"summary",content:A.content,contentHash:"eval-existing-summary",visibility:A.visibility,created:"2026-01-01T00:00:00.000Z",updated:"2026-01-01T00:00:00.000Z",metadata:{conversationId:A.conversationId,channelId:"eval-channel",interfaceType:"eval",messageCount:A.messageCount,entryCount:1,sourceHash:"eval-source-hash",projectionVersion:A.projectionVersion}}}function Qo0(A,Q){return A.map((B,w)=>{let $=B.timestamp??new Date(Date.UTC(2026,0,1,0,w)).toISOString();return{id:`eval-message-${w+1}`,conversationId:Q,role:B.role,content:B.content,timestamp:$,metadata:{...B.actor?{actor:B.actor}:{},...B.source?{source:B.source}:{}}}})}function rqB(A){let Q=A.messages[0],B=A.messages[A.messages.length-1],w=Q?.timestamp??"2026-01-01T00:00:00.000Z",$=B?.timestamp??w;return{id:A.conversationId,sessionId:A.conversationId,interfaceType:A.interfaceType,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},startedAt:w,lastActiveAt:$,createdAt:w,updatedAt:$,metadata:{}}}function oqB(A){let Q=_K(A.conversation);return{...A.context,spaces:[Q],conversations:{...A.context.conversations,get:async()=>A.conversation,getMessages:async()=>A.messages},ai:{...A.context.ai,generateObject:async()=>({object:{decision:A.projectionDecision,rationale:"Forced by eval input"}})},entityService:{...A.context.entityService,getEntity:async({entityType:B})=>B==="summary"?A.existing:null,listEntities:async()=>[],deleteEntity:async(B)=>{return A.deleted.push(B),!0},upsertEntity:async({entity:B})=>{return A.upserted.push(B),{entityId:B.id,jobId:"eval-upsert",created:!0,skipped:!1}}}}}function B02(A,Q){let B=Q.map(sqB),w=B.map(($,D)=>({entity:$,score:Q[D]?.score??1,excerpt:Q[D]?.excerpt??dE($)}));return{...A,entityService:{...A.entityService,search:async()=>w,listEntities:async({entityType:$})=>B.filter((D)=>D.entityType===$)}}}function sqB(A){if(A.entityType==="summary")return aqB(A);if(A.entityType==="decision")return tqB(A);return eqB(A)}function wo0(A){let Q=A.updated??"2026-01-01T00:00:00.000Z";return{id:A.id,content:A.content,contentHash:RB(A.content),visibility:A.visibility,created:Q,updated:Q}}function aqB(A){return{...wo0(A),entityType:"summary",metadata:{conversationId:A.conversationId,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},interfaceType:A.interfaceType,messageCount:3,entryCount:1,sourceHash:`source-${A.id}`,projectionVersion:1,...A.participants?{participants:A.participants}:{}}}}function tqB(A){return{...wo0(A),entityType:"decision",metadata:{conversationId:A.conversationId,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},interfaceType:A.interfaceType,spaceId:_K(A),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:A.conversationId,sourceMessageCount:2,projectionVersion:1,status:A.status==="superseded"?"superseded":"active",...A.decidedBy?{decidedBy:A.decidedBy}:{},...A.mentionedBy?{mentionedBy:A.mentionedBy}:{}}}}function eqB(A){let Q=A.status==="done"||A.status==="dropped"?A.status:"open";return{...wo0(A),entityType:"action-item",metadata:{conversationId:A.conversationId,channelId:A.channelId,...A.channelName?{channelName:A.channelName}:{},interfaceType:A.interfaceType,spaceId:_K(A),timeRange:{start:"2026-01-01T00:00:00.000Z",end:"2026-01-01T00:01:00.000Z"},sourceSummaryId:A.conversationId,sourceMessageCount:2,projectionVersion:1,status:Q,...A.assignedTo?{assignedTo:A.assignedTo}:{},...A.requestedBy?{requestedBy:A.requestedBy}:{}}}}var D02={name:"@brains/conversation-memory",private:!0,version:"0.2.0-alpha.129",description:"Plugin for deriving durable conversation memory",type:"module",main:"./src/index.ts",exports:{".":"./src/index.ts"},scripts:{test:"bun test",typecheck:"tsc --noEmit",lint:"eslint src test --ext .ts,.tsx",eval:"cd evals && bun run brain-eval","lint:fix":"eslint src test --ext .ts,.tsx --fix"},dependencies:{"@brains/content-formatters":"workspace:*","@brains/contracts":"workspace:*","@brains/conversation-service":"workspace:*","@brains/dashboard":"workspace:*","@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/eslint-config":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@types/node":"^20.0.0",eslint:"^8.56.0",typescript:"^5.3.3"}};var Q3B=new ZW,B3B=new mE,w3B=new uE,$3B=K.object({conversationId:K.string()});class $o0 extends PQ{entityType=q5;schema=Eo;adapter=Q3B;constructor(A={}){super(fY0,D02,A,rr0)}getConfig(){return this.config}getTemplates(){return{"summary-list":Re1,"summary-detail":ve1,"ai-response":he1}}getDataSources(){return[new er0(this.logger.child("SummaryDataSource"))]}getDerivedEntityProjections(A){if(!this.config.enableProjection)return[];return[{id:"conversation-memory-projection",targetType:q5,job:{type:je1,handler:new KY0(A,this.logger,this.config)},initialSync:{shouldEnqueue:async()=>A.spaces.length>0&&!await zN(A,q5,{outputVisibility:this.config.memoryVisibility}),jobData:{mode:"rebuild-all",reason:"initial-sync"},jobOptions:{source:nr0,deduplication:"coalesce",deduplicationKey:"conversation-memory:rebuild-all:initial-sync",metadata:{operationType:"data_processing",operationTarget:"conversation-memory:rebuild-all",pluginId:fY0}}},sourceChange:{sourceKind:qS,sourceTypes:[qS],shouldEnqueue:(Q)=>this.shouldEnqueueConversationProjection(A,Q),events:[rO],jobData:(Q)=>{let{conversationId:B}=this.parseConversationMessagePayload(Q);return{mode:"conversation",conversationId:B,reason:"message-added"}},jobOptions:(Q)=>{let{conversationId:B}=this.parseConversationMessagePayload(Q);return{priority:5,delayMs:this.config.projectionDelayMs,source:nr0,deduplication:"skip",deduplicationKey:`conversation-memory:${B}`,metadata:{operationType:"data_processing",operationTarget:`conversation-memory:${B}`,pluginId:fY0}}}}}]}parseConversationMessagePayload(A){return $3B.parse(A)}async shouldEnqueueConversationProjection(A,Q){let{conversationId:B}=this.parseConversationMessagePayload(Q),w=await A.conversations.get(B);if(!w)return!1;return yP({conversation:w,spaces:A.spaces}).eligible}async onRegister(A){A.entities.register(EX,go,B3B),A.entities.register(WW,To,w3B),Ee1({context:A,pluginId:this.id}),Te1({context:A,pluginId:this.id}),re1({context:A,pluginId:this.id}),ae1({context:A,pluginId:this.id,config:this.config}),Ao0(A),$02({context:A,logger:this.logger,config:this.config})}}function Do0(A){return new $o0(A)}p0();K0();p0();var JF=K.object({title:K.string(),section:K.string(),order:K.number().int(),sourcePath:K.string(),description:K.string().optional(),slug:K.string().optional()}),f02=JF.pick({title:!0,section:!0,order:!0,description:!0}).extend({slug:K.string()}),rE=o1.extend({entityType:K.literal("doc"),metadata:f02}),LF=rE.extend({frontmatter:JF,body:K.string()});p0();K0();class fo0 extends V2{constructor(){super({entityType:"doc",schema:rE,frontmatterSchema:JF})}toMarkdown(A){let Q=this.extractBody(A.content),B=this.parseFrontMatter(A.content,JF);return this.buildMarkdown(Q,B)}fromMarkdown(A){let Q=this.parseFrontMatter(A,JF),B=Q.slug??Y1(Q.title);return{content:A,entityType:"doc",metadata:{title:Q.title,section:Q.section,order:Q.order,slug:B,...Q.description?{description:Q.description}:{}}}}}var VY0=new fo0;p0();function Y02(A){return[...A].sort((Q,B)=>{let w=Q.metadata.order-B.metadata.order;if(w!==0)return w;return Q.metadata.title.localeCompare(B.metadata.title)})}function X02(A){let Q=h2(A.content,JF);return LF.parse({...A,frontmatter:Q.metadata,body:Q.content})}class JY0 extends W${id="docs:entities";name="Docs Entity DataSource";description="Fetches and transforms doc entities for rendering";config={entityType:"doc",defaultSort:[{field:"order",direction:"asc"},{field:"section",direction:"asc"},{field:"title",direction:"asc"}],defaultLimit:100,enableNavigation:!0};constructor(A){super(A)}transformEntity(A){return X02(A)}async fetch(A,Q,B){let w=this.parseQuery(A);if(!w.query.id){let W=await this.fetchList({...w.query,limit:1000,page:void 0,pageSize:void 0},B.entityService);return Q.parse(this.buildListResult(W.items,null,w.query))}let[$,D]=await Promise.all([this.fetchDetail(w.query.id,B.entityService),this.fetchList({limit:1000},B.entityService)]),f=Y02(D.items),Y=f.findIndex((W)=>W.id===$.item.id),X=Y>0?f[Y-1]:null,H=Y>=0&&Y<f.length-1?f[Y+1]:null;return Q.parse({doc:$.item,docs:f,prevDoc:X,nextDoc:H})}buildDetailResult(A,Q){return{doc:A,docs:[A],prevDoc:Q?.prev??null,nextDoc:Q?.next??null}}buildListResult(A,Q,B){return{docs:Y02(A),pagination:Q,baseUrl:B.baseUrl}}}p0();Jw();K0();import{jsxDEV as x$}from"preact/jsx-dev-runtime";var D3B=["I","II","III","IV","V","VI","VII","VIII","IX","X"];function uo(A){return[...A].sort((Q,B)=>{let w=Q.metadata.order-B.metadata.order;if(w!==0)return w;return Q.metadata.title.localeCompare(B.metadata.title)})}function LY0(A){let Q=new Map;for(let B of uo(A)){let w=B.metadata.section;Q.set(w,[...Q.get(w)??[],B])}return[...Q.entries()].map(([B,w])=>({section:B,docs:w}))}function oE(A){return`/docs/${A.metadata.slug}`}function bY0(A){return`section-${A+1}`}function sE(A){return D3B[A]??String(A+1)}var Z02="text-[var(--docs-text)] font-bold",K02="text-[var(--docs-accent)] font-bold",U02="text-[var(--docs-text-muted)]",f3B="docs-font-label text-xs uppercase tracking-[0.18em] text-[var(--docs-accent)]",Y3B="docs-font-display text-[var(--docs-heading)]",H02="inline-flex items-center justify-center rounded-lg border px-[18px] py-2.5 text-sm font-semibold transition-colors duration-150",W02="relative hidden py-1 text-[15px] text-[var(--docs-text-muted)] transition-colors duration-150 after:absolute after:bottom-0 after:left-0 after:h-px after:w-0 after:bg-[var(--docs-accent)] after:transition-[width] after:duration-300 hover:text-[var(--docs-text)] hover:after:w-full min-[861px]:inline-block",Yo0="docs-font-label text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:text-[var(--docs-text)]",Bz={wrap:"mx-auto max-w-6xl px-6 pt-20 md:px-12 md:pt-24",label:f3B,display:Y3B,button:`${H02} border-[var(--docs-text)] text-[var(--docs-text)] hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)]`,primaryButton:`${H02} border-[var(--docs-accent)] bg-[var(--docs-accent)] text-white hover:bg-transparent hover:text-[var(--docs-accent)]`},G02=()=>x$("nav",{className:"docs-header fixed inset-x-0 top-0 z-[100] flex items-center justify-between px-6 py-4 md:px-10 md:py-5 xl:px-20",children:[x$("a",{href:"/docs",className:"docs-font-body text-xl font-bold","aria-label":"Brains docs",children:[x$("span",{className:Z02,children:"brains"},void 0,!1,void 0,this),x$("span",{className:K02,children:"."},void 0,!1,void 0,this),x$("span",{className:U02,children:"docs"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x$("div",{className:"docs-header__nav flex items-center gap-4 md:gap-8",children:[x$("a",{className:W02,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),x$("a",{className:W02,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),x$("a",{href:"https://rizom.ai",className:"inline-flex items-center justify-center rounded-lg border border-[var(--docs-text)] px-4 py-2 text-[13px] font-semibold text-[var(--docs-text)] transition-colors duration-150 hover:border-[var(--docs-accent)] hover:text-[var(--docs-accent)] md:px-6 md:py-2.5 md:text-[15px]",children:"Get Brains"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),z02=()=>x$("footer",{className:"flex flex-col items-center justify-between gap-4 border-t border-[var(--docs-border-light)] py-8 text-center md:flex-row md:gap-6 md:py-6 md:text-left",children:[x$("a",{href:"https://rizom.ai",className:"docs-font-body text-[15px] font-bold",children:[x$("span",{className:Z02,children:"rizom"},void 0,!1,void 0,this),x$("span",{className:K02,children:"."},void 0,!1,void 0,this),x$("span",{className:U02,children:"ai"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),x$("div",{className:"flex flex-wrap items-center justify-center gap-6 md:justify-end",children:[x$("a",{className:Yo0,href:"/docs/roadmap",children:"Roadmap"},void 0,!1,void 0,this),x$("a",{className:Yo0,href:"https://github.com/rizom-ai/brains",children:"GitHub"},void 0,!1,void 0,this),x$("a",{className:Yo0,href:"https://rizom.ai",children:"Rizom"},void 0,!1,void 0,this),x$("button",{id:"themeToggle",className:"docs-font-label cursor-pointer rounded-md border border-[var(--docs-text-light)] bg-transparent px-2.5 py-1.5 text-[13px] text-[var(--docs-text-light)] transition-colors duration-150 hover:border-[var(--docs-text)] hover:text-[var(--docs-text)]",type:"button",children:"\u2600 Light"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),X3B=`
|
|
11824
11824
|
.docs-handbook {
|
|
11825
11825
|
--docs-bg: var(--color-bg, #0d0a1a);
|
|
11826
11826
|
--docs-bg-card: var(--color-bg-card, #1a0a3e);
|
|
@@ -11972,7 +11972,7 @@ facts, owners, or tasks. Return only the required structured JSON.`});K0();var Z
|
|
|
11972
11972
|
background: transparent;
|
|
11973
11973
|
}
|
|
11974
11974
|
|
|
11975
|
-
`,q02=()=>x$("style",{children:X3B},void 0,!1,void 0,this);import{jsxDEV as F2,Fragment as H3B}from"preact/jsx-dev-runtime";var NY0=({title:A,description:Q,children:B,detail:w=!1,footer:$=!1,contentClassName:D=""})=>F2(H3B,{children:[F2(NQ,{title:A,description:Q},void 0,!1,void 0,this),F2(q02,{},void 0,!1,void 0,this),F2("div",{className:`docs-handbook${w?" docs-handbook--detail":""}`,children:[F2(G02,{},void 0,!1,void 0,this),F2("div",{className:`${Bz.wrap} ${D}`.trim(),children:[B,$&&F2(z02,{},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),F02=({docsCount:A,sectionsCount:Q,startDoc:B})=>F2("section",{className:"border-b border-[var(--docs-text)] py-14 md:py-24 md:pb-[72px]",children:[F2("p",{className:`${Bz.label} mb-8`,children:"Handbook \xB7 Brains docs"},void 0,!1,void 0,this),F2("h1",{className:`${Bz.display} m-0 max-w-[16ch] text-5xl leading-[1.05] tracking-[-0.02em] md:text-7xl`,children:["Build, run, and publish"," ",F2("em",{className:"text-[var(--docs-accent)]",children:"brains."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F2("p",{className:"mt-8 max-w-[52ch] text-lg leading-[1.65] text-[var(--docs-text-muted)]",children:"Documentation for composing brain models, managing markdown entities, wiring interfaces, and shipping generated sites."},void 0,!1,void 0,this),F2("dl",{className:"mt-10 flex flex-wrap gap-7 docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] md:mt-14 md:gap-12",children:[F2("div",{children:[F2("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:A},void 0,!1,void 0,this),"Documents"]},void 0,!0,void 0,this),F2("div",{children:[F2("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:Q},void 0,!1,void 0,this),"Sections"]},void 0,!0,void 0,this),F2("div",{children:[F2("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:"April 2026"},void 0,!1,void 0,this),"Updated"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),F2("div",{className:"mt-9 flex flex-wrap gap-3.5",children:[B&&F2("a",{className:Bz.primaryButton,href:oE(B),children:"Start reading"},void 0,!1,void 0,this),F2("a",{className:Bz.button,href:"#sections",children:"Browse sections"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),I02=({groups:A})=>F2("aside",{className:"docs-rail sticky top-8 hidden docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] min-[861px]:block","aria-label":"Documentation sections",children:[F2("p",{className:"m-0 mb-3.5 font-medium text-[var(--docs-text)]",children:"Sections"},void 0,!1,void 0,this),F2("ol",{className:"m-0 list-none p-0",children:A.map((Q,B)=>F2("li",{className:"grid grid-cols-[32px_1fr] gap-2 py-1.5",children:[F2("span",{className:"docs-font-display text-[var(--docs-text-light)] italic",children:[sE(B),"."]},void 0,!0,void 0,this),F2("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:`#${bY0(B)}`,children:Q.section},void 0,!1,void 0,this)]},Q.section,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),V02=({group:A,index:Q})=>F2("article",{className:"mb-16 last:mb-0",id:bY0(Q),children:[F2("header",{className:"mb-2 grid grid-cols-[36px_auto_1fr] items-baseline gap-x-3 border-b border-[var(--docs-border)] pb-3.5 md:grid-cols-[48px_auto_1fr] md:gap-x-5",children:[F2("span",{className:"text-right docs-font-display text-3xl leading-[1.1] text-[var(--docs-accent)] italic md:text-4xl",children:[sE(Q),"."]},void 0,!0,void 0,this),F2("h2",{className:`${Bz.display} m-0 text-3xl leading-[1.1] tracking-[-0.015em] md:text-4xl`,children:A.section},void 0,!1,void 0,this),F2("span",{className:"docs-chapter__leader"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F2("ol",{className:"m-0 list-none p-0",children:A.docs.map((B)=>F2("li",{className:"border-b border-[var(--docs-border-light)] last:border-b-0",children:F2("a",{className:"group block py-[18px] pl-12 md:pl-[68px]",href:oE(B),children:[F2("p",{className:"m-0 text-[22px] leading-[1.2] tracking-[-0.005em] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:B.metadata.title},void 0,!1,void 0,this),B.metadata.description&&F2("p",{className:"mt-1.5 mb-0 max-w-[70ch] text-sm leading-[1.55] text-[var(--docs-text-muted)]",children:B.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},B.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),J02=({title:A})=>F2("nav",{className:"mb-8 flex flex-wrap items-baseline gap-2.5 docs-font-label text-[11px] uppercase tracking-[0.06em] text-[var(--docs-text-light)]","aria-label":"Breadcrumb",children:[F2("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/",children:"Home"},void 0,!1,void 0,this),F2("span",{children:"/"},void 0,!1,void 0,this),F2("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/docs",children:"Docs"},void 0,!1,void 0,this),F2("span",{children:"/"},void 0,!1,void 0,this),F2("span",{children:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this),L02=({groups:A,activeGroupIndex:Q,activeSlug:B})=>F2("aside",{className:"docs-detail-rail sticky top-24 hidden max-h-[calc(100vh-120px)] overflow-auto pr-2 min-[861px]:block","aria-label":"Documentation navigation",children:F2("nav",{className:"docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)]",children:[F2("p",{className:"m-0 mb-4 border-b border-[var(--docs-text)] pb-3 text-[11px] uppercase tracking-[0.08em] text-[var(--docs-text-light)]",children:"Documentation"},void 0,!1,void 0,this),F2("ol",{className:"m-0 list-none p-0",children:A.map((w,$)=>{let D=$===Q;return F2("li",{className:D?"mb-[22px]":"mb-3.5",children:[F2("a",{className:`mb-2 flex items-baseline gap-2.5 docs-font-label text-[11px] uppercase leading-[1.4] tracking-[0.06em] transition-colors duration-150 hover:text-[var(--docs-text)] ${D?"text-[var(--docs-text)]":"text-[var(--docs-text-muted)]"}`,href:`/docs#${bY0($)}`,children:[F2("span",{className:"docs-font-display text-sm text-[var(--docs-accent)] italic",children:[sE($),"."]},void 0,!0,void 0,this)," ",w.section]},void 0,!0,void 0,this),D&&F2("ol",{className:"mt-0.5 list-none p-0",children:w.docs.map((f)=>{let Y=f.metadata.slug===B;return F2("li",{children:F2("a",{className:`docs-rail__doc relative block py-1.5 docs-font-body text-sm leading-[1.4] tracking-normal transition-[color,padding-left] duration-150 hover:text-[var(--docs-text)] ${Y?"pl-3.5 font-medium text-[var(--docs-accent)]":"text-[var(--docs-text-muted)]"}`,href:oE(f),"aria-current":Y?"page":void 0,children:f.metadata.title},void 0,!1,void 0,this)},f.id,!1,void 0,this)})},void 0,!1,void 0,this)]},w.section,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),b02=({prevDoc:A,nextDoc:Q})=>{if(!A&&!Q)return null;return F2("nav",{className:"mt-12 grid grid-cols-1 gap-5 border-t border-[var(--docs-border)] pt-7 md:grid-cols-2","aria-label":"Previous and next docs",children:[A?F2("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] transition-colors duration-150 hover:border-[var(--docs-accent)]",href:oE(A),children:[F2("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Previous"},void 0,!1,void 0,this),F2("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:["\u2190 ",A.metadata.title]},void 0,!0,void 0,this)]},void 0,!0,void 0,this):F2("span",{},void 0,!1,void 0,this),Q&&F2("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] text-left transition-colors duration-150 hover:border-[var(--docs-accent)] md:text-right",href:oE(Q),children:[F2("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Next"},void 0,!1,void 0,this),F2("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:[Q.metadata.title," \u2192"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as aE}from"preact/jsx-dev-runtime";var Xo0=({docs:A})=>{let Q=uo(A),B=LY0(Q),$=Q.filter((D)=>D.metadata.slug!=="index")[0]??Q[0];return aE(NY0,{title:"Documentation",description:"Brains documentation",children:[aE(F02,{docsCount:A.length,sectionsCount:B.length,startDoc:$},void 0,!1,void 0,this),aE("section",{className:"grid items-start gap-10 py-12 md:grid-cols-[200px_minmax(0,1fr)] md:gap-20 md:py-20 md:pb-[120px]",id:"sections",children:[aE(I02,{groups:B},void 0,!1,void 0,this),aE("div",{children:B.map((D,f)=>aE(V02,{group:D,index:f},D.section,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as gX}from"preact/jsx-dev-runtime";var Ho0=({doc:A,docs:Q,prevDoc:B,nextDoc:w})=>{let $=LY0(Q.length>0?Q:[A]),D=uo(Q.length>0?Q:[A]),f=D.findIndex((X)=>X.metadata.slug===A.metadata.slug),Y=Math.max($.findIndex((X)=>X.docs.some((H)=>H.metadata.slug===A.metadata.slug)),0);return gX(NY0,{title:A.metadata.title,description:A.metadata.description??A.metadata.section,detail:!0,footer:!0,contentClassName:"pt-16",children:[gX(J02,{title:A.metadata.title},void 0,!1,void 0,this),gX("div",{className:"grid items-start gap-10 py-8 pb-24 md:grid-cols-[240px_minmax(0,1fr)] md:gap-20",children:[gX(L02,{groups:$,activeGroupIndex:Y,activeSlug:A.metadata.slug},void 0,!1,void 0,this),gX("article",{className:"min-w-0",children:[gX("header",{className:"mb-10 border-b border-[var(--docs-border)] pb-8",children:[gX("p",{className:`${Bz.label} m-0 mb-6 flex items-baseline gap-3`,children:[gX("span",{className:"docs-font-display text-lg leading-none tracking-normal normal-case text-[var(--docs-accent)] italic",children:[sE(Y),"."]},void 0,!0,void 0,this)," ",A.metadata.section,f>=0?` \xB7 ${f+1}/${D.length}`:""]},void 0,!0,void 0,this),gX("h1",{className:`${Bz.display} m-0 max-w-[18ch] text-4xl leading-[1.05] tracking-[-0.02em] md:text-6xl`,children:A.metadata.title},void 0,!1,void 0,this),A.metadata.description&&gX("p",{className:"mt-6 max-w-[56ch] docs-font-display text-[22px] font-[350] leading-[1.5] text-[var(--docs-text-muted)]",children:A.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),gX("div",{className:"docs-article__body",children:gX(f9,{markdown:A.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),gX(b02,{prevDoc:B,nextDoc:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};var W3B=K.object({docs:K.array(LF),pagination:e7.nullable(),baseUrl:K.string().optional()}),Z3B=K.object({doc:LF,docs:K.array(LF),prevDoc:LF.nullable(),nextDoc:LF.nullable()});function N02(){return{"doc-list":R1({name:"doc-list",description:"Documentation index template",schema:W3B,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:Xo0}}),"doc-detail":R1({name:"doc-detail",description:"Documentation page template",schema:Z3B,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:Ho0}})}}var j02={name:"@brains/doc",private:!0,version:"0.2.0-alpha.128",description:"Documentation entity type \u2014 markdown docs as first-class 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"},dependencies:{"@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"latest",typescript:"^5.3.3"}};class Wo0 extends PQ{entityType=VY0.entityType;schema=rE;adapter=VY0;constructor(){super("docs",j02,{},void 0)}getTemplates(){return N02()}getDataSources(){return[new JY0(this.logger.child("DocDataSource"))]}}function Zo0(){return new Wo0}p0();K0();K0();p$();var _02=K.object({label:K.string(),href:K.string()}),M02=K.object({label:K.string(),title:K.string(),detail:K.string()}),U3B=K.object({eyebrow:K.string(),name:K.string(),sub:K.string()}),G3B=K.object({tone:K.enum(["capture","synthesis","share"]),title:K.string(),text:K.string()}),Ko0=K.object({captures:K.number(),links:K.number(),topics:K.number(),summaries:K.number(),peers:K.number()}),tE=K.object({eyebrow:K.string(),headline:K.string(),intro:K.string(),primaryCta:_02,secondaryCta:_02,inputs:K.array(M02).min(1),outputs:K.array(M02).min(1),core:U3B,legend:K.array(G3B).min(1)}),Uo0=tE.extend({counts:Ko0}),P02={eyebrow:"A team brain, diagrammed",headline:"Relay sits between the work and the world, and keeps both honest.",intro:"Capture sources flow into a shared brain; the brain organizes, summarizes, and \u2014 selectively \u2014 exposes a public surface. Everything else stays private and operational.",primaryCta:{label:"See it on a real team",href:"#diagram"},secondaryCta:{label:"Read the model",href:"/about"},inputs:[{label:"Source \xB7 chat",title:"Discord",detail:"Shared decisions and field notes captured in flow."},{label:"Source \xB7 agent",title:"MCP / CLI",detail:"Structured captures from tools and assistants."},{label:"Source \xB7 web",title:"Links & docs",detail:"External material indexed with sourceable metadata."}],outputs:[{label:"Surface \xB7 public",title:"Default site",detail:"A small, durable face onto what the team currently knows."},{label:"Surface \xB7 agents",title:"A2A exchange",detail:"Peer brains coordinate over an approved, signed protocol."},{label:"Surface \xB7 query",title:"Team Q&A",detail:"Ask the brain in chat; answers cite the captures behind them."}],core:{eyebrow:"The relay",name:"brain",sub:"capture \u2192 topics \u2192 summaries"},legend:[{tone:"capture",title:"Capture",text:"Anything the team already does that produces a trace \u2014 chat messages, links, deploys, decisions."},{tone:"synthesis",title:"Synthesis",text:"The work the brain does on its own time \u2014 clustering captures into topics, summaries, and durable memory."},{tone:"share",title:"Share",text:"A small, opinionated public surface and an approved agent-to-agent protocol. Most memory stays private."}]},k02=new pB(tE,{title:"Home diagram",mappings:[{key:"eyebrow",label:"Eyebrow",type:"string"},{key:"headline",label:"Headline",type:"string"},{key:"intro",label:"Intro",type:"string"},{key:"primaryCta",label:"Primary CTA",type:"object",children:[{key:"label",label:"Label",type:"string"},{key:"href",label:"Href",type:"string"}]},{key:"secondaryCta",label:"Secondary CTA",type:"object",children:[{key:"label",label:"Label",type:"string"},{key:"href",label:"Href",type:"string"}]},{key:"inputs",label:"Inputs",type:"array",itemType:"object",itemMappings:[{key:"label",label:"Label",type:"string"},{key:"title",label:"Title",type:"string"},{key:"detail",label:"Detail",type:"string"}]},{key:"outputs",label:"Outputs",type:"array",itemType:"object",itemMappings:[{key:"label",label:"Label",type:"string"},{key:"title",label:"Title",type:"string"},{key:"detail",label:"Detail",type:"string"}]},{key:"core",label:"Core",type:"object",children:[{key:"eyebrow",label:"Eyebrow",type:"string"},{key:"name",label:"Name",type:"string"},{key:"sub",label:"Sub",type:"string"}]},{key:"legend",label:"Legend",type:"array",itemType:"object",itemMappings:[{key:"tone",label:"Tone",type:"string"},{key:"title",label:"Title",type:"string"},{key:"text",label:"Text",type:"string"}]}]});function jY0(A){return k02.parse(A)}function O02(A){return k02.format(A)}K0();var z3B=K.object({query:K.object({routeId:K.string().default("home"),sectionId:K.string().default("diagram")}).default({routeId:"home",sectionId:"diagram"})}).passthrough(),q3B={captures:"note",links:"link",topics:"topic",summaries:"summary",peers:"agent"};class Go0{id="relay-site:home-counts";name="Relay homepage counts";description="Fetches Relay homepage content and live entity counts for the system diagram";async fetch(A,Q,B){let w=z3B.parse(A??{}),$=await this.fetchContent(B,w.query.routeId,w.query.sectionId),D=await this.fetchCounts(B);return Q.parse({...$,counts:D})}async fetchContent(A,Q,B){let w=await A.entityService.getEntity({entityType:"site-content",id:`${Q}:${B}`});if(!w?.content)return P02;return tE.parse(jY0(w.content))}async fetchCounts(A){let Q=await Promise.all(Object.entries(q3B).map(async([B,w])=>[B,await this.countOrZero(A,w)]));return Ko0.parse(Object.fromEntries(Q))}async countOrZero(A,Q){if(!A.entityService.hasEntityType(Q))return 0;try{return await A.entityService.countEntities({entityType:Q})}catch{return 0}}}import{jsxDEV as w1}from"preact/jsx-dev-runtime";var x02=K.object({label:K.string(),href:K.string()}),F3B=K.object({eyebrow:K.string(),headline:K.string(),intro:K.string(),primaryCta:x02,secondaryCta:x02,signals:K.array(K.object({label:K.string(),value:K.string(),note:K.string()}))}),I3B=K.object({eyebrow:K.string(),title:K.string(),intro:K.string(),steps:K.array(K.object({phase:K.string(),title:K.string(),text:K.string()}))}),V3B=K.object({title:K.string(),intro:K.string(),cards:K.array(K.object({label:K.string(),title:K.string(),text:K.string()}))}),J3B=K.object({title:K.string(),intro:K.string(),points:K.array(K.string())}),L3B={title:"Relay is a collaborative team-memory brain.",intro:"It exists for teams that need to remember together: capturing what happened, summarizing why it matters, and coordinating with trusted peer brains when work crosses boundaries.",points:["Not a personal blog engine or portfolio shell.","Not a marketing automation stack.","A small public face for a larger private knowledge workflow."]},b3B="font-body text-[15px] text-theme-muted transition-colors hover:text-theme";function R02({href:A,label:Q}){return w1("a",{href:A,className:b3B,children:Q},void 0,!1,void 0,this)}function N3B({siteInfo:A,children:Q}){let B=[...A.navigation.primary,...A.navigation.secondary],w=A.cta??{buttonText:"Start here",buttonLink:"/about"};return w1(gE,{children:[w1("nav",{className:"fixed left-0 right-0 top-0 z-[100] flex items-center justify-between border-b border-theme-light bg-nav-fade px-6 py-4 backdrop-blur-[12px] md:px-10 xl:px-20",children:[w1("a",{href:"/",className:"font-nav text-[20px]","aria-label":"Relay home",children:[w1("span",{className:"font-bold text-theme",children:"relay"},void 0,!1,void 0,this),w1("span",{className:"font-bold text-accent",children:"."},void 0,!1,void 0,this),w1("span",{className:"text-theme-muted",children:"brain"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"flex items-center gap-5 md:gap-8",children:[w1("div",{className:"hidden items-center gap-6 md:flex",children:B.map(($)=>w1(R02,{...$},`${$.href}-${$.label}`,!1,void 0,this))},void 0,!1,void 0,this),w1("a",{href:w.buttonLink,className:"rounded-[999px] border border-theme px-4 py-2 font-body text-[13px] font-semibold text-theme transition-colors hover:border-accent hover:text-accent md:px-5",children:w.buttonText},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("main",{children:Q},void 0,!1,void 0,this),w1("footer",{className:"relative z-[1] border-t border-theme-light px-6 py-8 md:px-10 xl:px-20",children:w1("div",{className:"flex flex-col gap-4 md:flex-row md:items-center md:justify-between",children:[w1("div",{children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.22em] text-theme-light",children:A.copyright},void 0,!1,void 0,this),w1("p",{className:"mt-2 max-w-[560px] font-body text-body-xs text-theme-muted",children:A.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"flex flex-wrap items-center gap-5",children:[B.map(($)=>w1(R02,{...$},`footer-${$.href}-${$.label}`,!1,void 0,this)),w1("button",{id:"themeToggle","aria-label":"Toggle light mode",className:"rounded-md border border-theme-light bg-transparent px-2.5 py-1.5 font-body text-label-md text-theme-light transition-colors hover:border-theme hover:text-theme",children:"\u2600 Light"},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)}var j3B=({sections:A,siteInfo:Q})=>w1(N3B,{siteInfo:Q,children:A},void 0,!1,void 0,this);function _3B({eyebrow:A,headline:Q,intro:B,primaryCta:w,secondaryCta:$,signals:D}){return w1(gL,{className:"min-h-[92vh] pt-[152px] pb-20 md:pt-[190px]",children:w1("div",{className:"grid gap-10 lg:grid-cols-[minmax(0,1fr)_420px] lg:items-end",children:[w1("div",{children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-accent",children:A},void 0,!1,void 0,this),w1("h1",{className:"mt-7 max-w-[980px] font-display text-display-lg text-theme",children:Q},void 0,!1,void 0,this),w1("p",{className:"mt-7 max-w-[720px] font-body text-body-lg text-theme-muted",children:B},void 0,!1,void 0,this),w1("div",{className:"mt-10 flex flex-col gap-3 sm:flex-row",children:[w1(vP,{href:w.href,size:"lg",variant:"primary-strong",children:w.label},void 0,!1,void 0,this),w1(vP,{href:$.href,size:"lg",variant:"secondary",children:$.label},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"rounded-[32px] border border-card-relay-border bg-card-relay-bg p-5 shadow-[0_24px_90px_var(--color-glow-relay)] backdrop-blur-sm",children:[w1("p",{className:"font-label text-label-xs uppercase tracking-[0.24em] text-theme-light",children:"Live relay signals"},void 0,!1,void 0,this),w1("div",{className:"mt-5 grid gap-3",children:D.map((f)=>w1("div",{className:"rounded-[22px] border border-card-divider bg-bg-muted p-5",children:[w1("div",{className:"flex items-center justify-between gap-4",children:[w1("p",{className:"font-label text-label-xs uppercase tracking-[0.18em] text-secondary",children:f.label},void 0,!1,void 0,this),w1("span",{className:"h-2 w-2 rounded-full bg-accent shadow-[0_0_22px_var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("p",{className:"mt-4 font-display text-display-sm text-theme",children:f.value},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-body text-body-xs text-theme-muted",children:f.note},void 0,!1,void 0,this)]},f.label,!0,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)}function M3B({eyebrow:A,title:Q,intro:B,steps:w}){return w1(gL,{id:"operating-loop",className:"py-section",children:[w1("div",{className:"max-w-[840px]",children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-secondary",children:A},void 0,!1,void 0,this),w1("h2",{className:"mt-5 font-display text-display-md text-theme",children:Q},void 0,!1,void 0,this),w1("p",{className:"mt-5 font-body text-body-md text-theme-muted",children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mt-12 grid gap-4 md:grid-cols-3",children:w.map(($)=>w1("article",{className:"min-h-[300px] rounded-[28px] border border-card-panel-border bg-card-panel-bg p-6",children:[w1("p",{className:"font-label text-label-sm text-accent",children:$.phase},void 0,!1,void 0,this),w1("h3",{className:"mt-16 font-display text-display-sm text-theme",children:$.title},void 0,!1,void 0,this),w1("p",{className:"mt-4 font-body text-body-sm text-theme-muted",children:$.text},void 0,!1,void 0,this)]},$.phase,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function P3B({title:A,intro:Q,cards:B}){return w1(gL,{className:"py-section",children:w1("div",{className:"rounded-[36px] border border-theme-light bg-bg-muted p-6 md:p-10",children:w1("div",{className:"grid gap-8 lg:grid-cols-[360px_1fr]",children:[w1("div",{children:[w1("h2",{className:"font-display text-display-md text-theme",children:A},void 0,!1,void 0,this),w1("p",{className:"mt-5 font-body text-body-md text-theme-muted",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"grid gap-4",children:B.map((w)=>w1("article",{className:"rounded-[24px] border border-card-divider bg-bg-subtle/70 p-5",children:[w1("p",{className:"font-label text-label-xs uppercase tracking-[0.22em] text-accent",children:w.label},void 0,!1,void 0,this),w1("h3",{className:"mt-3 font-nav text-heading-lg text-theme",children:w.title},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-body text-body-sm text-theme-muted",children:w.text},void 0,!1,void 0,this)]},w.title,!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)}function k3B({title:A,intro:Q,points:B}){return w1(gL,{className:"min-h-[78vh] pt-[150px] pb-section md:pt-[190px]",children:[w1("div",{className:"max-w-[920px]",children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-accent",children:"Relay model"},void 0,!1,void 0,this),w1("h1",{className:"mt-6 font-display text-display-lg text-theme",children:A},void 0,!1,void 0,this),w1("p",{className:"mt-7 font-body text-body-lg text-theme-muted",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mt-12 grid gap-4 md:grid-cols-3",children:B.map((w)=>w1("div",{className:"rounded-[24px] border border-card-panel-current-border bg-card-panel-current-bg p-6 font-body text-body-md text-theme",children:w},w,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var O3B=(A)=>{switch(A){case"capture":return"bg-accent";case"synthesis":return"bg-secondary";case"share":return"bg-accent-bright"}},x3B=(A)=>new Intl.NumberFormat("en",{notation:A>999?"compact":"standard"}).format(A),co=(A,Q,B=`${Q}s`)=>`${x3B(A)} ${A===1?Q:B}`;function R3B({eyebrow:A,headline:Q,intro:B,primaryCta:w,secondaryCta:$,inputs:D,outputs:f,core:Y,legend:X,counts:H}){let W=[{key:"captures",className:"top-[-10px] left-1/2 -translate-x-1/2",label:co(H.captures,"capture")},{key:"topics",className:"top-1/2 right-[-28px] -translate-y-1/2",label:co(H.topics,"topic")},{key:"peers",className:"bottom-[-10px] left-1/2 -translate-x-1/2",label:co(H.peers,"peer brain")},{key:"summaries",className:"top-1/2 left-[-28px] -translate-y-1/2",label:co(H.summaries,"summary","summaries")}];return w1(gL,{className:"pt-[150px] pb-section md:pt-[190px]",id:"diagram",children:[w1("div",{className:"mx-auto max-w-[1040px] text-center",children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-accent",children:A},void 0,!1,void 0,this),w1("h1",{className:"mx-auto mt-7 max-w-[22ch] font-display text-display-lg text-theme",children:Q},void 0,!1,void 0,this),w1("p",{className:"mx-auto mt-7 max-w-[64ch] font-body text-body-lg text-theme-muted",children:B},void 0,!1,void 0,this),w1("div",{className:"mt-10 flex flex-col justify-center gap-3 sm:flex-row",children:[w1(vP,{href:w.href,size:"lg",variant:"primary-strong",children:w.label},void 0,!1,void 0,this),w1(vP,{href:$.href,size:"lg",variant:"secondary",children:$.label},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mx-auto mt-20 max-w-[1020px] rounded-[32px] border border-theme-light bg-[radial-gradient(circle_at_1px_1px,rgb(255_255_255_/_0.05)_1px,transparent_0),linear-gradient(180deg,rgb(255_255_255_/_0.02),transparent)] bg-[length:24px_24px,100%_100%] px-6 py-14",children:[w1("div",{className:"grid items-center gap-8 lg:grid-cols-[1fr_1.4fr_1fr]",children:[w1("div",{className:"flex flex-col gap-3.5",children:D.map((Z)=>w1("div",{className:"rounded-2xl border border-card-panel-border border-l-2 border-l-accent bg-card-panel-bg px-4 py-4 text-left backdrop-blur-sm",children:[w1("p",{className:"font-label text-[10px] uppercase tracking-[0.22em] text-secondary",children:Z.label},void 0,!1,void 0,this),w1("h2",{className:"mt-1.5 font-display text-[18px] font-medium text-theme",children:Z.title},void 0,!1,void 0,this),w1("p",{className:"mt-1 font-body text-[13px] leading-[1.5] text-theme-muted",children:Z.detail},void 0,!1,void 0,this)]},`${Z.label}-${Z.title}`,!0,void 0,this))},void 0,!1,void 0,this),w1("div",{className:"relative mx-auto grid aspect-square w-full max-w-[320px] place-items-center rounded-full bg-[radial-gradient(circle_at_center,rgb(232_119_34_/_0.25),transparent_65%)]",children:[w1("div",{className:"absolute inset-0 rounded-full border border-dashed border-accent/30"},void 0,!1,void 0,this),w1("div",{className:"absolute inset-6 animate-spin rounded-full border border-dashed border-secondary/40 [animation-duration:28s]"},void 0,!1,void 0,this),W.map((Z)=>w1("span",{className:`absolute whitespace-nowrap rounded-full border border-theme bg-bg px-2.5 py-1 font-label text-[10px] uppercase tracking-[0.18em] text-theme-light ${Z.className}`,children:Z.label},Z.key,!1,void 0,this)),w1("div",{className:"relative z-[1] px-6 text-center",children:[w1("p",{className:"font-label text-[10px] uppercase tracking-[0.28em] text-accent",children:Y.eyebrow},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-display text-[36px] leading-none text-theme",children:Y.name},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-body text-[13px] text-theme-muted",children:Y.sub},void 0,!1,void 0,this),w1("p",{className:"mt-4 font-label text-[10px] uppercase tracking-[0.18em] text-theme-light",children:[co(H.links,"link")," indexed"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"flex flex-col gap-3.5",children:f.map((Z)=>w1("div",{className:"rounded-2xl border border-card-panel-border border-r-2 border-r-secondary bg-card-panel-bg px-4 py-4 text-left backdrop-blur-sm",children:[w1("p",{className:"font-label text-[10px] uppercase tracking-[0.22em] text-secondary",children:Z.label},void 0,!1,void 0,this),w1("h2",{className:"mt-1.5 font-display text-[18px] font-medium text-theme",children:Z.title},void 0,!1,void 0,this),w1("p",{className:"mt-1 font-body text-[13px] leading-[1.5] text-theme-muted",children:Z.detail},void 0,!1,void 0,this)]},`${Z.label}-${Z.title}`,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mt-14 grid gap-4 border-t border-theme-light pt-8 md:grid-cols-3",children:X.map((Z)=>w1("div",{className:"text-left",children:[w1("h2",{className:"font-display text-[16px] font-medium text-theme",children:[w1("span",{className:`mr-2.5 inline-block h-3 w-3 rounded-[3px] align-middle ${O3B(Z.tone)}`},void 0,!1,void 0,this),Z.title]},void 0,!0,void 0,this),w1("p",{className:"mt-1.5 font-body text-[13px] leading-[1.6] text-theme-muted",children:Z.text},void 0,!1,void 0,this)]},Z.title,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var v3B=R1({name:"home-diagram",description:"Relay homepage system diagram with live entity counts",schema:Uo0,formatter:{parse:(A)=>Uo0.parse({...jY0(A),counts:{captures:0,links:0,topics:0,summaries:0,peers:0}}),format:(A)=>O02(tE.parse(A))},dataSourceId:"relay-site:home-counts",requiredPermission:"public",layout:{component:R3B}}),h3B=(A)=>_3B(F3B.parse(A)),C3B=(A)=>M3B(I3B.parse(A)),y3B=(A)=>P3B(V3B.parse(A)),E3B=(A)=>k3B(J3B.parse(A)),v02={type:"object",label:"CTA",fields:{label:{type:"string",label:"Label"},href:{type:"string",label:"Href"}}},h02={namespace:"relay-site",sections:{"home-hero":{title:"Home hero",description:"Relay homepage hero section",layout:h3B,fields:{eyebrow:{type:"string",label:"Eyebrow"},headline:{type:"string",label:"Headline"},intro:{type:"string",label:"Intro"},primaryCta:{...v02,label:"Primary CTA"},secondaryCta:{...v02,label:"Secondary CTA"},signals:{type:"array",label:"Signals",minItems:1,items:{type:"object",label:"Signal",fields:{label:{type:"string",label:"Label"},value:{type:"string",label:"Value"},note:{type:"string",label:"Note"}}}}}},"home-loop":{title:"Home operating loop",description:"Relay capture, synthesis, and sharing loop",layout:C3B,fields:{eyebrow:{type:"string",label:"Eyebrow"},title:{type:"string",label:"Title"},intro:{type:"string",label:"Intro"},steps:{type:"array",label:"Steps",minItems:1,items:{type:"object",label:"Step",fields:{phase:{type:"string",label:"Phase"},title:{type:"string",label:"Title"},text:{type:"string",label:"Text"}}}}}},"home-surface":{title:"Home surface",description:"Relay default template explanation cards",layout:y3B,fields:{title:{type:"string",label:"Title"},intro:{type:"string",label:"Intro"},cards:{type:"array",label:"Cards",minItems:1,items:{type:"object",label:"Card",fields:{label:{type:"string",label:"Label"},title:{type:"string",label:"Title"},text:{type:"string",label:"Text"}}}}}},about:{title:"About Relay",description:"Default Relay about page",layout:E3B,fields:{title:{type:"string",label:"Title"},intro:{type:"string",label:"Intro"},points:{type:"array",label:"Points",minItems:1,items:{type:"string",label:"Point"}}}}}},g3B=[{id:"home",path:"/",title:"Relay",description:"Collaborative team memory and synthesis brain",layout:"default",navigation:{show:!0,label:"Home",slot:"secondary",priority:10},sections:[{id:"diagram",template:"relay-site:home-diagram"}]},{id:"about",path:"/about",title:"About Relay",description:"What Relay is designed to do",layout:"default",navigation:{show:!0,label:"About",slot:"primary",priority:20},sections:[{id:"about",template:"relay-site:about",content:L3B}]}],C02=dr0({packageName:"@brains/relay/site",contentNamespace:"relay-site",themeProfile:"studio",layout:j3B,routes:g3B,templates:{"home-diagram":v3B},dataSources:[new Go0]});var y02={name:"@brains/relay",private:!0,version:"0.2.0-alpha.128",description:"Relay brain model \u2014 collaborative knowledge management",type:"module",files:["src","brain.eval.yaml","env.schema.template"],exports:{".":"./src/index.ts"},scripts:{"build:web-chat":"turbo run build --filter=@brains/web-chat","start:core":"bun run build:web-chat && cd test-apps/core && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:default":"bun run build:web-chat && cd test-apps/default && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:full":"bun run build:web-chat && cd test-apps/full && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:docs":"bun run build:web-chat && cd test-apps/docs && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start",typecheck:"tsc --noEmit",test:"bun test",eval:"brain-eval",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/a2a":"workspace:*","@brains/agent-discovery":"workspace:*","@brains/app":"workspace:*","@brains/assessment":"workspace:*","@brains/auth-service":"workspace:*","@brains/cms":"workspace:*","@brains/content-formatters":"workspace:*","@brains/conversation-memory":"workspace:*","@brains/dashboard":"workspace:*","@brains/decks":"workspace:*","@brains/directory-sync":"workspace:*","@brains/discord":"workspace:*","@brains/doc":"workspace:*","@brains/email-resend":"workspace:*","@brains/image-plugin":"workspace:*","@brains/link":"workspace:*","@brains/mcp":"workspace:*","@brains/note":"workspace:*","@brains/notifications":"workspace:*","@brains/plugins":"workspace:*","@brains/prompt":"workspace:*","@brains/rizom-ecosystem":"workspace:*","@brains/site-builder-plugin":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-content":"workspace:*","@brains/site-info":"workspace:*","@brains/site-rizom":"workspace:*","@brains/theme-rizom":"workspace:*","@brains/topics":"workspace:*","@brains/utils":"workspace:*","@brains/web-chat":"workspace:*","@brains/webserver":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/ai-evaluation":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*",typescript:"^5.3.3"}};var E02=["prompt","directory-sync","note","link","topics","conversation-memory","agents","assessment","auth-service","notifications","email-resend","cms","dashboard","mcp","webserver","web-chat","discord","a2a"],g02=[...E02,"image","site-info","site-content","site-builder"],m3B=[...g02,"docs","decks"],u3B=["Relay is a collaborative team-memory and synthesis brain. Optimize for capturing shared context, finding what the team already knows, summarizing cross-source evidence, and coordinating with peer brains.","Relay is not Rover-for-teams: do not default to personal branding, blog publishing, newsletters, social media, portfolio, or marketing workflows unless the installed plugins and user request explicitly support them.",'Relay entity mappings: "memo", "note", "team note", "capture" \u2192 entityType: note; "summary", "sync", "team digest" \u2192 entityType: summary; "decision" \u2192 entityType: decision; "action item", "todo" \u2192 entityType: action-item; "handbook", "doc", "documentation" \u2192 entityType: doc; "deck", "walkthrough", "presentation" \u2192 entityType: deck; "agent", "peer brain", "contact" \u2192 entityType: agent.'],T02=FV({name:"relay",version:y02.version,model:"gpt-5.4-mini",site:C02,theme:TE,presets:{core:E02,default:g02,full:m3B},evalDisable:["webserver","web-chat","mcp","discord"],agentInstructions:u3B,capabilities:[["prompt",kP,void 0],["note",FP,{}],["link",VP,{}],["image",Yc,void 0],["topics",gD0,{includeEntityTypes:["note","link","summary","agent","swot","deck","doc","anchor-profile","brain-character"],extractableStatuses:["published","draft"]}],["conversation-memory",Do0,{memoryVisibility:"shared"}],["docs",Zo0,void 0],["decks",Fr,void 0],["agents",Pf0,void 0],["assessment",gf0,void 0],["auth-service",tl,void 0],["notifications",pB0,void 0],["email-resend",g$0,void 0],["cms",_P,{}],["dashboard",CL,void 0],["directory-sync",JM,{seedContent:!0,seedContentPath:S3B(import.meta.dir,"..","seed-content"),initialSync:!0}],["site-content",ho,{definitions:h02}],["rizom-ecosystem",OP,void 0],["site-info",DP,void 0],["site-builder",$P,{}]],interfaces:[["mcp",tV,()=>({})],["discord",EJ,()=>({captureUrls:!0})],["a2a",yC,()=>({})],["webserver",mJ,()=>({})],["web-chat",CC,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"anchor"},{pattern:"discord:*",level:"public"},{pattern:"web-chat:*",level:"anchor"}],entityActions:{note:{create:"trusted",update:"trusted",delete:"anchor"},link:{create:"trusted",update:"trusted",delete:"anchor"},doc:{create:"trusted",update:"trusted",delete:"anchor"},deck:{create:"trusted",update:"trusted",delete:"anchor"},decision:{create:"trusted",update:"trusted",delete:"anchor"},"action-item":{create:"trusted",update:"trusted",delete:"anchor"},image:{create:"trusted",update:"trusted",delete:"anchor"}}},deployment:{cdn:{enabled:!0,provider:"bunny"}}});import{readFileSync as JJB}from"fs";import{join as LJB}from"path";import{execSync as bJB}from"child_process";import{parseArgs as p3B}from"util";var i3B={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"},"startup-check":{type:"boolean"},"storage-dir":{type:"string"},yes:{type:"boolean"},remote:{type:"string"},token:{type:"string"},outputDir:{type:"string"},help:{type:"boolean",short:"h"},version:{type:"boolean",short:"v"}};function MK(A,Q){let B=A[Q];return typeof B==="string"?B:void 0}function mL(A,Q){let B=A[Q];return typeof B==="boolean"?B:void 0}function S02(A){let{values:Q,positionals:B}=p3B({args:A,options:i3B,allowPositionals:!0,strict:!1});if(Q.help)return{command:"help",args:[],flags:{help:!0}};if(Q.version)return{command:"version",args:[],flags:{version:!0}};return{command:B[0]??"help",args:B.slice(1),flags:{model:MK(Q,"model"),domain:MK(Q,"domain"),"content-repo":MK(Q,"content-repo"),backend:MK(Q,"backend"),"push-to":MK(Q,"push-to"),"ai-api-key":MK(Q,"ai-api-key"),"no-interactive":mL(Q,"no-interactive"),preview:mL(Q,"preview"),deploy:mL(Q,"deploy"),regen:mL(Q,"regen"),all:mL(Q,"all"),only:MK(Q,"only"),"dry-run":mL(Q,"dry-run"),"startup-check":mL(Q,"startup-check"),"storage-dir":MK(Q,"storage-dir"),yes:mL(Q,"yes"),remote:MK(Q,"remote"),token:MK(Q,"token"),outputDir:MK(Q,"outputDir")}}}lo();import{mkdirSync as WJB}from"fs";import{join as ZJB}from"path";import{execSync as KJB}from"child_process";var MY0={name:"@rizom/brain",version:"0.2.0-alpha.128",description:"Brain runtime + CLI \u2014 scaffold, run, and manage AI brain instances",type:"module",bin:{brain:"./dist/brain.js"},exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"},"./cli":"./dist/brain.js","./plugins":{types:"./dist/plugins.d.ts",import:"./dist/plugins.js"},"./entities":{types:"./dist/entities.d.ts",import:"./dist/entities.js"},"./services":{types:"./dist/services.d.ts",import:"./dist/services.js"},"./interfaces":{types:"./dist/interfaces.d.ts",import:"./dist/interfaces.js"},"./templates":{types:"./dist/templates.d.ts",import:"./dist/templates.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"},"./tsconfig.instance.json":"./tsconfig.instance.json"},files:["dist","templates","tsconfig.instance.json"],scripts:{build:"bun scripts/build.ts",prepublishOnly:"bun scripts/build.ts","dev:start":"bun scripts/build.ts && bun dist/brain.js start",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:{"@bitwarden/sdk-napi":"^1.0.0","@libsql/client":"^0.15.7","@tailwindcss/oxide":"^4.1.4","better-sqlite3":"^11.8.1",lightningcss:"^1.29.2","playwright-core":"^1.56.0","react-devtools-core":"^6.1.1",sharp:"^0.34.5"},devDependencies:{"@brains/app":"workspace:*","@brains/content-formatters":"workspace:*","@brains/deploy-support":"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/theme-default":"workspace:*","@brains/theme-rizom":"workspace:*","@brains/typescript-config":"workspace:*","@brains/utils":"workspace:*","@types/bun":"latest",rollup:"^4.60.2","rollup-plugin-dts":"^6.4.1",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 AA2,writeFileSync as io,chmodSync as no,existsSync as jo0,readFileSync as _o0}from"fs";import{basename as Mo0,dirname as Po0,join as b6,resolve as _FB}from"path";import{fileURLToPath as MFB}from"url";var m02=`ARG BUN_VERSION=1.3.10
|
|
11975
|
+
`,q02=()=>x$("style",{children:X3B},void 0,!1,void 0,this);import{jsxDEV as F2,Fragment as H3B}from"preact/jsx-dev-runtime";var NY0=({title:A,description:Q,children:B,detail:w=!1,footer:$=!1,contentClassName:D=""})=>F2(H3B,{children:[F2(NQ,{title:A,description:Q},void 0,!1,void 0,this),F2(q02,{},void 0,!1,void 0,this),F2("div",{className:`docs-handbook${w?" docs-handbook--detail":""}`,children:[F2(G02,{},void 0,!1,void 0,this),F2("div",{className:`${Bz.wrap} ${D}`.trim(),children:[B,$&&F2(z02,{},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),F02=({docsCount:A,sectionsCount:Q,startDoc:B})=>F2("section",{className:"border-b border-[var(--docs-text)] py-14 md:py-24 md:pb-[72px]",children:[F2("p",{className:`${Bz.label} mb-8`,children:"Handbook \xB7 Brains docs"},void 0,!1,void 0,this),F2("h1",{className:`${Bz.display} m-0 max-w-[16ch] text-5xl leading-[1.05] tracking-[-0.02em] md:text-7xl`,children:["Build, run, and publish"," ",F2("em",{className:"text-[var(--docs-accent)]",children:"brains."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F2("p",{className:"mt-8 max-w-[52ch] text-lg leading-[1.65] text-[var(--docs-text-muted)]",children:"Documentation for composing brain models, managing markdown entities, wiring interfaces, and shipping generated sites."},void 0,!1,void 0,this),F2("dl",{className:"mt-10 flex flex-wrap gap-7 docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] md:mt-14 md:gap-12",children:[F2("div",{children:[F2("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:A},void 0,!1,void 0,this),"Documents"]},void 0,!0,void 0,this),F2("div",{children:[F2("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:Q},void 0,!1,void 0,this),"Sections"]},void 0,!0,void 0,this),F2("div",{children:[F2("strong",{className:"mb-0.5 block font-medium text-[var(--docs-text)]",children:"April 2026"},void 0,!1,void 0,this),"Updated"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),F2("div",{className:"mt-9 flex flex-wrap gap-3.5",children:[B&&F2("a",{className:Bz.primaryButton,href:oE(B),children:"Start reading"},void 0,!1,void 0,this),F2("a",{className:Bz.button,href:"#sections",children:"Browse sections"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),I02=({groups:A})=>F2("aside",{className:"docs-rail sticky top-8 hidden docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)] min-[861px]:block","aria-label":"Documentation sections",children:[F2("p",{className:"m-0 mb-3.5 font-medium text-[var(--docs-text)]",children:"Sections"},void 0,!1,void 0,this),F2("ol",{className:"m-0 list-none p-0",children:A.map((Q,B)=>F2("li",{className:"grid grid-cols-[32px_1fr] gap-2 py-1.5",children:[F2("span",{className:"docs-font-display text-[var(--docs-text-light)] italic",children:[sE(B),"."]},void 0,!0,void 0,this),F2("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:`#${bY0(B)}`,children:Q.section},void 0,!1,void 0,this)]},Q.section,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),V02=({group:A,index:Q})=>F2("article",{className:"mb-16 last:mb-0",id:bY0(Q),children:[F2("header",{className:"mb-2 grid grid-cols-[36px_auto_1fr] items-baseline gap-x-3 border-b border-[var(--docs-border)] pb-3.5 md:grid-cols-[48px_auto_1fr] md:gap-x-5",children:[F2("span",{className:"text-right docs-font-display text-3xl leading-[1.1] text-[var(--docs-accent)] italic md:text-4xl",children:[sE(Q),"."]},void 0,!0,void 0,this),F2("h2",{className:`${Bz.display} m-0 text-3xl leading-[1.1] tracking-[-0.015em] md:text-4xl`,children:A.section},void 0,!1,void 0,this),F2("span",{className:"docs-chapter__leader"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F2("ol",{className:"m-0 list-none p-0",children:A.docs.map((B)=>F2("li",{className:"border-b border-[var(--docs-border-light)] last:border-b-0",children:F2("a",{className:"group block py-[18px] pl-12 md:pl-[68px]",href:oE(B),children:[F2("p",{className:"m-0 text-[22px] leading-[1.2] tracking-[-0.005em] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:B.metadata.title},void 0,!1,void 0,this),B.metadata.description&&F2("p",{className:"mt-1.5 mb-0 max-w-[70ch] text-sm leading-[1.55] text-[var(--docs-text-muted)]",children:B.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},B.id,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),J02=({title:A})=>F2("nav",{className:"mb-8 flex flex-wrap items-baseline gap-2.5 docs-font-label text-[11px] uppercase tracking-[0.06em] text-[var(--docs-text-light)]","aria-label":"Breadcrumb",children:[F2("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/",children:"Home"},void 0,!1,void 0,this),F2("span",{children:"/"},void 0,!1,void 0,this),F2("a",{className:"text-[var(--docs-text-muted)] hover:text-[var(--docs-accent)]",href:"/docs",children:"Docs"},void 0,!1,void 0,this),F2("span",{children:"/"},void 0,!1,void 0,this),F2("span",{children:A},void 0,!1,void 0,this)]},void 0,!0,void 0,this),L02=({groups:A,activeGroupIndex:Q,activeSlug:B})=>F2("aside",{className:"docs-detail-rail sticky top-24 hidden max-h-[calc(100vh-120px)] overflow-auto pr-2 min-[861px]:block","aria-label":"Documentation navigation",children:F2("nav",{className:"docs-font-label text-xs tracking-[0.06em] text-[var(--docs-text-light)]",children:[F2("p",{className:"m-0 mb-4 border-b border-[var(--docs-text)] pb-3 text-[11px] uppercase tracking-[0.08em] text-[var(--docs-text-light)]",children:"Documentation"},void 0,!1,void 0,this),F2("ol",{className:"m-0 list-none p-0",children:A.map((w,$)=>{let D=$===Q;return F2("li",{className:D?"mb-[22px]":"mb-3.5",children:[F2("a",{className:`mb-2 flex items-baseline gap-2.5 docs-font-label text-[11px] uppercase leading-[1.4] tracking-[0.06em] transition-colors duration-150 hover:text-[var(--docs-text)] ${D?"text-[var(--docs-text)]":"text-[var(--docs-text-muted)]"}`,href:`/docs#${bY0($)}`,children:[F2("span",{className:"docs-font-display text-sm text-[var(--docs-accent)] italic",children:[sE($),"."]},void 0,!0,void 0,this)," ",w.section]},void 0,!0,void 0,this),D&&F2("ol",{className:"mt-0.5 list-none p-0",children:w.docs.map((f)=>{let Y=f.metadata.slug===B;return F2("li",{children:F2("a",{className:`docs-rail__doc relative block py-1.5 docs-font-body text-sm leading-[1.4] tracking-normal transition-[color,padding-left] duration-150 hover:text-[var(--docs-text)] ${Y?"pl-3.5 font-medium text-[var(--docs-accent)]":"text-[var(--docs-text-muted)]"}`,href:oE(f),"aria-current":Y?"page":void 0,children:f.metadata.title},void 0,!1,void 0,this)},f.id,!1,void 0,this)})},void 0,!1,void 0,this)]},w.section,!0,void 0,this)})},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),b02=({prevDoc:A,nextDoc:Q})=>{if(!A&&!Q)return null;return F2("nav",{className:"mt-12 grid grid-cols-1 gap-5 border-t border-[var(--docs-border)] pt-7 md:grid-cols-2","aria-label":"Previous and next docs",children:[A?F2("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] transition-colors duration-150 hover:border-[var(--docs-accent)]",href:oE(A),children:[F2("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Previous"},void 0,!1,void 0,this),F2("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:["\u2190 ",A.metadata.title]},void 0,!0,void 0,this)]},void 0,!0,void 0,this):F2("span",{},void 0,!1,void 0,this),Q&&F2("a",{className:"group border-t border-[var(--docs-border-light)] pt-[18px] text-left transition-colors duration-150 hover:border-[var(--docs-accent)] md:text-right",href:oE(Q),children:[F2("span",{className:"block docs-font-label text-[10.5px] uppercase tracking-[0.22em] text-[var(--docs-text-light)]",children:"Next"},void 0,!1,void 0,this),F2("span",{className:"mt-2 block docs-font-display text-[22px] leading-[1.2] text-[var(--docs-heading)] transition-colors duration-150 group-hover:text-[var(--docs-accent)]",children:[Q.metadata.title," \u2192"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as aE}from"preact/jsx-dev-runtime";var Xo0=({docs:A})=>{let Q=uo(A),B=LY0(Q),$=Q.filter((D)=>D.metadata.slug!=="index")[0]??Q[0];return aE(NY0,{title:"Documentation",description:"Brains documentation",children:[aE(F02,{docsCount:A.length,sectionsCount:B.length,startDoc:$},void 0,!1,void 0,this),aE("section",{className:"grid items-start gap-10 py-12 md:grid-cols-[200px_minmax(0,1fr)] md:gap-20 md:py-20 md:pb-[120px]",id:"sections",children:[aE(I02,{groups:B},void 0,!1,void 0,this),aE("div",{children:B.map((D,f)=>aE(V02,{group:D,index:f},D.section,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};import{jsxDEV as gX}from"preact/jsx-dev-runtime";var Ho0=({doc:A,docs:Q,prevDoc:B,nextDoc:w})=>{let $=LY0(Q.length>0?Q:[A]),D=uo(Q.length>0?Q:[A]),f=D.findIndex((X)=>X.metadata.slug===A.metadata.slug),Y=Math.max($.findIndex((X)=>X.docs.some((H)=>H.metadata.slug===A.metadata.slug)),0);return gX(NY0,{title:A.metadata.title,description:A.metadata.description??A.metadata.section,detail:!0,footer:!0,contentClassName:"pt-16",children:[gX(J02,{title:A.metadata.title},void 0,!1,void 0,this),gX("div",{className:"grid items-start gap-10 py-8 pb-24 md:grid-cols-[240px_minmax(0,1fr)] md:gap-20",children:[gX(L02,{groups:$,activeGroupIndex:Y,activeSlug:A.metadata.slug},void 0,!1,void 0,this),gX("article",{className:"min-w-0",children:[gX("header",{className:"mb-10 border-b border-[var(--docs-border)] pb-8",children:[gX("p",{className:`${Bz.label} m-0 mb-6 flex items-baseline gap-3`,children:[gX("span",{className:"docs-font-display text-lg leading-none tracking-normal normal-case text-[var(--docs-accent)] italic",children:[sE(Y),"."]},void 0,!0,void 0,this)," ",A.metadata.section,f>=0?` \xB7 ${f+1}/${D.length}`:""]},void 0,!0,void 0,this),gX("h1",{className:`${Bz.display} m-0 max-w-[18ch] text-4xl leading-[1.05] tracking-[-0.02em] md:text-6xl`,children:A.metadata.title},void 0,!1,void 0,this),A.metadata.description&&gX("p",{className:"mt-6 max-w-[56ch] docs-font-display text-[22px] font-[350] leading-[1.5] text-[var(--docs-text-muted)]",children:A.metadata.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),gX("div",{className:"docs-article__body",children:gX(f9,{markdown:A.body},void 0,!1,void 0,this)},void 0,!1,void 0,this),gX(b02,{prevDoc:B,nextDoc:w},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)};var W3B=K.object({docs:K.array(LF),pagination:e7.nullable(),baseUrl:K.string().optional()}),Z3B=K.object({doc:LF,docs:K.array(LF),prevDoc:LF.nullable(),nextDoc:LF.nullable()});function N02(){return{"doc-list":R1({name:"doc-list",description:"Documentation index template",schema:W3B,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:Xo0}}),"doc-detail":R1({name:"doc-detail",description:"Documentation page template",schema:Z3B,dataSourceId:"docs:entities",requiredPermission:"public",layout:{component:Ho0}})}}var j02={name:"@brains/doc",private:!0,version:"0.2.0-alpha.129",description:"Documentation entity type \u2014 markdown docs as first-class 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"},dependencies:{"@brains/plugins":"workspace:*","@brains/templates":"workspace:*","@brains/ui-library":"workspace:*","@brains/utils":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","bun-types":"latest",typescript:"^5.3.3"}};class Wo0 extends PQ{entityType=VY0.entityType;schema=rE;adapter=VY0;constructor(){super("docs",j02,{},void 0)}getTemplates(){return N02()}getDataSources(){return[new JY0(this.logger.child("DocDataSource"))]}}function Zo0(){return new Wo0}p0();K0();K0();p$();var _02=K.object({label:K.string(),href:K.string()}),M02=K.object({label:K.string(),title:K.string(),detail:K.string()}),U3B=K.object({eyebrow:K.string(),name:K.string(),sub:K.string()}),G3B=K.object({tone:K.enum(["capture","synthesis","share"]),title:K.string(),text:K.string()}),Ko0=K.object({captures:K.number(),links:K.number(),topics:K.number(),summaries:K.number(),peers:K.number()}),tE=K.object({eyebrow:K.string(),headline:K.string(),intro:K.string(),primaryCta:_02,secondaryCta:_02,inputs:K.array(M02).min(1),outputs:K.array(M02).min(1),core:U3B,legend:K.array(G3B).min(1)}),Uo0=tE.extend({counts:Ko0}),P02={eyebrow:"A team brain, diagrammed",headline:"Relay sits between the work and the world, and keeps both honest.",intro:"Capture sources flow into a shared brain; the brain organizes, summarizes, and \u2014 selectively \u2014 exposes a public surface. Everything else stays private and operational.",primaryCta:{label:"See it on a real team",href:"#diagram"},secondaryCta:{label:"Read the model",href:"/about"},inputs:[{label:"Source \xB7 chat",title:"Discord",detail:"Shared decisions and field notes captured in flow."},{label:"Source \xB7 agent",title:"MCP / CLI",detail:"Structured captures from tools and assistants."},{label:"Source \xB7 web",title:"Links & docs",detail:"External material indexed with sourceable metadata."}],outputs:[{label:"Surface \xB7 public",title:"Default site",detail:"A small, durable face onto what the team currently knows."},{label:"Surface \xB7 agents",title:"A2A exchange",detail:"Peer brains coordinate over an approved, signed protocol."},{label:"Surface \xB7 query",title:"Team Q&A",detail:"Ask the brain in chat; answers cite the captures behind them."}],core:{eyebrow:"The relay",name:"brain",sub:"capture \u2192 topics \u2192 summaries"},legend:[{tone:"capture",title:"Capture",text:"Anything the team already does that produces a trace \u2014 chat messages, links, deploys, decisions."},{tone:"synthesis",title:"Synthesis",text:"The work the brain does on its own time \u2014 clustering captures into topics, summaries, and durable memory."},{tone:"share",title:"Share",text:"A small, opinionated public surface and an approved agent-to-agent protocol. Most memory stays private."}]},k02=new pB(tE,{title:"Home diagram",mappings:[{key:"eyebrow",label:"Eyebrow",type:"string"},{key:"headline",label:"Headline",type:"string"},{key:"intro",label:"Intro",type:"string"},{key:"primaryCta",label:"Primary CTA",type:"object",children:[{key:"label",label:"Label",type:"string"},{key:"href",label:"Href",type:"string"}]},{key:"secondaryCta",label:"Secondary CTA",type:"object",children:[{key:"label",label:"Label",type:"string"},{key:"href",label:"Href",type:"string"}]},{key:"inputs",label:"Inputs",type:"array",itemType:"object",itemMappings:[{key:"label",label:"Label",type:"string"},{key:"title",label:"Title",type:"string"},{key:"detail",label:"Detail",type:"string"}]},{key:"outputs",label:"Outputs",type:"array",itemType:"object",itemMappings:[{key:"label",label:"Label",type:"string"},{key:"title",label:"Title",type:"string"},{key:"detail",label:"Detail",type:"string"}]},{key:"core",label:"Core",type:"object",children:[{key:"eyebrow",label:"Eyebrow",type:"string"},{key:"name",label:"Name",type:"string"},{key:"sub",label:"Sub",type:"string"}]},{key:"legend",label:"Legend",type:"array",itemType:"object",itemMappings:[{key:"tone",label:"Tone",type:"string"},{key:"title",label:"Title",type:"string"},{key:"text",label:"Text",type:"string"}]}]});function jY0(A){return k02.parse(A)}function O02(A){return k02.format(A)}K0();var z3B=K.object({query:K.object({routeId:K.string().default("home"),sectionId:K.string().default("diagram")}).default({routeId:"home",sectionId:"diagram"})}).passthrough(),q3B={captures:"note",links:"link",topics:"topic",summaries:"summary",peers:"agent"};class Go0{id="relay-site:home-counts";name="Relay homepage counts";description="Fetches Relay homepage content and live entity counts for the system diagram";async fetch(A,Q,B){let w=z3B.parse(A??{}),$=await this.fetchContent(B,w.query.routeId,w.query.sectionId),D=await this.fetchCounts(B);return Q.parse({...$,counts:D})}async fetchContent(A,Q,B){let w=await A.entityService.getEntity({entityType:"site-content",id:`${Q}:${B}`});if(!w?.content)return P02;return tE.parse(jY0(w.content))}async fetchCounts(A){let Q=await Promise.all(Object.entries(q3B).map(async([B,w])=>[B,await this.countOrZero(A,w)]));return Ko0.parse(Object.fromEntries(Q))}async countOrZero(A,Q){if(!A.entityService.hasEntityType(Q))return 0;try{return await A.entityService.countEntities({entityType:Q})}catch{return 0}}}import{jsxDEV as w1}from"preact/jsx-dev-runtime";var x02=K.object({label:K.string(),href:K.string()}),F3B=K.object({eyebrow:K.string(),headline:K.string(),intro:K.string(),primaryCta:x02,secondaryCta:x02,signals:K.array(K.object({label:K.string(),value:K.string(),note:K.string()}))}),I3B=K.object({eyebrow:K.string(),title:K.string(),intro:K.string(),steps:K.array(K.object({phase:K.string(),title:K.string(),text:K.string()}))}),V3B=K.object({title:K.string(),intro:K.string(),cards:K.array(K.object({label:K.string(),title:K.string(),text:K.string()}))}),J3B=K.object({title:K.string(),intro:K.string(),points:K.array(K.string())}),L3B={title:"Relay is a collaborative team-memory brain.",intro:"It exists for teams that need to remember together: capturing what happened, summarizing why it matters, and coordinating with trusted peer brains when work crosses boundaries.",points:["Not a personal blog engine or portfolio shell.","Not a marketing automation stack.","A small public face for a larger private knowledge workflow."]},b3B="font-body text-[15px] text-theme-muted transition-colors hover:text-theme";function R02({href:A,label:Q}){return w1("a",{href:A,className:b3B,children:Q},void 0,!1,void 0,this)}function N3B({siteInfo:A,children:Q}){let B=[...A.navigation.primary,...A.navigation.secondary],w=A.cta??{buttonText:"Start here",buttonLink:"/about"};return w1(gE,{children:[w1("nav",{className:"fixed left-0 right-0 top-0 z-[100] flex items-center justify-between border-b border-theme-light bg-nav-fade px-6 py-4 backdrop-blur-[12px] md:px-10 xl:px-20",children:[w1("a",{href:"/",className:"font-nav text-[20px]","aria-label":"Relay home",children:[w1("span",{className:"font-bold text-theme",children:"relay"},void 0,!1,void 0,this),w1("span",{className:"font-bold text-accent",children:"."},void 0,!1,void 0,this),w1("span",{className:"text-theme-muted",children:"brain"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"flex items-center gap-5 md:gap-8",children:[w1("div",{className:"hidden items-center gap-6 md:flex",children:B.map(($)=>w1(R02,{...$},`${$.href}-${$.label}`,!1,void 0,this))},void 0,!1,void 0,this),w1("a",{href:w.buttonLink,className:"rounded-[999px] border border-theme px-4 py-2 font-body text-[13px] font-semibold text-theme transition-colors hover:border-accent hover:text-accent md:px-5",children:w.buttonText},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("main",{children:Q},void 0,!1,void 0,this),w1("footer",{className:"relative z-[1] border-t border-theme-light px-6 py-8 md:px-10 xl:px-20",children:w1("div",{className:"flex flex-col gap-4 md:flex-row md:items-center md:justify-between",children:[w1("div",{children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.22em] text-theme-light",children:A.copyright},void 0,!1,void 0,this),w1("p",{className:"mt-2 max-w-[560px] font-body text-body-xs text-theme-muted",children:A.description},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"flex flex-wrap items-center gap-5",children:[B.map(($)=>w1(R02,{...$},`footer-${$.href}-${$.label}`,!1,void 0,this)),w1("button",{id:"themeToggle","aria-label":"Toggle light mode",className:"rounded-md border border-theme-light bg-transparent px-2.5 py-1.5 font-body text-label-md text-theme-light transition-colors hover:border-theme hover:text-theme",children:"\u2600 Light"},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)}var j3B=({sections:A,siteInfo:Q})=>w1(N3B,{siteInfo:Q,children:A},void 0,!1,void 0,this);function _3B({eyebrow:A,headline:Q,intro:B,primaryCta:w,secondaryCta:$,signals:D}){return w1(gL,{className:"min-h-[92vh] pt-[152px] pb-20 md:pt-[190px]",children:w1("div",{className:"grid gap-10 lg:grid-cols-[minmax(0,1fr)_420px] lg:items-end",children:[w1("div",{children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-accent",children:A},void 0,!1,void 0,this),w1("h1",{className:"mt-7 max-w-[980px] font-display text-display-lg text-theme",children:Q},void 0,!1,void 0,this),w1("p",{className:"mt-7 max-w-[720px] font-body text-body-lg text-theme-muted",children:B},void 0,!1,void 0,this),w1("div",{className:"mt-10 flex flex-col gap-3 sm:flex-row",children:[w1(vP,{href:w.href,size:"lg",variant:"primary-strong",children:w.label},void 0,!1,void 0,this),w1(vP,{href:$.href,size:"lg",variant:"secondary",children:$.label},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"rounded-[32px] border border-card-relay-border bg-card-relay-bg p-5 shadow-[0_24px_90px_var(--color-glow-relay)] backdrop-blur-sm",children:[w1("p",{className:"font-label text-label-xs uppercase tracking-[0.24em] text-theme-light",children:"Live relay signals"},void 0,!1,void 0,this),w1("div",{className:"mt-5 grid gap-3",children:D.map((f)=>w1("div",{className:"rounded-[22px] border border-card-divider bg-bg-muted p-5",children:[w1("div",{className:"flex items-center justify-between gap-4",children:[w1("p",{className:"font-label text-label-xs uppercase tracking-[0.18em] text-secondary",children:f.label},void 0,!1,void 0,this),w1("span",{className:"h-2 w-2 rounded-full bg-accent shadow-[0_0_22px_var(--color-accent)]"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("p",{className:"mt-4 font-display text-display-sm text-theme",children:f.value},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-body text-body-xs text-theme-muted",children:f.note},void 0,!1,void 0,this)]},f.label,!0,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)}function M3B({eyebrow:A,title:Q,intro:B,steps:w}){return w1(gL,{id:"operating-loop",className:"py-section",children:[w1("div",{className:"max-w-[840px]",children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-secondary",children:A},void 0,!1,void 0,this),w1("h2",{className:"mt-5 font-display text-display-md text-theme",children:Q},void 0,!1,void 0,this),w1("p",{className:"mt-5 font-body text-body-md text-theme-muted",children:B},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mt-12 grid gap-4 md:grid-cols-3",children:w.map(($)=>w1("article",{className:"min-h-[300px] rounded-[28px] border border-card-panel-border bg-card-panel-bg p-6",children:[w1("p",{className:"font-label text-label-sm text-accent",children:$.phase},void 0,!1,void 0,this),w1("h3",{className:"mt-16 font-display text-display-sm text-theme",children:$.title},void 0,!1,void 0,this),w1("p",{className:"mt-4 font-body text-body-sm text-theme-muted",children:$.text},void 0,!1,void 0,this)]},$.phase,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function P3B({title:A,intro:Q,cards:B}){return w1(gL,{className:"py-section",children:w1("div",{className:"rounded-[36px] border border-theme-light bg-bg-muted p-6 md:p-10",children:w1("div",{className:"grid gap-8 lg:grid-cols-[360px_1fr]",children:[w1("div",{children:[w1("h2",{className:"font-display text-display-md text-theme",children:A},void 0,!1,void 0,this),w1("p",{className:"mt-5 font-body text-body-md text-theme-muted",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"grid gap-4",children:B.map((w)=>w1("article",{className:"rounded-[24px] border border-card-divider bg-bg-subtle/70 p-5",children:[w1("p",{className:"font-label text-label-xs uppercase tracking-[0.22em] text-accent",children:w.label},void 0,!1,void 0,this),w1("h3",{className:"mt-3 font-nav text-heading-lg text-theme",children:w.title},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-body text-body-sm text-theme-muted",children:w.text},void 0,!1,void 0,this)]},w.title,!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)}function k3B({title:A,intro:Q,points:B}){return w1(gL,{className:"min-h-[78vh] pt-[150px] pb-section md:pt-[190px]",children:[w1("div",{className:"max-w-[920px]",children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-accent",children:"Relay model"},void 0,!1,void 0,this),w1("h1",{className:"mt-6 font-display text-display-lg text-theme",children:A},void 0,!1,void 0,this),w1("p",{className:"mt-7 font-body text-body-lg text-theme-muted",children:Q},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mt-12 grid gap-4 md:grid-cols-3",children:B.map((w)=>w1("div",{className:"rounded-[24px] border border-card-panel-current-border bg-card-panel-current-bg p-6 font-body text-body-md text-theme",children:w},w,!1,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var O3B=(A)=>{switch(A){case"capture":return"bg-accent";case"synthesis":return"bg-secondary";case"share":return"bg-accent-bright"}},x3B=(A)=>new Intl.NumberFormat("en",{notation:A>999?"compact":"standard"}).format(A),co=(A,Q,B=`${Q}s`)=>`${x3B(A)} ${A===1?Q:B}`;function R3B({eyebrow:A,headline:Q,intro:B,primaryCta:w,secondaryCta:$,inputs:D,outputs:f,core:Y,legend:X,counts:H}){let W=[{key:"captures",className:"top-[-10px] left-1/2 -translate-x-1/2",label:co(H.captures,"capture")},{key:"topics",className:"top-1/2 right-[-28px] -translate-y-1/2",label:co(H.topics,"topic")},{key:"peers",className:"bottom-[-10px] left-1/2 -translate-x-1/2",label:co(H.peers,"peer brain")},{key:"summaries",className:"top-1/2 left-[-28px] -translate-y-1/2",label:co(H.summaries,"summary","summaries")}];return w1(gL,{className:"pt-[150px] pb-section md:pt-[190px]",id:"diagram",children:[w1("div",{className:"mx-auto max-w-[1040px] text-center",children:[w1("p",{className:"font-label text-label-sm uppercase tracking-[0.28em] text-accent",children:A},void 0,!1,void 0,this),w1("h1",{className:"mx-auto mt-7 max-w-[22ch] font-display text-display-lg text-theme",children:Q},void 0,!1,void 0,this),w1("p",{className:"mx-auto mt-7 max-w-[64ch] font-body text-body-lg text-theme-muted",children:B},void 0,!1,void 0,this),w1("div",{className:"mt-10 flex flex-col justify-center gap-3 sm:flex-row",children:[w1(vP,{href:w.href,size:"lg",variant:"primary-strong",children:w.label},void 0,!1,void 0,this),w1(vP,{href:$.href,size:"lg",variant:"secondary",children:$.label},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mx-auto mt-20 max-w-[1020px] rounded-[32px] border border-theme-light bg-[radial-gradient(circle_at_1px_1px,rgb(255_255_255_/_0.05)_1px,transparent_0),linear-gradient(180deg,rgb(255_255_255_/_0.02),transparent)] bg-[length:24px_24px,100%_100%] px-6 py-14",children:[w1("div",{className:"grid items-center gap-8 lg:grid-cols-[1fr_1.4fr_1fr]",children:[w1("div",{className:"flex flex-col gap-3.5",children:D.map((Z)=>w1("div",{className:"rounded-2xl border border-card-panel-border border-l-2 border-l-accent bg-card-panel-bg px-4 py-4 text-left backdrop-blur-sm",children:[w1("p",{className:"font-label text-[10px] uppercase tracking-[0.22em] text-secondary",children:Z.label},void 0,!1,void 0,this),w1("h2",{className:"mt-1.5 font-display text-[18px] font-medium text-theme",children:Z.title},void 0,!1,void 0,this),w1("p",{className:"mt-1 font-body text-[13px] leading-[1.5] text-theme-muted",children:Z.detail},void 0,!1,void 0,this)]},`${Z.label}-${Z.title}`,!0,void 0,this))},void 0,!1,void 0,this),w1("div",{className:"relative mx-auto grid aspect-square w-full max-w-[320px] place-items-center rounded-full bg-[radial-gradient(circle_at_center,rgb(232_119_34_/_0.25),transparent_65%)]",children:[w1("div",{className:"absolute inset-0 rounded-full border border-dashed border-accent/30"},void 0,!1,void 0,this),w1("div",{className:"absolute inset-6 animate-spin rounded-full border border-dashed border-secondary/40 [animation-duration:28s]"},void 0,!1,void 0,this),W.map((Z)=>w1("span",{className:`absolute whitespace-nowrap rounded-full border border-theme bg-bg px-2.5 py-1 font-label text-[10px] uppercase tracking-[0.18em] text-theme-light ${Z.className}`,children:Z.label},Z.key,!1,void 0,this)),w1("div",{className:"relative z-[1] px-6 text-center",children:[w1("p",{className:"font-label text-[10px] uppercase tracking-[0.28em] text-accent",children:Y.eyebrow},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-display text-[36px] leading-none text-theme",children:Y.name},void 0,!1,void 0,this),w1("p",{className:"mt-2 font-body text-[13px] text-theme-muted",children:Y.sub},void 0,!1,void 0,this),w1("p",{className:"mt-4 font-label text-[10px] uppercase tracking-[0.18em] text-theme-light",children:[co(H.links,"link")," indexed"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"flex flex-col gap-3.5",children:f.map((Z)=>w1("div",{className:"rounded-2xl border border-card-panel-border border-r-2 border-r-secondary bg-card-panel-bg px-4 py-4 text-left backdrop-blur-sm",children:[w1("p",{className:"font-label text-[10px] uppercase tracking-[0.22em] text-secondary",children:Z.label},void 0,!1,void 0,this),w1("h2",{className:"mt-1.5 font-display text-[18px] font-medium text-theme",children:Z.title},void 0,!1,void 0,this),w1("p",{className:"mt-1 font-body text-[13px] leading-[1.5] text-theme-muted",children:Z.detail},void 0,!1,void 0,this)]},`${Z.label}-${Z.title}`,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this),w1("div",{className:"mt-14 grid gap-4 border-t border-theme-light pt-8 md:grid-cols-3",children:X.map((Z)=>w1("div",{className:"text-left",children:[w1("h2",{className:"font-display text-[16px] font-medium text-theme",children:[w1("span",{className:`mr-2.5 inline-block h-3 w-3 rounded-[3px] align-middle ${O3B(Z.tone)}`},void 0,!1,void 0,this),Z.title]},void 0,!0,void 0,this),w1("p",{className:"mt-1.5 font-body text-[13px] leading-[1.6] text-theme-muted",children:Z.text},void 0,!1,void 0,this)]},Z.title,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var v3B=R1({name:"home-diagram",description:"Relay homepage system diagram with live entity counts",schema:Uo0,formatter:{parse:(A)=>Uo0.parse({...jY0(A),counts:{captures:0,links:0,topics:0,summaries:0,peers:0}}),format:(A)=>O02(tE.parse(A))},dataSourceId:"relay-site:home-counts",requiredPermission:"public",layout:{component:R3B}}),h3B=(A)=>_3B(F3B.parse(A)),C3B=(A)=>M3B(I3B.parse(A)),y3B=(A)=>P3B(V3B.parse(A)),E3B=(A)=>k3B(J3B.parse(A)),v02={type:"object",label:"CTA",fields:{label:{type:"string",label:"Label"},href:{type:"string",label:"Href"}}},h02={namespace:"relay-site",sections:{"home-hero":{title:"Home hero",description:"Relay homepage hero section",layout:h3B,fields:{eyebrow:{type:"string",label:"Eyebrow"},headline:{type:"string",label:"Headline"},intro:{type:"string",label:"Intro"},primaryCta:{...v02,label:"Primary CTA"},secondaryCta:{...v02,label:"Secondary CTA"},signals:{type:"array",label:"Signals",minItems:1,items:{type:"object",label:"Signal",fields:{label:{type:"string",label:"Label"},value:{type:"string",label:"Value"},note:{type:"string",label:"Note"}}}}}},"home-loop":{title:"Home operating loop",description:"Relay capture, synthesis, and sharing loop",layout:C3B,fields:{eyebrow:{type:"string",label:"Eyebrow"},title:{type:"string",label:"Title"},intro:{type:"string",label:"Intro"},steps:{type:"array",label:"Steps",minItems:1,items:{type:"object",label:"Step",fields:{phase:{type:"string",label:"Phase"},title:{type:"string",label:"Title"},text:{type:"string",label:"Text"}}}}}},"home-surface":{title:"Home surface",description:"Relay default template explanation cards",layout:y3B,fields:{title:{type:"string",label:"Title"},intro:{type:"string",label:"Intro"},cards:{type:"array",label:"Cards",minItems:1,items:{type:"object",label:"Card",fields:{label:{type:"string",label:"Label"},title:{type:"string",label:"Title"},text:{type:"string",label:"Text"}}}}}},about:{title:"About Relay",description:"Default Relay about page",layout:E3B,fields:{title:{type:"string",label:"Title"},intro:{type:"string",label:"Intro"},points:{type:"array",label:"Points",minItems:1,items:{type:"string",label:"Point"}}}}}},g3B=[{id:"home",path:"/",title:"Relay",description:"Collaborative team memory and synthesis brain",layout:"default",navigation:{show:!0,label:"Home",slot:"secondary",priority:10},sections:[{id:"diagram",template:"relay-site:home-diagram"}]},{id:"about",path:"/about",title:"About Relay",description:"What Relay is designed to do",layout:"default",navigation:{show:!0,label:"About",slot:"primary",priority:20},sections:[{id:"about",template:"relay-site:about",content:L3B}]}],C02=dr0({packageName:"@brains/relay/site",contentNamespace:"relay-site",themeProfile:"studio",layout:j3B,routes:g3B,templates:{"home-diagram":v3B},dataSources:[new Go0]});var y02={name:"@brains/relay",private:!0,version:"0.2.0-alpha.129",description:"Relay brain model \u2014 collaborative knowledge management",type:"module",files:["src","brain.eval.yaml","env.schema.template"],exports:{".":"./src/index.ts"},scripts:{"build:web-chat":"turbo run build --filter=@brains/web-chat","start:core":"bun run build:web-chat && cd test-apps/core && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:default":"bun run build:web-chat && cd test-apps/default && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:full":"bun run build:web-chat && cd test-apps/full && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start","start:docs":"bun run build:web-chat && cd test-apps/docs && INIT_CWD=$PWD bun run --filter @rizom/brain dev:start",typecheck:"tsc --noEmit",test:"bun test",eval:"brain-eval",lint:"eslint . --ext .ts,.tsx","lint:fix":"eslint . --ext .ts,.tsx --fix"},dependencies:{"@brains/a2a":"workspace:*","@brains/agent-discovery":"workspace:*","@brains/app":"workspace:*","@brains/assessment":"workspace:*","@brains/auth-service":"workspace:*","@brains/cms":"workspace:*","@brains/content-formatters":"workspace:*","@brains/conversation-memory":"workspace:*","@brains/dashboard":"workspace:*","@brains/decks":"workspace:*","@brains/directory-sync":"workspace:*","@brains/discord":"workspace:*","@brains/doc":"workspace:*","@brains/email-resend":"workspace:*","@brains/image-plugin":"workspace:*","@brains/link":"workspace:*","@brains/mcp":"workspace:*","@brains/note":"workspace:*","@brains/notifications":"workspace:*","@brains/plugins":"workspace:*","@brains/prompt":"workspace:*","@brains/rizom-ecosystem":"workspace:*","@brains/site-builder-plugin":"workspace:*","@brains/site-composition":"workspace:*","@brains/site-content":"workspace:*","@brains/site-info":"workspace:*","@brains/site-rizom":"workspace:*","@brains/theme-rizom":"workspace:*","@brains/topics":"workspace:*","@brains/utils":"workspace:*","@brains/web-chat":"workspace:*","@brains/webserver":"workspace:*",preact:"^10.27.2"},devDependencies:{"@brains/ai-evaluation":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*",typescript:"^5.3.3"}};var E02=["prompt","directory-sync","note","link","topics","conversation-memory","agents","assessment","auth-service","notifications","email-resend","cms","dashboard","mcp","webserver","web-chat","discord","a2a"],g02=[...E02,"image","site-info","site-content","site-builder"],m3B=[...g02,"docs","decks"],u3B=["Relay is a collaborative team-memory and synthesis brain. Optimize for capturing shared context, finding what the team already knows, summarizing cross-source evidence, and coordinating with peer brains.","Relay is not Rover-for-teams: do not default to personal branding, blog publishing, newsletters, social media, portfolio, or marketing workflows unless the installed plugins and user request explicitly support them.",'Relay entity mappings: "memo", "note", "team note", "capture" \u2192 entityType: note; "summary", "sync", "team digest" \u2192 entityType: summary; "decision" \u2192 entityType: decision; "action item", "todo" \u2192 entityType: action-item; "handbook", "doc", "documentation" \u2192 entityType: doc; "deck", "walkthrough", "presentation" \u2192 entityType: deck; "agent", "peer brain", "contact" \u2192 entityType: agent.'],T02=FV({name:"relay",version:y02.version,model:"gpt-5.4-mini",site:C02,theme:TE,presets:{core:E02,default:g02,full:m3B},evalDisable:["webserver","web-chat","mcp","discord"],agentInstructions:u3B,capabilities:[["prompt",kP,void 0],["note",FP,{}],["link",VP,{}],["image",Yc,void 0],["topics",gD0,{includeEntityTypes:["note","link","summary","agent","swot","deck","doc","anchor-profile","brain-character"],extractableStatuses:["published","draft"]}],["conversation-memory",Do0,{memoryVisibility:"shared"}],["docs",Zo0,void 0],["decks",Fr,void 0],["agents",Pf0,void 0],["assessment",gf0,void 0],["auth-service",tl,void 0],["notifications",pB0,void 0],["email-resend",g$0,void 0],["cms",_P,{}],["dashboard",CL,void 0],["directory-sync",JM,{seedContent:!0,seedContentPath:S3B(import.meta.dir,"..","seed-content"),initialSync:!0}],["site-content",ho,{definitions:h02}],["rizom-ecosystem",OP,void 0],["site-info",DP,void 0],["site-builder",$P,{}]],interfaces:[["mcp",tV,()=>({})],["discord",EJ,()=>({captureUrls:!0})],["a2a",yC,()=>({})],["webserver",mJ,()=>({})],["web-chat",CC,()=>({})]],permissions:{rules:[{pattern:"cli:*",level:"anchor"},{pattern:"mcp:stdio",level:"anchor"},{pattern:"mcp:http",level:"anchor"},{pattern:"discord:*",level:"public"},{pattern:"web-chat:*",level:"anchor"}],entityActions:{note:{create:"trusted",update:"trusted",delete:"anchor"},link:{create:"trusted",update:"trusted",delete:"anchor"},doc:{create:"trusted",update:"trusted",delete:"anchor"},deck:{create:"trusted",update:"trusted",delete:"anchor"},decision:{create:"trusted",update:"trusted",delete:"anchor"},"action-item":{create:"trusted",update:"trusted",delete:"anchor"},image:{create:"trusted",update:"trusted",delete:"anchor"}}},deployment:{cdn:{enabled:!0,provider:"bunny"}}});import{readFileSync as JJB}from"fs";import{join as LJB}from"path";import{execSync as bJB}from"child_process";import{parseArgs as p3B}from"util";var i3B={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"},"startup-check":{type:"boolean"},"storage-dir":{type:"string"},yes:{type:"boolean"},remote:{type:"string"},token:{type:"string"},outputDir:{type:"string"},help:{type:"boolean",short:"h"},version:{type:"boolean",short:"v"}};function MK(A,Q){let B=A[Q];return typeof B==="string"?B:void 0}function mL(A,Q){let B=A[Q];return typeof B==="boolean"?B:void 0}function S02(A){let{values:Q,positionals:B}=p3B({args:A,options:i3B,allowPositionals:!0,strict:!1});if(Q.help)return{command:"help",args:[],flags:{help:!0}};if(Q.version)return{command:"version",args:[],flags:{version:!0}};return{command:B[0]??"help",args:B.slice(1),flags:{model:MK(Q,"model"),domain:MK(Q,"domain"),"content-repo":MK(Q,"content-repo"),backend:MK(Q,"backend"),"push-to":MK(Q,"push-to"),"ai-api-key":MK(Q,"ai-api-key"),"no-interactive":mL(Q,"no-interactive"),preview:mL(Q,"preview"),deploy:mL(Q,"deploy"),regen:mL(Q,"regen"),all:mL(Q,"all"),only:MK(Q,"only"),"dry-run":mL(Q,"dry-run"),"startup-check":mL(Q,"startup-check"),"storage-dir":MK(Q,"storage-dir"),yes:mL(Q,"yes"),remote:MK(Q,"remote"),token:MK(Q,"token"),outputDir:MK(Q,"outputDir")}}}lo();import{mkdirSync as WJB}from"fs";import{join as ZJB}from"path";import{execSync as KJB}from"child_process";var MY0={name:"@rizom/brain",version:"0.2.0-alpha.129",description:"Brain runtime + CLI \u2014 scaffold, run, and manage AI brain instances",type:"module",bin:{brain:"./dist/brain.js"},exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"},"./cli":"./dist/brain.js","./plugins":{types:"./dist/plugins.d.ts",import:"./dist/plugins.js"},"./entities":{types:"./dist/entities.d.ts",import:"./dist/entities.js"},"./services":{types:"./dist/services.d.ts",import:"./dist/services.js"},"./interfaces":{types:"./dist/interfaces.d.ts",import:"./dist/interfaces.js"},"./templates":{types:"./dist/templates.d.ts",import:"./dist/templates.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"},"./tsconfig.instance.json":"./tsconfig.instance.json"},files:["dist","templates","tsconfig.instance.json"],scripts:{build:"bun scripts/build.ts",prepublishOnly:"bun scripts/build.ts","dev:start":"bun scripts/build.ts && bun dist/brain.js start",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:{"@bitwarden/sdk-napi":"^1.0.0","@libsql/client":"^0.15.7","@tailwindcss/oxide":"^4.1.4","better-sqlite3":"^11.8.1",lightningcss:"^1.29.2","playwright-core":"^1.56.0","react-devtools-core":"^6.1.1",sharp:"^0.34.5"},devDependencies:{"@brains/app":"workspace:*","@brains/content-formatters":"workspace:*","@brains/deploy-support":"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/theme-default":"workspace:*","@brains/theme-rizom":"workspace:*","@brains/typescript-config":"workspace:*","@brains/utils":"workspace:*","@types/bun":"latest",rollup:"^4.60.2","rollup-plugin-dts":"^6.4.1",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 AA2,writeFileSync as io,chmodSync as no,existsSync as jo0,readFileSync as _o0}from"fs";import{basename as Mo0,dirname as Po0,join as b6,resolve as _FB}from"path";import{fileURLToPath as MFB}from"url";var m02=`ARG BUN_VERSION=1.3.10
|
|
11976
11976
|
FROM oven/bun:\${BUN_VERSION}-slim AS runtime
|
|
11977
11977
|
|
|
11978
11978
|
WORKDIR /app
|