ilml-plugin-linkedin 1.20.32 → 1.20.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.20.33
4
+ - **Fixed: replies couldn't be sent into some conversations because one of the other person's messages was being dropped when the thread was saved.** When someone sent two messages where the later one ended with the same words as an earlier one (for example "Tried calling you" and then "again tried calling you"), the save step mistook the second for a duplicate of the first and discarded it. The stored copy of the thread then held one fewer message than LinkedIn actually shows, so the safety check before sending — "did they reply since we last synced?" — saw the mismatch, assumed a new unread message had arrived, and aborted the send every time, making that conversation impossible to reply to automatically. The duplicate check now only merges two messages when they share the same timestamp (a true duplicate of a single message); distinct messages that merely end with the same words are kept. Genuine duplicates are still removed.
5
+ - No schema change. A thread that already lost a message repairs itself on the next sync.
6
+
3
7
  ## 1.20.32
4
8
  - **Fixed: Easy Apply silently gave up on some jobs and never tried them again.** On a subset of postings, clicking Easy Apply registered but the application form never actually opened (seen on sponsored postings that fire ad-tracking on click). The applier didn't verify the form had opened — it assumed the click worked, found nothing to fill, treated the job as a dead end after a few empty retries, and then marked it as permanently handled, so it was never retried on any later run. Over the past month this quietly dropped a large share of otherwise-applicable jobs. The applier now confirms the form really opened, re-clicks a few times if it didn't, and if it still won't open it skips the job *softly* — leaving it in the pool to try again next run instead of discarding it for good. Jobs whose form opens normally are unaffected.
5
9
  - No schema change.
