ilml-plugin-linkedin 1.20.11 → 1.20.12

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,10 +1,10 @@
1
- var Tt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{for(var n in t)Tt(e,n,{get:t[n],enumerable:!0})};import v from"fs";import A from"path";function he(){let e=process.env.ILML_SCOPE_DIR;return e?A.join(e,"plugins-state","linkedin","cookies.json"):Mt}function Ft(){let e=he(),t=A.dirname(e);return t&&t!=="."&&!v.existsSync(t)&&v.mkdirSync(t,{recursive:!0}),e}function Ue(e){let t=Ft();return v.writeFileSync(t,JSON.stringify(e)),t}function He(){let e=he();if(!v.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=v.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 Ve(){return v.existsSync(he())}function Ot(){let e=process.env.ILML_SCOPE_DIR;return e?A.join(e,"plugins-state","linkedin"):"."}function We(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function jt(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?We(t[1]):"default"}function Je(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),A.resolve(t);let n=We(e||jt()),o=A.join(Ot(),"chrome-profile",n);return v.existsSync(o)||v.mkdirSync(o,{recursive:!0}),A.resolve(o)}function Ye(e){return!v.existsSync(A.join(e,Ke))}function Ge(e){try{v.writeFileSync(A.join(e,Ke),new Date().toISOString())}catch{}}function ze(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{v.rmSync(A.join(e,n),{force:!0}),t++}catch{}return t}var Mt,Ke,ee=W(()=>{Mt="cookies.json";Ke=".ilml-seeded"});async function y(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function qt(e,t,{timeout:n=45e3,poll:o=1e3,label:i="page"}={}){let s=Date.now();for(;Date.now()-s<n;){try{if(await e.evaluate(d=>!!document.querySelector(d),t)){let d=Date.now()-s;return d>6e3&&console.log(` (waited ${Math.round(d/1e3)}s for LinkedIn to finish loading ${i})`),!0}}catch{}await new Promise(r=>setTimeout(r,o))}return!1}function Bt(e){return Qe.test(e||"")}async function Ut(e,{credentialWaitMs:t=36e4,label:n="page"}={}){console.log(` \u26A0 Auth wall on ${n} \u2014 attempting self-recovery (cookies may just need a refresh)...`);try{await e.goto("https://www.linkedin.com/feed/",{waitUntil:"domcontentloaded",timeout:6e4})}catch{}let o=!!(process.stdin&&process.stdin.isTTY),i=o?t:Math.min(t,45e3),s=Date.now(),r=!1;for(;Date.now()-s<i;){let m="wait";try{m=await e.evaluate(l=>!new RegExp(l).test(location.href)&&document.querySelector("#global-nav, nav.global-nav")?"in":document.querySelector('input#username, input[name="session_key"], input#password')?"creds":"wait",Qe.source)}catch{}if(m==="in"){try{let l=await e.cookies();if(Array.isArray(l)&&l.some(p=>p.name==="li_at")){let p=Ue(l);console.log(` \u2713 Session recovered \u2014 re-saved ${l.length} cookies (${p}).`)}else console.log(" \u2713 Session recovered (kept existing cookie snapshot \u2014 refreshed set had no li_at).")}catch(l){console.log(` \u2713 Session recovered (cookie re-save skipped: ${l.message}).`)}return!0}if(m==="creds"){if(!o){let l=new Error(`Session expired (${n}) \u2014 credentials required and no interactive terminal. Run: ilml linkedin login`);throw l.code="SESSION_EXPIRED",l}r||(r=!0,console.log(`
1
+ var Nt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Tt=(e,t)=>{for(var n in t)Nt(e,n,{get:t[n],enumerable:!0})};import E from"fs";import $ from"path";function he(){let e=process.env.ILML_SCOPE_DIR;return e?$.join(e,"plugins-state","linkedin","cookies.json"):Mt}function Ft(){let e=he(),t=$.dirname(e);return t&&t!=="."&&!E.existsSync(t)&&E.mkdirSync(t,{recursive:!0}),e}function Ue(e){let t=Ft();return E.writeFileSync(t,JSON.stringify(e)),t}function He(){let e=he();if(!E.existsSync(e))throw new Error(`Cookies not found at ${e}. Run: ilml linkedin login`);let t;try{t=E.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 Ve(){return E.existsSync(he())}function Ot(){let e=process.env.ILML_SCOPE_DIR;return e?$.join(e,"plugins-state","linkedin"):"."}function We(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function jt(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?We(t[1]):"default"}function Je(e){let t=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(t)return E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),$.resolve(t);let n=We(e||jt()),o=$.join(Ot(),"chrome-profile",n);return E.existsSync(o)||E.mkdirSync(o,{recursive:!0}),$.resolve(o)}function Ye(e){return!E.existsSync($.join(e,Ke))}function Ge(e){try{E.writeFileSync($.join(e,Ke),new Date().toISOString())}catch{}}function ze(e){let t=0;for(let n of["SingletonLock","SingletonCookie","SingletonSocket"])try{E.rmSync($.join(e,n),{force:!0}),t++}catch{}return t}var Mt,Ke,te=W(()=>{Mt="cookies.json";Ke=".ilml-seeded"});async function b(e){let t=Math.floor(Math.random()*2001),n=e+t;return new Promise(o=>setTimeout(o,n))}async function qt(e,t,{timeout:n=45e3,poll:o=1e3,label:i="page"}={}){let s=Date.now();for(;Date.now()-s<n;){try{if(await e.evaluate(u=>!!document.querySelector(u),t)){let u=Date.now()-s;return u>6e3&&console.log(` (waited ${Math.round(u/1e3)}s for LinkedIn to finish loading ${i})`),!0}}catch{}await new Promise(r=>setTimeout(r,o))}return!1}function Bt(e){return Xe.test(e||"")}async function Ut(e,{credentialWaitMs:t=36e4,label:n="page"}={}){console.log(` \u26A0 Auth wall on ${n} \u2014 attempting self-recovery (cookies may just need a refresh)...`);try{await e.goto("https://www.linkedin.com/feed/",{waitUntil:"domcontentloaded",timeout:6e4})}catch{}let o=!!(process.stdin&&process.stdin.isTTY),i=o?t:Math.min(t,45e3),s=Date.now(),r=!1;for(;Date.now()-s<i;){let m="wait";try{m=await e.evaluate(p=>!new RegExp(p).test(location.href)&&document.querySelector("#global-nav, nav.global-nav")?"in":document.querySelector('input#username, input[name="session_key"], input#password')?"creds":"wait",Xe.source)}catch{}if(m==="in"){try{let p=await e.cookies();if(Array.isArray(p)&&p.some(S=>S.name==="li_at")){let S=Ue(p);console.log(` \u2713 Session recovered \u2014 re-saved ${p.length} cookies (${S}).`)}else console.log(" \u2713 Session recovered (kept existing cookie snapshot \u2014 refreshed set had no li_at).")}catch(p){console.log(` \u2713 Session recovered (cookie re-save skipped: ${p.message}).`)}return!0}if(m==="creds"){if(!o){let p=new Error(`Session expired (${n}) \u2014 credentials required and no interactive terminal. Run: ilml linkedin login`);throw p.code="SESSION_EXPIRED",p}r||(r=!0,console.log(`
2
2
  \u26A0 LinkedIn is asking for your login + password (cookies not enough this time).`),console.log(" \u2192 Sign in MANUALLY in the browser window that is already open."),console.log(` I will wait and resume automatically \u2014 do NOT close the window or re-run the command.
3
- `))}await new Promise(l=>setTimeout(l,2500))}let d=new Error(`Session expired (${n}) \u2014 not signed in within the wait window. Run: ilml linkedin login`);throw d.code="SESSION_EXPIRED",d}async function te(e,{readySelector:t,label:n="page",timeout:o=45e3}={}){let i=await qt(e,t,{timeout:o,label:n});if(!i&&Bt(e.url())){let s=new Error(`Session expired (${n}) \u2014 redirected to login. Run: ilml linkedin login`);throw s.code="SESSION_EXPIRED",s}return i}async function Ze(e,t,{readySelector:n,label:o="page",timeout:i=45e3,gotoTimeout:s=6e4,autoRecover:r=!0}={}){await e.goto(t,{waitUntil:"domcontentloaded",timeout:s});try{return await te(e,{readySelector:n,label:o,timeout:i})}catch(d){if(r&&d.code==="SESSION_EXPIRED"){await Ut(e,{label:o});try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:s})}catch{}return await te(e,{readySelector:n,label:o,timeout:i})}throw d}}async function Xe(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"),d=i.includes("Get hired faster")||i.includes("Get hired 2x");if(s||r||d){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 l=o.querySelectorAll("button");for(let S of l){let p=S.innerText?.trim().toLowerCase()||"",g=S.getAttribute("aria-label")?.toLowerCase()||"";if(p==="not now"||p==="no thanks"||p==="dismiss"||g.includes("dismiss"))return S.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 Qe,we=W(()=>{ee();Qe=/\/authwall|\/login|\/checkpoint|\/uas\/login/});import{getPluginConfig as Ht}from"@ilivemylife/graph-sdk";var Vt,En,F,In,An,et=W(async()=>{Vt=await Ht();for(let[e,t]of Object.entries(Vt))process.env[e]===void 0&&(process.env[e]=t);En=process.env.LINKEDIN_NAME,F=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),In=Object.freeze(new Set([F.DRAFT,F.CONFIRMED,F.NEEDS_REVIEW])),An=Object.freeze(new Set([F.DRAFT,F.CONFIRMED,F.REJECTED,F.NEEDS_REVIEW]))});import"dotenv/config";import*as w from"fs";import*as b from"path";import{fileURLToPath as Wt}from"url";function rt(){w.existsSync(_)||w.mkdirSync(_,{recursive:!0})}function st(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";w.writeFileSync(o,n);for(let i=0;i<3;i++)try{w.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 lt(e,t){if(!w.existsSync(e))return null;try{let n=JSON.parse(w.readFileSync(e,"utf-8"));try{w.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(w.existsSync(o))try{let i=JSON.parse(w.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{w.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{w.copyFileSync(e,e+".corrupted")}catch{}return null}}function Yt(){return new Date().toISOString().split("T")[0]}function O(e){if(!e)return null;let t=e.match(/\/in\/([^/?#]+)/);return t?t[1].toLowerCase():null}function tt(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function at(e,t,n=null){if(!t||e[t])return t;let o=O(t);if(!o)return t;let i=null;for(let[s,r]of Object.entries(e)){if(O(r.profileUrl||s)===o)return s;!i&&Array.isArray(r.aliases)&&r.aliases.includes(o)&&(i=s)}if(i){let s=tt(n),r=tt(e[i].name);if(s&&r&&s===r)return i}return t}function Qt(){w.existsSync(ye)||w.mkdirSync(ye,{recursive:!0})}function ct(e){let t=O(e);return t?b.join(ye,`${t}.json`):null}function Zt(e){let t=ct(e);return t?lt(t,`profile-history/${O(e)}.json`)||[]:[]}function Xt(e,t){let n=ct(e);if(!n)return;Qt();let o=Zt(e);o.unshift(t);try{st(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${O(e)}: ${i.message}`)}}function nt(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function ot(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function en(e,t){if(!e)return[];let n=[];for(let o of zt){let i=e[o],s=t[o];nt(i)||nt(s)||ot(i)!==ot(s)&&n.push(o)}return n}function tn(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 be(){return J||(rt(),J=lt(ge,"people.json")||{},J)}function ut(e){rt(),J=e;try{st(ge,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${b.resolve(ge)}`)}}function Se(e,t={}){if(!e)return null;let n=be(),o=Yt(),i=new Date().toISOString(),s=at(n,e,t.name),r=n[s];if(r){let d=en(r,t);d.length>0&&(Xt(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:d,snapshot:tn(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 Gt)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 ut(n),n[s]}function ke(e,t,n={}){if(n.dryRun||!e||!t)return;let o=O(t);if(!o)return;let i=be(),s=at(i,e),r=i[s];if(!r)return;let d=O(r.profileUrl||s);o!==d&&(Array.isArray(r.aliases)||(r.aliases=[]),r.aliases.includes(o)||(r.aliases.push(o),r.lastUpdated=new Date().toISOString(),ut(i)))}var Jt,Kt,_,ge,Rn,Pn,Tn,Nn,Mn,ye,it,Fn,On,J,Gt,zt,ve=W(async()=>{await et();Jt=Wt(import.meta.url),Kt=b.dirname(b.dirname(Jt)),_=process.env.DATA_DIR?b.resolve(process.env.DATA_DIR,"collected-profiles"):b.join(Kt,"collected-profiles"),ge=b.join(_,"people.json"),Rn=b.join(_,"jobs.json"),Pn=b.join(_,"quota.json"),Tn=b.join(_,"conversations.json"),Nn=b.join(_,"sync-state.json"),Mn=b.join(_,"application-questions.json"),ye=b.join(_,"profile-history"),it=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},Fn=it(process.env.CONNECT_MAX_DAILY,20),On=it(process.env.CONNECT_MAX_WEEKLY,100),J=null;Gt=["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"],zt=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var dt={};Nt(dt,{extractCertificationsFromDetails:()=>ln,extractEducationFromDetails:()=>rn,extractExperienceFromDetails:()=>nn,extractFeaturedFromDetails:()=>on,extractRecommendationsFromDetails:()=>an,extractSkillsFromDetails:()=>sn});async function nn(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await e.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await te(e,{readySelector:"main .pvs-list, .scaffold-layout__main, main.scaffold-layout__main, section.artdeco-card",label:"experience details"}),await y(1e3);for(let i=0;i<5;i++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(900);await y(1e3);let o=0;for(;o<5&&await e.evaluate(()=>{for(let s of document.querySelectorAll("button"))if(/^Load more$/i.test((s.textContent||"").trim()))return s.click(),!0;return!1});)o++,await y(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(700);return await e.evaluate(()=>{let i=document.querySelector("main");if(!i)return[];function s(l){let S=[];for(let p of l.querySelectorAll("div")){let g=Array.from(p.children).filter(C=>C.tagName==="DIV");if(g.length<3)continue;let k=g.filter(C=>(C.textContent||"").trim().length>50);k.length<3||(p.textContent||"").length<500||S.push({el:p,count:k.length,totalText:(p.textContent||"").length})}return S.sort((p,g)=>g.count-p.count||p.totalText-g.totalText),S[0]?.el}let r=s(i);if(!r)return[];let d=Array.from(r.children).filter(l=>l.tagName==="DIV").filter(l=>(l.textContent||"").trim().length>50);function m(l){let S=l[0]||null,p=null,g=null;if(l[1]){let c=l[1].split("\xB7").map(x=>x.trim());p=c[0]||null,c[1]&&(g=c[1])}let k=l.findIndex(c=>/(\d{4}|present)/i.test(c)&&/(-|–|—)/i.test(c)&&c.length<80),C=null,R=null;if(k>=0){let c=l[k].split("\xB7").map(x=>x.trim());C=c[0]||null,c[1]&&(R=c[1])}let P=null,T=-1;if(k>=0&&l[k+1]){let c=l[k+1],x=/^[>*\-•]|^&gt;/.test(c),H=/https?:\/\//.test(c),q=/\d{4}/.test(c),B=/,/.test(c)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(c);!x&&!H&&!q&&c.length<100&&B&&(P=c,T=k+1)}let N=null,fe=-1,h=l[l.length-1];if(h&&/and\s+\+\d+\s+skills?$/i.test(h)){fe=l.length-1;let c=h.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);c&&(N={listed:c[1].split(",").map(x=>x.trim()),additional:parseInt(c[2],10)})}let U=new Set([0,1,k,T,fe].filter(c=>c>=0)),$=l.filter((c,x)=>!U.has(x)),M=$.length>0?$.join(`
3
+ `))}await new Promise(p=>setTimeout(p,2500))}let u=new Error(`Session expired (${n}) \u2014 not signed in within the wait window. Run: ilml linkedin login`);throw u.code="SESSION_EXPIRED",u}async function Qe(e,{readySelector:t,label:n="page",timeout:o=45e3}={}){let i=await qt(e,t,{timeout:o,label:n});if(!i&&Bt(e.url())){let s=new Error(`Session expired (${n}) \u2014 redirected to login. Run: ilml linkedin login`);throw s.code="SESSION_EXPIRED",s}return i}async function J(e,t,{readySelector:n,label:o="page",timeout:i=45e3,gotoTimeout:s=6e4,autoRecover:r=!0}={}){await e.goto(t,{waitUntil:"domcontentloaded",timeout:s});try{return await Qe(e,{readySelector:n,label:o,timeout:i})}catch(u){if(r&&u.code==="SESSION_EXPIRED"){await Ut(e,{label:o});try{await e.goto(t,{waitUntil:"domcontentloaded",timeout:s})}catch{}return await Qe(e,{readySelector:n,label:o,timeout:i})}throw u}}async function Ze(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"),u=i.includes("Get hired faster")||i.includes("Get hired 2x");if(s||r||u){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 p=o.querySelectorAll("button");for(let c of p){let S=c.innerText?.trim().toLowerCase()||"",g=c.getAttribute("aria-label")?.toLowerCase()||"";if(S==="not now"||S==="no thanks"||S==="dismiss"||g.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 Xe,we=W(()=>{te();Xe=/\/authwall|\/login|\/checkpoint|\/uas\/login/});import{getPluginConfig as Ht}from"@ilivemylife/graph-sdk";var Vt,En,j,In,_n,et=W(async()=>{Vt=await Ht();for(let[e,t]of Object.entries(Vt))process.env[e]===void 0&&(process.env[e]=t);En=process.env.LINKEDIN_NAME,j=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),In=Object.freeze(new Set([j.DRAFT,j.CONFIRMED,j.NEEDS_REVIEW])),_n=Object.freeze(new Set([j.DRAFT,j.CONFIRMED,j.REJECTED,j.NEEDS_REVIEW]))});import"dotenv/config";import*as h from"fs";import*as k from"path";import{fileURLToPath as Wt}from"url";function rt(){h.existsSync(D)||h.mkdirSync(D,{recursive:!0})}function st(e,t){let n=JSON.stringify(t,null,2),o=e+".tmp";h.writeFileSync(o,n);for(let i=0;i<3;i++)try{h.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 lt(e,t){if(!h.existsSync(e))return null;try{let n=JSON.parse(h.readFileSync(e,"utf-8"));try{h.copyFileSync(e,e+".backup")}catch{}return n}catch(n){console.error(`[!] ${t} is corrupted: ${n.message}`),console.error(` File: ${k.resolve(e)}`);let o=e+".backup";if(h.existsSync(o))try{let i=JSON.parse(h.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{h.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{h.copyFileSync(e,e+".corrupted")}catch{}return null}}function Yt(){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 tt(e){return typeof e=="string"?e.replace(/\s+/g," ").trim().toLowerCase():""}function at(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=tt(n),r=tt(e[i].name);if(s&&r&&s===r)return i}return t}function Qt(){h.existsSync(ye)||h.mkdirSync(ye,{recursive:!0})}function ct(e){let t=q(e);return t?k.join(ye,`${t}.json`):null}function Xt(e){let t=ct(e);return t?lt(t,`profile-history/${q(e)}.json`)||[]:[]}function Zt(e,t){let n=ct(e);if(!n)return;Qt();let o=Xt(e);o.unshift(t);try{st(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${q(e)}: ${i.message}`)}}function nt(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function ot(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function en(e,t){if(!e)return[];let n=[];for(let o of zt){let i=e[o],s=t[o];nt(i)||nt(s)||ot(i)!==ot(s)&&n.push(o)}return n}function tn(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 be(){return K||(rt(),K=lt(ge,"people.json")||{},K)}function ut(e){rt(),K=e;try{st(ge,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${k.resolve(ge)}`)}}function Se(e,t={}){if(!e)return null;let n=be(),o=Yt(),i=new Date().toISOString(),s=at(n,e,t.name),r=n[s];if(r){let u=en(r,t);u.length>0&&(Zt(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:u,snapshot:tn(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 Gt)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 ut(n),n[s]}function ke(e,t,n={}){if(n.dryRun||!e||!t)return;let o=q(t);if(!o)return;let i=be(),s=at(i,e),r=i[s];if(!r)return;let u=q(r.profileUrl||s);o!==u&&(Array.isArray(r.aliases)||(r.aliases=[]),r.aliases.includes(o)||(r.aliases.push(o),r.lastUpdated=new Date().toISOString(),ut(i)))}var Jt,Kt,D,ge,Rn,Pn,Nn,Tn,Mn,ye,it,Fn,On,K,Gt,zt,ve=W(async()=>{await et();Jt=Wt(import.meta.url),Kt=k.dirname(k.dirname(Jt)),D=process.env.DATA_DIR?k.resolve(process.env.DATA_DIR,"collected-profiles"):k.join(Kt,"collected-profiles"),ge=k.join(D,"people.json"),Rn=k.join(D,"jobs.json"),Pn=k.join(D,"quota.json"),Nn=k.join(D,"conversations.json"),Tn=k.join(D,"sync-state.json"),Mn=k.join(D,"application-questions.json"),ye=k.join(D,"profile-history"),it=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},Fn=it(process.env.CONNECT_MAX_DAILY,20),On=it(process.env.CONNECT_MAX_WEEKLY,100),K=null;Gt=["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"],zt=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"]});var dt={};Tt(dt,{extractCertificationsFromDetails:()=>ln,extractEducationFromDetails:()=>rn,extractExperienceFromDetails:()=>nn,extractFeaturedFromDetails:()=>on,extractRecommendationsFromDetails:()=>an,extractSkillsFromDetails:()=>sn});async function nn(e,t){let n=t.replace(/\/+$/,"")+"/details/experience/";try{await J(e,n,{readySelector:"main .pvs-list, .scaffold-layout__main, main.scaffold-layout__main, section.artdeco-card",label:"experience details"}),await b(1e3);let o=e.url();if(!o.toLowerCase().includes("/details/experience/"))throw new Error(`Section /details/experience/ not available on profile (landed on ${o})`);for(let s=0;s<5;s++)await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await b(900);await b(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 b(1500),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await b(700);return await e.evaluate(()=>{let s=document.querySelector("main");if(!s)return[];function r(c){let S=[];for(let g of c.querySelectorAll("div")){let y=Array.from(g.children).filter(_=>_.tagName==="DIV");if(y.length<3)continue;let v=y.filter(_=>(_.textContent||"").trim().length>50);v.length<3||(g.textContent||"").length<500||S.push({el:g,count:v.length,totalText:(g.textContent||"").length})}return S.sort((g,y)=>y.count-g.count||g.totalText-y.totalText),S[0]?.el}let u=r(s);if(!u)return[];let m=Array.from(u.children).filter(c=>c.tagName==="DIV").filter(c=>(c.textContent||"").trim().length>50);function p(c){let S=c[0]||null,g=null,y=null;if(c[1]){let f=c[1].split("\xB7").map(C=>C.trim());g=f[0]||null,f[1]&&(y=f[1])}let v=c.findIndex(f=>/(\d{4}|present)/i.test(f)&&/(-|–|—)/i.test(f)&&f.length<80),_=null,N=null;if(v>=0){let f=c[v].split("\xB7").map(C=>C.trim());_=f[0]||null,f[1]&&(N=f[1])}let T=null,M=-1;if(v>=0&&c[v+1]){let f=c[v+1],C=/^[>*\-•]|^&gt;/.test(f),U=/https?:\/\//.test(f),H=/\d{4}/.test(f),x=/,/.test(f)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(f);!C&&!U&&!H&&f.length<100&&x&&(T=f,M=v+1)}let fe=null,w=-1,F=c[c.length-1];if(F&&/and\s+\+\d+\s+skills?$/i.test(F)){w=c.length-1;let f=F.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);f&&(fe={listed:f[1].split(",").map(C=>C.trim()),additional:parseInt(f[2],10)})}let O=new Set([0,1,v,M,w].filter(f=>f>=0)),L=c.filter((f,C)=>!O.has(C)),I=L.length>0?L.join(`
4
4
 
5
- `):null;return{title:S,company:p,employmentType:g,dates:C,duration:R,location:P,description:M,skills:N,_raw:l}}return d.map(l=>{let p=(l.innerText||"").trim().split(`
6
- `).map(g=>g.trim()).filter(g=>g&&g.length<5e3);return m(p)}).filter(l=>l.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 K(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 d of document.querySelectorAll("button"))if(/^Load more$/i.test((d.textContent||"").trim()))return d.click(),!0;return!1});)s++,await y(1300),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await y(600)}async function G(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 on(e,t){return G(t,"featured","extractFeaturedFromDetails",async()=>(await K(e,t,"featured"),await e.evaluate(`(() => {
7
- ${Y}
5
+ `):null;return{title:S,company:g,employmentType:y,dates:_,duration:N,location:T,description:I,skills:fe,_raw:c}}return m.map(c=>{let g=(c.innerText||"").trim().split(`
6
+ `).map(y=>y.trim()).filter(y=>y&&y.length<5e3);return p(g)}).filter(c=>c.title)})}catch(o){if(o.code==="SESSION_EXPIRED"||/^session expired/i.test(o.message||""))throw o;return console.error(`extractExperienceFromDetails failed for ${t}: ${o.message?.slice(0,120)}`),[]}}async function Y(e,t,n){let o=t.replace(/\/+$/,"")+`/details/${n}/`;await J(e,o,{readySelector:"main .pvs-list, .scaffold-layout__main, main.scaffold-layout__main, section.artdeco-card",label:`details/${n}`}),await b(1e3);let i=e.url();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 b(700);await b(800);let s=0;for(;s<5&&await e.evaluate(()=>{for(let u of document.querySelectorAll("button"))if(/^Load more$/i.test((u.textContent||"").trim()))return u.click(),!0;return!1});)s++,await b(1300),await e.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await b(600)}async function z(e,t,n,o){try{return await o()}catch(i){let s=i.message||"";if(i.code==="SESSION_EXPIRED"||/^session expired/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 on(e,t){return z(t,"featured","extractFeaturedFromDetails",async()=>(await Y(e,t,"featured"),await e.evaluate(`(() => {
7
+ ${G}
8
8
 
9
9
  const main = document.querySelector('main');
10
10
  if (!main) return [];
@@ -44,8 +44,8 @@ var Tt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{f
44
44
  if (e.caption && /^\xB7\\s*\\d+(?:st|nd|rd|th)\\+?$/i.test(e.caption.trim())) return false;
45
45
  return true;
46
46
  });
47
- })()`)))}async function rn(e,t){return G(t,"education","extractEducationFromDetails",async()=>(await K(e,t,"education"),await e.evaluate(`(() => {
48
- ${Y}
47
+ })()`)))}async function rn(e,t){return z(t,"education","extractEducationFromDetails",async()=>(await Y(e,t,"education"),await e.evaluate(`(() => {
48
+ ${G}
49
49
 
50
50
  const main = document.querySelector('main');
51
51
  if (!main) return [];
@@ -81,8 +81,8 @@ var Tt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{f
81
81
  if (e.degree && /^\xB7\\s*\\d+(?:st|nd|rd|th)\\+?$/i.test(e.degree.trim())) return false;
82
82
  return true;
83
83
  });
84
- })()`)))}async function sn(e,t){return G(t,"skills","extractSkillsFromDetails",async()=>(await K(e,t,"skills"),await e.evaluate(`(() => {
85
- ${Y}
84
+ })()`)))}async function sn(e,t){return z(t,"skills","extractSkillsFromDetails",async()=>(await Y(e,t,"skills"),await e.evaluate(`(() => {
85
+ ${G}
86
86
 
87
87
  const main = document.querySelector('main');
88
88
  if (!main) return [];
@@ -113,8 +113,8 @@ var Tt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{f
113
113
  skills.push({ name, endorsements, _raw: lines });
114
114
  }
115
115
  return skills;
116
- })()`)))}async function ln(e,t){return G(t,"certifications","extractCertificationsFromDetails",async()=>(await K(e,t,"certifications"),await e.evaluate(`(() => {
117
- ${Y}
116
+ })()`)))}async function ln(e,t){return z(t,"certifications","extractCertificationsFromDetails",async()=>(await Y(e,t,"certifications"),await e.evaluate(`(() => {
117
+ ${G}
118
118
 
119
119
  const main = document.querySelector('main');
120
120
  if (!main) return [];
@@ -138,8 +138,8 @@ var Tt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{f
138
138
 
139
139
  return { name, issuer, issueDate, expiryDate, credentialId, _raw: lines };
140
140
  }).filter(e => e.name);
141
- })()`)))}async function an(e,t){return G(t,"recommendations","extractRecommendationsFromDetails",async()=>(await K(e,t,"recommendations"),await e.evaluate(`(() => {
142
- ${Y}
141
+ })()`)))}async function an(e,t){return z(t,"recommendations","extractRecommendationsFromDetails",async()=>(await Y(e,t,"recommendations"),await e.evaluate(`(() => {
142
+ ${G}
143
143
 
144
144
  const main = document.querySelector('main');
145
145
  if (!main) return [];
@@ -174,7 +174,7 @@ var Tt=Object.defineProperty;var W=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{f
174
174
  if (e.recommenderTitle && /^\xB7\\s*\\d+(?:st|nd|rd|th)\\+?$/i.test(e.recommenderTitle.trim())) return false;
175
175
  return true;
176
176
  });
177
- })()`)))}var Y,ft=W(()=>{we();Y=`
177
+ })()`)))}var G,ft=W(()=>{we();G=`
178
178
  function findEntryContainer(root) {
179
179
  const candidates = [];
180
180
  for (const div of root.querySelectorAll('div')) {
@@ -237,7 +237,7 @@ function findEntryContainer(root) {
237
237
  candidates.sort((a, b) => b.count - a.count || b.totalText - a.totalText);
238
238
  return candidates[0]?.el;
239
239
  }
240
- `});import"dotenv/config";import wn from"puppeteer";we();await ve();async function cn(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 mt(e,t,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:s=!1,extractSkills:r=!1,extractRecommendations:d=!1,extractCertifications:m=!1}=n;try{await Ze(e,t,{readySelector:".scaffold-layout__main, main.scaffold-layout__main, .pv-top-card, section.pv-top-card",label:"profile"}),await y(1500),await Xe(e)&&(console.log(" Dismissed Premium overlay"),await y(1500),await cn(e,t));let S=0;for(let h=0;h<2;h++){let U=await e.evaluate(()=>document.body.scrollHeight);for(let M=1;M<=6;M++)await e.evaluate(c=>window.scrollTo(0,c),U*M/6),await y(900);let $=await e.evaluate(()=>document.body.scrollHeight);if($===S)break;S=$}await y(800);let p=null;try{let h=e.url();h&&/\/in\/[^/?#]/.test(h)&&(p=h.split("?")[0].replace(/\/+$/,""))}catch{}let g=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"]),U=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"]),$=a=>{let u=(a||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(u)},M={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:[]},c=document.querySelector("main");if(!c)return M;let x=[...Array.from(c.querySelectorAll("h1")),...Array.from(c.querySelectorAll("h2"))],H=Array.from(c.querySelectorAll("h2")),q=x.find(a=>{let u=a.textContent&&a.textContent.trim(),f=(u||"").replace(/\s*\(\d+\)$/,"").trim();return u&&u.length>1&&u.length<100&&!h.has(f)&&!U.has(f)}),B=q?q.textContent.trim():null,E=q?q.parentElement:null;for(;E&&E!==c&&!Array.from(E.children).filter(u=>u.tagName==="P").some(u=>{let f=u.textContent&&u.textContent.trim();return f&&f.length>5&&!$(f)});)E=E.parentElement;let _e=null,$e=null,De=null,me=null;if(E&&E!==c){let a=Array.from(E.children).filter(f=>f.tagName==="P").filter(f=>{let D=f.textContent&&f.textContent.trim();return D&&D.length>5&&!$(D)});if(a[0]&&(_e=a[0].textContent.trim()),a[1]){let f=a[1].textContent.trim().split(/\s*[·•]\s*/);$e=f[0]||null,f.length>1&&(De=f.slice(1).join(" \xB7 "))}let u=Array.from(E.children).filter(f=>f.tagName==="DIV");for(let f=u.length-1;f>=0;f--){let D=u[f].textContent&&u[f].textContent.trim();if(D&&!(B&&D.startsWith(B))&&(me=D.split(/[·•]/)[0].trim(),me))break}}let Le=null;if(E){let a=E.querySelectorAll("p, span, div");for(let u of a){let f=(u.textContent||"").trim().replace(/^[·•]\s*/,"");if(f==="1st"||f==="2nd"||f==="3rd"){Le=f;break}}}let At=!!c.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),Re=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),_t=Re&&Re.src||null,Z=c.textContent||"",Pe=null,Te=Z.match(/(\d+\+?)\s+connections\b/i);Te&&(Pe=Te[1]+" connections");let X=null,Ne=Z.match(/(\d+)\s+mutual connection/i),Me=Z.match(/and\s+(\d+)\s+other mutual/i),$t=Z.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Ne?X=parseInt(Ne[1],10):Me?X=2+parseInt(Me[1],10):$t&&(X=2);let Fe=null,Oe=null,je=H.find(a=>a.textContent&&a.textContent.trim()==="About");if(je){let a=je.parentElement;for(;a&&a.tagName!=="SECTION";)a=a.parentElement;if(a){let u=(a.textContent||"").trim();u=u.replace(/^About\s*/,"").trim();let f=u.match(/Top skills\s*(.+?)$/i);if(f){let pe=f[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(Pt=>Pt.trim()).filter(Boolean);pe.length>0&&pe.length<10&&(Oe=pe)}u=u.split(/\n?…\s*more/i)[0].trim(),u=u.split(/\n?\.\.\.\s*more/i)[0].trim(),u=u.split(/\bTop skills\b/i)[0].trim(),u=u.split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim(),Fe=u||null}}let qe=null,Be=H.find(a=>a.textContent&&a.textContent.trim()==="Activity");if(Be){let a=Be.parentElement;for(;a&&a.tagName!=="SECTION";)a=a.parentElement;if(a){let u=(a.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);u&&(qe=parseInt(u[1].replace(/,/g,""),10))}}let Dt=[...new Set(H.map(a=>(a.textContent||"").trim().replace(/\s*\(\d+\)$/,"").trim()).filter(a=>a&&a.length>1&&a.length<60&&a!==B).filter(a=>h.has(a)))],V=document.body.textContent||"",Lt=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),Rt=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:B,title:_e,location:me,currentCompany:$e,currentSchool:De,connectionDegree:Le,hasVerifiedBadge:At,photoUrl:_t,connectionsLevel:Pe,mutualConnectionsCount:X,followers:qe,openToWork:Lt,hiring:Rt,about:Fe,topSkills:Oe,availableSections:Dt}});console.log(`Viewed: ${g.name} - ${g.title}`);let k=null,C=null,R=null,P=null,T=null,N=null;if(o||i||s||r||d||m){let h=await Promise.resolve().then(()=>(ft(),dt));o&&(k=await h.extractExperienceFromDetails(e,t),console.log(` + Experience: ${k.length} entries`)),i&&(C=await h.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${C.length} entries`)),s&&(R=await h.extractEducationFromDetails(e,t),console.log(` + Education: ${R.length} entries`)),r&&(P=await h.extractSkillsFromDetails(e,t),console.log(` + Skills: ${P.length} entries`)),d&&(T=await h.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${T.length} entries`)),m&&(N=await h.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${N.length} entries`))}return{...g,profileUrl:t,resolvedUrl:p,...k!==null&&{experience:k},...C!==null&&{featured:C},...R!==null&&{education:R},...P!==null&&{skillsFull:P},...T!==null&&{recommendations:T},...N!==null&&{certifications:N}}}catch(l){console.error(`Error viewing profile ${t}:`,l.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(l.message||""))throw l;return null}}await ve();ee();ee();import Ce from"fs";import un from"path";var dn={headless:!1,defaultViewport:null,protocolTimeout:3e5},Q=new Set,pt=!1;async function ne(){let e=[...Q].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});Q.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function fn(){if(pt)return;pt=!0;let e=t=>async()=>{await ne(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await ne(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await ne(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await ne(),process.exit(0))}),process.on("exit",()=>{for(let t of Q)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function xe(e){return un.join(e,".ilml-browser-session.json")}function yt(e,t={}){try{Ce.writeFileSync(xe(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function mn(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();yt(e,n?{wsEndpoint:n}:{})}catch{}}function pn(e){let t=bt(e);t&&t.ownerPid===process.pid&&z(e)}function z(e){try{Ce.rmSync(xe(e),{force:!0})}catch{}}function bt(e){try{return JSON.parse(Ce.readFileSync(xe(e),"utf-8"))}catch{return null}}function ht(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function wt(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 gt(e,t,{probeTimeoutMs:n=4e3}={}){let o=bt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&ht(o.ownerPid)?"live":(z(t),"free");let i=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await wt(s,n,i);if(r===i)return s.then(m=>{if(m)try{m.disconnect()}catch{}}),"live";if(!r)return z(t),"free";if(ht(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await wt(r.close().then(()=>!0).catch(()=>!1),n,!1))return z(t),"free";try{r.disconnect()}catch{}return"live"}function hn(e,t){e&&(fn(),Q.add(e),e.on("disconnected",()=>{Q.delete(e),t&&z(t)}))}async function St(e,t={}){let n=Je(),o={...dn,...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 gt(e,n)==="live")throw new Error(i);yt(n);let s;try{s=await e.launch(o)}catch{if(await gt(e,n)==="live")throw new Error(i);ze(n);try{s=await e.launch(o)}catch(d){throw pn(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: ${d.message})`)}}return hn(s,n),mn(n,s),{browser:s,profileDir:n,needsSeed:Ye(n)}}async function kt(e,t){if(!t||!t.needsSeed)return!1;if(!Ve())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(...He()),Ge(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function vt(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function Ct(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var I=process.argv.slice(2),gn=I.includes("--help")||I.includes("-h"),L=I.find(e=>e.startsWith("http")),j=I.includes("--full"),ie=j||I.includes("--with-experience"),re=j||I.includes("--with-featured"),se=j||I.includes("--with-education"),le=j||I.includes("--with-skills"),ae=j||I.includes("--with-recommendations"),ce=j||I.includes("--with-certifications"),xt=[["experience",ie],["featured",re],["education",se],["skills",le],["recommendations",ae],["certifications",ce]],Et=xt.filter(([,e])=>e).length,Ie=1+Et;function It(){console.log(`
240
+ `});import"dotenv/config";import wn from"puppeteer";we();await ve();async function cn(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 b(3e3);let o=e.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function mt(e,t,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:s=!1,extractSkills:r=!1,extractRecommendations:u=!1,extractCertifications:m=!1}=n;try{await J(e,t,{readySelector:".scaffold-layout__main, main.scaffold-layout__main, .pv-top-card, section.pv-top-card",label:"profile"}),await b(1500),await Ze(e)&&(console.log(" Dismissed Premium overlay"),await b(1500),await cn(e,t));let c=0;for(let w=0;w<2;w++){let F=await e.evaluate(()=>document.body.scrollHeight);for(let L=1;L<=6;L++)await e.evaluate(I=>window.scrollTo(0,I),F*L/6),await b(900);let O=await e.evaluate(()=>document.body.scrollHeight);if(O===c)break;c=O}await b(800);let S=null;try{let w=e.url();w&&/\/in\/[^/?#]/.test(w)&&(S=w.split("?")[0].replace(/\/+$/,""))}catch{}let g=await e.evaluate(()=>{let w=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"]),O=l=>{let a=(l||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(a)},L={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:[]},I=document.querySelector("main");if(!I)return L;let f=[...Array.from(I.querySelectorAll("h1")),...Array.from(I.querySelectorAll("h2"))],C=Array.from(I.querySelectorAll("h2")),U=f.find(l=>{let a=l.textContent&&l.textContent.trim(),d=(a||"").replace(/\s*\(\d+\)$/,"").trim();return a&&a.length>1&&a.length<100&&!w.has(d)&&!F.has(d)}),H=U?U.textContent.trim():null,x=U?U.parentElement:null;for(;x&&x!==I&&!Array.from(x.children).filter(a=>a.tagName==="P").some(a=>{let d=a.textContent&&a.textContent.trim();return d&&d.length>5&&!O(d)});)x=x.parentElement;let Ae=null,$e=null,De=null,me=null;if(x&&x!==I){let l=Array.from(x.children).filter(d=>d.tagName==="P").filter(d=>{let R=d.textContent&&d.textContent.trim();return R&&R.length>5&&!O(R)});if(l[0]&&(Ae=l[0].textContent.trim()),l[1]){let d=l[1].textContent.trim().split(/\s*[·•]\s*/);$e=d[0]||null,d.length>1&&(De=d.slice(1).join(" \xB7 "))}let a=Array.from(x.children).filter(d=>d.tagName==="DIV");for(let d=a.length-1;d>=0;d--){let R=a[d].textContent&&a[d].textContent.trim();if(R&&!(H&&R.startsWith(H))&&(me=R.split(/[·•]/)[0].trim(),me))break}}let Le=null;if(x){let l=x.querySelectorAll("p, span, div");for(let a of l){let d=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(d==="1st"||d==="2nd"||d==="3rd"){Le=d;break}}}let _t=!!I.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),Re=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),At=Re&&Re.src||null,Z=I.textContent||"",Pe=null,Ne=Z.match(/(\d+\+?)\s+connections\b/i);Ne&&(Pe=Ne[1]+" connections");let ee=null,Te=Z.match(/(\d+)\s+mutual connection/i),Me=Z.match(/and\s+(\d+)\s+other mutual/i),$t=Z.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Te?ee=parseInt(Te[1],10):Me?ee=2+parseInt(Me[1],10):$t&&(ee=2);let Fe=null,Oe=null,je=C.find(l=>l.textContent&&l.textContent.trim()==="About");if(je){let l=je.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").trim();a=a.replace(/^About\s*/,"").trim();let d=a.match(/Top skills\s*(.+?)$/i);if(d){let pe=d[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(Pt=>Pt.trim()).filter(Boolean);pe.length>0&&pe.length<10&&(Oe=pe)}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(),Fe=a||null}}let qe=null,Be=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(Be){let l=Be.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&(qe=parseInt(a[1].replace(/,/g,""),10))}}let Dt=[...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=>w.has(l)))],V=document.body.textContent||"",Lt=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),Rt=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:H,title:Ae,location:me,currentCompany:$e,currentSchool:De,connectionDegree:Le,hasVerifiedBadge:_t,photoUrl:At,connectionsLevel:Pe,mutualConnectionsCount:ee,followers:qe,openToWork:Lt,hiring:Rt,about:Fe,topSkills:Oe,availableSections:Dt}});console.log(`Viewed: ${g.name} - ${g.title}`);let y=null,v=null,_=null,N=null,T=null,M=null;if(o||i||s||r||u||m){let w=await Promise.resolve().then(()=>(ft(),dt));o&&(y=await w.extractExperienceFromDetails(e,t),console.log(` + Experience: ${y.length} entries`)),i&&(v=await w.extractFeaturedFromDetails(e,t),console.log(` + Featured: ${v.length} entries`)),s&&(_=await w.extractEducationFromDetails(e,t),console.log(` + Education: ${_.length} entries`)),r&&(N=await w.extractSkillsFromDetails(e,t),console.log(` + Skills: ${N.length} entries`)),u&&(T=await w.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${T.length} entries`)),m&&(M=await w.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${M.length} entries`))}return{...g,profileUrl:t,resolvedUrl:S,...y!==null&&{experience:y},...v!==null&&{featured:v},..._!==null&&{education:_},...N!==null&&{skillsFull:N},...T!==null&&{recommendations:T},...M!==null&&{certifications:M}}}catch(p){console.error(`Error viewing profile ${t}:`,p.message);try{await e.goto("about:blank",{timeout:1e4}),await b(1e3)}catch{}if(/session expired|bounced to|authwall|checkpoint|redirected to login/i.test(p.message||""))throw p;return null}}await ve();te();te();import Ce from"fs";import un from"path";var dn={headless:!1,defaultViewport:null,protocolTimeout:3e5},X=new Set,pt=!1;async function ne(){let e=[...X].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});X.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function fn(){if(pt)return;pt=!0;let e=t=>async()=>{await ne(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await ne(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await ne(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await ne(),process.exit(0))}),process.on("exit",()=>{for(let t of X)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function xe(e){return un.join(e,".ilml-browser-session.json")}function yt(e,t={}){try{Ce.writeFileSync(xe(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function mn(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();yt(e,n?{wsEndpoint:n}:{})}catch{}}function pn(e){let t=bt(e);t&&t.ownerPid===process.pid&&Q(e)}function Q(e){try{Ce.rmSync(xe(e),{force:!0})}catch{}}function bt(e){try{return JSON.parse(Ce.readFileSync(xe(e),"utf-8"))}catch{return null}}function ht(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function wt(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 gt(e,t,{probeTimeoutMs:n=4e3}={}){let o=bt(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&ht(o.ownerPid)?"live":(Q(t),"free");let i=Symbol("timeout"),s=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await wt(s,n,i);if(r===i)return s.then(m=>{if(m)try{m.disconnect()}catch{}}),"live";if(!r)return Q(t),"free";if(ht(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await wt(r.close().then(()=>!0).catch(()=>!1),n,!1))return Q(t),"free";try{r.disconnect()}catch{}return"live"}function hn(e,t){e&&(fn(),X.add(e),e.on("disconnected",()=>{X.delete(e),t&&Q(t)}))}async function St(e,t={}){let n=Je(),o={...dn,...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 gt(e,n)==="live")throw new Error(i);yt(n);let s;try{s=await e.launch(o)}catch{if(await gt(e,n)==="live")throw new Error(i);ze(n);try{s=await e.launch(o)}catch(u){throw pn(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: ${u.message})`)}}return hn(s,n),mn(n,s),{browser:s,profileDir:n,needsSeed:Ye(n)}}async function kt(e,t){if(!t||!t.needsSeed)return!1;if(!Ve())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(...He()),Ge(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function vt(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function Ct(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),gn=A.includes("--help")||A.includes("-h"),P=A.find(e=>e.startsWith("http")),B=A.includes("--full"),ie=B||A.includes("--with-experience"),re=B||A.includes("--with-featured"),se=B||A.includes("--with-education"),le=B||A.includes("--with-skills"),ae=B||A.includes("--with-recommendations"),ce=B||A.includes("--with-certifications"),xt=[["experience",ie],["featured",re],["education",se],["skills",le],["recommendations",ae],["certifications",ce]],Et=xt.filter(([,e])=>e).length,Ie=1+Et;function It(){console.log(`
241
241
  enrich-profile \u2014 visit ONE LinkedIn profile and save what we learn
242
242
 
243
243
  USAGE
@@ -288,4 +288,4 @@ WHEN TO USE
288
288
  - Audit your own LinkedIn profile (--full prints everything to stdout)
289
289
  - Deep-dive on one specific contact before reaching out
290
290
  - Verify what we know about a recruiter / lead
291
- `)}gn&&(It(),process.exit(0));L||(It(),process.exit(1));/linkedin\.com\/in\//i.test(L)||(console.error(`URL doesn't look like a LinkedIn profile: ${L}`),console.error("Expected format: https://www.linkedin.com/in/<slug>/"),process.exit(1));var Ae=vt(process.env.MY_LINKEDIN_URL||""),de=Ct(process.env.LINKEDIN_NAME||"");!Ae&&!de&&(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 ue=Ae&&vt(L)===Ae,Ee=xt.filter(([,e])=>e).map(([e])=>e);console.log("");console.log(` enrichProfile \u2014 ${L}`);j?console.log(` Mode: --full (${Ie} page loads: main + ${Ee.join(" + ")})`):Ee.length>0?console.log(` Mode: rich (${Ie} loads: main + ${Ee.join(" + ")})`):console.log(" Mode: basic (1 load \u2014 main page only)");console.log(ue?" Target: SELF (URL match) \u2014 will print to stdout, not saved to people.json":de?` 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)");Et>0&&(console.log(""),console.log(` \u26A0 ${Ie} 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 oe=null;try{let e=await St(wn);oe=e.browser;let t=await oe.newPage();await kt(t,e);let n=await mt(t,L,{extractExperience:ie,extractFeatured:re,extractEducation:se,extractSkills:le,extractRecommendations:ae,extractCertifications:ce});if((!n||!n.name)&&(console.error(" viewProfile returned no name \u2014 profile not loaded or DOM changed"),process.exit(1)),!ue&&de&&n.name&&Ct(n.name)===de&&(ue=!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)"}`),ie&&console.log(` experience: ${(n.experience||[]).length} entries`),re&&console.log(` featured: ${(n.featured||[]).length} entries`),se&&console.log(` education: ${(n.education||[]).length} entries`),le&&console.log(` skillsFull: ${(n.skillsFull||[]).length} entries`),ae&&console.log(` recommendations: ${(n.recommendations||[]).length} entries`),ce&&console.log(` certifications: ${(n.certifications||[]).length} entries`),console.log(""),ue)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",ie,n.experience],["featured",re,n.featured],["education",se,n.education],["skillsFull",le,n.skillsFull],["recommendations",ae,n.recommendations],["certifications",ce,n.certifications]],s=!1;for(let[r,d,m]of i)d&&(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()),Se(L,o),n.resolvedUrl&&ke(L,n.resolvedUrl),console.log(" \u2713 Saved to people.json")}}catch(e){console.error(" Error:",e.message),process.exit(1)}finally{oe&&await oe.close().catch(()=>{})}
291
+ `)}gn&&(It(),process.exit(0));P||(It(),process.exit(1));/linkedin\.com\/in\//i.test(P)||(console.error(`URL doesn't look like a LinkedIn profile: ${P}`),console.error("Expected format: https://www.linkedin.com/in/<slug>/"),process.exit(1));var _e=vt(process.env.MY_LINKEDIN_URL||""),de=Ct(process.env.LINKEDIN_NAME||"");!_e&&!de&&(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 ue=_e&&vt(P)===_e,Ee=xt.filter(([,e])=>e).map(([e])=>e);console.log("");console.log(` enrichProfile \u2014 ${P}`);B?console.log(` Mode: --full (${Ie} page loads: main + ${Ee.join(" + ")})`):Ee.length>0?console.log(` Mode: rich (${Ie} loads: main + ${Ee.join(" + ")})`):console.log(" Mode: basic (1 load \u2014 main page only)");console.log(ue?" Target: SELF (URL match) \u2014 will print to stdout, not saved to people.json":de?` 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)");Et>0&&(console.log(""),console.log(` \u26A0 ${Ie} 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 oe=null;try{let e=await St(wn);oe=e.browser;let t=await oe.newPage();await kt(t,e);let n=await mt(t,P,{extractExperience:ie,extractFeatured:re,extractEducation:se,extractSkills:le,extractRecommendations:ae,extractCertifications:ce});if((!n||!n.name)&&(console.error(" viewProfile returned no name \u2014 profile not loaded or DOM changed"),process.exit(1)),!ue&&de&&n.name&&Ct(n.name)===de&&(ue=!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)"}`),ie&&console.log(` experience: ${(n.experience||[]).length} entries`),re&&console.log(` featured: ${(n.featured||[]).length} entries`),se&&console.log(` education: ${(n.education||[]).length} entries`),le&&console.log(` skillsFull: ${(n.skillsFull||[]).length} entries`),ae&&console.log(` recommendations: ${(n.recommendations||[]).length} entries`),ce&&console.log(` certifications: ${(n.certifications||[]).length} entries`),console.log(""),ue)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",ie,n.experience],["featured",re,n.featured],["education",se,n.education],["skillsFull",le,n.skillsFull],["recommendations",ae,n.recommendations],["certifications",ce,n.certifications]],s=!1;for(let[r,u,m]of i)u&&(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()),Se(P,o),n.resolvedUrl&&ke(P,n.resolvedUrl),console.log(" \u2713 Saved to people.json")}}catch(e){console.error(" Error:",e.message),process.exit(1)}finally{oe&&await oe.close().catch(()=>{})}