@@ -1035,24 +1035,52 @@ ${outputFormat}`;
10351035 } catch { /* non-fatal */ }
10361036 }
10371037
1038- // Inject agent memories
1038+ // Inject agent memories + shared memories
10391039 const memories = await ctx . api . fetchAgentMemories ( ctx . agentName ) ;
1040- if ( memories . length > 0 ) {
1040+ // Fetch shared memories matching task labels
1041+ const taskLabels : string [ ] = ( ( ) => {
1042+ const raw = ( ctx . task as Record < string , unknown > ) . labels ;
1043+ if ( Array . isArray ( raw ) ) return raw ;
1044+ if ( typeof raw === "string" ) { try { return JSON . parse ( raw ) ; } catch { return [ ] ; } }
1045+ return [ ] ;
1046+ } ) ( ) ;
1047+ let sharedMemories : AgentMemory [ ] = [ ] ;
1048+ try {
1049+ const res = await fetch ( `${ ctx . config . apiUrl } /api/v1/agents/memories/shared${ taskLabels . length ? `?tags=${ taskLabels . join ( "," ) } ` : "" } ` , {
1050+ headers : { Authorization : `Bearer ${ ctx . config . apiKey } ` , "Content-Type" : "application/json" } ,
1051+ } ) ;
1052+ if ( res . ok ) {
1053+ const data = ( await res . json ( ) ) as { memories : AgentMemory [ ] } ;
1054+ // Exclude own memories (already in `memories`)
1055+ const ownKeys = new Set ( memories . map ( ( m ) => m . key ) ) ;
1056+ sharedMemories = data . memories . filter ( ( m ) => ! ownKeys . has ( m . key ) ) ;
1057+ }
1058+ } catch { /* non-fatal */ }
1059+
1060+ const allMemories = [ ...memories , ...sharedMemories ] ;
1061+ if ( allMemories . length > 0 ) {
1062+ const ownBlock = memories . length > 0
1063+ ? memories . map ( ( m ) => `## ${ m . type } : ${ m . key } \n${ m . content } ` ) . join ( "\n\n" )
1064+ : "" ;
1065+ const sharedBlock = sharedMemories . length > 0
1066+ ? `\n# Shared Team Knowledge\n\n${ sharedMemories . map ( ( m ) => `## ${ m . type } : ${ m . key } (from @${ m . agent_name } )\n${ m . content } ` ) . join ( "\n\n" ) } `
1067+ : "" ;
10411068 const memoryBlock = [
10421069 "<!-- TOBAN_MEMORY_START -->" ,
10431070 "# Agent Memory (auto-injected by Toban)" ,
10441071 "" ,
1045- ...memories . map ( ( m ) => `## ${ m . type } : ${ m . key } \n${ m . content } ` ) ,
1072+ ownBlock ,
1073+ sharedBlock ,
10461074 "<!-- TOBAN_MEMORY_END -->" ,
1047- ] . join ( "\n" ) ;
1075+ ] . filter ( Boolean ) . join ( "\n" ) ;
10481076
10491077 let existing = fs . existsSync ( claudeMdPath )
10501078 ? fs . readFileSync ( claudeMdPath , "utf-8" )
10511079 : "" ;
10521080 // Remove existing memory block to prevent duplicates
10531081 existing = existing . replace ( / < ! - - T O B A N _ M E M O R Y _ S T A R T - - > [ \s \S ] * ?< ! - - T O B A N _ M E M O R Y _ E N D - - > \n ? / g, "" ) . trimEnd ( ) ;
10541082 fs . writeFileSync ( claudeMdPath , existing + "\n\n" + memoryBlock + "\n" ) ;
1055- injected = memories . length ;
1083+ injected = allMemories . length ;
10561084 }
10571085
10581086 // Mark CLAUDE.md as assume-unchanged so inject_memory additions don't get committed
@@ -1113,7 +1141,13 @@ ${outputFormat}`;
11131141 const memType = getType [ 1 ] . trim ( ) ;
11141142 if ( ! [ "identity" , "feedback" , "project" , "reference" ] . includes ( memType ) ) continue ;
11151143
1116- await ctx . api . putAgentMemory ( ctx . agentName , key , { type : memType , content : body } ) ;
1144+ // Parse optional shared and tags from frontmatter
1145+ const getShared = frontmatter . match ( / ^ s h a r e d : \s * ( t r u e | f a l s e ) $ / m) ;
1146+ const getTags = frontmatter . match ( / ^ t a g s : \s * ( .+ ) $ / m) ;
1147+ const shared = getShared ?. [ 1 ] === "true" ;
1148+ const tags = getTags ?. [ 1 ] ?. trim ( ) || undefined ;
1149+
1150+ await ctx . api . putAgentMemory ( ctx . agentName , key , { type : memType , content : body , shared, tags } ) ;
11171151 saved ++ ;
11181152 } catch {
11191153 // Skip unparseable files
0 commit comments