ilml-plugin-linkedin 1.20.2 → 1.20.4

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.
@@ -1,7 +1,7 @@
1
- var yt=Object.defineProperty;var Q=(e,t)=>()=>(e&&(t=e(e=0)),t);var bt=(e,t)=>{for(var n in t)yt(e,n,{get:t[n],enumerable:!0})};async function g(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function Re(e){return await e.evaluate(()=>{let t=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of t){let i=o.innerText||"",s=i.includes("Premium")||i.includes("premium")||i.includes("Upgrade")||i.includes("upgrade"),r=i.includes("Try for")||i.includes("free trial")||i.includes("/month")||i.includes("per month")||i.includes("Start my")||i.includes("Subscribe"),y=i.includes("Get hired faster")||i.includes("Get hired 2x");if(s||r||y){let m=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(m)return m.click(),{dismissed:!0,matched:i.substring(0,80)};let $=o.querySelectorAll("button");for(let c of $){let k=c.innerText?.trim().toLowerCase()||"",h=c.getAttribute("aria-label")?.toLowerCase()||"";if(k==="not now"||k==="no thanks"||k==="dismiss"||h.includes("dismiss"))return c.click(),{dismissed:!0,matched:i.substring(0,80)}}}}let n=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(n){let o=n.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||n.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(o)return o.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}var ue=Q(()=>{});import{getPluginConfig as St}from"@ilivemylife/graph-sdk";var kt,Gt,O,zt,Qt,Te=Q(async()=>{kt=await St();for(let[e,t]of Object.entries(kt))process.env[e]===void 0&&(process.env[e]=t);Gt=process.env.LINKEDIN_NAME,O=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),zt=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.NEEDS_REVIEW])),Qt=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.REJECTED,O.NEEDS_REVIEW]))});import"dotenv/config";import*as f from"fs";import*as b from"path";import{fileURLToPath as Ct}from"url";function qe(){f.existsSync(_)||f.mkdirSync(_,{recursive:!0})}function Be(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";f.writeFileSync(o,n);for(let i=0;i<3;i++)try{f.renameSync(o,e);return}catch(s){if(i<2&&(s.code==="EPERM"||s.code==="EBUSY")){let r=Date.now();for(;Date.now()-r<200;);continue}throw s}}function Ue(e,t){if(!f.existsSync(e))return null;try{let n=JSON.parse(f.readFileSync(e,"utf-8"));try{f.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${b.resolve(e)}`);let o=e+".backup";if(f.existsSync(o))try{let i=JSON.parse(f.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{f.copyFileSync(o,e)}catch{}return i}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{f.copyFileSync(e,e+".corrupted")}catch{}return null}}function Et(){return new Date().toISOString().split("T")[0]}function q(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Fe(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function He(e,t,n=null){if(!t||e[t])return t;let o=q(t);if(!o)return t;let i=null;for(let[s,r]of Object.entries(e)){if(q(r.profileUrl||s)===o)return s;!i&&Array.isArray(r.aliases)&&r.aliases.includes(o)&&(i=s)}if(i){let s=Fe(n),r=Fe(e[i].name);if(s&&r&&s===r)return i}return t}function _t(){f.existsSync(fe)||f.mkdirSync(fe,{recursive:!0})}function Ve(e){let t=q(e);return t?b.join(fe,`${t}.json`):null}function $t(e){let t=Ve(e);return t?Ue(t,`profile-history/${q(e)}.json`)||[]:[]}function Dt(e,t){let n=Ve(e);if(!n)return;_t();let o=$t(e);o.unshift(t);try{Be(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${q(e)}: ${i.message}`)}}function Pe(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function je(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Lt(e,t){if(!e)return[];let n=[];for(let o of At){let i=e[o],s=t[o];Pe(i)||Pe(s)||je(i)!==je(s)&&n.push(o)}return n}function Mt(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,i]of Object.entries(e))t.has(o)||(n[o]=i);return n}function me(){return W||(qe(),W=Ue(de,"people.json")||{},W)}function We(e){qe(),W=e;try{Be(de,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${b.resolve(de)}`)}}function pe(e,t={}){if(!e)return null;let n=me(),o=Et(),i=new Date().toISOString(),s=He(n,e,t.name),r=n[s];if(r){let y=Lt(r,t);y.length>0&&(Dt(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:y,snapshot:Mt(r)}),r.lastSnapshotAt=i),r.seenCount=(r.seenCount||1)+1,r.lastSeen=o,r.lastUpdated=i,t.source&&!r.sources?.includes(t.source)&&(r.sources=r.sources||[],r.sources.push(t.source));for(let m of It)if(t[m]!=null){if(Array.isArray(t[m])&&t[m].length===0&&Array.isArray(r[m])&&r[m].length>0)continue;r[m]=t[m]}Array.isArray(t.availableSections)&&(r.lastFullVisitAt=i)}else n[s]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,featured:t.featured||null,education:t.education||null,skillsFull:t.skillsFull||null,recommendations:t.recommendations||null,certifications:t.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:i,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?i:null};return We(n),n[s]}function he(e,t,n={}){if(n.dryRun||!e||!t)return;let o=q(t);if(!o)return;let i=me(),s=He(i,e),r=i[s];if(!r)return;let y=q(r.profileUrl||s);o!==y&&(Array.isArray(r.aliases)||(r.aliases=[]),r.aliases.includes(o)||(r.aliases.push(o),r.lastUpdated=new Date().toISOString(),We(i)))}var vt,xt,_,de,nn,on,rn,sn,ln,fe,Oe,an,cn,W,It,At,we=Q(async()=>{await Te();vt=Ct(import.meta.url),xt=b.dirname(b.dirname(vt)),_=process.env.DATA_DIR?b.resolve(process.env.DATA_DIR,"collected-profiles"):b.join(xt,"collected-profiles"),de=b.join(_,"people.json"),nn=b.join(_,"jobs.json"),on=b.join(_,"quota.json"),rn=b.join(_,"conversations.json"),sn=b.join(_,"sync-state.json"),ln=b.join(_,"application-questions.json"),fe=b.join(_,"profile-history"),Oe=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},an=Oe(process.env.CONNECT_MAX_DAILY,20),cn=Oe(process.env.CONNECT_MAX_WEEKLY,100),W=null;It=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt","featured","education","skillsFull","recommendations","certifications"],At=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var Je={};bt(Je,{extractCertificationsFromDetails:()=>Pt,extractEducationFromDetails:()=>Tt,extractExperienceFromDetails:()=>Nt,extractFeaturedFromDetails:()=>Rt,extractRecommendationsFromDetails:()=>jt,extractSkillsFromDetails:()=>Ft});async function Nt(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3);let o=e.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(900);await g(1e3);let i=0;for(;i<5&&await e.evaluate(()=>{for(let r of document.querySelectorAll("button"))if(/^Load more$/i.test((r.textContent||"").trim()))return r.click(),!0;return!1});)i++,await g(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function r(c){let k=[];for(let h of c.querySelectorAll("div")){let w=Array.from(h.children).filter(E=>E.tagName==="DIV");if(w.length<3)continue;let S=w.filter(E=>(E.textContent||"").trim().length>50);S.length<3||(h.textContent||"").length<500||k.push({el:h,count:S.length,totalText:(h.textContent||"").length})}return k.sort((h,w)=>w.count-h.count||h.totalText-w.totalText),k[0]?.el}let y=r(s);if(!y)return[];let m=Array.from(y.children).filter(c=>c.tagName==="DIV").filter(c=>(c.textContent||"").trim().length>50);function $(c){let k=c[0]||null,h=null,w=null;if(c[1]){let d=c[1].split("\xB7").map(C=>C.trim());h=d[0]||null,d[1]&&(w=d[1])}let S=c.findIndex(d=>/(\d{4}|present)/i.test(d)&&/(-|–|—)/i.test(d)&&d.length<80),E=null,R=null;if(S>=0){let d=c[S].split("\xB7").map(C=>C.trim());E=d[0]||null,d[1]&&(R=d[1])}let T=null,F=-1;if(S>=0&&c[S+1]){let d=c[S+1],C=/^[>*\-•]|^&gt;/.test(d),U=/https?:\/\//.test(d),H=/\d{4}/.test(d),v=/,/.test(d)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(d);!C&&!U&&!H&&d.length<100&&v&&(T=d,F=S+1)}let le=null,p=-1,P=c[c.length-1];if(P&&/and\s+\+\d+\s+skills?$/i.test(P)){p=c.length-1;let d=P.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);d&&(le={listed:d[1].split(",").map(C=>C.trim()),additional:parseInt(d[2],10)})}let j=new Set([0,1,S,F,p].filter(d=>d>=0)),D=c.filter((d,C)=>!j.has(C)),x=D.length>0?D.join(`
1
+ var $t=Object.defineProperty;var X=(e,t)=>()=>(e&&(t=e(e=0)),t);var Dt=(e,t)=>{for(var n in t)$t(e,n,{get:t[n],enumerable:!0})};async function y(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function Oe(e){return await e.evaluate(()=>{let t=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of t){let i=o.innerText||"",s=i.includes("Premium")||i.includes("premium")||i.includes("Upgrade")||i.includes("upgrade"),r=i.includes("Try for")||i.includes("free trial")||i.includes("/month")||i.includes("per month")||i.includes("Start my")||i.includes("Subscribe"),m=i.includes("Get hired faster")||i.includes("Get hired 2x");if(s||r||m){let f=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(f)return f.click(),{dismissed:!0,matched:i.substring(0,80)};let $=o.querySelectorAll("button");for(let c of $){let k=c.innerText?.trim().toLowerCase()||"",w=c.getAttribute("aria-label")?.toLowerCase()||"";if(k==="not now"||k==="no thanks"||k==="dismiss"||w.includes("dismiss"))return c.click(),{dismissed:!0,matched:i.substring(0,80)}}}}let n=document.querySelector(".premium-upsell-link")||document.querySelector("[data-test-premium-upsell]")||document.querySelector(".premium-hub-upsell");if(n){let o=n.closest('[class*="modal"]')?.querySelector('button[aria-label="Dismiss"]')||n.closest('[class*="banner"]')?.querySelector('button[aria-label="Close"]');if(o)return o.click(),{dismissed:!0,matched:"premium-banner"}}return!1})}var me=X(()=>{});import{getPluginConfig as Lt}from"@ilivemylife/graph-sdk";var Tt,fn,O,mn,pn,qe=X(async()=>{Tt=await Lt();for(let[e,t]of Object.entries(Tt))process.env[e]===void 0&&(process.env[e]=t);fn=process.env.LINKEDIN_NAME,O=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),mn=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.NEEDS_REVIEW])),pn=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.REJECTED,O.NEEDS_REVIEW]))});import"dotenv/config";import*as p from"fs";import*as b from"path";import{fileURLToPath as Rt}from"url";function We(){p.existsSync(_)||p.mkdirSync(_,{recursive:!0})}function Je(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";p.writeFileSync(o,n);for(let i=0;i<3;i++)try{p.renameSync(o,e);return}catch(s){if(i<2&&(s.code==="EPERM"||s.code==="EBUSY")){let r=Date.now();for(;Date.now()-r<200;);continue}throw s}}function Ke(e,t){if(!p.existsSync(e))return null;try{let n=JSON.parse(p.readFileSync(e,"utf-8"));try{p.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${b.resolve(e)}`);let o=e+".backup";if(p.existsSync(o))try{let i=JSON.parse(p.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{p.copyFileSync(o,e)}catch{}return i}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${e}.corrupted`);try{p.copyFileSync(e,e+".corrupted")}catch{}return null}}function Nt(){return new Date().toISOString().split("T")[0]}function q(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function Be(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function Ye(e,t,n=null){if(!t||e[t])return t;let o=q(t);if(!o)return t;let i=null;for(let[s,r]of Object.entries(e)){if(q(r.profileUrl||s)===o)return s;!i&&Array.isArray(r.aliases)&&r.aliases.includes(o)&&(i=s)}if(i){let s=Be(n),r=Be(e[i].name);if(s&&r&&s===r)return i}return t}function Ot(){p.existsSync(he)||p.mkdirSync(he,{recursive:!0})}function Ge(e){let t=q(e);return t?b.join(he,`${t}.json`):null}function qt(e){let t=Ge(e);return t?Ke(t,`profile-history/${q(e)}.json`)||[]:[]}function Bt(e,t){let n=Ge(e);if(!n)return;Ot();let o=qt(e);o.unshift(t);try{Je(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${q(e)}: ${i.message}`)}}function He(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Ue(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function Ht(e,t){if(!e)return[];let n=[];for(let o of jt){let i=e[o],s=t[o];He(i)||He(s)||Ue(i)!==Ue(s)&&n.push(o)}return n}function Ut(e){let t=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,i]of Object.entries(e))t.has(o)||(n[o]=i);return n}function we(){return W||(We(),W=Ke(pe,"people.json")||{},W)}function ze(e){We(),W=e;try{Je(pe,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${b.resolve(pe)}`)}}function ge(e,t={}){if(!e)return null;let n=we(),o=Nt(),i=new Date().toISOString(),s=Ye(n,e,t.name),r=n[s];if(r){let m=Ht(r,t);m.length>0&&(Bt(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:m,snapshot:Ut(r)}),r.lastSnapshotAt=i),r.seenCount=(r.seenCount||1)+1,r.lastSeen=o,r.lastUpdated=i,t.source&&!r.sources?.includes(t.source)&&(r.sources=r.sources||[],r.sources.push(t.source));for(let f of Ft)if(t[f]!=null){if(Array.isArray(t[f])&&t[f].length===0&&Array.isArray(r[f])&&r[f].length>0)continue;r[f]=t[f]}Array.isArray(t.availableSections)&&(r.lastFullVisitAt=i)}else n[s]={name:t.name||null,title:t.title||null,location:t.location||null,company:t.company||null,about:t.about||null,connectionDegree:t.connectionDegree||null,connectionsCount:t.connectionsCount||null,mutualConnections:t.mutualConnections||null,photoUrl:t.photoUrl||null,hasVerifiedBadge:t.hasVerifiedBadge||!1,currentCompany:t.currentCompany||null,currentSchool:t.currentSchool||null,connectionsLevel:t.connectionsLevel||null,mutualConnectionsCount:t.mutualConnectionsCount||null,followers:t.followers||null,openToWork:t.openToWork||!1,hiring:t.hiring||!1,topSkills:t.topSkills||null,availableSections:t.availableSections||null,experience:t.experience||null,featuredLinks:t.featuredLinks||null,_lastEnrichedAt:t._lastEnrichedAt||null,featured:t.featured||null,education:t.education||null,skillsFull:t.skillsFull||null,recommendations:t.recommendations||null,certifications:t.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:t.source?[t.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:i,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(t.availableSections)?i:null};return ze(n),n[s]}function ye(e,t,n={}){if(n.dryRun||!e||!t)return;let o=q(t);if(!o)return;let i=we(),s=Ye(i,e),r=i[s];if(!r)return;let m=q(r.profileUrl||s);o!==m&&(Array.isArray(r.aliases)||(r.aliases=[]),r.aliases.includes(o)||(r.aliases.push(o),r.lastUpdated=new Date().toISOString(),ze(i)))}var Mt,Pt,_,pe,bn,Sn,kn,Cn,vn,he,Ve,xn,En,W,Ft,jt,be=X(async()=>{await qe();Mt=Rt(import.meta.url),Pt=b.dirname(b.dirname(Mt)),_=process.env.DATA_DIR?b.resolve(process.env.DATA_DIR,"collected-profiles"):b.join(Pt,"collected-profiles"),pe=b.join(_,"people.json"),bn=b.join(_,"jobs.json"),Sn=b.join(_,"quota.json"),kn=b.join(_,"conversations.json"),Cn=b.join(_,"sync-state.json"),vn=b.join(_,"application-questions.json"),he=b.join(_,"profile-history"),Ve=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},xn=Ve(process.env.CONNECT_MAX_DAILY,20),En=Ve(process.env.CONNECT_MAX_WEEKLY,100),W=null;Ft=["name","title","location","company","connectionDegree","connectionsCount","mutualConnections","photoUrl","hasVerifiedBadge","about","currentCompany","currentSchool","connectionsLevel","mutualConnectionsCount","followers","openToWork","hiring","topSkills","availableSections","experience","featuredLinks","_lastEnrichedAt","featured","education","skillsFull","recommendations","certifications"],jt=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var Qe={};Dt(Qe,{extractCertificationsFromDetails:()=>Yt,extractEducationFromDetails:()=>Jt,extractExperienceFromDetails:()=>Vt,extractFeaturedFromDetails:()=>Wt,extractRecommendationsFromDetails:()=>Gt,extractSkillsFromDetails:()=>Kt});async function Vt(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let o=e.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(900);await y(1e3);let i=0;for(;i<5&&await e.evaluate(()=>{for(let r of document.querySelectorAll("button"))if(/^Load more$/i.test((r.textContent||"").trim()))return r.click(),!0;return!1});)i++,await y(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function r(c){let k=[];for(let w of c.querySelectorAll("div")){let g=Array.from(w.children).filter(E=>E.tagName==="DIV");if(g.length<3)continue;let S=g.filter(E=>(E.textContent||"").trim().length>50);S.length<3||(w.textContent||"").length<500||k.push({el:w,count:S.length,totalText:(w.textContent||"").length})}return k.sort((w,g)=>g.count-w.count||w.totalText-g.totalText),k[0]?.el}let m=r(s);if(!m)return[];let f=Array.from(m.children).filter(c=>c.tagName==="DIV").filter(c=>(c.textContent||"").trim().length>50);function $(c){let k=c[0]||null,w=null,g=null;if(c[1]){let d=c[1].split("\xB7").map(C=>C.trim());w=d[0]||null,d[1]&&(g=d[1])}let S=c.findIndex(d=>/(\d{4}|present)/i.test(d)&&/(-|–|—)/i.test(d)&&d.length<80),E=null,M=null;if(S>=0){let d=c[S].split("\xB7").map(C=>C.trim());E=d[0]||null,d[1]&&(M=d[1])}let P=null,N=-1;if(S>=0&&c[S+1]){let d=c[S+1],C=/^[>*\-•]|^&gt;/.test(d),H=/https?:\/\//.test(d),U=/\d{4}/.test(d),v=/,/.test(d)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(d);!C&&!H&&!U&&d.length<100&&v&&(P=d,N=S+1)}let ue=null,h=-1,F=c[c.length-1];if(F&&/and\s+\+\d+\s+skills?$/i.test(F)){h=c.length-1;let d=F.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);d&&(ue={listed:d[1].split(",").map(C=>C.trim()),additional:parseInt(d[2],10)})}let j=new Set([0,1,S,N,h].filter(d=>d>=0)),D=c.filter((d,C)=>!j.has(C)),x=D.length>0?D.join(`
2
2
 
3
- `):null;return{title:k,company:h,employmentType:w,dates:E,duration:R,location:T,description:x,skills:le,_raw:c}}return m.map(c=>{let h=(c.innerText||"").trim().split(`
4
- `).map(w=>w.trim()).filter(w=>w&&w.length<5e3);return $(h)}).filter(c=>c.title)})}catch(o){if(/session expired|bounced to|authwall|checkpoint/i.test(o.message||""))throw o;return console.error(`extractExperienceFromDetails failed for ${t}: ${o.message?.slice(0,120)}`),[]}}async function J(e,t,n){let o=t.replace(/\/+$/,"")+`/details/${n}/`;await e.goto(o,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3);let i=e.url();if(/\/(login|authwall|checkpoint)/i.test(i))throw new Error(`Session expired \u2014 bounced to ${i} when fetching /details/${n}/`);if(!i.toLowerCase().includes(`/details/${n.toLowerCase()}/`))throw new Error(`Section /details/${n}/ not available on profile (landed on ${i})`);for(let r=0;r<4;r++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(700);await g(800);let s=0;for(;s<5&&await e.evaluate(()=>{for(let y of document.querySelectorAll("button"))if(/^Load more$/i.test((y.textContent||"").trim()))return y.click(),!0;return!1});)s++,await g(1300),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(600)}async function Y(e,t,n,o){try{return await o()}catch(i){let s=i.message||"";if(/session expired|bounced to|authwall|checkpoint/i.test(s))throw i;return/not available on profile/i.test(s)?(console.log(` (${t}: section not on profile \u2014 skipped)`),[]):(console.error(`${n} failed for ${e}: ${s.slice(0,120)}`),[])}}async function Rt(e,t){return Y(t,"featured","extractFeaturedFromDetails",async()=>(await J(e,t,"featured"),await e.evaluate(`(() => {
3
+ `):null;return{title:k,company:w,employmentType:g,dates:E,duration:M,location:P,description:x,skills:ue,_raw:c}}return f.map(c=>{let w=(c.innerText||"").trim().split(`
4
+ `).map(g=>g.trim()).filter(g=>g&&g.length<5e3);return $(w)}).filter(c=>c.title)})}catch(o){if(/session expired|bounced to|authwall|checkpoint/i.test(o.message||""))throw o;return console.error(`extractExperienceFromDetails failed for ${t}: ${o.message?.slice(0,120)}`),[]}}async function J(e,t,n){let o=t.replace(/\/+$/,"")+`/details/${n}/`;await e.goto(o,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let i=e.url();if(/\/(login|authwall|checkpoint)/i.test(i))throw new Error(`Session expired \u2014 bounced to ${i} when fetching /details/${n}/`);if(!i.toLowerCase().includes(`/details/${n.toLowerCase()}/`))throw new Error(`Section /details/${n}/ not available on profile (landed on ${i})`);for(let r=0;r<4;r++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(700);await y(800);let s=0;for(;s<5&&await e.evaluate(()=>{for(let m of document.querySelectorAll("button"))if(/^Load more$/i.test((m.textContent||"").trim()))return m.click(),!0;return!1});)s++,await y(1300),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(600)}async function Y(e,t,n,o){try{return await o()}catch(i){let s=i.message||"";if(/session expired|bounced to|authwall|checkpoint/i.test(s))throw i;return/not available on profile/i.test(s)?(console.log(` (${t}: section not on profile \u2014 skipped)`),[]):(console.error(`${n} failed for ${e}: ${s.slice(0,120)}`),[])}}async function Wt(e,t){return Y(t,"featured","extractFeaturedFromDetails",async()=>(await J(e,t,"featured"),await e.evaluate(`(() => {
5
5
  ${K}
6
6
 
7
7
  const main = document.querySelector('main');
@@ -42,7 +42,7 @@ var yt=Object.defineProperty;var Q=(e,t)=>()=>(e&&(t=e(e=0)),t);var bt=(e,t)=>{f
42
42
  if (e.caption && /^\xB7\\s*\\d+(?:st|nd|rd|th)\\+?$/i.test(e.caption.trim())) return false;
43
43
  return true;
44
44
  });
45
- })()`)))}async function Tt(e,t){return Y(t,"education","extractEducationFromDetails",async()=>(await J(e,t,"education"),await e.evaluate(`(() => {
45
+ })()`)))}async function Jt(e,t){return Y(t,"education","extractEducationFromDetails",async()=>(await J(e,t,"education"),await e.evaluate(`(() => {
46
46
  ${K}
47
47
 
48
48
  const main = document.querySelector('main');
@@ -79,7 +79,7 @@ var yt=Object.defineProperty;var Q=(e,t)=>()=>(e&&(t=e(e=0)),t);var bt=(e,t)=>{f
79
79
  if (e.degree && /^\xB7\\s*\\d+(?:st|nd|rd|th)\\+?$/i.test(e.degree.trim())) return false;
80
80
  return true;
81
81
  });
82
- })()`)))}async function Ft(e,t){return Y(t,"skills","extractSkillsFromDetails",async()=>(await J(e,t,"skills"),await e.evaluate(`(() => {
82
+ })()`)))}async function Kt(e,t){return Y(t,"skills","extractSkillsFromDetails",async()=>(await J(e,t,"skills"),await e.evaluate(`(() => {
83
83
  ${K}
84
84
 
85
85
  const main = document.querySelector('main');
@@ -111,7 +111,7 @@ var yt=Object.defineProperty;var Q=(e,t)=>()=>(e&&(t=e(e=0)),t);var bt=(e,t)=>{f
111
111
  skills.push({ name, endorsements, _raw: lines });
112
112
  }
113
113
  return skills;
114
- })()`)))}async function Pt(e,t){return Y(t,"certifications","extractCertificationsFromDetails",async()=>(await J(e,t,"certifications"),await e.evaluate(`(() => {
114
+ })()`)))}async function Yt(e,t){return Y(t,"certifications","extractCertificationsFromDetails",async()=>(await J(e,t,"certifications"),await e.evaluate(`(() => {
115
115
  ${K}
116
116
 
117
117
  const main = document.querySelector('main');
@@ -136,7 +136,7 @@ var yt=Object.defineProperty;var Q=(e,t)=>()=>(e&&(t=e(e=0)),t);var bt=(e,t)=>{f
136
136
 
137
137
  return { name, issuer, issueDate, expiryDate, credentialId, _raw: lines };
138
138
  }).filter(e => e.name);
139
- })()`)))}async function jt(e,t){return Y(t,"recommendations","extractRecommendationsFromDetails",async()=>(await J(e,t,"recommendations"),await e.evaluate(`(() => {
139
+ })()`)))}async function Gt(e,t){return Y(t,"recommendations","extractRecommendationsFromDetails",async()=>(await J(e,t,"recommendations"),await e.evaluate(`(() => {
140
140
  ${K}
141
141
 
142
142
  const main = document.querySelector('main');
@@ -172,7 +172,7 @@ var yt=Object.defineProperty;var Q=(e,t)=>()=>(e&&(t=e(e=0)),t);var bt=(e,t)=>{f
172
172
  if (e.recommenderTitle && /^\xB7\\s*\\d+(?:st|nd|rd|th)\\+?$/i.test(e.recommenderTitle.trim())) return false;
173
173
  return true;
174
174
  });
175
- })()`)))}var K,Ke=Q(()=>{ue();K=`
175
+ })()`)))}var K,Ze=X(()=>{me();K=`
176
176
  function findEntryContainer(root) {
177
177
  const candidates = [];
178
178
  for (const div of root.querySelectorAll('div')) {
@@ -235,7 +235,7 @@ function findEntryContainer(root) {
235
235
  candidates.sort((a, b) => b.count - a.count || b.totalText - a.totalText);
236
236
  return candidates[0]?.el;
237
237
  }
238
- `});import"dotenv/config";import Vt from"puppeteer";ue();await we();async function Ot(e,t){let n=e.url();if(n.includes("/in/"))return!1;if(n.includes("/login")||n.includes("/authwall")||n.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Ye(e,t,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:s=!1,extractSkills:r=!1,extractRecommendations:y=!1,extractCertifications:m=!1}=n;try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3),await Re(e)&&(console.log(" Dismissed Premium overlay"),await g(1500),await Ot(e,t));let c=0;for(let p=0;p<2;p++){let P=await e.evaluate(()=>document.body.scrollHeight);for(let D=1;D<=6;D++)await e.evaluate(x=>window.scrollTo(0,x),P*D/6),await g(900);let j=await e.evaluate(()=>document.body.scrollHeight);if(j===c)break;c=j}await g(800);let k=null;try{let p=e.url();p&&/\/in\/[^/?#]/.test(p)&&(k=p.split("?")[0].replace(/\/+$/,""))}catch{}let h=await e.evaluate(()=>{let p=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"]),P=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"]),j=l=>{let a=(l||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(a)},D={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:[]},x=document.querySelector("main");if(!x)return D;let d=[...Array.from(x.querySelectorAll("h1")),...Array.from(x.querySelectorAll("h2"))],C=Array.from(x.querySelectorAll("h2")),U=d.find(l=>{let a=l.textContent&&l.textContent.trim(),u=(a||"").replace(/\s*\(\d+\)$/,"").trim();return a&&a.length>1&&a.length<100&&!p.has(u)&&!P.has(u)}),H=U?U.textContent.trim():null,v=U?U.parentElement:null;for(;v&&v!==x&&!Array.from(v.children).filter(a=>a.tagName==="P").some(a=>{let u=a.textContent&&a.textContent.trim();return u&&u.length>5&&!j(u)});)v=v.parentElement;let Se=null,ke=null,Ce=null,ae=null;if(v&&v!==x){let l=Array.from(v.children).filter(u=>u.tagName==="P").filter(u=>{let L=u.textContent&&u.textContent.trim();return L&&L.length>5&&!j(L)});if(l[0]&&(Se=l[0].textContent.trim()),l[1]){let u=l[1].textContent.trim().split(/\s*[·•]\s*/);ke=u[0]||null,u.length>1&&(Ce=u.slice(1).join(" \xB7 "))}let a=Array.from(v.children).filter(u=>u.tagName==="DIV");for(let u=a.length-1;u>=0;u--){let L=a[u].textContent&&a[u].textContent.trim();if(L&&!(H&&L.startsWith(H))&&(ae=L.split(/[·•]/)[0].trim(),ae))break}}let ve=null;if(v){let l=v.querySelectorAll("p, span, div");for(let a of l){let u=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(u==="1st"||u==="2nd"||u==="3rd"){ve=u;break}}}let dt=!!x.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),xe=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),ft=xe&&xe.src||null,G=x.textContent||"",Ee=null,Ie=G.match(/(\d+\+?)\s+connections\b/i);Ie&&(Ee=Ie[1]+" connections");let z=null,Ae=G.match(/(\d+)\s+mutual connection/i),_e=G.match(/and\s+(\d+)\s+other mutual/i),mt=G.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Ae?z=parseInt(Ae[1],10):_e?z=2+parseInt(_e[1],10):mt&&(z=2);let $e=null,De=null,Le=C.find(l=>l.textContent&&l.textContent.trim()==="About");if(Le){let l=Le.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").trim();a=a.replace(/^About\s*/,"").trim();let u=a.match(/Top skills\s*(.+?)$/i);if(u){let ce=u[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(gt=>gt.trim()).filter(Boolean);ce.length>0&&ce.length<10&&(De=ce)}a=a.split(/\n?…\s*more/i)[0].trim(),a=a.split(/\n?\.\.\.\s*more/i)[0].trim(),a=a.split(/\bTop skills\b/i)[0].trim(),a=a.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),$e=a||null}}let Me=null,Ne=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(Ne){let l=Ne.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&(Me=parseInt(a[1].replace(/,/g,""),10))}}let pt=[...new Set(C.map(l=>(l.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(l=>l&&l.length>1&&l.length<60&&l!==H).filter(l=>p.has(l)))],V=document.body.textContent||"",ht=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),wt=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:H,title:Se,location:ae,currentCompany:ke,currentSchool:Ce,connectionDegree:ve,hasVerifiedBadge:dt,photoUrl:ft,connectionsLevel:Ee,mutualConnectionsCount:z,followers:Me,openToWork:ht,hiring:wt,about:$e,topSkills:De,availableSections:pt}});console.log(`Viewed: ${h.name} - ${h.title}`);let w=null,S=null,E=null,R=null,T=null,F=null;if(o||i||s||r||y||m){let p=await Promise.resolve().then(()=>(Ke(),Je));o&&(w=await p.extractExperienceFromDetails(e,t),console.log(` + Experience: ${w.length} entries`)),i&&(S=await p.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${S.length} entries`)),s&&(E=await p.extractEducationFromDetails(e,t),console.log(` + Education: ${E.length} entries`)),r&&(R=await p.extractSkillsFromDetails(e,t),console.log(` + Skills: ${R.length} entries`)),y&&(T=await p.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${T.length} entries`)),m&&(F=await p.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${F.length} entries`))}return{...h,profileUrl:t,resolvedUrl:k,...w!==null&&{experience:w},...S!==null&&{featured:S},...E!==null&&{education:E},...R!==null&&{skillsFull:R},...T!==null&&{recommendations:T},...F!==null&&{certifications:F}}}catch($){console.error(`Error viewing profile ${t}:`,$.message);try{await e.goto("about:blank",{timeout:1e4}),await g(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test($.message||""))throw $;return null}}await we();import I from"fs";import M from"path";var qt="cookies.json";function Ge(){let e=process.env.ILML_SCOPE_DIR;return e?M.join(e,"plugins-state","linkedin","cookies.json"):qt}function ze(){let e=Ge();if(!I.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=I.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}function Qe(){return I.existsSync(Ge())}function Bt(){let e=process.env.ILML_SCOPE_DIR;return e?M.join(e,"plugins-state","linkedin"):"."}function Ze(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function Ut(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?Ze(t[1]):"default"}function Xe(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return I.existsSync(t)||I.mkdirSync(t,{recursive:!0}),M.resolve(t);let n=Ze(e||Ut()),o=M.join(Bt(),"chrome-profile",n);return I.existsSync(o)||I.mkdirSync(o,{recursive:!0}),M.resolve(o)}var et=".ilml-seeded";function tt(e){return!I.existsSync(M.join(e,et))}function nt(e){try{I.writeFileSync(M.join(e,et),new Date().toISOString())}catch{}}function ot(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{I.rmSync(M.join(e,n),{force:!0}),t++}catch{}return t}var Ht={headless:!1,defaultViewport:null,protocolTimeout:3e5};async function it(e,t={}){let n=Xe(),o={...Ht,...t,userDataDir:n},i;try{i=await e.launch(o)}catch{ot(n);try{i=await e.launch(o)}catch(r){throw new Error(`Could not open the LinkedIn automation Chrome profile at ${n}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${r.message})`)}}return{browser:i,profileDir:n,needsSeed:tt(n)}}async function rt(e,t){if(!t||!t.needsSeed)return!1;if(!Qe())return console.warn(" \u26A0 No saved LinkedIn session found. If this command comes back empty or redirects to login, run: ilml linkedin login"),!1;try{return await e.setCookie(...ze()),nt(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function st(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function lt(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),Wt=A.includes("--help")||A.includes("-h"),N=A.find(e=>e.startsWith("http")),B=A.includes("--full"),X=B||A.includes("--with-experience"),ee=B||A.includes("--with-featured"),te=B||A.includes("--with-education"),ne=B||A.includes("--with-skills"),oe=B||A.includes("--with-recommendations"),ie=B||A.includes("--with-certifications"),at=[["experience",X],["featured",ee],["education",te],["skills",ne],["recommendations",oe],["certifications",ie]],ct=at.filter(([,e])=>e).length,ye=1+ct;function ut(){console.log(`
238
+ `});import"dotenv/config";import ln from"puppeteer";me();await be();async function zt(e,t){let n=e.url();if(n.includes("/in/"))return!1;if(n.includes("/login")||n.includes("/authwall")||n.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Xe(e,t,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:s=!1,extractSkills:r=!1,extractRecommendations:m=!1,extractCertifications:f=!1}=n;try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4}),await y(3e3),await Oe(e)&&(console.log(" Dismissed Premium overlay"),await y(1500),await zt(e,t));let c=0;for(let h=0;h<2;h++){let F=await e.evaluate(()=>document.body.scrollHeight);for(let D=1;D<=6;D++)await e.evaluate(x=>window.scrollTo(0,x),F*D/6),await y(900);let j=await e.evaluate(()=>document.body.scrollHeight);if(j===c)break;c=j}await y(800);let k=null;try{let h=e.url();h&&/\/in\/[^/?#]/.test(h)&&(k=h.split("?")[0].replace(/\/+$/,""))}catch{}let w=await e.evaluate(()=>{let h=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"]),F=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"]),j=l=>{let a=(l||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(a)},D={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:[]},x=document.querySelector("main");if(!x)return D;let d=[...Array.from(x.querySelectorAll("h1")),...Array.from(x.querySelectorAll("h2"))],C=Array.from(x.querySelectorAll("h2")),H=d.find(l=>{let a=l.textContent&&l.textContent.trim(),u=(a||"").replace(/\s*\(\d+\)$/,"").trim();return a&&a.length>1&&a.length<100&&!h.has(u)&&!F.has(u)}),U=H?H.textContent.trim():null,v=H?H.parentElement:null;for(;v&&v!==x&&!Array.from(v.children).filter(a=>a.tagName==="P").some(a=>{let u=a.textContent&&a.textContent.trim();return u&&u.length>5&&!j(u)});)v=v.parentElement;let Ee=null,Ie=null,Ae=null,de=null;if(v&&v!==x){let l=Array.from(v.children).filter(u=>u.tagName==="P").filter(u=>{let L=u.textContent&&u.textContent.trim();return L&&L.length>5&&!j(L)});if(l[0]&&(Ee=l[0].textContent.trim()),l[1]){let u=l[1].textContent.trim().split(/\s*[·•]\s*/);Ie=u[0]||null,u.length>1&&(Ae=u.slice(1).join(" \xB7 "))}let a=Array.from(v.children).filter(u=>u.tagName==="DIV");for(let u=a.length-1;u>=0;u--){let L=a[u].textContent&&a[u].textContent.trim();if(L&&!(U&&L.startsWith(U))&&(de=L.split(/[·•]/)[0].trim(),de))break}}let _e=null;if(v){let l=v.querySelectorAll("p, span, div");for(let a of l){let u=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(u==="1st"||u==="2nd"||u==="3rd"){_e=u;break}}}let Ct=!!x.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),$e=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),vt=$e&&$e.src||null,Q=x.textContent||"",De=null,Le=Q.match(/(\d+\+?)\s+connections\b/i);Le&&(De=Le[1]+" connections");let Z=null,Te=Q.match(/(\d+)\s+mutual connection/i),Re=Q.match(/and\s+(\d+)\s+other mutual/i),xt=Q.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Te?Z=parseInt(Te[1],10):Re?Z=2+parseInt(Re[1],10):xt&&(Z=2);let Me=null,Pe=null,Ne=C.find(l=>l.textContent&&l.textContent.trim()==="About");if(Ne){let l=Ne.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").trim();a=a.replace(/^About\s*/,"").trim();let u=a.match(/Top skills\s*(.+?)$/i);if(u){let fe=u[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(_t=>_t.trim()).filter(Boolean);fe.length>0&&fe.length<10&&(Pe=fe)}a=a.split(/\n?…\s*more/i)[0].trim(),a=a.split(/\n?\.\.\.\s*more/i)[0].trim(),a=a.split(/\bTop skills\b/i)[0].trim(),a=a.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),Me=a||null}}let Fe=null,je=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(je){let l=je.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&(Fe=parseInt(a[1].replace(/,/g,""),10))}}let Et=[...new Set(C.map(l=>(l.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(l=>l&&l.length>1&&l.length<60&&l!==U).filter(l=>h.has(l)))],V=document.body.textContent||"",It=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),At=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:U,title:Ee,location:de,currentCompany:Ie,currentSchool:Ae,connectionDegree:_e,hasVerifiedBadge:Ct,photoUrl:vt,connectionsLevel:De,mutualConnectionsCount:Z,followers:Fe,openToWork:It,hiring:At,about:Me,topSkills:Pe,availableSections:Et}});console.log(`Viewed: ${w.name} - ${w.title}`);let g=null,S=null,E=null,M=null,P=null,N=null;if(o||i||s||r||m||f){let h=await Promise.resolve().then(()=>(Ze(),Qe));o&&(g=await h.extractExperienceFromDetails(e,t),console.log(` + Experience: ${g.length} entries`)),i&&(S=await h.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${S.length} entries`)),s&&(E=await h.extractEducationFromDetails(e,t),console.log(` + Education: ${E.length} entries`)),r&&(M=await h.extractSkillsFromDetails(e,t),console.log(` + Skills: ${M.length} entries`)),m&&(P=await h.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${P.length} entries`)),f&&(N=await h.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${N.length} entries`))}return{...w,profileUrl:t,resolvedUrl:k,...g!==null&&{experience:g},...S!==null&&{featured:S},...E!==null&&{education:E},...M!==null&&{skillsFull:M},...P!==null&&{recommendations:P},...N!==null&&{certifications:N}}}catch($){console.error(`Error viewing profile ${t}:`,$.message);try{await e.goto("about:blank",{timeout:1e4}),await y(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test($.message||""))throw $;return null}}await be();import I from"fs";import T from"path";var Qt="cookies.json";function et(){let e=process.env.ILML_SCOPE_DIR;return e?T.join(e,"plugins-state","linkedin","cookies.json"):Qt}function tt(){let e=et();if(!I.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=I.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}function nt(){return I.existsSync(et())}function Zt(){let e=process.env.ILML_SCOPE_DIR;return e?T.join(e,"plugins-state","linkedin"):"."}function ot(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function Xt(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?ot(t[1]):"default"}function it(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return I.existsSync(t)||I.mkdirSync(t,{recursive:!0}),T.resolve(t);let n=ot(e||Xt()),o=T.join(Zt(),"chrome-profile",n);return I.existsSync(o)||I.mkdirSync(o,{recursive:!0}),T.resolve(o)}var rt=".ilml-seeded";function st(e){return!I.existsSync(T.join(e,rt))}function lt(e){try{I.writeFileSync(T.join(e,rt),new Date().toISOString())}catch{}}function at(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{I.rmSync(T.join(e,n),{force:!0}),t++}catch{}return t}import Se from"fs";import en from"path";var tn={headless:!1,defaultViewport:null,protocolTimeout:3e5},z=new Set,ct=!1;async function ee(){let e=[...z].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});z.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function nn(){if(ct)return;ct=!0;let e=t=>async()=>{await ee(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await ee(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await ee(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await ee(),process.exit(0))}),process.on("exit",()=>{for(let t of z)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function ke(e){return en.join(e,".ilml-browser-session.json")}function mt(e,t={}){try{Se.writeFileSync(ke(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function on(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();mt(e,n?{wsEndpoint:n}:{})}catch{}}function rn(e){let t=pt(e);t&&t.ownerPid===process.pid&&G(e)}function G(e){try{Se.rmSync(ke(e),{force:!0})}catch{}}function pt(e){try{return JSON.parse(Se.readFileSync(ke(e),"utf-8"))}catch{return null}}function ut(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function dt(e,t,n){let o,i=new Promise(r=>{o=setTimeout(()=>r(n),t)}),s=Promise.resolve(e).then(r=>(clearTimeout(o),r),r=>{throw clearTimeout(o),r});return Promise.race([s,i])}async function ft(e,t,{probeTimeoutMs:n=4e3}={}){let o=pt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&ut(o.ownerPid)?"live":(G(t),"free");let i=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await dt(s,n,i);if(r===i)return s.then(f=>{if(f)try{f.disconnect()}catch{}}),"live";if(!r)return G(t),"free";if(ut(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await dt(r.close().then(()=>!0).catch(()=>!1),n,!1))return G(t),"free";try{r.disconnect()}catch{}return"live"}function sn(e,t){e&&(nn(),z.add(e),e.on("disconnected",()=>{z.delete(e),t&&G(t)}))}async function ht(e,t={}){let n=it(),o={...tn,...t,userDataDir:n},i=`Could not open the LinkedIn automation Chrome profile at ${n}. Another LinkedIn automation command is already running (or its window is still open) \u2014 wait for it to finish or close that window, then retry.`;if(await ft(e,n)==="live")throw new Error(i);mt(n);let s;try{s=await e.launch(o)}catch{if(await ft(e,n)==="live")throw new Error(i);at(n);try{s=await e.launch(o)}catch(m){throw rn(n),new Error(`Could not open the LinkedIn automation Chrome profile at ${n}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${m.message})`)}}return sn(s,n),on(n,s),{browser:s,profileDir:n,needsSeed:st(n)}}async function wt(e,t){if(!t||!t.needsSeed)return!1;if(!nt())return console.warn(" \u26A0 No saved LinkedIn session found. If this command comes back empty or redirects to login, run: ilml linkedin login"),!1;try{return await e.setCookie(...tt()),lt(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function gt(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function yt(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),an=A.includes("--help")||A.includes("-h"),R=A.find(e=>e.startsWith("http")),B=A.includes("--full"),ne=B||A.includes("--with-experience"),oe=B||A.includes("--with-featured"),ie=B||A.includes("--with-education"),re=B||A.includes("--with-skills"),se=B||A.includes("--with-recommendations"),le=B||A.includes("--with-certifications"),bt=[["experience",ne],["featured",oe],["education",ie],["skills",re],["recommendations",se],["certifications",le]],St=bt.filter(([,e])=>e).length,ve=1+St;function kt(){console.log(`
239
239
  enrich-profile \u2014 visit ONE LinkedIn profile and save what we learn
240
240
 
241
241
  USAGE
@@ -286,4 +286,4 @@ WHEN TO USE
286
286
  - Audit your own LinkedIn profile (--full prints everything to stdout)
287
287
  - Deep-dive on one specific contact before reaching out
288
288
  - Verify what we know about a recruiter / lead
289
- `)}Wt&&(ut(),process.exit(0));N||(ut(),process.exit(1));/linkedin\.com\/in\//i.test(N)||(console.error(`URL doesn't look like a LinkedIn profile: ${N}`),console.error("Expected format: https://www.linkedin.com/in/<slug>/"),process.exit(1));var be=st(process.env.MY_LINKEDIN_URL||""),se=lt(process.env.LINKEDIN_NAME||"");!be&&!se&&(console.error(""),console.error(" \u26D4 Refusing to run: cannot self-detect without configuration."),console.error(""),console.error(" Set EITHER (preferably both) of:"),console.error(" MY_LINKEDIN_URL=https://www.linkedin.com/in/<your-slug>"),console.error(' LINKEDIN_NAME="Your Full Name"'),console.error(""),console.error(" in .env (dev) or via `ilml plugin config linkedin set <KEY> <VALUE>` (prod)."),console.error(" This prevents your own profile from accidentally landing in people.json."),console.error(""),process.exit(1));var re=be&&st(N)===be,ge=at.filter(([,e])=>e).map(([e])=>e);console.log("");console.log(` enrichProfile \u2014 ${N}`);B?console.log(` Mode: --full (${ye} page loads: main + ${ge.join(" + ")})`):ge.length>0?console.log(` Mode: rich (${ye} loads: main + ${ge.join(" + ")})`):console.log(" Mode: basic (1 load \u2014 main page only)");console.log(re?" Target: SELF (URL match) \u2014 will print to stdout, not saved to people.json":se?` Target: TBD \u2014 name-match against "${process.env.LINKEDIN_NAME}" after fetch`:" Target: will save to people.json (no MY_LINKEDIN_URL or LINKEDIN_NAME set for self-check)");ct>0&&(console.log(""),console.log(` \u26A0 ${ye} page loads on the SAME profile = normal "deep read" pattern.`),console.log(" This is intentionally single-URL \u2014 DO NOT batch. For batch enrichment"),console.log(" use `enrichProfiles.mjs --with-experience` (gated, capped)."));console.log("");var Z=null;try{let e=await it(Vt);Z=e.browser;let t=await Z.newPage();await rt(t,e);let n=await Ye(t,N,{extractExperience:X,extractFeatured:ee,extractEducation:te,extractSkills:ne,extractRecommendations:oe,extractCertifications:ie});if((!n||!n.name)&&(console.error(" viewProfile returned no name \u2014 profile not loaded or DOM changed"),process.exit(1)),!re&&se&&n.name&&lt(n.name)===se&&(re=!0,console.log(" \u2191 Detected self via LINKEDIN_NAME match \u2014 will NOT save to people.json")),console.log(""),console.log(" \u2500\u2500\u2500 extracted \u2500\u2500\u2500"),console.log(` name: ${n.name}`),console.log(` title: ${n.title||"(none)"}`),console.log(` location: ${n.location||"(none)"}`),console.log(` about: ${n.about?`${n.about.length} chars`:"(none)"}`),console.log(` topSkills: ${n.topSkills?n.topSkills.join(", "):"(none)"}`),X&&console.log(` experience: ${(n.experience||[]).length} entries`),ee&&console.log(` featured: ${(n.featured||[]).length} entries`),te&&console.log(` education: ${(n.education||[]).length} entries`),ne&&console.log(` skillsFull: ${(n.skillsFull||[]).length} entries`),oe&&console.log(` recommendations: ${(n.recommendations||[]).length} entries`),ie&&console.log(` certifications: ${(n.certifications||[]).length} entries`),console.log(""),re)console.log(" \u2500\u2500\u2500 full data (self \u2014 not persisted) \u2500\u2500\u2500"),console.log(JSON.stringify(n,null,2));else{let o={name:n.name,title:n.title,location:n.location,about:n.about,currentCompany:n.currentCompany,currentSchool:n.currentSchool,topSkills:n.topSkills,availableSections:n.availableSections,connectionsLevel:n.connectionsLevel,mutualConnectionsCount:n.mutualConnectionsCount,followers:n.followers,openToWork:n.openToWork,hiring:n.hiring,hasVerifiedBadge:n.hasVerifiedBadge,photoUrl:n.photoUrl,source:"enrich-profile-single"},i=[["experience",X,n.experience],["featured",ee,n.featured],["education",te,n.education],["skillsFull",ne,n.skillsFull],["recommendations",oe,n.recommendations],["certifications",ie,n.certifications]],s=!1;for(let[r,y,m]of i)y&&(Array.isArray(m)&&m.length>0?(o[r]=m,s=!0):console.log(` \u26A0 --with-${r==="skillsFull"?"skills":r} returned 0 entries \u2014 NOT writing ${r} (existing data preserved)`));s&&(o._lastEnrichedAt=new Date().toISOString()),pe(N,o),n.resolvedUrl&&he(N,n.resolvedUrl),console.log(" \u2713 Saved to people.json")}}catch(e){console.error(" Error:",e.message),process.exit(1)}finally{Z&&await Z.close().catch(()=>{})}
289
+ `)}an&&(kt(),process.exit(0));R||(kt(),process.exit(1));/linkedin\.com\/in\//i.test(R)||(console.error(`URL doesn't look like a LinkedIn profile: ${R}`),console.error("Expected format: https://www.linkedin.com/in/<slug>/"),process.exit(1));var xe=gt(process.env.MY_LINKEDIN_URL||""),ce=yt(process.env.LINKEDIN_NAME||"");!xe&&!ce&&(console.error(""),console.error(" \u26D4 Refusing to run: cannot self-detect without configuration."),console.error(""),console.error(" Set EITHER (preferably both) of:"),console.error(" MY_LINKEDIN_URL=https://www.linkedin.com/in/<your-slug>"),console.error(' LINKEDIN_NAME="Your Full Name"'),console.error(""),console.error(" in .env (dev) or via `ilml plugin config linkedin set <KEY> <VALUE>` (prod)."),console.error(" This prevents your own profile from accidentally landing in people.json."),console.error(""),process.exit(1));var ae=xe&&gt(R)===xe,Ce=bt.filter(([,e])=>e).map(([e])=>e);console.log("");console.log(` enrichProfile \u2014 ${R}`);B?console.log(` Mode: --full (${ve} page loads: main + ${Ce.join(" + ")})`):Ce.length>0?console.log(` Mode: rich (${ve} loads: main + ${Ce.join(" + ")})`):console.log(" Mode: basic (1 load \u2014 main page only)");console.log(ae?" Target: SELF (URL match) \u2014 will print to stdout, not saved to people.json":ce?` Target: TBD \u2014 name-match against "${process.env.LINKEDIN_NAME}" after fetch`:" Target: will save to people.json (no MY_LINKEDIN_URL or LINKEDIN_NAME set for self-check)");St>0&&(console.log(""),console.log(` \u26A0 ${ve} page loads on the SAME profile = normal "deep read" pattern.`),console.log(" This is intentionally single-URL \u2014 DO NOT batch. For batch enrichment"),console.log(" use `enrichProfiles.mjs --with-experience` (gated, capped)."));console.log("");var te=null;try{let e=await ht(ln);te=e.browser;let t=await te.newPage();await wt(t,e);let n=await Xe(t,R,{extractExperience:ne,extractFeatured:oe,extractEducation:ie,extractSkills:re,extractRecommendations:se,extractCertifications:le});if((!n||!n.name)&&(console.error(" viewProfile returned no name \u2014 profile not loaded or DOM changed"),process.exit(1)),!ae&&ce&&n.name&&yt(n.name)===ce&&(ae=!0,console.log(" \u2191 Detected self via LINKEDIN_NAME match \u2014 will NOT save to people.json")),console.log(""),console.log(" \u2500\u2500\u2500 extracted \u2500\u2500\u2500"),console.log(` name: ${n.name}`),console.log(` title: ${n.title||"(none)"}`),console.log(` location: ${n.location||"(none)"}`),console.log(` about: ${n.about?`${n.about.length} chars`:"(none)"}`),console.log(` topSkills: ${n.topSkills?n.topSkills.join(", "):"(none)"}`),ne&&console.log(` experience: ${(n.experience||[]).length} entries`),oe&&console.log(` featured: ${(n.featured||[]).length} entries`),ie&&console.log(` education: ${(n.education||[]).length} entries`),re&&console.log(` skillsFull: ${(n.skillsFull||[]).length} entries`),se&&console.log(` recommendations: ${(n.recommendations||[]).length} entries`),le&&console.log(` certifications: ${(n.certifications||[]).length} entries`),console.log(""),ae)console.log(" \u2500\u2500\u2500 full data (self \u2014 not persisted) \u2500\u2500\u2500"),console.log(JSON.stringify(n,null,2));else{let o={name:n.name,title:n.title,location:n.location,about:n.about,currentCompany:n.currentCompany,currentSchool:n.currentSchool,topSkills:n.topSkills,availableSections:n.availableSections,connectionsLevel:n.connectionsLevel,mutualConnectionsCount:n.mutualConnectionsCount,followers:n.followers,openToWork:n.openToWork,hiring:n.hiring,hasVerifiedBadge:n.hasVerifiedBadge,photoUrl:n.photoUrl,source:"enrich-profile-single"},i=[["experience",ne,n.experience],["featured",oe,n.featured],["education",ie,n.education],["skillsFull",re,n.skillsFull],["recommendations",se,n.recommendations],["certifications",le,n.certifications]],s=!1;for(let[r,m,f]of i)m&&(Array.isArray(f)&&f.length>0?(o[r]=f,s=!0):console.log(` \u26A0 --with-${r==="skillsFull"?"skills":r} returned 0 entries \u2014 NOT writing ${r} (existing data preserved)`));s&&(o._lastEnrichedAt=new Date().toISOString()),ge(R,o),n.resolvedUrl&&ye(R,n.resolvedUrl),console.log(" \u2713 Saved to people.json")}}catch(e){console.error(" Error:",e.message),process.exit(1)}finally{te&&await te.close().catch(()=>{})}