ilml-plugin-linkedin 1.20.3 → 1.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/dist/connect.mjs +35 -35
- package/dist/enrichProfile.mjs +3 -3
- package/dist/enrichProfiles.mjs +2 -2
- package/dist/messageBot.mjs +59 -59
- package/dist/run.mjs +12 -12
- package/dist/scout.mjs +1 -1
- package/dist/syncAll.mjs +68 -68
- package/dist/syncConnections.mjs +1 -1
- package/dist/verifyAbout.mjs +1 -1
- package/dist/version.mjs +1 -1
- package/dist/viewers.mjs +1 -1
- package/dist/visit.mjs +13 -13
- package/ilml-plugin.json +1 -1
- package/package.json +1 -1
package/dist/scout.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var zt=Object.defineProperty;var ue=(t,e)=>{for(var o in e)zt(t,o,{get:e[o],enumerable:!0})};import ao from"puppeteer";import{addExtra as uo}from"puppeteer-extra";import fo from"puppeteer-extra-plugin-stealth";async function D(t){let e=Math.floor(Math.random()*2001),o=t+e;return new Promise(r=>setTimeout(r,o))}import{getPluginConfig as Yt}from"@ilivemylife/graph-sdk";var Qt=await Yt();for(let[t,e]of Object.entries(Qt))process.env[t]===void 0&&(process.env[t]=e);var Xt=process.env.LINKEDIN_NAME,G=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Fn=Object.freeze(new Set([G.DRAFT,G.CONFIRMED,G.NEEDS_REVIEW])),Zt=Object.freeze(new Set([G.DRAFT,G.CONFIRMED,G.REJECTED,G.NEEDS_REVIEW]));import O from"fs";import B from"path";var eo="cookies.json";function qe(){let t=process.env.ILML_SCOPE_DIR;return t?B.join(t,"plugins-state","linkedin","cookies.json"):eo}function Be(){let t=qe();if(!O.existsSync(t))throw new Error(`Cookies not found at ${t}. Run: ilml linkedin login`);let e;try{e=O.readFileSync(t,"utf-8")}catch(r){throw new Error(`Failed to read cookies at ${t}: ${r.message}. Run: ilml linkedin login`)}let o;try{o=JSON.parse(e)}catch{throw new Error(`Cookies file at ${t} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(o)||o.length===0)throw new Error(`Cookies file at ${t} is empty or not an array. Run: ilml linkedin login`);return o}function Je(){return O.existsSync(qe())}function to(){let t=process.env.ILML_SCOPE_DIR;return t?B.join(t,"plugins-state","linkedin"):"."}function He(t){let e=String(t||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(e)?e:"default"}function oo(){let t=process.env.MY_LINKEDIN_URL,e=t&&t.match(/\/in\/([^/?#]+)/);return e&&e[1]?He(e[1]):"default"}function We(t){let e=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(e)return O.existsSync(e)||O.mkdirSync(e,{recursive:!0}),B.resolve(e);let o=He(t||oo()),r=B.join(to(),"chrome-profile",o);return O.existsSync(r)||O.mkdirSync(r,{recursive:!0}),B.resolve(r)}var Ge=".ilml-seeded";function Ve(t){return!O.existsSync(B.join(t,Ge))}function Ke(t){try{O.writeFileSync(B.join(t,Ge),new Date().toISOString())}catch{}}function ze(t){let e=0;for(let o of["SingletonLock","SingletonCookie","SingletonSocket"])try{O.rmSync(B.join(t,o),{force:!0}),e++}catch{}return e}import ve from"fs";import no from"path";var ro={headless:!1,defaultViewport:null,protocolTimeout:3e5},ee=new Set,Ye=!1;async function fe(){let t=[...ee].map(e=>{try{return Promise.resolve(e.close()).catch(()=>{})}catch{return Promise.resolve()}});ee.clear(),await Promise.race([Promise.all(t),new Promise(e=>setTimeout(e,5e3))])}function so(){if(Ye)return;Ye=!0;let t=e=>async()=>{await fe(),process.exit(e)};process.once("SIGINT",t(130)),process.once("SIGTERM",t(143)),process.once("SIGHUP",t(129)),process.once("uncaughtException",async e=>{await fe(),console.error(e&&e.stack||e),process.exit(1)}),process.once("unhandledRejection",async e=>{await fe(),console.error(e),process.exit(1)}),process.stdout.on("error",async e=>{e&&e.code==="EPIPE"&&(await fe(),process.exit(0))}),process.on("exit",()=>{for(let e of ee)try{let o=e.process&&e.process();o&&o.kill("SIGKILL")}catch{}})}function ke(t){return no.join(t,".ilml-browser-session.json")}function et(t,e={}){try{ve.writeFileSync(ke(t),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...e}))}catch{}}function io(t,e){try{let o=e.wsEndpoint&&e.wsEndpoint();et(t,o?{wsEndpoint:o}:{})}catch{}}function co(t){let e=tt(t);e&&e.ownerPid===process.pid&&Z(t)}function Z(t){try{ve.rmSync(ke(t),{force:!0})}catch{}}function tt(t){try{return JSON.parse(ve.readFileSync(ke(t),"utf-8"))}catch{return null}}function Qe(t){if(!t||t===process.pid)return!0;try{return process.kill(t,0),!0}catch(e){return!e||e.code!=="ESRCH"}}function Xe(t,e,o){let r,n=new Promise(s=>{r=setTimeout(()=>s(o),e)}),i=Promise.resolve(t).then(s=>(clearTimeout(r),s),s=>{throw clearTimeout(r),s});return Promise.race([i,n])}async function Ze(t,e,{probeTimeoutMs:o=4e3}={}){let r=tt(e);if(!r)return"free";if(!r.wsEndpoint)return r.ownerPid&&r.ownerPid!==process.pid&&Qe(r.ownerPid)?"live":(Z(e),"free");let n=Symbol("timeout"),i=t.connect({browserWSEndpoint:r.wsEndpoint,defaultViewport:null}).catch(()=>null),s=await Xe(i,o,n);if(s===n)return i.then(l=>{if(l)try{l.disconnect()}catch{}}),"live";if(!s)return Z(e),"free";if(Qe(r.ownerPid)){try{s.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await Xe(s.close().then(()=>!0).catch(()=>!1),o,!1))return Z(e),"free";try{s.disconnect()}catch{}return"live"}function lo(t,e){t&&(so(),ee.add(t),t.on("disconnected",()=>{ee.delete(t),e&&Z(e)}))}async function ot(t,e={}){let o=We(),r={...ro,...e,userDataDir:o},n=`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 Ze(t,o)==="live")throw new Error(n);et(o);let i;try{i=await t.launch(r)}catch{if(await Ze(t,o)==="live")throw new Error(n);ze(o);try{i=await t.launch(r)}catch(c){throw co(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 lo(i,o),io(o,i),{browser:i,profileDir:o,needsSeed:Ve(o)}}async function nt(t,e){if(!e||!e.needsSeed)return!1;if(!Je())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 t.setCookie(...Be()),Ke(e.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var rt=uo(ao);rt.use(fo());async function st(){let{browser:t,profileDir:e,needsSeed:o}=await ot(rt),r=await t.newPage();return await r.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await nt(r,{profileDir:e,needsSeed:o}),console.log(" Browser launched (persistent profile)."),{browser:t,page:r}}async function it(t){let e=[".jobs-search-results-list",".scaffold-layout__list-container",".jobs-search-two-pane__results","div.jobs-search-results-list"];return await t.evaluate(async r=>{let n=null,i=null;for(let h of r)if(n=document.querySelector(h),n){i=h;break}if(!n){let h=document.querySelector("li.scaffold-layout__list-item");if(h){let u=h.parentElement;for(;u&&u!==document.body;){if(u.scrollHeight>u.clientHeight){n=u,i="parent of li.scaffold-layout__list-item";break}u=u.parentElement}}}if(!n)return{found:!1,triedSelectors:r};let s=n.scrollTop,c=300,l=300,f=50,d=0;for(;d<f&&(n.scrollBy(0,c),await new Promise(h=>setTimeout(h,l)),!(n.scrollTop+n.clientHeight>=n.scrollHeight));)d++;return{found:!0,usedSelector:i,initialScroll:s,finalScroll:n.scrollTop,scrollHeight:n.scrollHeight,attempts:d}},e)}async function ct(t,{easyApplyOnly:e=!0}={}){let o=await t.evaluate(()=>{let r=document.querySelectorAll("li.scaffold-layout__list-item");return Array.from(r).map(n=>{let s=(n.querySelector(".job-card-list__footer-wrapper")?.innerText??"").includes("Easy Apply"),c=n.querySelector("a.job-card-container__link");if(c){let l=c.getAttribute("href").split("?")[0],f=n.querySelector(".job-card-list__title--link")?.getAttribute("aria-label")?.replace(/ with verification$/,""),d=n.querySelector(".artdeco-entity-lockup__subtitle")?.innerText.trim(),h=n.querySelector(".artdeco-entity-lockup__caption")?.innerText.trim(),u=n.querySelector(".artdeco-entity-lockup__metadata")?.innerText.trim();return{id:l,isEasyApply:s,applyType:s?"easy-apply":"external",dataId:c.getAttribute("data-control-id"),href:`https://linkedin.com${l}`,jobTitle:f,companyName:d,location:h,salary:u||null,jobLink:s?c.href:null}}return{isEasyApply:!1}})});return e?o.filter(r=>r.isEasyApply&&r.href):o.filter(r=>r.href)}async function lt(t){let e=await t.evaluate(()=>{let o=document.querySelector('button[aria-label="View next page"]')||document.querySelector(".jobs-search-pagination__button--next");if(o&&!o.disabled){let r=document.querySelector(".jobs-search-pagination__page-state")?.textContent?.trim();return o.click(),{success:!0,pageState:r}}return{success:!1,reason:"No next page button found"}});return console.log(" Pagination:",e.success?e.pageState:e.reason),e.success&&await D(2e3),e.success}async function at(t,e){let o=t.url();if(o.includes("/jobs/"))return!1;if(o.includes("/login")||o.includes("/authwall")||o.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${o.slice(0,80)}`),console.log(" Navigating back to job search..."),await t.goto(e,{waitUntil:"domcontentloaded",timeout:6e4}),await D(3e3);let n=t.url();if(!n.includes("/jobs/"))throw new Error(`Could not return to job search. Current URL: ${n.slice(0,80)}`);return console.log(" Recovered to job search page"),!0}async function ut(t){return t.evaluate(()=>{let e=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,o=e.querySelector(".hirer-card__hirer-information");if(o){let s=o.querySelector('a[href*="/in/"]'),c=o.querySelector(".jobs-poster__name")||o.querySelector("strong")||o.querySelector('[class*="name"]');if(s)return{name:c?.textContent?.trim()||s.textContent?.trim(),profileUrl:s.href?.split("?")[0],source:"hiring_team"}}let r=e.querySelector(".jobs-poster__name");if(r){let s=r.closest('a[href*="/in/"]')||r.parentElement?.querySelector('a[href*="/in/"]')||r.parentElement?.parentElement?.querySelector('a[href*="/in/"]');if(s)return{name:r.textContent?.trim(),profileUrl:s.href?.split("?")[0],source:"poster_name"}}let n=e.querySelector(".job-details-people-who-can-help__section--two-pane")||e.querySelector('[class*="people-who-can-help"]');if(n){let s=n.querySelector('a[href*="/in/"]');if(s)return{name:(n.querySelector(".jobs-poster__name")||n.querySelector("strong"))?.textContent?.trim()||s.textContent?.trim(),profileUrl:s.href?.split("?")[0],source:"people_section"}}let i=e.querySelectorAll('a[href*="/in/"]');for(let s of i){let c=s.textContent?.trim();if(c&&c.length>3&&!["View","Connect","Follow","Message","Apply","Save"].includes(c))return{name:c,profileUrl:s.href?.split("?")[0],source:"details_link"}}return null})}async function ft(t){return t.evaluate(()=>{let e=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,r=(e.querySelector(".jobs-description__content")||e.querySelector(".jobs-box__html-content")||e.querySelector(".jobs-description"))?.innerText?.trim()||"",n={},i=e.querySelectorAll(".jobs-unified-top-card__job-insight, li.job-criteria__item");for(let W of i){let we=W.querySelector(".job-criteria__subheader")?.textContent?.trim(),Ue=W.querySelector(".job-criteria__text")?.textContent?.trim();we&&Ue&&(n[we.toLowerCase()]=Ue)}let s=["Java","Python","JavaScript","TypeScript","React","Angular","Vue","Node.js","C#",".NET","C\\+\\+","Go","Rust","Scala","Kotlin","AWS","Azure","GCP","Docker","Kubernetes","Terraform","SQL","PostgreSQL","MongoDB","Redis","Kafka","RabbitMQ","Spring","Django","Flask","Express","Next.js","CI/CD","Jenkins","GitHub Actions","GraphQL","REST","Microservices","Machine Learning","AI","Data Engineering","Spark","Hadoop","Snowflake","Databricks","Airflow","iOS","Android","React Native","Flutter","Agile","Scrum","DevOps","SRE"],c=[];for(let W of s)new RegExp("\\b"+W.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\b","i").test(r)&&c.push(W.replace(/\\\+/g,"+"));let f=e.querySelector('.jobs-company__box, [class*="jobs-company"], [class*="company-card"]')?.innerText?.trim()?.slice(0,1e3)||null,h=e.querySelector('a.jobs-apply-button[href], a[data-tracking-control-name="public_jobs_apply-link-offsite_sign-up"]')?.getAttribute("href")||null,u=e.querySelector(".job-details-jobs-unified-top-card__company-name, .jobs-unified-top-card__company-name"),p=u?.innerText?.trim()||null,S=(u?.querySelector('a[href*="/company/"]')||e.querySelector('a[href*="/company/"]'))?.getAttribute("href")?.split("?")[0]||null,g=e.querySelector(".job-details-jobs-unified-top-card__primary-description-container")?.innerText?.trim()||"",M=g.match(/(\d+\s+(?:hour|day|week|month)s?\s+ago|Reposted|Just now)/i)?.[0]||null,U=g.match(/(\d[\d,]*)\s+applicant/i),ge=U?parseInt(U[1].replace(/,/g,"")):null,Se=e.querySelectorAll(".job-details-jobs-unified-top-card__job-insight"),ce=Array.from(Se).map(W=>W.innerText?.trim()?.replace(/\s+/g," ")),be=ce.join(" ").match(/([\d,]+-[\d,]+\s+employees|[\d,]+\+?\s+employees)/i)?.[0]||null,q=ce.join(" ")+" "+g,Vt=/\bremote\b/i.test(q)?"remote":/\bhybrid\b/i.test(q)?"hybrid":/\bon-?site\b/i.test(q)?"onsite":null,Kt=/\bcontract\b/i.test(q)?"contract":/\bfull-?time\b/i.test(q)?"full-time":/\bpart-?time\b/i.test(q)?"part-time":/\bfreelance\b/i.test(q)?"freelance":/\btemporary\b/i.test(q)?"temporary":null,Pe=e.querySelector(".job-details-jobs-unified-top-card__job-title, .jobs-unified-top-card__job-title, h2.t-24")?.innerText?.trim()||"",ae=e.querySelector(".job-details-jobs-unified-top-card__primary-description-container, .jobs-unified-top-card__subtitle-primary-grouping")?.innerText?.trim()||"",I=(Pe+" "+r+" "+ae).toLowerCase(),R=Pe.toLowerCase(),m=[];/\bremote\b/.test(I)&&m.push("remote"),/\bhybrid\b/.test(I)&&m.push("hybrid"),/\bon-?site\b|\bin-?office\b/.test(I)&&m.push("onsite"),(m.length===0||!m.includes("remote")&&!m.includes("hybrid")&&!m.includes("onsite"))&&/remote/i.test(ae)&&m.push("remote"),/\b(manager|director|vp|vice president|head of|chief|cto|cio|lead.*team|managing)\b/i.test(R)&&m.push("managerial"),/\b(architect|principal|staff|distinguished)\b/i.test(R)&&m.push("senior-ic"),/\b(developer|engineer|programmer|analyst)\b/i.test(R)&&!m.includes("managerial")&&m.push("ic"),/\b(junior|jr\.?|entry)\b/i.test(R)?m.push("junior"):/\b(senior|sr\.?)\b/i.test(R)?m.push("senior"):/\b(staff|principal|distinguished)\b/i.test(R)?m.push("staff+"):/\b(director|vp|chief|cto|cio)\b/i.test(R)?m.push("executive"):/\b(lead|team lead)\b/i.test(R)&&m.push("lead"),/\b(backend|back-end|server-side|api)\b/i.test(I)&&m.push("backend"),/\b(frontend|front-end|ui|ux)\b/i.test(I)&&m.push("frontend"),/\b(full.?stack|fullstack)\b/i.test(I)&&m.push("fullstack"),/\b(devops|sre|infrastructure|platform)\b/i.test(I)&&m.push("devops"),/\b(data engineer|data science|machine learning|ml engineer)\b/i.test(I)&&m.push("data"),/\b(mobile|ios|android|react native|flutter)\b/i.test(I)&&m.push("mobile"),/\b(architect)\b/i.test(R)&&m.push("architect"),/\b(consultant|consulting)\b/i.test(R)&&m.push("consultant");let Me=(n["employment type"]||"").toLowerCase();return(/contract|freelance|temporary/i.test(Me)||/\bcontract\b/i.test(I))&&m.push("contract"),/full.?time|permanent/i.test(Me)&&m.push("permanent"),/\bcanada\b|toronto|vancouver|montreal|ontario|british columbia|quebec|alberta|calgary|ottawa/i.test(ae)&&m.push("canada"),/\bunited states\b|\busa\b|new york|california|texas|seattle|san francisco/i.test(ae)&&m.push("usa"),(e.querySelector(".jobs-unified-top-card__job-insight--highlight, .compensation__salary")?.innerText?.trim()||""||/\$[\d,]+/.test(r))&&m.push("has-salary"),{description:r.substring(0,5e3),externalApplyUrl:h,companyName:p,companyUrl:S?S.startsWith("/")?"https://www.linkedin.com"+S:S:null,aboutCompany:f,seniority:n["seniority level"]||null,employmentType:n["employment type"]||null,industries:n.industries||null,jobFunction:n["job function"]||null,postedTime:M,applicantCount:ge,companySize:be,workplaceType:Vt,contractType:Kt,techStack:[...new Set(c)],jobTags:[...new Set(m)]}})}import"dotenv/config";import*as E from"fs";import*as _ from"path";import{fileURLToPath as po}from"url";function pt(t){if(!t||typeof t!="string"||/custom-invite|\/search\//i.test(t)||/\/in\/[^/?#]+\/(overlay|details)(\/|$)/i.test(t))return null;let e=t.match(/\/in\/([^/?#]+)/i);if(!e||!e[1])return null;let o=e[1].trim();return o?`https://www.linkedin.com/in/${o}/`:null}var mo=po(import.meta.url),ho=_.dirname(_.dirname(mo)),K=process.env.DATA_DIR?_.resolve(process.env.DATA_DIR,"market-research"):_.join(ho,"market-research"),dt=_.join(K,"scouted-jobs.json"),mt=_.join(K,"discovered-people.json"),yo=_.join(K,"visit-log.json"),ht=_.join(K,"companies.json"),dr=_.join(K,"job-decisions.json");function Ae(){E.existsSync(K)||E.mkdirSync(K,{recursive:!0})}function _e(t,e){let o=JSON.stringify(e,null,2),r=t+".tmp";E.writeFileSync(r,o);for(let n=0;n<3;n++)try{E.renameSync(r,t);return}catch(i){if(n<2&&(i.code==="EPERM"||i.code==="EBUSY")){let s=Date.now();for(;Date.now()-s<200;);continue}throw i}}function de(t){try{if(E.existsSync(t))return JSON.parse(E.readFileSync(t,"utf-8"))}catch{}return null}function yt(){te=null,go=null,oe=null,ne=null,V=null}var te=null;function me(){return te||(te=de(dt)||{},te)}function gt(t,e){if(!t)return;Ae();let o=me(),r=new Date().toISOString().slice(0,10);if(o[t]){for(let[n,i]of Object.entries(e))i!=null&&(o[t][n]=i);o[t].lastSeen=r}else o[t]={...e,scoutedAt:r,lastSeen:r};try{_e(dt,o)}catch(n){console.error(`[!] Failed to save scouted-jobs.json: ${n.message}`)}}var go=null;var oe=null;function St(){return oe||(oe=de(mt)||{},oe)}function pe(t){let e=String(t||"").match(/\/in\/([^/?#]+)/i);return e?e[1].toLowerCase():null}function So(t,e){let o=pt(e)||e;if(t[o])return o;let r=pe(e);if(!r)return o;let n=null;for(let[i,s]of Object.entries(t)){if(pe(s&&(s.canonicalUrl||s.profileUrl)||i)===r)return i;!n&&s&&Array.isArray(s.aliases)&&s.aliases.includes(r)&&(n=i)}return n||o}function bt(t,e){if(!t)return;Ae();let o=St(),r=new Date().toISOString().slice(0,10),n=So(o,t),i=pe(t);if(o[n]){let s=o[n];e.name&&(s.name=e.name),e.title&&(s.title=e.title),e.company&&(s.company=e.company),e.location&&(s.location=e.location),e.role&&(s.role=e.role),e.isConnected!=null&&(s.isConnected=e.isConnected),e.jobId&&(s.jobIds||(s.jobIds=[]),s.jobIds.includes(e.jobId)||s.jobIds.push(e.jobId)),i&&pe(s.canonicalUrl||s.profileUrl||n)!==i&&(Array.isArray(s.aliases)||(s.aliases=[]),s.aliases.includes(i)||s.aliases.push(i)),s.lastSeen=r,s.seenCount=(s.seenCount||1)+1}else o[n]={canonicalUrl:n,aliases:[],name:e.name||null,title:e.title||null,company:e.company||null,location:e.location||null,role:e.role||null,source:e.source||"scout",isConnected:e.isConnected||!1,discoveredAt:r,lastSeen:r,seenCount:1,jobIds:e.jobId?[e.jobId]:[]};try{_e(mt,o)}catch(s){console.error(`[!] Failed to save discovered-people.json: ${s.message}`)}}var ne=null;function bo(){return ne||(ne=de(ht)||{},ne)}function wt(t,e){if(!t)return;Ae();let o=bo(),r=new Date().toISOString().slice(0,10);if(o[t]){let n=o[t];e.name&&(n.name=e.name),e.about&&(n.about=e.about),e.size&&(n.size=e.size),e.industries&&(n.industries=e.industries),e.jobId&&(n.jobIds||(n.jobIds=[]),n.jobIds.includes(e.jobId)||n.jobIds.push(e.jobId)),e.recruiterUrl&&(n.recruiterUrls||(n.recruiterUrls=[]),n.recruiterUrls.includes(e.recruiterUrl)||n.recruiterUrls.push(e.recruiterUrl)),n.lastSeen=r,n.jobCount=n.jobIds?.length||0}else o[t]={name:e.name||null,about:e.about||null,size:e.size||null,industries:e.industries||null,discoveredAt:r,lastSeen:r,jobIds:e.jobId?[e.jobId]:[],recruiterUrls:e.recruiterUrl?[e.recruiterUrl]:[],jobCount:e.jobId?1:0};try{_e(ht,o)}catch(n){console.error(`[!] Failed to save companies.json: ${n.message}`)}}var V=null;function wo(){return V||(V=de(yo)||{visits:[]},Array.isArray(V.visits)||(V.visits=[]),V)}function vt(){let t=me(),e=St(),o=Object.values(t),r=Object.values(e),n={};for(let u of o)u.company&&(n[u.company]=(n[u.company]||0)+1);let i=Object.entries(n).sort((u,p)=>p[1]-u[1]).slice(0,5).map(([u,p])=>`${u} (${p})`),s={};for(let u of o)for(let p of u.techStack||[])s[p]=(s[p]||0)+1;let c=Object.entries(s).sort((u,p)=>p[1]-u[1]).slice(0,8).map(([u,p])=>`${u} (${p})`),l=wo(),f=new Date().toISOString().slice(0,10),d=l.visits.filter(u=>u.date.startsWith(f)).length,h=new Set(l.visits.map(u=>u.profileUrl)).size;return{totalJobs:o.length,totalRecruiters:r.length,topCompanies:i,topTech:c,totalVisited:h,todayVisited:d,lastScoutDate:o.length>0?o.sort((u,p)=>(p.scoutedAt||"").localeCompare(u.scoutedAt||""))[0]?.scoutedAt:null}}import"dotenv/config";import*as b from"fs";import*as v from"path";import{fileURLToPath as vo}from"url";var ko=vo(import.meta.url),Ao=v.dirname(v.dirname(ko)),F=process.env.DATA_DIR?v.resolve(process.env.DATA_DIR,"collected-profiles"):v.join(Ao,"collected-profiles"),_o=v.join(F,"people.json"),Eo=v.join(F,"jobs.json"),Sr=v.join(F,"quota.json"),br=v.join(F,"conversations.json"),wr=v.join(F,"sync-state.json"),vr=v.join(F,"application-questions.json"),kr=v.join(F,"profile-history"),kt=(t,e)=>{let o=parseInt(t,10);return Number.isInteger(o)&&o>=0?o:e},Ar=kt(process.env.CONNECT_MAX_DAILY,20),_r=kt(process.env.CONNECT_MAX_WEEKLY,100),re=null,se=null,jo=null,xo=null,Co=null,To=null;function At(){re=null,se=null,jo=null,xo=null,Co=null,To=null}function _t(){b.existsSync(F)||b.mkdirSync(F,{recursive:!0})}function Et(t,e){if(!b.existsSync(t))return null;try{let o=JSON.parse(b.readFileSync(t,"utf-8"));try{b.copyFileSync(t,t+".backup")}catch{}return o}catch(o){console.error(`[!] ${e} is corrupted: ${o.message}`),console.error(` File: ${v.resolve(t)}`);let r=t+".backup";if(b.existsSync(r))try{let n=JSON.parse(b.readFileSync(r,"utf-8"));console.error(` Restored from ${r}`);try{b.copyFileSync(r,t)}catch{}return n}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${t}.corrupted`);try{b.copyFileSync(t,t+".corrupted")}catch{}return null}}function jt(){return re||(_t(),re=Et(_o,"people.json")||{},re)}function xt(){return se||(_t(),se=Et(Eo,"jobs.json")||{},se)}import"dotenv/config";import*as j from"fs";import*as J from"path";import{fileURLToPath as No}from"url";import"dotenv/config";import{createGraphClient as $o,resolveToken as Io}from"@ilivemylife/graph-sdk";import{config as Ro}from"dotenv";Ro();var Ct=Io()||process.env.TOKEN;Ct||(console.error(`
|
|
1
|
+
var zt=Object.defineProperty;var ue=(t,e)=>{for(var o in e)zt(t,o,{get:e[o],enumerable:!0})};import ao from"puppeteer";import{addExtra as uo}from"puppeteer-extra";import fo from"puppeteer-extra-plugin-stealth";async function D(t){let e=Math.floor(Math.random()*2001),o=t+e;return new Promise(r=>setTimeout(r,o))}import{getPluginConfig as Yt}from"@ilivemylife/graph-sdk";var Qt=await Yt();for(let[t,e]of Object.entries(Qt))process.env[t]===void 0&&(process.env[t]=e);var Xt=process.env.LINKEDIN_NAME,G=Object.freeze({DRAFT:"draft",CONFIRMED:"confirmed",REJECTED:"rejected",NEEDS_REVIEW:"needs_review",SENT:"sent"}),Fn=Object.freeze(new Set([G.DRAFT,G.CONFIRMED,G.NEEDS_REVIEW])),Zt=Object.freeze(new Set([G.DRAFT,G.CONFIRMED,G.REJECTED,G.NEEDS_REVIEW]));import O from"fs";import B from"path";var eo="cookies.json";function qe(){let t=process.env.ILML_SCOPE_DIR;return t?B.join(t,"plugins-state","linkedin","cookies.json"):eo}function Be(){let t=qe();if(!O.existsSync(t))throw new Error(`Cookies not found at ${t}. Run: ilml linkedin login`);let e;try{e=O.readFileSync(t,"utf-8")}catch(r){throw new Error(`Failed to read cookies at ${t}: ${r.message}. Run: ilml linkedin login`)}let o;try{o=JSON.parse(e)}catch{throw new Error(`Cookies file at ${t} is corrupted (invalid JSON). Run: ilml linkedin login`)}if(!Array.isArray(o)||o.length===0)throw new Error(`Cookies file at ${t} is empty or not an array. Run: ilml linkedin login`);return o}function Je(){return O.existsSync(qe())}function to(){let t=process.env.ILML_SCOPE_DIR;return t?B.join(t,"plugins-state","linkedin"):"."}function He(t){let e=String(t||"").replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,80);return/[a-zA-Z0-9]/.test(e)?e:"default"}function oo(){let t=process.env.MY_LINKEDIN_URL,e=t&&t.match(/\/in\/([^/?#]+)/);return e&&e[1]?He(e[1]):"default"}function We(t){let e=process.env.LINKEDIN_CHROME_PROFILE_DIR;if(e)return O.existsSync(e)||O.mkdirSync(e,{recursive:!0}),B.resolve(e);let o=He(t||oo()),r=B.join(to(),"chrome-profile",o);return O.existsSync(r)||O.mkdirSync(r,{recursive:!0}),B.resolve(r)}var Ge=".ilml-seeded";function Ve(t){return!O.existsSync(B.join(t,Ge))}function Ke(t){try{O.writeFileSync(B.join(t,Ge),new Date().toISOString())}catch{}}function ze(t){let e=0;for(let o of["SingletonLock","SingletonCookie","SingletonSocket"])try{O.rmSync(B.join(t,o),{force:!0}),e++}catch{}return e}import ve from"fs";import no from"path";var ro={headless:!1,defaultViewport:null,protocolTimeout:3e5},ee=new Set,Ye=!1;async function fe(){let t=[...ee].map(e=>{try{return Promise.resolve(e.close()).catch(()=>{})}catch{return Promise.resolve()}});ee.clear(),await Promise.race([Promise.all(t),new Promise(e=>setTimeout(e,5e3))])}function so(){if(Ye)return;Ye=!0;let t=e=>async()=>{await fe(),process.exit(e)};process.once("SIGINT",t(130)),process.once("SIGTERM",t(143)),process.once("SIGHUP",t(129)),process.once("uncaughtException",async e=>{await fe(),console.error(e&&e.stack||e),process.exit(1)}),process.once("unhandledRejection",async e=>{await fe(),console.error(e),process.exit(1)}),process.stdout.on("error",async e=>{e&&e.code==="EPIPE"&&(await fe(),process.exit(0))}),process.on("exit",()=>{for(let e of ee)try{let o=e.process&&e.process();o&&o.kill("SIGKILL")}catch{}})}function ke(t){return no.join(t,".ilml-browser-session.json")}function et(t,e={}){try{ve.writeFileSync(ke(t),JSON.stringify({ownerPid:process.pid,startedAt:Date.now(),...e}))}catch{}}function io(t,e){try{let o=e.wsEndpoint&&e.wsEndpoint();et(t,o?{wsEndpoint:o}:{})}catch{}}function co(t){let e=tt(t);e&&e.ownerPid===process.pid&&Z(t)}function Z(t){try{ve.rmSync(ke(t),{force:!0})}catch{}}function tt(t){try{return JSON.parse(ve.readFileSync(ke(t),"utf-8"))}catch{return null}}function Qe(t){if(!t||t===process.pid)return!0;try{return process.kill(t,0),!0}catch(e){return!e||e.code!=="ESRCH"}}function Xe(t,e,o){let r,n=new Promise(s=>{r=setTimeout(()=>s(o),e)}),i=Promise.resolve(t).then(s=>(clearTimeout(r),s),s=>{throw clearTimeout(r),s});return Promise.race([i,n])}async function Ze(t,e,{probeTimeoutMs:o=4e3}={}){let r=tt(e);if(!r)return"free";if(!r.wsEndpoint)return r.ownerPid&&r.ownerPid!==process.pid&&Qe(r.ownerPid)?"live":(Z(e),"free");let n=Symbol("timeout"),i=t.connect({browserWSEndpoint:r.wsEndpoint,defaultViewport:null}).catch(()=>null),s=await Xe(i,o,n);if(s===n)return i.then(l=>{if(l)try{l.disconnect()}catch{}}),"live";if(!s)return Z(e),"free";if(Qe(r.ownerPid)){try{s.disconnect()}catch{}return"live"}if(console.log(" (recovered an orphaned automation browser from a previous run \u2014 closing it)"),await Xe(s.close().then(()=>!0).catch(()=>!1),o,!1))return Z(e),"free";try{s.disconnect()}catch{}return"live"}function lo(t,e){t&&(so(),ee.add(t),t.on("disconnected",()=>{ee.delete(t),e&&Z(e)}))}async function ot(t,e={}){let o=We(),r={...ro,...e,userDataDir:o},n=`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 Ze(t,o)==="live")throw new Error(n);et(o);let i;try{i=await t.launch(r)}catch{if(await Ze(t,o)==="live")throw new Error(n);ze(o);try{i=await t.launch(r)}catch(c){throw co(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 lo(i,o),io(o,i),{browser:i,profileDir:o,needsSeed:Ve(o)}}async function nt(t,e){if(!e||!e.needsSeed)return!1;if(!Je())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 t.setCookie(...Be()),Ke(e.profileDir),console.log(" (seeded persistent profile from saved cookies \u2014 one-time)"),!0}catch{return!1}}var rt=uo(ao);rt.use(fo());async function st(){let{browser:t,profileDir:e,needsSeed:o}=await ot(rt),r=await t.newPage();return await r.evaluateOnNewDocument(()=>{Object.defineProperty(navigator,"webdriver",{get:()=>{}})}),await nt(r,{profileDir:e,needsSeed:o}),console.log(" Browser launched (persistent profile)."),{browser:t,page:r}}async function it(t){let e=[".jobs-search-results-list",".scaffold-layout__list-container",".jobs-search-two-pane__results","div.jobs-search-results-list"];return await t.evaluate(async r=>{let n=null,i=null;for(let h of r)if(n=document.querySelector(h),n){i=h;break}if(!n){let h=document.querySelector("li.scaffold-layout__list-item");if(h){let u=h.parentElement;for(;u&&u!==document.body;){if(u.scrollHeight>u.clientHeight){n=u,i="parent of li.scaffold-layout__list-item";break}u=u.parentElement}}}if(!n)return{found:!1,triedSelectors:r};let s=n.scrollTop,c=300,l=300,f=50,d=0;for(;d<f&&(n.scrollBy(0,c),await new Promise(h=>setTimeout(h,l)),!(n.scrollTop+n.clientHeight>=n.scrollHeight));)d++;return{found:!0,usedSelector:i,initialScroll:s,finalScroll:n.scrollTop,scrollHeight:n.scrollHeight,attempts:d}},e)}async function ct(t,{easyApplyOnly:e=!0}={}){let o=await t.evaluate(()=>{let r=document.querySelectorAll("li.scaffold-layout__list-item");return Array.from(r).map(n=>{let s=(n.querySelector(".job-card-list__footer-wrapper")?.innerText??"").includes("Easy Apply"),c=n.querySelector("a.job-card-container__link");if(c){let l=c.getAttribute("href").split("?")[0],f=n.querySelector(".job-card-list__title--link")?.getAttribute("aria-label")?.replace(/ with verification$/,""),d=n.querySelector(".artdeco-entity-lockup__subtitle")?.innerText.trim(),h=n.querySelector(".artdeco-entity-lockup__caption")?.innerText.trim(),u=n.querySelector(".artdeco-entity-lockup__metadata")?.innerText.trim();return{id:l,isEasyApply:s,applyType:s?"easy-apply":"external",dataId:c.getAttribute("data-control-id"),href:`https://linkedin.com${l}`,jobTitle:f,companyName:d,location:h,salary:u||null,jobLink:s?c.href:null}}return{isEasyApply:!1}})});return e?o.filter(r=>r.isEasyApply&&r.href):o.filter(r=>r.href)}async function lt(t){let e=await t.evaluate(()=>{let o=document.querySelector('button[aria-label="View next page"]')||document.querySelector(".jobs-search-pagination__button--next");if(o&&!o.disabled){let r=document.querySelector(".jobs-search-pagination__page-state")?.textContent?.trim();return o.click(),{success:!0,pageState:r}}return{success:!1,reason:"No next page button found"}});return console.log(" Pagination:",e.success?e.pageState:e.reason),e.success&&await D(2e3),e.success}async function at(t,e){let o=t.url();if(o.includes("/jobs/"))return!1;if(o.includes("/login")||o.includes("/authwall")||o.includes("/checkpoint"))throw new Error("Session expired \u2014 redirected to login. Run: ilml linkedin login");console.log(` Off-track: ${o.slice(0,80)}`),console.log(" Navigating back to job search..."),await t.goto(e,{waitUntil:"domcontentloaded",timeout:6e4}),await D(3e3);let n=t.url();if(!n.includes("/jobs/"))throw new Error(`Could not return to job search. Current URL: ${n.slice(0,80)}`);return console.log(" Recovered to job search page"),!0}async function ut(t){return t.evaluate(()=>{let e=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,o=e.querySelector(".hirer-card__hirer-information");if(o){let s=o.querySelector('a[href*="/in/"]'),c=o.querySelector(".jobs-poster__name")||o.querySelector("strong")||o.querySelector('[class*="name"]');if(s)return{name:c?.textContent?.trim()||s.textContent?.trim(),profileUrl:s.href?.split("?")[0],source:"hiring_team"}}let r=e.querySelector(".jobs-poster__name");if(r){let s=r.closest('a[href*="/in/"]')||r.parentElement?.querySelector('a[href*="/in/"]')||r.parentElement?.parentElement?.querySelector('a[href*="/in/"]');if(s)return{name:r.textContent?.trim(),profileUrl:s.href?.split("?")[0],source:"poster_name"}}let n=e.querySelector(".job-details-people-who-can-help__section--two-pane")||e.querySelector('[class*="people-who-can-help"]');if(n){let s=n.querySelector('a[href*="/in/"]');if(s)return{name:(n.querySelector(".jobs-poster__name")||n.querySelector("strong"))?.textContent?.trim()||s.textContent?.trim(),profileUrl:s.href?.split("?")[0],source:"people_section"}}let i=e.querySelectorAll('a[href*="/in/"]');for(let s of i){let c=s.textContent?.trim();if(c&&c.length>3&&!["View","Connect","Follow","Message","Apply","Save"].includes(c))return{name:c,profileUrl:s.href?.split("?")[0],source:"details_link"}}return null})}async function ft(t){return t.evaluate(()=>{let e=document.querySelector(".scaffold-layout__detail")||document.querySelector(".jobs-search__job-details")||document.querySelector(".jobs-details")||document.body,r=(e.querySelector(".jobs-description__content")||e.querySelector(".jobs-box__html-content")||e.querySelector(".jobs-description"))?.innerText?.trim()||"",n={},i=e.querySelectorAll(".jobs-unified-top-card__job-insight, li.job-criteria__item");for(let W of i){let we=W.querySelector(".job-criteria__subheader")?.textContent?.trim(),Ue=W.querySelector(".job-criteria__text")?.textContent?.trim();we&&Ue&&(n[we.toLowerCase()]=Ue)}let s=["Java","Python","JavaScript","TypeScript","React","Angular","Vue","Node.js","C#",".NET","C\\+\\+","Go","Rust","Scala","Kotlin","AWS","Azure","GCP","Docker","Kubernetes","Terraform","SQL","PostgreSQL","MongoDB","Redis","Kafka","RabbitMQ","Spring","Django","Flask","Express","Next.js","CI/CD","Jenkins","GitHub Actions","GraphQL","REST","Microservices","Machine Learning","AI","Data Engineering","Spark","Hadoop","Snowflake","Databricks","Airflow","iOS","Android","React Native","Flutter","Agile","Scrum","DevOps","SRE"],c=[];for(let W of s)new RegExp("\\b"+W.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"\\b","i").test(r)&&c.push(W.replace(/\\\+/g,"+"));let f=e.querySelector('.jobs-company__box, [class*="jobs-company"], [class*="company-card"]')?.innerText?.trim()?.slice(0,1e3)||null,h=e.querySelector('a.jobs-apply-button[href], a[data-tracking-control-name="public_jobs_apply-link-offsite_sign-up"]')?.getAttribute("href")||null,u=e.querySelector(".job-details-jobs-unified-top-card__company-name, .jobs-unified-top-card__company-name"),p=u?.innerText?.trim()||null,S=(u?.querySelector('a[href*="/company/"]')||e.querySelector('a[href*="/company/"]'))?.getAttribute("href")?.split("?")[0]||null,g=e.querySelector(".job-details-jobs-unified-top-card__primary-description-container")?.innerText?.trim()||"",M=g.match(/(\d+\s+(?:hour|day|week|month)s?\s+ago|Reposted|Just now)/i)?.[0]||null,U=g.match(/(\d[\d,]*)\s+applicant/i),ge=U?parseInt(U[1].replace(/,/g,"")):null,Se=e.querySelectorAll(".job-details-jobs-unified-top-card__job-insight"),ce=Array.from(Se).map(W=>W.innerText?.trim()?.replace(/\s+/g," ")),be=ce.join(" ").match(/([\d,]+-[\d,]+\s+employees|[\d,]+\+?\s+employees)/i)?.[0]||null,q=ce.join(" ")+" "+g,Vt=/\bremote\b/i.test(q)?"remote":/\bhybrid\b/i.test(q)?"hybrid":/\bon-?site\b/i.test(q)?"onsite":null,Kt=/\bcontract\b/i.test(q)?"contract":/\bfull-?time\b/i.test(q)?"full-time":/\bpart-?time\b/i.test(q)?"part-time":/\bfreelance\b/i.test(q)?"freelance":/\btemporary\b/i.test(q)?"temporary":null,Pe=e.querySelector(".job-details-jobs-unified-top-card__job-title, .jobs-unified-top-card__job-title, h2.t-24")?.innerText?.trim()||"",ae=e.querySelector(".job-details-jobs-unified-top-card__primary-description-container, .jobs-unified-top-card__subtitle-primary-grouping")?.innerText?.trim()||"",I=(Pe+" "+r+" "+ae).toLowerCase(),R=Pe.toLowerCase(),m=[];/\bremote\b/.test(I)&&m.push("remote"),/\bhybrid\b/.test(I)&&m.push("hybrid"),/\bon-?site\b|\bin-?office\b/.test(I)&&m.push("onsite"),(m.length===0||!m.includes("remote")&&!m.includes("hybrid")&&!m.includes("onsite"))&&/remote/i.test(ae)&&m.push("remote"),/\b(manager|director|vp|vice president|head of|chief|cto|cio|lead.*team|managing)\b/i.test(R)&&m.push("managerial"),/\b(architect|principal|staff|distinguished)\b/i.test(R)&&m.push("senior-ic"),/\b(developer|engineer|programmer|analyst)\b/i.test(R)&&!m.includes("managerial")&&m.push("ic"),/\b(junior|jr\.?|entry)\b/i.test(R)?m.push("junior"):/\b(senior|sr\.?)\b/i.test(R)?m.push("senior"):/\b(staff|principal|distinguished)\b/i.test(R)?m.push("staff+"):/\b(director|vp|chief|cto|cio)\b/i.test(R)?m.push("executive"):/\b(lead|team lead)\b/i.test(R)&&m.push("lead"),/\b(backend|back-end|server-side|api)\b/i.test(I)&&m.push("backend"),/\b(frontend|front-end|ui|ux)\b/i.test(I)&&m.push("frontend"),/\b(full.?stack|fullstack)\b/i.test(I)&&m.push("fullstack"),/\b(devops|sre|infrastructure|platform)\b/i.test(I)&&m.push("devops"),/\b(data engineer|data science|machine learning|ml engineer)\b/i.test(I)&&m.push("data"),/\b(mobile|ios|android|react native|flutter)\b/i.test(I)&&m.push("mobile"),/\b(architect)\b/i.test(R)&&m.push("architect"),/\b(consultant|consulting)\b/i.test(R)&&m.push("consultant");let Me=(n["employment type"]||"").toLowerCase();return(/contract|freelance|temporary/i.test(Me)||/\bcontract\b/i.test(I))&&m.push("contract"),/full.?time|permanent/i.test(Me)&&m.push("permanent"),/\bcanada\b|toronto|vancouver|montreal|ontario|british columbia|quebec|alberta|calgary|ottawa/i.test(ae)&&m.push("canada"),/\bunited states\b|\busa\b|new york|california|texas|seattle|san francisco/i.test(ae)&&m.push("usa"),(e.querySelector(".jobs-unified-top-card__job-insight--highlight, .compensation__salary")?.innerText?.trim()||""||/\$[\d,]+/.test(r))&&m.push("has-salary"),{description:r.substring(0,5e3),externalApplyUrl:h,companyName:p,companyUrl:S?S.startsWith("/")?"https://www.linkedin.com"+S:S:null,aboutCompany:f,seniority:n["seniority level"]||null,employmentType:n["employment type"]||null,industries:n.industries||null,jobFunction:n["job function"]||null,postedTime:M,applicantCount:ge,companySize:be,workplaceType:Vt,contractType:Kt,techStack:[...new Set(c)],jobTags:[...new Set(m)]}})}import"dotenv/config";import*as E from"fs";import*as _ from"path";import{fileURLToPath as po}from"url";function pt(t){if(!t||typeof t!="string"||/custom-invite|\/search\//i.test(t)||/\/in\/[^/?#]+\/(overlay|details)(\/|$)/i.test(t))return null;let e=t.match(/\/in\/([^/?#]+)/i);if(!e||!e[1])return null;let o=e[1].trim();return o?`https://www.linkedin.com/in/${o}/`:null}var mo=po(import.meta.url),ho=_.dirname(_.dirname(mo)),K=process.env.DATA_DIR?_.resolve(process.env.DATA_DIR,"market-research"):_.join(ho,"market-research"),dt=_.join(K,"scouted-jobs.json"),mt=_.join(K,"discovered-people.json"),yo=_.join(K,"visit-log.json"),ht=_.join(K,"companies.json"),mr=_.join(K,"job-decisions.json");function Ae(){E.existsSync(K)||E.mkdirSync(K,{recursive:!0})}function _e(t,e){let o=JSON.stringify(e,null,2),r=t+".tmp";E.writeFileSync(r,o);for(let n=0;n<3;n++)try{E.renameSync(r,t);return}catch(i){if(n<2&&(i.code==="EPERM"||i.code==="EBUSY")){let s=Date.now();for(;Date.now()-s<200;);continue}throw i}}function de(t){try{if(E.existsSync(t))return JSON.parse(E.readFileSync(t,"utf-8"))}catch{}return null}function yt(){te=null,go=null,oe=null,ne=null,V=null}var te=null;function me(){return te||(te=de(dt)||{},te)}function gt(t,e){if(!t)return;Ae();let o=me(),r=new Date().toISOString().slice(0,10);if(o[t]){for(let[n,i]of Object.entries(e))i!=null&&(o[t][n]=i);o[t].lastSeen=r}else o[t]={...e,scoutedAt:r,lastSeen:r};try{_e(dt,o)}catch(n){console.error(`[!] Failed to save scouted-jobs.json: ${n.message}`)}}var go=null;var oe=null;function St(){return oe||(oe=de(mt)||{},oe)}function pe(t){let e=String(t||"").match(/\/in\/([^/?#]+)/i);return e?e[1].toLowerCase():null}function So(t,e){let o=pt(e)||e;if(t[o])return o;let r=pe(e);if(!r)return o;let n=null;for(let[i,s]of Object.entries(t)){if(pe(s&&(s.canonicalUrl||s.profileUrl)||i)===r)return i;!n&&s&&Array.isArray(s.aliases)&&s.aliases.includes(r)&&(n=i)}return n||o}function bt(t,e){if(!t)return;Ae();let o=St(),r=new Date().toISOString().slice(0,10),n=So(o,t),i=pe(t);if(o[n]){let s=o[n];e.name&&(s.name=e.name),e.title&&(s.title=e.title),e.company&&(s.company=e.company),e.location&&(s.location=e.location),e.role&&(s.role=e.role),e.isConnected!=null&&(s.isConnected=e.isConnected),e.jobId&&(s.jobIds||(s.jobIds=[]),s.jobIds.includes(e.jobId)||s.jobIds.push(e.jobId)),i&&pe(s.canonicalUrl||s.profileUrl||n)!==i&&(Array.isArray(s.aliases)||(s.aliases=[]),s.aliases.includes(i)||s.aliases.push(i)),s.lastSeen=r,s.seenCount=(s.seenCount||1)+1}else o[n]={canonicalUrl:n,aliases:[],name:e.name||null,title:e.title||null,company:e.company||null,location:e.location||null,role:e.role||null,source:e.source||"scout",isConnected:e.isConnected||!1,discoveredAt:r,lastSeen:r,seenCount:1,jobIds:e.jobId?[e.jobId]:[]};try{_e(mt,o)}catch(s){console.error(`[!] Failed to save discovered-people.json: ${s.message}`)}}var ne=null;function bo(){return ne||(ne=de(ht)||{},ne)}function wt(t,e){if(!t)return;Ae();let o=bo(),r=new Date().toISOString().slice(0,10);if(o[t]){let n=o[t];e.name&&(n.name=e.name),e.about&&(n.about=e.about),e.size&&(n.size=e.size),e.industries&&(n.industries=e.industries),e.jobId&&(n.jobIds||(n.jobIds=[]),n.jobIds.includes(e.jobId)||n.jobIds.push(e.jobId)),e.recruiterUrl&&(n.recruiterUrls||(n.recruiterUrls=[]),n.recruiterUrls.includes(e.recruiterUrl)||n.recruiterUrls.push(e.recruiterUrl)),n.lastSeen=r,n.jobCount=n.jobIds?.length||0}else o[t]={name:e.name||null,about:e.about||null,size:e.size||null,industries:e.industries||null,discoveredAt:r,lastSeen:r,jobIds:e.jobId?[e.jobId]:[],recruiterUrls:e.recruiterUrl?[e.recruiterUrl]:[],jobCount:e.jobId?1:0};try{_e(ht,o)}catch(n){console.error(`[!] Failed to save companies.json: ${n.message}`)}}var V=null;function wo(){return V||(V=de(yo)||{visits:[]},Array.isArray(V.visits)||(V.visits=[]),V)}function vt(){let t=me(),e=St(),o=Object.values(t),r=Object.values(e),n={};for(let u of o)u.company&&(n[u.company]=(n[u.company]||0)+1);let i=Object.entries(n).sort((u,p)=>p[1]-u[1]).slice(0,5).map(([u,p])=>`${u} (${p})`),s={};for(let u of o)for(let p of u.techStack||[])s[p]=(s[p]||0)+1;let c=Object.entries(s).sort((u,p)=>p[1]-u[1]).slice(0,8).map(([u,p])=>`${u} (${p})`),l=wo(),f=new Date().toISOString().slice(0,10),d=l.visits.filter(u=>u.date.startsWith(f)).length,h=new Set(l.visits.map(u=>u.profileUrl)).size;return{totalJobs:o.length,totalRecruiters:r.length,topCompanies:i,topTech:c,totalVisited:h,todayVisited:d,lastScoutDate:o.length>0?o.sort((u,p)=>(p.scoutedAt||"").localeCompare(u.scoutedAt||""))[0]?.scoutedAt:null}}import"dotenv/config";import*as b from"fs";import*as v from"path";import{fileURLToPath as vo}from"url";var ko=vo(import.meta.url),Ao=v.dirname(v.dirname(ko)),F=process.env.DATA_DIR?v.resolve(process.env.DATA_DIR,"collected-profiles"):v.join(Ao,"collected-profiles"),_o=v.join(F,"people.json"),Eo=v.join(F,"jobs.json"),br=v.join(F,"quota.json"),wr=v.join(F,"conversations.json"),vr=v.join(F,"sync-state.json"),kr=v.join(F,"application-questions.json"),Ar=v.join(F,"profile-history"),kt=(t,e)=>{let o=parseInt(t,10);return Number.isInteger(o)&&o>=0?o:e},_r=kt(process.env.CONNECT_MAX_DAILY,20),Er=kt(process.env.CONNECT_MAX_WEEKLY,100),re=null,se=null,jo=null,xo=null,Co=null,To=null;function At(){re=null,se=null,jo=null,xo=null,Co=null,To=null}function _t(){b.existsSync(F)||b.mkdirSync(F,{recursive:!0})}function Et(t,e){if(!b.existsSync(t))return null;try{let o=JSON.parse(b.readFileSync(t,"utf-8"));try{b.copyFileSync(t,t+".backup")}catch{}return o}catch(o){console.error(`[!] ${e} is corrupted: ${o.message}`),console.error(` File: ${v.resolve(t)}`);let r=t+".backup";if(b.existsSync(r))try{let n=JSON.parse(b.readFileSync(r,"utf-8"));console.error(` Restored from ${r}`);try{b.copyFileSync(r,t)}catch{}return n}catch{console.error(" Backup also corrupted!")}console.error(` Starting with empty data. Old file preserved as ${t}.corrupted`);try{b.copyFileSync(t,t+".corrupted")}catch{}return null}}function jt(){return re||(_t(),re=Et(_o,"people.json")||{},re)}function xt(){return se||(_t(),se=Et(Eo,"jobs.json")||{},se)}import"dotenv/config";import*as j from"fs";import*as J from"path";import{fileURLToPath as No}from"url";import"dotenv/config";import{createGraphClient as $o,resolveToken as Io}from"@ilivemylife/graph-sdk";import{config as Ro}from"dotenv";Ro();var Ct=Io()||process.env.TOKEN;Ct||(console.error(`
|
|
2
2
|
[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.
|
|
3
3
|
`),console.error(" Easiest way:"),console.error(" 1. npm install -g @ilivemylife/graph-sdk"),console.error(` 2. ilml login your@email.com yourpassword
|
|
4
4
|
`),console.error(` Or add ILML_TOKEN=... to .env
|