ilml-plugin-linkedin 1.11.2 → 1.11.3
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/CHANGELOG.md +3 -0
- package/dist/applyQueue.mjs +28 -28
- package/dist/daily.mjs +24 -24
- package/dist/enrichProfiles.mjs +1 -1
- package/dist/funnelRunner.mjs +28 -28
- package/dist/messageBot.mjs +6 -6
- package/dist/migrationCli.mjs +19 -19
- package/dist/profileHistory.mjs +5 -5
- package/dist/run.mjs +40 -40
- package/dist/scout.mjs +1 -1
- package/dist/syncAll.mjs +8 -8
- package/dist/verifyAbout.mjs +1 -1
- package/dist/viewers.mjs +1 -1
- package/dist/visit.mjs +1 -1
- package/ilml-plugin.json +1 -1
- package/package.json +1 -1
package/dist/scout.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var bt=Object.defineProperty;var Ae=(e,t)=>{for(var o in t)bt(e,o,{get:t[o],enumerable:!0})};import _t from"puppeteer";import{addExtra as Et}from"puppeteer-extra";import At from"puppeteer-extra-plugin-stealth";async function I(e){let t=Math.floor(Math.random()*2001),o=e+t;return new Promise(r=>setTimeout(r,o))}import{getPluginConfig as St}from"@ilivemylife/graph-sdk";var wt=await St();for(let[e,t]of Object.entries(wt))process.env[e]===void 0&&(process.env[e]=t);var vt=process.env.LINKEDIN_NAME,J=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Mo=Object.freeze(new Set([J.DRAFT,J.CONFIRMED,J.NEEDS_REVIEW])),kt=Object.freeze(new Set([J.DRAFT,J.CONFIRMED,J.REJECTED,J.NEEDS_REVIEW]));import xe from"fs";import jt from"path";var Tt="cookies.json";function $t(){let e=process.env.ILML_SCOPE_DIR;return e?jt.join(e,"plugins-state","linkedin","cookies.json"):Tt}function Ce(){let e=$t();if(!xe.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=xe.readFileSync(e,"utf-8")}catch(r){throw new Error(`Failed to read cookies at ${e}: ${r.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 Ie=Et(_t);Ie.use(At());async function Re(){let e=await Ie.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 r=Ce();await o.setCookie(...r),console.log(" Browser launched, cookies loaded.")}catch(r){console.error(`
|
|
3
3
|
[!] ${r.message}
|
|
4
|
-
`),await e.close(),process.exit(1)}return{browser:e,page:o}}async function De(e){let t=[".jobs-search-results-list",".scaffold-layout__list-container",".jobs-search-two-pane__results","div.jobs-search-results-list"];return await e.evaluate(async r=>{let n=null,s=null;for(let g of r)if(n=document.querySelector(g),n){s=g;break}if(!n){let g=document.querySelector("li.scaffold-layout__list-item");if(g){let u=g.parentElement;for(;u&&u!==document.body;){if(u.scrollHeight>u.clientHeight){n=u,s="parent of li.scaffold-layout__list-item";break}u=u.parentElement}}}if(!n)return{found:!1,triedSelectors:r};let i=n.scrollTop,c=300,l=300,f=50,d=0;for(;d<f&&(n.scrollBy(0,c),await new Promise(g=>setTimeout(g,l)),!(n.scrollTop+n.clientHeight>=n.scrollHeight));)d++;return{found:!0,usedSelector:s,initialScroll:i,finalScroll:n.scrollTop,scrollHeight:n.scrollHeight,attempts:d}},t)}async function Oe(e,{easyApplyOnly:t=!0}={}){let o=await e.evaluate(()=>{let r=document.querySelectorAll("li.scaffold-layout__list-item");return Array.from(r).map(n=>{let i=(n.querySelector(".job-card-list__footer-wrapper")?.innerText??"").includes("Easy Apply"),c=n.querySelector("a.job-card-container__link");if(c){let l=c.getAttribute("href").split("?")[0],f=n.querySelector(".job-card-list__title--link")?.getAttribute("aria-label")?.replace(/ with verification$/,""),d=n.querySelector(".artdeco-entity-lockup__subtitle")?.innerText.trim(),g=n.querySelector(".artdeco-entity-lockup__caption")?.innerText.trim(),u=n.querySelector(".artdeco-entity-lockup__metadata")?.innerText.trim();return{id:l,isEasyApply:i,applyType:i?"easy-apply":"external",dataId:c.getAttribute("data-control-id"),href:`https://linkedin.com${l}`,jobTitle:f,companyName:d,location:g,salary:u||null,jobLink:i?c.href:null}}return{isEasyApply:!1}})});return t?o.filter(r=>r.isEasyApply&&r.href):o.filter(r=>r.href)}async function Ne(e){let t=await e.evaluate(()=>{let o=document.querySelector('button[aria-label="View next page"]')||document.querySelector(".jobs-search-pagination__button--next");if(o&&!o.disabled){let r=document.querySelector(".jobs-search-pagination__page-state")?.textContent?.trim();return o.click(),{success:!0,pageState:r}}return{success:!1,reason:"No next page button found"}});return console.log(" Pagination:",t.success?t.pageState:t.reason),t.success&&await I(2e3),t.success}async function Fe(e,t){let o=e.url();if(o.includes("/jobs/"))return!1;if(o.includes("/login")||o.includes("/authwall")||o.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: npm run login");console.log(` Off-track: ${o.slice(0,80)}`),console.log(" Navigating back to job search..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await I(3e3);let n=e.url();if(!n.includes("/jobs/"))throw new Error(`Could not return to job search. Current URL: ${n.slice(0,80)}`);return console.log(" Recovered to job search page"),!0}async function Le(e){return e.evaluate(()=>{let t=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,o=t.querySelector(".hirer-card__hirer-information");if(o){let i=o.querySelector('a[href*="/in/"]'),c=o.querySelector(".jobs-poster__name")||o.querySelector("strong")||o.querySelector('[class*="name"]');if(i)return{name:c?.textContent?.trim()||i.textContent?.trim(),profileUrl:i.href?.split("?")[0],source:"hiring_team"}}let r=t.querySelector(".jobs-poster__name");if(r){let i=r.closest('a[href*="/in/"]')||r.parentElement?.querySelector('a[href*="/in/"]')||r.parentElement?.parentElement?.querySelector('a[href*="/in/"]');if(i)return{name:r.textContent?.trim(),profileUrl:i.href?.split("?")[0],source:"poster_name"}}let n=t.querySelector(".job-details-people-who-can-help__section--two-pane")||t.querySelector('[class*="people-who-can-help"]');if(n){let i=n.querySelector('a[href*="/in/"]');if(i)return{name:(n.querySelector(".jobs-poster__name")||n.querySelector("strong"))?.textContent?.trim()||i.textContent?.trim(),profileUrl:i.href?.split("?")[0],source:"people_section"}}let s=t.querySelectorAll('a[href*="/in/"]');for(let i of s){let c=i.textContent?.trim();if(c&&c.length>3&&!["View","Connect","Follow","Message","Apply","Save"].includes(c))return{name:c,profileUrl:i.href?.split("?")[0],source:"details_link"}}return null})}async function Pe(e){return e.evaluate(()=>{let t=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,r=(t.querySelector(".jobs-description__content")||t.querySelector(".jobs-box__html-content")||t.querySelector(".jobs-description"))?.innerText?.trim()||"",n={},s=t.querySelectorAll(".jobs-unified-top-card__job-insight, li.job-criteria__item");for(let U of s){let fe=U.querySelector(".job-criteria__subheader")?.textContent?.trim(),Ee=U.querySelector(".job-criteria__text")?.textContent?.trim();fe&&Ee&&(n[fe.toLowerCase()]=Ee)}let i=["Java","Python","JavaScript","TypeScript","React","Angular","Vue","Node.js","C#",".NET","C\\+\\+","Go","Rust","Scala","Kotlin","AWS","Azure","GCP","Docker","Kubernetes","Terraform","SQL","PostgreSQL","MongoDB","Redis","Kafka","RabbitMQ","Spring","Django","Flask","Express","Next.js","CI/CD","Jenkins","GitHub Actions","GraphQL","REST","Microservices","Machine Learning","AI","Data Engineering","Spark","Hadoop","Snowflake","Databricks","Airflow","iOS","Android","React Native","Flutter","Agile","Scrum","DevOps","SRE"],c=[];for(let U of i)new RegExp("\\b"+U.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\b","i").test(r)&&c.push(U.replace(/\\\+/g,"+"));let f=t.querySelector('.jobs-company__box, [class*="jobs-company"], [class*="company-card"]')?.innerText?.trim()?.slice(0,1e3)||null,g=t.querySelector('a.jobs-apply-button[href], a[data-tracking-control-name="public_jobs_apply-link-offsite_sign-up"]')?.getAttribute("href")||null,u=t.querySelector(".job-details-jobs-unified-top-card__company-name, .jobs-unified-top-card__company-name"),p=u?.innerText?.trim()||null,b=(u?.querySelector('a[href*="/company/"]')||t.querySelector('a[href*="/company/"]'))?.getAttribute("href")?.split("?")[0]||null,y=t.querySelector(".job-details-jobs-unified-top-card__primary-description-container")?.innerText?.trim()||"",F=y.match(/(\d+\s+(?:hour|day|week|month)s?\s+ago|Reposted|Just now)/i)?.[0]||null,L=y.match(/(\d[\d,]*)\s+applicant/i),le=L?parseInt(L[1].replace(/,/g,"")):null,ae=t.querySelectorAll(".job-details-jobs-unified-top-card__job-insight"),te=Array.from(ae).map(U=>U.innerText?.trim()?.replace(/\s+/g," ")),ue=te.join(" ").match(/([\d,]+-[\d,]+\s+employees|[\d,]+\+?\s+employees)/i)?.[0]||null,P=te.join(" ")+" "+y,gt=/\bremote\b/i.test(P)?"remote":/\bhybrid\b/i.test(P)?"hybrid":/\bon-?site\b/i.test(P)?"onsite":null,yt=/\bcontract\b/i.test(P)?"contract":/\bfull-?time\b/i.test(P)?"full-time":/\bpart-?time\b/i.test(P)?"part-time":/\bfreelance\b/i.test(P)?"freelance":/\btemporary\b/i.test(P)?"temporary":null,$e=t.querySelector(".job-details-jobs-unified-top-card__job-title, .jobs-unified-top-card__job-title, h2.t-24")?.innerText?.trim()||"",ne=t.querySelector(".job-details-jobs-unified-top-card__primary-description-container, .jobs-unified-top-card__subtitle-primary-grouping")?.innerText?.trim()||"",x=($e+" "+r+" "+ne).toLowerCase(),C=$e.toLowerCase(),m=[];/\bremote\b/.test(x)&&m.push("remote"),/\bhybrid\b/.test(x)&&m.push("hybrid"),/\bon-?site\b|\bin-?office\b/.test(x)&&m.push("onsite"),(m.length===0||!m.includes("remote")&&!m.includes("hybrid")&&!m.includes("onsite"))&&/remote/i.test(ne)&&m.push("remote"),/\b(manager|director|vp|vice president|head of|chief|cto|cio|lead.*team|managing)\b/i.test(C)&&m.push("managerial"),/\b(architect|principal|staff|distinguished)\b/i.test(C)&&m.push("senior-ic"),/\b(developer|engineer|programmer|analyst)\b/i.test(C)&&!m.includes("managerial")&&m.push("ic"),/\b(junior|jr\.?|entry)\b/i.test(C)?m.push("junior"):/\b(senior|sr\.?)\b/i.test(C)?m.push("senior"):/\b(staff|principal|distinguished)\b/i.test(C)?m.push("staff+"):/\b(director|vp|chief|cto|cio)\b/i.test(C)?m.push("executive"):/\b(lead|team lead)\b/i.test(C)&&m.push("lead"),/\b(backend|back-end|server-side|api)\b/i.test(x)&&m.push("backend"),/\b(frontend|front-end|ui|ux)\b/i.test(x)&&m.push("frontend"),/\b(full.?stack|fullstack)\b/i.test(x)&&m.push("fullstack"),/\b(devops|sre|infrastructure|platform)\b/i.test(x)&&m.push("devops"),/\b(data engineer|data science|machine learning|ml engineer)\b/i.test(x)&&m.push("data"),/\b(mobile|ios|android|react native|flutter)\b/i.test(x)&&m.push("mobile"),/\b(architect)\b/i.test(C)&&m.push("architect"),/\b(consultant|consulting)\b/i.test(C)&&m.push("consultant");let _e=(n["employment type"]||"").toLowerCase();return(/contract|freelance|temporary/i.test(_e)||/\bcontract\b/i.test(x))&&m.push("contract"),/full.?time|permanent/i.test(_e)&&m.push("permanent"),/\bcanada\b|toronto|vancouver|montreal|ontario|british columbia|quebec|alberta|calgary|ottawa/i.test(ne)&&m.push("canada"),/\bunited states\b|\busa\b|new york|california|texas|seattle|san francisco/i.test(ne)&&m.push("usa"),(t.querySelector(".jobs-unified-top-card__job-insight--highlight, .compensation__salary")?.innerText?.trim()||""||/\$[\d,]+/.test(r))&&m.push("has-salary"),{description:r.substring(0,5e3),externalApplyUrl:g,companyName:p,companyUrl:b?b.startsWith("/")?"https://www.linkedin.com"+b:b:null,aboutCompany:f,seniority:n["seniority level"]||null,employmentType:n["employment type"]||null,industries:n.industries||null,jobFunction:n["job function"]||null,postedTime:F,applicantCount:le,companySize:ue,workplaceType:gt,contractType:yt,techStack:[...new Set(c)],jobTags:[...new Set(m)]}})}import"dotenv/config";import*as $ from"fs";import*as T from"path";import{fileURLToPath as xt}from"url";var Ct=xt(import.meta.url),It=T.dirname(T.dirname(Ct)),H=process.env.DATA_DIR?T.resolve(process.env.DATA_DIR,"market-research"):T.join(It,"market-research"),Me=T.join(H,"scouted-jobs.json"),qe=T.join(H,"discovered-people.json"),Rt=T.join(H,"visit-log.json"),Ue=T.join(H,"companies.json"),cn=T.join(H,"job-decisions.json");function pe(){$.existsSync(H)||$.mkdirSync(H,{recursive:!0})}function de(e,t){let o=JSON.stringify(t,null,2),r=e+".tmp";$.writeFileSync(r,o);for(let n=0;n<3;n++)try{$.renameSync(r,e);return}catch(s){if(n<2&&(s.code==="EPERM"||s.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw s}}function re(e){try{if($.existsSync(e))return JSON.parse($.readFileSync(e,"utf-8"))}catch{}return null}function Je(){z=null,Dt=null,K=null,Q=null,B=null}var z=null;function se(){return z||(z=re(Me)||{},z)}function Be(e,t){if(!e)return;pe();let o=se(),r=new Date().toISOString().slice(0,10);if(o[e]){for(let[n,s]of Object.entries(t))s!=null&&(o[e][n]=s);o[e].lastSeen=r}else o[e]={...t,scoutedAt:r,lastSeen:r};try{de(Me,o)}catch(n){console.error(`[!] Failed to save scouted-jobs.json: ${n.message}`)}}var Dt=null;var K=null;function He(){return K||(K=re(qe)||{},K)}function Ve(e,t){if(!e)return;pe();let o=He(),r=new Date().toISOString().slice(0,10);if(o[e]){let n=o[e];t.name&&(n.name=t.name),t.title&&(n.title=t.title),t.company&&(n.company=t.company),t.location&&(n.location=t.location),t.role&&(n.role=t.role),t.isConnected!=null&&(n.isConnected=t.isConnected),t.jobId&&(n.jobIds||(n.jobIds=[]),n.jobIds.includes(t.jobId)||n.jobIds.push(t.jobId)),n.lastSeen=r,n.seenCount=(n.seenCount||1)+1}else o[e]={name:t.name||null,title:t.title||null,company:t.company||null,location:t.location||null,role:t.role||null,source:t.source||"scout",isConnected:t.isConnected||!1,discoveredAt:r,lastSeen:r,seenCount:1,jobIds:t.jobId?[t.jobId]:[]};try{de(qe,o)}catch(n){console.error(`[!] Failed to save discovered-people.json: ${n.message}`)}}var Q=null;function Ot(){return Q||(Q=re(Ue)||{},Q)}function We(e,t){if(!e)return;pe();let o=Ot(),r=new Date().toISOString().slice(0,10);if(o[e]){let n=o[e];t.name&&(n.name=t.name),t.about&&(n.about=t.about),t.size&&(n.size=t.size),t.industries&&(n.industries=t.industries),t.jobId&&(n.jobIds||(n.jobIds=[]),n.jobIds.includes(t.jobId)||n.jobIds.push(t.jobId)),t.recruiterUrl&&(n.recruiterUrls||(n.recruiterUrls=[]),n.recruiterUrls.includes(t.recruiterUrl)||n.recruiterUrls.push(t.recruiterUrl)),n.lastSeen=r,n.jobCount=n.jobIds?.length||0}else o[e]={name:t.name||null,about:t.about||null,size:t.size||null,industries:t.industries||null,discoveredAt:r,lastSeen:r,jobIds:t.jobId?[t.jobId]:[],recruiterUrls:t.recruiterUrl?[t.recruiterUrl]:[],jobCount:t.jobId?1:0};try{de(Ue,o)}catch(n){console.error(`[!] Failed to save companies.json: ${n.message}`)}}var B=null;function Nt(){return B||(B=re(Rt)||{visits:[]},Array.isArray(B.visits)||(B.visits=[]),B)}function Ge(){let e=se(),t=He(),o=Object.values(e),r=Object.values(t),n={};for(let u of o)u.company&&(n[u.company]=(n[u.company]||0)+1);let s=Object.entries(n).sort((u,p)=>p[1]-u[1]).slice(0,5).map(([u,p])=>`${u} (${p})`),i={};for(let u of o)for(let p of u.techStack||[])i[p]=(i[p]||0)+1;let c=Object.entries(i).sort((u,p)=>p[1]-u[1]).slice(0,8).map(([u,p])=>`${u} (${p})`),l=Nt(),f=new Date().toISOString().slice(0,10),d=l.visits.filter(u=>u.date.startsWith(f)).length,g=new Set(l.visits.map(u=>u.profileUrl)).size;return{totalJobs:o.length,totalRecruiters:r.length,topCompanies:s,topTech:c,totalVisited:g,todayVisited:d,lastScoutDate:o.length>0?o.sort((u,p)=>(p.scoutedAt||"").localeCompare(u.scoutedAt||""))[0]?.scoutedAt:null}}import"dotenv/config";import*as S from"fs";import*as v from"path";import{fileURLToPath as Ft}from"url";var Lt=Ft(import.meta.url),Pt=v.dirname(v.dirname(Lt)),O=process.env.DATA_DIR?v.resolve(process.env.DATA_DIR,"collected-profiles"):v.join(Pt,"collected-profiles"),Mt=v.join(O,"people.json"),qt=v.join(O,"jobs.json"),fn=v.join(O,"quota.json"),pn=v.join(O,"conversations.json"),dn=v.join(O,"sync-state.json"),mn=v.join(O,"application-questions.json"),hn=v.join(O,"profile-history");var X=null,Z=null,Ut=null,Jt=null,Bt=null,Ht=null;function Ye(){X=null,Z=null,Ut=null,Jt=null,Bt=null,Ht=null}function ze(){S.existsSync(O)||S.mkdirSync(O,{recursive:!0})}function Ke(e,t){if(!S.existsSync(e))return null;try{let o=JSON.parse(S.readFileSync(e,"utf-8"));try{S.copyFileSync(e,e+".backup")}catch{}return o}catch(o){console.error(`[!] ${t} is corrupted: ${o.message}`),console.error(` File: ${v.resolve(e)}`);let r=e+".backup";if(S.existsSync(r))try{let n=JSON.parse(S.readFileSync(r,"utf-8"));console.error(` Restored from ${r}`);try{S.copyFileSync(r,e)}catch{}return n}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{S.copyFileSync(e,e+".corrupted")}catch{}return null}}function Qe(){return X||(ze(),X=Ke(Mt,"people.json")||{},X)}function Xe(){return Z||(ze(),Z=Ke(qt,"jobs.json")||{},Z)}import"dotenv/config";import*as _ from"fs";import*as M from"path";import{fileURLToPath as Kt}from"url";import"dotenv/config";import{createGraphClient as Vt,resolveToken as Wt}from"@ilivemylife/graph-sdk";import{config as Gt}from"dotenv";Gt();var Ze=Wt()||process.env.TOKEN;Ze||(console.error(`
|
|
4
|
+
`),await e.close(),process.exit(1)}return{browser:e,page:o}}async function De(e){let t=[".jobs-search-results-list",".scaffold-layout__list-container",".jobs-search-two-pane__results","div.jobs-search-results-list"];return await e.evaluate(async r=>{let n=null,s=null;for(let g of r)if(n=document.querySelector(g),n){s=g;break}if(!n){let g=document.querySelector("li.scaffold-layout__list-item");if(g){let u=g.parentElement;for(;u&&u!==document.body;){if(u.scrollHeight>u.clientHeight){n=u,s="parent of li.scaffold-layout__list-item";break}u=u.parentElement}}}if(!n)return{found:!1,triedSelectors:r};let i=n.scrollTop,c=300,l=300,f=50,d=0;for(;d<f&&(n.scrollBy(0,c),await new Promise(g=>setTimeout(g,l)),!(n.scrollTop+n.clientHeight>=n.scrollHeight));)d++;return{found:!0,usedSelector:s,initialScroll:i,finalScroll:n.scrollTop,scrollHeight:n.scrollHeight,attempts:d}},t)}async function Oe(e,{easyApplyOnly:t=!0}={}){let o=await e.evaluate(()=>{let r=document.querySelectorAll("li.scaffold-layout__list-item");return Array.from(r).map(n=>{let i=(n.querySelector(".job-card-list__footer-wrapper")?.innerText??"").includes("Easy Apply"),c=n.querySelector("a.job-card-container__link");if(c){let l=c.getAttribute("href").split("?")[0],f=n.querySelector(".job-card-list__title--link")?.getAttribute("aria-label")?.replace(/ with verification$/,""),d=n.querySelector(".artdeco-entity-lockup__subtitle")?.innerText.trim(),g=n.querySelector(".artdeco-entity-lockup__caption")?.innerText.trim(),u=n.querySelector(".artdeco-entity-lockup__metadata")?.innerText.trim();return{id:l,isEasyApply:i,applyType:i?"easy-apply":"external",dataId:c.getAttribute("data-control-id"),href:`https://linkedin.com${l}`,jobTitle:f,companyName:d,location:g,salary:u||null,jobLink:i?c.href:null}}return{isEasyApply:!1}})});return t?o.filter(r=>r.isEasyApply&&r.href):o.filter(r=>r.href)}async function Ne(e){let t=await e.evaluate(()=>{let o=document.querySelector('button[aria-label="View next page"]')||document.querySelector(".jobs-search-pagination__button--next");if(o&&!o.disabled){let r=document.querySelector(".jobs-search-pagination__page-state")?.textContent?.trim();return o.click(),{success:!0,pageState:r}}return{success:!1,reason:"No next page button found"}});return console.log(" Pagination:",t.success?t.pageState:t.reason),t.success&&await I(2e3),t.success}async function Fe(e,t){let o=e.url();if(o.includes("/jobs/"))return!1;if(o.includes("/login")||o.includes("/authwall")||o.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: npm run login");console.log(` Off-track: ${o.slice(0,80)}`),console.log(" Navigating back to job search..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await I(3e3);let n=e.url();if(!n.includes("/jobs/"))throw new Error(`Could not return to job search. Current URL: ${n.slice(0,80)}`);return console.log(" Recovered to job search page"),!0}async function Le(e){return e.evaluate(()=>{let t=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,o=t.querySelector(".hirer-card__hirer-information");if(o){let i=o.querySelector('a[href*="/in/"]'),c=o.querySelector(".jobs-poster__name")||o.querySelector("strong")||o.querySelector('[class*="name"]');if(i)return{name:c?.textContent?.trim()||i.textContent?.trim(),profileUrl:i.href?.split("?")[0],source:"hiring_team"}}let r=t.querySelector(".jobs-poster__name");if(r){let i=r.closest('a[href*="/in/"]')||r.parentElement?.querySelector('a[href*="/in/"]')||r.parentElement?.parentElement?.querySelector('a[href*="/in/"]');if(i)return{name:r.textContent?.trim(),profileUrl:i.href?.split("?")[0],source:"poster_name"}}let n=t.querySelector(".job-details-people-who-can-help__section--two-pane")||t.querySelector('[class*="people-who-can-help"]');if(n){let i=n.querySelector('a[href*="/in/"]');if(i)return{name:(n.querySelector(".jobs-poster__name")||n.querySelector("strong"))?.textContent?.trim()||i.textContent?.trim(),profileUrl:i.href?.split("?")[0],source:"people_section"}}let s=t.querySelectorAll('a[href*="/in/"]');for(let i of s){let c=i.textContent?.trim();if(c&&c.length>3&&!["View","Connect","Follow","Message","Apply","Save"].includes(c))return{name:c,profileUrl:i.href?.split("?")[0],source:"details_link"}}return null})}async function Pe(e){return e.evaluate(()=>{let t=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,r=(t.querySelector(".jobs-description__content")||t.querySelector(".jobs-box__html-content")||t.querySelector(".jobs-description"))?.innerText?.trim()||"",n={},s=t.querySelectorAll(".jobs-unified-top-card__job-insight, li.job-criteria__item");for(let U of s){let fe=U.querySelector(".job-criteria__subheader")?.textContent?.trim(),Ee=U.querySelector(".job-criteria__text")?.textContent?.trim();fe&&Ee&&(n[fe.toLowerCase()]=Ee)}let i=["Java","Python","JavaScript","TypeScript","React","Angular","Vue","Node.js","C#",".NET","C\\+\\+","Go","Rust","Scala","Kotlin","AWS","Azure","GCP","Docker","Kubernetes","Terraform","SQL","PostgreSQL","MongoDB","Redis","Kafka","RabbitMQ","Spring","Django","Flask","Express","Next.js","CI/CD","Jenkins","GitHub Actions","GraphQL","REST","Microservices","Machine Learning","AI","Data Engineering","Spark","Hadoop","Snowflake","Databricks","Airflow","iOS","Android","React Native","Flutter","Agile","Scrum","DevOps","SRE"],c=[];for(let U of i)new RegExp("\\b"+U.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\b","i").test(r)&&c.push(U.replace(/\\\+/g,"+"));let f=t.querySelector('.jobs-company__box, [class*="jobs-company"], [class*="company-card"]')?.innerText?.trim()?.slice(0,1e3)||null,g=t.querySelector('a.jobs-apply-button[href], a[data-tracking-control-name="public_jobs_apply-link-offsite_sign-up"]')?.getAttribute("href")||null,u=t.querySelector(".job-details-jobs-unified-top-card__company-name, .jobs-unified-top-card__company-name"),p=u?.innerText?.trim()||null,b=(u?.querySelector('a[href*="/company/"]')||t.querySelector('a[href*="/company/"]'))?.getAttribute("href")?.split("?")[0]||null,y=t.querySelector(".job-details-jobs-unified-top-card__primary-description-container")?.innerText?.trim()||"",F=y.match(/(\d+\s+(?:hour|day|week|month)s?\s+ago|Reposted|Just now)/i)?.[0]||null,L=y.match(/(\d[\d,]*)\s+applicant/i),le=L?parseInt(L[1].replace(/,/g,"")):null,ae=t.querySelectorAll(".job-details-jobs-unified-top-card__job-insight"),te=Array.from(ae).map(U=>U.innerText?.trim()?.replace(/\s+/g," ")),ue=te.join(" ").match(/([\d,]+-[\d,]+\s+employees|[\d,]+\+?\s+employees)/i)?.[0]||null,P=te.join(" ")+" "+y,gt=/\bremote\b/i.test(P)?"remote":/\bhybrid\b/i.test(P)?"hybrid":/\bon-?site\b/i.test(P)?"onsite":null,yt=/\bcontract\b/i.test(P)?"contract":/\bfull-?time\b/i.test(P)?"full-time":/\bpart-?time\b/i.test(P)?"part-time":/\bfreelance\b/i.test(P)?"freelance":/\btemporary\b/i.test(P)?"temporary":null,$e=t.querySelector(".job-details-jobs-unified-top-card__job-title, .jobs-unified-top-card__job-title, h2.t-24")?.innerText?.trim()||"",ne=t.querySelector(".job-details-jobs-unified-top-card__primary-description-container, .jobs-unified-top-card__subtitle-primary-grouping")?.innerText?.trim()||"",x=($e+" "+r+" "+ne).toLowerCase(),C=$e.toLowerCase(),m=[];/\bremote\b/.test(x)&&m.push("remote"),/\bhybrid\b/.test(x)&&m.push("hybrid"),/\bon-?site\b|\bin-?office\b/.test(x)&&m.push("onsite"),(m.length===0||!m.includes("remote")&&!m.includes("hybrid")&&!m.includes("onsite"))&&/remote/i.test(ne)&&m.push("remote"),/\b(manager|director|vp|vice president|head of|chief|cto|cio|lead.*team|managing)\b/i.test(C)&&m.push("managerial"),/\b(architect|principal|staff|distinguished)\b/i.test(C)&&m.push("senior-ic"),/\b(developer|engineer|programmer|analyst)\b/i.test(C)&&!m.includes("managerial")&&m.push("ic"),/\b(junior|jr\.?|entry)\b/i.test(C)?m.push("junior"):/\b(senior|sr\.?)\b/i.test(C)?m.push("senior"):/\b(staff|principal|distinguished)\b/i.test(C)?m.push("staff+"):/\b(director|vp|chief|cto|cio)\b/i.test(C)?m.push("executive"):/\b(lead|team lead)\b/i.test(C)&&m.push("lead"),/\b(backend|back-end|server-side|api)\b/i.test(x)&&m.push("backend"),/\b(frontend|front-end|ui|ux)\b/i.test(x)&&m.push("frontend"),/\b(full.?stack|fullstack)\b/i.test(x)&&m.push("fullstack"),/\b(devops|sre|infrastructure|platform)\b/i.test(x)&&m.push("devops"),/\b(data engineer|data science|machine learning|ml engineer)\b/i.test(x)&&m.push("data"),/\b(mobile|ios|android|react native|flutter)\b/i.test(x)&&m.push("mobile"),/\b(architect)\b/i.test(C)&&m.push("architect"),/\b(consultant|consulting)\b/i.test(C)&&m.push("consultant");let _e=(n["employment type"]||"").toLowerCase();return(/contract|freelance|temporary/i.test(_e)||/\bcontract\b/i.test(x))&&m.push("contract"),/full.?time|permanent/i.test(_e)&&m.push("permanent"),/\bcanada\b|toronto|vancouver|montreal|ontario|british columbia|quebec|alberta|calgary|ottawa/i.test(ne)&&m.push("canada"),/\bunited states\b|\busa\b|new york|california|texas|seattle|san francisco/i.test(ne)&&m.push("usa"),(t.querySelector(".jobs-unified-top-card__job-insight--highlight, .compensation__salary")?.innerText?.trim()||""||/\$[\d,]+/.test(r))&&m.push("has-salary"),{description:r.substring(0,5e3),externalApplyUrl:g,companyName:p,companyUrl:b?b.startsWith("/")?"https://www.linkedin.com"+b:b:null,aboutCompany:f,seniority:n["seniority level"]||null,employmentType:n["employment type"]||null,industries:n.industries||null,jobFunction:n["job function"]||null,postedTime:F,applicantCount:le,companySize:ue,workplaceType:gt,contractType:yt,techStack:[...new Set(c)],jobTags:[...new Set(m)]}})}import"dotenv/config";import*as $ from"fs";import*as T from"path";import{fileURLToPath as xt}from"url";var Ct=xt(import.meta.url),It=T.dirname(T.dirname(Ct)),H=process.env.DATA_DIR?T.resolve(process.env.DATA_DIR,"market-research"):T.join(It,"market-research"),Me=T.join(H,"scouted-jobs.json"),qe=T.join(H,"discovered-people.json"),Rt=T.join(H,"visit-log.json"),Ue=T.join(H,"companies.json"),cn=T.join(H,"job-decisions.json");function pe(){$.existsSync(H)||$.mkdirSync(H,{recursive:!0})}function de(e,t){let o=JSON.stringify(t,null,2),r=e+".tmp";$.writeFileSync(r,o);for(let n=0;n<3;n++)try{$.renameSync(r,e);return}catch(s){if(n<2&&(s.code==="EPERM"||s.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw s}}function re(e){try{if($.existsSync(e))return JSON.parse($.readFileSync(e,"utf-8"))}catch{}return null}function Je(){z=null,Dt=null,K=null,Q=null,B=null}var z=null;function se(){return z||(z=re(Me)||{},z)}function Be(e,t){if(!e)return;pe();let o=se(),r=new Date().toISOString().slice(0,10);if(o[e]){for(let[n,s]of Object.entries(t))s!=null&&(o[e][n]=s);o[e].lastSeen=r}else o[e]={...t,scoutedAt:r,lastSeen:r};try{de(Me,o)}catch(n){console.error(`[!] Failed to save scouted-jobs.json: ${n.message}`)}}var Dt=null;var K=null;function He(){return K||(K=re(qe)||{},K)}function Ve(e,t){if(!e)return;pe();let o=He(),r=new Date().toISOString().slice(0,10);if(o[e]){let n=o[e];t.name&&(n.name=t.name),t.title&&(n.title=t.title),t.company&&(n.company=t.company),t.location&&(n.location=t.location),t.role&&(n.role=t.role),t.isConnected!=null&&(n.isConnected=t.isConnected),t.jobId&&(n.jobIds||(n.jobIds=[]),n.jobIds.includes(t.jobId)||n.jobIds.push(t.jobId)),n.lastSeen=r,n.seenCount=(n.seenCount||1)+1}else o[e]={name:t.name||null,title:t.title||null,company:t.company||null,location:t.location||null,role:t.role||null,source:t.source||"scout",isConnected:t.isConnected||!1,discoveredAt:r,lastSeen:r,seenCount:1,jobIds:t.jobId?[t.jobId]:[]};try{de(qe,o)}catch(n){console.error(`[!] Failed to save discovered-people.json: ${n.message}`)}}var Q=null;function Ot(){return Q||(Q=re(Ue)||{},Q)}function We(e,t){if(!e)return;pe();let o=Ot(),r=new Date().toISOString().slice(0,10);if(o[e]){let n=o[e];t.name&&(n.name=t.name),t.about&&(n.about=t.about),t.size&&(n.size=t.size),t.industries&&(n.industries=t.industries),t.jobId&&(n.jobIds||(n.jobIds=[]),n.jobIds.includes(t.jobId)||n.jobIds.push(t.jobId)),t.recruiterUrl&&(n.recruiterUrls||(n.recruiterUrls=[]),n.recruiterUrls.includes(t.recruiterUrl)||n.recruiterUrls.push(t.recruiterUrl)),n.lastSeen=r,n.jobCount=n.jobIds?.length||0}else o[e]={name:t.name||null,about:t.about||null,size:t.size||null,industries:t.industries||null,discoveredAt:r,lastSeen:r,jobIds:t.jobId?[t.jobId]:[],recruiterUrls:t.recruiterUrl?[t.recruiterUrl]:[],jobCount:t.jobId?1:0};try{de(Ue,o)}catch(n){console.error(`[!] Failed to save companies.json: ${n.message}`)}}var B=null;function Nt(){return B||(B=re(Rt)||{visits:[]},Array.isArray(B.visits)||(B.visits=[]),B)}function Ge(){let e=se(),t=He(),o=Object.values(e),r=Object.values(t),n={};for(let u of o)u.company&&(n[u.company]=(n[u.company]||0)+1);let s=Object.entries(n).sort((u,p)=>p[1]-u[1]).slice(0,5).map(([u,p])=>`${u} (${p})`),i={};for(let u of o)for(let p of u.techStack||[])i[p]=(i[p]||0)+1;let c=Object.entries(i).sort((u,p)=>p[1]-u[1]).slice(0,8).map(([u,p])=>`${u} (${p})`),l=Nt(),f=new Date().toISOString().slice(0,10),d=l.visits.filter(u=>u.date.startsWith(f)).length,g=new Set(l.visits.map(u=>u.profileUrl)).size;return{totalJobs:o.length,totalRecruiters:r.length,topCompanies:s,topTech:c,totalVisited:g,todayVisited:d,lastScoutDate:o.length>0?o.sort((u,p)=>(p.scoutedAt||"").localeCompare(u.scoutedAt||""))[0]?.scoutedAt:null}}import"dotenv/config";import*as S from"fs";import*as v from"path";import{fileURLToPath as Ft}from"url";var Lt=Ft(import.meta.url),Pt=v.dirname(v.dirname(Lt)),O=process.env.DATA_DIR?v.resolve(process.env.DATA_DIR,"collected-profiles"):v.join(Pt,"collected-profiles"),Mt=v.join(O,"people.json"),qt=v.join(O,"jobs.json"),pn=v.join(O,"quota.json"),dn=v.join(O,"conversations.json"),mn=v.join(O,"sync-state.json"),hn=v.join(O,"application-questions.json"),gn=v.join(O,"profile-history");var X=null,Z=null,Ut=null,Jt=null,Bt=null,Ht=null;function Ye(){X=null,Z=null,Ut=null,Jt=null,Bt=null,Ht=null}function ze(){S.existsSync(O)||S.mkdirSync(O,{recursive:!0})}function Ke(e,t){if(!S.existsSync(e))return null;try{let o=JSON.parse(S.readFileSync(e,"utf-8"));try{S.copyFileSync(e,e+".backup")}catch{}return o}catch(o){console.error(`[!] ${t} is corrupted: ${o.message}`),console.error(` File: ${v.resolve(e)}`);let r=e+".backup";if(S.existsSync(r))try{let n=JSON.parse(S.readFileSync(r,"utf-8"));console.error(` Restored from ${r}`);try{S.copyFileSync(r,e)}catch{}return n}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{S.copyFileSync(e,e+".corrupted")}catch{}return null}}function Qe(){return X||(ze(),X=Ke(Mt,"people.json")||{},X)}function Xe(){return Z||(ze(),Z=Ke(qt,"jobs.json")||{},Z)}import"dotenv/config";import*as _ from"fs";import*as M from"path";import{fileURLToPath as Kt}from"url";import"dotenv/config";import{createGraphClient as Vt,resolveToken as Wt}from"@ilivemylife/graph-sdk";import{config as Gt}from"dotenv";Gt();var Ze=Wt()||process.env.TOKEN;Ze||(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
|
package/dist/syncAll.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var Eo=Object.defineProperty;var Tt=(e,t)=>{for(var o in t)Eo(e,o,{get:t[o],enumerable:!0})};var Ve={jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11},_o={sunday:0,monday:1,tuesday:2,wednesday:3,thursday:4,friday:5,saturday:6};function be(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 We(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=be(o),l=new Date(t);return a?l.setHours(a.hours,a.minutes,0,0):l.setHours(0,0,0,0),l.toISOString()}let n=o.match(/^(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s*(.*)/i);if(n){let a=_o[n[1].toLowerCase()],l=be(n[2]||""),c=new Date(t),d=c.getDay()-a;return d<=0&&(d+=7),c.setDate(c.getDate()-d),l?c.setHours(l.hours,l.minutes,0,0):c.setHours(0,0,0,0),c.toISOString()}let s=o.match(/^([A-Z][a-z]+)\s+(\d{1,2}),?\s+(\d{4})\s*(.*)/i);if(s){let a=Ve[s[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let l=parseInt(s[2],10),c=parseInt(s[3],10),f=be(s[4]||"");return new Date(c,a,l,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=Ve[r[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let l=parseInt(r[2],10),c=be(r[3]||""),f=t.getFullYear(),d=new Date(f,a,l,c?.hours||0,c?.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=Ve[i[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let l=parseInt(i[2],10),c=be(i[3]||""),f=t.getFullYear(),d=new Date(f,a,l,c?.hours||0,c?.minutes||0,0,0);return d>t&&d.setFullYear(f-1),d.toISOString()}return null}async function E(e){let t=Math.floor(Math.random()*2001),o=e+t;return new Promise(n=>setTimeout(n,o))}async function At(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 E(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 Et(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 _t(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"dotenv/config";import*as O from"fs";import*as I from"path";import{fileURLToPath as Ro}from"url";import{execSync as Ye}from"child_process";var Do=Ro(import.meta.url),Oo=I.dirname(I.dirname(Do)),U=process.env.DATA_DIR?I.resolve(process.env.DATA_DIR,"collected-profiles"):I.join(Oo,"collected-profiles"),Ge=I.join(U,"people.json"),Ys=I.join(U,"jobs.json"),Io=I.join(U,"quota.json"),xe=I.join(U,"conversations.json"),jt=I.join(U,"sync-state.json"),Rt=I.join(U,"application-questions.json"),ze=I.join(U,"profile-history"),Dt=20,Ot=100,ue=null,xo=null,z=null,oe=null,fe=null,te=null;function Mt(){ue=null,xo=null,z=null,oe=null,fe=null,te=null}function Q(){O.existsSync(U)||O.mkdirSync(U,{recursive:!0})}function ve(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 $e(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: ${I.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 Nt(){return new Date().toISOString().split("T")[0]}var jo=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections"],Mo=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"];function Qe(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function No(){O.existsSync(ze)||O.mkdirSync(ze,{recursive:!0})}function Pt(e){let t=Qe(e);return t?I.join(ze,`${t}.json`):null}function Po(e){let t=Pt(e);return t?$e(t,`profile-history/${Qe(e)}.json`)||[]:[]}function Fo(e,t){let o=Pt(e);if(!o)return;No();let n=Po(e);n.unshift(t);try{ve(o,n)}catch(s){console.error(`[!] Failed to append profile-history for ${Qe(e)}: ${s.message}`)}}function It(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function xt(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Lo(e,t){if(!e)return[];let o=[];for(let n of Mo){let s=e[n],r=t[n];It(s)||It(r)||xt(s)!==xt(r)&&o.push(n)}return o}function Uo(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 V(){return ue||(Q(),ue=$e(Ge,"people.json")||{},ue)}function je(e){Q(),ue=e;try{ve(Ge,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${I.resolve(Ge)}`)}}function Ce(){return oe||(Q(),oe=$e(xe,"conversations.json")||{},Bo(oe),oe)}function Bo(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{ve(xe,e)}catch{}}}function K(e){Q(),oe=e;try{ve(xe,e)}catch(t){console.error(`[!] Failed to save conversations.json: ${t.message}`),console.error(` Path: ${I.resolve(xe)}`)}}function Ft(e,t={}){if(!e)return null;let o=V(),n=Nt(),s=new Date().toISOString(),r=o[e];if(r){let i=Lo(r,t);i.length>0&&(Fo(e,{capturedAt:s,previousLastUpdated:r.lastUpdated||null,changedFields:i,snapshot:Uo(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 jo)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 je(o),o[e]}function qo(){return z||(Q(),z=$e(Io,"quota.json"),(!z||!z.connections)&&(z={connections:[]}),z)}function Jo(){let e=qo(),t=new Date;t.setDate(t.getDate()-7);let o=t.toISOString().split("T")[0];return e.connections.filter(n=>n.date>=o)}function Lt(){let e=Jo(),t=Nt(),o=e.filter(s=>s.date===t).length,n=e.length;return{daily:{sent:o,max:Dt,remaining:Dt-o},weekly:{sent:n,max:Ot,remaining:Ot-n}}}function Ke(){return fe||(Q(),fe=$e(jt,"sync-state.json")||{},fe)}function Ut(e){Q(),fe=e;try{ve(jt,e)}catch(t){console.error(`[!] Failed to save sync-state.json: ${t.message}`)}}function Ho(){if(te)return te;Q();try{O.existsSync(Rt)&&(te=JSON.parse(O.readFileSync(Rt,"utf-8")))}catch{}return te||(te={}),te}function Vo(e){return Array.isArray(e.applications)}function Wo(){let e=Ho();if(Vo(e))return e.applications;let t=[];for(let o of Object.values(e))o.applications&&t.push(...o.applications);return t}function Bt(){let e=Wo(),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 l=t.get(a);l.count++;let c=(i.answer||"").trim();l.answers.set(c,(l.answers.get(c)||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 Xe(e){if(O.existsSync(I.join(U,".git")))try{let t={cwd:U,stdio:"pipe",timeout:1e4};Ye("git add conversations.json people.json jobs.json quota.json sync-state.json run-log.json application-questions.json",t);try{Ye("git diff --cached --quiet",t);return}catch{}let o=(e||`sync ${new Date().toISOString().slice(0,16)}`).replace(/"/g,'\\"');Ye(`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 se from"fs";import*as P from"path";import{fileURLToPath as Yo}from"url";var Go=Yo(import.meta.url),zo=P.dirname(P.dirname(Go)),Ee=process.env.DATA_DIR?P.resolve(process.env.DATA_DIR,"market-research"):P.join(zo,"market-research"),Qo=P.join(Ee,"scouted-jobs.json"),Ko=P.join(Ee,"discovered-people.json"),Xo=P.join(Ee,"visit-log.json"),Ks=P.join(Ee,"companies.json"),Zo=P.join(Ee,"job-decisions.json");function Me(e){try{if(se.existsSync(e))return JSON.parse(se.readFileSync(e,"utf-8"))}catch{}return null}function qt(){ke=null,Te=null,Ae=null,tn=null,ne=null}var ke=null;function Ze(){return ke||(ke=Me(Qo)||{},ke)}var Te=null;function Jt(){return Te||(Te=Me(Zo)||{},Te)}var Ae=null;function en(){return Ae||(Ae=Me(Ko)||{},Ae)}var tn=null;var ne=null;function on(){return ne||(ne=Me(Xo)||{visits:[]},Array.isArray(ne.visits)||(ne.visits=[]),ne)}function Ht(){let e=Ze(),t=en(),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})`),l=on(),c=new Date().toISOString().slice(0,10),f=l.visits.filter(u=>u.date.startsWith(c)).length,d=new Set(l.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 nn=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"]),sn=new Set(["iot","machine learning","ai","data engineering","spark","go","rust","kotlin","next.js","devops","sre"]),Vt=["vancouver","british columbia"],rn=["canada","montreal","quebec","alberta","calgary","ottawa"],an=["toronto","ontario"],ln=["india","pakistan","nigeria","philippines"];function cn(e,t={}){let o=0,n=(e.techStack||[]).map(f=>f.toLowerCase()),s=0,r=0;for(let f of n)nn.has(f)&&s++,sn.has(f)&&r++;if(o+=Math.min(s*6,24),o+=Math.min(r*3,6),e.salary){let f=un(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";ln.some(f=>i.includes(f))?o-=30:a&&/united states|usa|\bus\b/i.test(i)?o+=25:a&&Vt.some(f=>i.includes(f))?o+=22:a?o+=20:Vt.some(f=>i.includes(f))?o+=18:rn.some(f=>i.includes(f))?o+=10:an.some(f=>i.includes(f))&&(o+=5),e.isEasyApply&&(o+=5);let l=(e.seniority||"").toLowerCase();l.includes("senior")||l.includes("lead")||l.includes("staff")?o+=10:l.includes("mid")?o+=5:(l.includes("entry")||l.includes("intern"))&&(o-=10),e.recruiterUrl&&(t.conversationRecruiters?.has(e.recruiterUrl)?o+=20:t.connectedRecruiters?.has(e.recruiterUrl)?o+=15:o+=3);let c=new Set(e.jobTags||[]);return c.has("managerial")?o+=8:c.has("senior-ic")&&(o+=5),c.has("junior")&&(o-=15),c.has("consultant")&&(o-=3),Math.max(0,Math.min(100,o))}function Wt(e=10,t={}){let{easyApplyOnly:o=!0}=t,n=Ze(),s=V(),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},l=Jt(),c=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=l[d];return!(m&&c.has(m.status))}).map(([d,u])=>({jobId:d,score:cn(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 un(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{getPluginConfig as fn}from"@ilivemylife/graph-sdk";var dn=await fn();for(let[e,t]of Object.entries(dn))process.env[e]===void 0&&(process.env[e]=t);var F=process.env.LINKEDIN_NAME,x=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),_e=Object.freeze(new Set([x.DRAFT,x.CONFIRMED,x.NEEDS_REVIEW])),de=Object.freeze(new Set([x.DRAFT,x.CONFIRMED,x.REJECTED,x.NEEDS_REVIEW]));import hn from"puppeteer";import{addExtra as yn}from"puppeteer-extra";import Sn from"puppeteer-extra-plugin-stealth";import Yt from"fs";import pn from"path";var gn="cookies.json";function mn(){let e=process.env.ILML_SCOPE_DIR;return e?pn.join(e,"plugins-state","linkedin","cookies.json"):gn}function Ne(){let e=mn();if(!Yt.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=Yt.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 Qt=yn(hn);Qt.use(Sn());async function Kt(){let e=await Qt.launch({headless:!1,defaultViewport:null,protocolTimeout:3e5}),t=async()=>{console.log(`
|
|
1
|
+
var Eo=Object.defineProperty;var Tt=(e,t)=>{for(var o in t)Eo(e,o,{get:t[o],enumerable:!0})};var Ve={jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11},_o={sunday:0,monday:1,tuesday:2,wednesday:3,thursday:4,friday:5,saturday:6};function be(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 We(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=be(o),l=new Date(t);return a?l.setHours(a.hours,a.minutes,0,0):l.setHours(0,0,0,0),l.toISOString()}let n=o.match(/^(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)\s*(.*)/i);if(n){let a=_o[n[1].toLowerCase()],l=be(n[2]||""),c=new Date(t),d=c.getDay()-a;return d<=0&&(d+=7),c.setDate(c.getDate()-d),l?c.setHours(l.hours,l.minutes,0,0):c.setHours(0,0,0,0),c.toISOString()}let s=o.match(/^([A-Z][a-z]+)\s+(\d{1,2}),?\s+(\d{4})\s*(.*)/i);if(s){let a=Ve[s[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let l=parseInt(s[2],10),c=parseInt(s[3],10),f=be(s[4]||"");return new Date(c,a,l,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=Ve[r[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let l=parseInt(r[2],10),c=be(r[3]||""),f=t.getFullYear(),d=new Date(f,a,l,c?.hours||0,c?.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=Ve[i[1].toLowerCase().slice(0,3)];if(a===void 0)return null;let l=parseInt(i[2],10),c=be(i[3]||""),f=t.getFullYear(),d=new Date(f,a,l,c?.hours||0,c?.minutes||0,0,0);return d>t&&d.setFullYear(f-1),d.toISOString()}return null}async function E(e){let t=Math.floor(Math.random()*2001),o=e+t;return new Promise(n=>setTimeout(n,o))}async function At(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 E(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 Et(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 _t(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 Ro}from"@ilivemylife/graph-sdk";var Do=await Ro();for(let[e,t]of Object.entries(Do))process.env[e]===void 0&&(process.env[e]=t);var P=process.env.LINKEDIN_NAME,x=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),ve=Object.freeze(new Set([x.DRAFT,x.CONFIRMED,x.NEEDS_REVIEW])),ue=Object.freeze(new Set([x.DRAFT,x.CONFIRMED,x.REJECTED,x.NEEDS_REVIEW]));import"dotenv/config";import*as O from"fs";import*as I from"path";import{fileURLToPath as Oo}from"url";import{execSync as Ye}from"child_process";var Io=Oo(import.meta.url),xo=I.dirname(I.dirname(Io)),U=process.env.DATA_DIR?I.resolve(process.env.DATA_DIR,"collected-profiles"):I.join(xo,"collected-profiles"),Ge=I.join(U,"people.json"),Qs=I.join(U,"jobs.json"),jo=I.join(U,"quota.json"),xe=I.join(U,"conversations.json"),jt=I.join(U,"sync-state.json"),Rt=I.join(U,"application-questions.json"),ze=I.join(U,"profile-history"),Dt=20,Ot=100,fe=null,Mo=null,z=null,oe=null,de=null,te=null;function Mt(){fe=null,Mo=null,z=null,oe=null,de=null,te=null}function Q(){O.existsSync(U)||O.mkdirSync(U,{recursive:!0})}function $e(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: ${I.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 Nt(){return new Date().toISOString().split("T")[0]}var No=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections"],Po=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"];function Qe(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Fo(){O.existsSync(ze)||O.mkdirSync(ze,{recursive:!0})}function Pt(e){let t=Qe(e);return t?I.join(ze,`${t}.json`):null}function Lo(e){let t=Pt(e);return t?Ce(t,`profile-history/${Qe(e)}.json`)||[]:[]}function Uo(e,t){let o=Pt(e);if(!o)return;Fo();let n=Lo(e);n.unshift(t);try{$e(o,n)}catch(s){console.error(`[!] Failed to append profile-history for ${Qe(e)}: ${s.message}`)}}function It(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function xt(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Bo(e,t){if(!e)return[];let o=[];for(let n of Po){let s=e[n],r=t[n];It(s)||It(r)||xt(s)!==xt(r)&&o.push(n)}return o}function qo(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 V(){return fe||(Q(),fe=Ce(Ge,"people.json")||{},fe)}function je(e){Q(),fe=e;try{$e(Ge,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${I.resolve(Ge)}`)}}function ke(){return oe||(Q(),oe=Ce(xe,"conversations.json")||{},Jo(oe),oe)}function Jo(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{$e(xe,e)}catch{}}}function K(e){Q(),oe=e;try{$e(xe,e)}catch(t){console.error(`[!] Failed to save conversations.json: ${t.message}`),console.error(` Path: ${I.resolve(xe)}`)}}function Ft(e,t={}){if(!e)return null;let o=V(),n=Nt(),s=new Date().toISOString(),r=o[e];if(r){let i=Bo(r,t);i.length>0&&(Uo(e,{capturedAt:s,previousLastUpdated:r.lastUpdated||null,changedFields:i,snapshot:qo(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 No)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 je(o),o[e]}function Ho(){return z||(Q(),z=Ce(jo,"quota.json"),(!z||!z.connections)&&(z={connections:[]}),z)}function Vo(){let e=Ho(),t=new Date;t.setDate(t.getDate()-7);let o=t.toISOString().split("T")[0];return e.connections.filter(n=>n.date>=o)}function Lt(){let e=Vo(),t=Nt(),o=e.filter(s=>s.date===t).length,n=e.length;return{daily:{sent:o,max:Dt,remaining:Dt-o},weekly:{sent:n,max:Ot,remaining:Ot-n}}}function Ke(){return de||(Q(),de=Ce(jt,"sync-state.json")||{},de)}function Ut(e){Q(),de=e;try{$e(jt,e)}catch(t){console.error(`[!] Failed to save sync-state.json: ${t.message}`)}}function Wo(){if(te)return te;Q();try{O.existsSync(Rt)&&(te=JSON.parse(O.readFileSync(Rt,"utf-8")))}catch{}return te||(te={}),te}function Yo(e){return Array.isArray(e.applications)}function Go(){let e=Wo();if(Yo(e))return e.applications;let t=[];for(let o of Object.values(e))o.applications&&t.push(...o.applications);return t}function Bt(){let e=Go(),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 l=t.get(a);l.count++;let c=(i.answer||"").trim();l.answers.set(c,(l.answers.get(c)||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 Xe(e){if(O.existsSync(I.join(U,".git")))try{let t={cwd:U,stdio:"pipe",timeout:1e4};Ye("git add conversations.json people.json jobs.json quota.json sync-state.json run-log.json application-questions.json",t);try{Ye("git diff --cached --quiet",t);return}catch{}let o=(e||`sync ${new Date().toISOString().slice(0,16)}`).replace(/"/g,'\\"');Ye(`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 se from"fs";import*as F from"path";import{fileURLToPath as zo}from"url";var Qo=zo(import.meta.url),Ko=F.dirname(F.dirname(Qo)),_e=process.env.DATA_DIR?F.resolve(process.env.DATA_DIR,"market-research"):F.join(Ko,"market-research"),Xo=F.join(_e,"scouted-jobs.json"),Zo=F.join(_e,"discovered-people.json"),en=F.join(_e,"visit-log.json"),er=F.join(_e,"companies.json"),tn=F.join(_e,"job-decisions.json");function Me(e){try{if(se.existsSync(e))return JSON.parse(se.readFileSync(e,"utf-8"))}catch{}return null}function qt(){Te=null,Ae=null,Ee=null,nn=null,ne=null}var Te=null;function Ze(){return Te||(Te=Me(Xo)||{},Te)}var Ae=null;function Jt(){return Ae||(Ae=Me(tn)||{},Ae)}var Ee=null;function on(){return Ee||(Ee=Me(Zo)||{},Ee)}var nn=null;var ne=null;function sn(){return ne||(ne=Me(en)||{visits:[]},Array.isArray(ne.visits)||(ne.visits=[]),ne)}function Ht(){let e=Ze(),t=on(),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})`),l=sn(),c=new Date().toISOString().slice(0,10),f=l.visits.filter(u=>u.date.startsWith(c)).length,d=new Set(l.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 rn=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"]),an=new Set(["iot","machine learning","ai","data engineering","spark","go","rust","kotlin","next.js","devops","sre"]),Vt=["vancouver","british columbia"],ln=["canada","montreal","quebec","alberta","calgary","ottawa"],cn=["toronto","ontario"],un=["india","pakistan","nigeria","philippines"];function fn(e,t={}){let o=0,n=(e.techStack||[]).map(f=>f.toLowerCase()),s=0,r=0;for(let f of n)rn.has(f)&&s++,an.has(f)&&r++;if(o+=Math.min(s*6,24),o+=Math.min(r*3,6),e.salary){let f=dn(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";un.some(f=>i.includes(f))?o-=30:a&&/united states|usa|\bus\b/i.test(i)?o+=25:a&&Vt.some(f=>i.includes(f))?o+=22:a?o+=20:Vt.some(f=>i.includes(f))?o+=18:ln.some(f=>i.includes(f))?o+=10:cn.some(f=>i.includes(f))&&(o+=5),e.isEasyApply&&(o+=5);let l=(e.seniority||"").toLowerCase();l.includes("senior")||l.includes("lead")||l.includes("staff")?o+=10:l.includes("mid")?o+=5:(l.includes("entry")||l.includes("intern"))&&(o-=10),e.recruiterUrl&&(t.conversationRecruiters?.has(e.recruiterUrl)?o+=20:t.connectedRecruiters?.has(e.recruiterUrl)?o+=15:o+=3);let c=new Set(e.jobTags||[]);return c.has("managerial")?o+=8:c.has("senior-ic")&&(o+=5),c.has("junior")&&(o-=15),c.has("consultant")&&(o-=3),Math.max(0,Math.min(100,o))}function Wt(e=10,t={}){let{easyApplyOnly:o=!0}=t,n=Ze(),s=V(),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},l=Jt(),c=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=l[d];return!(m&&c.has(m.status))}).map(([d,u])=>({jobId:d,score:fn(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 dn(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 hn from"puppeteer";import{addExtra as yn}from"puppeteer-extra";import Sn from"puppeteer-extra-plugin-stealth";import Yt from"fs";import pn from"path";var gn="cookies.json";function mn(){let e=process.env.ILML_SCOPE_DIR;return e?pn.join(e,"plugins-state","linkedin","cookies.json"):gn}function Ne(){let e=mn();if(!Yt.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=Yt.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 Qt=yn(hn);Qt.use(Sn());async function Kt(){let e=await Qt.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=Ne();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 et(e){await e.goto("https://www.linkedin.com/messaging/",{waitUntil:"domcontentloaded",timeout:6e4}),await E(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 E(3e3)}console.log(" Inbox loaded.")}async function Xt(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 l=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(l)||/^\s*Promoted\b/i.test(l))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(l.startsWith("You:"))u="me",m=l.slice(4).trim();else{let y=i.split(" ")[0];if(l.startsWith(i+":")||l.startsWith(y+":")){u="them";let v=l.indexOf(":");m=l.slice(v+1).trim()}else u="them",m=l}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=We(o.lastMessageTime)||o.lastMessageTime;return t}async function tt(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 wn(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 ot(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 Gt(e,t){let o=await wn(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 Pe(e,t){let o=t.split(" ")[0],n=8e3,s=500,r=0;for(;r<n;){let{match:l,headerName:c}=await Gt(e,t);if(l)return await E(500),{verified:!0,headerName:c};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 E(300),{verified:!0,headerName:o};await E(s),r+=s}let{match:i,headerName:a}=await Gt(e,t);return i?{verified:!0,headerName:a}:{verified:!1,headerName:a}}async function bn(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 c=document.querySelector(".msg-overlay-conversation-bubble");c&&(i=c.querySelector(".msg-s-message-list-container")||c.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 E(800),r.msgCount===o){if(n++,n>=3)break}else n=0;o=r.msgCount}}async function nt(e,{scrollUp:t=!0}={}){t&&await bn(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 l="";function c(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 C=m?new Date(m).toISOString():u?`${u} ${y}`.trim():y;return{sender:d,text:$,time:C}}for(let f of i){let d=f.querySelector("time.msg-s-message-list__time-heading");d&&(l=d.textContent?.trim()||l);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 C=c($,y,l);C&&n.push(C)}}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 $=c(S,s||"Unknown",l);$&&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=We(n.time)||n.time);return o}function st(e,t,o){if(e.length===0)return!0;let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(c=>c.length>1),r=[...new Set(e.map(c=>c.sender).filter(c=>c&&c!=="Unknown"))],i=r.some(c=>{let f=c.toLowerCase();return f.includes(n)||s.some(d=>f.includes(d))}),a=F.toLowerCase().split(/\s+/),l=r.every(c=>{let f=c.toLowerCase();return a.some(d=>f.includes(d))});if(i)return!0;if(l){for(let c of e){let d=(c.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 c=o.map(d=>d.toLowerCase());if(r.some(d=>{let u=d.toLowerCase();return c.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 pe(e){return(e||"").replace(/\s+/g," ").trim().toLowerCase()}function rt(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let o=u=>pe(u.sender)+"||"+pe(u.text),n=new Set(t.map(o)),s=new Set(e.map(o)),r=e.filter(u=>de.has(u.status)?!1:!n.has(o(u))),i=t.filter(u=>!s.has(o(u))),a=t.filter(u=>s.has(o(u))),l=e.filter(u=>de.has(u.status)),c=[...r,...a,...i],f=[];for(let u of c){let m=pe(u.text),S=pe(u.sender),y=!1;for(let v=0;v<f.length;v++){let $=f[v];if(pe($.sender)!==S)continue;let C=pe($.text);if(m.length>C.length&&m.endsWith(C)){y=!0;break}if(C.length>m.length&&C.endsWith(m)){f[v]=u,y=!0;break}}y||f.push(u)}return[...f,...l]}async function Zt(e,t){await et(e),await E(2500),await e.evaluate(()=>{let a=[".msg-conversations-container__conversations-list",".msg-conversations-container"];for(let l of a){let c=document.querySelector(l);if(c){c.scrollTop=0;return}}}),await E(500);async function o(){return e.evaluate(a=>{let l=document.querySelectorAll(".msg-conversation-listitem");for(let c of l)if(c.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===a){let u=c.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 l=await tt(e);if(!l)break;if(l.scrollTop===r){if(i++,i>=2)break}else i=0,r=l.scrollTop;await E(600),n=await o()}return n?(await e.mouse.click(n.x,n.y),await E(3e3),Pe(e,t)):{verified:!1,headerName:null}}async function it(e,t){let o=await e.evaluate(i=>{let a=document.querySelectorAll(".msg-conversation-listitem");for(let l of a)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===i){let d=l.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 E(3e3);let i=await Pe(e,t);if(i.verified)return i}let n=Et(t),s=n!==t?[t,n]:[t];for(let i of s)if(await zt(e,i,t)){let l=await Pe(e,t);if(l.verified)return l}let r=_t(n);if(r!==n&&r.length>0&&await zt(e,r,t,{requireUnique:!0})){let a=await Pe(e,t);if(a.verified)return a}return{verified:!1,headerName:null}}async function zt(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 E(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await E(300),await r.type(t,{delay:30}),await E(500),await e.keyboard.press("Enter"),await E(3500);let i=await e.evaluate((a,l)=>{let c=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," ")||"",C=$.toLowerCase();if(C.includes(c)){let g=y.getBoundingClientRect();if(g.height>0){let p=$.includes(",")||/\d+ other/.test($),w=C===f?3:C.includes(f)?2:1,k={text:$,isGroup:p,score:w,x:g.x+g.width/2,y:g.y+g.height/2};p?m.push(k):u.push(k)}}}u.sort((y,v)=>v.score-y.score);let S=[...u,...m];return l&&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 X(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await E(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 E(1e3))}function lt(e,t,o){if(!e)return e;let s=(e.messages||[]).filter(l=>!de.has(l.status)),r=Rn(t,e.profileUrl,o),i=Cn(s,t);if(e._cardSynced||(e.lastMessageBy=i),e.conversationStatus=e.lastMessageBy==="me"?"awaiting_reply":"unanswered_by_us",e.categorySource!=="manual"){let l=vn(s,t,r);l&&(e.category=l,e.categorySource=e.categorySource||"message_content")}if(e.situation=$n(s,i,t),s.length>0){let l=s[s.length-1];e.lastMessageTime=l.time}if(s.length>0&&!e.initiatedBy){let l=s[0];l.sender===F?e.initiatedBy="us":l.sender!=="Unknown"&&l.sender!==""&&(e.initiatedBy="them")}e.engagement=no(s,t),e.personContext=En(r),e.summary=kn(e,t,r),e.autoTags=Tn(e,t,r);let a=An(e);return e.actionNeeded=a.action,e.actionDetail=a.detail,e.suggestedPriority=_n(e),e}var to={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 vn(e,t,o){if(!e||e.length===0)return o?.title?at(o.title):null;let n=e.filter(s=>s.sender!==F&&s.sender!=="Unknown"&&s.sender!=="").map(s=>s.text).join(" ");for(let[s,r]of Object.entries(to))if(r.theirMessages){for(let i of r.theirMessages)if(i.test(n))return s}if(o?.title){let s=at(o.title);if(s)return s}return null}function at(e){if(!e)return null;for(let[t,o]of Object.entries(to))if(o.title){for(let n of o.title)if(n.test(e))return t}return null}var eo=/\b(call|meet|teams|zoom|schedule|available|availability|invite|slot|calendar)\b/i;function $n(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 eo.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!==F&&r.sender!=="Unknown");return eo.test(s?.text||"")?"they_want_to_schedule_call":e.length>=6?"active_conversation_needs_our_reply":"needs_our_reply"}function Cn(e,t){if(!e||e.length===0)return"them";for(let o=e.length-1;o>=0;o--){let n=e[o].sender;if(n===F)return"me";if(n!=="Unknown"&&n!=="")return"them"}return"them"}function kn(e,t,o){let n=e.messages||[];if(n.length===0)return null;let s=[],r=e.category,i=o?.title,a=o?.company,l=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(`${ct(r)}: ${ge(i,40)}`):i?s.push(ge(i,50)):s.push(t.split(" ")[0]);let c=n.filter(S=>S.sender!==F&&S.sender!=="Unknown").map(S=>S.text).join(" "),f=Dn(c),d=On(c),u=In(c),m=[];return f&&m.push(f),u&&u!==l&&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 Tn(e,t,o){let n=[],s=(e.messages||[]).filter(c=>!de.has(c.status)),r=s.map(c=>c.text).join(" "),i=s.filter(c=>c.sender!==F&&c.sender!=="Unknown").map(c=>c.text).join(" "),a=oo(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 l=e.engagement||no(s,t);return l.messageCount>=6&&n.push("active-thread"),l.theirCount===0&&l.ourCount>0&&n.push("no-response"),l.ourCount===0&&l.theirCount>0&&n.push("unanswered"),e.situation==="they_want_to_schedule_call"&&n.push("hot-lead"),(e.messages||[]).some(c=>_e.has(c.status))&&n.push("has-draft"),[...new Set(n)]}function oo(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 An(e){let{category:t,situation:o,conversationStatus:n}=e;if(e.dismissedAtPreview&&Re(e.lastMessagePreview)===Re(e.dismissedAtPreview))return{action:"none",detail:e.dismissReason||"Dismissed."};let s=(e.messages||[]).find(r=>_e.has(r.status));return s?s.status===x.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:`${ct(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 no(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(l=>l.text).join(" ");for(let l of e)l.sender===F?o++:l.sender==="Unknown"||l.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 En(e){return e?{title:e.title||null,company:e.company||null,location:e.location||null,connectionStatus:e.connectionStatus||null}:null}function _n(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 Rn(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 Re(e){return(e||"").replace(/\s+/g," ").trim().slice(0,80).toLowerCase()}function ct(e){return e?e.charAt(0).toUpperCase()+e.slice(1):""}function ge(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function Dn(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 On(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 In(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 so(e,t){if(!e)return e;if(e.categorySource!=="manual"){let n=at(e.title);n&&(e.category=n,e.categorySource=e.categorySource||"title")}xn(e),e.personSummary=jn(e),e.personAutoTags=Mn(e);let o=Nn(e);return e.personActionNeeded=o.action,e.personActionDetail=o.detail,e.personPriorityManual||(e.personPriority=Pn(e)),e}function xn(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 jn(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(`${ge(n,40)} at ${ge(s,30)}`):n?t.push(ge(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: ${ge(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 Mn(e){let t=[],o=[e.title,e.company,e.location].filter(Boolean).join(" "),n=oo("",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 Nn(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:`${ct(t)} \u2014 no outreach needed.`}:t==="investor"?{action:"initiate_contact",detail:"Investor connection. Consider intro message."}:{action:"none",detail:"No specific action identified."}}function Pn(e){let t=e.category;if(!t)return null;let o=Fn(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 Fn(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 Z from"path";import{fileURLToPath as Hn}from"url";import"dotenv/config";import{createGraphClient as Ln,resolveToken as Un}from"@ilivemylife/graph-sdk";import{config as Bn}from"dotenv";Bn();var ro=Un()||process.env.TOKEN;ro||(console.error(`
|
|
4
|
+
`),await e.close(),process.exit(1)}return{browser:e,page:o}}async function et(e){await e.goto("https://www.linkedin.com/messaging/",{waitUntil:"domcontentloaded",timeout:6e4}),await E(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 E(3e3)}console.log(" Inbox loaded.")}async function Xt(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 l=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(l)||/^\s*Promoted\b/i.test(l))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(l.startsWith("You:"))u="me",m=l.slice(4).trim();else{let y=i.split(" ")[0];if(l.startsWith(i+":")||l.startsWith(y+":")){u="them";let v=l.indexOf(":");m=l.slice(v+1).trim()}else u="them",m=l}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=We(o.lastMessageTime)||o.lastMessageTime;return t}async function tt(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 wn(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 ot(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 Gt(e,t){let o=await wn(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 Pe(e,t){let o=t.split(" ")[0],n=8e3,s=500,r=0;for(;r<n;){let{match:l,headerName:c}=await Gt(e,t);if(l)return await E(500),{verified:!0,headerName:c};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 E(300),{verified:!0,headerName:o};await E(s),r+=s}let{match:i,headerName:a}=await Gt(e,t);return i?{verified:!0,headerName:a}:{verified:!1,headerName:a}}async function bn(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 c=document.querySelector(".msg-overlay-conversation-bubble");c&&(i=c.querySelector(".msg-s-message-list-container")||c.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 E(800),r.msgCount===o){if(n++,n>=3)break}else n=0;o=r.msgCount}}async function nt(e,{scrollUp:t=!0}={}){t&&await bn(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 l="";function c(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 C=m?new Date(m).toISOString():u?`${u} ${y}`.trim():y;return{sender:d,text:$,time:C}}for(let f of i){let d=f.querySelector("time.msg-s-message-list__time-heading");d&&(l=d.textContent?.trim()||l);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 C=c($,y,l);C&&n.push(C)}}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 $=c(S,s||"Unknown",l);$&&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=We(n.time)||n.time);return o}function st(e,t,o){if(e.length===0)return!0;let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(c=>c.length>1),r=[...new Set(e.map(c=>c.sender).filter(c=>c&&c!=="Unknown"))],i=r.some(c=>{let f=c.toLowerCase();return f.includes(n)||s.some(d=>f.includes(d))}),a=P.toLowerCase().split(/\s+/),l=r.every(c=>{let f=c.toLowerCase();return a.some(d=>f.includes(d))});if(i)return!0;if(l){for(let c of e){let d=(c.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 c=o.map(d=>d.toLowerCase());if(r.some(d=>{let u=d.toLowerCase();return c.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 pe(e){return(e||"").replace(/\s+/g," ").trim().toLowerCase()}function rt(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let o=u=>pe(u.sender)+"||"+pe(u.text),n=new Set(t.map(o)),s=new Set(e.map(o)),r=e.filter(u=>ue.has(u.status)?!1:!n.has(o(u))),i=t.filter(u=>!s.has(o(u))),a=t.filter(u=>s.has(o(u))),l=e.filter(u=>ue.has(u.status)),c=[...r,...a,...i],f=[];for(let u of c){let m=pe(u.text),S=pe(u.sender),y=!1;for(let v=0;v<f.length;v++){let $=f[v];if(pe($.sender)!==S)continue;let C=pe($.text);if(m.length>C.length&&m.endsWith(C)){y=!0;break}if(C.length>m.length&&C.endsWith(m)){f[v]=u,y=!0;break}}y||f.push(u)}return[...f,...l]}async function Zt(e,t){await et(e),await E(2500),await e.evaluate(()=>{let a=[".msg-conversations-container__conversations-list",".msg-conversations-container"];for(let l of a){let c=document.querySelector(l);if(c){c.scrollTop=0;return}}}),await E(500);async function o(){return e.evaluate(a=>{let l=document.querySelectorAll(".msg-conversation-listitem");for(let c of l)if(c.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===a){let u=c.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 l=await tt(e);if(!l)break;if(l.scrollTop===r){if(i++,i>=2)break}else i=0,r=l.scrollTop;await E(600),n=await o()}return n?(await e.mouse.click(n.x,n.y),await E(3e3),Pe(e,t)):{verified:!1,headerName:null}}async function it(e,t){let o=await e.evaluate(i=>{let a=document.querySelectorAll(".msg-conversation-listitem");for(let l of a)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===i){let d=l.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 E(3e3);let i=await Pe(e,t);if(i.verified)return i}let n=Et(t),s=n!==t?[t,n]:[t];for(let i of s)if(await zt(e,i,t)){let l=await Pe(e,t);if(l.verified)return l}let r=_t(n);if(r!==n&&r.length>0&&await zt(e,r,t,{requireUnique:!0})){let a=await Pe(e,t);if(a.verified)return a}return{verified:!1,headerName:null}}async function zt(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 E(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await E(300),await r.type(t,{delay:30}),await E(500),await e.keyboard.press("Enter"),await E(3500);let i=await e.evaluate((a,l)=>{let c=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," ")||"",C=$.toLowerCase();if(C.includes(c)){let g=y.getBoundingClientRect();if(g.height>0){let p=$.includes(",")||/\d+ other/.test($),w=C===f?3:C.includes(f)?2:1,k={text:$,isGroup:p,score:w,x:g.x+g.width/2,y:g.y+g.height/2};p?m.push(k):u.push(k)}}}u.sort((y,v)=>v.score-y.score);let S=[...u,...m];return l&&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 X(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await E(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 E(1e3))}function lt(e,t,o){if(!e)return e;let s=(e.messages||[]).filter(l=>!ue.has(l.status)),r=Rn(t,e.profileUrl,o),i=Cn(s,t);if(e._cardSynced||(e.lastMessageBy=i),e.conversationStatus=e.lastMessageBy==="me"?"awaiting_reply":"unanswered_by_us",e.categorySource!=="manual"){let l=vn(s,t,r);l&&(e.category=l,e.categorySource=e.categorySource||"message_content")}if(e.situation=$n(s,i,t),s.length>0){let l=s[s.length-1];e.lastMessageTime=l.time}if(s.length>0&&!e.initiatedBy){let l=s[0];l.sender===P?e.initiatedBy="us":l.sender!=="Unknown"&&l.sender!==""&&(e.initiatedBy="them")}e.engagement=no(s,t),e.personContext=En(r),e.summary=kn(e,t,r),e.autoTags=Tn(e,t,r);let a=An(e);return e.actionNeeded=a.action,e.actionDetail=a.detail,e.suggestedPriority=_n(e),e}var to={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 vn(e,t,o){if(!e||e.length===0)return o?.title?at(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(to))if(r.theirMessages){for(let i of r.theirMessages)if(i.test(n))return s}if(o?.title){let s=at(o.title);if(s)return s}return null}function at(e){if(!e)return null;for(let[t,o]of Object.entries(to))if(o.title){for(let n of o.title)if(n.test(e))return t}return null}var eo=/\b(call|meet|teams|zoom|schedule|available|availability|invite|slot|calendar)\b/i;function $n(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 eo.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 eo.test(s?.text||"")?"they_want_to_schedule_call":e.length>=6?"active_conversation_needs_our_reply":"needs_our_reply"}function Cn(e,t){if(!e||e.length===0)return"them";for(let o=e.length-1;o>=0;o--){let n=e[o].sender;if(n===P)return"me";if(n!=="Unknown"&&n!=="")return"them"}return"them"}function kn(e,t,o){let n=e.messages||[];if(n.length===0)return null;let s=[],r=e.category,i=o?.title,a=o?.company,l=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(`${ct(r)}: ${ge(i,40)}`):i?s.push(ge(i,50)):s.push(t.split(" ")[0]);let c=n.filter(S=>S.sender!==P&&S.sender!=="Unknown").map(S=>S.text).join(" "),f=Dn(c),d=On(c),u=In(c),m=[];return f&&m.push(f),u&&u!==l&&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 Tn(e,t,o){let n=[],s=(e.messages||[]).filter(c=>!ue.has(c.status)),r=s.map(c=>c.text).join(" "),i=s.filter(c=>c.sender!==P&&c.sender!=="Unknown").map(c=>c.text).join(" "),a=oo(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 l=e.engagement||no(s,t);return l.messageCount>=6&&n.push("active-thread"),l.theirCount===0&&l.ourCount>0&&n.push("no-response"),l.ourCount===0&&l.theirCount>0&&n.push("unanswered"),e.situation==="they_want_to_schedule_call"&&n.push("hot-lead"),(e.messages||[]).some(c=>ve.has(c.status))&&n.push("has-draft"),[...new Set(n)]}function oo(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 An(e){let{category:t,situation:o,conversationStatus:n}=e;if(e.dismissedAtPreview&&Re(e.lastMessagePreview)===Re(e.dismissedAtPreview))return{action:"none",detail:e.dismissReason||"Dismissed."};let s=(e.messages||[]).find(r=>ve.has(r.status));return s?s.status===x.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:`${ct(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 no(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(l=>l.text).join(" ");for(let l of e)l.sender===P?o++:l.sender==="Unknown"||l.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 En(e){return e?{title:e.title||null,company:e.company||null,location:e.location||null,connectionStatus:e.connectionStatus||null}:null}function _n(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 Rn(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 Re(e){return(e||"").replace(/\s+/g," ").trim().slice(0,80).toLowerCase()}function ct(e){return e?e.charAt(0).toUpperCase()+e.slice(1):""}function ge(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function Dn(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 On(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 In(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 so(e,t){if(!e)return e;if(e.categorySource!=="manual"){let n=at(e.title);n&&(e.category=n,e.categorySource=e.categorySource||"title")}xn(e),e.personSummary=jn(e),e.personAutoTags=Mn(e);let o=Nn(e);return e.personActionNeeded=o.action,e.personActionDetail=o.detail,e.personPriorityManual||(e.personPriority=Pn(e)),e}function xn(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 jn(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(`${ge(n,40)} at ${ge(s,30)}`):n?t.push(ge(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: ${ge(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 Mn(e){let t=[],o=[e.title,e.company,e.location].filter(Boolean).join(" "),n=oo("",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 Nn(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:`${ct(t)} \u2014 no outreach needed.`}:t==="investor"?{action:"initiate_contact",detail:"Investor connection. Consider intro message."}:{action:"none",detail:"No specific action identified."}}function Pn(e){let t=e.category;if(!t)return null;let o=Fn(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 Fn(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 Z from"path";import{fileURLToPath as Hn}from"url";import"dotenv/config";import{createGraphClient as Ln,resolveToken as Un}from"@ilivemylife/graph-sdk";import{config as Bn}from"dotenv";Bn();var ro=Un()||process.env.TOKEN;ro||(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
|
|
@@ -51,7 +51,7 @@ ${n.join(`
|
|
|
51
51
|
\u2713 Schema is now at v${ee}
|
|
52
52
|
`)}var hs=[/\.json\.tmp$/,/\.schema-version\.tmp$/,/\.backup\.tmp$/];function ys(e){let t=e.toLowerCase();return hs.some(o=>o.test(t))}var Ss=6e4;function ws(){let e=Date.now(),t=[];for(let o of[H,ie,ae]){if(!b.existsSync(o))continue;let n;try{n=b.readdirSync(o)}catch{continue}for(let s of n){if(!ys(s))continue;let r=_.join(o,s);try{let i=b.statSync(r);if(!i.isFile()||e-i.mtimeMs<Ss)continue;t.push({dir:o,file:s,fullPath:r})}catch{}}}return t}function bs({verbose:e=!1}={}){let t=ws();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 vs(){let e=[];for(let t of[ie,ae]){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{Be(s)}catch(r){e.push({dir:_.basename(t),file:n,err:r.message})}}}return e.length===0?{ok:!0}:{ok:!1,broken:e}}function $s(e){let t=[],o=[];for(let r of[ie,ae]){if(!b.existsSync(r))continue;let i=b.readdirSync(r).filter(a=>a.endsWith(e));for(let a of i){let l=_.join(r,a),c=a.slice(0,-e.length),f=_.join(r,c);try{c.toLowerCase().endsWith(".json")?Be(l):b.accessSync(l,b.constants.R_OK),t.push({backupPath:l,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:l}of t)try{wo(r,i),n++}catch(c){s.push(`${_.basename(l)}/${a}: ${c.message}`)}return s.length>0?{ok:!1,error:s.join("; "),restored:n}:{ok:!0,restored:n}}function wo(e,t){let o=t+".tmp";try{b.copyFileSync(e,o),yo(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 Cs(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 bo(e,t,{returnUrl:o,gotoTimeoutMs:n=6e4,cookiesProvider:s=null,setupPage:r=null}={}){try{await Cs(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 So();var To="https://www.linkedin.com/messaging/",ks=10,wt=3,Ts=async e=>{await e.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})})},As=()=>Ne(),ce={pageRecoveries:0};async function qe(e,t){if(ce.pageRecoveries>=ks)throw new Error(`CDP unrecoverable: ${ce.pageRecoveries} page recoveries already attempted. Last: ${t}`);console.log(`
|
|
53
53
|
\u{1F504} CDP dead \u2014 recovering page (#${ce.pageRecoveries+1}). Reason: ${t}`),e.page=await bo(e.browser,e.page,{returnUrl:To,cookiesProvider:As,setupPage:Ts}),ce.pageRecoveries++,await E(3e3);try{await e.page.waitForSelector(".msg-conversation-listitem",{timeout:15e3})}catch{}console.log(`\u2713 Page recovered (total: ${ce.pageRecoveries}).
|
|
54
|
-
`)}function he(e){return(e.messages||[]).find(t=>
|
|
54
|
+
`)}function he(e){return(e.messages||[]).find(t=>ve.has(t.status))?.status}var G=process.argv.slice(2),bt=G.includes("--full"),L=G.includes("--dry-run"),vo=G.includes("--report"),vt=G.includes("--verbose"),$o=G.includes("--backfill"),Co=G.includes("--enrich"),ko=G.includes("--today"),$t=G.includes("--read-unread"),De=parseInt(G.find(e=>e.startsWith("--max="))?.split("=")[1]||"50");function Es(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);return n&&o&&n!==o?"preview_changed":e.lastMessageBy&&e.lastMessageBy!==t.lastMessageBy?"sender_changed":null}async function _s(e,t){console.log(`
|
|
55
55
|
\u2550\u2550 PHASE 1: Inbox Scan \u2550\u2550
|
|
56
56
|
`);let o=Ke(),n=o.lastIncrementalSync?new Date(o.lastIncrementalSync):null,s=new Map,r=new Map,i=new Map,a=0,l=0,c=0,f=0,d=0,u=-1,m=0;for(;;){l++;let $=await Xt(e),C=0;for(let p of $){if(!p.name||s.has(p.name))continue;s.set(p.name,p),C++,p.unread&&i.set(p.name,p);let w=t[p.name],k=Es(p,w);k&&(!$t&&p.unread?a++:r.set(p.name,{card:p,reason:k})),w&&(k||(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(vt?console.log(` Round #${l}: +${C} new | Total: ${s.size} | Need reading: ${r.size}`):process.stdout.write(`\r Scanned: ${s.size} conversations (page #${l}, ${r.size} need reading)`),C===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(!bt){if(r.size===f){if(c++,c>=3){console.log(`
|
|
@@ -64,7 +64,7 @@ ${n.join(`
|
|
|
64
64
|
`);let a=[],l=[],c=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 it(y,u)}catch(C){if(le(C))throw C;console.log(` searchAndOpenThread threw: ${(C.message||"").substring(0,80)}`)}if(!v.verified){console.log(" Sidebar fallback (scroll-to-find)...");try{v=await Zt(e.page,u)}catch(C){if(le(C))throw C;console.log(` Fallback threw: ${(C.message||"").substring(0,80)}`)}}if(!v.verified){console.log(" Could not open thread."),c++;try{await X(e.page)}catch{}continue}let $=await nt(y);if($&&$.length>0){if(!st($,u,l)){console.log(" Skipped \u2014 stale data."),c++,await X(y);continue}let g=await ot(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=rt(p.messages,$),p.lastSynced=new Date().toISOString(),g&&!p.profileUrl&&(p.profileUrl=g),p.lastMessageBy=m.lastMessageBy,p.lastMessagePreview=m.lastMessagePreview||p.lastMessagePreview,p.lastMessageTime=m.lastMessageTime||p.lastMessageTime,p.unread=!1,p._cardSynced=!0,o[u]=p,L||K(o);let k=p.messages.length-w;console.log(` ${p.messages.length} msgs (${k>=0?"+"+k:k} new)${g&&!p.profileUrl?" +url":""}`),a.push({name:u}),l=[...new Set($.map(R=>R.sender).filter(R=>R&&R!=="Unknown"))]}else console.log(" No messages extracted."),c++;await X(y),await E(500)}catch(v){if(!le(v))throw v;f++,n&&n.add(u),await qe(e,`Phase 2 thread ${d+1}/${r} (${u})`)}}return console.log(`
|
|
65
65
|
Phase 2 complete: ${a.length} read, ${c} 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 Ds(e,t){console.log(`
|
|
66
66
|
\u2550\u2550 PHASE 3: Post-processing & Enrichment \u2550\u2550
|
|
67
|
-
`);let o=V();for(let n of t){let{name:s}=n,r=e[s];if(!r?.messages?.length)continue;try{lt(r,s,o)}catch(l){console.warn(` [!] Enrichment failed for ${s}: ${l.message}`)}delete r._cardSynced;let i=r.profileUrl,a=null;if(i&&(a=o[i]||null),!a){let l=Object.entries(o).filter(([,c])=>c.name===s);l.length===1&&(i||(i=l[0][0],r.profileUrl=i),a=l[0][1])}!a&&i&&(Ft(i,{name:s,source:"sync-all"}),a=V()[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||(je(o),K(e)),console.log(` Enriched ${t.length} conversations.`),Ao(e)}function Ao(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,l=a===r?i:r,c=new Set((a.conv.messages||[]).map(f=>`${f.text?.slice(0,80)}|${f.time}`));for(let f of l.conv.messages||[]){let d=`${f.text?.slice(0,80)}|${f.time}`;c.has(d)||(a.conv.messages.push(f),c.add(d))}a.conv.messages.sort((f,d)=>(f.time||"").localeCompare(d.time||"")),l.conv.notes&&!a.conv.notes&&(a.conv.notes=l.conv.notes),l.conv.priority&&!a.conv.priority&&(a.conv.priority=l.conv.priority),l.conv.categorySource==="manual"&&a.conv.categorySource!=="manual"&&(a.conv.category=l.conv.category,a.conv.categorySource="manual"),(l.conv.lastSynced||"")>(a.conv.lastSynced||"")&&(a.conv.lastSynced=l.conv.lastSynced),delete e[l.name],console.log(` Merged: "${l.name}" \u2192 "${a.name}"`),n++}n>0&&(L||K(e),console.log(` ${n} duplicates merged.`))}function Os(){let e=
|
|
67
|
+
`);let o=V();for(let n of t){let{name:s}=n,r=e[s];if(!r?.messages?.length)continue;try{lt(r,s,o)}catch(l){console.warn(` [!] Enrichment failed for ${s}: ${l.message}`)}delete r._cardSynced;let i=r.profileUrl,a=null;if(i&&(a=o[i]||null),!a){let l=Object.entries(o).filter(([,c])=>c.name===s);l.length===1&&(i||(i=l[0][0],r.profileUrl=i),a=l[0][1])}!a&&i&&(Ft(i,{name:s,source:"sync-all"}),a=V()[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||(je(o),K(e)),console.log(` Enriched ${t.length} conversations.`),Ao(e)}function Ao(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,l=a===r?i:r,c=new Set((a.conv.messages||[]).map(f=>`${f.text?.slice(0,80)}|${f.time}`));for(let f of l.conv.messages||[]){let d=`${f.text?.slice(0,80)}|${f.time}`;c.has(d)||(a.conv.messages.push(f),c.add(d))}a.conv.messages.sort((f,d)=>(f.time||"").localeCompare(d.time||"")),l.conv.notes&&!a.conv.notes&&(a.conv.notes=l.conv.notes),l.conv.priority&&!a.conv.priority&&(a.conv.priority=l.conv.priority),l.conv.categorySource==="manual"&&a.conv.categorySource!=="manual"&&(a.conv.category=l.conv.category,a.conv.categorySource="manual"),(l.conv.lastSynced||"")>(a.conv.lastSynced||"")&&(a.conv.lastSynced=l.conv.lastSynced),delete e[l.name],console.log(` Merged: "${l.name}" \u2192 "${a.name}"`),n++}n>0&&(L||K(e),console.log(` ${n} duplicates merged.`))}function Os(){let e=ke(),t=V(),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{lt(u,d,t)}catch(m){console.warn(` [!] Enrichment failed for ${d}: ${m.message}`)}n++}Ao(e),L||K(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)),l=Object.entries(t),c=0,f=0;for(let[d,u]of l){if(a.has(d)){f++;continue}if(u.name&&i.has(u.name)){f++;continue}if(u.connectionStatus!=="connected"){f++;continue}so(u,d),c++}L||je(t),console.log(`
|
|
70
70
|
People enriched: ${c}`),console.log(` People skipped (have conversation or not connected): ${f}`),console.log(` People total: ${l.length}`),Ct(e,null,null)}function Ct(e,t,o,n={}){let s=Object.entries(e),r=V(),{unreadCards:i=null,readUnread:a=!1}=n;console.log(`
|
|
@@ -83,7 +83,7 @@ ${n.join(`
|
|
|
83
83
|
To pull them into the local DB (will lose unread badges): npm run sync-all -- --read-unread
|
|
84
84
|
`)}if(w.length>0){let h=w.filter(([,A])=>he(A)===x.CONFIRMED),T=w.filter(([,A])=>{let D=he(A);return D===x.DRAFT||D===x.NEEDS_REVIEW});console.log(` Drafts: ${w.length} total (${h.length} confirmed, ${T.length} pending)`),T.length>0&&console.log(" Review: npm run messages -- --review-drafts"),h.length>0&&console.log(" Send: npm run messages -- --push-drafts"),console.log()}let k=p.filter(([,h])=>h.actionNeeded==="schedule_call"),R=p.filter(([,h])=>h.actionNeeded!=="schedule_call");if(R.sort((h,T)=>{let A={high:0,medium:1,low:2}[h[1].suggestedPriority]??3,D={high:0,medium:1,low:2}[T[1].suggestedPriority]??3;return A-D}),k.length>0){console.log(` SCHEDULE CALL (${k.length}):
|
|
85
85
|
`);for(let[h,T]of k){let A=T.category||"",D=T.summary||"";console.log(` ${h}${A?` [${A}]`:""} \u2192 schedule_call`),D&&console.log(` ${D}`)}console.log()}if(R.length>0){console.log(` REPLY NEEDED (${R.length}):
|
|
86
|
-
`);let h=20;for(let[T,A]of R.slice(0,h)){let D=A.category||"",N=A.suggestedPriority?`[${A.suggestedPriority}]`:"",Oe=(A.autoTags||[]).slice(0,4).join(", "),Se=A.summary||"",Ie=[...A.messages||[]].reverse().find(we=>we.sender!==
|
|
86
|
+
`);let h=20;for(let[T,A]of R.slice(0,h)){let D=A.category||"",N=A.suggestedPriority?`[${A.suggestedPriority}]`:"",Oe=(A.autoTags||[]).slice(0,4).join(", "),Se=A.summary||"",Ie=[...A.messages||[]].reverse().find(we=>we.sender!==P&&we.sender!=="Unknown")?.text?.slice(0,80)||A.lastMessagePreview?.slice(0,80)||"";console.log(` ${N} ${T}${D?` [${D}]`:""}`),console.log(Se?` ${Se}`:` "${Ie}"`),Oe&&console.log(` #${Oe.replace(/, /g," #")}`)}R.length>h&&console.log(`
|
|
87
87
|
... and ${R.length-h} more`)}p.length===0&&console.log(" All caught up \u2014 no unanswered messages.");let M=new Set(Object.keys(e)),Je=new Set(Object.values(e).map(h=>h.profileUrl).filter(Boolean)),ye=Object.entries(r).filter(([h,T])=>T.connectionStatus==="connected"&&T.personActionNeeded==="initiate_contact"&&!Je.has(h)&&!(T.name&&M.has(T.name))).sort((h,T)=>{let A={high:0,medium:1,low:2}[h[1].personPriority]??3,D={high:0,medium:1,low:2}[T[1].personPriority]??3;return A!==D?A-D:(T[1].connectionDate||"").localeCompare(h[1].connectionDate||"")});if(ye.length>0){console.log(`
|
|
88
88
|
INITIATE CONTACT (${ye.length}):
|
|
89
89
|
`);let h=20;for(let[T,A]of ye.slice(0,h)){let D=A.personPriority?`[${A.personPriority.toUpperCase()}]`:"",N=A.personSummary||A.title||"";console.log(` ${D} ${A.name||"Unknown"} \u2014 ${N}`)}ye.length>h&&console.log(`
|
|
@@ -95,7 +95,7 @@ ${n.join(`
|
|
|
95
95
|
\u2550\u2550 BACKFILL: Reading conversations with 0 messages \u2550\u2550
|
|
96
96
|
`);let o=Object.entries(t).filter(([,l])=>!l.messages||l.messages.length===0).map(([l,c])=>({name:l,preview:c.lastMessagePreview||"",lastBy:c.lastMessageBy}));if(o.length===0)return console.log(" All conversations already have messages."),[];o.sort((l,c)=>l.lastBy==="them"&&c.lastBy!=="them"?-1:l.lastBy!=="them"&&c.lastBy==="them"?1:0);let n=Math.min(o.length,De);console.log(` ${o.length} conversations without messages, reading ${n} (--max=${De})
|
|
97
97
|
`);let s=[],r=0,i=0,a=[];for(let l=0;l<n;l++){let{name:c}=o[l];console.log(` [${l+1}/${n}] ${c}`);let f=e.page;try{if(await At(f),!(await it(f,c)).verified){console.log(" Not found or thread didn't load."),r++,await X(f),await E(500);continue}let u=await nt(f);if(!u||u.length===0){console.log(" No messages extracted."),r++,await X(f),await E(500);continue}if(!st(u,c,a)){console.log(" Skipped \u2014 stale data."),r++,await X(f),await E(500);continue}let S=await ot(f),y=t[c]||{profileUrl:null,lastSynced:new Date().toISOString(),lastMessageBy:null,lastMessagePreview:"",lastMessageTime:"",unread:!1,conversationStatus:null,messages:[]};y.messages=rt(y.messages,u),y.lastSynced=new Date().toISOString(),S&&(y.profileUrl=S),t[c]=y,L||K(t),console.log(` \u2713 ${y.messages.length} msgs${S?" +url":""}`),s.push({name:c}),a=[...new Set(u.map(v=>v.sender).filter(v=>v&&v!=="Unknown"))],await X(f),await E(500)}catch(d){if(!le(d))throw d;i++,await qe(e,`Backfill thread ${l+1}/${n} (${c})`)}}return console.log(`
|
|
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 xs(e){let t=Lt(),o=Object.values(e),n=o.filter(l=>l.sources?.includes("recruiters-from-jobs")&&!l.connectionStatus).length,s=o.filter(l=>l.connectionStatus==="modal_failed").length,r=n+s,i=o.filter(l=>l.connectionStatus==="connected"&&l.connectionMethod).length,a=o.filter(l=>l.connectionStatus==="pending"||l.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 js(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?Y(n.lastJobTitle,25):"",i=n.lastJobDate||"",a=r?` (last: ${r}${i?", "+i:""})`:"";console.log(` ${String(o+1).padStart(2)}. ${Y(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 Ms(){let e=Wt(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=Y(n.title||"?",30),r=Y(n.company||"?",15),i=n.salary?` \u2014 ${Y(n.salary,12)}`:"",a=n.location?` \u2014 ${Y(n.location,15)}`:"",l=n.recruiterUrl?" \u{1F464}":"";console.log(` ${String(t+1).padStart(2)}. [${String(o).padStart(2)}] ${s} @ ${r}${i}${a}${l}`)}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 Ns(){let e=Ht();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 Ps(){let e=Bt();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=Y(t.topAnswer,30);console.log(` "${Y(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(` "${Y(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 Y(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function Fs(){let e=
|
|
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 xs(e){let t=Lt(),o=Object.values(e),n=o.filter(l=>l.sources?.includes("recruiters-from-jobs")&&!l.connectionStatus).length,s=o.filter(l=>l.connectionStatus==="modal_failed").length,r=n+s,i=o.filter(l=>l.connectionStatus==="connected"&&l.connectionMethod).length,a=o.filter(l=>l.connectionStatus==="pending"||l.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 js(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?Y(n.lastJobTitle,25):"",i=n.lastJobDate||"",a=r?` (last: ${r}${i?", "+i:""})`:"";console.log(` ${String(o+1).padStart(2)}. ${Y(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 Ms(){let e=Wt(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=Y(n.title||"?",30),r=Y(n.company||"?",15),i=n.salary?` \u2014 ${Y(n.salary,12)}`:"",a=n.location?` \u2014 ${Y(n.location,15)}`:"",l=n.recruiterUrl?" \u{1F464}":"";console.log(` ${String(t+1).padStart(2)}. [${String(o).padStart(2)}] ${s} @ ${r}${i}${a}${l}`)}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 Ns(){let e=Ht();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 Ps(){let e=Bt();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=Y(t.topAnswer,30);console.log(` "${Y(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(` "${Y(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 Y(e,t){return e?e.length>t?e.slice(0,t-1)+"\u2026":e:""}function Fs(){let e=ke(),t=V(),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(co()),console.log(""),xs(t),console.log(""),js(t),console.log(""),Ns(),console.log(""),Ms(),console.log(""),Ps(),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:
|
|
101
101
|
`);for(let p=0;p<g.length;p++){let[w,k]=g[p],R=k.category?` [${k.category}]`:"",M=k.summary||(k.personContext?.title?`${k.personContext.title}${k.personContext.company?` at ${k.personContext.company}`:""}`:null)||k.lastMessagePreview?.slice(0,60)||null;console.log(` ${p+1}. ${w}${R}${M?` \u2014 ${M}`:""}`)}r.length>10&&console.log(` ... +${r.length-10} more`),console.log()}let i=new Date().toISOString().slice(0,10),a=s.filter(([,g])=>g.followUpNote),l=a.filter(([,g])=>!g.followUpDate||g.followUpDate<=i),c=a.filter(([,g])=>g.followUpDate&&g.followUpDate>i);if(a.length>0){console.log(` FOLLOW-UPS (${l.length} due, ${c.length} scheduled):
|
|
@@ -106,9 +106,9 @@ ${n.join(`
|
|
|
106
106
|
`);for(let p=0;p<g.length;p++){let[w,k]=g[p],R=k.category?` [${k.category}]`:"",M=k.summary||"";console.log(` ${p+1}. ${w}${R} \u2014 ${M}`)}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,k={high:0,medium:1,low:2}[p[1].personPriority]??3;return w!==k?w-k:(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],k=w.personPriority?`[${w.personPriority.toUpperCase()}]`:"",R=w.connectionDate?Ls(w.connectionDate):"",M=w.title?`${w.title}${w.company?` at ${w.company}`:""}`:w.company||"";console.log(` ${p+1}. ${k} ${w.name||"Unknown"} \u2014 ${M}${R?` (${R})`:""}`)}y.length>10&&console.log(` ... +${y.length-10} more`),console.log()}let v=s.filter(([,g])=>he(g));if(v.length>0){let g=v.filter(([,w])=>he(w)===x.CONFIRMED).length,p=v.filter(([,w])=>{let k=he(w);return k===x.DRAFT||k===x.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,C=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, ${C} 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 Ls(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 Us(){let e=
|
|
109
|
+
`)}function Ls(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 Us(){let e=ke();Ct(e,null,null)}async function Bs(){if(console.log(`
|
|
110
110
|
LinkedIn Sync-All
|
|
111
|
-
`),ko){Fs();return}if(vo){let i=Le("sync-all","report");Us(),me(i,"success");return}if(Co){let i=Le("sync-all","enrich");try{Os(),me(i,"success")}catch(a){throw me(i,"error",null,a.message),a}return}let e=$o?"backfill":bt?"full":"incremental",t=Le("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: ${De}`);let n=
|
|
111
|
+
`),ko){Fs();return}if(vo){let i=Le("sync-all","report");Us(),me(i,"success");return}if(Co){let i=Le("sync-all","enrich");try{Os(),me(i,"success")}catch(a){throw me(i,"error",null,a.message),a}return}let e=$o?"backfill":bt?"full":"incremental",t=Le("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: ${De}`);let n=ke(),s=await Kt(),r={browser:s.browser,page:s.page};try{await et(r.page);let i=null,a=[];if($o)a=await Is(r,n);else{let l=0;for(;;)try{i=await _s(r.page,n);break}catch(u){if(!le(u))throw u;if(l++,l>=wt)throw new Error(`Phase 1 failed ${wt} times on CDP death \u2014 giving up. Last: ${u.message}`);console.log(`
|
|
112
112
|
\u26A0 Phase 1 CDP dead (attempt ${l}/${wt}). Recovering and restarting Phase 1...`),await qe(r,`Phase 1 attempt ${l}`)}let c=new Set;a=await Rs(r,i.toReRead,n,c),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)||c.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||K(n))}o.threadsRead=a.length,o.newMessages=a.reduce((l,c)=>l+(c.newMessages||0),0),a.length>0&&Ds(n,a),Ct(n,i,a,{unreadCards:i?.unreadCards,readUnread:$t}),ce.pageRecoveries>0&&console.log(`
|
|
113
113
|
CDP page recoveries this run: ${ce.pageRecoveries}`),L||Xe(),me(t,"success",o)}catch(i){console.error(`
|
|
114
114
|
Error:`,i.message),vt&&console.error(i.stack),me(t,"error",o,i.message)}finally{if(!L&&!vo&&!Co&&!ko)try{Xe()}catch{}await r.browser.close()}}Bs();
|
package/dist/verifyAbout.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import he from"puppeteer";import{addExtra as ge}from"puppeteer-extra";import we from"puppeteer-extra-plugin-stealth";async function p(e){let i=Math.floor(Math.random()*2001),o=e+i;return new Promise(t=>setTimeout(t,o))}async function Y(e){return await e.evaluate(()=>{let i=document.querySelectorAll("div.artdeco-modal--is-open");for(let t of i){let l=t.innerText||"",g=l.includes("Premium")||l.includes("premium")||l.includes("Upgrade")||l.includes("upgrade"),a=l.includes("Try for")||l.includes("free trial")||l.includes("/month")||l.includes("per month")||l.includes("Start my")||l.includes("Subscribe"),d=l.includes("Get hired faster")||l.includes("Get hired 2x");if(g||a||d){let y=t.querySelector('button[aria-label="Dismiss"]')||t.querySelector("button.artdeco-modal__dismiss")||t.querySelector("button[data-test-modal-close-btn]");if(y)return y.click(),{dismissed:!0,matched:l.substring(0,80)};let f=t.querySelectorAll("button");for(let k of f){let S=k.innerText?.trim().toLowerCase()||"",v=k.getAttribute("aria-label")?.toLowerCase()||"";if(S==="not now"||S==="no thanks"||S==="dismiss"||v.includes("dismiss"))return k.click(),{dismissed:!0,matched:l.substring(0,80)}}}}let o=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(o){let t=o.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||o.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(t)return t.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}import{getPluginConfig as ae}from"@ilivemylife/graph-sdk";var ce=await ae();for(let[e,i]of Object.entries(ce))process.env[e]===void 0&&(process.env[e]=i);var ue=process.env.LINKEDIN_NAME,C=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),De=Object.freeze(new Set([C.DRAFT,C.CONFIRMED,C.NEEDS_REVIEW])),de=Object.freeze(new Set([C.DRAFT,C.CONFIRMED,C.REJECTED,C.NEEDS_REVIEW]));import z from"fs";import fe from"path";var me="cookies.json";function pe(){let e=process.env.ILML_SCOPE_DIR;return e?fe.join(e,"plugins-state","linkedin","cookies.json"):me}function G(){let e=pe();if(!z.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let i;try{i=z.readFileSync(e,"utf-8")}catch(t){throw new Error(`Failed to read cookies at ${e}: ${t.message}. Run: ilml linkedin login`)}let o;try{o=JSON.parse(i)}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 Q=ge(he);Q.use(we());async function K(){let e=await Q.launch({headless:!1,defaultViewport:null,protocolTimeout:3e5}),i=async()=>{console.log(`
|
|
2
2
|
Closing browser...`);try{await e.close()}catch{}process.exit(0)};process.on("SIGINT",i),process.on("SIGTERM",i);let o=await e.newPage();await o.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})});try{let t=G();await o.setCookie(...t),console.log(" Browser launched, cookies loaded.")}catch(t){console.error(`
|
|
3
3
|
[!] ${t.message}
|
|
4
|
-
`),await e.close(),process.exit(1)}return{browser:e,page:o}}import"dotenv/config";import*as c from"fs";import*as u from"path";import{fileURLToPath as ye}from"url";var be=ye(import.meta.url),Se=u.dirname(u.dirname(be)),w=process.env.DATA_DIR?u.resolve(process.env.DATA_DIR,"collected-profiles"):u.join(Se,"collected-profiles"),Ce=u.join(w,"people.json"),
|
|
4
|
+
`),await e.close(),process.exit(1)}return{browser:e,page:o}}import"dotenv/config";import*as c from"fs";import*as u from"path";import{fileURLToPath as ye}from"url";var be=ye(import.meta.url),Se=u.dirname(u.dirname(be)),w=process.env.DATA_DIR?u.resolve(process.env.DATA_DIR,"collected-profiles"):u.join(Se,"collected-profiles"),Ce=u.join(w,"people.json"),Ge=u.join(w,"jobs.json"),Qe=u.join(w,"quota.json"),Ke=u.join(w,"conversations.json"),Ze=u.join(w,"sync-state.json"),Xe=u.join(w,"application-questions.json"),et=u.join(w,"profile-history");var $=null;function ve(){c.existsSync(w)||c.mkdirSync(w,{recursive:!0})}function ke(e,i){if(!c.existsSync(e))return null;try{let o=JSON.parse(c.readFileSync(e,"utf-8"));try{c.copyFileSync(e,e+".backup")}catch{}return o}catch(o){console.error(`[!] ${i} is corrupted: ${o.message}`),console.error(` File: ${u.resolve(e)}`);let t=e+".backup";if(c.existsSync(t))try{let l=JSON.parse(c.readFileSync(t,"utf-8"));console.error(` Restored from ${t}`);try{c.copyFileSync(t,e)}catch{}return l}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{c.copyFileSync(e,e+".corrupted")}catch{}return null}}function D(){return $||(ve(),$=ke(Ce,"people.json")||{},$)}async function xe(e,i){let o=e.url();if(o.includes("/in/"))return!1;if(o.includes("/login")||o.includes("/authwall")||o.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: npm run login");console.log(` Off-track: ${o.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(i,{waitUntil:"domcontentloaded",timeout:6e4}),await p(3e3);let t=e.url();return t.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${t.slice(0,80)}`),!0}async function Z(e,i){try{await e.goto(i,{waitUntil:"domcontentloaded",timeout:6e4}),await p(3e3),await Y(e)&&(console.log(" Dismissed Premium overlay"),await p(1500),await xe(e,i));let t=0;for(let g=0;g<2;g++){let a=await e.evaluate(()=>document.body.scrollHeight);for(let y=1;y<=6;y++)await e.evaluate(f=>window.scrollTo(0,f),a*y/6),await p(900);let d=await e.evaluate(()=>document.body.scrollHeight);if(d===t)break;t=d}await p(800);let l=await e.evaluate(()=>{let g=new Set(["Highlights","About","Activity","Experience","Education","Skills","Recommendations","Languages","Interests","Volunteer experience","Featured","Honors & awards","Honors and awards","Projects","Publications","Patents","Certifications","Licenses & certifications","Courses","Test scores","Organizations"]),a=new Set(["Ad Options","Don\u2019t want to see this","0 notifications","Explore Premium profiles","You might like","People you may know","Suggested for you","More profiles for you","Promoted"]),d=n=>{let s=(n||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(s)},y={name:null,title:null,location:null,currentCompany:null,currentSchool:null,connectionDegree:null,hasVerifiedBadge:!1,photoUrl:null,connectionsLevel:null,mutualConnectionsCount:null,followers:null,openToWork:!1,hiring:!1,about:null,topSkills:null,availableSections:[]},f=document.querySelector("main");if(!f)return y;let k=[...Array.from(f.querySelectorAll("h1")),...Array.from(f.querySelectorAll("h2"))],S=Array.from(f.querySelectorAll("h2")),v=k.find(n=>{let s=n.textContent&&n.textContent.trim(),r=(s||"").replace(/\s*\(\d+\)$/,"").trim();return s&&s.length>1&&s.length<100&&!g.has(r)&&!a.has(r)}),_=v?v.textContent.trim():null,m=v?v.parentElement:null;for(;m&&m!==f&&!Array.from(m.children).filter(s=>s.tagName==="P").some(s=>{let r=s.textContent&&s.textContent.trim();return r&&r.length>5&&!d(r)});)m=m.parentElement;let q=null,L=null,P=null,I=null;if(m&&m!==f){let n=Array.from(m.children).filter(r=>r.tagName==="P").filter(r=>{let b=r.textContent&&r.textContent.trim();return b&&b.length>5&&!d(b)});if(n[0]&&(q=n[0].textContent.trim()),n[1]){let r=n[1].textContent.trim().split(/\s*[·•]\s*/);L=r[0]||null,r.length>1&&(P=r.slice(1).join(" \xB7 "))}let s=Array.from(m.children).filter(r=>r.tagName==="DIV");for(let r=s.length-1;r>=0;r--){let b=s[r].textContent&&s[r].textContent.trim();if(b&&!(_&&b.startsWith(_))&&(I=b.split(/[·•]/)[0].trim(),I))break}}let F=null;if(m){let n=m.querySelectorAll("p, span, div");for(let s of n){let r=(s.textContent||"").trim().replace(/^[·•]\s*/,"");if(r==="1st"||r==="2nd"||r==="3rd"){F=r;break}}}let te=!!f.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),j=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),ne=j&&j.src||null,A=f.textContent||"",O=null,N=A.match(/(\d+\+?)\s+connections\b/i);N&&(O=N[1]+" connections");let E=null,R=A.match(/(\d+)\s+mutual connection/i),B=A.match(/and\s+(\d+)\s+other mutual/i),oe=A.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);R?E=parseInt(R[1],10):B?E=2+parseInt(B[1],10):oe&&(E=2);let U=null,H=null,V=S.find(n=>n.textContent&&n.textContent.trim()==="About");if(V){let n=V.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(n){let s=(n.textContent||"").trim();s=s.replace(/^About\s*/,"").trim();let r=s.match(/Top skills\s*(.+?)$/i);if(r){let T=r[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(le=>le.trim()).filter(Boolean);T.length>0&&T.length<10&&(H=T)}s=s.split(/\n?…\s*more/i)[0].trim(),s=s.split(/\n?\.\.\.\s*more/i)[0].trim(),s=s.split(/\bTop skills\b/i)[0].trim(),s=s.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),U=s||null}}let W=null,J=S.find(n=>n.textContent&&n.textContent.trim()==="Activity");if(J){let n=J.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(n){let s=(n.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);s&&(W=parseInt(s[1].replace(/,/g,""),10))}}let se=[...new Set(S.map(n=>(n.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(n=>n&&n.length>1&&n.length<60&&n!==_).filter(n=>g.has(n)))],x=document.body.textContent||"",ie=/#OpenToWork\b/i.test(x)||/\bOpen to work\b/.test(x),re=/#Hiring\b/i.test(x)||/\bI'?m hiring\b/i.test(x)||/\bWe are hiring\b/i.test(x);return{name:_,title:q,location:I,currentCompany:L,currentSchool:P,connectionDegree:F,hasVerifiedBadge:te,photoUrl:ne,connectionsLevel:O,mutualConnectionsCount:E,followers:W,openToWork:ie,hiring:re,about:U,topSkills:H,availableSections:se}});return console.log(`Viewed: ${l.name} - ${l.title}`),{...l,profileUrl:i}}catch(o){console.error(`Error viewing profile ${i}:`,o.message);try{await e.goto("about:blank",{timeout:1e4}),await p(1e3)}catch{}return null}}var M=process.argv.slice(2),X=M.filter(e=>e.startsWith("http")),ee=parseInt(M.find(e=>e.startsWith("--pick="))?.split("=")[1]||"0"),_e=M.includes("--has-about");function Ae(e,i){return[...e].sort(()=>Math.random()-.5).slice(0,i)}function Ee(){if(X.length>0)return X.map(i=>({url:i,name:"(arg)"}));if(ee>0){let i=D(),o=Object.entries(i).filter(([t])=>t.startsWith("http")).filter(([,t])=>_e?!!(t.about&&t.about.trim()):!t.about);return Ae(o,ee).map(([t,l])=>({url:t,name:l.name}))}let e=process.env.MY_LINKEDIN_URL;return e||(console.error("Pass a URL, use --pick=N, or set MY_LINKEDIN_URL in .env"),process.exit(1)),[{url:e,name:"(self)"}]}function h(e,i,o=80){if(i==null){console.log(` ${e.padEnd(20)} (null)`);return}let t=String(i),l=t.length>o?t.slice(0,o)+`\u2026 (+${t.length-o} chars)`:t;console.log(` ${e.padEnd(20)} ${l} [len=${t.length}]`)}async function $e(){let e=Ee();console.log(`
|
|
5
5
|
About-selector verification \u2014 ${e.length} profile(s)
|
|
6
6
|
`);let{browser:i,page:o}=await K();try{for(let t=0;t<e.length;t++){let{url:l,name:g}=e[t];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"),console.log(` [${t+1}/${e.length}] ${g}`),console.log(` ${l}`),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");let a=await Z(o,l);if(!a){console.log(` \u26A0 viewProfile returned null \u2014 selector failed entirely
|
|
7
7
|
`);continue}h("name",a.name),h("title",a.title),h("location",a.location),h("company",a.company),h("connectionDegree",a.connectionDegree),h("connectionsCount",a.connectionsCount),h("mutualConnections",a.mutualConnections),h("hasVerifiedBadge",a.hasVerifiedBadge),h("photoUrl",a.photoUrl,60),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 about \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),h("about",a.about,200);let d=[];a.name||d.push("NAME MISSING"),a.title||d.push("TITLE MISSING"),a.location||d.push("LOCATION MISSING"),a.about||d.push("ABOUT MISSING"),console.log(`
|
package/dist/viewers.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var je=Object.defineProperty;var ne=(e,t)=>{for(var n in t)je(e,n,{get:t[n],enumerable:!0})};import"dotenv/config";import*as $ from"fs";import*as N from"path";import{fileURLToPath as Wt}from"url";import Ue from"puppeteer";import{addExtra as Je}from"puppeteer-extra";import Ve from"puppeteer-extra-plugin-stealth";async function V(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}import{getPluginConfig as _e}from"@ilivemylife/graph-sdk";var Fe=await _e();for(let[e,t]of Object.entries(Fe))process.env[e]===void 0&&(process.env[e]=t);var Ne=process.env.LINKEDIN_NAME,R=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),eo=Object.freeze(new Set([R.DRAFT,R.CONFIRMED,R.NEEDS_REVIEW])),Le=Object.freeze(new Set([R.DRAFT,R.CONFIRMED,R.REJECTED,R.NEEDS_REVIEW]));import se from"fs";import Pe from"path";var Me="cookies.json";function qe(){let e=process.env.ILML_SCOPE_DIR;return e?Pe.join(e,"plugins-state","linkedin","cookies.json"):Me}function re(){let e=qe();if(!se.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=se.readFileSync(e,"utf-8")}catch(o){throw new Error(`Failed to read cookies at ${e}: ${o.message}. Run: ilml linkedin login`)}let n;try{n=JSON.parse(t)}catch{throw new Error(`Cookies file at ${e} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(n)||n.length===0)throw new Error(`Cookies file at ${e} is empty or not an array. Run: ilml linkedin login`);return n}var ie=Je(Ue);ie.use(Ve());async function ce(){let e=await ie.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 n=await e.newPage();await n.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})});try{let o=re();await n.setCookie(...o),console.log(" Browser launched, cookies loaded.")}catch(o){console.error(`
|
|
3
3
|
[!] ${o.message}
|
|
4
|
-
`),await e.close(),process.exit(1)}return{browser:e,page:n}}import"dotenv/config";import*as m from"fs";import*as g from"path";import{fileURLToPath as Be}from"url";var We=Be(import.meta.url),He=g.dirname(g.dirname(We)),E=process.env.DATA_DIR?g.resolve(process.env.DATA_DIR,"collected-profiles"):g.join(He,"collected-profiles"),Ge=g.join(E,"people.json"),
|
|
4
|
+
`),await e.close(),process.exit(1)}return{browser:e,page:n}}import"dotenv/config";import*as m from"fs";import*as g from"path";import{fileURLToPath as Be}from"url";var We=Be(import.meta.url),He=g.dirname(g.dirname(We)),E=process.env.DATA_DIR?g.resolve(process.env.DATA_DIR,"collected-profiles"):g.join(He,"collected-profiles"),Ge=g.join(E,"people.json"),wo=g.join(E,"jobs.json"),vo=g.join(E,"quota.json"),bo=g.join(E,"conversations.json"),ko=g.join(E,"sync-state.json"),$o=g.join(E,"application-questions.json"),Ao=g.join(E,"profile-history");var q=null,Ye=null,ze=null,Ke=null,Qe=null,Xe=null;function le(){q=null,Ye=null,ze=null,Ke=null,Qe=null,Xe=null}function Ze(){m.existsSync(E)||m.mkdirSync(E,{recursive:!0})}function et(e,t){if(!m.existsSync(e))return null;try{let n=JSON.parse(m.readFileSync(e,"utf-8"));try{m.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${g.resolve(e)}`);let o=e+".backup";if(m.existsSync(o))try{let s=JSON.parse(m.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{m.copyFileSync(o,e)}catch{}return s}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{m.copyFileSync(e,e+".corrupted")}catch{}return null}}function ae(){return q||(Ze(),q=et(Ge,"people.json")||{},q)}import"dotenv/config";import*as O from"fs";import*as S from"path";import{fileURLToPath as tt}from"url";var ot=tt(import.meta.url),nt=S.dirname(S.dirname(ot)),J=process.env.DATA_DIR?S.resolve(process.env.DATA_DIR,"market-research"):S.join(nt,"market-research"),Do=S.join(J,"scouted-jobs.json"),st=S.join(J,"discovered-people.json"),rt=S.join(J,"visit-log.json"),Io=S.join(J,"companies.json"),Ro=S.join(J,"job-decisions.json");function ue(e){try{if(O.existsSync(e))return JSON.parse(O.readFileSync(e,"utf-8"))}catch{}return null}function fe(){it=null,ct=null,U=null,lt=null,x=null}var it=null;var ct=null;var U=null;function pe(){return U||(U=ue(st)||{},U)}var lt=null;var x=null;function de(){return x||(x=ue(rt)||{visits:[]},Array.isArray(x.visits)||(x.visits=[]),x)}async function me(e){await e.goto("https://www.linkedin.com/analytics/profile-views/",{waitUntil:"domcontentloaded",timeout:6e4}),await V(5e3);for(let n=0;n<5;n++)await e.evaluate(()=>window.scrollBy(0,600)),await V(1e3);return await e.evaluate(()=>{let n=[],o=document.querySelectorAll('a[href*="/in/"]'),s=new Set;for(let i of o){let r=i.getAttribute("href")?.split("?")[0];if(!r||s.has(r))continue;s.add(r);let c=i;for(let p=0;p<8&&!(!c.parentElement||(c=c.parentElement,c.tagName==="LI"||c.classList?.contains("pvs-list__paged-list-wrapper")));p++);let l=c?.innerText?.trim()||"",u=l.split(`
|
|
5
5
|
`).map(p=>p.trim()).filter(Boolean),f="";for(let p of u)if(p.length>2&&p.length<60&&!p.includes("View")&&!p.includes("profile")&&!p.includes("\xB7")&&!p.startsWith("1st")&&!p.startsWith("2nd")&&!p.startsWith("3rd")){f=p;break}f||(f=i.textContent?.trim()?.split(`
|
|
6
6
|
`)[0]?.trim()||""),f=f.replace(/View .+?'s profile$/i,"").trim();let h=l.match(/·\s*(1st|2nd|3rd)/)?.[1]||null,w="",L=u.indexOf(f);if(L>=0&&L+1<u.length){let p=u[L+1];!p.includes("\xB7")&&!p.startsWith("1st")&&!p.startsWith("2nd")&&(w=p)}f&&f.length>1&&n.push({profileUrl:r.startsWith("/")?"https://www.linkedin.com"+r:r,name:f,title:w||null,connectionDegree:h})}return n})}function he(e){let t=ae(),n=de(),o=pe(),s=new Map;for(let i of n.visits||[]){let r=s.get(i.profileUrl);(!r||i.date>r)&&s.set(i.profileUrl,i.date)}return e.map(i=>{let r=t[i.profileUrl],c=o[i.profileUrl],l=s.get(i.profileUrl);return{...i,isConnected:r?.connectionStatus==="connected",isPending:r?.connectionStatus==="pending"||r?.connectionStatus==="sent_without_note",isInPeopleDb:!!r,isDiscovered:!!c,weVisitedThem:!!l,ourVisitDate:l||null,category:r?.category||c?.role||null}})}import"dotenv/config";import*as v from"fs";import*as D from"path";import{fileURLToPath as mt}from"url";import"dotenv/config";import{createGraphClient as at,resolveToken as ut}from"@ilivemylife/graph-sdk";import{config as ft}from"dotenv";ft();var ge=ut()||process.env.TOKEN;ge||(console.error(`
|
|
7
7
|
[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.
|