@@ -6,7 +6,7 @@ var go=Object.defineProperty;var ae=(e,t)=>{for(var o in t)go(e,o,{get:t[o],enum
6
6
  `),console.error(` Or add ILML_TOKEN=... to .env
7
7
  `),process.exit(1));var Rt=Oo({token:_t});function Mo(e){if(!e||e<1e3)return`${e||0}ms`;let t=Math.round(e/1e3);if(t<60)return`${t}s`;let o=Math.floor(t/60),n=t%60;return n?`${o}m ${n}s`:`${o}m`}var Po={apply:"Job apply","apply-queue":"Job apply (queue)",scout:"Job scout",connect:"Connect run",funnel:"Recruiter funnel",messages:"Messages",sync:"Connections sync","sync-all":"Inbox sync",visit:"Profile visits",viewers:"Profile viewers",daily:"Daily run"};function Fo(e){let t=String(e||"").toLowerCase();return/authwall|session expired|not logged in|re-?auth|logged out|sign ?in/.test(t)?"LinkedIn asked to sign in again. Run `ilml linkedin login`, then run this again.":/protocoltimeout|callfunctionon|target closed|session closed|detached|execution context|browser.*disconnected|connection closed/.test(t)?"The browser stopped responding partway through. This is usually temporary \u2014 just run it again.":/err_aborted|err_network|err_connection|err_name_not_resolved|net::/.test(t)?"A page failed to load (network hiccup). Try running it again in a moment.":/navigation timeout|timeout.*exceeded|waiting for selector|waiting for/.test(t)?"A page took too long to load. Try again in a moment.":/invite limit|weekly.*limit|too many|rate.?limit|quota/.test(t)?"You've reached a LinkedIn sending limit for now. Wait a while, then try again.":"Something went wrong partway through. It is safe to run the command again."}function Lo({scriptName:e,mode:t,status:o,summaryLines:n,error:s,stoppedReason:r,duration:i}){let c=o==="error"||o==="stopped"?o==="error"?"\u2717":"\u26A0":o==="quota-reached"?"\u26A0":"\u2713",l=o==="error"?"stopped early":o==="stopped"?`stopped \u2014 ${r||"did not finish"}`:o==="quota-reached"?"daily limit reached":"done",a=Po[e]||e,u=t&&t!=="default"?` \xB7 ${t}`:"",d=new Date().toISOString().slice(0,16).replace("T"," "),m=i?` \xB7 ${Mo(i)}`:"",g=[];g.push(`## ${c} ${a} \u2014 ${l}`),g.push(`_${d}${u}${m}_`),g.push("");for(let p of n)g.push(`- ${p}`);if(o==="error"){g.push(""),g.push(`**What happened:** ${Fo(s)}`);let p=String(s||"").replace(/\s+/g," ").trim();p&&g.push(`_Technical detail: ${p.slice(0,140)}_`)}return g.join(`
8
8
  `)}async function Fe({scriptName:e,mode:t,status:o,summaryLines:n,error:s,stoppedReason:r,duration:i}){let c=process.env.NODE_RUN_REPORTS;if(!c||!Array.isArray(n)||n.length===0)return;let l=Lo({scriptName:e,mode:t,status:o,summaryLines:n,error:s,stoppedReason:r,duration:i});try{await Rt.addMessage(c,l)}catch(a){console.error(`[runReport] Failed to post end-of-session message: ${a.message}`)}}var Bo=Uo(import.meta.url),qo=Q.dirname(Q.dirname(Bo)),Le=process.env.DATA_DIR?Q.resolve(process.env.DATA_DIR,"collected-profiles"):Q.join(qo,"collected-profiles"),Ue=Q.join(Le,"run-log.json");function Jo(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";L.writeFileSync(n,o);for(let s=0;s<3;s++)try{L.renameSync(n,e);return}catch(r){if(s<2&&(r.code==="EPERM"||r.code==="EBUSY")){let i=Date.now();for(;Date.now()-i<200;);continue}throw r}}function Dt(){try{if(!L.existsSync(Ue))return{runs:[]};let e=JSON.parse(L.readFileSync(Ue,"utf-8"));return!e.runs||!Array.isArray(e.runs)?{runs:[]}:e}catch{return{runs:[]}}}function It(e){L.existsSync(Le)||L.mkdirSync(Le,{recursive:!0});try{Jo(Ue,e)}catch(t){console.error(`[!] Failed to save run-log.json: ${t.message}`)}}function Wo(e,t="default"){let o=Dt();for(let i of o.runs)i.status==="running"&&(i.status="interrupted",i.result="interrupted",i.timestamp&&(i.duration=Date.now()-new Date(i.timestamp).getTime()));let n=new Date,s={timestamp:n.toISOString(),script:e,mode:t,status:"running",result:null,duration:null,stats:null,error:null};o.runs.push(s);let r=Date.now()-30*24*60*60*1e3;return o.runs=o.runs.filter(i=>new Date(i.timestamp).getTime()>r),It(o),{script:e,mode:t,startTime:n.getTime(),runIndex:o.runs.length-1}}function Ho(e,t,o=null,n=null){if(!e)return;let s=null;try{let c=Dt(),l=c.runs[e.runIndex];if(l&&l.status==="running"&&l.script===e.script)l.status=t,l.result=t,l.duration=Date.now()-e.startTime,l.stats=o,l.error=n,s=l.duration;else{let a=c.runs.find(u=>u.script===e.script&&u.status==="running"&&u.timestamp===new Date(e.startTime).toISOString());a&&(a.status=t,a.result=t,a.duration=Date.now()-e.startTime,a.stats=o,a.error=n,s=a.duration)}It(c)}catch(c){console.error(`[runLog] Failed to end run: ${c.message}`)}let r=o&&Array.isArray(o.summaryLines)?o.summaryLines:null,i=o&&o.__deferReport===!0;if(r&&r.length>0&&process.env.NODE_RUN_REPORTS&&!i){let c=t==="error"?"error":o&&o.dailyLimitHit?"quota-reached":"done";Fe({scriptName:e.script,mode:e.mode,status:c,summaryLines:r,error:n,duration:s??Date.now()-e.startTime}).catch(l=>console.error(`[runLog] postRunReport failed: ${l.message}`))}}async function Tt(e,t,o,n,s={}){let{rethrow:r=!0}=s,i=Wo(e,t),c={},l=null;try{await o(c)}catch(m){l=m}let a=[];try{let m=n?n(c):[];a=(Array.isArray(m)?m:[]).filter(g=>typeof g=="string"&&g.trim())}catch(m){console.error(`[runLog] summarize threw (report still sent): ${m.message}`)}if(a.length===0&&l&&(a=["(crashed before any progress was recorded)"]),l){let m=t&&t!=="default"?` (${t})`:"";console.error(`
9
- \u2717 ${e}${m} failed: ${l.message||l}`)}let u=Date.now()-i.startTime,d=!l&&c.stoppedReason?String(c.stoppedReason):null;try{Ho(i,l?"error":d?"partial":"success",{...c,summaryLines:a,__deferReport:!0},l?l.message||String(l):null)}catch(m){console.error(`[runLog] endRun failed: ${m.message}`)}if(a.length>0&&process.env.NODE_RUN_REPORTS){let m=l?"error":d?"stopped":c.dailyLimitHit?"quota-reached":"done";try{await Fe({scriptName:i.script,mode:i.mode,status:m,summaryLines:a,error:l?l.message||String(l):null,stoppedReason:d,duration:u})}catch(g){console.error(`[runLog] report post failed: ${g.message}`)}}if(l&&r)throw l;return c}import Xo from"puppeteer";import{addExtra as Zo}from"puppeteer-extra";import en from"puppeteer-extra-plugin-stealth";import Be from"fs";import Vo from"path";var Yo={headless:!1,defaultViewport:null,protocolTimeout:3e5},pe=new Set,Ot=!1;async function be(){let e=[...pe].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});pe.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function Go(){if(Ot)return;Ot=!0;let e=t=>async()=>{await be(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await be(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await be(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await be(),process.exit(0))}),process.on("exit",()=>{for(let t of pe)try{let o=t.process&&t.process();o&&o.kill("SIGKILL")}catch{}})}function qe(e){return Vo.join(e,".ilml-browser-session.json")}function Pt(e,t={}){try{Be.writeFileSync(qe(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function zo(e,t){try{let o=t.wsEndpoint&&t.wsEndpoint();Pt(e,o?{wsEndpoint:o}:{})}catch{}}function Ko(e){let t=Ft(e);t&&t.ownerPid===process.pid&&de(e)}function de(e){try{Be.rmSync(qe(e),{force:!0})}catch{}}function Ft(e){try{return JSON.parse(Be.readFileSync(qe(e),"utf-8"))}catch{return null}}function jt(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function Nt(e,t,o){let n,s=new Promise(i=>{n=setTimeout(()=>i(o),t)}),r=Promise.resolve(e).then(i=>(clearTimeout(n),i),i=>{throw clearTimeout(n),i});return Promise.race([r,s])}async function Mt(e,t,{probeTimeoutMs:o=4e3}={}){let n=Ft(t);if(!n)return"free";if(!n.wsEndpoint)return n.ownerPid&&n.ownerPid!==process.pid&&jt(n.ownerPid)?"live":(de(t),"free");let s=Symbol("timeout"),r=e.connect({browserWSEndpoint:n.wsEndpoint,defaultViewport:null}).catch(()=>null),i=await Nt(r,o,s);if(i===s)return r.then(l=>{if(l)try{l.disconnect()}catch{}}),"live";if(!i)return de(t),"free";if(jt(n.ownerPid)){try{i.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await Nt(i.close().then(()=>!0).catch(()=>!1),o,!1))return de(t),"free";try{i.disconnect()}catch{}return"live"}function Qo(e,t){e&&(Go(),pe.add(e),e.on("disconnected",()=>{pe.delete(e),t&&de(t)}))}async function Lt(e,t={}){let o=dt(),n={...Yo,...t,userDataDir:o},s=`Could not open the LinkedIn automation Chrome profile at ${o}. 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 Mt(e,o)==="live")throw new Error(s);Pt(o);let r;try{r=await e.launch(n)}catch{if(await Mt(e,o)==="live")throw new Error(s);ht(o);try{r=await e.launch(n)}catch(c){throw Ko(o),new Error(`Could not open the LinkedIn automation Chrome profile at ${o}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${c.message})`)}}return Qo(r,o),zo(o,r),{browser:r,profileDir:o,needsSeed:mt(o)}}async function Ut(e,t){if(!t||!t.needsSeed)return!1;if(!ut())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(...at()),gt(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var Jt=Zo(Xo);Jt.use(en());async function Wt(){let{browser:e,profileDir:t,needsSeed:o}=await Lt(Jt),n=await e.newPage();return await n.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await Ut(n,{profileDir:t,needsSeed:o}),console.log(" Browser launched (persistent profile)."),{browser:e,page:n}}async function We(e){await we(e,"https://www.linkedin.com/messaging/",{readySelector:".msg-conversations-container__conversations-list, .msg-conversation-listitem",label:"inbox"})||(console.warn(" Inbox container not found via known selectors, proceeding..."),await E(3e3)),console.log(" Inbox loaded.")}async function Ht(e){let t=await e.evaluate(()=>{let o=document.querySelectorAll(".msg-conversation-listitem"),n=[];for(let s of o){let i=s.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||null;if(!i)continue;let l=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(l)||/^\s*Promoted\b/i.test(l))continue;let u=s.querySelector(".msg-conversation-listitem__time-stamp, .msg-conversation-card__time-stamp")?.textContent?.trim()||"",d=s.querySelector(".msg-conversation-card__convo-item-container--unread")!==null||s.querySelector(".msg-conversation-card__unread-count")!==null,m,g;if(l.startsWith("You:"))m="me",g=l.slice(4).trim();else{let f=i.split(" ")[0];if(l.startsWith(i+":")||l.startsWith(f+":")){m="them";let h=l.indexOf(":");g=l.slice(h+1).trim()}else m="them",g=l}let p=s.getBoundingClientRect();n.push({name:i,lastMessagePreview:g,lastMessageTime:u,unread:d,lastMessageBy:m,x:p.x+p.width/2,y:p.y+p.height/2})}return n});for(let o of t)o.lastMessageTime=Oe(o.lastMessageTime)||o.lastMessageTime;return t}async function Vt(e){return e.evaluate(()=>{let t=[".msg-conversations-container__conversations-list",".msg-conversations-container",'[class*="msg-conversations-container"] ul'];for(let n of t){let s=document.querySelector(n);if(s&&s.scrollHeight>s.clientHeight)return s.scrollBy(0,600),{scrollTop:s.scrollTop,scrollHeight:s.scrollHeight}}let o=document.querySelector(".msg-conversation-listitem");if(o){let n=o.parentElement;for(;n;){if(n.scrollHeight>n.clientHeight+10)return n.scrollBy(0,600),{scrollTop:n.scrollTop,scrollHeight:n.scrollHeight};n=n.parentElement}}return null})}async function tn(e){return e.evaluate(()=>{let t=/^status\s+is\s+|^online$|^offline$|^away$|^busy$|^active\s/i,o=['.msg-overlay-conversation-bubble__header a[href*="/in/"] .truncate','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header__title a[href*="/in/"]',".msg-overlay-bubble-header__title",".msg-overlay-conversation-bubble__header .truncate",".msg-thread__link-to-profile","h2.msg-entity-lockup__entity-title",".msg-s-message-list-container h2",".msg-thread h2",".msg-conversations-container__title-row h2",'.msg-thread a[href*="/in/"]'];for(let s of o){let r=document.querySelector(s);if(r){let i=r.textContent?.trim()?.replace(/\s+/g," ");if(i&&i.length>1&&i.length<100&&!t.test(i))return i}}let n=document.querySelectorAll(".msg-s-message-list-container h2, .msg-thread h2");for(let s of n){let r=s.textContent?.trim();if(r&&r.length>1&&r.length<100&&!/conversation/i.test(r)&&!t.test(r))return r}return null})}async function Bt(e,t){let o=await tn(e);if(!o)return{match:!1,headerName:null};let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(c=>c.length>1),r=o.toLowerCase();return{match:r.includes(n)||s.some(c=>r.includes(c)),headerName:o}}async function Je(e,t){let o=t.split(" ")[0],n=8e3,s=500,r=0;for(;r<n;){let{match:l,headerName:a}=await Bt(e,t);if(l)return await E(500),{verified:!0,headerName:a};let u=await e.evaluate(()=>{let d=document.querySelectorAll(".msg-s-message-group__name"),m=Array.from(d).map(p=>p.textContent?.trim()).filter(Boolean),g=document.querySelectorAll(".msg-s-event-listitem").length;return{allSenders:m,msgCount:g}});if(u.msgCount>0&&u.allSenders.some(m=>m.toLowerCase().includes(o.toLowerCase())))return await E(300),{verified:!0,headerName:o};await E(s),r+=s}let{match:i,headerName:c}=await Bt(e,t);return i?{verified:!0,headerName:c}:{verified:!1,headerName:c}}async function on(e){let o=0,n=0;for(let s=0;s<50;s++){let r=await e.evaluate(()=>{let i=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!i){let a=document.querySelector(".msg-overlay-conversation-bubble");a&&(i=a.querySelector(".msg-s-message-list-container")||a.querySelector(".msg-s-message-list"))}if(!i)return{found:!1};let c=i.querySelectorAll("li.msg-s-message-list__event").length;return i.scrollTop<=1?{found:!0,atTop:!0,msgCount:c}:(i.scrollTop=0,{found:!0,atTop:!1,msgCount:c})});if(!r.found||r.atTop)break;if(await E(800),r.msgCount===o){if(n++,n>=3)break}else n=0;o=r.msgCount}}async function ce(e,{scrollUp:t=!0}={}){t&&await on(e);let o=await e.evaluate(()=>{let n=[],s="",r=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!r){let u=document.querySelector(".msg-overlay-conversation-bubble");u&&(r=u.querySelector(".msg-s-message-list-container")||u.querySelector(".msg-s-message-list"))}if(!r)return n;let i=r.querySelectorAll("li.msg-s-message-list__event");if(i.length===0){let u=document.querySelector(".msg-overlay-conversation-bubble, .msg-overlay-list-bubble");u&&(i=u.querySelectorAll("li.msg-s-message-list__event, .msg-s-event-listitem"))}function c(u){let d=u.getAttribute("data-event-urn");if(!d)return null;let m=d.match(/,2-([A-Za-z0-9+/=]+)\)/);if(!m)return null;try{let p=atob(m[1]).match(/^(\d{13})/);if(!p)return null;let f=Number(p[1]);if(f>14200704e5&&f<20512224e5)return f}catch{}return null}let l="";function a(u,d,m){let g=c(u),f=u.querySelector(".msg-s-message-group__timestamp, time")?.textContent?.trim()||"",h=u.querySelector(".msg-s-event-listitem__message-bubble");if(!h)return null;let S=h.textContent?.trim()?.replace(/Open Emoji Keyboard|Reply to this message|React with[^.]+/g,"")?.replace(/^(?:👏\s*👍\s*😊\s*)+/,"")?.replace(/\s+/g," ")?.trim()||"";if(!S)return null;let y=g?new Date(g).toISOString():m?`${m} ${f}`.trim():f;return{sender:d,text:S,time:y}}for(let u of i){let d=u.querySelector("time.msg-s-message-list__time-heading");d&&(l=d.textContent?.trim()||l);let m=u.querySelectorAll(".msg-s-message-group");if(m.length>0)for(let g of m){let p=g.querySelector(".msg-s-message-group__name");p&&(s=p.textContent?.trim()||s);let f=s||"Unknown",h=g.querySelectorAll(".msg-s-event-listitem");for(let S of h){let y=a(S,f,l);y&&n.push(y)}}else{let g=u.querySelectorAll(".msg-s-event-listitem");for(let p of g){let f=p.querySelector(".msg-s-message-group__name");f&&(s=f.textContent?.trim()||s);let S=a(p,s||"Unknown",l);S&&n.push(S)}}}if(n.length===0){let u=document.querySelectorAll(".msg-s-event-listitem--group-a11y-heading");for(let d of u){let m=d.textContent?.trim();m&&n.push({sender:"",text:m,time:""})}}return n});for(let n of o)(!n.time||!/^\d{4}-\d{2}-\d{2}T/.test(n.time))&&(n.time=Oe(n.time)||n.time);return o}function le(e){return String(e||"").replace(/\s+/g," ").trim().toLowerCase()}function $e(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let o=m=>le(m.sender)+"||"+le(m.text).replace(/\s+/g,""),n=new Set(t.map(o)),s=new Set(e.map(o)),r=e.filter(m=>K.has(m.status)?!1:!n.has(o(m))),i=t.filter(m=>!s.has(o(m))),c=t.filter(m=>s.has(o(m))),l=e.filter(m=>K.has(m.status)),a=[...r,...c,...i],u=[];for(let m of a){let g=le(m.text),p=le(m.sender),f=!1;for(let h=0;h<u.length;h++){let S=u[h];if(le(S.sender)!==p)continue;let y=le(S.text);if(g.length>y.length&&g.endsWith(y)){f=!0;break}if(y.length>g.length&&y.endsWith(g)){u[h]=m,f=!0;break}}f||u.push(m)}return[...u,...l]}async function ke(e,t){let o=await e.evaluate(i=>{let c=document.querySelectorAll(".msg-conversation-listitem");for(let l of c)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===i){let d=l.getBoundingClientRect();if(d.height>0)return{x:d.x+d.width/2,y:d.y+d.height/2}}return null},t);if(o){await e.mouse.click(o.x,o.y),await E(3e3);let i=await Je(e,t);if(i.verified)return i}let n=vt(t),s=n!==t?[t,n]:[t];for(let i of s)if(await qt(e,i,t)){let l=await Je(e,t);if(l.verified)return l}let r=bt(n);if(r!==n&&r.length>0&&await qt(e,r,t,{requireUnique:!0})){let c=await Je(e,t);if(c.verified)return c}return{verified:!1,headerName:null}}async function qt(e,t,o,n={}){let{requireUnique:s=!1}=n,r=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");if(!r)return!1;await r.click(),await E(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await E(300),await r.type(t,{delay:30}),await E(500),await e.keyboard.press("Enter"),await E(3500);let i=await e.evaluate((c,l)=>{let a=c.split(" ")[0].toLowerCase(),u=c.toLowerCase(),d=document.querySelectorAll(".msg-conversation-listitem"),m=[],g=[];for(let f of d){let S=f.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||"",y=S.toLowerCase();if(y.includes(a)){let $=f.getBoundingClientRect();if($.height>0){let w=S.includes(",")||/\d+ other/.test(S),R=y===u?3:y.includes(u)?2:1,_={text:S,isGroup:w,score:R,x:$.x+$.width/2,y:$.y+$.height/2};w?g.push(_):m.push(_)}}}m.sort((f,h)=>h.score-f.score);let p=[...m,...g];return l&&p.length!==1?null:m[0]||g[0]||null},o,s);return i?(s&&console.log(" (found via stripped designations)"),await e.mouse.click(i.x,i.y),!0):!1}async function Yt(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await E(200),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await e.keyboard.press("Escape"),await E(1e3))}import"dotenv/config";import*as v from"fs";import*as Ze from"os";import*as x from"path";import{fileURLToPath as Bn}from"url";var Ye={};ae(Ye,{NAME:()=>sn,VERSION:()=>nn,up:()=>cn});import*as U from"fs";import*as Ee from"path";var nn=1,sn="normalize-jobs-and-questions",rn=["description","techStack","jobTags","seniority","employmentType","industries","jobFunction","postedTime","applicantCount","companySize","workplaceType","contractType","isEasyApply","applyType","companyUrl","scoutedAt","lastSeen"],ln=50;function He(e){return U.existsSync(e)?JSON.parse(U.readFileSync(e,"utf-8")):null}function Ve(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{U.writeFileSync(n,o)}catch(s){try{U.unlinkSync(n)}catch{}throw s}try{U.renameSync(n,e)}catch(s){try{U.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function cn(e,t){let o=Ee.join(e,"jobs.json"),n=Ee.join(t,"scouted-jobs.json"),s=Ee.join(e,"application-questions.json"),r=He(o)||{},i=He(n)||{},c=0,l=[];for(let u of Object.keys(r)){if(!i[u])continue;let d=i[u],m=r[u];for(let g of rn)d[g]!=null&&m[g]==null&&(m[g]=d[g]);l.push(u),c++}c>0?(Ve(o,r),console.log(` Phase 1: Merged ${c} scouted jobs into jobs.json`)):console.log(" Phase 1: No overlapping jobs to merge");let a=He(s);if(a&&Array.isArray(a.applications)){let u={},d=0;for(let m of a.applications){let g=m.jobId||"unknown";u[g]||(u[g]={applications:[]});let p=(m.questions||[]).map(f=>{let h={type:f.type||"input",question:f.question||"",answer:f.answer||""};return f.options&&(f.options.length<=ln?h.options=f.options:(h.optionsOmitted=!0,d++)),f.page&&(h.page=f.page),f.wasPreFilled&&(h.wasPreFilled=!0),f.wasRetry&&(h.wasRetry=!0),h});u[g].applications.push({applicationId:m.applicationId,date:m.date,result:m.result||"submitted",formPages:m.formPages||null,duration:m.duration||null,retries:m.retries||0,failedField:m.failedField||null,questionCount:m.questionCount||p.length,questions:p})}Ve(s,u),console.log(` Phase 2: Rekeyed ${a.applications.length} applications by jobId (${Object.keys(u).length} unique jobs)`),d>0&&console.log(` Phase 2: Stripped bloated options from ${d} questions`)}else a&&!a.applications?console.log(" Phase 2: application-questions.json already in keyed format"):console.log(" Phase 2: No application-questions.json found");if(l.length>0){for(let u of l)delete i[u];Ve(n,i),console.log(` Phase 3: Removed ${l.length} merged entries from scouted-jobs.json (${Object.keys(i).length} remaining)`)}else console.log(" Phase 3: No entries to remove from scouted-jobs.json")}var Ge={};ae(Ge,{NAME:()=>un,VERSION:()=>an,up:()=>pn});import*as B from"fs";import*as Gt from"path";var an=2,un="reset-unread-flags";function fn(e){return B.existsSync(e)?JSON.parse(B.readFileSync(e,"utf-8")):null}function dn(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{B.writeFileSync(n,o)}catch(s){try{B.unlinkSync(n)}catch{}throw s}try{B.renameSync(n,e)}catch(s){try{B.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function pn(e){let t=Gt.join(e,"conversations.json"),o=fn(t);if(!o){console.log(" conversations.json not found \u2014 nothing to reset.");return}let n=0;for(let s of Object.keys(o))o[s].unread===!0&&(o[s].unread=!1,n++);if(n===0){console.log(" No stale unread flags found \u2014 nothing to do.");return}dn(t,o),console.log(` Reset unread=false on ${n} conversations. Run 'ilml linkedin sync-all' to re-establish real unread state from LinkedIn.`)}var ze={};ae(ze,{NAME:()=>gn,VERSION:()=>mn,up:()=>vn});import*as q from"fs";import*as zt from"path";var mn=3,gn="recompute-last-message-by",hn=new Set(["draft","confirmed","rejected","needs_review"]);function yn(e){return q.existsSync(e)?JSON.parse(q.readFileSync(e,"utf-8")):null}function wn(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{q.writeFileSync(n,o)}catch(s){try{q.unlinkSync(n)}catch{}throw s}try{q.renameSync(n,e)}catch(s){try{q.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}function Sn(e,t){if(!e||e.length===0)return"them";let o=e.filter(r=>!hn.has(r.status));if(o.length===0)return"them";let n=o.map(r=>({m:r,t:Date.parse(r.time)})).filter(r=>Number.isFinite(r.t)).sort((r,i)=>i.t-r.t).map(r=>r.m),s=n.length>0?n:[...o].reverse();for(let r of s){let i=r.sender;if(i===t)return"me";if(i!=="Unknown"&&i!=="")return"them"}return"them"}async function vn(e){let t=zt.join(e,"conversations.json"),o=yn(t);if(!o){console.log(" conversations.json not found \u2014 nothing to recompute.");return}let n=process.env.LINKEDIN_NAME;if(!n||typeof n!="string"||!n.trim())throw new Error(`LINKEDIN_NAME env var is not set. Migration v003 needs your display name to determine which messages are yours vs theirs. Set LINKEDIN_NAME in your .env (or run "ilml plugin config linkedin set LINKEDIN_NAME 'Your Name'") and retry.`);let s=0,r=0,i=0;for(let c of Object.keys(o)){let l=o[c];if(!l||typeof l!="object")continue;Object.prototype.hasOwnProperty.call(l,"_cardSynced")&&(delete l._cardSynced,r++);let a=Array.isArray(l.messages)?l.messages:[],u=Sn(a,n),d=u==="me"?"awaiting_reply":"unanswered_by_us";l.lastMessageBy!==u&&i++,l.lastMessageBy=u,l.conversationStatus=d,s++}if(s===0){console.log(" No conversations to recompute.");return}wn(t,o),console.log(` Recomputed lastMessageBy + conversationStatus on ${s} conversations.`),console.log(` ${i} had stale lastMessageBy (now corrected).`),r>0&&console.log(` Cleaned ${r} leftover _cardSynced flags.`),console.log(" Re-run 'ilml linkedin enrich' if you want actionNeeded / summary / autoTags to also update.")}var Ke={};ae(Ke,{NAME:()=>$n,VERSION:()=>bn,up:()=>Cn});import*as J from"fs";import*as Kt from"path";var bn=4,$n="split-connection-timestamps",kn=new Set(["pending","sent_without_note","sent_with_note","sent_without_note_upsell"]);function En(e){if(!J.existsSync(e))return null;let t=J.readFileSync(e,"utf-8");return t.charCodeAt(0)===65279&&(t=t.slice(1)),JSON.parse(t)}function An(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{J.writeFileSync(n,o)}catch(s){try{J.unlinkSync(n)}catch{}throw s}try{J.renameSync(n,e)}catch(s){try{J.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function Cn(e){let t=Kt.join(e,"people.json"),o=En(t);if(!o||typeof o!="object"){console.log(" people.json not found \u2014 nothing to migrate.");return}let n=0,s=0;for(let r of Object.keys(o)){let i=o[r];!i||typeof i!="object"||(s++,kn.has(i.connectionStatus)&&i.connectionDate&&!i.requestedConnectionAt&&(i.requestedConnectionAt=i.connectionDate,i.connectionDate=null,n++))}if(n===0){console.log(` Scanned ${s} people \u2014 none needed the connectionDate\u2192requestedConnectionAt move.`);return}An(t,o),console.log(` Moved connectionDate \u2192 requestedConnectionAt on ${n} still-pending people (of ${s} scanned).`),console.log(' connectionDate now means "accepted on" only; requestedConnectionAt means "requested on".')}var Qe={};ae(Qe,{NAME:()=>_n,VERSION:()=>xn,up:()=>Tn});import*as W from"fs";import*as Qt from"path";var xn=5,_n="rename-headline-to-title",te=/[·•]\s*(1st|2nd|3rd)\+?/i,Rn=e=>(e||"").replace(/\s+/g," ").trim(),me=e=>Rn(e).replace(/^[+·•\s]+/,"").replace(/[·•\s]+$/,"");function Dn(e){if(!W.existsSync(e))return null;let t=W.readFileSync(e,"utf-8");return t.charCodeAt(0)===65279&&(t=t.slice(1)),JSON.parse(t)}function In(e,t){let o=JSON.stringify(t),n=e+".tmp";try{W.writeFileSync(n,o)}catch(s){try{W.unlinkSync(n)}catch{}throw s}try{W.renameSync(n,e)}catch(s){try{W.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function Tn(e,t){let o=Qt.join(t,"discovered-people.json"),n=Dn(o);if(!n||typeof n!="object"){console.log(" discovered-people.json not found \u2014 nothing to migrate.");return}let s=Array.isArray(n)?n:Object.values(n),r=0,i=0,c=0;for(let l of s)if(!(!l||typeof l!="object")){if(r++,l.name&&te.test(l.name)){let a=me(String(l.name).split(te)[0]),u=String(l.name).match(/[·•]\s*(?:1st|2nd|3rd)\+?\s*(.+)$/i),d=u?me(u[1]):"";a&&(l.name=a,i++),d&&(!l.headline||te.test(String(l.headline))||!me(l.headline))&&(l.headline=d)}if(Object.prototype.hasOwnProperty.call(l,"headline")){let a=me(l.headline||"");te.test(a)&&(a=""),(!l.title||te.test(String(l.title)))&&(l.title=a||(l.title&&!te.test(String(l.title))?l.title:null)||null),delete l.headline,c++}else if(typeof l.title=="string"){let a=me(l.title);a&&!te.test(a)&&a!==l.title&&(l.title=a)}}if(c===0&&i===0){console.log(` Scanned ${r} discovered people \u2014 already unified (no headline field, clean names).`);return}In(o,n),console.log(` discovered-people.json: scanned ${r}, de-glued ${i} names, moved ${c} headline\u2192title.`),console.log(" Every record now carries a single `title` field (matches people.json).")}import"dotenv/config";import*as F from"path";import{fileURLToPath as On}from"url";var jn=On(import.meta.url),Nn=F.dirname(F.dirname(jn)),ge=process.env.DATA_DIR?F.resolve(process.env.DATA_DIR,"market-research"):F.join(Nn,"market-research"),gr=F.join(ge,"scouted-jobs.json"),hr=F.join(ge,"discovered-people.json"),yr=F.join(ge,"visit-log.json"),wr=F.join(ge,"companies.json"),Sr=F.join(ge,"job-decisions.json");function Xt(){Mn=null,Pn=null,Fn=null,Ln=null,Un=null}var Mn=null;var Pn=null;var Fn=null;var Ln=null;var Un=null;var qn=Bn(import.meta.url),Jn=x.dirname(qn),Wn=x.dirname(x.dirname(Jn));function Hn(e){return e&&(e==="~"?Ze.homedir():e.startsWith("~/")||e.startsWith("~\\")?x.join(Ze.homedir(),e.slice(2)):e)}var H=process.env.DATA_DIR?x.resolve(Hn(process.env.DATA_DIR)):Wn,ne=x.join(H,"collected-profiles"),se=x.join(H,"market-research"),N=x.join(H,".schema-version"),Zt=[x.join(ne,".schema-version"),x.join(se,".schema-version")],X=5,z=[{version:1,module:Ye},{version:2,module:Ge},{version:3,module:ze},{version:4,module:Ke},{version:5,module:Qe}];(function(){z.sort((n,s)=>n.version-s.version);let t=new Set;for(let n of z){if(!Number.isInteger(n.version)||n.version<1)throw new Error(`MIGRATION_REGISTRY: invalid version ${JSON.stringify(n.version)} (must be positive integer)`);if(t.has(n.version))throw new Error(`MIGRATION_REGISTRY: duplicate version v${n.version}`);t.add(n.version);let s=n.module;if(!s||typeof s.up!="function")throw new Error(`MIGRATION_REGISTRY: v${n.version} module is missing up()`);if(s.VERSION!==void 0&&s.VERSION!==n.version)throw new Error(`MIGRATION_REGISTRY: v${n.version} entry does not match module VERSION (${s.VERSION}). Drift between registry and module \u2014 pick one source of truth.`)}let o=z.length?z[z.length-1].version:0;if(o!==X)throw new Error(`MIGRATION_REGISTRY: highest version v${o} but CURRENT_SCHEMA_VERSION=${X}. Forgot to bump CURRENT_SCHEMA_VERSION when adding the new migration?`);for(let n=0;n<z.length;n++){let s=n+1;if(z[n].version!==s)throw new Error(`MIGRATION_REGISTRY: gap detected \u2014 expected v${s} at position ${n} but found v${z[n].version}`)}})();function no(){process.env.DATA_DIR!==void 0&&process.env.DATA_DIR.trim()===""&&process.env.DATA_DIR.length>0&&(console.error(`
9
+ \u2717 ${e}${m} failed: ${l.message||l}`)}let u=Date.now()-i.startTime,d=!l&&c.stoppedReason?String(c.stoppedReason):null;try{Ho(i,l?"error":d?"partial":"success",{...c,summaryLines:a,__deferReport:!0},l?l.message||String(l):null)}catch(m){console.error(`[runLog] endRun failed: ${m.message}`)}if(a.length>0&&process.env.NODE_RUN_REPORTS){let m=l?"error":d?"stopped":c.dailyLimitHit?"quota-reached":"done";try{await Fe({scriptName:i.script,mode:i.mode,status:m,summaryLines:a,error:l?l.message||String(l):null,stoppedReason:d,duration:u})}catch(g){console.error(`[runLog] report post failed: ${g.message}`)}}if(l&&r)throw l;return c}import Xo from"puppeteer";import{addExtra as Zo}from"puppeteer-extra";import en from"puppeteer-extra-plugin-stealth";import Be from"fs";import Vo from"path";var Yo={headless:!1,defaultViewport:null,protocolTimeout:3e5},pe=new Set,Ot=!1;async function be(){let e=[...pe].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});pe.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function Go(){if(Ot)return;Ot=!0;let e=t=>async()=>{await be(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await be(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await be(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await be(),process.exit(0))}),process.on("exit",()=>{for(let t of pe)try{let o=t.process&&t.process();o&&o.kill("SIGKILL")}catch{}})}function qe(e){return Vo.join(e,".ilml-browser-session.json")}function Pt(e,t={}){try{Be.writeFileSync(qe(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function zo(e,t){try{let o=t.wsEndpoint&&t.wsEndpoint();Pt(e,o?{wsEndpoint:o}:{})}catch{}}function Ko(e){let t=Ft(e);t&&t.ownerPid===process.pid&&de(e)}function de(e){try{Be.rmSync(qe(e),{force:!0})}catch{}}function Ft(e){try{return JSON.parse(Be.readFileSync(qe(e),"utf-8"))}catch{return null}}function jt(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function Nt(e,t,o){let n,s=new Promise(i=>{n=setTimeout(()=>i(o),t)}),r=Promise.resolve(e).then(i=>(clearTimeout(n),i),i=>{throw clearTimeout(n),i});return Promise.race([r,s])}async function Mt(e,t,{probeTimeoutMs:o=4e3}={}){let n=Ft(t);if(!n)return"free";if(!n.wsEndpoint)return n.ownerPid&&n.ownerPid!==process.pid&&jt(n.ownerPid)?"live":(de(t),"free");let s=Symbol("timeout"),r=e.connect({browserWSEndpoint:n.wsEndpoint,defaultViewport:null}).catch(()=>null),i=await Nt(r,o,s);if(i===s)return r.then(l=>{if(l)try{l.disconnect()}catch{}}),"live";if(!i)return de(t),"free";if(jt(n.ownerPid)){try{i.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await Nt(i.close().then(()=>!0).catch(()=>!1),o,!1))return de(t),"free";try{i.disconnect()}catch{}return"live"}function Qo(e,t){e&&(Go(),pe.add(e),e.on("disconnected",()=>{pe.delete(e),t&&de(t)}))}async function Lt(e,t={}){let o=dt(),n={...Yo,...t,userDataDir:o},s=`Could not open the LinkedIn automation Chrome profile at ${o}. 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 Mt(e,o)==="live")throw new Error(s);Pt(o);let r;try{r=await e.launch(n)}catch{if(await Mt(e,o)==="live")throw new Error(s);ht(o);try{r=await e.launch(n)}catch(c){throw Ko(o),new Error(`Could not open the LinkedIn automation Chrome profile at ${o}. If a LinkedIn automation window is already open, close it and retry. (Chrome: ${c.message})`)}}return Qo(r,o),zo(o,r),{browser:r,profileDir:o,needsSeed:mt(o)}}async function Ut(e,t){if(!t||!t.needsSeed)return!1;if(!ut())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(...at()),gt(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var Jt=Zo(Xo);Jt.use(en());async function Wt(){let{browser:e,profileDir:t,needsSeed:o}=await Lt(Jt),n=await e.newPage();return await n.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await Ut(n,{profileDir:t,needsSeed:o}),console.log(" Browser launched (persistent profile)."),{browser:e,page:n}}async function We(e){await we(e,"https://www.linkedin.com/messaging/",{readySelector:".msg-conversations-container__conversations-list, .msg-conversation-listitem",label:"inbox"})||(console.warn(" Inbox container not found via known selectors, proceeding..."),await E(3e3)),console.log(" Inbox loaded.")}async function Ht(e){let t=await e.evaluate(()=>{let o=document.querySelectorAll(".msg-conversation-listitem"),n=[];for(let s of o){let i=s.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||null;if(!i)continue;let l=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(l)||/^\s*Promoted\b/i.test(l))continue;let u=s.querySelector(".msg-conversation-listitem__time-stamp, .msg-conversation-card__time-stamp")?.textContent?.trim()||"",d=s.querySelector(".msg-conversation-card__convo-item-container--unread")!==null||s.querySelector(".msg-conversation-card__unread-count")!==null,m,g;if(l.startsWith("You:"))m="me",g=l.slice(4).trim();else{let f=i.split(" ")[0];if(l.startsWith(i+":")||l.startsWith(f+":")){m="them";let h=l.indexOf(":");g=l.slice(h+1).trim()}else m="them",g=l}let p=s.getBoundingClientRect();n.push({name:i,lastMessagePreview:g,lastMessageTime:u,unread:d,lastMessageBy:m,x:p.x+p.width/2,y:p.y+p.height/2})}return n});for(let o of t)o.lastMessageTime=Oe(o.lastMessageTime)||o.lastMessageTime;return t}async function Vt(e){return e.evaluate(()=>{let t=[".msg-conversations-container__conversations-list",".msg-conversations-container",'[class*="msg-conversations-container"] ul'];for(let n of t){let s=document.querySelector(n);if(s&&s.scrollHeight>s.clientHeight)return s.scrollBy(0,600),{scrollTop:s.scrollTop,scrollHeight:s.scrollHeight}}let o=document.querySelector(".msg-conversation-listitem");if(o){let n=o.parentElement;for(;n;){if(n.scrollHeight>n.clientHeight+10)return n.scrollBy(0,600),{scrollTop:n.scrollTop,scrollHeight:n.scrollHeight};n=n.parentElement}}return null})}async function tn(e){return e.evaluate(()=>{let t=/^status\s+is\s+|^online$|^offline$|^away$|^busy$|^active\s/i,o=['.msg-overlay-conversation-bubble__header a[href*="/in/"] .truncate','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header__title a[href*="/in/"]',".msg-overlay-bubble-header__title",".msg-overlay-conversation-bubble__header .truncate",".msg-thread__link-to-profile","h2.msg-entity-lockup__entity-title",".msg-s-message-list-container h2",".msg-thread h2",".msg-conversations-container__title-row h2",'.msg-thread a[href*="/in/"]'];for(let s of o){let r=document.querySelector(s);if(r){let i=r.textContent?.trim()?.replace(/\s+/g," ");if(i&&i.length>1&&i.length<100&&!t.test(i))return i}}let n=document.querySelectorAll(".msg-s-message-list-container h2, .msg-thread h2");for(let s of n){let r=s.textContent?.trim();if(r&&r.length>1&&r.length<100&&!/conversation/i.test(r)&&!t.test(r))return r}return null})}async function Bt(e,t){let o=await tn(e);if(!o)return{match:!1,headerName:null};let n=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(c=>c.length>1),r=o.toLowerCase();return{match:r.includes(n)||s.some(c=>r.includes(c)),headerName:o}}async function Je(e,t){let o=t.split(" ")[0],n=8e3,s=500,r=0;for(;r<n;){let{match:l,headerName:a}=await Bt(e,t);if(l)return await E(500),{verified:!0,headerName:a};let u=await e.evaluate(()=>{let d=document.querySelectorAll(".msg-s-message-group__name"),m=Array.from(d).map(p=>p.textContent?.trim()).filter(Boolean),g=document.querySelectorAll(".msg-s-event-listitem").length;return{allSenders:m,msgCount:g}});if(u.msgCount>0&&u.allSenders.some(m=>m.toLowerCase().includes(o.toLowerCase())))return await E(300),{verified:!0,headerName:o};await E(s),r+=s}let{match:i,headerName:c}=await Bt(e,t);return i?{verified:!0,headerName:c}:{verified:!1,headerName:c}}async function on(e){let o=0,n=0;for(let s=0;s<50;s++){let r=await e.evaluate(()=>{let i=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!i){let a=document.querySelector(".msg-overlay-conversation-bubble");a&&(i=a.querySelector(".msg-s-message-list-container")||a.querySelector(".msg-s-message-list"))}if(!i)return{found:!1};let c=i.querySelectorAll("li.msg-s-message-list__event").length;return i.scrollTop<=1?{found:!0,atTop:!0,msgCount:c}:(i.scrollTop=0,{found:!0,atTop:!1,msgCount:c})});if(!r.found||r.atTop)break;if(await E(800),r.msgCount===o){if(n++,n>=3)break}else n=0;o=r.msgCount}}async function ce(e,{scrollUp:t=!0}={}){t&&await on(e);let o=await e.evaluate(()=>{let n=[],s="",r=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!r){let u=document.querySelector(".msg-overlay-conversation-bubble");u&&(r=u.querySelector(".msg-s-message-list-container")||u.querySelector(".msg-s-message-list"))}if(!r)return n;let i=r.querySelectorAll("li.msg-s-message-list__event");if(i.length===0){let u=document.querySelector(".msg-overlay-conversation-bubble, .msg-overlay-list-bubble");u&&(i=u.querySelectorAll("li.msg-s-message-list__event, .msg-s-event-listitem"))}function c(u){let d=u.getAttribute("data-event-urn");if(!d)return null;let m=d.match(/,2-([A-Za-z0-9+/=]+)\)/);if(!m)return null;try{let p=atob(m[1]).match(/^(\d{13})/);if(!p)return null;let f=Number(p[1]);if(f>14200704e5&&f<20512224e5)return f}catch{}return null}let l="";function a(u,d,m){let g=c(u),f=u.querySelector(".msg-s-message-group__timestamp, time")?.textContent?.trim()||"",h=u.querySelector(".msg-s-event-listitem__message-bubble");if(!h)return null;let S=h.textContent?.trim()?.replace(/Open Emoji Keyboard|Reply to this message|React with[^.]+/g,"")?.replace(/^(?:👏\s*👍\s*😊\s*)+/,"")?.replace(/\s+/g," ")?.trim()||"";if(!S)return null;let y=g?new Date(g).toISOString():m?`${m} ${f}`.trim():f;return{sender:d,text:S,time:y}}for(let u of i){let d=u.querySelector("time.msg-s-message-list__time-heading");d&&(l=d.textContent?.trim()||l);let m=u.querySelectorAll(".msg-s-message-group");if(m.length>0)for(let g of m){let p=g.querySelector(".msg-s-message-group__name");p&&(s=p.textContent?.trim()||s);let f=s||"Unknown",h=g.querySelectorAll(".msg-s-event-listitem");for(let S of h){let y=a(S,f,l);y&&n.push(y)}}else{let g=u.querySelectorAll(".msg-s-event-listitem");for(let p of g){let f=p.querySelector(".msg-s-message-group__name");f&&(s=f.textContent?.trim()||s);let S=a(p,s||"Unknown",l);S&&n.push(S)}}}if(n.length===0){let u=document.querySelectorAll(".msg-s-event-listitem--group-a11y-heading");for(let d of u){let m=d.textContent?.trim();m&&n.push({sender:"",text:m,time:""})}}return n});for(let n of o)(!n.time||!/^\d{4}-\d{2}-\d{2}T/.test(n.time))&&(n.time=Oe(n.time)||n.time);return o}function le(e){return String(e||"").replace(/\s+/g," ").trim().toLowerCase()}function $e(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let o=m=>le(m.sender)+"||"+le(m.text).replace(/\s+/g,""),n=new Set(t.map(o)),s=new Set(e.map(o)),r=e.filter(m=>K.has(m.status)?!1:!n.has(o(m))),i=t.filter(m=>!s.has(o(m))),c=t.filter(m=>s.has(o(m))),l=e.filter(m=>K.has(m.status)),a=[...r,...c,...i],u=[];for(let m of a){let g=le(m.text),p=le(m.sender),f=!1;for(let h=0;h<u.length;h++){let S=u[h];if(le(S.sender)!==p||!S.time||!m.time||S.time!==m.time)continue;let y=le(S.text);if(g.length>y.length&&g.endsWith(y)){f=!0;break}if(y.length>g.length&&y.endsWith(g)){u[h]=m,f=!0;break}}f||u.push(m)}return[...u,...l]}async function ke(e,t){let o=await e.evaluate(i=>{let c=document.querySelectorAll(".msg-conversation-listitem");for(let l of c)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===i){let d=l.getBoundingClientRect();if(d.height>0)return{x:d.x+d.width/2,y:d.y+d.height/2}}return null},t);if(o){await e.mouse.click(o.x,o.y),await E(3e3);let i=await Je(e,t);if(i.verified)return i}let n=vt(t),s=n!==t?[t,n]:[t];for(let i of s)if(await qt(e,i,t)){let l=await Je(e,t);if(l.verified)return l}let r=bt(n);if(r!==n&&r.length>0&&await qt(e,r,t,{requireUnique:!0})){let c=await Je(e,t);if(c.verified)return c}return{verified:!1,headerName:null}}async function qt(e,t,o,n={}){let{requireUnique:s=!1}=n,r=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");if(!r)return!1;await r.click(),await E(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await E(300),await r.type(t,{delay:30}),await E(500),await e.keyboard.press("Enter"),await E(3500);let i=await e.evaluate((c,l)=>{let a=c.split(" ")[0].toLowerCase(),u=c.toLowerCase(),d=document.querySelectorAll(".msg-conversation-listitem"),m=[],g=[];for(let f of d){let S=f.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||"",y=S.toLowerCase();if(y.includes(a)){let $=f.getBoundingClientRect();if($.height>0){let w=S.includes(",")||/\d+ other/.test(S),R=y===u?3:y.includes(u)?2:1,_={text:S,isGroup:w,score:R,x:$.x+$.width/2,y:$.y+$.height/2};w?g.push(_):m.push(_)}}}m.sort((f,h)=>h.score-f.score);let p=[...m,...g];return l&&p.length!==1?null:m[0]||g[0]||null},o,s);return i?(s&&console.log(" (found via stripped designations)"),await e.mouse.click(i.x,i.y),!0):!1}async function Yt(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await E(200),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await e.keyboard.press("Escape"),await E(1e3))}import"dotenv/config";import*as v from"fs";import*as Ze from"os";import*as x from"path";import{fileURLToPath as Bn}from"url";var Ye={};ae(Ye,{NAME:()=>sn,VERSION:()=>nn,up:()=>cn});import*as U from"fs";import*as Ee from"path";var nn=1,sn="normalize-jobs-and-questions",rn=["description","techStack","jobTags","seniority","employmentType","industries","jobFunction","postedTime","applicantCount","companySize","workplaceType","contractType","isEasyApply","applyType","companyUrl","scoutedAt","lastSeen"],ln=50;function He(e){return U.existsSync(e)?JSON.parse(U.readFileSync(e,"utf-8")):null}function Ve(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{U.writeFileSync(n,o)}catch(s){try{U.unlinkSync(n)}catch{}throw s}try{U.renameSync(n,e)}catch(s){try{U.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function cn(e,t){let o=Ee.join(e,"jobs.json"),n=Ee.join(t,"scouted-jobs.json"),s=Ee.join(e,"application-questions.json"),r=He(o)||{},i=He(n)||{},c=0,l=[];for(let u of Object.keys(r)){if(!i[u])continue;let d=i[u],m=r[u];for(let g of rn)d[g]!=null&&m[g]==null&&(m[g]=d[g]);l.push(u),c++}c>0?(Ve(o,r),console.log(` Phase 1: Merged ${c} scouted jobs into jobs.json`)):console.log(" Phase 1: No overlapping jobs to merge");let a=He(s);if(a&&Array.isArray(a.applications)){let u={},d=0;for(let m of a.applications){let g=m.jobId||"unknown";u[g]||(u[g]={applications:[]});let p=(m.questions||[]).map(f=>{let h={type:f.type||"input",question:f.question||"",answer:f.answer||""};return f.options&&(f.options.length<=ln?h.options=f.options:(h.optionsOmitted=!0,d++)),f.page&&(h.page=f.page),f.wasPreFilled&&(h.wasPreFilled=!0),f.wasRetry&&(h.wasRetry=!0),h});u[g].applications.push({applicationId:m.applicationId,date:m.date,result:m.result||"submitted",formPages:m.formPages||null,duration:m.duration||null,retries:m.retries||0,failedField:m.failedField||null,questionCount:m.questionCount||p.length,questions:p})}Ve(s,u),console.log(` Phase 2: Rekeyed ${a.applications.length} applications by jobId (${Object.keys(u).length} unique jobs)`),d>0&&console.log(` Phase 2: Stripped bloated options from ${d} questions`)}else a&&!a.applications?console.log(" Phase 2: application-questions.json already in keyed format"):console.log(" Phase 2: No application-questions.json found");if(l.length>0){for(let u of l)delete i[u];Ve(n,i),console.log(` Phase 3: Removed ${l.length} merged entries from scouted-jobs.json (${Object.keys(i).length} remaining)`)}else console.log(" Phase 3: No entries to remove from scouted-jobs.json")}var Ge={};ae(Ge,{NAME:()=>un,VERSION:()=>an,up:()=>pn});import*as B from"fs";import*as Gt from"path";var an=2,un="reset-unread-flags";function fn(e){return B.existsSync(e)?JSON.parse(B.readFileSync(e,"utf-8")):null}function dn(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{B.writeFileSync(n,o)}catch(s){try{B.unlinkSync(n)}catch{}throw s}try{B.renameSync(n,e)}catch(s){try{B.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function pn(e){let t=Gt.join(e,"conversations.json"),o=fn(t);if(!o){console.log(" conversations.json not found \u2014 nothing to reset.");return}let n=0;for(let s of Object.keys(o))o[s].unread===!0&&(o[s].unread=!1,n++);if(n===0){console.log(" No stale unread flags found \u2014 nothing to do.");return}dn(t,o),console.log(` Reset unread=false on ${n} conversations. Run 'ilml linkedin sync-all' to re-establish real unread state from LinkedIn.`)}var ze={};ae(ze,{NAME:()=>gn,VERSION:()=>mn,up:()=>vn});import*as q from"fs";import*as zt from"path";var mn=3,gn="recompute-last-message-by",hn=new Set(["draft","confirmed","rejected","needs_review"]);function yn(e){return q.existsSync(e)?JSON.parse(q.readFileSync(e,"utf-8")):null}function wn(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{q.writeFileSync(n,o)}catch(s){try{q.unlinkSync(n)}catch{}throw s}try{q.renameSync(n,e)}catch(s){try{q.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}function Sn(e,t){if(!e||e.length===0)return"them";let o=e.filter(r=>!hn.has(r.status));if(o.length===0)return"them";let n=o.map(r=>({m:r,t:Date.parse(r.time)})).filter(r=>Number.isFinite(r.t)).sort((r,i)=>i.t-r.t).map(r=>r.m),s=n.length>0?n:[...o].reverse();for(let r of s){let i=r.sender;if(i===t)return"me";if(i!=="Unknown"&&i!=="")return"them"}return"them"}async function vn(e){let t=zt.join(e,"conversations.json"),o=yn(t);if(!o){console.log(" conversations.json not found \u2014 nothing to recompute.");return}let n=process.env.LINKEDIN_NAME;if(!n||typeof n!="string"||!n.trim())throw new Error(`LINKEDIN_NAME env var is not set. Migration v003 needs your display name to determine which messages are yours vs theirs. Set LINKEDIN_NAME in your .env (or run "ilml plugin config linkedin set LINKEDIN_NAME 'Your Name'") and retry.`);let s=0,r=0,i=0;for(let c of Object.keys(o)){let l=o[c];if(!l||typeof l!="object")continue;Object.prototype.hasOwnProperty.call(l,"_cardSynced")&&(delete l._cardSynced,r++);let a=Array.isArray(l.messages)?l.messages:[],u=Sn(a,n),d=u==="me"?"awaiting_reply":"unanswered_by_us";l.lastMessageBy!==u&&i++,l.lastMessageBy=u,l.conversationStatus=d,s++}if(s===0){console.log(" No conversations to recompute.");return}wn(t,o),console.log(` Recomputed lastMessageBy + conversationStatus on ${s} conversations.`),console.log(` ${i} had stale lastMessageBy (now corrected).`),r>0&&console.log(` Cleaned ${r} leftover _cardSynced flags.`),console.log(" Re-run 'ilml linkedin enrich' if you want actionNeeded / summary / autoTags to also update.")}var Ke={};ae(Ke,{NAME:()=>$n,VERSION:()=>bn,up:()=>Cn});import*as J from"fs";import*as Kt from"path";var bn=4,$n="split-connection-timestamps",kn=new Set(["pending","sent_without_note","sent_with_note","sent_without_note_upsell"]);function En(e){if(!J.existsSync(e))return null;let t=J.readFileSync(e,"utf-8");return t.charCodeAt(0)===65279&&(t=t.slice(1)),JSON.parse(t)}function An(e,t){let o=JSON.stringify(t,null,2),n=e+".tmp";try{J.writeFileSync(n,o)}catch(s){try{J.unlinkSync(n)}catch{}throw s}try{J.renameSync(n,e)}catch(s){try{J.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function Cn(e){let t=Kt.join(e,"people.json"),o=En(t);if(!o||typeof o!="object"){console.log(" people.json not found \u2014 nothing to migrate.");return}let n=0,s=0;for(let r of Object.keys(o)){let i=o[r];!i||typeof i!="object"||(s++,kn.has(i.connectionStatus)&&i.connectionDate&&!i.requestedConnectionAt&&(i.requestedConnectionAt=i.connectionDate,i.connectionDate=null,n++))}if(n===0){console.log(` Scanned ${s} people \u2014 none needed the connectionDate\u2192requestedConnectionAt move.`);return}An(t,o),console.log(` Moved connectionDate \u2192 requestedConnectionAt on ${n} still-pending people (of ${s} scanned).`),console.log(' connectionDate now means "accepted on" only; requestedConnectionAt means "requested on".')}var Qe={};ae(Qe,{NAME:()=>_n,VERSION:()=>xn,up:()=>Tn});import*as W from"fs";import*as Qt from"path";var xn=5,_n="rename-headline-to-title",te=/[·•]\s*(1st|2nd|3rd)\+?/i,Rn=e=>(e||"").replace(/\s+/g," ").trim(),me=e=>Rn(e).replace(/^[+·•\s]+/,"").replace(/[·•\s]+$/,"");function Dn(e){if(!W.existsSync(e))return null;let t=W.readFileSync(e,"utf-8");return t.charCodeAt(0)===65279&&(t=t.slice(1)),JSON.parse(t)}function In(e,t){let o=JSON.stringify(t),n=e+".tmp";try{W.writeFileSync(n,o)}catch(s){try{W.unlinkSync(n)}catch{}throw s}try{W.renameSync(n,e)}catch(s){try{W.unlinkSync(n)}catch{}if(s.code==="EPERM"||s.code==="EBUSY"){let r=new Error(`File locked: ${e} (${s.code}). On Windows usually antivirus / file explorer / open editor. Close it and re-run.`);throw r.code=s.code,r}throw s}}async function Tn(e,t){let o=Qt.join(t,"discovered-people.json"),n=Dn(o);if(!n||typeof n!="object"){console.log(" discovered-people.json not found \u2014 nothing to migrate.");return}let s=Array.isArray(n)?n:Object.values(n),r=0,i=0,c=0;for(let l of s)if(!(!l||typeof l!="object")){if(r++,l.name&&te.test(l.name)){let a=me(String(l.name).split(te)[0]),u=String(l.name).match(/[·•]\s*(?:1st|2nd|3rd)\+?\s*(.+)$/i),d=u?me(u[1]):"";a&&(l.name=a,i++),d&&(!l.headline||te.test(String(l.headline))||!me(l.headline))&&(l.headline=d)}if(Object.prototype.hasOwnProperty.call(l,"headline")){let a=me(l.headline||"");te.test(a)&&(a=""),(!l.title||te.test(String(l.title)))&&(l.title=a||(l.title&&!te.test(String(l.title))?l.title:null)||null),delete l.headline,c++}else if(typeof l.title=="string"){let a=me(l.title);a&&!te.test(a)&&a!==l.title&&(l.title=a)}}if(c===0&&i===0){console.log(` Scanned ${r} discovered people \u2014 already unified (no headline field, clean names).`);return}In(o,n),console.log(` discovered-people.json: scanned ${r}, de-glued ${i} names, moved ${c} headline\u2192title.`),console.log(" Every record now carries a single `title` field (matches people.json).")}import"dotenv/config";import*as F from"path";import{fileURLToPath as On}from"url";var jn=On(import.meta.url),Nn=F.dirname(F.dirname(jn)),ge=process.env.DATA_DIR?F.resolve(process.env.DATA_DIR,"market-research"):F.join(Nn,"market-research"),gr=F.join(ge,"scouted-jobs.json"),hr=F.join(ge,"discovered-people.json"),yr=F.join(ge,"visit-log.json"),wr=F.join(ge,"companies.json"),Sr=F.join(ge,"job-decisions.json");function Xt(){Mn=null,Pn=null,Fn=null,Ln=null,Un=null}var Mn=null;var Pn=null;var Fn=null;var Ln=null;var Un=null;var qn=Bn(import.meta.url),Jn=x.dirname(qn),Wn=x.dirname(x.dirname(Jn));function Hn(e){return e&&(e==="~"?Ze.homedir():e.startsWith("~/")||e.startsWith("~\\")?x.join(Ze.homedir(),e.slice(2)):e)}var H=process.env.DATA_DIR?x.resolve(Hn(process.env.DATA_DIR)):Wn,ne=x.join(H,"collected-profiles"),se=x.join(H,"market-research"),N=x.join(H,".schema-version"),Zt=[x.join(ne,".schema-version"),x.join(se,".schema-version")],X=5,z=[{version:1,module:Ye},{version:2,module:Ge},{version:3,module:ze},{version:4,module:Ke},{version:5,module:Qe}];(function(){z.sort((n,s)=>n.version-s.version);let t=new Set;for(let n of z){if(!Number.isInteger(n.version)||n.version<1)throw new Error(`MIGRATION_REGISTRY: invalid version ${JSON.stringify(n.version)} (must be positive integer)`);if(t.has(n.version))throw new Error(`MIGRATION_REGISTRY: duplicate version v${n.version}`);t.add(n.version);let s=n.module;if(!s||typeof s.up!="function")throw new Error(`MIGRATION_REGISTRY: v${n.version} module is missing up()`);if(s.VERSION!==void 0&&s.VERSION!==n.version)throw new Error(`MIGRATION_REGISTRY: v${n.version} entry does not match module VERSION (${s.VERSION}). Drift between registry and module \u2014 pick one source of truth.`)}let o=z.length?z[z.length-1].version:0;if(o!==X)throw new Error(`MIGRATION_REGISTRY: highest version v${o} but CURRENT_SCHEMA_VERSION=${X}. Forgot to bump CURRENT_SCHEMA_VERSION when adding the new migration?`);for(let n=0;n<z.length;n++){let s=n+1;if(z[n].version!==s)throw new Error(`MIGRATION_REGISTRY: gap detected \u2014 expected v${s} at position ${n} but found v${z[n].version}`)}})();function no(){process.env.DATA_DIR!==void 0&&process.env.DATA_DIR.trim()===""&&process.env.DATA_DIR.length>0&&(console.error(`
10
10
  [FATAL] DATA_DIR is set to whitespace ("${process.env.DATA_DIR}"). Either unset it or set a real path.
11
11
  `),process.exit(1));try{v.mkdirSync(H,{recursive:!0})}catch(t){t.code!=="EEXIST"&&(console.error(`
12
12
  [FATAL] Cannot create DATA_DIR (${H}): ${t.message}`),console.error(` Fix the path or permissions and try again.
package/dist/syncAll.mjs CHANGED
@@ -245,7 +245,7 @@ function findEntryContainer(root) {
245
245
  \u26A0 Browser disconnected \u2014 aborting funnel`);break}if(!w.profileUrl){console.log(`[${m+1}/${t.length}] Skipping - no URL`);continue}let g=Ro(w.profileUrl);if(g==="pending"||g==="connected"||g==="sent_with_note"||g==="sent_without_note"||g==="sent_without_note_upsell"){console.log(`[${m+1}/${t.length}] ${w.name||w.profileUrl} \u2014 skipped (db: ${g})`),g==="pending"||g==="sent_with_note"||g==="sent_without_note"||g==="sent_without_note_upsell"?f.skipped.pending++:f.skipped.connected++,a&&await a(w,f,{success:!1,reason:g,connectionSent:!1,withCustomMessage:!1,messageSent:null,method:null,error:null,profileInfo:null});continue}console.log(`[${m+1}/${t.length}] ${w.name||w.profileUrl}`);let b=null;if(r){let y=await Un(e,w.profileUrl);y?(Ie(w.profileUrl,{...y,source:u}),f.viewed++,b={success:!0,reason:"viewed",connectionSent:!1,profileInfo:y,resolvedUrl:y.resolvedUrl}):(f.errors++,b={success:!1,reason:"view_failed",connectionSent:!1,profileInfo:null})}else{if(f.connectionsSent>=i){console.log(` Max connections per session (${i}) reached`);break}let y=sn();if(!y.allowed){console.log(` \u26A0 Global quota exhausted: ${y.reason}`);break}if(b=await Bn(e,w.profileUrl,{message:o,useCustomMessage:s,excludeLocations:l,source:u,skipQuotaGate:!0}),b.success)f.connectionsSent++;else switch(b.reason){case"pending":f.skipped.pending++;break;case"connected":f.skipped.connected++;break;case"email_required":f.skipped.email++;break;case"button_not_found":f.skipped.notFound++;break;case"excluded_location":f.skipped.excludedLocation++;break;default:f.errors++}}if(b?.fatal){console.log(`
246
246
  \u26A0 Fatal error \u2014 page is dead, aborting funnel`),f.errors++;break}if(b?.reason==="error"){if(d++,d>=3){console.log(`
247
247
  \u26A0 ${d} consecutive errors \u2014 aborting funnel`);break}}else d=0;if(b&&b.reason&&(To(w.profileUrl,b.reason,{method:b.method,messageSent:b.messageSent,profileInfo:b.profileInfo}),b.resolvedUrl&&Nt(w.profileUrl,b.resolvedUrl),xo(w.profileUrl,{source:u||"funnel",jobId:w.jobId||w.fromJob?.jobId||null,jobTitle:w.fromJob?.title||null,jobCompany:w.fromJob?.company||null,action:b.reason})),a&&await a(w,f,b),m<t.length-1){let y=c+Math.random()*2e3;await k(y)}}if(console.log(`
248
- === Funnel Complete ===`),console.log(` Viewed: ${f.viewed}`),console.log(` Connections sent: ${f.connectionsSent}`),console.log(` Skipped (pending): ${f.skipped.pending}`),console.log(` Skipped (connected): ${f.skipped.connected}`),console.log(` Skipped (email req): ${f.skipped.email}`),console.log(` Skipped (not found): ${f.skipped.notFound}`),f.skipped.excludedLocation>0&&console.log(` Skipped (excluded location): ${f.skipped.excludedLocation}`),console.log(` Errors: ${f.errors}`),!r){let m=dt();console.log(` Connection quota left: today ${m.daily.remaining} of ${m.daily.max} | week ${m.weekly.remaining} of ${m.weekly.max}`)}return f}var La,Js=Z(async()=>{qe();await Ye();La={viewProfile:Un,detectConnectionStatus:Ee,findConnectButton:xt,clickConnectButton:qn,sendConnectionRequest:Bn,runFunnel:Bs,shouldExcludeLocation:Gt}});qe();await Ye();St();await Ye();St();var Wr=new Set(["java","c#",".net","scala","python","typescript","javascript","react","node.js","aws","azure","docker","kubernetes","microservices","graphql","rest","sql","postgresql","mongodb","kafka","redis","ci/cd","terraform","spring"]),Yr=new Set(["iot","machine learning","ai","data engineering","spark","go","rust","kotlin","next.js","devops","sre"]),Wo=["vancouver","british columbia"],Gr=["canada","montreal","quebec","alberta","calgary","ottawa"],zr=["toronto","ontario"],Kr=["india","pakistan","nigeria","philippines"];function Qr(e,t={}){let n=0,o=(e.techStack||[]).map(u=>u.toLowerCase()),s=0,i=0;for(let u of o)Wr.has(u)&&s++,Yr.has(u)&&i++;if(n+=Math.min(s*6,24),n+=Math.min(i*3,6),e.salary){let u=Xr(e.salary);u&&(u>=15e4?n+=20:u>=12e4?n+=15:u>=1e5?n+=10:u>=8e4?n+=5:u>=100&&u<1e3?n+=15:u>=70&&u<1e3&&(n+=10))}let r=(e.location||"").toLowerCase(),c=/remote/i.test(r)||e.workplaceType==="remote";Kr.some(u=>r.includes(u))?n-=30:c&&/united states|usa|\bus\b/i.test(r)?n+=25:c&&Wo.some(u=>r.includes(u))?n+=22:c?n+=20:Wo.some(u=>r.includes(u))?n+=18:Gr.some(u=>r.includes(u))?n+=10:zr.some(u=>r.includes(u))&&(n+=5),e.isEasyApply&&(n+=5);let a=(e.seniority||"").toLowerCase();a.includes("senior")||a.includes("lead")||a.includes("staff")?n+=10:a.includes("mid")?n+=5:(a.includes("entry")||a.includes("intern"))&&(n-=10),e.recruiterUrl&&(t.conversationRecruiters?.has(e.recruiterUrl)?n+=20:t.connectedRecruiters?.has(e.recruiterUrl)?n+=15:n+=3);let l=new Set(e.jobTags||[]);return l.has("managerial")?n+=8:l.has("senior-ic")&&(n+=5),l.has("junior")&&(n-=15),l.has("consultant")&&(n-=3),Math.max(0,Math.min(100,n))}function Yo(e=10,t={}){let{easyApplyOnly:n=!0}=t,o=yt(),s=V(),i=new Set,r=new Set;for(let[f,d]of Object.entries(s))d.connectionStatus==="connected"&&i.add(f);let c={connectedRecruiters:i,conversationRecruiters:r},a=wt(),l=new Set(["applied","skipped","expired","archived"]);return Object.entries(o).filter(([f,d])=>{if(typeof d!="object"||n&&!d.isEasyApply||d.applied)return!1;let m=a[f];return!(m&&l.has(m.status))}).map(([f,d])=>({jobId:f,score:Qr(d,c),job:d})).sort((f,d)=>{if(d.score!==f.score)return d.score-f.score;let m=f.job.scoutedAt||f.job.postedTime||"";return(d.job.scoutedAt||d.job.postedTime||"").localeCompare(m)}).slice(0,e)}function Xr(e){if(!e)return null;let t=e.match(/[\$£€CAD\s]*([\d,]+(?:\.\d+)?)\s*[kK]?/g);if(!t||t.length===0)return null;let n=t.map(o=>{let s=parseFloat(o.replace(/[^\d.]/g,""));return o.toLowerCase().includes("k")&&(s*=1e3),s}).filter(o=>o>0);return n.length>=2?(n[0]+n[1])/2:n.length===1?n[0]:null}await rt();import ri from"puppeteer";import{addExtra as ii}from"puppeteer-extra";import ai from"puppeteer-extra-plugin-stealth";qe();await rt();nt();nt();import pn from"fs";import Zr from"path";var ei={headless:!1,defaultViewport:null,protocolTimeout:3e5},kt=new Set,Go=!1;async function Ft(){let e=[...kt].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});kt.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function ti(){if(Go)return;Go=!0;let e=t=>async()=>{await Ft(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await Ft(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await Ft(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await Ft(),process.exit(0))}),process.on("exit",()=>{for(let t of kt)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function gn(e){return Zr.join(e,".ilml-browser-session.json")}function Xo(e,t={}){try{pn.writeFileSync(gn(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function ni(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();Xo(e,n?{wsEndpoint:n}:{})}catch{}}function oi(e){let t=Zo(e);t&&t.ownerPid===process.pid&&vt(e)}function vt(e){try{pn.rmSync(gn(e),{force:!0})}catch{}}function Zo(e){try{return JSON.parse(pn.readFileSync(gn(e),"utf-8"))}catch{return null}}function zo(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function Ko(e,t,n){let o,s=new Promise(r=>{o=setTimeout(()=>r(n),t)}),i=Promise.resolve(e).then(r=>(clearTimeout(o),r),r=>{throw clearTimeout(o),r});return Promise.race([i,s])}async function Qo(e,t,{probeTimeoutMs:n=4e3}={}){let o=Zo(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&zo(o.ownerPid)?"live":(vt(t),"free");let s=Symbol("timeout"),i=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await Ko(i,n,s);if(r===s)return i.then(a=>{if(a)try{a.disconnect()}catch{}}),"live";if(!r)return vt(t),"free";if(zo(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await Ko(r.close().then(()=>!0).catch(()=>!1),n,!1))return vt(t),"free";try{r.disconnect()}catch{}return"live"}function si(e,t){e&&(ti(),kt.add(e),e.on("disconnected",()=>{kt.delete(e),t&&vt(t)}))}async function es(e,t={}){let n=so(),o={...ei,...t,userDataDir:n},s=`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 Qo(e,n)==="live")throw new Error(s);Xo(n);let i;try{i=await e.launch(o)}catch{if(await Qo(e,n)==="live")throw new Error(s);lo(n);try{i=await e.launch(o)}catch(c){throw oi(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: ${c.message})`)}}return si(i,n),ni(n,i),{browser:i,profileDir:n,needsSeed:io(n)}}async function ts(e,t){if(!t||!t.needsSeed)return!1;if(!no())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(...It()),ao(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var ss=ii(ri);ss.use(ai());async function rs(){let{browser:e,profileDir:t,needsSeed:n}=await es(ss),o=await e.newPage();return await o.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await ts(o,{profileDir:t,needsSeed:n}),console.log(" Browser launched (persistent profile)."),{browser:e,page:o}}async function hn(e){await be(e,"https://www.linkedin.com/messaging/",{readySelector:".msg-conversations-container__conversations-list, .msg-conversation-listitem",label:"inbox"})||(console.warn(" Inbox container not found via known selectors, proceeding..."),await k(3e3)),console.log(" Inbox loaded.")}async function is(e){let t=await e.evaluate(()=>{let n=document.querySelectorAll(".msg-conversation-listitem"),o=[];for(let s of n){let r=s.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||null;if(!r)continue;let a=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(a)||/^\s*Promoted\b/i.test(a))continue;let u=s.querySelector(".msg-conversation-listitem__time-stamp, .msg-conversation-card__time-stamp")?.textContent?.trim()||"",f=s.querySelector(".msg-conversation-card__convo-item-container--unread")!==null||s.querySelector(".msg-conversation-card__unread-count")!==null,d,m;if(a.startsWith("You:"))d="me",m=a.slice(4).trim();else{let g=r.split(" ")[0];if(a.startsWith(r+":")||a.startsWith(g+":")){d="them";let b=a.indexOf(":");m=a.slice(b+1).trim()}else d="them",m=a}let w=s.getBoundingClientRect();o.push({name:r,lastMessagePreview:m,lastMessageTime:u,unread:f,lastMessageBy:d,x:w.x+w.width/2,y:w.y+w.height/2})}return o});for(let n of t)n.lastMessageTime=en(n.lastMessageTime)||n.lastMessageTime;return t}async function yn(e){return e.evaluate(()=>{let t=[".msg-conversations-container__conversations-list",".msg-conversations-container",'[class*="msg-conversations-container"] ul'];for(let o of t){let s=document.querySelector(o);if(s&&s.scrollHeight>s.clientHeight)return s.scrollBy(0,600),{scrollTop:s.scrollTop,scrollHeight:s.scrollHeight}}let n=document.querySelector(".msg-conversation-listitem");if(n){let o=n.parentElement;for(;o;){if(o.scrollHeight>o.clientHeight+10)return o.scrollBy(0,600),{scrollTop:o.scrollTop,scrollHeight:o.scrollHeight};o=o.parentElement}}return null})}async function li(e){return e.evaluate(()=>{let t=/^status\s+is\s+|^online$|^offline$|^away$|^busy$|^active\s/i,n=['.msg-overlay-conversation-bubble__header a[href*="/in/"] .truncate','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header__title a[href*="/in/"]',".msg-overlay-bubble-header__title",".msg-overlay-conversation-bubble__header .truncate",".msg-thread__link-to-profile","h2.msg-entity-lockup__entity-title",".msg-s-message-list-container h2",".msg-thread h2",".msg-conversations-container__title-row h2",'.msg-thread a[href*="/in/"]'];for(let s of n){let i=document.querySelector(s);if(i){let r=i.textContent?.trim()?.replace(/\s+/g," ");if(r&&r.length>1&&r.length<100&&!t.test(r))return r}}let o=document.querySelectorAll(".msg-s-message-list-container h2, .msg-thread h2");for(let s of o){let i=s.textContent?.trim();if(i&&i.length>1&&i.length<100&&!/conversation/i.test(i)&&!t.test(i))return i}return null})}async function wn(e){return e.evaluate(()=>{let t=[".msg-thread__link-to-profile",'.msg-entity-lockup__entity-title a[href*="/in/"]','.msg-s-message-list-container a[href*="/in/"]','.msg-thread a[href*="/in/"]','.msg-conversations-container__title-row a[href*="/in/"]','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header a[href*="/in/"]','.msg-overlay-conversation-bubble a[href*="/in/"]'];for(let n of t){let o=document.querySelector(n);if(o){let s=o.getAttribute("href")||"";if(s&&s.includes("/in/"))return s.startsWith("/")&&(s="https://www.linkedin.com"+s),s=s.replace(/\/$/,"").split("?")[0],s}}return null})}async function ns(e,t){let n=await li(e);if(!n)return{match:!1,headerName:null};let o=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(c=>c.length>1),i=n.toLowerCase();return{match:i.includes(o)||s.some(c=>i.includes(c)),headerName:n}}async function Ut(e,t){let n=t.split(" ")[0],o=8e3,s=500,i=0;for(;i<o;){let{match:a,headerName:l}=await ns(e,t);if(a)return await k(500),{verified:!0,headerName:l};let u=await e.evaluate(()=>{let f=document.querySelectorAll(".msg-s-message-group__name"),d=Array.from(f).map(w=>w.textContent?.trim()).filter(Boolean),m=document.querySelectorAll(".msg-s-event-listitem").length;return{allSenders:d,msgCount:m}});if(u.msgCount>0&&u.allSenders.some(d=>d.toLowerCase().includes(n.toLowerCase())))return await k(300),{verified:!0,headerName:n};await k(s),i+=s}let{match:r,headerName:c}=await ns(e,t);return r?{verified:!0,headerName:c}:{verified:!1,headerName:c}}async function ci(e){let n=0,o=0;for(let s=0;s<50;s++){let i=await e.evaluate(()=>{let r=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!r){let l=document.querySelector(".msg-overlay-conversation-bubble");l&&(r=l.querySelector(".msg-s-message-list-container")||l.querySelector(".msg-s-message-list"))}if(!r)return{found:!1};let c=r.querySelectorAll("li.msg-s-message-list__event").length;return r.scrollTop<=1?{found:!0,atTop:!0,msgCount:c}:(r.scrollTop=0,{found:!0,atTop:!1,msgCount:c})});if(!i.found||i.atTop)break;if(await k(800),i.msgCount===n){if(o++,o>=3)break}else o=0;n=i.msgCount}}async function bn(e,{scrollUp:t=!0}={}){t&&await ci(e);let n=await e.evaluate(()=>{let o=[],s="",i=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!i){let u=document.querySelector(".msg-overlay-conversation-bubble");u&&(i=u.querySelector(".msg-s-message-list-container")||u.querySelector(".msg-s-message-list"))}if(!i)return o;let r=i.querySelectorAll("li.msg-s-message-list__event");if(r.length===0){let u=document.querySelector(".msg-overlay-conversation-bubble, .msg-overlay-list-bubble");u&&(r=u.querySelectorAll("li.msg-s-message-list__event, .msg-s-event-listitem"))}function c(u){let f=u.getAttribute("data-event-urn");if(!f)return null;let d=f.match(/,2-([A-Za-z0-9+/=]+)\)/);if(!d)return null;try{let w=atob(d[1]).match(/^(\d{13})/);if(!w)return null;let g=Number(w[1]);if(g>14200704e5&&g<20512224e5)return g}catch{}return null}let a="";function l(u,f,d){let m=c(u),g=u.querySelector(".msg-s-message-group__timestamp, time")?.textContent?.trim()||"",b=u.querySelector(".msg-s-event-listitem__message-bubble");if(!b)return null;let y=b.textContent?.trim()?.replace(/Open Emoji Keyboard|Reply to this message|React with[^.]+/g,"")?.replace(/^(?:👏\s*👍\s*😊\s*)+/,"")?.replace(/\s+/g," ")?.trim()||"";if(!y)return null;let S=m?new Date(m).toISOString():d?`${d} ${g}`.trim():g;return{sender:f,text:y,time:S}}for(let u of r){let f=u.querySelector("time.msg-s-message-list__time-heading");f&&(a=f.textContent?.trim()||a);let d=u.querySelectorAll(".msg-s-message-group");if(d.length>0)for(let m of d){let w=m.querySelector(".msg-s-message-group__name");w&&(s=w.textContent?.trim()||s);let g=s||"Unknown",b=m.querySelectorAll(".msg-s-event-listitem");for(let y of b){let S=l(y,g,a);S&&o.push(S)}}else{let m=u.querySelectorAll(".msg-s-event-listitem");for(let w of m){let g=w.querySelector(".msg-s-message-group__name");g&&(s=g.textContent?.trim()||s);let y=l(w,s||"Unknown",a);y&&o.push(y)}}}if(o.length===0){let u=document.querySelectorAll(".msg-s-event-listitem--group-a11y-heading");for(let f of u){let d=f.textContent?.trim();d&&o.push({sender:"",text:d,time:""})}}return o});for(let o of n)(!o.time||!/^\d{4}-\d{2}-\d{2}T/.test(o.time))&&(o.time=en(o.time)||o.time);return n}function Sn(e,t,n){if(e.length===0)return!0;let o=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(l=>l.length>1),i=[...new Set(e.map(l=>l.sender).filter(l=>l&&l!=="Unknown"))],r=i.some(l=>{let u=l.toLowerCase();return u.includes(o)||s.some(f=>u.includes(f))}),c=K.toLowerCase().split(/\s+/),a=i.every(l=>{let u=l.toLowerCase();return c.some(f=>u.includes(f))});if(r)return!0;if(a){for(let l of e){let f=(l.text||"").trim().match(/^(?:Hi|Hey|Hello|Dear)\s+([A-Z][a-z]+)/);if(f){let d=f[1].toLowerCase();if(d!=="there"&&d!=="all"&&!(s.some(w=>w===d)||d===o))return console.log(` STALE DATA: message says "Hi ${f[1]}" but expected "${t}"`),!1}}return!0}if(n?.length>0){let l=n.map(f=>f.toLowerCase());if(i.some(f=>{let d=f.toLowerCase();return l.some(m=>d.includes(m.split(" ")[0]))}))return console.log(` STALE DATA: messages belong to previous conversation (senders: ${i.join(", ")})`),!1}return console.log(` Sender warning: no match for "${t}" (found: ${i.join(", ")})`),!1}function Ke(e){return String(e||"").replace(/\s+/g," ").trim().toLowerCase()}function vn(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let n=d=>Ke(d.sender)+"||"+Ke(d.text).replace(/\s+/g,""),o=new Set(t.map(n)),s=new Set(e.map(n)),i=e.filter(d=>Be.has(d.status)?!1:!o.has(n(d))),r=t.filter(d=>!s.has(n(d))),c=t.filter(d=>s.has(n(d))),a=e.filter(d=>Be.has(d.status)),l=[...i,...c,...r],u=[];for(let d of l){let m=Ke(d.text),w=Ke(d.sender),g=!1;for(let b=0;b<u.length;b++){let y=u[b];if(Ke(y.sender)!==w)continue;let S=Ke(y.text);if(m.length>S.length&&m.endsWith(S)){g=!0;break}if(S.length>m.length&&S.endsWith(m)){u[b]=d,g=!0;break}}g||u.push(d)}return[...u,...a]}async function as(e,t){await hn(e),await k(2500),await e.evaluate(()=>{let c=[".msg-conversations-container__conversations-list",".msg-conversations-container"];for(let a of c){let l=document.querySelector(a);if(l){l.scrollTop=0;return}}}),await k(500);async function n(){return e.evaluate(c=>{let a=document.querySelectorAll(".msg-conversation-listitem");for(let l of a)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===c){let d=l.getBoundingClientRect();if(d.height>0)return{x:d.x+d.width/2,y:d.y+d.height/2}}return null},t)}let o=await n(),s=50,i=-1,r=0;for(let c=0;c<s&&!o;c++){let a=await yn(e);if(!a)break;if(a.scrollTop===i){if(r++,r>=2)break}else r=0,i=a.scrollTop;await k(600),o=await n()}return o?(await e.mouse.click(o.x,o.y),await k(3e3),Ut(e,t)):{verified:!1,headerName:null}}async function kn(e,t){let n=await e.evaluate(r=>{let c=document.querySelectorAll(".msg-conversation-listitem");for(let a of c)if(a.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===r){let f=a.getBoundingClientRect();if(f.height>0)return{x:f.x+f.width/2,y:f.y+f.height/2}}return null},t);if(n){await e.mouse.click(n.x,n.y),await k(3e3);let r=await Ut(e,t);if(r.verified)return r}let o=mo(t),s=o!==t?[t,o]:[t];for(let r of s)if(await os(e,r,t)){let a=await Ut(e,t);if(a.verified)return a}let i=po(o);if(i!==o&&i.length>0&&await os(e,i,t,{requireUnique:!0})){let c=await Ut(e,t);if(c.verified)return c}return{verified:!1,headerName:null}}async function os(e,t,n,o={}){let{requireUnique:s=!1}=o,i=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");if(!i)return!1;await i.click(),await k(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await k(300),await i.type(t,{delay:30}),await k(500),await e.keyboard.press("Enter"),await k(3500);let r=await e.evaluate((c,a)=>{let l=c.split(" ")[0].toLowerCase(),u=c.toLowerCase(),f=document.querySelectorAll(".msg-conversation-listitem"),d=[],m=[];for(let g of f){let y=g.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||"",S=y.toLowerCase();if(S.includes(l)){let h=g.getBoundingClientRect();if(h.height>0){let p=y.includes(",")||/\d+ other/.test(y),v=S===u?3:S.includes(u)?2:1,C={text:y,isGroup:p,score:v,x:h.x+h.width/2,y:h.y+h.height/2};p?m.push(C):d.push(C)}}}d.sort((g,b)=>b.score-g.score);let w=[...d,...m];return a&&w.length!==1?null:d[0]||m[0]||null},n,s);return r?(s&&console.log(" (found via stripped designations)"),await e.mouse.click(r.x,r.y),!0):!1}async function $e(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await k(200),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await e.keyboard.press("Escape"),await k(1e3))}await En();import"dotenv/config";import*as oe from"fs";import*as Ce from"path";import{fileURLToPath as xi}from"url";import"dotenv/config";import{createGraphClient as vi,resolveToken as ki}from"@ilivemylife/graph-sdk";import{config as $i}from"dotenv";$i();var ws=ki()||process.env.TOKEN;ws||(console.error(`
248
+ === Funnel Complete ===`),console.log(` Viewed: ${f.viewed}`),console.log(` Connections sent: ${f.connectionsSent}`),console.log(` Skipped (pending): ${f.skipped.pending}`),console.log(` Skipped (connected): ${f.skipped.connected}`),console.log(` Skipped (email req): ${f.skipped.email}`),console.log(` Skipped (not found): ${f.skipped.notFound}`),f.skipped.excludedLocation>0&&console.log(` Skipped (excluded location): ${f.skipped.excludedLocation}`),console.log(` Errors: ${f.errors}`),!r){let m=dt();console.log(` Connection quota left: today ${m.daily.remaining} of ${m.daily.max} | week ${m.weekly.remaining} of ${m.weekly.max}`)}return f}var La,Js=Z(async()=>{qe();await Ye();La={viewProfile:Un,detectConnectionStatus:Ee,findConnectButton:xt,clickConnectButton:qn,sendConnectionRequest:Bn,runFunnel:Bs,shouldExcludeLocation:Gt}});qe();await Ye();St();await Ye();St();var Wr=new Set(["java","c#",".net","scala","python","typescript","javascript","react","node.js","aws","azure","docker","kubernetes","microservices","graphql","rest","sql","postgresql","mongodb","kafka","redis","ci/cd","terraform","spring"]),Yr=new Set(["iot","machine learning","ai","data engineering","spark","go","rust","kotlin","next.js","devops","sre"]),Wo=["vancouver","british columbia"],Gr=["canada","montreal","quebec","alberta","calgary","ottawa"],zr=["toronto","ontario"],Kr=["india","pakistan","nigeria","philippines"];function Qr(e,t={}){let n=0,o=(e.techStack||[]).map(u=>u.toLowerCase()),s=0,i=0;for(let u of o)Wr.has(u)&&s++,Yr.has(u)&&i++;if(n+=Math.min(s*6,24),n+=Math.min(i*3,6),e.salary){let u=Xr(e.salary);u&&(u>=15e4?n+=20:u>=12e4?n+=15:u>=1e5?n+=10:u>=8e4?n+=5:u>=100&&u<1e3?n+=15:u>=70&&u<1e3&&(n+=10))}let r=(e.location||"").toLowerCase(),c=/remote/i.test(r)||e.workplaceType==="remote";Kr.some(u=>r.includes(u))?n-=30:c&&/united states|usa|\bus\b/i.test(r)?n+=25:c&&Wo.some(u=>r.includes(u))?n+=22:c?n+=20:Wo.some(u=>r.includes(u))?n+=18:Gr.some(u=>r.includes(u))?n+=10:zr.some(u=>r.includes(u))&&(n+=5),e.isEasyApply&&(n+=5);let a=(e.seniority||"").toLowerCase();a.includes("senior")||a.includes("lead")||a.includes("staff")?n+=10:a.includes("mid")?n+=5:(a.includes("entry")||a.includes("intern"))&&(n-=10),e.recruiterUrl&&(t.conversationRecruiters?.has(e.recruiterUrl)?n+=20:t.connectedRecruiters?.has(e.recruiterUrl)?n+=15:n+=3);let l=new Set(e.jobTags||[]);return l.has("managerial")?n+=8:l.has("senior-ic")&&(n+=5),l.has("junior")&&(n-=15),l.has("consultant")&&(n-=3),Math.max(0,Math.min(100,n))}function Yo(e=10,t={}){let{easyApplyOnly:n=!0}=t,o=yt(),s=V(),i=new Set,r=new Set;for(let[f,d]of Object.entries(s))d.connectionStatus==="connected"&&i.add(f);let c={connectedRecruiters:i,conversationRecruiters:r},a=wt(),l=new Set(["applied","skipped","expired","archived"]);return Object.entries(o).filter(([f,d])=>{if(typeof d!="object"||n&&!d.isEasyApply||d.applied)return!1;let m=a[f];return!(m&&l.has(m.status))}).map(([f,d])=>({jobId:f,score:Qr(d,c),job:d})).sort((f,d)=>{if(d.score!==f.score)return d.score-f.score;let m=f.job.scoutedAt||f.job.postedTime||"";return(d.job.scoutedAt||d.job.postedTime||"").localeCompare(m)}).slice(0,e)}function Xr(e){if(!e)return null;let t=e.match(/[\$£€CAD\s]*([\d,]+(?:\.\d+)?)\s*[kK]?/g);if(!t||t.length===0)return null;let n=t.map(o=>{let s=parseFloat(o.replace(/[^\d.]/g,""));return o.toLowerCase().includes("k")&&(s*=1e3),s}).filter(o=>o>0);return n.length>=2?(n[0]+n[1])/2:n.length===1?n[0]:null}await rt();import ri from"puppeteer";import{addExtra as ii}from"puppeteer-extra";import ai from"puppeteer-extra-plugin-stealth";qe();await rt();nt();nt();import pn from"fs";import Zr from"path";var ei={headless:!1,defaultViewport:null,protocolTimeout:3e5},kt=new Set,Go=!1;async function Ft(){let e=[...kt].map(t=>{try{return Promise.resolve(t.close()).catch(()=>{})}catch{return Promise.resolve()}});kt.clear(),await Promise.race([Promise.all(e),new Promise(t=>setTimeout(t,5e3))])}function ti(){if(Go)return;Go=!0;let e=t=>async()=>{await Ft(),process.exit(t)};process.once("SIGINT",e(130)),process.once("SIGTERM",e(143)),process.once("SIGHUP",e(129)),process.once("uncaughtException",async t=>{await Ft(),console.error(t&&t.stack||t),process.exit(1)}),process.once("unhandledRejection",async t=>{await Ft(),console.error(t),process.exit(1)}),process.stdout.on("error",async t=>{t&&t.code==="EPIPE"&&(await Ft(),process.exit(0))}),process.on("exit",()=>{for(let t of kt)try{let n=t.process&&t.process();n&&n.kill("SIGKILL")}catch{}})}function gn(e){return Zr.join(e,".ilml-browser-session.json")}function Xo(e,t={}){try{pn.writeFileSync(gn(e),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...t}))}catch{}}function ni(e,t){try{let n=t.wsEndpoint&&t.wsEndpoint();Xo(e,n?{wsEndpoint:n}:{})}catch{}}function oi(e){let t=Zo(e);t&&t.ownerPid===process.pid&&vt(e)}function vt(e){try{pn.rmSync(gn(e),{force:!0})}catch{}}function Zo(e){try{return JSON.parse(pn.readFileSync(gn(e),"utf-8"))}catch{return null}}function zo(e){if(!e||e===process.pid)return!0;try{return process.kill(e,0),!0}catch(t){return!t||t.code!=="ESRCH"}}function Ko(e,t,n){let o,s=new Promise(r=>{o=setTimeout(()=>r(n),t)}),i=Promise.resolve(e).then(r=>(clearTimeout(o),r),r=>{throw clearTimeout(o),r});return Promise.race([i,s])}async function Qo(e,t,{probeTimeoutMs:n=4e3}={}){let o=Zo(t);if(!o)return"free";if(!o.wsEndpoint)return o.ownerPid&&o.ownerPid!==process.pid&&zo(o.ownerPid)?"live":(vt(t),"free");let s=Symbol("timeout"),i=e.connect({browserWSEndpoint:o.wsEndpoint,defaultViewport:null}).catch(()=>null),r=await Ko(i,n,s);if(r===s)return i.then(a=>{if(a)try{a.disconnect()}catch{}}),"live";if(!r)return vt(t),"free";if(zo(o.ownerPid)){try{r.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await Ko(r.close().then(()=>!0).catch(()=>!1),n,!1))return vt(t),"free";try{r.disconnect()}catch{}return"live"}function si(e,t){e&&(ti(),kt.add(e),e.on("disconnected",()=>{kt.delete(e),t&&vt(t)}))}async function es(e,t={}){let n=so(),o={...ei,...t,userDataDir:n},s=`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 Qo(e,n)==="live")throw new Error(s);Xo(n);let i;try{i=await e.launch(o)}catch{if(await Qo(e,n)==="live")throw new Error(s);lo(n);try{i=await e.launch(o)}catch(c){throw oi(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: ${c.message})`)}}return si(i,n),ni(n,i),{browser:i,profileDir:n,needsSeed:io(n)}}async function ts(e,t){if(!t||!t.needsSeed)return!1;if(!no())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(...It()),ao(t.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var ss=ii(ri);ss.use(ai());async function rs(){let{browser:e,profileDir:t,needsSeed:n}=await es(ss),o=await e.newPage();return await o.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await ts(o,{profileDir:t,needsSeed:n}),console.log(" Browser launched (persistent profile)."),{browser:e,page:o}}async function hn(e){await be(e,"https://www.linkedin.com/messaging/",{readySelector:".msg-conversations-container__conversations-list, .msg-conversation-listitem",label:"inbox"})||(console.warn(" Inbox container not found via known selectors, proceeding..."),await k(3e3)),console.log(" Inbox loaded.")}async function is(e){let t=await e.evaluate(()=>{let n=document.querySelectorAll(".msg-conversation-listitem"),o=[];for(let s of n){let r=s.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||null;if(!r)continue;let a=s.querySelector(".msg-conversation-card__message-snippet")?.textContent?.trim()?.replace(/\s+/g," ")||"";if(/^\s*Sponsored\b/i.test(a)||/^\s*Promoted\b/i.test(a))continue;let u=s.querySelector(".msg-conversation-listitem__time-stamp, .msg-conversation-card__time-stamp")?.textContent?.trim()||"",f=s.querySelector(".msg-conversation-card__convo-item-container--unread")!==null||s.querySelector(".msg-conversation-card__unread-count")!==null,d,m;if(a.startsWith("You:"))d="me",m=a.slice(4).trim();else{let g=r.split(" ")[0];if(a.startsWith(r+":")||a.startsWith(g+":")){d="them";let b=a.indexOf(":");m=a.slice(b+1).trim()}else d="them",m=a}let w=s.getBoundingClientRect();o.push({name:r,lastMessagePreview:m,lastMessageTime:u,unread:f,lastMessageBy:d,x:w.x+w.width/2,y:w.y+w.height/2})}return o});for(let n of t)n.lastMessageTime=en(n.lastMessageTime)||n.lastMessageTime;return t}async function yn(e){return e.evaluate(()=>{let t=[".msg-conversations-container__conversations-list",".msg-conversations-container",'[class*="msg-conversations-container"] ul'];for(let o of t){let s=document.querySelector(o);if(s&&s.scrollHeight>s.clientHeight)return s.scrollBy(0,600),{scrollTop:s.scrollTop,scrollHeight:s.scrollHeight}}let n=document.querySelector(".msg-conversation-listitem");if(n){let o=n.parentElement;for(;o;){if(o.scrollHeight>o.clientHeight+10)return o.scrollBy(0,600),{scrollTop:o.scrollTop,scrollHeight:o.scrollHeight};o=o.parentElement}}return null})}async function li(e){return e.evaluate(()=>{let t=/^status\s+is\s+|^online$|^offline$|^away$|^busy$|^active\s/i,n=['.msg-overlay-conversation-bubble__header a[href*="/in/"] .truncate','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header__title a[href*="/in/"]',".msg-overlay-bubble-header__title",".msg-overlay-conversation-bubble__header .truncate",".msg-thread__link-to-profile","h2.msg-entity-lockup__entity-title",".msg-s-message-list-container h2",".msg-thread h2",".msg-conversations-container__title-row h2",'.msg-thread a[href*="/in/"]'];for(let s of n){let i=document.querySelector(s);if(i){let r=i.textContent?.trim()?.replace(/\s+/g," ");if(r&&r.length>1&&r.length<100&&!t.test(r))return r}}let o=document.querySelectorAll(".msg-s-message-list-container h2, .msg-thread h2");for(let s of o){let i=s.textContent?.trim();if(i&&i.length>1&&i.length<100&&!/conversation/i.test(i)&&!t.test(i))return i}return null})}async function wn(e){return e.evaluate(()=>{let t=[".msg-thread__link-to-profile",'.msg-entity-lockup__entity-title a[href*="/in/"]','.msg-s-message-list-container a[href*="/in/"]','.msg-thread a[href*="/in/"]','.msg-conversations-container__title-row a[href*="/in/"]','.msg-overlay-conversation-bubble__header a[href*="/in/"]','.msg-overlay-bubble-header a[href*="/in/"]','.msg-overlay-conversation-bubble a[href*="/in/"]'];for(let n of t){let o=document.querySelector(n);if(o){let s=o.getAttribute("href")||"";if(s&&s.includes("/in/"))return s.startsWith("/")&&(s="https://www.linkedin.com"+s),s=s.replace(/\/$/,"").split("?")[0],s}}return null})}async function ns(e,t){let n=await li(e);if(!n)return{match:!1,headerName:null};let o=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(c=>c.length>1),i=n.toLowerCase();return{match:i.includes(o)||s.some(c=>i.includes(c)),headerName:n}}async function Ut(e,t){let n=t.split(" ")[0],o=8e3,s=500,i=0;for(;i<o;){let{match:a,headerName:l}=await ns(e,t);if(a)return await k(500),{verified:!0,headerName:l};let u=await e.evaluate(()=>{let f=document.querySelectorAll(".msg-s-message-group__name"),d=Array.from(f).map(w=>w.textContent?.trim()).filter(Boolean),m=document.querySelectorAll(".msg-s-event-listitem").length;return{allSenders:d,msgCount:m}});if(u.msgCount>0&&u.allSenders.some(d=>d.toLowerCase().includes(n.toLowerCase())))return await k(300),{verified:!0,headerName:n};await k(s),i+=s}let{match:r,headerName:c}=await ns(e,t);return r?{verified:!0,headerName:c}:{verified:!1,headerName:c}}async function ci(e){let n=0,o=0;for(let s=0;s<50;s++){let i=await e.evaluate(()=>{let r=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!r){let l=document.querySelector(".msg-overlay-conversation-bubble");l&&(r=l.querySelector(".msg-s-message-list-container")||l.querySelector(".msg-s-message-list"))}if(!r)return{found:!1};let c=r.querySelectorAll("li.msg-s-message-list__event").length;return r.scrollTop<=1?{found:!0,atTop:!0,msgCount:c}:(r.scrollTop=0,{found:!0,atTop:!1,msgCount:c})});if(!i.found||i.atTop)break;if(await k(800),i.msgCount===n){if(o++,o>=3)break}else o=0;n=i.msgCount}}async function bn(e,{scrollUp:t=!0}={}){t&&await ci(e);let n=await e.evaluate(()=>{let o=[],s="",i=document.querySelector(".msg-thread .msg-s-message-list-container")||document.querySelector(".msg-s-message-list-container");if(!i){let u=document.querySelector(".msg-overlay-conversation-bubble");u&&(i=u.querySelector(".msg-s-message-list-container")||u.querySelector(".msg-s-message-list"))}if(!i)return o;let r=i.querySelectorAll("li.msg-s-message-list__event");if(r.length===0){let u=document.querySelector(".msg-overlay-conversation-bubble, .msg-overlay-list-bubble");u&&(r=u.querySelectorAll("li.msg-s-message-list__event, .msg-s-event-listitem"))}function c(u){let f=u.getAttribute("data-event-urn");if(!f)return null;let d=f.match(/,2-([A-Za-z0-9+/=]+)\)/);if(!d)return null;try{let w=atob(d[1]).match(/^(\d{13})/);if(!w)return null;let g=Number(w[1]);if(g>14200704e5&&g<20512224e5)return g}catch{}return null}let a="";function l(u,f,d){let m=c(u),g=u.querySelector(".msg-s-message-group__timestamp, time")?.textContent?.trim()||"",b=u.querySelector(".msg-s-event-listitem__message-bubble");if(!b)return null;let y=b.textContent?.trim()?.replace(/Open Emoji Keyboard|Reply to this message|React with[^.]+/g,"")?.replace(/^(?:👏\s*👍\s*😊\s*)+/,"")?.replace(/\s+/g," ")?.trim()||"";if(!y)return null;let S=m?new Date(m).toISOString():d?`${d} ${g}`.trim():g;return{sender:f,text:y,time:S}}for(let u of r){let f=u.querySelector("time.msg-s-message-list__time-heading");f&&(a=f.textContent?.trim()||a);let d=u.querySelectorAll(".msg-s-message-group");if(d.length>0)for(let m of d){let w=m.querySelector(".msg-s-message-group__name");w&&(s=w.textContent?.trim()||s);let g=s||"Unknown",b=m.querySelectorAll(".msg-s-event-listitem");for(let y of b){let S=l(y,g,a);S&&o.push(S)}}else{let m=u.querySelectorAll(".msg-s-event-listitem");for(let w of m){let g=w.querySelector(".msg-s-message-group__name");g&&(s=g.textContent?.trim()||s);let y=l(w,s||"Unknown",a);y&&o.push(y)}}}if(o.length===0){let u=document.querySelectorAll(".msg-s-event-listitem--group-a11y-heading");for(let f of u){let d=f.textContent?.trim();d&&o.push({sender:"",text:d,time:""})}}return o});for(let o of n)(!o.time||!/^\d{4}-\d{2}-\d{2}T/.test(o.time))&&(o.time=en(o.time)||o.time);return n}function Sn(e,t,n){if(e.length===0)return!0;let o=t.split(" ")[0].toLowerCase(),s=t.toLowerCase().split(/[\s,]+/).filter(l=>l.length>1),i=[...new Set(e.map(l=>l.sender).filter(l=>l&&l!=="Unknown"))],r=i.some(l=>{let u=l.toLowerCase();return u.includes(o)||s.some(f=>u.includes(f))}),c=K.toLowerCase().split(/\s+/),a=i.every(l=>{let u=l.toLowerCase();return c.some(f=>u.includes(f))});if(r)return!0;if(a){for(let l of e){let f=(l.text||"").trim().match(/^(?:Hi|Hey|Hello|Dear)\s+([A-Z][a-z]+)/);if(f){let d=f[1].toLowerCase();if(d!=="there"&&d!=="all"&&!(s.some(w=>w===d)||d===o))return console.log(` STALE DATA: message says "Hi ${f[1]}" but expected "${t}"`),!1}}return!0}if(n?.length>0){let l=n.map(f=>f.toLowerCase());if(i.some(f=>{let d=f.toLowerCase();return l.some(m=>d.includes(m.split(" ")[0]))}))return console.log(` STALE DATA: messages belong to previous conversation (senders: ${i.join(", ")})`),!1}return console.log(` Sender warning: no match for "${t}" (found: ${i.join(", ")})`),!1}function Ke(e){return String(e||"").replace(/\s+/g," ").trim().toLowerCase()}function vn(e,t){if(!e||e.length===0)return t||[];if(!t||t.length===0)return e;let n=d=>Ke(d.sender)+"||"+Ke(d.text).replace(/\s+/g,""),o=new Set(t.map(n)),s=new Set(e.map(n)),i=e.filter(d=>Be.has(d.status)?!1:!o.has(n(d))),r=t.filter(d=>!s.has(n(d))),c=t.filter(d=>s.has(n(d))),a=e.filter(d=>Be.has(d.status)),l=[...i,...c,...r],u=[];for(let d of l){let m=Ke(d.text),w=Ke(d.sender),g=!1;for(let b=0;b<u.length;b++){let y=u[b];if(Ke(y.sender)!==w||!y.time||!d.time||y.time!==d.time)continue;let S=Ke(y.text);if(m.length>S.length&&m.endsWith(S)){g=!0;break}if(S.length>m.length&&S.endsWith(m)){u[b]=d,g=!0;break}}g||u.push(d)}return[...u,...a]}async function as(e,t){await hn(e),await k(2500),await e.evaluate(()=>{let c=[".msg-conversations-container__conversations-list",".msg-conversations-container"];for(let a of c){let l=document.querySelector(a);if(l){l.scrollTop=0;return}}}),await k(500);async function n(){return e.evaluate(c=>{let a=document.querySelectorAll(".msg-conversation-listitem");for(let l of a)if(l.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===c){let d=l.getBoundingClientRect();if(d.height>0)return{x:d.x+d.width/2,y:d.y+d.height/2}}return null},t)}let o=await n(),s=50,i=-1,r=0;for(let c=0;c<s&&!o;c++){let a=await yn(e);if(!a)break;if(a.scrollTop===i){if(r++,r>=2)break}else r=0,i=a.scrollTop;await k(600),o=await n()}return o?(await e.mouse.click(o.x,o.y),await k(3e3),Ut(e,t)):{verified:!1,headerName:null}}async function kn(e,t){let n=await e.evaluate(r=>{let c=document.querySelectorAll(".msg-conversation-listitem");for(let a of c)if(a.querySelector(".msg-conversation-listitem__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")===r){let f=a.getBoundingClientRect();if(f.height>0)return{x:f.x+f.width/2,y:f.y+f.height/2}}return null},t);if(n){await e.mouse.click(n.x,n.y),await k(3e3);let r=await Ut(e,t);if(r.verified)return r}let o=mo(t),s=o!==t?[t,o]:[t];for(let r of s)if(await os(e,r,t)){let a=await Ut(e,t);if(a.verified)return a}let i=po(o);if(i!==o&&i.length>0&&await os(e,i,t,{requireUnique:!0})){let c=await Ut(e,t);if(c.verified)return c}return{verified:!1,headerName:null}}async function os(e,t,n,o={}){let{requireUnique:s=!1}=o,i=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");if(!i)return!1;await i.click(),await k(300),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await k(300),await i.type(t,{delay:30}),await k(500),await e.keyboard.press("Enter"),await k(3500);let r=await e.evaluate((c,a)=>{let l=c.split(" ")[0].toLowerCase(),u=c.toLowerCase(),f=document.querySelectorAll(".msg-conversation-listitem"),d=[],m=[];for(let g of f){let y=g.querySelector(".msg-conversation-listitem__participant-names, .msg-conversation-card__participant-names")?.textContent?.trim()?.replace(/\s+/g," ")||"",S=y.toLowerCase();if(S.includes(l)){let h=g.getBoundingClientRect();if(h.height>0){let p=y.includes(",")||/\d+ other/.test(y),v=S===u?3:S.includes(u)?2:1,C={text:y,isGroup:p,score:v,x:h.x+h.width/2,y:h.y+h.height/2};p?m.push(C):d.push(C)}}}d.sort((g,b)=>b.score-g.score);let w=[...d,...m];return a&&w.length!==1?null:d[0]||m[0]||null},n,s);return r?(s&&console.log(" (found via stripped designations)"),await e.mouse.click(r.x,r.y),!0):!1}async function $e(e){let t=await e.$("input#search-conversations, .msg-cross-pillar-search-form__search-field");t&&(await t.click(),await k(200),await e.keyboard.down("Control"),await e.keyboard.press("a"),await e.keyboard.up("Control"),await e.keyboard.press("Backspace"),await e.keyboard.press("Escape"),await k(1e3))}await En();import"dotenv/config";import*as oe from"fs";import*as Ce from"path";import{fileURLToPath as xi}from"url";import"dotenv/config";import{createGraphClient as vi,resolveToken as ki}from"@ilivemylife/graph-sdk";import{config as $i}from"dotenv";$i();var ws=ki()||process.env.TOKEN;ws||(console.error(`
249
249
  [FATAL] No iLiveMyLife token found.`),console.error(" The bot uses Lifebot AI to decide which jobs to apply for"),console.error(` and how to fill application forms. It cannot work without it.
250
250
  `),console.error(" Easiest way:"),console.error(" 1. npm install -g @ilivemylife/graph-sdk"),console.error(` 2. ilml login your@email.com yourpassword
251
251
  `),console.error(` Or add ILML_TOKEN=... to .env
package/dist/version.mjs CHANGED
@@ -1 +1 @@
1
- import{readFileSync as e}from"fs";import{fileURLToPath as r}from"url";function i(){return"1.20.32";try{let n=new URL("./ilml-plugin.json",import.meta.url);return JSON.parse(e(r(n),"utf-8")).version}catch{return"unknown"}}console.log(`ilml-plugin-linkedin ${i()}`);
1
+ import{readFileSync as e}from"fs";import{fileURLToPath as r}from"url";function i(){return"1.20.33";try{let n=new URL("./ilml-plugin.json",import.meta.url);return JSON.parse(e(r(n),"utf-8")).version}catch{return"unknown"}}console.log(`ilml-plugin-linkedin ${i()}`);
package/ilml-plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkedin",
3
- "version": "1.20.32",
3
+ "version": "1.20.33",
4
4
  "description": "Reference ilml plugin: keep a local mirror of your LinkedIn data with AI-assisted workflows",
5
5
  "commands": {
6
6
  "help": { "run": "node dist/help.mjs", "description": "List all commands with descriptions; or `help <cmd>` for detailed info on one command (usage, flags, ban-risk, when-to-use). Reads ilml-plugin.json directly.", "usage": "ilml linkedin help [<cmd>]", "useWhen": "You forgot what a command does, or you're an AI agent picking the right tool." },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilml-plugin-linkedin",
3
- "version": "1.20.32",
3
+ "version": "1.20.33",
4
4
  "description": "Reference ilml plugin: keep a local mirror of your LinkedIn data and run AI-assisted workflows under your direction.",
5
5
  "type": "module",
6
6
  "files": [