{"version":2,"sessionId":"28c5590e-729e-495a-9c0f-1db361e94bfb","initialFileContents":[["file:///c%3A/Servers/mailchecker/index.js","eec4c5b"]],"timeline":{"checkpoints":[{"checkpointId":"2dfb9a06-22a0-4064-98bc-8bab2743dd61","epoch":0,"label":"Initial State","description":"Starting point before any edits"},{"checkpointId":"9e37dac8-9d23-4caa-b193-93969445ef42","requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","epoch":1,"label":"Request request_b127f860-9b2d-4d85-9ac6-ac10faffbec8"},{"checkpointId":"9e02c99e-a8e5-4015-a497-a368eec15629","requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","undoStopId":"b1660ca5-89fd-466e-8838-9c6d4a423a80","epoch":2,"label":"Request request_b127f860-9b2d-4d85-9ac6-ac10faffbec8 - Stop b1660ca5-89fd-466e-8838-9c6d4a423a80"},{"checkpointId":"ec8e6e1f-53aa-462d-9148-9346ff42ea07","requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","undoStopId":"2a3eb2b1-6fb4-401e-b336-c84652bedf1a","epoch":5,"label":"Request request_b127f860-9b2d-4d85-9ac6-ac10faffbec8 - Stop 2a3eb2b1-6fb4-401e-b336-c84652bedf1a"},{"checkpointId":"e75e1cf3-1c52-4824-ba17-4efc6efb4b9d","requestId":"request_2eb39787-727b-41d7-95d2-05f3ba5b9acf","epoch":7,"label":"Request request_2eb39787-727b-41d7-95d2-05f3ba5b9acf"}],"currentEpoch":8,"fileBaselines":[["file:///c%3A/Servers/mailchecker/index.js::request_b127f860-9b2d-4d85-9ac6-ac10faffbec8",{"uri":{"$mid":1,"fsPath":"c:\\Servers\\mailchecker\\index.js","_sep":1,"external":"file:///c%3A/Servers/mailchecker/index.js","path":"/C:/Servers/mailchecker/index.js","scheme":"file"},"requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","content":"const { ImapFlow } = require('imapflow');\r\nconst { simpleParser } = require('mailparser');\r\nconst OpenAI = require('openai');\r\nconst { zodResponseFormat } = require('openai/helpers/zod');\r\nconst { z: zod } = require('zod');\r\n// const fs = require('fs');\r\n\r\nconst openai = new OpenAI({\r\n    dangerouslyAllowBrowser: true,\r\n    apiKey: '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'\r\n})\r\n\r\nconst classifyEmailSchema = zod.object({\r\n    label: zod.enum([\r\n        'APPLICATION_ACK',        // receipt/thanks/“we’ll review”\r\n        'INTERVIEW_SCHEDULING',   // scheduling now: dates, Calendly, “pick a time”\r\n        'ASSESSMENT_REQUEST',     // “please complete assessment/test/form”\r\n        'REJECTION',              // “not moving forward”, “unfortunately”\r\n        'OFFER',                  // “we’re pleased to offer…”\r\n        'OTHER'\r\n    ])\r\n});\r\n\r\nconst ACCOUNTS = [\r\n    {\r\n        user: 'anthonyortega4592@gmail.com',\r\n        pass: 'hmam rmdo sdxs cfft'\r\n    },\r\n    // {\r\n    //     user: 'jlee.app712@gmail.com',\r\n    //     pass: 'pbdn rkts ykrp bfwo'\r\n    // },\r\n    // {\r\n    //     user: 'miloveselino@gmail.com',\r\n    //     pass: 'wgzy zpde dxlj byik'\r\n    // }\r\n]\r\n\r\nasync function main() {\r\n    ACCOUNTS.forEach(account => {\r\n        startAccount(account);\r\n    });\r\n}\r\n\r\nasync function startAccount(account) {\r\n    while (true) {\r\n        const client = new ImapFlow({\r\n            host: 'imap.gmail.com',\r\n            port: 993,\r\n            secure: true,\r\n            auth: {\r\n                user: account.user,\r\n                pass: account.pass\r\n            },\r\n            tls: {\r\n                rejectUnauthorized: false,\r\n            }\r\n        });\r\n\r\n        try {\r\n            await client.connect();\r\n\r\n            let lock = await client.getMailboxLock('INBOX');\r\n            try {\r\n                // ...existing code for initial fetch and classification...\r\n                const uids = await client.search({}, { uid: true });\r\n                uids.sort((a, b) => b - a);\r\n                const latestUids = uids.slice(0, 60);\r\n                const messages = [];\r\n                for await (let message of client.fetch(\r\n                    latestUids,\r\n                    {\r\n                        uid: true,\r\n                        flags: true,\r\n                        bodyStructure: true,\r\n                        envelope: true,\r\n                        internalDate: true,\r\n                        size: true,\r\n                        source: true,\r\n                        threadId: true,\r\n                        labels: true,\r\n                        headers: true\r\n                    }\r\n                )) {\r\n                    messages.push(message);\r\n                }\r\n\r\n                // Watch for new incoming emails\r\n                client.on('exists', async (mailbox) => {\r\n                    let message = await client.fetchOne(client.mailbox.exists, {\r\n                        uid: true,\r\n                        flags: true,\r\n                        bodyStructure: true,\r\n                        envelope: true,\r\n                        internalDate: true,\r\n                        size: true,\r\n                        source: true,\r\n                        threadId: true,\r\n                        labels: true,\r\n                        headers: true\r\n                    });\r\n\r\n                    if (message && message.source) {\r\n                        const parsed = await simpleParser(message.source);\r\n                        const label = await classifyMessage(parsed.subject, parsed.text);\r\n                        const logLine = `${parsed.date} | Email UID ${message.uid} | label: ${label} | From: ${parsed.from?.text} | Subject: ${parsed.subject}\\n`;\r\n                        console.log(logLine.trim());\r\n                        // fs.appendFileSync('D:\\\\05-Projects\\\\Mine\\\\mail-checker\\\\mail-checker\\\\out\\\\email_classification.log', logLine);\r\n                        await client.messageFlagsAdd([message.uid], [label], { useLabels: true, uid: true });\r\n                    }\r\n                });\r\n\r\n                for (let i = messages.length - 1; i >= 0; i--) {\r\n                    const message = messages[i];\r\n                    if (message.source) {\r\n                        const parsed = await simpleParser(message.source);\r\n                        const msgObj = {\r\n                            uid: message.uid,\r\n                            subject: parsed.subject,\r\n                            from: {\r\n                                address: parsed.from?.value?.[0]?.address || '',\r\n                                name: parsed.from?.value?.[0]?.name || ''\r\n                            },\r\n                            to: {\r\n                                address: parsed.to?.value?.[0]?.address || '',\r\n                                name: parsed.to?.value?.[0]?.name || ''\r\n                            },\r\n                            date: parsed.date,\r\n                            text: parsed.text?.trim() || ''\r\n                        };\r\n\r\n                        const label = await classifyMessage(parsed.subject, parsed.text);\r\n                        const logLine = `${parsed.date} | Email UID ${message.uid} | label: ${label} | From: ${parsed.from?.text} | Subject: ${parsed.subject}\\n`;\r\n                        console.log(logLine.trim());\r\n                        // fs.appendFileSync('D:\\\\05-Projects\\\\Mine\\\\mail-checker\\\\mail-checker\\\\out\\\\email_classification.log', logLine);\r\n\r\n                        await client.messageFlagsAdd([message.uid], [label], { useLabels: true, uid: true });\r\n                    }\r\n                }\r\n\r\n                // Keep process alive to watch for new mail\r\n                console.log('Watching for new incoming emails...');\r\n                await new Promise(() => {}); // Never resolves, keeps process running\r\n            } finally {\r\n                lock.release();\r\n            }\r\n        } catch (err) {\r\n            console.error('IMAP error, will retry:', err);\r\n            if (client && client.connected) {\r\n                try { await client.logout(); } catch (e) {}\r\n            }\r\n            // Wait 10 seconds before retrying\r\n            await new Promise(res => setTimeout(res, 10000));\r\n        }\r\n    }\r\n}\r\n\r\n\r\nasync function classifyMessage(subject, text) {\r\n    let completions;\r\n    let label = 'other';\r\n    try {\r\n        completions = await openai.chat.completions.create({\r\n            model: 'gpt-4.1-nano',\r\n            messages: [\r\n                { role: 'system', content: `You are a strict email classifier for job-app emails. Return JSON { \"label\": <ONE_ENUM> }.\r\n                    Decision rules (apply exactly, do not infer future steps):\r\n                    - APPLICATION_ACK: receipt/thanks (“thank you for your application/interest”, “we will review”, “we may reach out”).\r\n                    - INTERVIEW_SCHEDULING: there is an explicit scheduling action NOW (dates, availability request, calendar link, “book a time”, “please schedule”).\r\n                    - ASSESSMENT_REQUEST: asks to complete assessment/test/questionnaire/skills survey.\r\n                    - REJECTION: “not moving forward”, “unfortunately”, “declined”.\r\n                    - OFFER: a job offer (“we’re pleased to offer”, “offer letter attached”).\r\n                    - OTHER: Anything not advancing the hiring process (job alerts/newsletters/marketing; OTP, password reset, sign-in/activation).\r\n                    If multiple apply, pick the most specific explicit action present *in this email*. Do not predict future steps.` },\r\n\r\n                { role: 'user', content: `Classify this email: ${subject}\\n\\n${text}` }\r\n            ],\r\n            temperature: 0,\r\n            response_format: zodResponseFormat(classifyEmailSchema, 'email_category'),\r\n        });\r\n\r\n        // If function call, extract label from function_call arguments\r\n        const choice = completions.choices[0];\r\n        if (choice.message.content) {\r\n            // fallback if content is present\r\n            label = JSON.parse(choice.message.content.trim()).label;\r\n            console.log('=============================')\r\n            console.log(subject);\r\n            console.log(label);\r\n            // if (context === 'job_application_success/appreciate_mail') label = 'application';\r\n            // if (context === '(scheduling/inviting) to (interview/next_step)') label = 'interview';\r\n            // if (context === 'requesting (assessment/questionnaire)') label = 'assessment';\r\n            // if (context === 'rejection/not_considering/not_moving_forward application') label = 'rejection';\r\n            // if (context === '(job/position) offer') label = 'offer';\r\n        }\r\n    } catch (error) {\r\n        console.error('Error classifying message:', error);\r\n        return \"{}\";\r\n    }\r\n\r\n    console.log('Token usage:', completions.usage);\r\n\r\n    return label.toUpperCase();\r\n}\r\n\r\nmain().catch(err => {\r\n    console.error('Error:', err);\r\n    setTimeout(main, 10000);\r\n});\r\n\r\nprocess.on('uncaughtException', (err) => {\r\n    console.error('Uncaught Exception:', err);\r\n    // Prevent exit, let retry logic in startAccount handle reconnect\r\n    setTimeout(main, 10000);\r\n});\r\nprocess.on('unhandledRejection', (reason, promise) => {\r\n    console.error('Unhandled Rejection:', reason);\r\n    // Prevent exit, let retry logic in startAccount handle reconnect\r\n    setTimeout(main, 10000);\r\n});","epoch":3,"telemetryInfo":{}}]],"operations":[{"type":"textEdit","uri":{"$mid":1,"fsPath":"c:\\Servers\\mailchecker\\index.js","_sep":1,"external":"file:///c%3A/Servers/mailchecker/index.js","path":"/C:/Servers/mailchecker/index.js","scheme":"file"},"requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","epoch":4,"edits":[{"text":"const ACCOUNTS = [\r\n    {\r\n        user: 'anthonyortega4592@gmail.com',\r\n        pass: 'hmam rmdo sdxs cfft',\r\n        host: 'imap.gmail.com'\r\n    },\r\n    // {\r\n    //     user: 'jlee.app712@gmail.com',\r\n    //     pass: 'pbdn rkts ykrp bfwo',\r\n    //     host: 'imap.gmail.com'\r\n    // },\r\n    // {\r\n    //     user: 'miloveselino@gmail.com',\r\n    //     pass: 'wgzy zpde dxlj byik',\r\n    //     host: 'imap.gmail.com'\r\n    // },\r\n    {\r\n        user: 'your-email@outlook.com',\r\n        pass: 'your-app-password',\r\n        host: 'outlook.office365.com'\r\n    }\r\n]","range":{"startLineNumber":24,"startColumn":1,"endLineNumber":37,"endColumn":2}}]},{"type":"textEdit","uri":{"$mid":1,"fsPath":"c:\\Servers\\mailchecker\\index.js","_sep":1,"external":"file:///c%3A/Servers/mailchecker/index.js","path":"/C:/Servers/mailchecker/index.js","scheme":"file"},"requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","epoch":6,"edits":[{"text":"async function startAccount(account) {\r\n    while (true) {\r\n        const client = new ImapFlow({\r\n            host: account.host,\r\n            port: 993,\r\n            secure: true,\r\n            auth: {\r\n                user: account.user,\r\n                pass: account.pass\r\n            },\r\n            tls: {\r\n                rejectUnauthorized: false,\r\n            }\r\n        });","range":{"startLineNumber":53,"startColumn":1,"endLineNumber":66,"endColumn":12}}]}],"epochCounter":8},"recentSnapshot":{"entries":[{"resource":"file:///c%3A/Servers/mailchecker/index.js","languageId":"javascript","originalHash":"d2fdc3c","currentHash":"d2fdc3c","state":1,"snapshotUri":"chat-editing-snapshot-text-model:/c%3A/Servers/mailchecker/index.js?%7B%22sessionId%22%3A%2228c5590e-729e-495a-9c0f-1db361e94bfb%22%2C%22requestId%22%3A%22%22%2C%22undoStop%22%3A%22%22%7D","telemetryInfo":{"requestId":"request_b127f860-9b2d-4d85-9ac6-ac10faffbec8","agentId":"github.copilot.editsAgent","modelId":"copilot/claude-opus-4.5","modeId":"agent"}}]}}