ilml-plugin-linkedin 1.11.7 → 1.12.0

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/syncAll.mjs CHANGED
@@ -1,7 +1,7 @@
1
- var Oo=Object.defineProperty;var We=(e,t)=>{for(var o in t)Oo(e,o,{get:t[o],enumerable:!0})};var Ye={jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11},Io={sunday:0,monday:1,tuesday:2,wednesday:3,thursday:4,friday:5,saturday:6};function ve(e){let t=e.match(/(\d{1,2}):(\d{2})\s*(AM|PM)/i);if(!t)return null;let o=parseInt(t[1],10),n=parseInt(t[2],10),s=t[3].toUpperCase()==="PM";return s&&o!==12&&(o+=12),!s&&o===12&&(o=0),{hours:o,minutes:n}}function Ge(e,t){if(!e)return null;let o=e.trim();if(!o)return null;if(t=t||new Date,/^just\s*now$/i.test(o))return t.toISOString();if(/^today\b/i.test(o)||/^\d{1,2}:\d{2}\s*(AM|PM)$/i.test(o)){let a=ve(o),c=new Date(t);return a?c.setHours(a.hours,a.minutes,0,0):c.setHours(0,0,0,0),c.toISOString()}let n=o.match(/^(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s*(.*)/i);if(n){let a=Io[n[1].toLowerCase()],c=ve(n[2]||""),l=new Date(t),d=l.getDay()-a;return d<=0&&(d+=7),l.setDate(l.getDate()-d),c?l.setHours(c.hours,c.minutes,0,0):l.setHours(0,0,0,0),l.toISOString()}let s=o.match(/^([A-Z][a-z]+)\s+(\d{1,2}),?\s+(\d{4})\s*(.*)/i);if(s){let a=Ye[s[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let c=parseInt(s[2],10),l=parseInt(s[3],10),f=ve(s[4]||"");return new Date(l,a,c,f?.hours||0,f?.minutes||0,0,0).toISOString()}let r=o.match(/^([A-Z][a-z]+)\s+(\d{1,2}),\s*(.*)/i);if(r){let a=Ye[r[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let c=parseInt(r[2],10),l=ve(r[3]||""),f=t.getFullYear(),d=new Date(f,a,c,l?.hours||0,l?.minutes||0,0,0);return d>t&&d.setFullYear(f-1),d.toISOString()}let i=o.match(/^([A-Z][a-z]+)\s+(\d{1,2})\s*(.*)/i);if(i){let a=Ye[i[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let c=parseInt(i[2],10),l=ve(i[3]||""),f=t.getFullYear(),d=new Date(f,a,c,l?.hours||0,l?.minutes||0,0,0);return d>t&&d.setFullYear(f-1),d.toISOString()}return null}async function _(e){let t=Math.floor(Math.random()*2001),o=e+t;return new Promise(n=>setTimeout(n,o))}async function Rt(e){let t=e.url();if(t.includes("/messaging"))return!1;if(t.includes("/login")||t.includes("/authwall"))throw new Error("Session expired \u2014 redirected to login");console.log(` \u26A0 Off-track: ${t.slice(0,80)}`),console.log(" \u21BB Navigating back to /messaging/..."),await e.goto("https://www.linkedin.com/messaging/",{waitUntil:"domcontentloaded",timeout:6e4}),await _(4e3);let n=e.url();if(n.includes("/login")||n.includes("/authwall"))throw new Error("Session expired during recovery");return console.log(" \u2713 Back on messaging"),!0}function Dt(e){return e&&e.replace(/[®™]/g,"").replace(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{27BF}]|[\u{FE00}-\u{FE0F}]|[\u{1F000}-\u{1FAFF}]|[\u{200D}]|[\u{20E3}]|[\u{E0020}-\u{E007F}]/gu,"").replace(/[\u{2B50}\u{2728}\u{2764}\u{270C}\u{270B}\u{1F3FB}-\u{1F3FF}]/gu,"").replace(/\s*\([^)]*[\u4E00-\u9FFF\u3400-\u4DBF][^)]*\)/g,"").replace(/\s{2,}/g," ").trim()}function Ot(e){return e&&e.replace(/(?:,\s*(?:Ph\.?D\.?|P\.?E\.?|P\.?Eng\.?|MBA|M\.?Sc\.?|B\.?Sc\.?|M\.?Ed\.?(?:Tech\.?)?|B\.?Tech\.?|B\.?Comm\.?|B\.?Eng\.?|CPA|CFA|CFP|PMP|CISSP|CISM|CSM|CSP|ITIL|FCA|CA|CMA|PE|SE|RA|AIA|LEED\s*AP|SHRM-(?:CP|SCP)|SPHR|PHR|RN|MD|J\.?D\.?|Esq\.?|DDS|OD|DO|PA-C|RD|LPC|LCSW|CDP|ACC|PCC|MCC|ICD\.?D|RCC|CPHR|CHRP|CCP|CIM|CLU|DFSA|CTS|HRMD|CPIR|CPI|MCIPD)\.?\s*)+$/gi,"").replace(/\s+(?:MBA|M\.?Ed\.?(?:Tech\.?)?|Ph\.?D\.?|B\.?Tech\.?|CPHR|CTS)\s*$/gi,"").replace(/,\s*[A-Z][A-Z.\s]*$/g,"").replace(/\s{2,}/g," ").trim()}import{getPluginConfig as xo}from"@ilivemylife/graph-sdk";var jo=await xo();for(let[e,t]of Object.entries(jo))process.env[e]===void 0&&(process.env[e]=t);var P=process.env.LINKEDIN_NAME,j=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),$e=Object.freeze(new Set([j.DRAFT,j.CONFIRMED,j.NEEDS_REVIEW])),fe=Object.freeze(new Set([j.DRAFT,j.CONFIRMED,j.REJECTED,j.NEEDS_REVIEW]));import"dotenv/config";import*as O from"fs";import*as x from"path";import{fileURLToPath as No}from"url";import{execSync as ze}from"child_process";var Mo=No(import.meta.url),Po=x.dirname(x.dirname(Mo)),U=process.env.DATA_DIR?x.resolve(process.env.DATA_DIR,"collected-profiles"):x.join(Po,"collected-profiles"),Ke=x.join(U,"people.json"),ir=x.join(U,"jobs.json"),Fo=x.join(U,"quota.json"),je=x.join(U,"conversations.json"),Pt=x.join(U,"sync-state.json"),It=x.join(U,"application-questions.json"),Qe=x.join(U,"profile-history"),xt=20,jt=100,de=null,Lo=null,K=null,ne=null,pe=null,oe=null;function Ft(){de=null,Lo=null,K=null,ne=null,pe=null,oe=null}function Q(){O.existsSync(U)||O.mkdirSync(U,{recursive:!0})}function ke(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";O.writeFileSync(n,o);for(let s=0;s<3;s++)try{O.renameSync(n,e);return}catch(r){if(s<2&&(r.code==="EPERM"||r.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw r}}function Ce(e,t){if(!O.existsSync(e))return null;try{let o=JSON.parse(O.readFileSync(e,"utf-8"));try{O.copyFileSync(e,e+".backup")}catch{}return o}catch(o){console.error(`[!] ${t} is corrupted: ${o.message}`),console.error(` File: ${x.resolve(e)}`);let n=e+".backup";if(O.existsSync(n))try{let s=JSON.parse(O.readFileSync(n,"utf-8"));console.error(` Restored from ${n}`);try{O.copyFileSync(n,e)}catch{}return s}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{O.copyFileSync(e,e+".corrupted")}catch{}return null}}function Lt(){return new Date().toISOString().split("T")[0]}var Uo=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections"],Bo=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"];function Xe(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function qo(){O.existsSync(Qe)||O.mkdirSync(Qe,{recursive:!0})}function Ut(e){let t=Xe(e);return t?x.join(Qe,`${t}.json`):null}function Jo(e){let t=Ut(e);return t?Ce(t,`profile-history/${Xe(e)}.json`)||[]:[]}function Ho(e,t){let o=Ut(e);if(!o)return;qo();let n=Jo(e);n.unshift(t);try{ke(o,n)}catch(s){console.error(`[!] Failed to append profile-history for ${Xe(e)}: ${s.message}`)}}function Nt(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Mt(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Vo(e,t){if(!e)return[];let o=[];for(let n of Bo){let s=e[n],r=t[n];Nt(s)||Nt(r)||Mt(s)!==Mt(r)&&o.push(n)}return o}function Wo(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),o={};for(let[n,s]of Object.entries(e))t.has(n)||(o[n]=s);return o}function W(){return de||(Q(),de=Ce(Ke,"people.json")||{},de)}function Ne(e){Q(),de=e;try{ke(Ke,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${x.resolve(Ke)}`)}}function Te(){return ne||(Q(),ne=Ce(je,"conversations.json")||{},Yo(ne),ne)}function Yo(e){let t=0;for(let o of Object.values(e)){if(!(o.draftStatus!==void 0||o.draftPreparedAt!==void 0))continue;let s=(o.messages||[]).find(r=>r.status==="draft");s&&o.draftStatus&&o.draftStatus!=="pending"&&(s.status=o.draftStatus),delete o.draftStatus,delete o.draftPreparedAt,t++}if(t>0){console.log(` [migration] Moved draft state from conv to msg.status for ${t} conversations`);try{ke(je,e)}catch{}}}function X(e){Q(),ne=e;try{ke(je,e)}catch(t){console.error(`[!] Failed to save conversations.json: ${t.message}`),console.error(` Path: ${x.resolve(je)}`)}}function Bt(e,t={}){if(!e)return null;let o=W(),n=Lt(),s=new Date().toISOString(),r=o[e];if(r){let i=Vo(r,t);i.length>0&&(Ho(e,{capturedAt:s,previousLastUpdated:r.lastUpdated||null,changedFields:i,snapshot:Wo(r)}),r.lastSnapshotAt=s),r.seenCount=(r.seenCount||1)+1,r.lastSeen=n,r.lastUpdated=s,t.source&&!r.sources?.includes(t.source)&&(r.sources=r.sources||[],r.sources.push(t.source));for(let a of Uo)t[a]!=null&&(r[a]=t[a]);Array.isArray(t.availableSections)&&(r.lastFullVisitAt=s)}else o[e]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,firstSeen:n,lastSeen:n,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:s,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?s:null};return Ne(o),o[e]}function Go(){return K||(Q(),K=Ce(Fo,"quota.json"),(!K||!K.connections)&&(K={connections:[]}),K)}function zo(){let e=Go(),t=new Date;t.setDate(t.getDate()-7);let o=t.toISOString().split("T")[0];return e.connections.filter(n=>n.date>=o)}function qt(){let e=zo(),t=Lt(),o=e.filter(s=>s.date===t).length,n=e.length;return{daily:{sent:o,max:xt,remaining:xt-o},weekly:{sent:n,max:jt,remaining:jt-n}}}function Ze(){return pe||(Q(),pe=Ce(Pt,"sync-state.json")||{},pe)}function Jt(e){Q(),pe=e;try{ke(Pt,e)}catch(t){console.error(`[!] Failed to save sync-state.json: ${t.message}`)}}function Ko(){if(oe)return oe;Q();try{O.existsSync(It)&&(oe=JSON.parse(O.readFileSync(It,"utf-8")))}catch{}return oe||(oe={}),oe}function Qo(e){return Array.isArray(e.applications)}function Xo(){let e=Ko();if(Qo(e))return e.applications;let t=[];for(let o of Object.values(e))o.applications&&t.push(...o.applications);return t}function Ht(){let e=Xo(),t=new Map;for(let r of e)for(let i of r.questions||[]){let a=i.question.toLowerCase().trim();if(!a)continue;t.has(a)||t.set(a,{question:i.question,count:0,answers:new Map});let c=t.get(a);c.count++;let l=(i.answer||"").trim();c.answers.set(l,(c.answers.get(l)||0)+1)}let o=[...t.values()].sort((r,i)=>i.count-r.count),n=o.slice(0,15).map(r=>({question:r.question,count:r.count,topAnswer:[...r.answers.entries()].sort((i,a)=>a[1]-i[1])[0]?.[0]||""})),s=o.filter(r=>r.answers.size>1&&r.count>=3).map(r=>({question:r.question,count:r.count,answers:[...r.answers.entries()].sort((i,a)=>a[1]-i[1]).map(([i,a])=>`${i} (${a}x)`)}));return{totalApplications:e.length,uniqueQuestions:t.size,topQuestions:n,inconsistent:s}}function et(e){if(O.existsSync(x.join(U,".git")))try{let t={cwd:U,stdio:"pipe",timeout:1e4};ze("git add conversations.json people.json jobs.json quota.json sync-state.json run-log.json application-questions.json",t);try{ze("git diff --cached --quiet",t);return}catch{}let o=(e||`sync ${new Date().toISOString().slice(0,16)}`).replace(/"/g,'\\"');ze(`git commit -m "${o}"`,t)}catch(t){process.env.VERBOSE&&console.log(` [git] snapshot skipped: ${t.message?.slice(0,80)}`)}}import"dotenv/config";import*as re from"fs";import*as F from"path";import{fileURLToPath as Zo}from"url";var en=Zo(import.meta.url),tn=F.dirname(F.dirname(en)),Re=process.env.DATA_DIR?F.resolve(process.env.DATA_DIR,"market-research"):F.join(tn,"market-research"),on=F.join(Re,"scouted-jobs.json"),nn=F.join(Re,"discovered-people.json"),sn=F.join(Re,"visit-log.json"),ur=F.join(Re,"companies.json"),rn=F.join(Re,"job-decisions.json");function Me(e){try{if(re.existsSync(e))return JSON.parse(re.readFileSync(e,"utf-8"))}catch{}return null}function Vt(){Ee=null,_e=null,Ae=null,cn=null,se=null}var Ee=null;function tt(){return Ee||(Ee=Me(on)||{},Ee)}var _e=null;function Wt(){return _e||(_e=Me(rn)||{},_e)}var Ae=null;function an(){return Ae||(Ae=Me(nn)||{},Ae)}var cn=null;var se=null;function ln(){return se||(se=Me(sn)||{visits:[]},Array.isArray(se.visits)||(se.visits=[]),se)}function Yt(){let e=tt(),t=an(),o=Object.values(e),n=Object.values(t),s={};for(let u of o)u.company&&(s[u.company]=(s[u.company]||0)+1);let r=Object.entries(s).sort((u,m)=>m[1]-u[1]).slice(0,5).map(([u,m])=>`${u} (${m})`),i={};for(let u of o)for(let m of u.techStack||[])i[m]=(i[m]||0)+1;let a=Object.entries(i).sort((u,m)=>m[1]-u[1]).slice(0,8).map(([u,m])=>`${u} (${m})`),c=ln(),l=new Date().toISOString().slice(0,10),f=c.visits.filter(u=>u.date.startsWith(l)).length,d=new Set(c.visits.map(u=>u.profileUrl)).size;return{totalJobs:o.length,totalRecruiters:n.length,topCompanies:r,topTech:a,totalVisited:d,todayVisited:f,lastScoutDate:o.length>0?o.sort((u,m)=>(m.scoutedAt||"").localeCompare(u.scoutedAt||""))[0]?.scoutedAt:null}}var un=new Set(["java","c#",".net","scala","python","typescript","javascript","react","node.js","aws","azure","docker","kubernetes","microservices","graphql","rest","sql","postgresql","mongodb","kafka","redis","ci/cd","terraform","spring"]),fn=new Set(["iot","machine learning","ai","data engineering","spark","go","rust","kotlin","next.js","devops","sre"]),Gt=["vancouver","british columbia"],dn=["canada","montreal","quebec","alberta","calgary","ottawa"],pn=["toronto","ontario"],gn=["india","pakistan","nigeria","philippines"];function mn(e,t={}){let o=0,n=(e.techStack||[]).map(f=>f.toLowerCase()),s=0,r=0;for(let f of n)un.has(f)&&s++,fn.has(f)&&r++;if(o+=Math.min(s*6,24),o+=Math.min(r*3,6),e.salary){let f=hn(e.salary);f&&(f>=15e4?o+=20:f>=12e4?o+=15:f>=1e5?o+=10:f>=8e4?o+=5:f>=100&&f<1e3?o+=15:f>=70&&f<1e3&&(o+=10))}let i=(e.location||"").toLowerCase(),a=/remote/i.test(i)||e.workplaceType==="remote";gn.some(f=>i.includes(f))?o-=30:a&&/united states|usa|\bus\b/i.test(i)?o+=25:a&&Gt.some(f=>i.includes(f))?o+=22:a?o+=20:Gt.some(f=>i.includes(f))?o+=18:dn.some(f=>i.includes(f))?o+=10:pn.some(f=>i.includes(f))&&(o+=5),e.isEasyApply&&(o+=5);let c=(e.seniority||"").toLowerCase();c.includes("senior")||c.includes("lead")||c.includes("staff")?o+=10:c.includes("mid")?o+=5:(c.includes("entry")||c.includes("intern"))&&(o-=10),e.recruiterUrl&&(t.conversationRecruiters?.has(e.recruiterUrl)?o+=20:t.connectedRecruiters?.has(e.recruiterUrl)?o+=15:o+=3);let l=new Set(e.jobTags||[]);return l.has("managerial")?o+=8:l.has("senior-ic")&&(o+=5),l.has("junior")&&(o-=15),l.has("consultant")&&(o-=3),Math.max(0,Math.min(100,o))}function zt(e=10,t={}){let{easyApplyOnly:o=!0}=t,n=tt(),s=W(),r=new Set,i=new Set;for(let[d,u]of Object.entries(s))u.connectionStatus==="connected"&&r.add(d);let a={connectedRecruiters:r,conversationRecruiters:i},c=Wt(),l=new Set(["applied","skipped","expired","archived"]);return Object.entries(n).filter(([d,u])=>{if(typeof u!="object"||o&&!u.isEasyApply||u.applied)return!1;let m=c[d];return!(m&&l.has(m.status))}).map(([d,u])=>({jobId:d,score:mn(u,a),job:u})).sort((d,u)=>{if(u.score!==d.score)return u.score-d.score;let m=d.job.scoutedAt||d.job.postedTime||"";return(u.job.scoutedAt||u.job.postedTime||"").localeCompare(m)}).slice(0,e)}function hn(e){if(!e)return null;let t=e.match(/[\$£€CAD\s]*([\d,]+(?:\.\d+)?)\s*[kK]?/g);if(!t||t.length===0)return null;let o=t.map(n=>{let s=parseFloat(n.replace(/[^\d.]/g,""));return n.toLowerCase().includes("k")&&(s*=1e3),s}).filter(n=>n>0);return o.length>=2?(o[0]+o[1])/2:o.length===1?o[0]:null}import bn from"puppeteer";import{addExtra as vn}from"puppeteer-extra";import $n from"puppeteer-extra-plugin-stealth";import Kt from"fs";import yn from"path";var Sn="cookies.json";function wn(){let e=process.env.ILML_SCOPE_DIR;return e?yn.join(e,"plugins-state","linkedin","cookies.json"):Sn}function Pe(){let e=wn();if(!Kt.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=Kt.readFileSync(e,"utf-8")}catch(n){throw new Error(`Failed to read cookies at ${e}: ${n.message}. Run: ilml linkedin login`)}let o;try{o=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(o)||o.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return o}var Zt=vn(bn);Zt.use($n());async function eo(){let e=await Zt.launch({headless:!1,defaultViewport:null,protocolTimeout:3e5}),t=async()=>{console.log(`
1
+ var Oo=Object.defineProperty;var We=(e,t)=>{for(var o in t)Oo(e,o,{get:t[o],enumerable:!0})};var Ye={jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11},Io={sunday:0,monday:1,tuesday:2,wednesday:3,thursday:4,friday:5,saturday:6};function ve(e){let t=e.match(/(\d{1,2}):(\d{2})\s*(AM|PM)/i);if(!t)return null;let o=parseInt(t[1],10),n=parseInt(t[2],10),s=t[3].toUpperCase()==="PM";return s&&o!==12&&(o+=12),!s&&o===12&&(o=0),{hours:o,minutes:n}}function Ge(e,t){if(!e)return null;let o=e.trim();if(!o)return null;if(t=t||new Date,/^just\s*now$/i.test(o))return t.toISOString();if(/^today\b/i.test(o)||/^\d{1,2}:\d{2}\s*(AM|PM)$/i.test(o)){let a=ve(o),c=new Date(t);return a?c.setHours(a.hours,a.minutes,0,0):c.setHours(0,0,0,0),c.toISOString()}let n=o.match(/^(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s*(.*)/i);if(n){let a=Io[n[1].toLowerCase()],c=ve(n[2]||""),l=new Date(t),d=l.getDay()-a;return d<=0&&(d+=7),l.setDate(l.getDate()-d),c?l.setHours(c.hours,c.minutes,0,0):l.setHours(0,0,0,0),l.toISOString()}let s=o.match(/^([A-Z][a-z]+)\s+(\d{1,2}),?\s+(\d{4})\s*(.*)/i);if(s){let a=Ye[s[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let c=parseInt(s[2],10),l=parseInt(s[3],10),f=ve(s[4]||"");return new Date(l,a,c,f?.hours||0,f?.minutes||0,0,0).toISOString()}let r=o.match(/^([A-Z][a-z]+)\s+(\d{1,2}),\s*(.*)/i);if(r){let a=Ye[r[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let c=parseInt(r[2],10),l=ve(r[3]||""),f=t.getFullYear(),d=new Date(f,a,c,l?.hours||0,l?.minutes||0,0,0);return d>t&&d.setFullYear(f-1),d.toISOString()}let i=o.match(/^([A-Z][a-z]+)\s+(\d{1,2})\s*(.*)/i);if(i){let a=Ye[i[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let c=parseInt(i[2],10),l=ve(i[3]||""),f=t.getFullYear(),d=new Date(f,a,c,l?.hours||0,l?.minutes||0,0,0);return d>t&&d.setFullYear(f-1),d.toISOString()}return null}async function A(e){let t=Math.floor(Math.random()*2001),o=e+t;return new Promise(n=>setTimeout(n,o))}async function Rt(e){let t=e.url();if(t.includes("/messaging"))return!1;if(t.includes("/login")||t.includes("/authwall"))throw new Error("Session expired \u2014 redirected to login");console.log(` \u26A0 Off-track: ${t.slice(0,80)}`),console.log(" \u21BB Navigating back to /messaging/..."),await e.goto("https://www.linkedin.com/messaging/",{waitUntil:"domcontentloaded",timeout:6e4}),await A(4e3);let n=e.url();if(n.includes("/login")||n.includes("/authwall"))throw new Error("Session expired during recovery");return console.log(" \u2713 Back on messaging"),!0}function Dt(e){return e&&e.replace(/[®™]/g,"").replace(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{27BF}]|[\u{FE00}-\u{FE0F}]|[\u{1F000}-\u{1FAFF}]|[\u{200D}]|[\u{20E3}]|[\u{E0020}-\u{E007F}]/gu,"").replace(/[\u{2B50}\u{2728}\u{2764}\u{270C}\u{270B}\u{1F3FB}-\u{1F3FF}]/gu,"").replace(/\s*\([^)]*[\u4E00-\u9FFF\u3400-\u4DBF][^)]*\)/g,"").replace(/\s{2,}/g," ").trim()}function Ot(e){return e&&e.replace(/(?:,\s*(?:Ph\.?D\.?|P\.?E\.?|P\.?Eng\.?|MBA|M\.?Sc\.?|B\.?Sc\.?|M\.?Ed\.?(?:Tech\.?)?|B\.?Tech\.?|B\.?Comm\.?|B\.?Eng\.?|CPA|CFA|CFP|PMP|CISSP|CISM|CSM|CSP|ITIL|FCA|CA|CMA|PE|SE|RA|AIA|LEED\s*AP|SHRM-(?:CP|SCP)|SPHR|PHR|RN|MD|J\.?D\.?|Esq\.?|DDS|OD|DO|PA-C|RD|LPC|LCSW|CDP|ACC|PCC|MCC|ICD\.?D|RCC|CPHR|CHRP|CCP|CIM|CLU|DFSA|CTS|HRMD|CPIR|CPI|MCIPD)\.?\s*)+$/gi,"").replace(/\s+(?:MBA|M\.?Ed\.?(?:Tech\.?)?|Ph\.?D\.?|B\.?Tech\.?|CPHR|CTS)\s*$/gi,"").replace(/,\s*[A-Z][A-Z.\s]*$/g,"").replace(/\s{2,}/g," ").trim()}import{getPluginConfig as xo}from"@ilivemylife/graph-sdk";var jo=await xo();for(let[e,t]of Object.entries(jo))process.env[e]===void 0&&(process.env[e]=t);var P=process.env.LINKEDIN_NAME,j=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),$e=Object.freeze(new Set([j.DRAFT,j.CONFIRMED,j.NEEDS_REVIEW])),fe=Object.freeze(new Set([j.DRAFT,j.CONFIRMED,j.REJECTED,j.NEEDS_REVIEW]));import"dotenv/config";import*as O from"fs";import*as x from"path";import{fileURLToPath as No}from"url";import{execSync as ze}from"child_process";var Mo=No(import.meta.url),Po=x.dirname(x.dirname(Mo)),U=process.env.DATA_DIR?x.resolve(process.env.DATA_DIR,"collected-profiles"):x.join(Po,"collected-profiles"),Ke=x.join(U,"people.json"),ir=x.join(U,"jobs.json"),Fo=x.join(U,"quota.json"),je=x.join(U,"conversations.json"),Pt=x.join(U,"sync-state.json"),It=x.join(U,"application-questions.json"),Qe=x.join(U,"profile-history"),xt=20,jt=100,de=null,Lo=null,K=null,ne=null,pe=null,oe=null;function Ft(){de=null,Lo=null,K=null,ne=null,pe=null,oe=null}function Q(){O.existsSync(U)||O.mkdirSync(U,{recursive:!0})}function ke(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";O.writeFileSync(n,o);for(let s=0;s<3;s++)try{O.renameSync(n,e);return}catch(r){if(s<2&&(r.code==="EPERM"||r.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw r}}function Ce(e,t){if(!O.existsSync(e))return null;try{let o=JSON.parse(O.readFileSync(e,"utf-8"));try{O.copyFileSync(e,e+".backup")}catch{}return o}catch(o){console.error(`[!] ${t} is corrupted: ${o.message}`),console.error(` File: ${x.resolve(e)}`);let n=e+".backup";if(O.existsSync(n))try{let s=JSON.parse(O.readFileSync(n,"utf-8"));console.error(` Restored from ${n}`);try{O.copyFileSync(n,e)}catch{}return s}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{O.copyFileSync(e,e+".corrupted")}catch{}return null}}function Lt(){return new Date().toISOString().split("T")[0]}var Uo=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt"],Bo=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"];function Xe(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function qo(){O.existsSync(Qe)||O.mkdirSync(Qe,{recursive:!0})}function Ut(e){let t=Xe(e);return t?x.join(Qe,`${t}.json`):null}function Jo(e){let t=Ut(e);return t?Ce(t,`profile-history/${Xe(e)}.json`)||[]:[]}function Ho(e,t){let o=Ut(e);if(!o)return;qo();let n=Jo(e);n.unshift(t);try{ke(o,n)}catch(s){console.error(`[!] Failed to append profile-history for ${Xe(e)}: ${s.message}`)}}function Nt(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Mt(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Vo(e,t){if(!e)return[];let o=[];for(let n of Bo){let s=e[n],r=t[n];Nt(s)||Nt(r)||Mt(s)!==Mt(r)&&o.push(n)}return o}function Wo(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),o={};for(let[n,s]of Object.entries(e))t.has(n)||(o[n]=s);return o}function W(){return de||(Q(),de=Ce(Ke,"people.json")||{},de)}function Ne(e){Q(),de=e;try{ke(Ke,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${x.resolve(Ke)}`)}}function Te(){return ne||(Q(),ne=Ce(je,"conversations.json")||{},Yo(ne),ne)}function Yo(e){let t=0;for(let o of Object.values(e)){if(!(o.draftStatus!==void 0||o.draftPreparedAt!==void 0))continue;let s=(o.messages||[]).find(r=>r.status==="draft");s&&o.draftStatus&&o.draftStatus!=="pending"&&(s.status=o.draftStatus),delete o.draftStatus,delete o.draftPreparedAt,t++}if(t>0){console.log(` [migration] Moved draft state from conv to msg.status for ${t} conversations`);try{ke(je,e)}catch{}}}function X(e){Q(),ne=e;try{ke(je,e)}catch(t){console.error(`[!] Failed to save conversations.json: ${t.message}`),console.error(` Path: ${x.resolve(je)}`)}}function Bt(e,t={}){if(!e)return null;let o=W(),n=Lt(),s=new Date().toISOString(),r=o[e];if(r){let i=Vo(r,t);i.length>0&&(Ho(e,{capturedAt:s,previousLastUpdated:r.lastUpdated||null,changedFields:i,snapshot:Wo(r)}),r.lastSnapshotAt=s),r.seenCount=(r.seenCount||1)+1,r.lastSeen=n,r.lastUpdated=s,t.source&&!r.sources?.includes(t.source)&&(r.sources=r.sources||[],r.sources.push(t.source));for(let a of Uo)if(t[a]!=null){if(Array.isArray(t[a])&&t[a].length===0&&Array.isArray(r[a])&&r[a].length>0)continue;r[a]=t[a]}Array.isArray(t.availableSections)&&(r.lastFullVisitAt=s)}else o[e]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,firstSeen:n,lastSeen:n,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:s,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?s:null};return Ne(o),o[e]}function Go(){return K||(Q(),K=Ce(Fo,"quota.json"),(!K||!K.connections)&&(K={connections:[]}),K)}function zo(){let e=Go(),t=new Date;t.setDate(t.getDate()-7);let o=t.toISOString().split("T")[0];return e.connections.filter(n=>n.date>=o)}function qt(){let e=zo(),t=Lt(),o=e.filter(s=>s.date===t).length,n=e.length;return{daily:{sent:o,max:xt,remaining:xt-o},weekly:{sent:n,max:jt,remaining:jt-n}}}function Ze(){return pe||(Q(),pe=Ce(Pt,"sync-state.json")||{},pe)}function Jt(e){Q(),pe=e;try{ke(Pt,e)}catch(t){console.error(`[!] Failed to save sync-state.json: ${t.message}`)}}function Ko(){if(oe)return oe;Q();try{O.existsSync(It)&&(oe=JSON.parse(O.readFileSync(It,"utf-8")))}catch{}return oe||(oe={}),oe}function Qo(e){return Array.isArray(e.applications)}function Xo(){let e=Ko();if(Qo(e))return e.applications;let t=[];for(let o of Object.values(e))o.applications&&t.push(...o.applications);return t}function Ht(){let e=Xo(),t=new Map;for(let r of e)for(let i of r.questions||[]){let a=i.question.toLowerCase().trim();if(!a)continue;t.has(a)||t.set(a,{question:i.question,count:0,answers:new Map});let c=t.get(a);c.count++;let l=(i.answer||"").trim();c.answers.set(l,(c.answers.get(l)||0)+1)}let o=[...t.values()].sort((r,i)=>i.count-r.count),n=o.slice(0,15).map(r=>({question:r.question,count:r.count,topAnswer:[...r.answers.entries()].sort((i,a)=>a[1]-i[1])[0]?.[0]||""})),s=o.filter(r=>r.answers.size>1&&r.count>=3).map(r=>({question:r.question,count:r.count,answers:[...r.answers.entries()].sort((i,a)=>a[1]-i[1]).map(([i,a])=>`${i} (${a}x)`)}));return{totalApplications:e.length,uniqueQuestions:t.size,topQuestions:n,inconsistent:s}}function et(e){if(O.existsSync(x.join(U,".git")))try{let t={cwd:U,stdio:"pipe",timeout:1e4};ze("git add conversations.json people.json jobs.json quota.json sync-state.json run-log.json application-questions.json",t);try{ze("git diff --cached --quiet",t);return}catch{}let o=(e||`sync ${new Date().toISOString().slice(0,16)}`).replace(/"/g,'\\"');ze(`git commit -m "${o}"`,t)}catch(t){process.env.VERBOSE&&console.log(` [git] snapshot skipped: ${t.message?.slice(0,80)}`)}}import"dotenv/config";import*as re from"fs";import*as F from"path";import{fileURLToPath as Zo}from"url";var en=Zo(import.meta.url),tn=F.dirname(F.dirname(en)),Re=process.env.DATA_DIR?F.resolve(process.env.DATA_DIR,"market-research"):F.join(tn,"market-research"),on=F.join(Re,"scouted-jobs.json"),nn=F.join(Re,"discovered-people.json"),sn=F.join(Re,"visit-log.json"),ur=F.join(Re,"companies.json"),rn=F.join(Re,"job-decisions.json");function Me(e){try{if(re.existsSync(e))return JSON.parse(re.readFileSync(e,"utf-8"))}catch{}return null}function Vt(){Ee=null,Ae=null,_e=null,cn=null,se=null}var Ee=null;function tt(){return Ee||(Ee=Me(on)||{},Ee)}var Ae=null;function Wt(){return Ae||(Ae=Me(rn)||{},Ae)}var _e=null;function an(){return _e||(_e=Me(nn)||{},_e)}var cn=null;var se=null;function ln(){return se||(se=Me(sn)||{visits:[]},Array.isArray(se.visits)||(se.visits=[]),se)}function Yt(){let e=tt(),t=an(),o=Object.values(e),n=Object.values(t),s={};for(let u of o)u.company&&(s[u.company]=(s[u.company]||0)+1);let r=Object.entries(s).sort((u,m)=>m[1]-u[1]).slice(0,5).map(([u,m])=>`${u} (${m})`),i={};for(let u of o)for(let m of u.techStack||[])i[m]=(i[m]||0)+1;let a=Object.entries(i).sort((u,m)=>m[1]-u[1]).slice(0,8).map(([u,m])=>`${u} (${m})`),c=ln(),l=new Date().toISOString().slice(0,10),f=c.visits.filter(u=>u.date.startsWith(l)).length,d=new Set(c.visits.map(u=>u.profileUrl)).size;return{totalJobs:o.length,totalRecruiters:n.length,topCompanies:r,topTech:a,totalVisited:d,todayVisited:f,lastScoutDate:o.length>0?o.sort((u,m)=>(m.scoutedAt||"").localeCompare(u.scoutedAt||""))[0]?.scoutedAt:null}}var un=new Set(["java","c#",".net","scala","python","typescript","javascript","react","node.js","aws","azure","docker","kubernetes","microservices","graphql","rest","sql","postgresql","mongodb","kafka","redis","ci/cd","terraform","spring"]),fn=new Set(["iot","machine learning","ai","data engineering","spark","go","rust","kotlin","next.js","devops","sre"]),Gt=["vancouver","british columbia"],dn=["canada","montreal","quebec","alberta","calgary","ottawa"],pn=["toronto","ontario"],gn=["india","pakistan","nigeria","philippines"];function mn(e,t={}){let o=0,n=(e.techStack||[]).map(f=>f.toLowerCase()),s=0,r=0;for(let f of n)un.has(f)&&s++,fn.has(f)&&r++;if(o+=Math.min(s*6,24),o+=Math.min(r*3,6),e.salary){let f=hn(e.salary);f&&(f>=15e4?o+=20:f>=12e4?o+=15:f>=1e5?o+=10:f>=8e4?o+=5:f>=100&&f<1e3?o+=15:f>=70&&f<1e3&&(o+=10))}let i=(e.location||"").toLowerCase(),a=/remote/i.test(i)||e.workplaceType==="remote";gn.some(f=>i.includes(f))?o-=30:a&&/united states|usa|\bus\b/i.test(i)?o+=25:a&&Gt.some(f=>i.includes(f))?o+=22:a?o+=20:Gt.some(f=>i.includes(f))?o+=18:dn.some(f=>i.includes(f))?o+=10:pn.some(f=>i.includes(f))&&(o+=5),e.isEasyApply&&(o+=5);let c=(e.seniority||"").toLowerCase();c.includes("senior")||c.includes("lead")||c.includes("staff")?o+=10:c.includes("mid")?o+=5:(c.includes("entry")||c.includes("intern"))&&(o-=10),e.recruiterUrl&&(t.conversationRecruiters?.has(e.recruiterUrl)?o+=20:t.connectedRecruiters?.has(e.recruiterUrl)?o+=15:o+=3);let l=new Set(e.jobTags||[]);return l.has("managerial")?o+=8:l.has("senior-ic")&&(o+=5),l.has("junior")&&(o-=15),l.has("consultant")&&(o-=3),Math.max(0,Math.min(100,o))}function zt(e=10,t={}){let{easyApplyOnly:o=!0}=t,n=tt(),s=W(),r=new Set,i=new Set;for(let[d,u]of Object.entries(s))u.connectionStatus==="connected"&&r.add(d);let a={connectedRecruiters:r,conversationRecruiters:i},c=Wt(),l=new Set(["applied","skipped","expired","archived"]);return Object.entries(n).filter(([d,u])=>{if(typeof u!="object"||o&&!u.isEasyApply||u.applied)return!1;let m=c[d];return!(m&&l.has(m.status))}).map(([d,u])=>({jobId:d,score:mn(u,a),job:u})).sort((d,u)=>{if(u.score!==d.score)return u.score-d.score;let m=d.job.scoutedAt||d.job.postedTime||"";return(u.job.scoutedAt||u.job.postedTime||"").localeCompare(m)}).slice(0,e)}function hn(e){if(!e)return null;let t=e.match(/[\$£€CAD\s]*([\d,]+(?:\.\d+)?)\s*[kK]?/g);if(!t||t.length===0)return null;let o=t.map(n=>{let s=parseFloat(n.replace(/[^\d.]/g,""));return n.toLowerCase().includes("k")&&(s*=1e3),s}).filter(n=>n>0);return o.length>=2?(o[0]+o[1])/2:o.length===1?o[0]:null}import bn from"puppeteer";import{addExtra as vn}from"puppeteer-extra";import $n from"puppeteer-extra-plugin-stealth";import Kt from"fs";import yn from"path";var Sn="cookies.json";function wn(){let e=process.env.ILML_SCOPE_DIR;return e?yn.join(e,"plugins-state","linkedin","cookies.json"):Sn}function Pe(){let e=wn();if(!Kt.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=Kt.readFileSync(e,"utf-8")}catch(n){throw new Error(`Failed to read cookies at ${e}: ${n.message}. Run: ilml linkedin login`)}let o;try{o=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(o)||o.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return o}var Zt=vn(bn);Zt.use($n());async function eo(){let e=await Zt.launch({headless:!1,defaultViewport:null,protocolTimeout:3e5}),t=async()=>{console.log(`
2
2
  Closing browser...`);try{await e.close()}catch{}process.exit(0)};process.on("SIGINT",t),process.on("SIGTERM",t);let o=await e.newPage();await o.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})});try{let n=Pe();await o.setCookie(...n),console.log(" Browser launched, cookies loaded.")}catch(n){console.error(`
3
3
  [!] ${n.message}
4
- `),await e.close(),process.exit(1)}return{browser:e,page:o}}async function ot(e){await e.goto("https://www.linkedin.com/messaging/",{waitUntil:"domcontentloaded",timeout:6e4}),await _(4e3);let t=e.url();if(t.includes("/login")||t.includes("/authwall"))throw new Error("Redirected to login \u2014 cookies expired. Run: npm run login");try{await e.waitForSelector(".msg-conversations-container__conversations-list, .msg-conversation-listitem",{timeout:15e3})}catch{console.warn(" Inbox container not found via known selectors, proceeding..."),await _(3e3)}console.log(" Inbox loaded.")}async function to(e){let t=await e.evaluate(()=>{let o=document.querySelectorAll(".msg-conversation-listitem"),n=[];for(let s of o){let i=s.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||null;if(!i)continue;let c=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(c)||/^\s*Promoted\b/i.test(c))continue;let f=s.querySelector(".msg-conversation-listitem__time-stamp, .msg-conversation-card__time-stamp")?.textContent?.trim()||"",d=s.querySelector(".msg-conversation-card__convo-item-container--unread")!==null||s.querySelector(".msg-conversation-card__unread-count")!==null,u,m;if(c.startsWith("You:"))u="me",m=c.slice(4).trim();else{let y=i.split(" ")[0];if(c.startsWith(i+":")||c.startsWith(y+":")){u="them";let v=c.indexOf(":");m=c.slice(v+1).trim()}else u="them",m=c}let S=s.getBoundingClientRect();n.push({name:i,lastMessagePreview:m,lastMessageTime:f,unread:d,lastMessageBy:u,x:S.x+S.width/2,y:S.y+S.height/2})}return n});for(let o of t)o.lastMessageTime=Ge(o.lastMessageTime)||o.lastMessageTime;return t}async function nt(e){return e.evaluate(()=>{let t=[".msg-conversations-container__conversations-list",".msg-conversations-container",'[class*="msg-conversations-container"] ul'];for(let n of t){let s=document.querySelector(n);if(s&&s.scrollHeight>s.clientHeight)return s.scrollBy(0,600),{scrollTop:s.scrollTop,scrollHeight:s.scrollHeight}}let o=document.querySelector(".msg-conversation-listitem");if(o){let n=o.parentElement;for(;n;){if(n.scrollHeight>n.clientHeight+10)return n.scrollBy(0,600),{scrollTop:n.scrollTop,scrollHeight:n.scrollHeight};n=n.parentElement}}return null})}async function kn(e){return e.evaluate(()=>{let t=/^status\s+is\s+|^online$|^offline$|^away$|^busy$|^active\s/i,o=['.msg-overlay-conversation-bubble__header a[href*="/in/"] .truncate','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header__title a[href*="/in/"]',".msg-overlay-bubble-header__title",".msg-overlay-conversation-bubble__header .truncate",".msg-thread__link-to-profile","h2.msg-entity-lockup__entity-title",".msg-s-message-list-container h2",".msg-thread h2",".msg-conversations-container__title-row h2",'.msg-thread a[href*="/in/"]'];for(let s of o){let r=document.querySelector(s);if(r){let i=r.textContent?.trim()?.replace(/\s+/g," ");if(i&&i.length>1&&i.length<100&&!t.test(i))return i}}let n=document.querySelectorAll(".msg-s-message-list-container h2, .msg-thread h2");for(let s of n){let r=s.textContent?.trim();if(r&&r.length>1&&r.length<100&&!/conversation/i.test(r)&&!t.test(r))return r}return null})}async function st(e){return e.evaluate(()=>{let t=[".msg-thread__link-to-profile",'.msg-entity-lockup__entity-title a[href*="/in/"]','.msg-s-message-list-container a[href*="/in/"]','.msg-thread a[href*="/in/"]','.msg-conversations-container__title-row a[href*="/in/"]','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header a[href*="/in/"]','.msg-overlay-conversation-bubble a[href*="/in/"]'];for(let o of t){let n=document.querySelector(o);if(n){let s=n.getAttribute("href")||"";if(s&&s.includes("/in/"))return s.startsWith("/")&&(s="https://www.linkedin.com"+s),s=s.replace(/\/$/,"").split("?")[0],s}}return null})}async function Qt(e,t){let o=await kn(e);if(!o)return{match:!1,headerName:null};let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(a=>a.length>1),r=o.toLowerCase();return{match:r.includes(n)||s.some(a=>r.includes(a)),headerName:o}}async function Fe(e,t){let o=t.split(" ")[0],n=8e3,s=500,r=0;for(;r<n;){let{match:c,headerName:l}=await Qt(e,t);if(c)return await _(500),{verified:!0,headerName:l};let f=await e.evaluate(()=>{let d=document.querySelectorAll(".msg-s-message-group__name"),u=Array.from(d).map(S=>S.textContent?.trim()).filter(Boolean),m=document.querySelectorAll(".msg-s-event-listitem").length;return{allSenders:u,msgCount:m}});if(f.msgCount>0&&f.allSenders.some(u=>u.toLowerCase().includes(o.toLowerCase())))return await _(300),{verified:!0,headerName:o};await _(s),r+=s}let{match:i,headerName:a}=await Qt(e,t);return i?{verified:!0,headerName:a}:{verified:!1,headerName:a}}async function Cn(e){let o=0,n=0;for(let s=0;s<50;s++){let r=await e.evaluate(()=>{let i=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!i){let l=document.querySelector(".msg-overlay-conversation-bubble");l&&(i=l.querySelector(".msg-s-message-list-container")||l.querySelector(".msg-s-message-list"))}if(!i)return{found:!1};let a=i.querySelectorAll("li.msg-s-message-list__event").length;return i.scrollTop<=1?{found:!0,atTop:!0,msgCount:a}:(i.scrollTop=0,{found:!0,atTop:!1,msgCount:a})});if(!r.found||r.atTop)break;if(await _(800),r.msgCount===o){if(n++,n>=3)break}else n=0;o=r.msgCount}}async function rt(e,{scrollUp:t=!0}={}){t&&await Cn(e);let o=await e.evaluate(()=>{let n=[],s="",r=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!r){let f=document.querySelector(".msg-overlay-conversation-bubble");f&&(r=f.querySelector(".msg-s-message-list-container")||f.querySelector(".msg-s-message-list"))}if(!r)return n;let i=r.querySelectorAll("li.msg-s-message-list__event");if(i.length===0){let f=document.querySelector(".msg-overlay-conversation-bubble, .msg-overlay-list-bubble");f&&(i=f.querySelectorAll("li.msg-s-message-list__event, .msg-s-event-listitem"))}function a(f){let d=f.getAttribute("data-event-urn");if(!d)return null;let u=d.match(/,2-([A-Za-z0-9+/=]+)\)/);if(!u)return null;try{let S=atob(u[1]).match(/^(\d{13})/);if(!S)return null;let y=Number(S[1]);if(y>14200704e5&&y<20512224e5)return y}catch{}return null}let c="";function l(f,d,u){let m=a(f),y=f.querySelector(".msg-s-message-group__timestamp, time")?.textContent?.trim()||"",v=f.querySelector(".msg-s-event-listitem__message-bubble");if(!v)return null;let $=v.textContent?.trim()?.replace(/Open Emoji Keyboard|Reply to this message|React with[^.]+/g,"")?.replace(/^(?:👏\s*👍\s*😊\s*)+/,"")?.replace(/\s+/g," ")?.trim()||"";if(!$)return null;let k=m?new Date(m).toISOString():u?`${u} ${y}`.trim():y;return{sender:d,text:$,time:k}}for(let f of i){let d=f.querySelector("time.msg-s-message-list__time-heading");d&&(c=d.textContent?.trim()||c);let u=f.querySelectorAll(".msg-s-message-group");if(u.length>0)for(let m of u){let S=m.querySelector(".msg-s-message-group__name");S&&(s=S.textContent?.trim()||s);let y=s||"Unknown",v=m.querySelectorAll(".msg-s-event-listitem");for(let $ of v){let k=l($,y,c);k&&n.push(k)}}else{let m=f.querySelectorAll(".msg-s-event-listitem");for(let S of m){let y=S.querySelector(".msg-s-message-group__name");y&&(s=y.textContent?.trim()||s);let $=l(S,s||"Unknown",c);$&&n.push($)}}}if(n.length===0){let f=document.querySelectorAll(".msg-s-event-listitem--group-a11y-heading");for(let d of f){let u=d.textContent?.trim();u&&n.push({sender:"",text:u,time:""})}}return n});for(let n of o)(!n.time||!/^\d{4}-\d{2}-\d{2}T/.test(n.time))&&(n.time=Ge(n.time)||n.time);return o}function it(e,t,o){if(e.length===0)return!0;let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(l=>l.length>1),r=[...new Set(e.map(l=>l.sender).filter(l=>l&&l!=="Unknown"))],i=r.some(l=>{let f=l.toLowerCase();return f.includes(n)||s.some(d=>f.includes(d))}),a=P.toLowerCase().split(/\s+/),c=r.every(l=>{let f=l.toLowerCase();return a.some(d=>f.includes(d))});if(i)return!0;if(c){for(let l of e){let d=(l.text||"").trim().match(/^(?:Hi|Hey|Hello|Dear)\s+([A-Z][a-z]+)/);if(d){let u=d[1].toLowerCase();if(u!=="there"&&u!=="all"&&!(s.some(S=>S===u)||u===n))return console.log(` STALE DATA: message says "Hi ${d[1]}" but expected "${t}"`),!1}}return!0}if(o?.length>0){let l=o.map(d=>d.toLowerCase());if(r.some(d=>{let u=d.toLowerCase();return l.some(m=>u.includes(m.split(" ")[0]))}))return console.log(` STALE DATA: messages belong to previous conversation (senders: ${r.join(", ")})`),!1}return console.log(` Sender warning: no match for "${t}" (found: ${r.join(", ")})`),!1}function ge(e){return(e||"").replace(/\s+/g," ").trim().toLowerCase()}function at(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let o=u=>ge(u.sender)+"||"+ge(u.text),n=new Set(t.map(o)),s=new Set(e.map(o)),r=e.filter(u=>fe.has(u.status)?!1:!n.has(o(u))),i=t.filter(u=>!s.has(o(u))),a=t.filter(u=>s.has(o(u))),c=e.filter(u=>fe.has(u.status)),l=[...r,...a,...i],f=[];for(let u of l){let m=ge(u.text),S=ge(u.sender),y=!1;for(let v=0;v<f.length;v++){let $=f[v];if(ge($.sender)!==S)continue;let k=ge($.text);if(m.length>k.length&&m.endsWith(k)){y=!0;break}if(k.length>m.length&&k.endsWith(m)){f[v]=u,y=!0;break}}y||f.push(u)}return[...f,...c]}async function oo(e,t){await ot(e),await _(2500),await e.evaluate(()=>{let a=[".msg-conversations-container__conversations-list",".msg-conversations-container"];for(let c of a){let l=document.querySelector(c);if(l){l.scrollTop=0;return}}}),await _(500);async function o(){return e.evaluate(a=>{let c=document.querySelectorAll(".msg-conversation-listitem");for(let l of c)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===a){let u=l.getBoundingClientRect();if(u.height>0)return{x:u.x+u.width/2,y:u.y+u.height/2}}return null},t)}let n=await o(),s=50,r=-1,i=0;for(let a=0;a<s&&!n;a++){let c=await nt(e);if(!c)break;if(c.scrollTop===r){if(i++,i>=2)break}else i=0,r=c.scrollTop;await _(600),n=await o()}return n?(await e.mouse.click(n.x,n.y),await _(3e3),Fe(e,t)):{verified:!1,headerName:null}}async function ct(e,t){let o=await e.evaluate(i=>{let a=document.querySelectorAll(".msg-conversation-listitem");for(let c of a)if(c.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===i){let d=c.getBoundingClientRect();if(d.height>0)return{x:d.x+d.width/2,y:d.y+d.height/2}}return null},t);if(o){await e.mouse.click(o.x,o.y),await _(3e3);let i=await Fe(e,t);if(i.verified)return i}let n=Dt(t),s=n!==t?[t,n]:[t];for(let i of s)if(await Xt(e,i,t)){let c=await Fe(e,t);if(c.verified)return c}let r=Ot(n);if(r!==n&&r.length>0&&await Xt(e,r,t,{requireUnique:!0})){let a=await Fe(e,t);if(a.verified)return a}return{verified:!1,headerName:null}}async function Xt(e,t,o,n={}){let{requireUnique:s=!1}=n,r=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");if(!r)return!1;await r.click(),await _(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await _(300),await r.type(t,{delay:30}),await _(500),await e.keyboard.press("Enter"),await _(3500);let i=await e.evaluate((a,c)=>{let l=a.split(" ")[0].toLowerCase(),f=a.toLowerCase(),d=document.querySelectorAll(".msg-conversation-listitem"),u=[],m=[];for(let y of d){let $=y.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||"",k=$.toLowerCase();if(k.includes(l)){let g=y.getBoundingClientRect();if(g.height>0){let p=$.includes(",")||/\d+ other/.test($),w=k===f?3:k.includes(f)?2:1,C={text:$,isGroup:p,score:w,x:g.x+g.width/2,y:g.y+g.height/2};p?m.push(C):u.push(C)}}}u.sort((y,v)=>v.score-y.score);let S=[...u,...m];return c&&S.length!==1?null:u[0]||m[0]||null},o,s);return i?(s&&console.log(" (found via stripped designations)"),await e.mouse.click(i.x,i.y),!0):!1}async function Z(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await _(200),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await e.keyboard.press("Escape"),await _(1e3))}function ut(e,t,o){if(!e)return e;let s=(e.messages||[]).filter(c=>!fe.has(c.status)),r=In(t,e.profileUrl,o),i=ft(s,t);if(e.lastMessageBy=i,e.conversationStatus=i==="me"?"awaiting_reply":"unanswered_by_us",e.categorySource!=="manual"){let c=Tn(s,t,r);c&&(e.category=c,e.categorySource=e.categorySource||"message_content")}if(e.situation=En(s,i,t),s.length>0){let c=s[s.length-1];e.lastMessageTime=c.time}if(s.length>0&&!e.initiatedBy){let c=s[0];c.sender===P?e.initiatedBy="us":c.sender!=="Unknown"&&c.sender!==""&&(e.initiatedBy="them")}e.engagement=io(s,t),e.personContext=Dn(r),e.summary=_n(e,t,r),e.autoTags=An(e,t,r);let a=Rn(e);return e.actionNeeded=a.action,e.actionDetail=a.detail,e.suggestedPriority=On(e),e}var so={recruiter:{theirMessages:[/\b(recruiter|recruiting|talent.?acqui|staffing|headhunter|head\s*hunter|sourcer|executive\s*search)\b/i],title:[/\b(recruiter|recruiting|talent.?acqui|staffing|sourcer|sourcing)\b/i,/\b(head\s*hunter|executive\s*search)\b/i]},hiring_manager:{theirMessages:[/\b(my|our)\s+team\b/i,/\b(i.?m|we.?re|i\s+am|we\s+are)\s+(currently\s+|actively\s+|now\s+)?(looking|hiring|recruiting)\b/i,/\bjoin\s+(my|our)\b/i,/\bdirect.?report/i,/\b(engineering manager|team lead|vp of|director of|head of)\b/i],title:[/\b(engineering manager|team lead|vp|director|head of engineering)\b/i]},founder:{theirMessages:[/\b(founder|co-founder|ceo|cto|my company|my startup|i.?m building)\b/i],title:[/\b(founder|co-founder|ceo|cto)\b/i]},investor:{theirMessages:[/\b(investor|invest|funding|vc|venture|angel)\b/i],title:[/\b(investor|venture|capital|angel|partner at)\b/i,/\binvestment\s+(manager|partner|director|associate|analyst|principal)\b/i]},coach:{theirMessages:[/\b(coach|coaching|mentor|mentoring|career.?(advice|guidance|help))\b/i,/\b(resume.?(review|writing)|interview.?prep|career.?transition)\b/i],title:[/\b(coach|mentor|career.?(consultant|advisor))\b/i]},peer:{theirMessages:[/\b(fellow|peer|networking|connect|nice.?to.?meet|great.?to.?connect)\b/i,/\b(your (profile|background|experience).*interest)\b/i]},sales:{theirMessages:[/\b(sales|business develop|partnership|proposal|offer|demo|pricing|platform|solution)\b/i],title:[/\b(sales|business develop|account.?exec|bdm|bdr|sdr)\b/i]},spam:{theirMessages:[/\b(crypto|bitcoin|forex|trading.?signal|guaranteed.?return|make.?money)\b/i,/\b(whatsapp|telegram.?group|click (here|this link))\b/i]},event:{theirMessages:[/\b(event|conference|webinar|summit|meetup|workshop|speak(er|ing))\b/i,/\b(attend|register|rsvp|invitation|invite.?you)\b/i]}};function Tn(e,t,o){if(!e||e.length===0)return o?.title?lt(o.title):null;let n=e.filter(s=>s.sender!==P&&s.sender!=="Unknown"&&s.sender!=="").map(s=>s.text).join(" ");for(let[s,r]of Object.entries(so))if(r.theirMessages){for(let i of r.theirMessages)if(i.test(n))return s}if(o?.title){let s=lt(o.title);if(s)return s}return null}function lt(e){if(!e)return null;for(let[t,o]of Object.entries(so))if(o.title){for(let n of o.title)if(n.test(e))return t}return null}var no=/\b(call|meet|teams|zoom|schedule|available|availability|invite|slot|calendar)\b/i;function En(e,t,o){if(!e||e.length===0)return"no_messages";let n=e[e.length-1];if(e.length===1)return t==="them"?"initial_outreach_unanswered":"we_initiated_waiting";if(t==="me")return no.test(n.text)?"scheduling_proposed_by_us":e.length>=6?"active_conversation_ball_in_their_court":"awaiting_their_reply";let s=[...e].reverse().find(r=>r.sender!==P&&r.sender!=="Unknown");return no.test(s?.text||"")?"they_want_to_schedule_call":e.length>=6?"active_conversation_needs_our_reply":"needs_our_reply"}function ft(e,t){if(!e||e.length===0)return"them";let o=[...e].map(s=>({m:s,t:Date.parse(s.time)})).filter(s=>Number.isFinite(s.t)).sort((s,r)=>r.t-s.t).map(s=>s.m),n=o.length>0?o:[...e].reverse();for(let s of n){let r=s.sender;if(r===P)return"me";if(r!=="Unknown"&&r!=="")return"them"}return"them"}function _n(e,t,o){let n=e.messages||[];if(n.length===0)return null;let s=[],r=e.category,i=o?.title,a=o?.company,c=o?.location;r==="recruiter"&&a?s.push(`Recruiter from ${a}`):r==="hiring_manager"&&a?s.push(`Hiring manager at ${a}`):r==="founder"&&a?s.push(`Founder of ${a}`):r&&i?s.push(`${dt(r)}: ${me(i,40)}`):i?s.push(me(i,50)):s.push(t.split(" ")[0]);let l=n.filter(S=>S.sender!==P&&S.sender!=="Unknown").map(S=>S.text).join(" "),f=xn(l),d=jn(l),u=Nn(l),m=[];return f&&m.push(f),u&&u!==c&&m.push(u),d&&m.push(d),m.length>0&&s.push(m.join(", ")),e.situation==="they_want_to_schedule_call"?s.push("wants to schedule call"):e.situation==="scheduling_proposed_by_us"?s.push("we proposed scheduling"):e.conversationStatus==="unanswered_by_us"?s.push("needs reply"):e.conversationStatus==="awaiting_reply"&&s.push("waiting on them"),s.join(". ").replace(/\.\./g,".")}function An(e,t,o){let n=[],s=(e.messages||[]).filter(l=>!fe.has(l.status)),r=s.map(l=>l.text).join(" "),i=s.filter(l=>l.sender!==P&&l.sender!=="Unknown").map(l=>l.text).join(" "),a=ro(i,o?.location);n.push(...a),/\b(contract|contractor|c2c|corp.?to.?corp)\b/i.test(r)&&n.push("contract"),/\b(full.?time|permanent|fte|perm)\b/i.test(r)&&n.push("full-time"),/\b(remote|work.?from.?home|wfh)\b/i.test(r)&&n.push("remote"),/\b(hybrid)\b/i.test(r)&&n.push("hybrid"),/\b(on.?site|in.?office|in.?person)\b/i.test(r)&&n.push("onsite"),/\b(java)\b/i.test(r)&&!/javascript/i.test(r)&&n.push("java"),/\b(python)\b/i.test(r)&&n.push("python"),/\b(react|angular|vue|front.?end)\b/i.test(r)&&n.push("frontend"),/\b(node|backend|back.?end|api|microservice)\b/i.test(r)&&n.push("backend"),/\b(full.?stack)\b/i.test(r)&&n.push("fullstack"),/\b(devops|sre|cloud|aws|azure|gcp|kubernetes|k8s)\b/i.test(r)&&n.push("devops"),/\b(data.?engineer|data.?scien|ml|machine.?learn|ai)\b/i.test(r)&&n.push("data/ml"),/\b(lead|senior|staff|principal|architect)\b/i.test(r)&&n.push("senior-role"),/\b(manager|director|vp|head of)\b/i.test(r)&&n.push("management"),/\$[\d,]+|\d+k|\d+\/hr|\d+\s*per\s*(hour|annum|year)/i.test(r)&&n.push("has-salary");let c=e.engagement||io(s,t);return c.messageCount>=6&&n.push("active-thread"),c.theirCount===0&&c.ourCount>0&&n.push("no-response"),c.ourCount===0&&c.theirCount>0&&n.push("unanswered"),e.situation==="they_want_to_schedule_call"&&n.push("hot-lead"),(e.messages||[]).some(l=>$e.has(l.status))&&n.push("has-draft"),[...new Set(n)]}function ro(e,t){let o=[],n=["toronto","vancouver","montreal","ottawa","calgary","edmonton","new york","san francisco","seattle","chicago","austin","boston","los angeles","denver","atlanta","dallas","houston","miami","london","berlin","amsterdam","dubai"],s=[["canada","canada"],["ontario","ontario"],["british columbia","bc"],["alberta","alberta"],["quebec","quebec"],["usa","usa"],["united states","usa"]],r=(e+" "+(t||"")).toLowerCase();for(let i of n)r.includes(i)&&o.push(i.replace(/\s+/g,"-"));for(let[i,a]of s)r.includes(i)&&o.push(a);return o}function Rn(e){let{category:t,situation:o,conversationStatus:n}=e;if(e.dismissedAtPreview&&De(e.lastMessagePreview)===De(e.dismissedAtPreview))return{action:"none",detail:e.dismissReason||"Dismissed."};let s=(e.messages||[]).find(r=>$e.has(r.status));return s?s.status===j.CONFIRMED?{action:"push_draft",detail:"Draft confirmed. Run --push-drafts to send."}:{action:"review_draft",detail:"Draft needs review. Run --review-drafts."}:n==="awaiting_reply"?{action:"none",detail:"Ball in their court."}:o==="no_messages"?{action:"none",detail:"No messages read yet."}:o==="they_want_to_schedule_call"?{action:"schedule_call",detail:"They proposed a call. Reply with time slots."}:o==="initial_outreach_unanswered"?t==="spam"?{action:"archive",detail:"Likely spam. Safe to ignore."}:t==="recruiter"||t==="hiring_manager"?{action:"reply",detail:"New recruiter/HM message. Review and respond."}:t==="coach"||t==="sales"?{action:"archive",detail:`${dt(t||"unknown")} outreach. Likely not relevant.`}:{action:"reply",detail:"New message. Review and respond."}:o==="active_conversation_needs_our_reply"||o==="needs_our_reply"?{action:"reply",detail:"They replied. Continue the conversation."}:{action:"none",detail:""}}function io(e,t){if(!e||e.length===0)return{messageCount:0,theirCount:0,ourCount:0,unknownCount:0,hasJob:!1,hasSalary:!1};let o=0,n=0,s=0,r=!1,i=!1,a=e.map(c=>c.text).join(" ");for(let c of e)c.sender===P?o++:c.sender==="Unknown"||c.sender===""?s++:n++;return r=/\b(job|role|position|opening)\b/i.test(a),i=/\$[\d,]+|\d+k|\d+\/hr/i.test(a),{messageCount:e.length,theirCount:n,ourCount:o,unknownCount:s,hasJob:r,hasSalary:i}}function Dn(e){return e?{title:e.title||null,company:e.company||null,location:e.location||null,connectionStatus:e.connectionStatus||null}:null}function On(e){let{category:t,situation:o,engagement:n}=e;return o==="they_want_to_schedule_call"?"high":(t==="recruiter"||t==="hiring_manager")&&(o==="active_conversation_needs_our_reply"||o==="needs_our_reply")?n?.messageCount>=4?"high":"medium":t==="recruiter"&&o==="initial_outreach_unanswered"||t==="founder"&&e.conversationStatus==="unanswered_by_us"?"medium":t==="spam"||t==="coach"||t==="sales"?"low":e.conversationStatus==="unanswered_by_us"?"medium":null}function In(e,t,o){if(!o)return null;if(t&&o[t])return o[t];if(!e)return null;let n=Object.values(o).filter(s=>s.name===e);return n.length===1?n[0]:null}function De(e){return(e||"").replace(/\s+/g," ").trim().slice(0,80).toLowerCase()}function dt(e){return e?e.charAt(0).toUpperCase()+e.slice(1):""}function me(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function xn(e){let t=e.match(/\b((?:senior |sr\.? |lead |staff |principal |junior |jr\.? )?(?:software|full.?stack|front.?end|back.?end|data|devops|cloud|platform|mobile|ios|android|qa|sdet)\s*(?:engineer|developer|architect|lead|manager|scientist))\b/i);if(t)return t[1];let o=e.match(/\b((?:java|python|react|node|\.net|golang|rust|scala)\s*developer)\b/i);return o?o[1]:null}function jn(e){let t=e.match(/\$[\d,]+(?:k|K)?(?:\s*[-–]\s*\$?[\d,]+(?:k|K)?)?(?:\s*\/\s*(?:hr|hour|yr|year|annum))?/);return t?t[0]:null}function Nn(e){let t=e.match(/\b(?:in|based in|located in)\s+([A-Z][a-z]+(?:\s[A-Z][a-z]+)?(?:,\s*[A-Z]{2})?)/);return t?t[1]:null}function ao(e,t){if(!e)return e;if(e.categorySource!=="manual"){let n=lt(e.title);n&&(e.category=n,e.categorySource=e.categorySource||"title")}Mn(e),e.personSummary=Pn(e),e.personAutoTags=Fn(e);let o=Ln(e);return e.personActionNeeded=o.action,e.personActionDetail=o.detail,e.personPriorityManual||(e.personPriority=Un(e)),e}function Mn(e){if(e.jobCount=e.jobIds?.length||0,e.encounterCount=e.encounters?.length||0,e.encounters?.length>0){let t=e.encounters.filter(o=>o.jobTitle).sort((o,n)=>(n.date||"").localeCompare(o.date||""));t.length>0&&(e.lastJobTitle=t[0].jobTitle,e.lastJobCompany=t[0].jobCompany||null,e.lastJobDate=t[0].date)}e.isRepeatRecruiter=e.jobCount>=3}function Pn(e){let t=[],o=e.category,n=e.title,s=e.company,r=e.location;if(o==="recruiter"&&s?t.push(`Recruiter at ${s}`):o==="hiring_manager"&&s?t.push(`Hiring manager at ${s}`):o==="founder"&&s?t.push(`Founder of ${s}`):n&&s?t.push(`${me(n,40)} at ${me(s,30)}`):n?t.push(me(n,50)):e.name&&t.push(e.name.split(" ")[0]),r&&t.push(r),e.connectionDate){let i=new Date(e.connectionDate);if(!isNaN(i)){let a=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];t.push(`Connected ${a[i.getMonth()]} ${i.getDate()}`)}}if(e.jobCount>0){let i=`${e.jobCount} job${e.jobCount>1?"s":""}`;if(e.lastJobTitle){if(i+=` (last: ${me(e.lastJobTitle,30)}`,e.lastJobDate){let a=new Date(e.lastJobDate);isNaN(a)||(i+=`, ${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][a.getMonth()]} ${a.getDate()}`)}i+=")"}t.push(i)}return t.join(". ").replace(/\.\./g,".")||null}function Fn(e){let t=[],o=[e.title,e.company,e.location].filter(Boolean).join(" "),n=ro("",e.location);return t.push(...n),e.category&&t.push(e.category),/\b(java)\b/i.test(o)&&!/javascript/i.test(o)&&t.push("java"),/\b(python)\b/i.test(o)&&t.push("python"),/\b(react|angular|vue|front.?end)\b/i.test(o)&&t.push("frontend"),/\b(node|backend|back.?end|api|microservice)\b/i.test(o)&&t.push("backend"),/\b(full.?stack)\b/i.test(o)&&t.push("fullstack"),/\b(devops|sre|cloud|aws|azure|gcp|kubernetes|k8s)\b/i.test(o)&&t.push("devops"),/\b(data.?engineer|data.?scien|ml|machine.?learn|ai)\b/i.test(o)&&t.push("data/ml"),/\b(lead|senior|staff|principal|architect)\b/i.test(o)&&t.push("senior-role"),/\b(manager|director|vp|head of)\b/i.test(o)&&t.push("management"),/\b(staffing|agency|consulting|outsourc)\b/i.test(o)&&t.push("staffing"),[...new Set(t)]}function Ln(e){if(e.connectionStatus!=="connected")return{action:"none",detail:"Not connected."};let t=e.category;return t==="recruiter"||t==="hiring_manager"?{action:"initiate_contact",detail:`New ${t.replace("_"," ")} connection. Send intro message.`}:t==="founder"?{action:"initiate_contact",detail:"Founder connection. Consider reaching out."}:t==="sales"||t==="coach"||t==="spam"?{action:"none",detail:`${dt(t)} \u2014 no outreach needed.`}:t==="investor"?{action:"initiate_contact",detail:"Investor connection. Consider intro message."}:{action:"none",detail:"No specific action identified."}}function Un(e){let t=e.category;if(!t)return null;let o=Bn(e,7);return e.isRepeatRecruiter&&(t==="recruiter"||t==="hiring_manager")||(t==="recruiter"||t==="hiring_manager")&&o?"high":t==="recruiter"||t==="hiring_manager"||t==="founder"&&o?"medium":t==="founder"||t==="investor"?"low":t==="sales"||t==="coach"||t==="spam"?null:t==="peer"?"low":null}function Bn(e,t){if(!e.connectionDate)return!1;let o=new Date(e.connectionDate);if(isNaN(o))return!1;let n=new Date;return n.setDate(n.getDate()-t),o>=n}import"dotenv/config";import*as B from"fs";import*as ee from"path";import{fileURLToPath as Yn}from"url";import"dotenv/config";import{createGraphClient as qn,resolveToken as Jn}from"@ilivemylife/graph-sdk";import{config as Hn}from"dotenv";Hn();var co=Jn()||process.env.TOKEN;co||(console.error(`
4
+ `),await e.close(),process.exit(1)}return{browser:e,page:o}}async function ot(e){await e.goto("https://www.linkedin.com/messaging/",{waitUntil:"domcontentloaded",timeout:6e4}),await A(4e3);let t=e.url();if(t.includes("/login")||t.includes("/authwall"))throw new Error("Redirected to login \u2014 cookies expired. Run: npm run login");try{await e.waitForSelector(".msg-conversations-container__conversations-list, .msg-conversation-listitem",{timeout:15e3})}catch{console.warn(" Inbox container not found via known selectors, proceeding..."),await A(3e3)}console.log(" Inbox loaded.")}async function to(e){let t=await e.evaluate(()=>{let o=document.querySelectorAll(".msg-conversation-listitem"),n=[];for(let s of o){let i=s.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||null;if(!i)continue;let c=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(c)||/^\s*Promoted\b/i.test(c))continue;let f=s.querySelector(".msg-conversation-listitem__time-stamp, .msg-conversation-card__time-stamp")?.textContent?.trim()||"",d=s.querySelector(".msg-conversation-card__convo-item-container--unread")!==null||s.querySelector(".msg-conversation-card__unread-count")!==null,u,m;if(c.startsWith("You:"))u="me",m=c.slice(4).trim();else{let y=i.split(" ")[0];if(c.startsWith(i+":")||c.startsWith(y+":")){u="them";let v=c.indexOf(":");m=c.slice(v+1).trim()}else u="them",m=c}let S=s.getBoundingClientRect();n.push({name:i,lastMessagePreview:m,lastMessageTime:f,unread:d,lastMessageBy:u,x:S.x+S.width/2,y:S.y+S.height/2})}return n});for(let o of t)o.lastMessageTime=Ge(o.lastMessageTime)||o.lastMessageTime;return t}async function nt(e){return e.evaluate(()=>{let t=[".msg-conversations-container__conversations-list",".msg-conversations-container",'[class*="msg-conversations-container"] ul'];for(let n of t){let s=document.querySelector(n);if(s&&s.scrollHeight>s.clientHeight)return s.scrollBy(0,600),{scrollTop:s.scrollTop,scrollHeight:s.scrollHeight}}let o=document.querySelector(".msg-conversation-listitem");if(o){let n=o.parentElement;for(;n;){if(n.scrollHeight>n.clientHeight+10)return n.scrollBy(0,600),{scrollTop:n.scrollTop,scrollHeight:n.scrollHeight};n=n.parentElement}}return null})}async function kn(e){return e.evaluate(()=>{let t=/^status\s+is\s+|^online$|^offline$|^away$|^busy$|^active\s/i,o=['.msg-overlay-conversation-bubble__header a[href*="/in/"] .truncate','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header__title a[href*="/in/"]',".msg-overlay-bubble-header__title",".msg-overlay-conversation-bubble__header .truncate",".msg-thread__link-to-profile","h2.msg-entity-lockup__entity-title",".msg-s-message-list-container h2",".msg-thread h2",".msg-conversations-container__title-row h2",'.msg-thread a[href*="/in/"]'];for(let s of o){let r=document.querySelector(s);if(r){let i=r.textContent?.trim()?.replace(/\s+/g," ");if(i&&i.length>1&&i.length<100&&!t.test(i))return i}}let n=document.querySelectorAll(".msg-s-message-list-container h2, .msg-thread h2");for(let s of n){let r=s.textContent?.trim();if(r&&r.length>1&&r.length<100&&!/conversation/i.test(r)&&!t.test(r))return r}return null})}async function st(e){return e.evaluate(()=>{let t=[".msg-thread__link-to-profile",'.msg-entity-lockup__entity-title a[href*="/in/"]','.msg-s-message-list-container a[href*="/in/"]','.msg-thread a[href*="/in/"]','.msg-conversations-container__title-row a[href*="/in/"]','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header a[href*="/in/"]','.msg-overlay-conversation-bubble a[href*="/in/"]'];for(let o of t){let n=document.querySelector(o);if(n){let s=n.getAttribute("href")||"";if(s&&s.includes("/in/"))return s.startsWith("/")&&(s="https://www.linkedin.com"+s),s=s.replace(/\/$/,"").split("?")[0],s}}return null})}async function Qt(e,t){let o=await kn(e);if(!o)return{match:!1,headerName:null};let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(a=>a.length>1),r=o.toLowerCase();return{match:r.includes(n)||s.some(a=>r.includes(a)),headerName:o}}async function Fe(e,t){let o=t.split(" ")[0],n=8e3,s=500,r=0;for(;r<n;){let{match:c,headerName:l}=await Qt(e,t);if(c)return await A(500),{verified:!0,headerName:l};let f=await e.evaluate(()=>{let d=document.querySelectorAll(".msg-s-message-group__name"),u=Array.from(d).map(S=>S.textContent?.trim()).filter(Boolean),m=document.querySelectorAll(".msg-s-event-listitem").length;return{allSenders:u,msgCount:m}});if(f.msgCount>0&&f.allSenders.some(u=>u.toLowerCase().includes(o.toLowerCase())))return await A(300),{verified:!0,headerName:o};await A(s),r+=s}let{match:i,headerName:a}=await Qt(e,t);return i?{verified:!0,headerName:a}:{verified:!1,headerName:a}}async function Cn(e){let o=0,n=0;for(let s=0;s<50;s++){let r=await e.evaluate(()=>{let i=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!i){let l=document.querySelector(".msg-overlay-conversation-bubble");l&&(i=l.querySelector(".msg-s-message-list-container")||l.querySelector(".msg-s-message-list"))}if(!i)return{found:!1};let a=i.querySelectorAll("li.msg-s-message-list__event").length;return i.scrollTop<=1?{found:!0,atTop:!0,msgCount:a}:(i.scrollTop=0,{found:!0,atTop:!1,msgCount:a})});if(!r.found||r.atTop)break;if(await A(800),r.msgCount===o){if(n++,n>=3)break}else n=0;o=r.msgCount}}async function rt(e,{scrollUp:t=!0}={}){t&&await Cn(e);let o=await e.evaluate(()=>{let n=[],s="",r=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!r){let f=document.querySelector(".msg-overlay-conversation-bubble");f&&(r=f.querySelector(".msg-s-message-list-container")||f.querySelector(".msg-s-message-list"))}if(!r)return n;let i=r.querySelectorAll("li.msg-s-message-list__event");if(i.length===0){let f=document.querySelector(".msg-overlay-conversation-bubble, .msg-overlay-list-bubble");f&&(i=f.querySelectorAll("li.msg-s-message-list__event, .msg-s-event-listitem"))}function a(f){let d=f.getAttribute("data-event-urn");if(!d)return null;let u=d.match(/,2-([A-Za-z0-9+/=]+)\)/);if(!u)return null;try{let S=atob(u[1]).match(/^(\d{13})/);if(!S)return null;let y=Number(S[1]);if(y>14200704e5&&y<20512224e5)return y}catch{}return null}let c="";function l(f,d,u){let m=a(f),y=f.querySelector(".msg-s-message-group__timestamp, time")?.textContent?.trim()||"",v=f.querySelector(".msg-s-event-listitem__message-bubble");if(!v)return null;let $=v.textContent?.trim()?.replace(/Open Emoji Keyboard|Reply to this message|React with[^.]+/g,"")?.replace(/^(?:👏\s*👍\s*😊\s*)+/,"")?.replace(/\s+/g," ")?.trim()||"";if(!$)return null;let k=m?new Date(m).toISOString():u?`${u} ${y}`.trim():y;return{sender:d,text:$,time:k}}for(let f of i){let d=f.querySelector("time.msg-s-message-list__time-heading");d&&(c=d.textContent?.trim()||c);let u=f.querySelectorAll(".msg-s-message-group");if(u.length>0)for(let m of u){let S=m.querySelector(".msg-s-message-group__name");S&&(s=S.textContent?.trim()||s);let y=s||"Unknown",v=m.querySelectorAll(".msg-s-event-listitem");for(let $ of v){let k=l($,y,c);k&&n.push(k)}}else{let m=f.querySelectorAll(".msg-s-event-listitem");for(let S of m){let y=S.querySelector(".msg-s-message-group__name");y&&(s=y.textContent?.trim()||s);let $=l(S,s||"Unknown",c);$&&n.push($)}}}if(n.length===0){let f=document.querySelectorAll(".msg-s-event-listitem--group-a11y-heading");for(let d of f){let u=d.textContent?.trim();u&&n.push({sender:"",text:u,time:""})}}return n});for(let n of o)(!n.time||!/^\d{4}-\d{2}-\d{2}T/.test(n.time))&&(n.time=Ge(n.time)||n.time);return o}function it(e,t,o){if(e.length===0)return!0;let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(l=>l.length>1),r=[...new Set(e.map(l=>l.sender).filter(l=>l&&l!=="Unknown"))],i=r.some(l=>{let f=l.toLowerCase();return f.includes(n)||s.some(d=>f.includes(d))}),a=P.toLowerCase().split(/\s+/),c=r.every(l=>{let f=l.toLowerCase();return a.some(d=>f.includes(d))});if(i)return!0;if(c){for(let l of e){let d=(l.text||"").trim().match(/^(?:Hi|Hey|Hello|Dear)\s+([A-Z][a-z]+)/);if(d){let u=d[1].toLowerCase();if(u!=="there"&&u!=="all"&&!(s.some(S=>S===u)||u===n))return console.log(` STALE DATA: message says "Hi ${d[1]}" but expected "${t}"`),!1}}return!0}if(o?.length>0){let l=o.map(d=>d.toLowerCase());if(r.some(d=>{let u=d.toLowerCase();return l.some(m=>u.includes(m.split(" ")[0]))}))return console.log(` STALE DATA: messages belong to previous conversation (senders: ${r.join(", ")})`),!1}return console.log(` Sender warning: no match for "${t}" (found: ${r.join(", ")})`),!1}function ge(e){return(e||"").replace(/\s+/g," ").trim().toLowerCase()}function at(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let o=u=>ge(u.sender)+"||"+ge(u.text),n=new Set(t.map(o)),s=new Set(e.map(o)),r=e.filter(u=>fe.has(u.status)?!1:!n.has(o(u))),i=t.filter(u=>!s.has(o(u))),a=t.filter(u=>s.has(o(u))),c=e.filter(u=>fe.has(u.status)),l=[...r,...a,...i],f=[];for(let u of l){let m=ge(u.text),S=ge(u.sender),y=!1;for(let v=0;v<f.length;v++){let $=f[v];if(ge($.sender)!==S)continue;let k=ge($.text);if(m.length>k.length&&m.endsWith(k)){y=!0;break}if(k.length>m.length&&k.endsWith(m)){f[v]=u,y=!0;break}}y||f.push(u)}return[...f,...c]}async function oo(e,t){await ot(e),await A(2500),await e.evaluate(()=>{let a=[".msg-conversations-container__conversations-list",".msg-conversations-container"];for(let c of a){let l=document.querySelector(c);if(l){l.scrollTop=0;return}}}),await A(500);async function o(){return e.evaluate(a=>{let c=document.querySelectorAll(".msg-conversation-listitem");for(let l of c)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===a){let u=l.getBoundingClientRect();if(u.height>0)return{x:u.x+u.width/2,y:u.y+u.height/2}}return null},t)}let n=await o(),s=50,r=-1,i=0;for(let a=0;a<s&&!n;a++){let c=await nt(e);if(!c)break;if(c.scrollTop===r){if(i++,i>=2)break}else i=0,r=c.scrollTop;await A(600),n=await o()}return n?(await e.mouse.click(n.x,n.y),await A(3e3),Fe(e,t)):{verified:!1,headerName:null}}async function ct(e,t){let o=await e.evaluate(i=>{let a=document.querySelectorAll(".msg-conversation-listitem");for(let c of a)if(c.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===i){let d=c.getBoundingClientRect();if(d.height>0)return{x:d.x+d.width/2,y:d.y+d.height/2}}return null},t);if(o){await e.mouse.click(o.x,o.y),await A(3e3);let i=await Fe(e,t);if(i.verified)return i}let n=Dt(t),s=n!==t?[t,n]:[t];for(let i of s)if(await Xt(e,i,t)){let c=await Fe(e,t);if(c.verified)return c}let r=Ot(n);if(r!==n&&r.length>0&&await Xt(e,r,t,{requireUnique:!0})){let a=await Fe(e,t);if(a.verified)return a}return{verified:!1,headerName:null}}async function Xt(e,t,o,n={}){let{requireUnique:s=!1}=n,r=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");if(!r)return!1;await r.click(),await A(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await A(300),await r.type(t,{delay:30}),await A(500),await e.keyboard.press("Enter"),await A(3500);let i=await e.evaluate((a,c)=>{let l=a.split(" ")[0].toLowerCase(),f=a.toLowerCase(),d=document.querySelectorAll(".msg-conversation-listitem"),u=[],m=[];for(let y of d){let $=y.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||"",k=$.toLowerCase();if(k.includes(l)){let g=y.getBoundingClientRect();if(g.height>0){let p=$.includes(",")||/\d+ other/.test($),w=k===f?3:k.includes(f)?2:1,C={text:$,isGroup:p,score:w,x:g.x+g.width/2,y:g.y+g.height/2};p?m.push(C):u.push(C)}}}u.sort((y,v)=>v.score-y.score);let S=[...u,...m];return c&&S.length!==1?null:u[0]||m[0]||null},o,s);return i?(s&&console.log(" (found via stripped designations)"),await e.mouse.click(i.x,i.y),!0):!1}async function Z(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await A(200),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await e.keyboard.press("Escape"),await A(1e3))}function ut(e,t,o){if(!e)return e;let s=(e.messages||[]).filter(c=>!fe.has(c.status)),r=In(t,e.profileUrl,o),i=ft(s,t);if(e.lastMessageBy=i,e.conversationStatus=i==="me"?"awaiting_reply":"unanswered_by_us",e.categorySource!=="manual"){let c=Tn(s,t,r);c&&(e.category=c,e.categorySource=e.categorySource||"message_content")}if(e.situation=En(s,i,t),s.length>0){let c=s[s.length-1];e.lastMessageTime=c.time}if(s.length>0&&!e.initiatedBy){let c=s[0];c.sender===P?e.initiatedBy="us":c.sender!=="Unknown"&&c.sender!==""&&(e.initiatedBy="them")}e.engagement=io(s,t),e.personContext=Dn(r),e.summary=An(e,t,r),e.autoTags=_n(e,t,r);let a=Rn(e);return e.actionNeeded=a.action,e.actionDetail=a.detail,e.suggestedPriority=On(e),e}var so={recruiter:{theirMessages:[/\b(recruiter|recruiting|talent.?acqui|staffing|headhunter|head\s*hunter|sourcer|executive\s*search)\b/i],title:[/\b(recruiter|recruiting|talent.?acqui|staffing|sourcer|sourcing)\b/i,/\b(head\s*hunter|executive\s*search)\b/i]},hiring_manager:{theirMessages:[/\b(my|our)\s+team\b/i,/\b(i.?m|we.?re|i\s+am|we\s+are)\s+(currently\s+|actively\s+|now\s+)?(looking|hiring|recruiting)\b/i,/\bjoin\s+(my|our)\b/i,/\bdirect.?report/i,/\b(engineering manager|team lead|vp of|director of|head of)\b/i],title:[/\b(engineering manager|team lead|vp|director|head of engineering)\b/i]},founder:{theirMessages:[/\b(founder|co-founder|ceo|cto|my company|my startup|i.?m building)\b/i],title:[/\b(founder|co-founder|ceo|cto)\b/i]},investor:{theirMessages:[/\b(investor|invest|funding|vc|venture|angel)\b/i],title:[/\b(investor|venture|capital|angel|partner at)\b/i,/\binvestment\s+(manager|partner|director|associate|analyst|principal)\b/i]},coach:{theirMessages:[/\b(coach|coaching|mentor|mentoring|career.?(advice|guidance|help))\b/i,/\b(resume.?(review|writing)|interview.?prep|career.?transition)\b/i],title:[/\b(coach|mentor|career.?(consultant|advisor))\b/i]},peer:{theirMessages:[/\b(fellow|peer|networking|connect|nice.?to.?meet|great.?to.?connect)\b/i,/\b(your (profile|background|experience).*interest)\b/i]},sales:{theirMessages:[/\b(sales|business develop|partnership|proposal|offer|demo|pricing|platform|solution)\b/i],title:[/\b(sales|business develop|account.?exec|bdm|bdr|sdr)\b/i]},spam:{theirMessages:[/\b(crypto|bitcoin|forex|trading.?signal|guaranteed.?return|make.?money)\b/i,/\b(whatsapp|telegram.?group|click (here|this link))\b/i]},event:{theirMessages:[/\b(event|conference|webinar|summit|meetup|workshop|speak(er|ing))\b/i,/\b(attend|register|rsvp|invitation|invite.?you)\b/i]}};function Tn(e,t,o){if(!e||e.length===0)return o?.title?lt(o.title):null;let n=e.filter(s=>s.sender!==P&&s.sender!=="Unknown"&&s.sender!=="").map(s=>s.text).join(" ");for(let[s,r]of Object.entries(so))if(r.theirMessages){for(let i of r.theirMessages)if(i.test(n))return s}if(o?.title){let s=lt(o.title);if(s)return s}return null}function lt(e){if(!e)return null;for(let[t,o]of Object.entries(so))if(o.title){for(let n of o.title)if(n.test(e))return t}return null}var no=/\b(call|meet|teams|zoom|schedule|available|availability|invite|slot|calendar)\b/i;function En(e,t,o){if(!e||e.length===0)return"no_messages";let n=e[e.length-1];if(e.length===1)return t==="them"?"initial_outreach_unanswered":"we_initiated_waiting";if(t==="me")return no.test(n.text)?"scheduling_proposed_by_us":e.length>=6?"active_conversation_ball_in_their_court":"awaiting_their_reply";let s=[...e].reverse().find(r=>r.sender!==P&&r.sender!=="Unknown");return no.test(s?.text||"")?"they_want_to_schedule_call":e.length>=6?"active_conversation_needs_our_reply":"needs_our_reply"}function ft(e,t){if(!e||e.length===0)return"them";let o=[...e].map(s=>({m:s,t:Date.parse(s.time)})).filter(s=>Number.isFinite(s.t)).sort((s,r)=>r.t-s.t).map(s=>s.m),n=o.length>0?o:[...e].reverse();for(let s of n){let r=s.sender;if(r===P)return"me";if(r!=="Unknown"&&r!=="")return"them"}return"them"}function An(e,t,o){let n=e.messages||[];if(n.length===0)return null;let s=[],r=e.category,i=o?.title,a=o?.company,c=o?.location;r==="recruiter"&&a?s.push(`Recruiter from ${a}`):r==="hiring_manager"&&a?s.push(`Hiring manager at ${a}`):r==="founder"&&a?s.push(`Founder of ${a}`):r&&i?s.push(`${dt(r)}: ${me(i,40)}`):i?s.push(me(i,50)):s.push(t.split(" ")[0]);let l=n.filter(S=>S.sender!==P&&S.sender!=="Unknown").map(S=>S.text).join(" "),f=xn(l),d=jn(l),u=Nn(l),m=[];return f&&m.push(f),u&&u!==c&&m.push(u),d&&m.push(d),m.length>0&&s.push(m.join(", ")),e.situation==="they_want_to_schedule_call"?s.push("wants to schedule call"):e.situation==="scheduling_proposed_by_us"?s.push("we proposed scheduling"):e.conversationStatus==="unanswered_by_us"?s.push("needs reply"):e.conversationStatus==="awaiting_reply"&&s.push("waiting on them"),s.join(". ").replace(/\.\./g,".")}function _n(e,t,o){let n=[],s=(e.messages||[]).filter(l=>!fe.has(l.status)),r=s.map(l=>l.text).join(" "),i=s.filter(l=>l.sender!==P&&l.sender!=="Unknown").map(l=>l.text).join(" "),a=ro(i,o?.location);n.push(...a),/\b(contract|contractor|c2c|corp.?to.?corp)\b/i.test(r)&&n.push("contract"),/\b(full.?time|permanent|fte|perm)\b/i.test(r)&&n.push("full-time"),/\b(remote|work.?from.?home|wfh)\b/i.test(r)&&n.push("remote"),/\b(hybrid)\b/i.test(r)&&n.push("hybrid"),/\b(on.?site|in.?office|in.?person)\b/i.test(r)&&n.push("onsite"),/\b(java)\b/i.test(r)&&!/javascript/i.test(r)&&n.push("java"),/\b(python)\b/i.test(r)&&n.push("python"),/\b(react|angular|vue|front.?end)\b/i.test(r)&&n.push("frontend"),/\b(node|backend|back.?end|api|microservice)\b/i.test(r)&&n.push("backend"),/\b(full.?stack)\b/i.test(r)&&n.push("fullstack"),/\b(devops|sre|cloud|aws|azure|gcp|kubernetes|k8s)\b/i.test(r)&&n.push("devops"),/\b(data.?engineer|data.?scien|ml|machine.?learn|ai)\b/i.test(r)&&n.push("data/ml"),/\b(lead|senior|staff|principal|architect)\b/i.test(r)&&n.push("senior-role"),/\b(manager|director|vp|head of)\b/i.test(r)&&n.push("management"),/\$[\d,]+|\d+k|\d+\/hr|\d+\s*per\s*(hour|annum|year)/i.test(r)&&n.push("has-salary");let c=e.engagement||io(s,t);return c.messageCount>=6&&n.push("active-thread"),c.theirCount===0&&c.ourCount>0&&n.push("no-response"),c.ourCount===0&&c.theirCount>0&&n.push("unanswered"),e.situation==="they_want_to_schedule_call"&&n.push("hot-lead"),(e.messages||[]).some(l=>$e.has(l.status))&&n.push("has-draft"),[...new Set(n)]}function ro(e,t){let o=[],n=["toronto","vancouver","montreal","ottawa","calgary","edmonton","new york","san francisco","seattle","chicago","austin","boston","los angeles","denver","atlanta","dallas","houston","miami","london","berlin","amsterdam","dubai"],s=[["canada","canada"],["ontario","ontario"],["british columbia","bc"],["alberta","alberta"],["quebec","quebec"],["usa","usa"],["united states","usa"]],r=(e+" "+(t||"")).toLowerCase();for(let i of n)r.includes(i)&&o.push(i.replace(/\s+/g,"-"));for(let[i,a]of s)r.includes(i)&&o.push(a);return o}function Rn(e){let{category:t,situation:o,conversationStatus:n}=e;if(e.dismissedAtPreview&&De(e.lastMessagePreview)===De(e.dismissedAtPreview))return{action:"none",detail:e.dismissReason||"Dismissed."};let s=(e.messages||[]).find(r=>$e.has(r.status));return s?s.status===j.CONFIRMED?{action:"push_draft",detail:"Draft confirmed. Run --push-drafts to send."}:{action:"review_draft",detail:"Draft needs review. Run --review-drafts."}:n==="awaiting_reply"?{action:"none",detail:"Ball in their court."}:o==="no_messages"?{action:"none",detail:"No messages read yet."}:o==="they_want_to_schedule_call"?{action:"schedule_call",detail:"They proposed a call. Reply with time slots."}:o==="initial_outreach_unanswered"?t==="spam"?{action:"archive",detail:"Likely spam. Safe to ignore."}:t==="recruiter"||t==="hiring_manager"?{action:"reply",detail:"New recruiter/HM message. Review and respond."}:t==="coach"||t==="sales"?{action:"archive",detail:`${dt(t||"unknown")} outreach. Likely not relevant.`}:{action:"reply",detail:"New message. Review and respond."}:o==="active_conversation_needs_our_reply"||o==="needs_our_reply"?{action:"reply",detail:"They replied. Continue the conversation."}:{action:"none",detail:""}}function io(e,t){if(!e||e.length===0)return{messageCount:0,theirCount:0,ourCount:0,unknownCount:0,hasJob:!1,hasSalary:!1};let o=0,n=0,s=0,r=!1,i=!1,a=e.map(c=>c.text).join(" ");for(let c of e)c.sender===P?o++:c.sender==="Unknown"||c.sender===""?s++:n++;return r=/\b(job|role|position|opening)\b/i.test(a),i=/\$[\d,]+|\d+k|\d+\/hr/i.test(a),{messageCount:e.length,theirCount:n,ourCount:o,unknownCount:s,hasJob:r,hasSalary:i}}function Dn(e){return e?{title:e.title||null,company:e.company||null,location:e.location||null,connectionStatus:e.connectionStatus||null}:null}function On(e){let{category:t,situation:o,engagement:n}=e;return o==="they_want_to_schedule_call"?"high":(t==="recruiter"||t==="hiring_manager")&&(o==="active_conversation_needs_our_reply"||o==="needs_our_reply")?n?.messageCount>=4?"high":"medium":t==="recruiter"&&o==="initial_outreach_unanswered"||t==="founder"&&e.conversationStatus==="unanswered_by_us"?"medium":t==="spam"||t==="coach"||t==="sales"?"low":e.conversationStatus==="unanswered_by_us"?"medium":null}function In(e,t,o){if(!o)return null;if(t&&o[t])return o[t];if(!e)return null;let n=Object.values(o).filter(s=>s.name===e);return n.length===1?n[0]:null}function De(e){return(e||"").replace(/\s+/g," ").trim().slice(0,80).toLowerCase()}function dt(e){return e?e.charAt(0).toUpperCase()+e.slice(1):""}function me(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function xn(e){let t=e.match(/\b((?:senior |sr\.? |lead |staff |principal |junior |jr\.? )?(?:software|full.?stack|front.?end|back.?end|data|devops|cloud|platform|mobile|ios|android|qa|sdet)\s*(?:engineer|developer|architect|lead|manager|scientist))\b/i);if(t)return t[1];let o=e.match(/\b((?:java|python|react|node|\.net|golang|rust|scala)\s*developer)\b/i);return o?o[1]:null}function jn(e){let t=e.match(/\$[\d,]+(?:k|K)?(?:\s*[-–]\s*\$?[\d,]+(?:k|K)?)?(?:\s*\/\s*(?:hr|hour|yr|year|annum))?/);return t?t[0]:null}function Nn(e){let t=e.match(/\b(?:in|based in|located in)\s+([A-Z][a-z]+(?:\s[A-Z][a-z]+)?(?:,\s*[A-Z]{2})?)/);return t?t[1]:null}function ao(e,t){if(!e)return e;if(e.categorySource!=="manual"){let n=lt(e.title);n&&(e.category=n,e.categorySource=e.categorySource||"title")}Mn(e),e.personSummary=Pn(e),e.personAutoTags=Fn(e);let o=Ln(e);return e.personActionNeeded=o.action,e.personActionDetail=o.detail,e.personPriorityManual||(e.personPriority=Un(e)),e}function Mn(e){if(e.jobCount=e.jobIds?.length||0,e.encounterCount=e.encounters?.length||0,e.encounters?.length>0){let t=e.encounters.filter(o=>o.jobTitle).sort((o,n)=>(n.date||"").localeCompare(o.date||""));t.length>0&&(e.lastJobTitle=t[0].jobTitle,e.lastJobCompany=t[0].jobCompany||null,e.lastJobDate=t[0].date)}e.isRepeatRecruiter=e.jobCount>=3}function Pn(e){let t=[],o=e.category,n=e.title,s=e.company,r=e.location;if(o==="recruiter"&&s?t.push(`Recruiter at ${s}`):o==="hiring_manager"&&s?t.push(`Hiring manager at ${s}`):o==="founder"&&s?t.push(`Founder of ${s}`):n&&s?t.push(`${me(n,40)} at ${me(s,30)}`):n?t.push(me(n,50)):e.name&&t.push(e.name.split(" ")[0]),r&&t.push(r),e.connectionDate){let i=new Date(e.connectionDate);if(!isNaN(i)){let a=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];t.push(`Connected ${a[i.getMonth()]} ${i.getDate()}`)}}if(e.jobCount>0){let i=`${e.jobCount} job${e.jobCount>1?"s":""}`;if(e.lastJobTitle){if(i+=` (last: ${me(e.lastJobTitle,30)}`,e.lastJobDate){let a=new Date(e.lastJobDate);isNaN(a)||(i+=`, ${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][a.getMonth()]} ${a.getDate()}`)}i+=")"}t.push(i)}return t.join(". ").replace(/\.\./g,".")||null}function Fn(e){let t=[],o=[e.title,e.company,e.location].filter(Boolean).join(" "),n=ro("",e.location);return t.push(...n),e.category&&t.push(e.category),/\b(java)\b/i.test(o)&&!/javascript/i.test(o)&&t.push("java"),/\b(python)\b/i.test(o)&&t.push("python"),/\b(react|angular|vue|front.?end)\b/i.test(o)&&t.push("frontend"),/\b(node|backend|back.?end|api|microservice)\b/i.test(o)&&t.push("backend"),/\b(full.?stack)\b/i.test(o)&&t.push("fullstack"),/\b(devops|sre|cloud|aws|azure|gcp|kubernetes|k8s)\b/i.test(o)&&t.push("devops"),/\b(data.?engineer|data.?scien|ml|machine.?learn|ai)\b/i.test(o)&&t.push("data/ml"),/\b(lead|senior|staff|principal|architect)\b/i.test(o)&&t.push("senior-role"),/\b(manager|director|vp|head of)\b/i.test(o)&&t.push("management"),/\b(staffing|agency|consulting|outsourc)\b/i.test(o)&&t.push("staffing"),[...new Set(t)]}function Ln(e){if(e.connectionStatus!=="connected")return{action:"none",detail:"Not connected."};let t=e.category;return t==="recruiter"||t==="hiring_manager"?{action:"initiate_contact",detail:`New ${t.replace("_"," ")} connection. Send intro message.`}:t==="founder"?{action:"initiate_contact",detail:"Founder connection. Consider reaching out."}:t==="sales"||t==="coach"||t==="spam"?{action:"none",detail:`${dt(t)} \u2014 no outreach needed.`}:t==="investor"?{action:"initiate_contact",detail:"Investor connection. Consider intro message."}:{action:"none",detail:"No specific action identified."}}function Un(e){let t=e.category;if(!t)return null;let o=Bn(e,7);return e.isRepeatRecruiter&&(t==="recruiter"||t==="hiring_manager")||(t==="recruiter"||t==="hiring_manager")&&o?"high":t==="recruiter"||t==="hiring_manager"||t==="founder"&&o?"medium":t==="founder"||t==="investor"?"low":t==="sales"||t==="coach"||t==="spam"?null:t==="peer"?"low":null}function Bn(e,t){if(!e.connectionDate)return!1;let o=new Date(e.connectionDate);if(isNaN(o))return!1;let n=new Date;return n.setDate(n.getDate()-t),o>=n}import"dotenv/config";import*as B from"fs";import*as ee from"path";import{fileURLToPath as Yn}from"url";import"dotenv/config";import{createGraphClient as qn,resolveToken as Jn}from"@ilivemylife/graph-sdk";import{config as Hn}from"dotenv";Hn();var co=Jn()||process.env.TOKEN;co||(console.error(`
5
5
  [FATAL] No iLiveMyLife token found.`),console.error(" The bot uses Lifebot AI to decide which jobs to apply for"),console.error(` and how to fill application forms. It cannot work without it.
6
6
  `),console.error(" Easiest way:"),console.error(" 1. npm install -g @ilivemylife/graph-sdk"),console.error(` 2. ilml login your@email.com yourpassword
7
7
  `),console.error(` Or add ILML_TOKEN=... to .env
@@ -9,7 +9,7 @@ var Oo=Object.defineProperty;var We=(e,t)=>{for(var o in t)Oo(e,o,{get:t[o],enum
9
9
 
10
10
  ${n.join(`
11
11
  `)}`;try{await lo.addMessage(i,c)}catch(l){console.error(`[runReport] Failed to post end-of-session message: ${l.message}`)}}var Gn=Yn(import.meta.url),zn=ee.dirname(ee.dirname(Gn)),pt=process.env.DATA_DIR?ee.resolve(process.env.DATA_DIR,"collected-profiles"):ee.join(zn,"collected-profiles"),gt=ee.join(pt,"run-log.json");function Kn(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";B.writeFileSync(n,o);for(let s=0;s<3;s++)try{B.renameSync(n,e);return}catch(r){if(s<2&&(r.code==="EPERM"||r.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw r}}function Le(){try{if(!B.existsSync(gt))return{runs:[]};let e=JSON.parse(B.readFileSync(gt,"utf-8"));return!e.runs||!Array.isArray(e.runs)?{runs:[]}:e}catch{return{runs:[]}}}function fo(e){B.existsSync(pt)||B.mkdirSync(pt,{recursive:!0});try{Kn(gt,e)}catch(t){console.error(`[!] Failed to save run-log.json: ${t.message}`)}}function Ue(e,t="default"){let o=Le();for(let i of o.runs)i.status==="running"&&(i.status="interrupted",i.result="interrupted",i.timestamp&&(i.duration=Date.now()-new Date(i.timestamp).getTime()));let n=new Date,s={timestamp:n.toISOString(),script:e,mode:t,status:"running",result:null,duration:null,stats:null,error:null};o.runs.push(s);let r=Date.now()-30*24*60*60*1e3;return o.runs=o.runs.filter(i=>new Date(i.timestamp).getTime()>r),fo(o),{script:e,mode:t,startTime:n.getTime(),runIndex:o.runs.length-1}}function he(e,t,o=null,n=null){if(!e)return;let s=null;try{let i=Le(),a=i.runs[e.runIndex];if(a&&a.status==="running"&&a.script===e.script)a.status=t,a.result=t,a.duration=Date.now()-e.startTime,a.stats=o,a.error=n,s=a.duration;else{let c=i.runs.find(l=>l.script===e.script&&l.status==="running"&&l.timestamp===new Date(e.startTime).toISOString());c&&(c.status=t,c.result=t,c.duration=Date.now()-e.startTime,c.stats=o,c.error=n,s=c.duration)}fo(i)}catch(i){console.error(`[runLog] Failed to end run: ${i.message}`)}let r=o&&Array.isArray(o.summaryLines)?o.summaryLines:null;if(r&&r.length>0&&process.env.NODE_RUN_REPORTS){let i=t==="error"?"error":o&&o.dailyLimitHit?"quota-reached":"done";uo({scriptName:e.script,mode:e.mode,status:i,summaryLines:r,error:n,duration:s??Date.now()-e.startTime}).catch(a=>console.error(`[runLog] postRunReport failed: ${a.message}`))}}function Qn(){let e=new Date().toISOString().slice(0,10),t=Le(),o={};for(let n of t.runs){if(!n.timestamp.startsWith(e))continue;o[n.script]||(o[n.script]={total:0,success:0,error:0,interrupted:0,partial:0,running:0,lastRun:null});let s=o[n.script];s.total++,n.status==="success"?s.success++:n.status==="error"?s.error++:n.status==="interrupted"?s.interrupted++:n.status==="partial"?s.partial++:n.status==="running"&&s.running++,s.lastRun=n}return o}function Xn(e){if(!e)return"never";let t=Date.now()-new Date(e).getTime(),o=Math.floor(t/6e4),n=Math.floor(t/36e5),s=Math.floor(t/864e5);return o<1?"just now":o<60?`${o}m ago`:n<24?`${n}h ago`:s===1?"yesterday":`${s} days ago`}function po(){let e=["sync-all","messages","funnel","sync","apply"],t=Le(),o=Qn(),n=[];n.push("\u2550\u2550\u2550 SCRIPT STATUS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");for(let r of e){let i=t.runs.filter(y=>y.script===r),a=[...i].reverse().find(y=>y.status==="success"),c=i[i.length-1],l=a||c,f=l?Xn(l.timestamp):"never",u=(l?Math.floor((Date.now()-new Date(l.timestamp).getTime())/864e5):1/0)>1?" \u26A0":l?.status==="error"?" \u2717":" \u2713",m="";if(l?.stats){let y=l.stats,v=Object.entries(y).filter(([,$])=>typeof $=="number"&&$>0).slice(0,3).map(([$,k])=>`${k} ${$}`);v.length&&(m=` (${v.join(", ")})`)}let S=l?.duration?` ${Math.round(l.duration/1e3)}s`:"";n.push(` ${r.padEnd(14)} ${f.padEnd(16)}${S}${m}${u}`)}let s=Object.entries(o);if(s.length>0){n.push("");for(let[r,i]of s){let a=[];i.success&&a.push(`${i.success} success`),i.error&&a.push(`${i.error} error`),i.interrupted&&a.push(`${i.interrupted} interrupted`),i.running&&a.push(`${i.running} running`),n.push(` Today: ${r} \xD7${i.total} (${a.join(", ")})`)}}return n.push("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),n.join(`
12
- `)}import"dotenv/config";import*as b from"fs";import*as vt from"os";import*as A from"path";import{fileURLToPath as hs}from"url";var yt={};We(yt,{NAME:()=>es,VERSION:()=>Zn,up:()=>ns});import*as q from"fs";import*as Be from"path";var Zn=1,es="normalize-jobs-and-questions",ts=["description","techStack","jobTags","seniority","employmentType","industries","jobFunction","postedTime","applicantCount","companySize","workplaceType","contractType","isEasyApply","applyType","companyUrl","scoutedAt","lastSeen"],os=50;function mt(e){return q.existsSync(e)?JSON.parse(q.readFileSync(e,"utf-8")):null}function ht(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{q.writeFileSync(n,o)}catch(s){try{q.unlinkSync(n)}catch{}throw s}try{q.renameSync(n,e)}catch(s){try{q.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function ns(e,t){let o=Be.join(e,"jobs.json"),n=Be.join(t,"scouted-jobs.json"),s=Be.join(e,"application-questions.json"),r=mt(o)||{},i=mt(n)||{},a=0,c=[];for(let f of Object.keys(r)){if(!i[f])continue;let d=i[f],u=r[f];for(let m of ts)d[m]!=null&&u[m]==null&&(u[m]=d[m]);c.push(f),a++}a>0?(ht(o,r),console.log(` Phase 1: Merged ${a} scouted jobs into jobs.json`)):console.log(" Phase 1: No overlapping jobs to merge");let l=mt(s);if(l&&Array.isArray(l.applications)){let f={},d=0;for(let u of l.applications){let m=u.jobId||"unknown";f[m]||(f[m]={applications:[]});let S=(u.questions||[]).map(y=>{let v={type:y.type||"input",question:y.question||"",answer:y.answer||""};return y.options&&(y.options.length<=os?v.options=y.options:(v.optionsOmitted=!0,d++)),y.page&&(v.page=y.page),y.wasPreFilled&&(v.wasPreFilled=!0),y.wasRetry&&(v.wasRetry=!0),v});f[m].applications.push({applicationId:u.applicationId,date:u.date,result:u.result||"submitted",formPages:u.formPages||null,duration:u.duration||null,retries:u.retries||0,failedField:u.failedField||null,questionCount:u.questionCount||S.length,questions:S})}ht(s,f),console.log(` Phase 2: Rekeyed ${l.applications.length} applications by jobId (${Object.keys(f).length} unique jobs)`),d>0&&console.log(` Phase 2: Stripped bloated options from ${d} questions`)}else l&&!l.applications?console.log(" Phase 2: application-questions.json already in keyed format"):console.log(" Phase 2: No application-questions.json found");if(c.length>0){for(let f of c)delete i[f];ht(n,i),console.log(` Phase 3: Removed ${c.length} merged entries from scouted-jobs.json (${Object.keys(i).length} remaining)`)}else console.log(" Phase 3: No entries to remove from scouted-jobs.json")}var St={};We(St,{NAME:()=>rs,VERSION:()=>ss,up:()=>cs});import*as J from"fs";import*as go from"path";var ss=2,rs="reset-unread-flags";function is(e){return J.existsSync(e)?JSON.parse(J.readFileSync(e,"utf-8")):null}function as(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{J.writeFileSync(n,o)}catch(s){try{J.unlinkSync(n)}catch{}throw s}try{J.renameSync(n,e)}catch(s){try{J.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function cs(e){let t=go.join(e,"conversations.json"),o=is(t);if(!o){console.log(" conversations.json not found \u2014 nothing to reset.");return}let n=0;for(let s of Object.keys(o))o[s].unread===!0&&(o[s].unread=!1,n++);if(n===0){console.log(" No stale unread flags found \u2014 nothing to do.");return}as(t,o),console.log(` Reset unread=false on ${n} conversations. Run 'ilml linkedin sync-all' to re-establish real unread state from LinkedIn.`)}var wt={};We(wt,{NAME:()=>us,VERSION:()=>ls,up:()=>ms});import*as H from"fs";import*as mo from"path";var ls=3,us="recompute-last-message-by",fs=new Set(["draft","confirmed","rejected","needs_review"]);function ds(e){return H.existsSync(e)?JSON.parse(H.readFileSync(e,"utf-8")):null}function ps(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{H.writeFileSync(n,o)}catch(s){try{H.unlinkSync(n)}catch{}throw s}try{H.renameSync(n,e)}catch(s){try{H.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}function gs(e,t){if(!e||e.length===0)return"them";let o=e.filter(r=>!fs.has(r.status));if(o.length===0)return"them";let n=o.map(r=>({m:r,t:Date.parse(r.time)})).filter(r=>Number.isFinite(r.t)).sort((r,i)=>i.t-r.t).map(r=>r.m),s=n.length>0?n:[...o].reverse();for(let r of s){let i=r.sender;if(i===t)return"me";if(i!=="Unknown"&&i!=="")return"them"}return"them"}async function ms(e){let t=mo.join(e,"conversations.json"),o=ds(t);if(!o){console.log(" conversations.json not found \u2014 nothing to recompute.");return}let n=process.env.LINKEDIN_NAME;if(!n||typeof n!="string"||!n.trim())throw new Error(`LINKEDIN_NAME env var is not set. Migration v003 needs your display name to determine which messages are yours vs theirs. Set LINKEDIN_NAME in your .env (or run "ilml plugin config linkedin set LINKEDIN_NAME 'Your Name'") and retry.`);let s=0,r=0,i=0;for(let a of Object.keys(o)){let c=o[a];if(!c||typeof c!="object")continue;Object.prototype.hasOwnProperty.call(c,"_cardSynced")&&(delete c._cardSynced,r++);let l=Array.isArray(c.messages)?c.messages:[],f=gs(l,n),d=f==="me"?"awaiting_reply":"unanswered_by_us";c.lastMessageBy!==f&&i++,c.lastMessageBy=f,c.conversationStatus=d,s++}if(s===0){console.log(" No conversations to recompute.");return}ps(t,o),console.log(` Recomputed lastMessageBy + conversationStatus on ${s} conversations.`),console.log(` ${i} had stale lastMessageBy (now corrected).`),r>0&&console.log(` Cleaned ${r} leftover _cardSynced flags.`),console.log(" Re-run 'ilml linkedin enrich' if you want actionNeeded / summary / autoTags to also update.")}var ys=hs(import.meta.url),Ss=A.dirname(ys),ws=A.dirname(A.dirname(Ss));function bs(e){return e&&(e==="~"?vt.homedir():e.startsWith("~/")||e.startsWith("~\\")?A.join(vt.homedir(),e.slice(2)):e)}var V=process.env.DATA_DIR?A.resolve(bs(process.env.DATA_DIR)):ws,ae=A.join(V,"collected-profiles"),ce=A.join(V,"market-research"),N=A.join(V,".schema-version"),ho=[A.join(ae,".schema-version"),A.join(ce,".schema-version")],te=3,Y=[{version:1,module:yt},{version:2,module:St},{version:3,module:wt}];(function(){Y.sort((n,s)=>n.version-s.version);let t=new Set;for(let n of Y){if(!Number.isInteger(n.version)||n.version<1)throw new Error(`MIGRATION_REGISTRY: invalid version ${JSON.stringify(n.version)} (must be positive integer)`);if(t.has(n.version))throw new Error(`MIGRATION_REGISTRY: duplicate version v${n.version}`);t.add(n.version);let s=n.module;if(!s||typeof s.up!="function")throw new Error(`MIGRATION_REGISTRY: v${n.version} module is missing up()`);if(s.VERSION!==void 0&&s.VERSION!==n.version)throw new Error(`MIGRATION_REGISTRY: v${n.version} entry does not match module VERSION (${s.VERSION}). Drift between registry and module \u2014 pick one source of truth.`)}let o=Y.length?Y[Y.length-1].version:0;if(o!==te)throw new Error(`MIGRATION_REGISTRY: highest version v${o} but CURRENT_SCHEMA_VERSION=${te}. Forgot to bump CURRENT_SCHEMA_VERSION when adding the new migration?`);for(let n=0;n<Y.length;n++){let s=n+1;if(Y[n].version!==s)throw new Error(`MIGRATION_REGISTRY: gap detected \u2014 expected v${s} at position ${n} but found v${Y[n].version}`)}})();function bo(){process.env.DATA_DIR!==void 0&&process.env.DATA_DIR.trim()===""&&process.env.DATA_DIR.length>0&&(console.error(`
12
+ `)}import"dotenv/config";import*as b from"fs";import*as vt from"os";import*as _ from"path";import{fileURLToPath as hs}from"url";var yt={};We(yt,{NAME:()=>es,VERSION:()=>Zn,up:()=>ns});import*as q from"fs";import*as Be from"path";var Zn=1,es="normalize-jobs-and-questions",ts=["description","techStack","jobTags","seniority","employmentType","industries","jobFunction","postedTime","applicantCount","companySize","workplaceType","contractType","isEasyApply","applyType","companyUrl","scoutedAt","lastSeen"],os=50;function mt(e){return q.existsSync(e)?JSON.parse(q.readFileSync(e,"utf-8")):null}function ht(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{q.writeFileSync(n,o)}catch(s){try{q.unlinkSync(n)}catch{}throw s}try{q.renameSync(n,e)}catch(s){try{q.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function ns(e,t){let o=Be.join(e,"jobs.json"),n=Be.join(t,"scouted-jobs.json"),s=Be.join(e,"application-questions.json"),r=mt(o)||{},i=mt(n)||{},a=0,c=[];for(let f of Object.keys(r)){if(!i[f])continue;let d=i[f],u=r[f];for(let m of ts)d[m]!=null&&u[m]==null&&(u[m]=d[m]);c.push(f),a++}a>0?(ht(o,r),console.log(` Phase 1: Merged ${a} scouted jobs into jobs.json`)):console.log(" Phase 1: No overlapping jobs to merge");let l=mt(s);if(l&&Array.isArray(l.applications)){let f={},d=0;for(let u of l.applications){let m=u.jobId||"unknown";f[m]||(f[m]={applications:[]});let S=(u.questions||[]).map(y=>{let v={type:y.type||"input",question:y.question||"",answer:y.answer||""};return y.options&&(y.options.length<=os?v.options=y.options:(v.optionsOmitted=!0,d++)),y.page&&(v.page=y.page),y.wasPreFilled&&(v.wasPreFilled=!0),y.wasRetry&&(v.wasRetry=!0),v});f[m].applications.push({applicationId:u.applicationId,date:u.date,result:u.result||"submitted",formPages:u.formPages||null,duration:u.duration||null,retries:u.retries||0,failedField:u.failedField||null,questionCount:u.questionCount||S.length,questions:S})}ht(s,f),console.log(` Phase 2: Rekeyed ${l.applications.length} applications by jobId (${Object.keys(f).length} unique jobs)`),d>0&&console.log(` Phase 2: Stripped bloated options from ${d} questions`)}else l&&!l.applications?console.log(" Phase 2: application-questions.json already in keyed format"):console.log(" Phase 2: No application-questions.json found");if(c.length>0){for(let f of c)delete i[f];ht(n,i),console.log(` Phase 3: Removed ${c.length} merged entries from scouted-jobs.json (${Object.keys(i).length} remaining)`)}else console.log(" Phase 3: No entries to remove from scouted-jobs.json")}var St={};We(St,{NAME:()=>rs,VERSION:()=>ss,up:()=>cs});import*as J from"fs";import*as go from"path";var ss=2,rs="reset-unread-flags";function is(e){return J.existsSync(e)?JSON.parse(J.readFileSync(e,"utf-8")):null}function as(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{J.writeFileSync(n,o)}catch(s){try{J.unlinkSync(n)}catch{}throw s}try{J.renameSync(n,e)}catch(s){try{J.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function cs(e){let t=go.join(e,"conversations.json"),o=is(t);if(!o){console.log(" conversations.json not found \u2014 nothing to reset.");return}let n=0;for(let s of Object.keys(o))o[s].unread===!0&&(o[s].unread=!1,n++);if(n===0){console.log(" No stale unread flags found \u2014 nothing to do.");return}as(t,o),console.log(` Reset unread=false on ${n} conversations. Run 'ilml linkedin sync-all' to re-establish real unread state from LinkedIn.`)}var wt={};We(wt,{NAME:()=>us,VERSION:()=>ls,up:()=>ms});import*as H from"fs";import*as mo from"path";var ls=3,us="recompute-last-message-by",fs=new Set(["draft","confirmed","rejected","needs_review"]);function ds(e){return H.existsSync(e)?JSON.parse(H.readFileSync(e,"utf-8")):null}function ps(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{H.writeFileSync(n,o)}catch(s){try{H.unlinkSync(n)}catch{}throw s}try{H.renameSync(n,e)}catch(s){try{H.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}function gs(e,t){if(!e||e.length===0)return"them";let o=e.filter(r=>!fs.has(r.status));if(o.length===0)return"them";let n=o.map(r=>({m:r,t:Date.parse(r.time)})).filter(r=>Number.isFinite(r.t)).sort((r,i)=>i.t-r.t).map(r=>r.m),s=n.length>0?n:[...o].reverse();for(let r of s){let i=r.sender;if(i===t)return"me";if(i!=="Unknown"&&i!=="")return"them"}return"them"}async function ms(e){let t=mo.join(e,"conversations.json"),o=ds(t);if(!o){console.log(" conversations.json not found \u2014 nothing to recompute.");return}let n=process.env.LINKEDIN_NAME;if(!n||typeof n!="string"||!n.trim())throw new Error(`LINKEDIN_NAME env var is not set. Migration v003 needs your display name to determine which messages are yours vs theirs. Set LINKEDIN_NAME in your .env (or run "ilml plugin config linkedin set LINKEDIN_NAME 'Your Name'") and retry.`);let s=0,r=0,i=0;for(let a of Object.keys(o)){let c=o[a];if(!c||typeof c!="object")continue;Object.prototype.hasOwnProperty.call(c,"_cardSynced")&&(delete c._cardSynced,r++);let l=Array.isArray(c.messages)?c.messages:[],f=gs(l,n),d=f==="me"?"awaiting_reply":"unanswered_by_us";c.lastMessageBy!==f&&i++,c.lastMessageBy=f,c.conversationStatus=d,s++}if(s===0){console.log(" No conversations to recompute.");return}ps(t,o),console.log(` Recomputed lastMessageBy + conversationStatus on ${s} conversations.`),console.log(` ${i} had stale lastMessageBy (now corrected).`),r>0&&console.log(` Cleaned ${r} leftover _cardSynced flags.`),console.log(" Re-run 'ilml linkedin enrich' if you want actionNeeded / summary / autoTags to also update.")}var ys=hs(import.meta.url),Ss=_.dirname(ys),ws=_.dirname(_.dirname(Ss));function bs(e){return e&&(e==="~"?vt.homedir():e.startsWith("~/")||e.startsWith("~\\")?_.join(vt.homedir(),e.slice(2)):e)}var V=process.env.DATA_DIR?_.resolve(bs(process.env.DATA_DIR)):ws,ae=_.join(V,"collected-profiles"),ce=_.join(V,"market-research"),N=_.join(V,".schema-version"),ho=[_.join(ae,".schema-version"),_.join(ce,".schema-version")],te=3,Y=[{version:1,module:yt},{version:2,module:St},{version:3,module:wt}];(function(){Y.sort((n,s)=>n.version-s.version);let t=new Set;for(let n of Y){if(!Number.isInteger(n.version)||n.version<1)throw new Error(`MIGRATION_REGISTRY: invalid version ${JSON.stringify(n.version)} (must be positive integer)`);if(t.has(n.version))throw new Error(`MIGRATION_REGISTRY: duplicate version v${n.version}`);t.add(n.version);let s=n.module;if(!s||typeof s.up!="function")throw new Error(`MIGRATION_REGISTRY: v${n.version} module is missing up()`);if(s.VERSION!==void 0&&s.VERSION!==n.version)throw new Error(`MIGRATION_REGISTRY: v${n.version} entry does not match module VERSION (${s.VERSION}). Drift between registry and module \u2014 pick one source of truth.`)}let o=Y.length?Y[Y.length-1].version:0;if(o!==te)throw new Error(`MIGRATION_REGISTRY: highest version v${o} but CURRENT_SCHEMA_VERSION=${te}. Forgot to bump CURRENT_SCHEMA_VERSION when adding the new migration?`);for(let n=0;n<Y.length;n++){let s=n+1;if(Y[n].version!==s)throw new Error(`MIGRATION_REGISTRY: gap detected \u2014 expected v${s} at position ${n} but found v${Y[n].version}`)}})();function bo(){process.env.DATA_DIR!==void 0&&process.env.DATA_DIR.trim()===""&&process.env.DATA_DIR.length>0&&(console.error(`
13
13
  [FATAL] DATA_DIR is set to whitespace ("${process.env.DATA_DIR}"). Either unset it or set a real path.
14
14
  `),process.exit(1));try{b.mkdirSync(V,{recursive:!0})}catch(t){t.code!=="EEXIST"&&(console.error(`
15
15
  [FATAL] Cannot create DATA_DIR (${V}): ${t.message}`),console.error(` Fix the path or permissions and try again.
@@ -19,7 +19,7 @@ ${n.join(`
19
19
  [FATAL] DATA_DIR (${V}) exists but is NOT a directory.`),console.error(` Looks like a typo \u2014 your DATA_DIR points at a file. Fix the path and try again.
20
20
  `),process.exit(1));for(let t of[ae,ce]){let o;try{o=b.lstatSync(t)}catch(n){if(n.code==="ENOENT")continue;throw n}o.isSymbolicLink()&&(console.error(`
21
21
  [FATAL] Data subdirectory is a symbolic link: ${t}`),console.error(" Refusing to follow \u2014 backup code would copy whatever the link points at."),console.error(` If this is intentional, replace the symlink with the real directory.
22
- `),process.exit(1))}}var ie=A.join(V,".migration-lock");function vs(){let e=JSON.stringify({pid:process.pid,startedAt:new Date().toISOString()},null,2);try{return b.writeFileSync(ie,e,{flag:"wx"}),!0}catch(n){if(n.code!=="EEXIST")throw n}let t;try{t=JSON.parse(b.readFileSync(ie,"utf-8"))}catch{t=null}if(t&&Number.isInteger(t.pid)){let n=!1;try{process.kill(t.pid,0),n=!0}catch(i){i.code==="EPERM"&&(n=!0)}let s=24*60*60*1e3,r=1/0;if(t.startedAt){let i=Date.parse(t.startedAt);Number.isNaN(i)||(r=Date.now()-i)}n&&r<s&&(console.error(`
22
+ `),process.exit(1))}}var ie=_.join(V,".migration-lock");function vs(){let e=JSON.stringify({pid:process.pid,startedAt:new Date().toISOString()},null,2);try{return b.writeFileSync(ie,e,{flag:"wx"}),!0}catch(n){if(n.code!=="EEXIST")throw n}let t;try{t=JSON.parse(b.readFileSync(ie,"utf-8"))}catch{t=null}if(t&&Number.isInteger(t.pid)){let n=!1;try{process.kill(t.pid,0),n=!0}catch(i){i.code==="EPERM"&&(n=!0)}let s=24*60*60*1e3,r=1/0;if(t.startedAt){let i=Date.parse(t.startedAt);Number.isNaN(i)||(r=Date.now()-i)}n&&r<s&&(console.error(`
23
23
  [FATAL] Another plugin process is currently running migrations:`),console.error(` PID: ${t.pid}`),console.error(` Started at: ${t.startedAt||"(unknown)"}`),console.error(` Lock file: ${ie}
24
24
  `),console.error(" Wait for it to finish, or if you're sure it's not actually running,"),console.error(` delete the lock file manually and re-run.
25
25
  `),process.exit(1)),n&&r>=s&&console.log(` Lock holder PID ${t.pid} is alive but lock is older than 24h \u2014 assuming PID reuse, taking over.`)}console.log(` Stale migration lock from PID ${t?.pid??"?"} found \u2014 taking over.`);let o=ie+".tmp";try{return b.writeFileSync(o,e),b.renameSync(o,ie),!0}catch(n){try{b.unlinkSync(o)}catch{}throw new Error(`Failed to take over stale migration lock: ${n.message}`)}}function $t(){try{if(JSON.parse(b.readFileSync(ie,"utf-8")).pid!==process.pid)return;b.unlinkSync(ie)}catch{}}var yo=!1;function $s(){if(yo)return;yo=!0;let e=()=>{try{$t()}catch{}process.exit(1)};for(let t of["SIGINT","SIGTERM","SIGHUP"])try{process.on(t,e)}catch{}}function ks(){if(b.existsSync(N))return;let e=[],t=[];for(let r of ho)if(b.existsSync(r))try{e.push({file:r,schema:qe(r)})}catch(i){t.push({file:r,err:i.message})}if(t.length>0){console.error(`
@@ -31,7 +31,7 @@ ${n.join(`
31
31
  [FATAL] ${N} is not valid JSON: ${o.message}`),console.error(" Refusing to proceed \u2014 silently treating it as 'fresh install' would re-apply"),console.error(" every migration on top of already-migrated data and corrupt it."),console.error(' Repair the file (set it to {"version":N,"migrations":[...]} matching your real state)'),console.error(` or restore from the *.pre-vNNN.backup files if you have them.
32
32
  `),process.exit(1)}let t=Cs(e);return t===null&&(console.error(`
33
33
  [FATAL] ${N} has invalid structure:`),console.error(` ${JSON.stringify(e)?.slice(0,200)||"(unparseable)"}`),console.error(' Expected shape: { "version": <integer>, "migrations": [...] }'),console.error(` Repair the file or restore from a backup.
34
- `),process.exit(1)),t}function vo(e){try{b.chmodSync(e,384)}catch{}}function Ts(e){if(bo(),b.existsSync(N))try{if(b.lstatSync(N).isSymbolicLink())throw new Error(`SCHEMA_FILE is a symbolic link: ${N}. Refusing to write through it (potential symlink attack). Remove the link and re-run.`)}catch(o){if(o.message?.includes("symbolic link"))throw o}let t=N+".tmp";try{b.writeFileSync(t,JSON.stringify(e,null,2)),vo(t),b.renameSync(t,N)}catch(o){try{b.unlinkSync(t)}catch{}throw o}}function wo(e,t){if(!b.existsSync(e))return;let o=`.pre-v${String(t).padStart(3,"0")}.backup`,n=b.readdirSync(e).filter(a=>{let c=a.toLowerCase();if(c.includes(".backup")||c===".schema-version"||c.endsWith(".tmp"))return!1;try{return b.statSync(A.join(e,a)).isFile()}catch{return!1}}),s=0,r=0,i=[];for(let a of n){let c=A.join(e,a),l=A.join(e,a+o);if(b.existsSync(l)){r++;continue}try{ko(c,l),s++}catch(f){i.push({file:a,err:f.message})}}if(i.length>0){let a=new Error(`Failed to back up ${i.length} file(s) in ${A.basename(e)}/: `+i.map(c=>`${c.file} (${c.err})`).join(", "));throw a.code="BACKUP_INCOMPLETE",a}if(s>0||r>0){let a=r>0?` (${r} pre-existing backup(s) preserved)`:"";console.log(` Backed up ${s} files in ${A.basename(e)}/ (${o})${a}`)}}var bt=!1;async function $o(){if(bt)return;bo(),Ds();let t=So().version;if(t===te){bt=!0;return}$s(),vs(),process.on("exit",$t),t>te&&(console.error(`
34
+ `),process.exit(1)),t}function vo(e){try{b.chmodSync(e,384)}catch{}}function Ts(e){if(bo(),b.existsSync(N))try{if(b.lstatSync(N).isSymbolicLink())throw new Error(`SCHEMA_FILE is a symbolic link: ${N}. Refusing to write through it (potential symlink attack). Remove the link and re-run.`)}catch(o){if(o.message?.includes("symbolic link"))throw o}let t=N+".tmp";try{b.writeFileSync(t,JSON.stringify(e,null,2)),vo(t),b.renameSync(t,N)}catch(o){try{b.unlinkSync(t)}catch{}throw o}}function wo(e,t){if(!b.existsSync(e))return;let o=`.pre-v${String(t).padStart(3,"0")}.backup`,n=b.readdirSync(e).filter(a=>{let c=a.toLowerCase();if(c.includes(".backup")||c===".schema-version"||c.endsWith(".tmp"))return!1;try{return b.statSync(_.join(e,a)).isFile()}catch{return!1}}),s=0,r=0,i=[];for(let a of n){let c=_.join(e,a),l=_.join(e,a+o);if(b.existsSync(l)){r++;continue}try{ko(c,l),s++}catch(f){i.push({file:a,err:f.message})}}if(i.length>0){let a=new Error(`Failed to back up ${i.length} file(s) in ${_.basename(e)}/: `+i.map(c=>`${c.file} (${c.err})`).join(", "));throw a.code="BACKUP_INCOMPLETE",a}if(s>0||r>0){let a=r>0?` (${r} pre-existing backup(s) preserved)`:"";console.log(` Backed up ${s} files in ${_.basename(e)}/ (${o})${a}`)}}var bt=!1;async function $o(){if(bt)return;bo(),Ds();let t=So().version;if(t===te){bt=!0;return}$s(),vs(),process.on("exit",$t),t>te&&(console.error(`
35
35
  [FATAL] Your data schema is at v${t}, but this plugin build only understands up to v${te}.`),console.error(" This usually means you downgraded the plugin without rolling back data."),console.error(` Operating on the newer-format data with this build would risk corrupting it.
36
36
  `),console.error(" Options:"),console.error(" A) Re-install the newer plugin version that produced this schema, then"),console.error(" (if you really want to downgrade) run 'rollback-data --confirm' first,"),console.error(" then re-install the older plugin version."),console.error(` B) Manually restore your data from the *.pre-vNNN.backup files matching v${te}.
37
37
  `),process.exit(1)),console.log(`
@@ -49,25 +49,25 @@ ${n.join(`
49
49
  [FATAL] Migration ${r} applied successfully but schema version file could NOT be updated: ${c.message}`),console.error(` Your data is in the v${s.version} state but .schema-version still shows v${t}.`),console.error(` On next plugin command the runner will try to re-apply ${r}. If that migration is`),console.error(` idempotent (most are), it will succeed harmlessly. If you're unsure, run 'data-cleanup' and contact support.
50
50
  `),process.exit(1)}console.log(` \u2713 Migration ${r} complete`)}try{Ft()}catch{}try{Vt()}catch{}bt=!0,$t(),console.log(`
51
51
  \u2713 Schema is now at v${te}
52
- `)}var Es=[/\.json\.tmp$/,/\.schema-version\.tmp$/,/\.backup\.tmp$/];function _s(e){let t=e.toLowerCase();return Es.some(o=>o.test(t))}var As=6e4;function Rs(){let e=Date.now(),t=[];for(let o of[V,ae,ce]){if(!b.existsSync(o))continue;let n;try{n=b.readdirSync(o)}catch{continue}for(let s of n){if(!_s(s))continue;let r=A.join(o,s);try{let i=b.statSync(r);if(!i.isFile()||e-i.mtimeMs<As)continue;t.push({dir:o,file:s,fullPath:r})}catch{}}}return t}function Ds({verbose:e=!1}={}){let t=Rs();if(t.length===0)return e&&console.log(" No orphan .tmp files found."),0;let o=0;for(let n of t)try{b.unlinkSync(n.fullPath),o++,e&&console.log(` Removed orphan: ${A.basename(n.dir)}/${n.file}`)}catch(s){console.warn(` [!] Could not remove orphan ${n.fullPath}: ${s.message}`)}return!e&&o>0&&console.log(` Cleaned up ${o} orphan .tmp file(s) from previous run.`),o}function Os(){let e=[];for(let t of[ae,ce]){if(!b.existsSync(t))continue;let o=b.readdirSync(t).filter(n=>{let s=n.toLowerCase();return s.endsWith(".json")&&!s.includes(".backup")});for(let n of o){let s=A.join(t,n);try{qe(s)}catch(r){e.push({dir:A.basename(t),file:n,err:r.message})}}}return e.length===0?{ok:!0}:{ok:!1,broken:e}}function Is(e){let t=[],o=[];for(let r of[ae,ce]){if(!b.existsSync(r))continue;let i=b.readdirSync(r).filter(a=>a.endsWith(e));for(let a of i){let c=A.join(r,a),l=a.slice(0,-e.length),f=A.join(r,l);try{l.toLowerCase().endsWith(".json")?qe(c):b.accessSync(c,b.constants.R_OK),t.push({backupPath:c,originalPath:f,fileName:a,dir:r})}catch(d){o.push(`${A.basename(r)}/${a}: ${d.message}`)}}}if(o.length>0)return{ok:!1,error:o.join("; "),restored:0};let n=0,s=[];for(let{backupPath:r,originalPath:i,fileName:a,dir:c}of t)try{ko(r,i),n++}catch(l){s.push(`${A.basename(c)}/${a}: ${l.message}`)}return s.length>0?{ok:!1,error:s.join("; "),restored:n}:{ok:!0,restored:n}}function ko(e,t){let o=t+".tmp";try{b.copyFileSync(e,o),vo(o)}catch(n){try{b.unlinkSync(o)}catch{}throw n}try{b.renameSync(o,t)}catch(n){try{b.unlinkSync(o)}catch{}if(n.code==="EPERM"||n.code==="EBUSY"){let s=new Error(`File locked: ${t} (${n.code}). On Windows this is usually antivirus / Search Indexer / the file open in another app. Close anything that might be holding it and re-run.`);throw s.code=n.code,s}throw n}}async function xs(e,t,o="op"){let n,s=new Promise((r,i)=>{n=setTimeout(()=>i(new Error(`${o} timeout after ${t}ms`)),t)});try{return await Promise.race([e,s])}finally{clearTimeout(n)}}function le(e){if(!e)return!1;let t=e.constructor?.name||"";if(t==="ProtocolError"||t==="TargetCloseError")return!0;let o=e.message||"";return/Runtime\.callFunctionOn timed out/i.test(o)||/Target closed/i.test(o)||/Session closed/i.test(o)||/Connection closed/i.test(o)||/Most likely the page has been closed/i.test(o)||/Navigating frame was detached/i.test(o)||/Protocol error.*timed out/i.test(o)}async function Co(e,t,{returnUrl:o,gotoTimeoutMs:n=6e4,cookiesProvider:s=null,setupPage:r=null}={}){try{await xs(t.close({runBeforeUnload:!1}),5e3,"oldPage.close")}catch{}let i=await e.newPage();if(r)try{await r(i)}catch{}if(s)try{let a=s();Array.isArray(a)&&a.length>0&&await i.setCookie(...a)}catch{}if(o){await i.goto(o,{waitUntil:"domcontentloaded",timeout:n});let a=i.url();if(/\/login|\/checkpoint|\/uas\/login|\/authwall/.test(a))throw new Error(`Session expired after recovery \u2014 landed on ${a}. Run: ilml linkedin login`)}return i}await $o();var Ro="https://www.linkedin.com/messaging/",js=10,kt=3,Ns=async e=>{await e.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})})},Ms=()=>Pe(),ue={pageRecoveries:0};async function Je(e,t){if(ue.pageRecoveries>=js)throw new Error(`CDP unrecoverable: ${ue.pageRecoveries} page recoveries already attempted. Last: ${t}`);console.log(`
53
- \u{1F504} CDP dead \u2014 recovering page (#${ue.pageRecoveries+1}). Reason: ${t}`),e.page=await Co(e.browser,e.page,{returnUrl:Ro,cookiesProvider:Ms,setupPage:Ns}),ue.pageRecoveries++,await _(3e3);try{await e.page.waitForSelector(".msg-conversation-listitem",{timeout:15e3})}catch{}console.log(`\u2713 Page recovered (total: ${ue.pageRecoveries}).
54
- `)}function ye(e){return(e.messages||[]).find(t=>$e.has(t.status))?.status}var z=process.argv.slice(2),Ct=z.includes("--full"),L=z.includes("--dry-run"),To=z.includes("--report"),Tt=z.includes("--verbose"),Eo=z.includes("--backfill"),_o=z.includes("--enrich"),Ao=z.includes("--today"),Et=z.includes("--read-unread"),Oe=parseInt(z.find(e=>e.startsWith("--max="))?.split("=")[1]||"50");function Ps(e,t){if(!t)return"new";if(e.unread)return"unread";if(!t.profileUrl&&(t.messages?.length||t.lastMessagePreview))return"missing_url";let o=(t.lastMessagePreview||"").substring(0,50),n=(e.lastMessagePreview||"").substring(0,50);if(n&&o&&n!==o)return"preview_changed";if(e.lastMessageBy==="me"&&t.lastMessageBy!=="me")return"sender_changed";if(t.lastSynced&&e.lastMessageTime){let s=new Date(e.lastMessageTime).getTime(),r=new Date(t.lastSynced).getTime();if(Number.isFinite(s)&&Number.isFinite(r)&&s>r)return"activity_after_last_read"}return null}async function Fs(e,t){console.log(`
52
+ `)}var Es=[/\.json\.tmp$/,/\.schema-version\.tmp$/,/\.backup\.tmp$/];function As(e){let t=e.toLowerCase();return Es.some(o=>o.test(t))}var _s=6e4;function Rs(){let e=Date.now(),t=[];for(let o of[V,ae,ce]){if(!b.existsSync(o))continue;let n;try{n=b.readdirSync(o)}catch{continue}for(let s of n){if(!As(s))continue;let r=_.join(o,s);try{let i=b.statSync(r);if(!i.isFile()||e-i.mtimeMs<_s)continue;t.push({dir:o,file:s,fullPath:r})}catch{}}}return t}function Ds({verbose:e=!1}={}){let t=Rs();if(t.length===0)return e&&console.log(" No orphan .tmp files found."),0;let o=0;for(let n of t)try{b.unlinkSync(n.fullPath),o++,e&&console.log(` Removed orphan: ${_.basename(n.dir)}/${n.file}`)}catch(s){console.warn(` [!] Could not remove orphan ${n.fullPath}: ${s.message}`)}return!e&&o>0&&console.log(` Cleaned up ${o} orphan .tmp file(s) from previous run.`),o}function Os(){let e=[];for(let t of[ae,ce]){if(!b.existsSync(t))continue;let o=b.readdirSync(t).filter(n=>{let s=n.toLowerCase();return s.endsWith(".json")&&!s.includes(".backup")});for(let n of o){let s=_.join(t,n);try{qe(s)}catch(r){e.push({dir:_.basename(t),file:n,err:r.message})}}}return e.length===0?{ok:!0}:{ok:!1,broken:e}}function Is(e){let t=[],o=[];for(let r of[ae,ce]){if(!b.existsSync(r))continue;let i=b.readdirSync(r).filter(a=>a.endsWith(e));for(let a of i){let c=_.join(r,a),l=a.slice(0,-e.length),f=_.join(r,l);try{l.toLowerCase().endsWith(".json")?qe(c):b.accessSync(c,b.constants.R_OK),t.push({backupPath:c,originalPath:f,fileName:a,dir:r})}catch(d){o.push(`${_.basename(r)}/${a}: ${d.message}`)}}}if(o.length>0)return{ok:!1,error:o.join("; "),restored:0};let n=0,s=[];for(let{backupPath:r,originalPath:i,fileName:a,dir:c}of t)try{ko(r,i),n++}catch(l){s.push(`${_.basename(c)}/${a}: ${l.message}`)}return s.length>0?{ok:!1,error:s.join("; "),restored:n}:{ok:!0,restored:n}}function ko(e,t){let o=t+".tmp";try{b.copyFileSync(e,o),vo(o)}catch(n){try{b.unlinkSync(o)}catch{}throw n}try{b.renameSync(o,t)}catch(n){try{b.unlinkSync(o)}catch{}if(n.code==="EPERM"||n.code==="EBUSY"){let s=new Error(`File locked: ${t} (${n.code}). On Windows this is usually antivirus / Search Indexer / the file open in another app. Close anything that might be holding it and re-run.`);throw s.code=n.code,s}throw n}}async function xs(e,t,o="op"){let n,s=new Promise((r,i)=>{n=setTimeout(()=>i(new Error(`${o} timeout after ${t}ms`)),t)});try{return await Promise.race([e,s])}finally{clearTimeout(n)}}function le(e){if(!e)return!1;let t=e.constructor?.name||"";if(t==="ProtocolError"||t==="TargetCloseError")return!0;let o=e.message||"";return/Runtime\.callFunctionOn timed out/i.test(o)||/Target closed/i.test(o)||/Session closed/i.test(o)||/Connection closed/i.test(o)||/Most likely the page has been closed/i.test(o)||/Navigating frame was detached/i.test(o)||/Protocol error.*timed out/i.test(o)}async function Co(e,t,{returnUrl:o,gotoTimeoutMs:n=6e4,cookiesProvider:s=null,setupPage:r=null}={}){try{await xs(t.close({runBeforeUnload:!1}),5e3,"oldPage.close")}catch{}let i=await e.newPage();if(r)try{await r(i)}catch{}if(s)try{let a=s();Array.isArray(a)&&a.length>0&&await i.setCookie(...a)}catch{}if(o){await i.goto(o,{waitUntil:"domcontentloaded",timeout:n});let a=i.url();if(/\/login|\/checkpoint|\/uas\/login|\/authwall/.test(a))throw new Error(`Session expired after recovery \u2014 landed on ${a}. Run: ilml linkedin login`)}return i}await $o();var Ro="https://www.linkedin.com/messaging/",js=10,kt=3,Ns=async e=>{await e.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})})},Ms=()=>Pe(),ue={pageRecoveries:0};async function Je(e,t){if(ue.pageRecoveries>=js)throw new Error(`CDP unrecoverable: ${ue.pageRecoveries} page recoveries already attempted. Last: ${t}`);console.log(`
53
+ \u{1F504} CDP dead \u2014 recovering page (#${ue.pageRecoveries+1}). Reason: ${t}`),e.page=await Co(e.browser,e.page,{returnUrl:Ro,cookiesProvider:Ms,setupPage:Ns}),ue.pageRecoveries++,await A(3e3);try{await e.page.waitForSelector(".msg-conversation-listitem",{timeout:15e3})}catch{}console.log(`\u2713 Page recovered (total: ${ue.pageRecoveries}).
54
+ `)}function ye(e){return(e.messages||[]).find(t=>$e.has(t.status))?.status}var z=process.argv.slice(2),Ct=z.includes("--full"),L=z.includes("--dry-run"),To=z.includes("--report"),Tt=z.includes("--verbose"),Eo=z.includes("--backfill"),Ao=z.includes("--enrich"),_o=z.includes("--today"),Et=z.includes("--read-unread"),Oe=parseInt(z.find(e=>e.startsWith("--max="))?.split("=")[1]||"50");function Ps(e,t){if(!t)return"new";if(e.unread)return"unread";if(!t.profileUrl&&(t.messages?.length||t.lastMessagePreview))return"missing_url";let o=(t.lastMessagePreview||"").substring(0,50),n=(e.lastMessagePreview||"").substring(0,50);if(n&&o&&n!==o)return"preview_changed";if(e.lastMessageBy==="me"&&t.lastMessageBy!=="me")return"sender_changed";if(t.lastSynced&&e.lastMessageTime){let s=new Date(e.lastMessageTime).getTime(),r=new Date(t.lastSynced).getTime();if(Number.isFinite(s)&&Number.isFinite(r)&&s>r)return"activity_after_last_read"}return null}async function Fs(e,t){console.log(`
55
55
  \u2550\u2550 PHASE 1: Inbox Scan \u2550\u2550
56
56
  `);let o=Ze(),n=o.lastIncrementalSync?new Date(o.lastIncrementalSync):null,s=new Map,r=new Map,i=new Map,a=0,c=0,l=0,f=0,d=0,u=-1,m=0;for(;;){c++;let $=await to(e),k=0;for(let p of $){if(!p.name||s.has(p.name))continue;s.set(p.name,p),k++,p.unread&&i.set(p.name,p);let w=t[p.name],C=Ps(p,w);C&&(!Et&&p.unread?a++:r.set(p.name,{card:p,reason:C})),w&&(C||(w.lastMessageBy=p.lastMessageBy,w.lastMessagePreview=p.lastMessagePreview||w.lastMessagePreview,w.lastMessageTime=p.lastMessageTime||w.lastMessageTime),w.unread=p.unread,p.lastMessageBy==="them"&&p.unread&&(w.conversationStatus="unanswered_by_us"))}if(Tt?console.log(` Round #${c}: +${k} new | Total: ${s.size} | Need reading: ${r.size}`):process.stdout.write(`\r Scanned: ${s.size} conversations (page #${c}, ${r.size} need reading)`),k===0){if(d++,d>=3){console.log(`
57
57
  3 rounds with no new items \u2014 end of visible list.`);break}}else d=0;if(!Ct){if(r.size===f){if(l++,l>=3){console.log(`
58
58
  Caught up \u2014 3 screens with no new threads to read.`);break}}else l=0;f=r.size}let g=await nt(e);if(g){if(g.scrollTop===u){if(m++,m>=3){console.log(`
59
- Scroll stalled \u2014 reached end of inbox.`);break}}else m=0;u=g.scrollTop}else{let p=await e.$(".msg-conversation-listitem");if(p){let w=await p.boundingBox();w&&(await e.mouse.move(w.x+w.width/2,w.y+w.height/2),await e.mouse.wheel({deltaY:600}))}}await _(2e3)}Tt||process.stdout.write(`
59
+ Scroll stalled \u2014 reached end of inbox.`);break}}else m=0;u=g.scrollTop}else{let p=await e.$(".msg-conversation-listitem");if(p){let w=await p.boundingBox();w&&(await e.mouse.move(w.x+w.width/2,w.y+w.height/2),await e.mouse.wheel({deltaY:600}))}}await A(2e3)}Tt||process.stdout.write(`
60
60
  `);let S=new Date().toISOString(),y=0;for(let[$,{card:k}]of r)t[$]||(t[$]={profileUrl:null,lastSynced:S,lastMessageBy:k.lastMessageBy,lastMessagePreview:k.lastMessagePreview||"",lastMessageTime:k.lastMessageTime||"",unread:k.unread||!1,conversationStatus:k.lastMessageBy==="them"?"unanswered_by_us":"awaiting_reply",messages:[]},y++);let v=0;for(let[$,k]of i)t[$]||(t[$]={profileUrl:null,lastSynced:S,lastMessageBy:k.lastMessageBy,lastMessagePreview:k.lastMessagePreview||"",lastMessageTime:k.lastMessageTime||"",unread:!0,conversationStatus:k.lastMessageBy==="them"?"unanswered_by_us":"awaiting_reply",messages:[]},v++);if(console.log(`
61
61
  Inbox scan complete:`),console.log(` Total conversations seen: ${s.size}`),console.log(` New conversations: ${y}`),console.log(` Need reading/re-reading: ${r.size}`),!Et&&a>0&&console.log(` Preserved unread (default): ${a} \u2014 kept bold in LinkedIn UI; pass --read-unread to vacuum them into the DB`),v>0&&console.log(` New unread stubs: ${v} \u2014 saved to DB so 'today' / 'report' can show them offline`),r.size>0){let $={};for(let{reason:k}of r.values())$[k]=($[k]||0)+1;for(let[k,g]of Object.entries($))console.log(` ${k}: ${g}`)}if(!L){let $=Ze();$.lastIncrementalSync=new Date().toISOString(),Ct&&($.lastFullSync=$.lastIncrementalSync),Jt($),X(t)}return{allCards:s,toReRead:r,unreadCards:i}}async function Ls(e,t,o,n){console.log(`
62
62
  \u2550\u2550 PHASE 2: Read Changed Threads \u2550\u2550
63
- `);let s=Array.from(t.entries()),r=Math.min(s.length,Oe);if(r===0)return console.log(" No threads to read \u2014 all up to date."),[];console.log(" Resetting inbox view...");try{await e.page.goto(Ro,{waitUntil:"domcontentloaded",timeout:6e4})}catch(d){if(!le(d))throw d;await Je(e,"Phase 2 inbox reset")}await _(4e3);try{await e.page.waitForSelector(".msg-conversation-listitem",{timeout:15e3})}catch{}let i={unread:0,preview_changed:1,sender_changed:2,no_messages:3,new:4};s.sort((d,u)=>(i[d[1].reason]??5)-(i[u[1].reason]??5)),console.log(` Reading ${r} of ${s.length} threads (--max=${Oe})
64
- `);let a=[],c=[],l=0,f=0;for(let d=0;d<r;d++){let[u,{card:m,reason:S}]=s[d];console.log(` [${d+1}/${r}] ${u} (${S})`);let y=e.page;try{let v={verified:!1,headerName:null};try{v=await ct(y,u)}catch(k){if(le(k))throw k;console.log(` searchAndOpenThread threw: ${(k.message||"").substring(0,80)}`)}if(!v.verified){console.log(" Sidebar fallback (scroll-to-find)...");try{v=await oo(e.page,u)}catch(k){if(le(k))throw k;console.log(` Fallback threw: ${(k.message||"").substring(0,80)}`)}}if(!v.verified){console.log(" Could not open thread."),l++;try{await Z(e.page)}catch{}continue}let $=await rt(y);if($&&$.length>0){if(!it($,u,c)){console.log(" Skipped \u2014 stale data."),l++,await Z(y);continue}let g=await st(y),p=o[u]||{profileUrl:null,lastSynced:new Date().toISOString(),lastMessageBy:null,lastMessagePreview:"",lastMessageTime:"",unread:!1,conversationStatus:null,messages:[]},w=p.messages?.length||0;p.messages=at(p.messages,$),p.lastSynced=new Date().toISOString(),g&&!p.profileUrl&&(p.profileUrl=g);let C=p.messages.filter(I=>!["draft","confirmed","rejected","needs_review"].includes(I.status));p.lastMessageBy=ft(C,u),p.lastMessagePreview=m.lastMessagePreview||p.lastMessagePreview,p.lastMessageTime=m.lastMessageTime||p.lastMessageTime,p.unread=!1,o[u]=p,L||X(o);let R=p.messages.length-w;console.log(` ${p.messages.length} msgs (${R>=0?"+"+R:R} new)${g&&!p.profileUrl?" +url":""}`),a.push({name:u}),c=[...new Set($.map(I=>I.sender).filter(I=>I&&I!=="Unknown"))]}else console.log(" No messages extracted."),l++;await Z(y),await _(500)}catch(v){if(!le(v))throw v;f++,n&&n.add(u),await Je(e,`Phase 2 thread ${d+1}/${r} (${u})`)}}return console.log(`
63
+ `);let s=Array.from(t.entries()),r=Math.min(s.length,Oe);if(r===0)return console.log(" No threads to read \u2014 all up to date."),[];console.log(" Resetting inbox view...");try{await e.page.goto(Ro,{waitUntil:"domcontentloaded",timeout:6e4})}catch(d){if(!le(d))throw d;await Je(e,"Phase 2 inbox reset")}await A(4e3);try{await e.page.waitForSelector(".msg-conversation-listitem",{timeout:15e3})}catch{}let i={unread:0,preview_changed:1,sender_changed:2,no_messages:3,new:4};s.sort((d,u)=>(i[d[1].reason]??5)-(i[u[1].reason]??5)),console.log(` Reading ${r} of ${s.length} threads (--max=${Oe})
64
+ `);let a=[],c=[],l=0,f=0;for(let d=0;d<r;d++){let[u,{card:m,reason:S}]=s[d];console.log(` [${d+1}/${r}] ${u} (${S})`);let y=e.page;try{let v={verified:!1,headerName:null};try{v=await ct(y,u)}catch(k){if(le(k))throw k;console.log(` searchAndOpenThread threw: ${(k.message||"").substring(0,80)}`)}if(!v.verified){console.log(" Sidebar fallback (scroll-to-find)...");try{v=await oo(e.page,u)}catch(k){if(le(k))throw k;console.log(` Fallback threw: ${(k.message||"").substring(0,80)}`)}}if(!v.verified){console.log(" Could not open thread."),l++;try{await Z(e.page)}catch{}continue}let $=await rt(y);if($&&$.length>0){if(!it($,u,c)){console.log(" Skipped \u2014 stale data."),l++,await Z(y);continue}let g=await st(y),p=o[u]||{profileUrl:null,lastSynced:new Date().toISOString(),lastMessageBy:null,lastMessagePreview:"",lastMessageTime:"",unread:!1,conversationStatus:null,messages:[]},w=p.messages?.length||0;p.messages=at(p.messages,$),p.lastSynced=new Date().toISOString(),g&&!p.profileUrl&&(p.profileUrl=g);let C=p.messages.filter(I=>!["draft","confirmed","rejected","needs_review"].includes(I.status));p.lastMessageBy=ft(C,u),p.lastMessagePreview=m.lastMessagePreview||p.lastMessagePreview,p.lastMessageTime=m.lastMessageTime||p.lastMessageTime,p.unread=!1,o[u]=p,L||X(o);let R=p.messages.length-w;console.log(` ${p.messages.length} msgs (${R>=0?"+"+R:R} new)${g&&!p.profileUrl?" +url":""}`),a.push({name:u}),c=[...new Set($.map(I=>I.sender).filter(I=>I&&I!=="Unknown"))]}else console.log(" No messages extracted."),l++;await Z(y),await A(500)}catch(v){if(!le(v))throw v;f++,n&&n.add(u),await Je(e,`Phase 2 thread ${d+1}/${r} (${u})`)}}return console.log(`
65
65
  Phase 2 complete: ${a.length} read, ${l} failed${f?`, ${f} skipped on CDP recovery`:""}`),s.length>r&&console.log(` ${s.length-r} more threads pending (run again or increase --max)`),a}function Us(e,t){console.log(`
66
66
  \u2550\u2550 PHASE 3: Post-processing & Enrichment \u2550\u2550
67
67
  `);let o=W();for(let n of t){let{name:s}=n,r=e[s];if(!r?.messages?.length)continue;try{ut(r,s,o)}catch(c){console.warn(` [!] Enrichment failed for ${s}: ${c.message}`)}r._cardSynced&&delete r._cardSynced;let i=r.profileUrl,a=null;if(i&&(a=o[i]||null),!a){let c=Object.entries(o).filter(([,l])=>l.name===s);c.length===1&&(i||(i=c[0][0],r.profileUrl=i),a=c[0][1])}!a&&i&&(Bt(i,{name:s,source:"sync-all"}),a=W()[i]),a&&(r.category&&!a.category&&(a.category=r.category),a.conversationStatus=r.conversationStatus,a.lastUpdated=new Date().toISOString()),i&&a&&(r.isConnection=a.connectionStatus==="connected")}L||(Ne(o),X(e)),console.log(` Enriched ${t.length} conversations.`),Do(e)}function Do(e){let t=new Map;for(let[s,r]of Object.entries(e)){if(!r.profileUrl)continue;let i=r.profileUrl.toLowerCase().replace(/\/$/,"");t.has(i)||t.set(i,[]),t.get(i).push(s)}let o=[...t.entries()].filter(([,s])=>s.length===2);if(o.length===0)return;let n=0;for(let[,s]of o){let[r,i]=s.map(f=>({name:f,conv:e[f]})),a=(r.conv.messages?.length||0)>=(i.conv.messages?.length||0)?r:i,c=a===r?i:r,l=new Set((a.conv.messages||[]).map(f=>`${f.text?.slice(0,80)}|${f.time}`));for(let f of c.conv.messages||[]){let d=`${f.text?.slice(0,80)}|${f.time}`;l.has(d)||(a.conv.messages.push(f),l.add(d))}a.conv.messages.sort((f,d)=>(f.time||"").localeCompare(d.time||"")),c.conv.notes&&!a.conv.notes&&(a.conv.notes=c.conv.notes),c.conv.priority&&!a.conv.priority&&(a.conv.priority=c.conv.priority),c.conv.categorySource==="manual"&&a.conv.categorySource!=="manual"&&(a.conv.category=c.conv.category,a.conv.categorySource="manual"),(c.conv.lastSynced||"")>(a.conv.lastSynced||"")&&(a.conv.lastSynced=c.conv.lastSynced),delete e[c.name],console.log(` Merged: "${c.name}" \u2192 "${a.name}"`),n++}n>0&&(L||X(e),console.log(` ${n} duplicates merged.`))}function Bs(){let e=Te(),t=W(),o=Object.entries(e);console.log(`
68
68
  \u2550\u2550 ENRICHMENT: Re-processing all conversations \u2550\u2550
69
69
  `);let n=0,s=0,r=0;for(let[d,u]of o){if(!u.profileUrl){let m=Object.entries(t).filter(([,S])=>S.name===d);m.length===1&&(u.profileUrl=m[0][0],r++)}if(!u.messages||u.messages.length===0){s++;continue}try{ut(u,d,t)}catch(m){console.warn(` [!] Enrichment failed for ${d}: ${m.message}`)}n++}Do(e),L||X(e),console.log(` Enriched: ${n}`),console.log(` Skipped (no messages): ${s}`),r>0&&console.log(` Linked profileUrl from people.json: ${r}`),console.log(` Total: ${o.length}`);let i=new Set(Object.keys(e)),a=new Set(Object.values(e).map(d=>d.profileUrl).filter(Boolean)),c=Object.entries(t),l=0,f=0;for(let[d,u]of c){if(a.has(d)){f++;continue}if(u.name&&i.has(u.name)){f++;continue}if(u.connectionStatus!=="connected"){f++;continue}ao(u,d),l++}L||Ne(t),console.log(`
70
- People enriched: ${l}`),console.log(` People skipped (have conversation or not connected): ${f}`),console.log(` People total: ${c.length}`),_t(e,null,null)}function _t(e,t,o,n={}){let s=Object.entries(e),r=W(),{unreadCards:i=null,readUnread:a=!1}=n;console.log(`
70
+ People enriched: ${l}`),console.log(` People skipped (have conversation or not connected): ${f}`),console.log(` People total: ${c.length}`),At(e,null,null)}function At(e,t,o,n={}){let s=Object.entries(e),r=W(),{unreadCards:i=null,readUnread:a=!1}=n;console.log(`
71
71
  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`),console.log(" SYNC REPORT"),console.log(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
72
72
  `),t&&(console.log(" Inbox Scan:"),console.log(` Conversations seen: ${t.allCards.size}`),console.log(` Needed reading: ${t.toReRead.size}`)),o&&console.log(` Actually read: ${o.length}`);let c=s.length,l=s.filter(([,h])=>h.messages?.length>0).length,f=s.filter(([,h])=>!h.messages||h.messages.length===0).length,d=s.filter(([,h])=>h.profileUrl).length,u=s.filter(([,h])=>!h.profileUrl).length;console.log(`
73
73
  Database:`),console.log(` Total conversations: ${c}`),console.log(` With messages: ${l}`),console.log(` Without messages: ${f}`),console.log(` With profileUrl: ${d}`),console.log(` Without profileUrl: ${u}`);let m=0,S=0;for(let[,h]of s)for(let T of h.messages||[])m++,(!T.sender||T.sender==="Unknown")&&S++;console.log(`
@@ -87,14 +87,14 @@ ${n.join(`
87
87
  ... and ${R.length-h} more`)}p.length===0&&console.log(" All caught up \u2014 no unanswered messages.");let I=new Set(Object.keys(e)),He=new Set(Object.values(e).map(h=>h.profileUrl).filter(Boolean)),Se=Object.entries(r).filter(([h,T])=>T.connectionStatus==="connected"&&T.personActionNeeded==="initiate_contact"&&!He.has(h)&&!(T.name&&I.has(T.name))).sort((h,T)=>{let E={high:0,medium:1,low:2}[h[1].personPriority]??3,D={high:0,medium:1,low:2}[T[1].personPriority]??3;return E!==D?E-D:(T[1].connectionDate||"").localeCompare(h[1].connectionDate||"")});if(Se.length>0){console.log(`
88
88
  INITIATE CONTACT (${Se.length}):
89
89
  `);let h=20;for(let[T,E]of Se.slice(0,h)){let D=E.personPriority?`[${E.personPriority.toUpperCase()}]`:"",M=E.personSummary||E.title||"";console.log(` ${D} ${E.name||"Unknown"} \u2014 ${M}`)}Se.length>h&&console.log(`
90
- ... and ${Se.length-h} more`)}let At=s.filter(([,h])=>h.conversationStatus==="awaiting_reply");At.length>0&&console.log(`
91
- BALL IN THEIR COURT: ${At.length} conversations`),L&&console.log(`
90
+ ... and ${Se.length-h} more`)}let _t=s.filter(([,h])=>h.conversationStatus==="awaiting_reply");_t.length>0&&console.log(`
91
+ BALL IN THEIR COURT: ${_t.length} conversations`),L&&console.log(`
92
92
  [DRY RUN \u2014 no changes written]`),console.log(`
93
93
  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
94
94
  `)}async function qs(e,t){console.log(`
95
95
  \u2550\u2550 BACKFILL: Reading conversations with 0 messages \u2550\u2550
96
96
  `);let o=Object.entries(t).filter(([,c])=>!c.messages||c.messages.length===0).map(([c,l])=>({name:c,preview:l.lastMessagePreview||"",lastBy:l.lastMessageBy}));if(o.length===0)return console.log(" All conversations already have messages."),[];o.sort((c,l)=>c.lastBy==="them"&&l.lastBy!=="them"?-1:c.lastBy!=="them"&&l.lastBy==="them"?1:0);let n=Math.min(o.length,Oe);console.log(` ${o.length} conversations without messages, reading ${n} (--max=${Oe})
97
- `);let s=[],r=0,i=0,a=[];for(let c=0;c<n;c++){let{name:l}=o[c];console.log(` [${c+1}/${n}] ${l}`);let f=e.page;try{if(await Rt(f),!(await ct(f,l)).verified){console.log(" Not found or thread didn't load."),r++,await Z(f),await _(500);continue}let u=await rt(f);if(!u||u.length===0){console.log(" No messages extracted."),r++,await Z(f),await _(500);continue}if(!it(u,l,a)){console.log(" Skipped \u2014 stale data."),r++,await Z(f),await _(500);continue}let S=await st(f),y=t[l]||{profileUrl:null,lastSynced:new Date().toISOString(),lastMessageBy:null,lastMessagePreview:"",lastMessageTime:"",unread:!1,conversationStatus:null,messages:[]};y.messages=at(y.messages,u),y.lastSynced=new Date().toISOString(),S&&(y.profileUrl=S),t[l]=y,L||X(t),console.log(` \u2713 ${y.messages.length} msgs${S?" +url":""}`),s.push({name:l}),a=[...new Set(u.map(v=>v.sender).filter(v=>v&&v!=="Unknown"))],await Z(f),await _(500)}catch(d){if(!le(d))throw d;i++,await Je(e,`Backfill thread ${c+1}/${n} (${l})`)}}return console.log(`
97
+ `);let s=[],r=0,i=0,a=[];for(let c=0;c<n;c++){let{name:l}=o[c];console.log(` [${c+1}/${n}] ${l}`);let f=e.page;try{if(await Rt(f),!(await ct(f,l)).verified){console.log(" Not found or thread didn't load."),r++,await Z(f),await A(500);continue}let u=await rt(f);if(!u||u.length===0){console.log(" No messages extracted."),r++,await Z(f),await A(500);continue}if(!it(u,l,a)){console.log(" Skipped \u2014 stale data."),r++,await Z(f),await A(500);continue}let S=await st(f),y=t[l]||{profileUrl:null,lastSynced:new Date().toISOString(),lastMessageBy:null,lastMessagePreview:"",lastMessageTime:"",unread:!1,conversationStatus:null,messages:[]};y.messages=at(y.messages,u),y.lastSynced=new Date().toISOString(),S&&(y.profileUrl=S),t[l]=y,L||X(t),console.log(` \u2713 ${y.messages.length} msgs${S?" +url":""}`),s.push({name:l}),a=[...new Set(u.map(v=>v.sender).filter(v=>v&&v!=="Unknown"))],await Z(f),await A(500)}catch(d){if(!le(d))throw d;i++,await Je(e,`Backfill thread ${c+1}/${n} (${l})`)}}return console.log(`
98
98
  Backfill complete: ${s.length} read, ${r} failed${i?`, ${i} skipped on CDP recovery`:""}`),o.length>n&&console.log(` ${o.length-n} more remaining (run again or increase --max)`),s}function Js(e){let t=qt(),o=Object.values(e),n=o.filter(c=>c.sources?.includes("recruiters-from-jobs")&&!c.connectionStatus).length,s=o.filter(c=>c.connectionStatus==="modal_failed").length,r=n+s,i=o.filter(c=>c.connectionStatus==="connected"&&c.connectionMethod).length,a=o.filter(c=>c.connectionStatus==="pending"||c.connectionStatus==="sent_without_note").length;console.log("\u2550\u2550\u2550 CONNECTION QUOTA & QUEUE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),console.log(` Today: ${t.daily.sent}/${t.daily.max} sent (${t.daily.remaining} remaining)`),console.log(` Week: ${t.weekly.sent}/${t.weekly.max} sent (${t.weekly.remaining} remaining)`),console.log(` Queue: ${r} profiles (${n} new, ${s} retry)`),console.log(` Funnel: ${i} accepted, ${a} pending`),r===0&&console.log(" \u26A0 Queue empty \u2014 need new job applications to feed funnel"),console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}function Hs(e){let t=Object.values(e).filter(o=>o.jobCount>=2).sort((o,n)=>(n.jobCount||0)-(o.jobCount||0)).slice(0,10);if(t.length!==0){console.log("\u2550\u2550\u2550 TOP RECRUITERS (by job count) \u2550\u2550\u2550");for(let o=0;o<t.length;o++){let n=t[o],s=n.connectionStatus==="connected"?"connected":n.connectionStatus==="pending"||n.connectionStatus==="sent_without_note"?"pending":n.connectionStatus||"unknown",r=n.lastJobTitle?G(n.lastJobTitle,25):"",i=n.lastJobDate||"",a=r?` (last: ${r}${i?", "+i:""})`:"";console.log(` ${String(o+1).padStart(2)}. ${G(n.name||"?",25).padEnd(25)} ${String(n.jobCount).padStart(2)} jobs | ${s.padEnd(10)}${a}`)}console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}}function Vs(){let e=zt(10);if(e.length!==0){console.log("\u2550\u2550\u2550 TOP JOBS TO APPLY \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");for(let t=0;t<e.length;t++){let{score:o,job:n}=e[t],s=G(n.title||"?",30),r=G(n.company||"?",15),i=n.salary?` \u2014 ${G(n.salary,12)}`:"",a=n.location?` \u2014 ${G(n.location,15)}`:"",c=n.recruiterUrl?" \u{1F464}":"";console.log(` ${String(t+1).padStart(2)}. [${String(o).padStart(2)}] ${s} @ ${r}${i}${a}${c}`)}console.log(" Apply: npm run apply-queue"),console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}}function Ws(){let e=Yt();e.totalJobs===0&&e.totalVisited===0||(console.log("\u2550\u2550\u2550 MARKET RESEARCH \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"),console.log(` Scouted jobs: ${e.totalJobs}${e.lastScoutDate?` (last: ${e.lastScoutDate})`:""}`),console.log(` Discovered people: ${e.totalRecruiters}`),console.log(` Profile visits: ${e.totalVisited} unique (${e.todayVisited} today)`),e.topTech.length>0&&console.log(` Top tech: ${e.topTech.slice(0,5).join(", ")}`),e.topCompanies.length>0&&console.log(` Top companies: ${e.topCompanies.slice(0,5).join(", ")}`),console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"))}function Ys(){let e=Ht();if(e.totalApplications!==0){if(console.log(`\u2550\u2550\u2550 FAQ STATS (${e.totalApplications} applications) \u2550\u2550`),console.log(` Unique questions: ${e.uniqueQuestions}`),e.topQuestions.length>0){console.log(" Top questions:");for(let t of e.topQuestions.slice(0,8)){let o=G(t.topAnswer,30);console.log(` "${G(t.question,40)}" \u2014 ${t.count}x \u2192 ${o}`)}}if(e.inconsistent.length>0){console.log(` Inconsistent answers: ${e.inconsistent.length} \u26A0`);for(let t of e.inconsistent.slice(0,3))console.log(` "${G(t.question,35)}" \u2014 ${t.answers.join(", ")}`)}console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550")}}function G(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function Gs(){let e=Te(),t=W(),o=new Set(Object.keys(e)),n=new Set(Object.values(e).map(g=>g.profileUrl).filter(Boolean));console.log(`
99
99
  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`),console.log(" TODAY'S PRIORITIES"),console.log(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
100
100
  `),console.log(po()),console.log(""),Js(t),console.log(""),Hs(t),console.log(""),Ws(),console.log(""),Vs(),console.log(""),Ys(),console.log("");let s=Object.entries(e),r=s.filter(([,g])=>g.unread===!0).sort((g,p)=>(p[1].lastMessageTime||"").localeCompare(g[1].lastMessageTime||""));if(r.length>0){let g=r.slice(0,10);console.log(` UNREAD ON LINKEDIN (${r.length}) \u2014 bold in LinkedIn UI, not yet opened:
@@ -106,9 +106,9 @@ ${n.join(`
106
106
  `);for(let p=0;p<g.length;p++){let[w,C]=g[p],R=C.category?` [${C.category}]`:"",I=C.summary||"";console.log(` ${p+1}. ${w}${R} \u2014 ${I}`)}S.length>5&&console.log(` ... +${S.length-5} more`),console.log()}let y=Object.entries(t).filter(([g,p])=>p.connectionStatus==="connected"&&p.personActionNeeded==="initiate_contact"&&!n.has(g)&&!(p.name&&o.has(p.name))).sort((g,p)=>{let w={high:0,medium:1,low:2}[g[1].personPriority]??3,C={high:0,medium:1,low:2}[p[1].personPriority]??3;return w!==C?w-C:(p[1].connectionDate||"").localeCompare(g[1].connectionDate||"")});if(y.length>0){let g=y.slice(0,10);console.log(` NEW CONNECTIONS TO MESSAGE (${y.length}):
107
107
  `);for(let p=0;p<g.length;p++){let[,w]=g[p],C=w.personPriority?`[${w.personPriority.toUpperCase()}]`:"",R=w.connectionDate?zs(w.connectionDate):"",I=w.title?`${w.title}${w.company?` at ${w.company}`:""}`:w.company||"";console.log(` ${p+1}. ${C} ${w.name||"Unknown"} \u2014 ${I}${R?` (${R})`:""}`)}y.length>10&&console.log(` ... +${y.length-10} more`),console.log()}let v=s.filter(([,g])=>ye(g));if(v.length>0){let g=v.filter(([,w])=>ye(w)===j.CONFIRMED).length,p=v.filter(([,w])=>{let C=ye(w);return C===j.DRAFT||C===j.NEEDS_REVIEW}).length;console.log(` DRAFTS: ${v.length} (${g} confirmed, ${p} pending)`),g>0&&console.log(" Send: npm run messages -- --push-drafts"),p>0&&console.log(" Review: npm run messages -- --review-drafts"),console.log()}let $=s.filter(([,g])=>g.conversationStatus==="unanswered_by_us").length,k=s.filter(([,g])=>g.conversationStatus==="awaiting_reply").length;console.log(` Summary: ${r.length} unread on LinkedIn, ${d.length} unreviewed, ${$} need reply, ${y.length} new connections, ${k} ball in their court`),console.log(`
108
108
  \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
109
- `)}function zs(e){let t=new Date(e);if(isNaN(t))return"";let o=Math.floor((Date.now()-t.getTime())/864e5);return o===0?"today":o===1?"1d ago":`${o}d ago`}function Ks(){let e=Te();_t(e,null,null)}async function Qs(){if(console.log(`
109
+ `)}function zs(e){let t=new Date(e);if(isNaN(t))return"";let o=Math.floor((Date.now()-t.getTime())/864e5);return o===0?"today":o===1?"1d ago":`${o}d ago`}function Ks(){let e=Te();At(e,null,null)}async function Qs(){if(console.log(`
110
110
  LinkedIn Sync-All
111
- `),Ao){Gs();return}if(To){let i=Ue("sync-all","report");Ks(),he(i,"success");return}if(_o){let i=Ue("sync-all","enrich");try{Bs(),he(i,"success")}catch(a){throw he(i,"error",null,a.message),a}return}let e=Eo?"backfill":Ct?"full":"incremental",t=Ue("sync-all",e),o={scanned:0,toReRead:0,threadsRead:0,newMessages:0};L&&console.log(" [DRY RUN mode]"),console.log(` Mode: ${e} | Max threads to read: ${Oe}`);let n=Te(),s=await eo(),r={browser:s.browser,page:s.page};try{await ot(r.page);let i=null,a=[];if(Eo)a=await qs(r,n);else{let c=0;for(;;)try{i=await Fs(r.page,n);break}catch(u){if(!le(u))throw u;if(c++,c>=kt)throw new Error(`Phase 1 failed ${kt} times on CDP death \u2014 giving up. Last: ${u.message}`);console.log(`
112
- \u26A0 Phase 1 CDP dead (attempt ${c}/${kt}). Recovering and restarting Phase 1...`),await Je(r,`Phase 1 attempt ${c}`)}let l=new Set;a=await Ls(r,i.toReRead,n,l),o.scanned=i.totalCards||0,o.toReRead=i.toReRead?.size||0;let f=new Set(a.map(u=>u.name)),d=0;for(let[u,{card:m}]of i.toReRead){if(f.has(u)||l.has(u))continue;let S=n[u];S&&(S.lastMessageBy=m.lastMessageBy,S.lastMessageTime=m.lastMessageTime||S.lastMessageTime,S.unread=m.unread,d++)}d>0&&(console.log(` Pending re-read: ${d} threads (raise --max or re-run to drain).`),L||X(n))}o.threadsRead=a.length,o.newMessages=a.reduce((c,l)=>c+(l.newMessages||0),0),a.length>0&&Us(n,a),_t(n,i,a,{unreadCards:i?.unreadCards,readUnread:Et}),ue.pageRecoveries>0&&console.log(`
111
+ `),_o){Gs();return}if(To){let i=Ue("sync-all","report");Ks(),he(i,"success");return}if(Ao){let i=Ue("sync-all","enrich");try{Bs(),he(i,"success")}catch(a){throw he(i,"error",null,a.message),a}return}let e=Eo?"backfill":Ct?"full":"incremental",t=Ue("sync-all",e),o={scanned:0,toReRead:0,threadsRead:0,newMessages:0};L&&console.log(" [DRY RUN mode]"),console.log(` Mode: ${e} | Max threads to read: ${Oe}`);let n=Te(),s=await eo(),r={browser:s.browser,page:s.page};try{await ot(r.page);let i=null,a=[];if(Eo)a=await qs(r,n);else{let c=0;for(;;)try{i=await Fs(r.page,n);break}catch(u){if(!le(u))throw u;if(c++,c>=kt)throw new Error(`Phase 1 failed ${kt} times on CDP death \u2014 giving up. Last: ${u.message}`);console.log(`
112
+ \u26A0 Phase 1 CDP dead (attempt ${c}/${kt}). Recovering and restarting Phase 1...`),await Je(r,`Phase 1 attempt ${c}`)}let l=new Set;a=await Ls(r,i.toReRead,n,l),o.scanned=i.totalCards||0,o.toReRead=i.toReRead?.size||0;let f=new Set(a.map(u=>u.name)),d=0;for(let[u,{card:m}]of i.toReRead){if(f.has(u)||l.has(u))continue;let S=n[u];S&&(S.lastMessageBy=m.lastMessageBy,S.lastMessageTime=m.lastMessageTime||S.lastMessageTime,S.unread=m.unread,d++)}d>0&&(console.log(` Pending re-read: ${d} threads (raise --max or re-run to drain).`),L||X(n))}o.threadsRead=a.length,o.newMessages=a.reduce((c,l)=>c+(l.newMessages||0),0),a.length>0&&Us(n,a),At(n,i,a,{unreadCards:i?.unreadCards,readUnread:Et}),ue.pageRecoveries>0&&console.log(`
113
113
  CDP page recoveries this run: ${ue.pageRecoveries}`),L||et(),he(t,"success",o)}catch(i){console.error(`
114
- Error:`,i.message),Tt&&console.error(i.stack),he(t,"error",o,i.message)}finally{if(!L&&!To&&!_o&&!Ao)try{et()}catch{}await r.browser.close()}}Qs();
114
+ Error:`,i.message),Tt&&console.error(i.stack),he(t,"error",o,i.message)}finally{if(!L&&!To&&!Ao&&!_o)try{et()}catch{}await r.browser.close()}}Qs();