@@ -27,7 +27,6 @@ const WEB_DIST_DIR = join(__dirname, '../../web/dist')
2727const README_PATH = join ( __dirname , '../../../README.md' )
2828const SHOULD_SERVE_BUILT_WEB = existsSync ( WEB_DIST_DIR ) && ( __filename . endsWith ( '/dist/index.js' ) || process . env . NODE_ENV === 'production' )
2929const WEB_ORIGIN = process . env . WEB_ORIGIN || ( SHOULD_SERVE_BUILT_WEB ? `http://localhost:${ PORT } ` : 'http://localhost:5173' )
30- const mockEmailMonitors = new Map < string , { running : boolean } > ( )
3130
3231app . use ( cors ( ) )
3332app . use ( express . json ( ) )
@@ -69,133 +68,6 @@ function createSessionId(): string {
6968 return id
7069}
7170
72- function sleep ( ms : number ) : Promise < void > {
73- return new Promise ( resolve => setTimeout ( resolve , ms ) )
74- }
75-
76- function buildMockReplyDraft ( email : Record < string , unknown > ) : Record < string , unknown > {
77- const from = String ( email . from ?? 'sender@example.com' )
78- const subject = String ( email . subject ?? 'Re: Email' )
79- const body = String ( email . body ?? email . preview ?? '' ) . trim ( )
80- const lines = body . split ( '\n' ) . map ( line => line . trim ( ) ) . filter ( Boolean )
81- const summaryLine = lines . find ( line => ! line . startsWith ( '-' ) && ! line . startsWith ( '*' ) ) ?? 'I reviewed your note.'
82- return {
83- replyTo : from ,
84- to : from ,
85- subject : subject . startsWith ( 'Re:' ) ? subject : `Re: ${ subject } ` ,
86- paragraphs : [
87- { id : 'mock_p1' , content : `Thanks. I reviewed this and the main point is clear: ${ summaryLine } ` } ,
88- { id : 'mock_p2' , content : 'I am aligned with the current direction. If there is an updated version or final changelog, send it over and I will review it quickly.' } ,
89- ] ,
90- intentSuggestions : [
91- { id : 'mock_intent_ack' , text : 'Acknowledge the email' } ,
92- { id : 'mock_intent_brief' , text : 'Keep the reply brief' } ,
93- { id : 'mock_intent_followup' , text : 'Ask for the latest update' } ,
94- ] ,
95- }
96- }
97-
98- function buildMockReadMoreEmails ( categories : string [ ] , existingIds : string [ ] ) : Array < Record < string , unknown > > {
99- const now = Date . now ( )
100- const requested = categories . length > 0 ? categories : [ 'Primary' , 'Updates' , 'Promotions' ]
101- const samples : Array < Record < string , unknown > > = requested . flatMap ( ( category , index ) => ( [
102- {
103- id : `mock_more_${ category . toLowerCase ( ) } _${ index } _a` ,
104- from : category === 'Updates' ? 'Google Scholar Alerts' : category === 'Promotions' ? 'HeyGen' : 'Project Ops' ,
105- to : 'hm@example.com' ,
106- subject : category === 'Updates' ? 'New papers matching your LLM alert' : category === 'Promotions' ? 'Slack integration is now live' : 'Follow-up on current workstream' ,
107- preview : category === 'Updates' ? 'Several new papers were published overnight.' : category === 'Promotions' ? 'A new product integration is available today.' : 'A short follow-up requiring attention today.' ,
108- body : category === 'Updates'
109- ? 'Several new papers matching your alert were published overnight, including safety evaluations and efficient fine-tuning work.'
110- : category === 'Promotions'
111- ? 'A new integration is now available with guided setup, templates, and launch pricing.'
112- : 'Following up on the current workstream. Please confirm whether the latest change list is final.' ,
113- unread : true ,
114- category,
115- timestamp : now - ( index + 1 ) * 60000 ,
116- } ,
117- ] ) )
118-
119- return samples . filter ( email => ! existingIds . includes ( String ( email . id ) ) )
120- }
121-
122- async function startMockEmailMonitor ( sessionId : string ) : Promise < void > {
123- if ( mockEmailMonitors . get ( sessionId ) ?. running ) return
124- mockEmailMonitors . set ( sessionId , { running : true } )
125-
126- try {
127- while ( true ) {
128- const session = getSession ( sessionId )
129- if ( ! session ) break
130- if ( session . pageStatus ?. stopMonitoring ) break
131- if ( session . status === 'completed' ) break
132- if ( session . status !== 'rewriting' ) {
133- await sleep ( 500 )
134- continue
135- }
136-
137- const payload = session . payload as Record < string , unknown >
138- const result = ( session . result ?? { } ) as Record < string , unknown >
139- const inbox = Array . isArray ( payload . inbox ) ? payload . inbox as Array < Record < string , unknown > > : [ ]
140- const draft = payload . draft as Record < string , unknown > | undefined
141-
142- if ( result . requestReplyDraft ) {
143- const emailId = String ( result . emailId ?? '' )
144- const targetEmail = inbox . find ( email => String ( email . id ) === emailId )
145- if ( ! targetEmail ) {
146- updateSessionPayload ( sessionId , payload )
147- continue
148- }
149- await sleep ( 1200 )
150- updateSessionPayload ( sessionId , {
151- ...payload ,
152- inbox : inbox . map ( email => String ( email . id ) === emailId
153- ? {
154- ...email ,
155- replyState : 'ready' ,
156- replyUnread : true ,
157- replyDraft : buildMockReplyDraft ( email ) ,
158- }
159- : email ) ,
160- draft,
161- } )
162- continue
163- }
164-
165- if ( result . readMore ) {
166- const categories = Array . isArray ( result . requestedCategories )
167- ? result . requestedCategories . filter ( ( item ) : item is string => typeof item === 'string' )
168- : [ ]
169- const existingIds = inbox . map ( email => String ( email . id ?? '' ) )
170- const extraEmails = buildMockReadMoreEmails ( categories , existingIds )
171- await sleep ( 800 )
172- updateSessionPayload ( sessionId , {
173- ...payload ,
174- inbox : [ ...inbox , ...extraEmails ] ,
175- draft,
176- } )
177- continue
178- }
179-
180- const editedDraft = result . editedDraft && typeof result . editedDraft === 'object'
181- ? result . editedDraft as Record < string , unknown >
182- : null
183- if ( editedDraft ) {
184- await sleep ( 900 )
185- updateSessionPayload ( sessionId , {
186- ...payload ,
187- draft : editedDraft ,
188- } )
189- continue
190- }
191-
192- await sleep ( 500 )
193- }
194- } finally {
195- mockEmailMonitors . delete ( sessionId )
196- }
197- }
198-
19971// Lightweight identity endpoint so clients can verify the service is AgentClick.
20072app . get ( '/api/identity' , ( _req , res ) => {
20173 res . json ( {
@@ -594,16 +466,6 @@ app.post('/api/sessions/:id/page-status', (req, res) => {
594466 res . json ( { ok : true , pageStatus } )
595467} )
596468
597- app . post ( '/api/mock/email-monitor/start' , ( req , res ) => {
598- const sessionId = typeof req . body ?. sessionId === 'string' ? req . body . sessionId : ''
599- if ( ! sessionId ) return res . status ( 400 ) . json ( { error : 'Missing sessionId' } )
600- const session = getSession ( sessionId )
601- if ( ! session ) return res . status ( 404 ) . json ( { error : 'Session not found' } )
602- if ( session . type !== 'email_review' ) return res . status ( 400 ) . json ( { error : 'Session is not an email review' } )
603- void startMockEmailMonitor ( sessionId )
604- res . json ( { ok : true , started : true , sessionId } )
605- } )
606-
607469app . post ( '/api/sessions/:id/email-send' , async ( req , res ) => {
608470 const session = getSession ( req . params . id )
609471 if ( ! session ) return res . status ( 404 ) . json ( { error : 'Session not found' } )
0 commit comments