terminalhire 0.2.3 → 0.2.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.
@@ -747,16 +747,102 @@ var init_ashby = __esm({
747
747
  }
748
748
  });
749
749
 
750
- // ../../packages/core/src/feeds/himalayas.ts
750
+ // ../../packages/core/src/feeds/lever.ts
751
751
  function tokenize3(text) {
752
752
  return text.toLowerCase().replace(/[^a-z0-9.\-+#]/g, " ").split(/\s+/).filter(Boolean);
753
753
  }
754
- function extractTags3(job) {
754
+ function extractTags3(p) {
755
+ const cat = p.categories ?? {};
756
+ const texts = [
757
+ p.text,
758
+ cat.team ?? "",
759
+ cat.department ?? "",
760
+ cat.location ?? "",
761
+ ...cat.allLocations ?? [],
762
+ p.descriptionPlain ?? ""
763
+ ];
764
+ return normalize(texts.flatMap(tokenize3));
765
+ }
766
+ function mapCommitment(raw) {
767
+ if (!raw) return "full_time";
768
+ const lower = raw.toLowerCase();
769
+ if (lower.includes("contract") || lower.includes("contractor")) return "contract";
770
+ if (lower.includes("freelance")) return "freelance";
771
+ return "full_time";
772
+ }
773
+ function inferRemote3(p) {
774
+ if ((p.workplaceType ?? "").toLowerCase() === "remote") return true;
775
+ const cat = p.categories ?? {};
776
+ const haystack = [cat.location ?? "", ...cat.allLocations ?? []].join(" ").toLowerCase();
777
+ return haystack.includes("remote") || haystack.includes("anywhere");
778
+ }
779
+ function toIso(ms) {
780
+ if (typeof ms !== "number" || !Number.isFinite(ms)) return void 0;
781
+ try {
782
+ return new Date(ms).toISOString();
783
+ } catch {
784
+ return void 0;
785
+ }
786
+ }
787
+ async function fetchSlug3(slug) {
788
+ const url = `https://api.lever.co/v0/postings/${slug}?mode=json`;
789
+ const res = await fetch(url, { headers: { Accept: "application/json" } });
790
+ if (!res.ok) {
791
+ throw new Error(`Lever ${slug}: HTTP ${res.status}`);
792
+ }
793
+ const data = await res.json();
794
+ const postings = Array.isArray(data) ? data : [];
795
+ if (postings.length === 0) {
796
+ console.warn(`[lever] ${slug}: 0 jobs returned (board may be private or slug invalid)`);
797
+ } else {
798
+ console.info(`[lever] ${slug}: ${postings.length} jobs`);
799
+ }
800
+ return postings.filter((p) => p && p.id && p.text).map((p) => ({
801
+ id: `lever:${p.id}`,
802
+ source: "lever",
803
+ title: p.text,
804
+ company: slug,
805
+ url: p.hostedUrl ?? p.applyUrl ?? `https://jobs.lever.co/${slug}/${p.id}`,
806
+ remote: inferRemote3(p),
807
+ location: p.categories?.location,
808
+ tags: extractTags3(p),
809
+ roleType: mapCommitment(p.categories?.commitment),
810
+ postedAt: toIso(p.createdAt),
811
+ applyMode: "direct",
812
+ raw: p
813
+ }));
814
+ }
815
+ var lever;
816
+ var init_lever = __esm({
817
+ "../../packages/core/src/feeds/lever.ts"() {
818
+ "use strict";
819
+ init_vocabulary();
820
+ lever = {
821
+ source: "lever",
822
+ async fetch(opts) {
823
+ const slugs = opts?.slugs ?? [];
824
+ const results = await Promise.allSettled(slugs.map(fetchSlug3));
825
+ const jobs = [];
826
+ for (const r of results) {
827
+ if (r.status === "fulfilled") jobs.push(...r.value);
828
+ else console.warn("[lever] slug fetch rejected:", r.reason);
829
+ }
830
+ return jobs;
831
+ }
832
+ };
833
+ }
834
+ });
835
+
836
+ // ../../packages/core/src/feeds/himalayas.ts
837
+ function tokenize4(text) {
838
+ return text.toLowerCase().replace(/[^a-z0-9.\-+#]/g, " ").split(/\s+/).filter(Boolean);
839
+ }
840
+ function extractTags4(job) {
755
841
  const texts = [
756
842
  job.title,
757
843
  ...job.tags ?? []
758
844
  ];
759
- return normalize(texts.flatMap(tokenize3));
845
+ return normalize(texts.flatMap(tokenize4));
760
846
  }
761
847
  function mapJobType(raw) {
762
848
  if (!raw) return "full_time";
@@ -802,7 +888,7 @@ var init_himalayas = __esm({
802
888
  location: (j.locationRestrictions ?? []).join(", ") || "Remote",
803
889
  compMin: j.salaryMin,
804
890
  compMax: j.salaryMax,
805
- tags: extractTags3(j),
891
+ tags: extractTags4(j),
806
892
  roleType: mapJobType(j.jobType),
807
893
  postedAt: j.pubDate ?? j.createdAt,
808
894
  applyMode: "direct",
@@ -814,7 +900,7 @@ var init_himalayas = __esm({
814
900
  });
815
901
 
816
902
  // ../../packages/core/src/feeds/wwr.ts
817
- function tokenize4(text) {
903
+ function tokenize5(text) {
818
904
  return text.toLowerCase().replace(/[^a-z0-9.\-+#]/g, " ").split(/\s+/).filter(Boolean);
819
905
  }
820
906
  function stripHtml(html) {
@@ -856,9 +942,9 @@ function parseRss(xml) {
856
942
  }
857
943
  return items;
858
944
  }
859
- function extractTags4(item) {
945
+ function extractTags5(item) {
860
946
  const text = [item.title, item.category, stripHtml(item.description)].join(" ");
861
- return normalize(tokenize4(text));
947
+ return normalize(tokenize5(text));
862
948
  }
863
949
  var WWR_RSS_URL, wwr;
864
950
  var init_wwr = __esm({
@@ -887,7 +973,7 @@ var init_wwr = __esm({
887
973
  // WWR is a remote-only board
888
974
  remote: true,
889
975
  location: "Remote",
890
- tags: extractTags4(item),
976
+ tags: extractTags5(item),
891
977
  roleType: inferRoleType(item.category),
892
978
  postedAt: item.pubDate ? new Date(item.pubDate).toISOString() : void 0,
893
979
  applyMode: "direct",
@@ -899,7 +985,7 @@ var init_wwr = __esm({
899
985
  });
900
986
 
901
987
  // ../../packages/core/src/feeds/hn.ts
902
- function tokenize5(text) {
988
+ function tokenize6(text) {
903
989
  return text.toLowerCase().replace(/[^a-z0-9.\-+#]/g, " ").split(/\s+/).filter(Boolean);
904
990
  }
905
991
  function stripHtml2(html) {
@@ -909,7 +995,7 @@ function extractUrl(text) {
909
995
  const match2 = text.match(/https?:\/\/[^\s<>"']+/);
910
996
  return match2?.[0] ?? "";
911
997
  }
912
- function inferRemote3(text) {
998
+ function inferRemote4(text) {
913
999
  const lower = text.toLowerCase();
914
1000
  return lower.includes("remote") || lower.includes("anywhere") || lower.includes("distributed");
915
1001
  }
@@ -932,7 +1018,7 @@ function parseComment(item) {
932
1018
  return null;
933
1019
  }
934
1020
  const url = extractUrl(raw) || `https://news.ycombinator.com/item?id=${item.id}`;
935
- const tags = extractTags5(raw);
1021
+ const tags = extractTags6(raw);
936
1022
  if (tags.length === 0) return null;
937
1023
  return {
938
1024
  id: `hn:${item.id}`,
@@ -940,7 +1026,7 @@ function parseComment(item) {
940
1026
  title: title.slice(0, 120),
941
1027
  company: company.slice(0, 80),
942
1028
  url,
943
- remote: inferRemote3(raw),
1029
+ remote: inferRemote4(raw),
944
1030
  location: location || void 0,
945
1031
  tags,
946
1032
  roleType: inferRoleType2(raw),
@@ -949,8 +1035,8 @@ function parseComment(item) {
949
1035
  raw: item
950
1036
  };
951
1037
  }
952
- function extractTags5(text) {
953
- return normalize(tokenize5(text));
1038
+ function extractTags6(text) {
1039
+ return normalize(tokenize6(text));
954
1040
  }
955
1041
  var ALGOLIA_SEARCH, ALGOLIA_ITEMS, hn;
956
1042
  var init_hn = __esm({
@@ -994,20 +1080,25 @@ var init_hn = __esm({
994
1080
  });
995
1081
 
996
1082
  // ../../packages/core/src/feeds/index.ts
1083
+ function flattenTiers(t) {
1084
+ return [.../* @__PURE__ */ new Set([...t.bigco, ...t.scaleup, ...t.startup])];
1085
+ }
997
1086
  async function aggregate(opts) {
998
1087
  const ghSlugs = opts?.slugs?.["greenhouse"] ?? DEFAULT_GREENHOUSE_SLUGS;
999
1088
  const ashbySlugs = opts?.slugs?.["ashby"] ?? DEFAULT_ASHBY_SLUGS;
1089
+ const leverSlugs = opts?.slugs?.["lever"] ?? DEFAULT_LEVER_SLUGS;
1000
1090
  const limit = opts?.limit ?? 150;
1001
1091
  const settled = await Promise.allSettled([
1002
1092
  greenhouse.fetch({ slugs: ghSlugs, limit }),
1003
1093
  ashby.fetch({ slugs: ashbySlugs, limit }),
1094
+ lever.fetch({ slugs: leverSlugs, limit }),
1004
1095
  himalayas.fetch({ limit }),
1005
1096
  wwr.fetch({ limit }),
1006
1097
  hn.fetch({ limit })
1007
1098
  ]);
1008
1099
  const seen = /* @__PURE__ */ new Set();
1009
1100
  const jobs = [];
1010
- const sourceNames = ["greenhouse", "ashby", "himalayas", "wwr", "hn"];
1101
+ const sourceNames = ["greenhouse", "ashby", "lever", "himalayas", "wwr", "hn"];
1011
1102
  for (let i = 0; i < settled.length; i++) {
1012
1103
  const result = settled[i];
1013
1104
  if (result.status === "rejected") {
@@ -1023,46 +1114,122 @@ async function aggregate(opts) {
1023
1114
  }
1024
1115
  return jobs;
1025
1116
  }
1026
- var FEEDS, DEFAULT_GREENHOUSE_SLUGS, DEFAULT_ASHBY_SLUGS;
1117
+ var FEEDS, GREENHOUSE_SLUGS_BY_TIER, ASHBY_SLUGS_BY_TIER, LEVER_SLUGS_BY_TIER, DEFAULT_GREENHOUSE_SLUGS, DEFAULT_ASHBY_SLUGS, DEFAULT_LEVER_SLUGS;
1027
1118
  var init_feeds = __esm({
1028
1119
  "../../packages/core/src/feeds/index.ts"() {
1029
1120
  "use strict";
1030
1121
  init_greenhouse();
1031
1122
  init_ashby();
1123
+ init_lever();
1032
1124
  init_himalayas();
1033
1125
  init_wwr();
1034
1126
  init_hn();
1035
- FEEDS = [greenhouse, ashby, himalayas, wwr, hn];
1036
- DEFAULT_GREENHOUSE_SLUGS = [
1037
- "stripe",
1038
- "linear",
1039
- "vercel",
1040
- "ramp",
1041
- "notion",
1042
- "airbnb",
1043
- "anthropic",
1044
- "figma",
1045
- "discord",
1046
- "brex",
1047
- "mercury",
1048
- "retool",
1049
- "vanta",
1050
- "plaid",
1051
- "gusto",
1052
- "scale",
1053
- "databricks",
1054
- "coinbase",
1055
- "robinhood",
1056
- "doordash"
1057
- ];
1058
- DEFAULT_ASHBY_SLUGS = [
1059
- "ramp",
1060
- "notion",
1061
- "linear",
1062
- "vercel",
1063
- "replit",
1064
- "posthog"
1065
- ];
1127
+ FEEDS = [greenhouse, ashby, lever, himalayas, wwr, hn];
1128
+ GREENHOUSE_SLUGS_BY_TIER = {
1129
+ bigco: [
1130
+ "stripe",
1131
+ "anthropic",
1132
+ "figma",
1133
+ "discord",
1134
+ "brex",
1135
+ "mercury",
1136
+ "plaid",
1137
+ "gusto",
1138
+ "scale",
1139
+ "databricks",
1140
+ "coinbase",
1141
+ "robinhood",
1142
+ "doordash",
1143
+ "airbnb",
1144
+ "dropbox",
1145
+ "datadog",
1146
+ "cloudflare",
1147
+ "reddit",
1148
+ "lyft",
1149
+ "instacart"
1150
+ ],
1151
+ scaleup: [
1152
+ "samsara",
1153
+ "verkada",
1154
+ "affirm",
1155
+ "gitlab",
1156
+ "asana",
1157
+ "flexport",
1158
+ "faire",
1159
+ "twitch",
1160
+ "airtable",
1161
+ "retool"
1162
+ ],
1163
+ startup: [
1164
+ "watershed"
1165
+ ]
1166
+ };
1167
+ ASHBY_SLUGS_BY_TIER = {
1168
+ bigco: [
1169
+ "openai"
1170
+ ],
1171
+ scaleup: [
1172
+ "harvey",
1173
+ "elevenlabs",
1174
+ "notion",
1175
+ "sierra",
1176
+ "cohere",
1177
+ "ramp",
1178
+ "vanta",
1179
+ "decagon",
1180
+ "cursor",
1181
+ "replit",
1182
+ "perplexity",
1183
+ "baseten",
1184
+ "drata",
1185
+ "writer",
1186
+ "temporal",
1187
+ "supabase"
1188
+ ],
1189
+ startup: [
1190
+ "suno",
1191
+ "attio",
1192
+ "modal",
1193
+ "workos",
1194
+ "linear",
1195
+ "render",
1196
+ "warp",
1197
+ "plain",
1198
+ "posthog",
1199
+ "pylon",
1200
+ "resend",
1201
+ "langfuse",
1202
+ "railway",
1203
+ "mintlify",
1204
+ "neon",
1205
+ "browserbase",
1206
+ "knock",
1207
+ "speakeasy",
1208
+ "stytch",
1209
+ "runway",
1210
+ "doppler",
1211
+ "inngest",
1212
+ "hightouch",
1213
+ "zed"
1214
+ ]
1215
+ };
1216
+ LEVER_SLUGS_BY_TIER = {
1217
+ bigco: [
1218
+ "palantir",
1219
+ "spotify"
1220
+ ],
1221
+ scaleup: [
1222
+ "mistral",
1223
+ "ro",
1224
+ "secureframe"
1225
+ ],
1226
+ startup: [
1227
+ "anyscale"
1228
+ ]
1229
+ };
1230
+ DEFAULT_GREENHOUSE_SLUGS = flattenTiers(GREENHOUSE_SLUGS_BY_TIER);
1231
+ DEFAULT_ASHBY_SLUGS = flattenTiers(ASHBY_SLUGS_BY_TIER);
1232
+ DEFAULT_LEVER_SLUGS = flattenTiers(LEVER_SLUGS_BY_TIER);
1066
1233
  }
1067
1234
  });
1068
1235
 
@@ -1249,10 +1416,14 @@ var init_github = __esm({
1249
1416
  // ../../packages/core/src/index.ts
1250
1417
  var src_exports = {};
1251
1418
  __export(src_exports, {
1419
+ ASHBY_SLUGS_BY_TIER: () => ASHBY_SLUGS_BY_TIER,
1252
1420
  COASTAL_BUYER: () => COASTAL_BUYER,
1253
1421
  DEFAULT_ASHBY_SLUGS: () => DEFAULT_ASHBY_SLUGS,
1254
1422
  DEFAULT_GREENHOUSE_SLUGS: () => DEFAULT_GREENHOUSE_SLUGS,
1423
+ DEFAULT_LEVER_SLUGS: () => DEFAULT_LEVER_SLUGS,
1255
1424
  FEEDS: () => FEEDS,
1425
+ GREENHOUSE_SLUGS_BY_TIER: () => GREENHOUSE_SLUGS_BY_TIER,
1426
+ LEVER_SLUGS_BY_TIER: () => LEVER_SLUGS_BY_TIER,
1256
1427
  SYNONYMS: () => SYNONYMS,
1257
1428
  VOCABULARY: () => VOCABULARY,
1258
1429
  aggregate: () => aggregate,
@@ -1260,10 +1431,12 @@ __export(src_exports, {
1260
1431
  buildIndex: () => buildIndex,
1261
1432
  buildReason: () => buildReason,
1262
1433
  fetchGitHubProfile: () => fetchGitHubProfile,
1434
+ flattenTiers: () => flattenTiers,
1263
1435
  githubToFingerprint: () => githubToFingerprint,
1264
1436
  greenhouse: () => greenhouse,
1265
1437
  himalayas: () => himalayas,
1266
1438
  hn: () => hn,
1439
+ lever: () => lever,
1267
1440
  loadCoastalRoles: () => loadCoastalRoles,
1268
1441
  match: () => match,
1269
1442
  matchOne: () => matchOne,
@@ -2321,6 +2494,7 @@ __export(spinner_exports, {
2321
2494
  clearSpinnerVerbs: () => clearSpinnerVerbs,
2322
2495
  ctaVerb: () => ctaVerb,
2323
2496
  formatVerbs: () => formatVerbs,
2497
+ interleaveBySource: () => interleaveBySource,
2324
2498
  rankBySessionTags: () => rankBySessionTags,
2325
2499
  readSpinnerConfig: () => readSpinnerConfig
2326
2500
  });
@@ -2474,13 +2648,40 @@ function clearSpinnerVerbs() {
2474
2648
  }
2475
2649
  return { cleared: true, keptUserVerbs };
2476
2650
  }
2651
+ function interleaveBySource(topMatches) {
2652
+ if (!Array.isArray(topMatches) || topMatches.length === 0) return topMatches;
2653
+ const buckets = /* @__PURE__ */ new Map();
2654
+ const order = [];
2655
+ for (const m of topMatches) {
2656
+ const id = m && m.id ? String(m.id) : "";
2657
+ const idx = id.indexOf(":");
2658
+ const source = idx > 0 ? id.slice(0, idx) : "_";
2659
+ if (!buckets.has(source)) {
2660
+ buckets.set(source, []);
2661
+ order.push(source);
2662
+ }
2663
+ buckets.get(source).push(m);
2664
+ }
2665
+ const out = [];
2666
+ let remaining = topMatches.length;
2667
+ while (remaining > 0) {
2668
+ for (const source of order) {
2669
+ const b = buckets.get(source);
2670
+ if (b && b.length) {
2671
+ out.push(b.shift());
2672
+ remaining--;
2673
+ }
2674
+ }
2675
+ }
2676
+ return out;
2677
+ }
2477
2678
  function buildTips(topMatches, baseUrl, max = 8) {
2478
2679
  const base = String(baseUrl || "https://terminalhire.com").replace(/\/+$/, "");
2479
2680
  const out = [];
2480
2681
  const seenRole = /* @__PURE__ */ new Set();
2481
2682
  const perCompany = /* @__PURE__ */ new Map();
2482
2683
  const COMPANY_CAP = 2;
2483
- for (const m of Array.isArray(topMatches) ? topMatches : []) {
2684
+ for (const m of interleaveBySource(Array.isArray(topMatches) ? topMatches : [])) {
2484
2685
  if (!m || !m.title || !m.company || !m.id) continue;
2485
2686
  const idx = String(m.id).indexOf(":");
2486
2687
  if (idx <= 0) continue;