ilml-plugin-linkedin 1.17.2 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
- var st=Object.defineProperty;var De=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{for(var n in e)st(t,n,{get:e[n],enumerable:!0})};async function g(t){let e=Math.floor(Math.random()*2001),n=t+e;return new Promise(o=>setTimeout(o,n))}async function Le(t){return await t.evaluate(()=>{let e=document.querySelectorAll("div.artdeco-modal--is-open");for(let o of e){let i=o.innerText||"",r=i.includes("Premium")||i.includes("premium")||i.includes("Upgrade")||i.includes("upgrade"),s=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(r||s||m){let b=o.querySelector('button[aria-label="Dismiss"]')||o.querySelector("button.artdeco-modal__dismiss")||o.querySelector("button[data-test-modal-close-btn]");if(b)return b.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 le=De(()=>{});var Be={};rt(Be,{extractCertificationsFromDetails:()=>vt,extractEducationFromDetails:()=>Ct,extractExperienceFromDetails:()=>St,extractFeaturedFromDetails:()=>kt,extractRecommendationsFromDetails:()=>Et,extractSkillsFromDetails:()=>xt});async function St(t,e){let n=e.replace(/\/+$/,"")+"/details/experience/";try{await t.goto(n,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3);let o=t.url();if(/\/(login|authwall|checkpoint)/i.test(o))throw new Error(`Session expired \u2014 bounced to ${o} when fetching /details/experience/`);for(let r=0;r<5;r++)await t.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(900);await g(1e3);let i=0;for(;i<5&&await t.evaluate(()=>{for(let s of document.querySelectorAll("button"))if(/^Load more$/i.test((s.textContent||"").trim()))return s.click(),!0;return!1});)i++,await g(1500),await t.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(700);return await t.evaluate(()=>{let r=document.querySelector("main");if(!r)return[];function s(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 m=s(r);if(!m)return[];let b=Array.from(m.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,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 F=null,T=-1;if(S>=0&&c[S+1]){let d=c[S+1],C=/^[>*\-•]|^&gt;/.test(d),q=/https?:\/\//.test(d),U=/\d{4}/.test(d),x=/,/.test(d)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(d);!C&&!q&&!U&&d.length<100&&x&&(F=d,T=S+1)}let ie=null,p=-1,N=c[c.length-1];if(N&&/and\s+\+\d+\s+skills?$/i.test(N)){p=c.length-1;let d=N.match(/^(.+?)\s+and\s+\+(\d+)\s+skills?$/i);d&&(ie={listed:d[1].split(",").map(C=>C.trim()),additional:parseInt(d[2],10)})}let R=new Set([0,1,S,T,p].filter(d=>d>=0)),_=c.filter((d,C)=>!R.has(C)),v=_.length>0?_.join(`
1
+ var wt=Object.defineProperty;var Me=(e,t)=>()=>(e&&(t=e(e=0)),t);var gt=(e,t)=>{for(var n in t)wt(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 Ne(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 ce=Me(()=>{});var Ve={};gt(Ve,{extractCertificationsFromDetails:()=>Tt,extractEducationFromDetails:()=>Nt,extractExperienceFromDetails:()=>Lt,extractFeaturedFromDetails:()=>Mt,extractRecommendationsFromDetails:()=>Rt,extractSkillsFromDetails:()=>Ft});async function Lt(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,F=null;if(S>=0){let d=c[S].split("\xB7").map(C=>C.trim());E=d[0]||null,d[1]&&(F=d[1])}let T=null,R=-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),x=/,/.test(d)||/\bArea\b|\bRegion\b|\bProvince\b|\bCountry\b|, [A-Z]{2}\b/.test(d);!C&&!U&&!H&&d.length<100&&x&&(T=d,R=S+1)}let se=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&&(se={listed:d[1].split(",").map(C=>C.trim()),additional:parseInt(d[2],10)})}let j=new Set([0,1,S,R,p].filter(d=>d>=0)),D=c.filter((d,C)=>!j.has(C)),v=D.length>0?D.join(`
2
2
 
3
- `):null;return{title:k,company:h,employmentType:w,dates:E,duration:M,location:F,description:v,skills:ie,_raw:c}}return b.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 ${e}: ${o.message?.slice(0,120)}`),[]}}async function V(t,e,n){let o=e.replace(/\/+$/,"")+`/details/${n}/`;await t.goto(o,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3);let i=t.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 s=0;s<4;s++)await t.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(700);await g(800);let r=0;for(;r<5&&await t.evaluate(()=>{for(let m of document.querySelectorAll("button"))if(/^Load more$/i.test((m.textContent||"").trim()))return m.click(),!0;return!1});)r++,await g(1300),await t.evaluate(()=>window.scrollTo(0,document.body.scrollHeight)),await g(600)}async function J(t,e,n,o){try{return await o()}catch(i){let r=i.message||"";if(/session expired|bounced to|authwall|checkpoint/i.test(r))throw i;return/not available on profile/i.test(r)?(console.log(` (${e}: section not on profile \u2014 skipped)`),[]):(console.error(`${n} failed for ${t}: ${r.slice(0,120)}`),[])}}async function kt(t,e){return J(e,"featured","extractFeaturedFromDetails",async()=>(await V(t,e,"featured"),await t.evaluate(`(() => {
5
- ${W}
3
+ `):null;return{title:k,company:h,employmentType:w,dates:E,duration:F,location:T,description:v,skills:se,_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 Mt(e,t){return Y(t,"featured","extractFeaturedFromDetails",async()=>(await J(e,t,"featured"),await e.evaluate(`(() => {
5
+ ${K}
6
6
 
7
7
  const main = document.querySelector('main');
8
8
  if (!main) return [];
@@ -42,8 +42,8 @@ var st=Object.defineProperty;var De=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{
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 Ct(t,e){return J(e,"education","extractEducationFromDetails",async()=>(await V(t,e,"education"),await t.evaluate(`(() => {
46
- ${W}
45
+ })()`)))}async function Nt(e,t){return Y(t,"education","extractEducationFromDetails",async()=>(await J(e,t,"education"),await e.evaluate(`(() => {
46
+ ${K}
47
47
 
48
48
  const main = document.querySelector('main');
49
49
  if (!main) return [];
@@ -79,8 +79,8 @@ var st=Object.defineProperty;var De=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{
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 xt(t,e){return J(e,"skills","extractSkillsFromDetails",async()=>(await V(t,e,"skills"),await t.evaluate(`(() => {
83
- ${W}
82
+ })()`)))}async function Ft(e,t){return Y(t,"skills","extractSkillsFromDetails",async()=>(await J(e,t,"skills"),await e.evaluate(`(() => {
83
+ ${K}
84
84
 
85
85
  const main = document.querySelector('main');
86
86
  if (!main) return [];
@@ -111,8 +111,8 @@ var st=Object.defineProperty;var De=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{
111
111
  skills.push({ name, endorsements, _raw: lines });
112
112
  }
113
113
  return skills;
114
- })()`)))}async function vt(t,e){return J(e,"certifications","extractCertificationsFromDetails",async()=>(await V(t,e,"certifications"),await t.evaluate(`(() => {
115
- ${W}
114
+ })()`)))}async function Tt(e,t){return Y(t,"certifications","extractCertificationsFromDetails",async()=>(await J(e,t,"certifications"),await e.evaluate(`(() => {
115
+ ${K}
116
116
 
117
117
  const main = document.querySelector('main');
118
118
  if (!main) return [];
@@ -136,8 +136,8 @@ var st=Object.defineProperty;var De=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{
136
136
 
137
137
  return { name, issuer, issueDate, expiryDate, credentialId, _raw: lines };
138
138
  }).filter(e => e.name);
139
- })()`)))}async function Et(t,e){return J(e,"recommendations","extractRecommendationsFromDetails",async()=>(await V(t,e,"recommendations"),await t.evaluate(`(() => {
140
- ${W}
139
+ })()`)))}async function Rt(e,t){return Y(t,"recommendations","extractRecommendationsFromDetails",async()=>(await J(e,t,"recommendations"),await e.evaluate(`(() => {
140
+ ${K}
141
141
 
142
142
  const main = document.querySelector('main');
143
143
  if (!main) return [];
@@ -172,7 +172,7 @@ var st=Object.defineProperty;var De=(t,e)=>()=>(t&&(e=t(t=0)),e);var rt=(t,e)=>{
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 W,He=De(()=>{le();W=`
175
+ })()`)))}var K,We=Me(()=>{ce();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 Dt from"puppeteer";le();import{getPluginConfig as lt}from"@ilivemylife/graph-sdk";var at=await lt();for(let[t,e]of Object.entries(at))process.env[t]===void 0&&(process.env[t]=e);var Nt=process.env.LINKEDIN_NAME,P=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Rt=Object.freeze(new Set([P.DRAFT,P.CONFIRMED,P.NEEDS_REVIEW])),Pt=Object.freeze(new Set([P.DRAFT,P.CONFIRMED,P.REJECTED,P.NEEDS_REVIEW]));import"dotenv/config";import*as f from"fs";import*as y from"path";import{fileURLToPath as ct}from"url";var ut=ct(import.meta.url),dt=y.dirname(y.dirname(ut)),I=process.env.DATA_DIR?y.resolve(process.env.DATA_DIR,"collected-profiles"):y.join(dt,"collected-profiles"),ae=y.join(I,"people.json"),Bt=y.join(I,"jobs.json"),Ht=y.join(I,"quota.json"),Vt=y.join(I,"conversations.json"),Wt=y.join(I,"sync-state.json"),Jt=y.join(I,"application-questions.json"),ce=y.join(I,"profile-history"),Ne=(t,e)=>{let n=parseInt(t,10);return Number.isInteger(n)&&n>=0?n:e},Kt=Ne(process.env.CONNECT_MAX_DAILY,20),Yt=Ne(process.env.CONNECT_MAX_WEEKLY,100),H=null;function Re(){f.existsSync(I)||f.mkdirSync(I,{recursive:!0})}function Pe(t,e){let n=JSON.stringify(e,null,2),o=t+".tmp";f.writeFileSync(o,n);for(let i=0;i<3;i++)try{f.renameSync(o,t);return}catch(r){if(i<2&&(r.code==="EPERM"||r.code==="EBUSY")){let s=Date.now();for(;Date.now()-s<200;);continue}throw r}}function je(t,e){if(!f.existsSync(t))return null;try{let n=JSON.parse(f.readFileSync(t,"utf-8"));try{f.copyFileSync(t,t+".backup")}catch{}return n}catch(n){console.error(`[!] ${e} is corrupted: ${n.message}`),console.error(` File: ${y.resolve(t)}`);let o=t+".backup";if(f.existsSync(o))try{let i=JSON.parse(f.readFileSync(o,"utf-8"));console.error(` Restored from ${o}`);try{f.copyFileSync(o,t)}catch{}return i}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${t}.corrupted`);try{f.copyFileSync(t,t+".corrupted")}catch{}return null}}function ft(){return new Date().toISOString().split("T")[0]}var mt=["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"],pt=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"];function j(t){if(!t)return null;let e=t.match(/\/in\/([^/?#]+)/);return e?e[1].toLowerCase():null}function Me(t){return typeof t=="string"?t.replace(/\s+/g," ").trim().toLowerCase():""}function Oe(t,e,n=null){if(!e||t[e])return e;let o=j(e);if(!o)return e;let i=null;for(let[r,s]of Object.entries(t)){if(j(s.profileUrl||r)===o)return r;!i&&Array.isArray(s.aliases)&&s.aliases.includes(o)&&(i=r)}if(i){let r=Me(n),s=Me(t[i].name);if(r&&s&&r===s)return i}return e}function ht(){f.existsSync(ce)||f.mkdirSync(ce,{recursive:!0})}function qe(t){let e=j(t);return e?y.join(ce,`${e}.json`):null}function wt(t){let e=qe(t);return e?je(e,`profile-history/${j(t)}.json`)||[]:[]}function gt(t,e){let n=qe(t);if(!n)return;ht();let o=wt(t);o.unshift(e);try{Pe(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${j(t)}: ${i.message}`)}}function Fe(t){return!!(t==null||Array.isArray(t)&&t.length===0||typeof t=="string"&&!t.trim())}function Te(t){return Array.isArray(t)?[...t].map(e=>String(e).trim()).sort().join("||"):typeof t=="string"?t.replace(/\s+/g," ").trim():t}function yt(t,e){if(!t)return[];let n=[];for(let o of pt){let i=t[o],r=e[o];Fe(i)||Fe(r)||Te(i)!==Te(r)&&n.push(o)}return n}function bt(t){let e=new Set(["seenCount","sources","firstSeen","lastSeen","lastUpdated","encounters","jobIds","lastFullVisitAt","lastSnapshotAt","messageSent","connectionStatus","connectionDate","connectionMethod"]),n={};for(let[o,i]of Object.entries(t))e.has(o)||(n[o]=i);return n}function ue(){return H||(Re(),H=je(ae,"people.json")||{},H)}function Ue(t){Re(),H=t;try{Pe(ae,t)}catch(e){console.error(`[!] Failed to save people.json: ${e.message}`),console.error(` Path: ${y.resolve(ae)}`)}}function de(t,e={}){if(!t)return null;let n=ue(),o=ft(),i=new Date().toISOString(),r=Oe(n,t,e.name),s=n[r];if(s){let m=yt(s,e);m.length>0&&(gt(r,{capturedAt:i,previousLastUpdated:s.lastUpdated||null,changedFields:m,snapshot:bt(s)}),s.lastSnapshotAt=i),s.seenCount=(s.seenCount||1)+1,s.lastSeen=o,s.lastUpdated=i,e.source&&!s.sources?.includes(e.source)&&(s.sources=s.sources||[],s.sources.push(e.source));for(let b of mt)if(e[b]!=null){if(Array.isArray(e[b])&&e[b].length===0&&Array.isArray(s[b])&&s[b].length>0)continue;s[b]=e[b]}Array.isArray(e.availableSections)&&(s.lastFullVisitAt=i)}else n[r]={name:e.name||null,title:e.title||null,location:e.location||null,company:e.company||null,about:e.about||null,connectionDegree:e.connectionDegree||null,connectionsCount:e.connectionsCount||null,mutualConnections:e.mutualConnections||null,photoUrl:e.photoUrl||null,hasVerifiedBadge:e.hasVerifiedBadge||!1,currentCompany:e.currentCompany||null,currentSchool:e.currentSchool||null,connectionsLevel:e.connectionsLevel||null,mutualConnectionsCount:e.mutualConnectionsCount||null,followers:e.followers||null,openToWork:e.openToWork||!1,hiring:e.hiring||!1,topSkills:e.topSkills||null,availableSections:e.availableSections||null,experience:e.experience||null,featuredLinks:e.featuredLinks||null,_lastEnrichedAt:e._lastEnrichedAt||null,featured:e.featured||null,education:e.education||null,skillsFull:e.skillsFull||null,recommendations:e.recommendations||null,certifications:e.certifications||null,firstSeen:o,lastSeen:o,seenCount:1,sources:e.source?[e.source]:[],connectionStatus:null,requestedConnectionAt:null,connectionDate:null,connectionMethod:null,messageSent:null,jobIds:[],lastUpdated:i,lastSnapshotAt:null,lastFullVisitAt:Array.isArray(e.availableSections)?i:null};return Ue(n),n[r]}function fe(t,e,n={}){if(n.dryRun||!t||!e)return;let o=j(e);if(!o)return;let i=ue(),r=Oe(i,t),s=i[r];if(!s)return;let m=j(s.profileUrl||r);o!==m&&(Array.isArray(s.aliases)||(s.aliases=[]),s.aliases.includes(o)||(s.aliases.push(o),s.lastUpdated=new Date().toISOString(),Ue(i)))}async function At(t,e){let n=t.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: npm run login");console.log(` Off-track: ${n.slice(0,80)}`),console.log(" Navigating back to profile..."),await t.goto(e,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3);let o=t.url();return o.includes("/in/")||console.log(` Recovery failed \u2014 still on: ${o.slice(0,80)}`),!0}async function Ve(t,e,n={}){let{extractExperience:o=!1,extractFeatured:i=!1,extractEducation:r=!1,extractSkills:s=!1,extractRecommendations:m=!1,extractCertifications:b=!1}=n;try{await t.goto(e,{waitUntil:"domcontentloaded",timeout:6e4}),await g(3e3),await Le(t)&&(console.log(" Dismissed Premium overlay"),await g(1500),await At(t,e));let c=0;for(let p=0;p<2;p++){let N=await t.evaluate(()=>document.body.scrollHeight);for(let _=1;_<=6;_++)await t.evaluate(v=>window.scrollTo(0,v),N*_/6),await g(900);let R=await t.evaluate(()=>document.body.scrollHeight);if(R===c)break;c=R}await g(800);let k=null;try{let p=t.url();p&&/\/in\/[^/?#]/.test(p)&&(k=p.split("?")[0].replace(/\/+$/,""))}catch{}let h=await t.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"]),N=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"]),R=l=>{let a=(l||"").trim().replace(/^[·•]\s*/,"");return/^(1st|2nd|3rd|she\/her|he\/him|they\/them|their\/them)$/i.test(a)},_={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:[]},v=document.querySelector("main");if(!v)return _;let d=[...Array.from(v.querySelectorAll("h1")),...Array.from(v.querySelectorAll("h2"))],C=Array.from(v.querySelectorAll("h2")),q=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)&&!N.has(u)}),U=q?q.textContent.trim():null,x=q?q.parentElement:null;for(;x&&x!==v&&!Array.from(x.children).filter(a=>a.tagName==="P").some(a=>{let u=a.textContent&&a.textContent.trim();return u&&u.length>5&&!R(u)});)x=x.parentElement;let we=null,ge=null,ye=null,se=null;if(x&&x!==v){let l=Array.from(x.children).filter(u=>u.tagName==="P").filter(u=>{let D=u.textContent&&u.textContent.trim();return D&&D.length>5&&!R(D)});if(l[0]&&(we=l[0].textContent.trim()),l[1]){let u=l[1].textContent.trim().split(/\s*[·•]\s*/);ge=u[0]||null,u.length>1&&(ye=u.slice(1).join(" \xB7 "))}let a=Array.from(x.children).filter(u=>u.tagName==="DIV");for(let u=a.length-1;u>=0;u--){let D=a[u].textContent&&a[u].textContent.trim();if(D&&!(U&&D.startsWith(U))&&(se=D.split(/[·•]/)[0].trim(),se))break}}let be=null;if(x){let l=x.querySelectorAll("p, span, div");for(let a of l){let u=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(u==="1st"||u==="2nd"||u==="3rd"){be=u;break}}}let Ze=!!v.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),Se=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),Xe=Se&&Se.src||null,K=v.textContent||"",ke=null,Ce=K.match(/(\d+\+?)\s+connections\b/i);Ce&&(ke=Ce[1]+" connections");let Y=null,xe=K.match(/(\d+)\s+mutual connection/i),ve=K.match(/and\s+(\d+)\s+other mutual/i),et=K.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);xe?Y=parseInt(xe[1],10):ve?Y=2+parseInt(ve[1],10):et&&(Y=2);let Ee=null,Ae=null,Ie=C.find(l=>l.textContent&&l.textContent.trim()==="About");if(Ie){let l=Ie.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 re=u[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(it=>it.trim()).filter(Boolean);re.length>0&&re.length<10&&(Ae=re)}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(),Ee=a||null}}let $e=null,_e=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(_e){let l=_e.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&($e=parseInt(a[1].replace(/,/g,""),10))}}let tt=[...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=>p.has(l)))],B=document.body.textContent||"",nt=/#OpenToWork\b/i.test(B)||/\bOpen to work\b/.test(B),ot=/#Hiring\b/i.test(B)||/\bI'?m hiring\b/i.test(B)||/\bWe are hiring\b/i.test(B);return{name:U,title:we,location:se,currentCompany:ge,currentSchool:ye,connectionDegree:be,hasVerifiedBadge:Ze,photoUrl:Xe,connectionsLevel:ke,mutualConnectionsCount:Y,followers:$e,openToWork:nt,hiring:ot,about:Ee,topSkills:Ae,availableSections:tt}});console.log(`Viewed: ${h.name} - ${h.title}`);let w=null,S=null,E=null,M=null,F=null,T=null;if(o||i||r||s||m||b){let p=await Promise.resolve().then(()=>(He(),Be));o&&(w=await p.extractExperienceFromDetails(t,e),console.log(` + Experience: ${w.length} entries`)),i&&(S=await p.extractFeaturedFromDetails(t,e),console.log(` + Featured: ${S.length} entries`)),r&&(E=await p.extractEducationFromDetails(t,e),console.log(` + Education: ${E.length} entries`)),s&&(M=await p.extractSkillsFromDetails(t,e),console.log(` + Skills: ${M.length} entries`)),m&&(F=await p.extractRecommendationsFromDetails(t,e),console.log(` + Recommendations: ${F.length} entries`)),b&&(T=await p.extractCertificationsFromDetails(t,e),console.log(` + Certifications: ${T.length} entries`))}return{...h,profileUrl:e,resolvedUrl:k,...w!==null&&{experience:w},...S!==null&&{featured:S},...E!==null&&{education:E},...M!==null&&{skillsFull:M},...F!==null&&{recommendations:F},...T!==null&&{certifications:T}}}catch($){console.error(`Error viewing profile ${e}:`,$.message);try{await t.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}}import We from"fs";import It from"path";var $t="cookies.json";function _t(){let t=process.env.ILML_SCOPE_DIR;return t?It.join(t,"plugins-state","linkedin","cookies.json"):$t}function Je(){let t=_t();if(!We.existsSync(t))throw new Error(`Cookies not found at ${t}. Run: ilml linkedin login`);let e;try{e=We.readFileSync(t,"utf-8")}catch(o){throw new Error(`Failed to read cookies at ${t}: ${o.message}. Run: ilml linkedin login`)}let n;try{n=JSON.parse(e)}catch{throw new Error(`Cookies file at ${t} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(n)||n.length===0)throw new Error(`Cookies file at ${t} is empty or not an array. Run: ilml linkedin login`);return n}function Ke(t){return t?t.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function Ye(t){return(t||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),Lt=A.includes("--help")||A.includes("-h"),L=A.find(t=>t.startsWith("http")),O=A.includes("--full"),Q=O||A.includes("--with-experience"),z=O||A.includes("--with-featured"),Z=O||A.includes("--with-education"),X=O||A.includes("--with-skills"),ee=O||A.includes("--with-recommendations"),te=O||A.includes("--with-certifications"),Ge=[["experience",Q],["featured",z],["education",Z],["skills",X],["recommendations",ee],["certifications",te]],Qe=Ge.filter(([,t])=>t).length,pe=1+Qe;function ze(){console.log(`
238
+ `});import"dotenv/config";import Ut from"puppeteer";ce();import{getPluginConfig as yt}from"@ilivemylife/graph-sdk";var bt=await yt();for(let[e,t]of Object.entries(bt))process.env[e]===void 0&&(process.env[e]=t);var Kt=process.env.LINKEDIN_NAME,O=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Yt=Object.freeze(new Set([O.DRAFT,O.CONFIRMED,O.NEEDS_REVIEW])),zt=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 St}from"url";var kt=St(import.meta.url),Ct=b.dirname(b.dirname(kt)),_=process.env.DATA_DIR?b.resolve(process.env.DATA_DIR,"collected-profiles"):b.join(Ct,"collected-profiles"),ue=b.join(_,"people.json"),en=b.join(_,"jobs.json"),tn=b.join(_,"quota.json"),nn=b.join(_,"conversations.json"),on=b.join(_,"sync-state.json"),rn=b.join(_,"application-questions.json"),de=b.join(_,"profile-history"),Pe=(e,t)=>{let n=parseInt(e,10);return Number.isInteger(n)&&n>=0?n:t},sn=Pe(process.env.CONNECT_MAX_DAILY,20),ln=Pe(process.env.CONNECT_MAX_WEEKLY,100),W=null;function je(){f.existsSync(_)||f.mkdirSync(_,{recursive:!0})}function Oe(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 qe(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 xt(){return new Date().toISOString().split("T")[0]}var vt=["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"],Et=["name","title","location","currentCompany","currentSchool","connectionDegree","hasVerifiedBadge","openToWork","hiring","about","topSkills"];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 Be(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 It(){f.existsSync(de)||f.mkdirSync(de,{recursive:!0})}function Ue(e){let t=q(e);return t?b.join(de,`${t}.json`):null}function At(e){let t=Ue(e);return t?qe(t,`profile-history/${q(e)}.json`)||[]:[]}function _t(e,t){let n=Ue(e);if(!n)return;It();let o=At(e);o.unshift(t);try{Oe(n,o)}catch(i){console.error(`[!] Failed to append profile-history for ${q(e)}: ${i.message}`)}}function Te(e){return!!(e==null||Array.isArray(e)&&e.length===0||typeof e=="string"&&!e.trim())}function Re(e){return Array.isArray(e)?[...e].map(t=>String(t).trim()).sort().join("||"):typeof e=="string"?e.replace(/\s+/g," ").trim():e}function $t(e,t){if(!e)return[];let n=[];for(let o of Et){let i=e[o],s=t[o];Te(i)||Te(s)||Re(i)!==Re(s)&&n.push(o)}return n}function Dt(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 fe(){return W||(je(),W=qe(ue,"people.json")||{},W)}function He(e){je(),W=e;try{Oe(ue,e)}catch(t){console.error(`[!] Failed to save people.json: ${t.message}`),console.error(` Path: ${b.resolve(ue)}`)}}function me(e,t={}){if(!e)return null;let n=fe(),o=xt(),i=new Date().toISOString(),s=Be(n,e,t.name),r=n[s];if(r){let y=$t(r,t);y.length>0&&(_t(s,{capturedAt:i,previousLastUpdated:r.lastUpdated||null,changedFields:y,snapshot:Dt(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 vt)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 He(n),n[s]}function pe(e,t,n={}){if(n.dryRun||!e||!t)return;let o=q(t);if(!o)return;let i=fe(),s=Be(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(),He(i)))}async function Pt(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 Je(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 Ne(e)&&(console.log(" Dismissed Premium overlay"),await g(1500),await Pt(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(v=>window.scrollTo(0,v),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:[]},v=document.querySelector("main");if(!v)return D;let d=[...Array.from(v.querySelectorAll("h1")),...Array.from(v.querySelectorAll("h2"))],C=Array.from(v.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,x=U?U.parentElement:null;for(;x&&x!==v&&!Array.from(x.children).filter(a=>a.tagName==="P").some(a=>{let u=a.textContent&&a.textContent.trim();return u&&u.length>5&&!j(u)});)x=x.parentElement;let ye=null,be=null,Se=null,le=null;if(x&&x!==v){let l=Array.from(x.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]&&(ye=l[0].textContent.trim()),l[1]){let u=l[1].textContent.trim().split(/\s*[·•]\s*/);be=u[0]||null,u.length>1&&(Se=u.slice(1).join(" \xB7 "))}let a=Array.from(x.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))&&(le=L.split(/[·•]/)[0].trim(),le))break}}let ke=null;if(x){let l=x.querySelectorAll("p, span, div");for(let a of l){let u=(a.textContent||"").trim().replace(/^[·•]\s*/,"");if(u==="1st"||u==="2nd"||u==="3rd"){ke=u;break}}}let ct=!!v.querySelector('svg[data-test-icon="verified"], [aria-label*="Verified" i]'),Ce=document.querySelector('main img[width="200"], button img[alt*="photo" i]'),ut=Ce&&Ce.src||null,z=v.textContent||"",xe=null,ve=z.match(/(\d+\+?)\s+connections\b/i);ve&&(xe=ve[1]+" connections");let G=null,Ee=z.match(/(\d+)\s+mutual connection/i),Ie=z.match(/and\s+(\d+)\s+other mutual/i),dt=z.match(/([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+and\s+([A-Z][\w'-]+(?:\s+[A-Z][\w'-]+)?)\s+are\s+mutual/);Ee?G=parseInt(Ee[1],10):Ie?G=2+parseInt(Ie[1],10):dt&&(G=2);let Ae=null,_e=null,$e=C.find(l=>l.textContent&&l.textContent.trim()==="About");if($e){let l=$e.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 ae=u[1].split(/\b(?:see (?:more|less)|show (?:more|less))\b/i)[0].trim().split(/\s*[·•]\s*/).map(ht=>ht.trim()).filter(Boolean);ae.length>0&&ae.length<10&&(_e=ae)}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(),Ae=a||null}}let De=null,Le=C.find(l=>l.textContent&&l.textContent.trim()==="Activity");if(Le){let l=Le.parentElement;for(;l&&l.tagName!=="SECTION";)l=l.parentElement;if(l){let a=(l.textContent||"").slice(0,200).match(/([\d,]+)\s+followers/i);a&&(De=parseInt(a[1].replace(/,/g,""),10))}}let ft=[...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||"",mt=/#OpenToWork\b/i.test(V)||/\bOpen to work\b/.test(V),pt=/#Hiring\b/i.test(V)||/\bI'?m hiring\b/i.test(V)||/\bWe are hiring\b/i.test(V);return{name:H,title:ye,location:le,currentCompany:be,currentSchool:Se,connectionDegree:ke,hasVerifiedBadge:ct,photoUrl:ut,connectionsLevel:xe,mutualConnectionsCount:G,followers:De,openToWork:mt,hiring:pt,about:Ae,topSkills:_e,availableSections:ft}});console.log(`Viewed: ${h.name} - ${h.title}`);let w=null,S=null,E=null,F=null,T=null,R=null;if(o||i||s||r||y||m){let p=await Promise.resolve().then(()=>(We(),Ve));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&&(F=await p.extractSkillsFromDetails(e,t),console.log(` + Skills: ${F.length} entries`)),y&&(T=await p.extractRecommendationsFromDetails(e,t),console.log(` + Recommendations: ${T.length} entries`)),m&&(R=await p.extractCertificationsFromDetails(e,t),console.log(` + Certifications: ${R.length} entries`))}return{...h,profileUrl:t,resolvedUrl:k,...w!==null&&{experience:w},...S!==null&&{featured:S},...E!==null&&{education:E},...F!==null&&{skillsFull:F},...T!==null&&{recommendations:T},...R!==null&&{certifications:R}}}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}}import I from"fs";import M from"path";var jt="cookies.json";function Ke(){let e=process.env.ILML_SCOPE_DIR;return e?M.join(e,"plugins-state","linkedin","cookies.json"):jt}function Ye(){let e=Ke();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 ze(){return I.existsSync(Ke())}function Ot(){let e=process.env.ILML_SCOPE_DIR;return e?M.join(e,"plugins-state","linkedin"):"."}function Ge(e){let t=String(e||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(t)?t:"default"}function qt(){let e=process.env.MY_LINKEDIN_URL,t=e&&e.match(/\/in\/([^/?#]+)/);return t&&t[1]?Ge(t[1]):"default"}function Qe(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=Ge(e||qt()),o=M.join(Ot(),"chrome-profile",n);return I.existsSync(o)||I.mkdirSync(o,{recursive:!0}),M.resolve(o)}var Ze=".ilml-seeded";function Xe(e){return!I.existsSync(M.join(e,Ze))}function et(e){try{I.writeFileSync(M.join(e,Ze),new Date().toISOString())}catch{}}function tt(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 Bt={headless:!1,defaultViewport:null,protocolTimeout:3e5};async function nt(e,t={}){let n=Qe(),o={...Bt,...t,userDataDir:n},i;try{i=await e.launch(o)}catch{tt(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:Xe(n)}}async function ot(e,t){if(!t||!t.needsSeed)return!1;if(!ze())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(...Ye()),et(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}function it(e){return e?e.replace(/^https?:\/\/(www\.|m\.)?linkedin\.com/i,"https://linkedin.com").split("?")[0].split("#")[0].replace(/\/+$/,"").toLowerCase():""}function rt(e){return(e||"").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}var A=process.argv.slice(2),Ht=A.includes("--help")||A.includes("-h"),N=A.find(e=>e.startsWith("http")),B=A.includes("--full"),Z=B||A.includes("--with-experience"),X=B||A.includes("--with-featured"),ee=B||A.includes("--with-education"),te=B||A.includes("--with-skills"),ne=B||A.includes("--with-recommendations"),oe=B||A.includes("--with-certifications"),st=[["experience",Z],["featured",X],["education",ee],["skills",te],["recommendations",ne],["certifications",oe]],lt=st.filter(([,e])=>e).length,we=1+lt;function at(){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
- `)}Lt&&(ze(),process.exit(0));L||(ze(),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 he=Ke(process.env.MY_LINKEDIN_URL||""),oe=Ye(process.env.LINKEDIN_NAME||"");!he&&!oe&&(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 ne=he&&Ke(L)===he,me=Ge.filter(([,t])=>t).map(([t])=>t);console.log("");console.log(` enrichProfile \u2014 ${L}`);O?console.log(` Mode: --full (${pe} page loads: main + ${me.join(" + ")})`):me.length>0?console.log(` Mode: rich (${pe} loads: main + ${me.join(" + ")})`):console.log(" Mode: basic (1 load \u2014 main page only)");console.log(ne?" Target: SELF (URL match) \u2014 will print to stdout, not saved to people.json":oe?` 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)");Qe>0&&(console.log(""),console.log(` \u26A0 ${pe} 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 G=null;try{G=await Dt.launch({headless:!1,defaultViewport:null,protocolTimeout:3e5});let t=await G.newPage();await t.setCookie(...Je());let e=await Ve(t,L,{extractExperience:Q,extractFeatured:z,extractEducation:Z,extractSkills:X,extractRecommendations:ee,extractCertifications:te});if((!e||!e.name)&&(console.error(" viewProfile returned no name \u2014 profile not loaded or DOM changed"),process.exit(1)),!ne&&oe&&e.name&&Ye(e.name)===oe&&(ne=!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: ${e.name}`),console.log(` title: ${e.title||"(none)"}`),console.log(` location: ${e.location||"(none)"}`),console.log(` about: ${e.about?`${e.about.length} chars`:"(none)"}`),console.log(` topSkills: ${e.topSkills?e.topSkills.join(", "):"(none)"}`),Q&&console.log(` experience: ${(e.experience||[]).length} entries`),z&&console.log(` featured: ${(e.featured||[]).length} entries`),Z&&console.log(` education: ${(e.education||[]).length} entries`),X&&console.log(` skillsFull: ${(e.skillsFull||[]).length} entries`),ee&&console.log(` recommendations: ${(e.recommendations||[]).length} entries`),te&&console.log(` certifications: ${(e.certifications||[]).length} entries`),console.log(""),ne)console.log(" \u2500\u2500\u2500 full data (self \u2014 not persisted) \u2500\u2500\u2500"),console.log(JSON.stringify(e,null,2));else{let n={name:e.name,title:e.title,location:e.location,about:e.about,currentCompany:e.currentCompany,currentSchool:e.currentSchool,topSkills:e.topSkills,availableSections:e.availableSections,connectionsLevel:e.connectionsLevel,mutualConnectionsCount:e.mutualConnectionsCount,followers:e.followers,openToWork:e.openToWork,hiring:e.hiring,hasVerifiedBadge:e.hasVerifiedBadge,photoUrl:e.photoUrl,source:"enrich-profile-single"},o=[["experience",Q,e.experience],["featured",z,e.featured],["education",Z,e.education],["skillsFull",X,e.skillsFull],["recommendations",ee,e.recommendations],["certifications",te,e.certifications]],i=!1;for(let[r,s,m]of o)s&&(Array.isArray(m)&&m.length>0?(n[r]=m,i=!0):console.log(` \u26A0 --with-${r==="skillsFull"?"skills":r} returned 0 entries \u2014 NOT writing ${r} (existing data preserved)`));i&&(n._lastEnrichedAt=new Date().toISOString()),de(L,n),e.resolvedUrl&&fe(L,e.resolvedUrl),console.log(" \u2713 Saved to people.json")}}catch(t){console.error(" Error:",t.message),process.exit(1)}finally{G&&await G.close().catch(()=>{})}
289
+ `)}Ht&&(at(),process.exit(0));N||(at(),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 ge=it(process.env.MY_LINKEDIN_URL||""),re=rt(process.env.LINKEDIN_NAME||"");!ge&&!re&&(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 ie=ge&&it(N)===ge,he=st.filter(([,e])=>e).map(([e])=>e);console.log("");console.log(` enrichProfile \u2014 ${N}`);B?console.log(` Mode: --full (${we} page loads: main + ${he.join(" + ")})`):he.length>0?console.log(` Mode: rich (${we} loads: main + ${he.join(" + ")})`):console.log(" Mode: basic (1 load \u2014 main page only)");console.log(ie?" Target: SELF (URL match) \u2014 will print to stdout, not saved to people.json":re?` 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)");lt>0&&(console.log(""),console.log(` \u26A0 ${we} 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 Q=null;try{let e=await nt(Ut);Q=e.browser;let t=await Q.newPage();await ot(t,e);let n=await Je(t,N,{extractExperience:Z,extractFeatured:X,extractEducation:ee,extractSkills:te,extractRecommendations:ne,extractCertifications:oe});if((!n||!n.name)&&(console.error(" viewProfile returned no name \u2014 profile not loaded or DOM changed"),process.exit(1)),!ie&&re&&n.name&&rt(n.name)===re&&(ie=!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)"}`),Z&&console.log(` experience: ${(n.experience||[]).length} entries`),X&&console.log(` featured: ${(n.featured||[]).length} entries`),ee&&console.log(` education: ${(n.education||[]).length} entries`),te&&console.log(` skillsFull: ${(n.skillsFull||[]).length} entries`),ne&&console.log(` recommendations: ${(n.recommendations||[]).length} entries`),oe&&console.log(` certifications: ${(n.certifications||[]).length} entries`),console.log(""),ie)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",Z,n.experience],["featured",X,n.featured],["education",ee,n.education],["skillsFull",te,n.skillsFull],["recommendations",ne,n.recommendations],["certifications",oe,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()),me(N,o),n.resolvedUrl&&pe(N,n.resolvedUrl),console.log(" \u2713 Saved to people.json")}}catch(e){console.error(" Error:",e.message),process.exit(1)}finally{Q&&await Q.close().catch(()=>{})}