terminalhire 0.2.2 → 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;
@@ -3066,7 +3267,7 @@ async function run8() {
3066
3267
  console.log("This will:");
3067
3268
  console.log(" 1. Optionally sign you in with GitHub (public profile only, read:user)");
3068
3269
  console.log(" 2. Seed your local job cache (anonymous index download)");
3069
- console.log(" 3. Install the statusLine hook in ~/.claude/settings.json");
3270
+ console.log(" 3. Enable the ambient spinner job surface in ~/.claude/settings.json");
3070
3271
  console.log(" (with backup + your explicit consent before any file is touched)");
3071
3272
  console.log("");
3072
3273
  console.log('You can stop at any step. Nothing is changed until you say "yes".');
@@ -3119,11 +3320,11 @@ async function run8() {
3119
3320
  console.log(" Run `terminalhire jobs` after a few Claude Code sessions to populate it.");
3120
3321
  }
3121
3322
  console.log("");
3122
- console.log("Step 3/3 \u2014 Install statusLine hook in ~/.claude/settings.json");
3323
+ console.log("Step 3/3 \u2014 Enable the ambient spinner job surface in ~/.claude/settings.json");
3123
3324
  console.log("");
3124
3325
  console.log(" This is the only step that modifies a system file.");
3125
3326
  console.log(" A timestamped backup is created before any change.");
3126
- console.log(" Uninstall at any time: node install.js --uninstall");
3327
+ console.log(" Disable at any time: node install.js --uninstall (or terminalhire spinner --off)");
3127
3328
  console.log("");
3128
3329
  const installJs = resolveInstallJs();
3129
3330
  const installChild = spawnSync(process.execPath, [installJs], {
@@ -3138,11 +3339,11 @@ async function run8() {
3138
3339
  console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
3139
3340
  console.log("\u2502 terminalhire init complete! \u2502");
3140
3341
  console.log("\u2502 \u2502");
3141
- console.log("\u2502 Restart Claude Code to see the statusLine nudge. \u2502");
3342
+ console.log("\u2502 Restart Claude Code to see the ambient spinner job surface. \u2502");
3142
3343
  console.log("\u2502 \u2502");
3143
3344
  console.log("\u2502 Quick reference: \u2502");
3144
3345
  console.log("\u2502 terminalhire jobs \u2014 browse matching roles \u2502");
3145
- console.log("\u2502 terminalhire config --show \u2014 view nudge settings \u2502");
3346
+ console.log("\u2502 terminalhire spinner --off \u2014 disable the spinner surface \u2502");
3146
3347
  console.log("\u2502 terminalhire login \u2014 sign in with GitHub \u2502");
3147
3348
  console.log("\u2502 terminalhire profile --show \u2014 inspect your local profile \u2502");
3148
3349
  console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
@@ -39,7 +39,7 @@ async function run() {
39
39
  console.log("This will:");
40
40
  console.log(" 1. Optionally sign you in with GitHub (public profile only, read:user)");
41
41
  console.log(" 2. Seed your local job cache (anonymous index download)");
42
- console.log(" 3. Install the statusLine hook in ~/.claude/settings.json");
42
+ console.log(" 3. Enable the ambient spinner job surface in ~/.claude/settings.json");
43
43
  console.log(" (with backup + your explicit consent before any file is touched)");
44
44
  console.log("");
45
45
  console.log('You can stop at any step. Nothing is changed until you say "yes".');
@@ -92,11 +92,11 @@ async function run() {
92
92
  console.log(" Run `terminalhire jobs` after a few Claude Code sessions to populate it.");
93
93
  }
94
94
  console.log("");
95
- console.log("Step 3/3 \u2014 Install statusLine hook in ~/.claude/settings.json");
95
+ console.log("Step 3/3 \u2014 Enable the ambient spinner job surface in ~/.claude/settings.json");
96
96
  console.log("");
97
97
  console.log(" This is the only step that modifies a system file.");
98
98
  console.log(" A timestamped backup is created before any change.");
99
- console.log(" Uninstall at any time: node install.js --uninstall");
99
+ console.log(" Disable at any time: node install.js --uninstall (or terminalhire spinner --off)");
100
100
  console.log("");
101
101
  const installJs = resolveInstallJs();
102
102
  const installChild = spawnSync(process.execPath, [installJs], {
@@ -111,11 +111,11 @@ async function run() {
111
111
  console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
112
112
  console.log("\u2502 terminalhire init complete! \u2502");
113
113
  console.log("\u2502 \u2502");
114
- console.log("\u2502 Restart Claude Code to see the statusLine nudge. \u2502");
114
+ console.log("\u2502 Restart Claude Code to see the ambient spinner job surface. \u2502");
115
115
  console.log("\u2502 \u2502");
116
116
  console.log("\u2502 Quick reference: \u2502");
117
117
  console.log("\u2502 terminalhire jobs \u2014 browse matching roles \u2502");
118
- console.log("\u2502 terminalhire config --show \u2014 view nudge settings \u2502");
118
+ console.log("\u2502 terminalhire spinner --off \u2014 disable the spinner surface \u2502");
119
119
  console.log("\u2502 terminalhire login \u2014 sign in with GitHub \u2502");
120
120
  console.log("\u2502 terminalhire profile --show \u2014 inspect your local profile \u2502");
121
121
  console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");