terminalhire 0.17.0 → 0.17.2

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.
@@ -644,15 +644,90 @@ var init_vocabulary = __esm({
644
644
  }
645
645
  });
646
646
 
647
+ // ../../packages/core/src/feeds/bounty-gate.ts
648
+ function isDenylistedRepo(fullName) {
649
+ return DENYLIST_LC.has(fullName.toLowerCase());
650
+ }
651
+ function isAiBanRepo(fullName) {
652
+ const lc = fullName.toLowerCase();
653
+ const owner = lc.split("/")[0];
654
+ return AI_BAN_LC.has(lc) || AI_BAN_LC.has(owner);
655
+ }
656
+ function passesAntiFarm(amountUSD, stargazers) {
657
+ return !(amountUSD > HIGH_VALUE_USD && stargazers < HIGH_VALUE_MIN_STARS);
658
+ }
659
+ function ageDays(createdAtIso) {
660
+ const created = Date.parse(createdAtIso);
661
+ if (!Number.isFinite(created)) return 0;
662
+ return (Date.now() - created) / (1e3 * 60 * 60 * 24);
663
+ }
664
+ function passesMaturityGate(repo) {
665
+ if (isDenylistedRepo(repo.fullName)) return false;
666
+ if (isAiBanRepo(repo.fullName)) return false;
667
+ if (repo.archived || repo.disabled) return false;
668
+ if (repo.stargazers < MIN_REPO_STARS) return false;
669
+ if (ageDays(repo.createdAt) < MIN_REPO_AGE_DAYS) return false;
670
+ return true;
671
+ }
672
+ var DEFAULT_BOUNTY_REPOS, BOUNTY_REPO_DENYLIST, DENYLIST_LC, AI_BAN_DENYLIST, AI_BAN_LC, MAX_BOUNTIES_PER_REPO, MAX_BOUNTIES_PER_DISCOVERED_REPO, MIN_REPO_STARS, HIGH_VALUE_USD, HIGH_VALUE_MIN_STARS, MIN_REPO_AGE_DAYS;
673
+ var init_bounty_gate = __esm({
674
+ "../../packages/core/src/feeds/bounty-gate.ts"() {
675
+ "use strict";
676
+ DEFAULT_BOUNTY_REPOS = [
677
+ "tenstorrent/tt-metal",
678
+ "sequelize/sequelize",
679
+ "commaai/opendbc",
680
+ "aragon/hack",
681
+ "spacemeshos/app",
682
+ "archestra-ai/archestra",
683
+ "ucfopen/Obojobo",
684
+ "moorcheh-ai/memanto",
685
+ "PrismarineJS/mineflayer"
686
+ ];
687
+ BOUNTY_REPO_DENYLIST = [
688
+ "SecureBananaLabs/bug-bounty",
689
+ // Meta-farm: a bounty PLATFORM whose own issues are an assignment-gated
690
+ // contributor queue ("please assign me, my chief") — an unsolicited PR won't
691
+ // merge, so it's not a real claimable bounty. Not structurally derivable from
692
+ // any fetched field, so it's a manual entry (also dropped from the allowlist).
693
+ "boundlessfi/boundless"
694
+ ];
695
+ DENYLIST_LC = new Set(BOUNTY_REPO_DENYLIST.map((r) => r.toLowerCase()));
696
+ AI_BAN_DENYLIST = [
697
+ // Gentoo Council voted 6-0 (2024-04-14) to ban AI/ML-generated contributions
698
+ // project-wide. https://wiki.gentoo.org/wiki/Project:Council/AI_policy
699
+ "gentoo",
700
+ // NetBSD Commit Guidelines: code generated by an LLM/similar technology is
701
+ // "presumed to be tainted code, and must not be committed without prior
702
+ // written approval by core". https://www.netbsd.org/developers/commit-guidelines.html
703
+ "NetBSD"
704
+ // NOT listed (checked, deliberately excluded): QEMU's blanket AI-contribution
705
+ // ban is IN FLUX as of 2026-05 — a patch replacing it with a disclosure-based
706
+ // policy ("AI-used-for:" tag) was posted to qemu-devel and appears to have
707
+ // developer buy-in, so it is no longer a clean/current ban to key a hard
708
+ // supply-side drop on. https://www.theregister.com/ai-and-ml/2026/05/29/qemu-mulls-relaxing-ai-contribution-ban/
709
+ ];
710
+ AI_BAN_LC = new Set(AI_BAN_DENYLIST.map((g) => g.toLowerCase()));
711
+ MAX_BOUNTIES_PER_REPO = 10;
712
+ MAX_BOUNTIES_PER_DISCOVERED_REPO = 3;
713
+ MIN_REPO_STARS = 5;
714
+ HIGH_VALUE_USD = 500;
715
+ HIGH_VALUE_MIN_STARS = 50;
716
+ MIN_REPO_AGE_DAYS = 30;
717
+ }
718
+ });
719
+
647
720
  // ../../packages/core/src/feeds/contribution-gate.ts
648
721
  function passesContributionGate(input) {
649
722
  if (input.contributors === void 0) return false;
723
+ if (isAiBanRepo(input.fullName)) return false;
650
724
  return input.stars >= MIN_STARS && input.contributors >= MIN_CONTRIBUTORS && !TRIVIAL_PR_TITLE.test(input.title) && !input.archived && !input.fork;
651
725
  }
652
726
  var MIN_STARS, MIN_CONTRIBUTORS, TRIVIAL_PR_TITLE;
653
727
  var init_contribution_gate = __esm({
654
728
  "../../packages/core/src/feeds/contribution-gate.ts"() {
655
729
  "use strict";
730
+ init_bounty_gate();
656
731
  MIN_STARS = 50;
657
732
  MIN_CONTRIBUTORS = 10;
658
733
  TRIVIAL_PR_TITLE = /^\s*(fix\s+typo|typo\b|update\s+readme|readme\b|docs?:|docs?\(|chore:|chore\(|style:|ci:|build:|bump\b|update\s+dependenc)/i;
@@ -1710,58 +1785,6 @@ var init_hn = __esm({
1710
1785
  }
1711
1786
  });
1712
1787
 
1713
- // ../../packages/core/src/feeds/bounty-gate.ts
1714
- function isDenylistedRepo(fullName) {
1715
- return DENYLIST_LC.has(fullName.toLowerCase());
1716
- }
1717
- function passesAntiFarm(amountUSD, stargazers) {
1718
- return !(amountUSD > HIGH_VALUE_USD && stargazers < HIGH_VALUE_MIN_STARS);
1719
- }
1720
- function ageDays(createdAtIso) {
1721
- const created = Date.parse(createdAtIso);
1722
- if (!Number.isFinite(created)) return 0;
1723
- return (Date.now() - created) / (1e3 * 60 * 60 * 24);
1724
- }
1725
- function passesMaturityGate(repo) {
1726
- if (isDenylistedRepo(repo.fullName)) return false;
1727
- if (repo.archived || repo.disabled) return false;
1728
- if (repo.stargazers < MIN_REPO_STARS) return false;
1729
- if (ageDays(repo.createdAt) < MIN_REPO_AGE_DAYS) return false;
1730
- return true;
1731
- }
1732
- var DEFAULT_BOUNTY_REPOS, BOUNTY_REPO_DENYLIST, DENYLIST_LC, MAX_BOUNTIES_PER_REPO, MAX_BOUNTIES_PER_DISCOVERED_REPO, MIN_REPO_STARS, HIGH_VALUE_USD, HIGH_VALUE_MIN_STARS, MIN_REPO_AGE_DAYS;
1733
- var init_bounty_gate = __esm({
1734
- "../../packages/core/src/feeds/bounty-gate.ts"() {
1735
- "use strict";
1736
- DEFAULT_BOUNTY_REPOS = [
1737
- "tenstorrent/tt-metal",
1738
- "sequelize/sequelize",
1739
- "commaai/opendbc",
1740
- "aragon/hack",
1741
- "spacemeshos/app",
1742
- "archestra-ai/archestra",
1743
- "ucfopen/Obojobo",
1744
- "moorcheh-ai/memanto",
1745
- "PrismarineJS/mineflayer"
1746
- ];
1747
- BOUNTY_REPO_DENYLIST = [
1748
- "SecureBananaLabs/bug-bounty",
1749
- // Meta-farm: a bounty PLATFORM whose own issues are an assignment-gated
1750
- // contributor queue ("please assign me, my chief") — an unsolicited PR won't
1751
- // merge, so it's not a real claimable bounty. Not structurally derivable from
1752
- // any fetched field, so it's a manual entry (also dropped from the allowlist).
1753
- "boundlessfi/boundless"
1754
- ];
1755
- DENYLIST_LC = new Set(BOUNTY_REPO_DENYLIST.map((r) => r.toLowerCase()));
1756
- MAX_BOUNTIES_PER_REPO = 10;
1757
- MAX_BOUNTIES_PER_DISCOVERED_REPO = 3;
1758
- MIN_REPO_STARS = 5;
1759
- HIGH_VALUE_USD = 500;
1760
- HIGH_VALUE_MIN_STARS = 50;
1761
- MIN_REPO_AGE_DAYS = 30;
1762
- }
1763
- });
1764
-
1765
1788
  // ../../packages/core/src/concurrency.ts
1766
1789
  async function mapWithConcurrency(items, limit, fn) {
1767
1790
  const results = new Array(items.length);
@@ -2413,6 +2436,7 @@ async function aggregateBounties(opts) {
2413
2436
  const repo = j.bounty?.repoFullName?.toLowerCase();
2414
2437
  if (repo) {
2415
2438
  if (isDenylistedRepo(repo)) continue;
2439
+ if (isAiBanRepo(repo)) continue;
2416
2440
  const titleKey = `${repo} ${normalizeBountyTitle(j.title)}`;
2417
2441
  if (seenRepoTitles.has(titleKey)) continue;
2418
2442
  const cap = allowlist.has(repo) ? MAX_BOUNTIES_PER_REPO : MAX_BOUNTIES_PER_DISCOVERED_REPO;
@@ -2750,6 +2774,7 @@ async function aggregateContributions(opts = {}) {
2750
2774
  const title = decodeEntities(issue.title).trim();
2751
2775
  const contributors = await repoContribCount(fullName);
2752
2776
  if (!passesContributionGate({
2777
+ fullName,
2753
2778
  stars: repo.stargazers_count,
2754
2779
  contributors,
2755
2780
  title,
@@ -2819,21 +2844,21 @@ var init_contributions = __esm({
2819
2844
  });
2820
2845
 
2821
2846
  // ../../packages/core/src/partners.ts
2822
- import { readFileSync as readFileSync2 } from "fs";
2823
- import { join as join2 } from "path";
2847
+ import { readFileSync } from "fs";
2848
+ import { join } from "path";
2824
2849
  import { fileURLToPath } from "url";
2825
2850
  function resolveDataPath() {
2826
2851
  try {
2827
2852
  const dir = fileURLToPath(new URL("../../../data", import.meta.url));
2828
- return join2(dir, "partner-roles.json");
2853
+ return join(dir, "partner-roles.json");
2829
2854
  } catch {
2830
- return join2(process.cwd(), "data", "partner-roles.json");
2855
+ return join(process.cwd(), "data", "partner-roles.json");
2831
2856
  }
2832
2857
  }
2833
2858
  function loadPartnerRoles() {
2834
2859
  const filePath = resolveDataPath();
2835
2860
  try {
2836
- const raw = readFileSync2(filePath, "utf-8");
2861
+ const raw = readFileSync(filePath, "utf-8");
2837
2862
  const parsed = JSON.parse(raw);
2838
2863
  if (!Array.isArray(parsed)) {
2839
2864
  console.warn("[partners] partner-roles.json is not an array \u2014 skipping");
@@ -6345,16 +6370,113 @@ var init_legible = __esm({
6345
6370
  }
6346
6371
  });
6347
6372
 
6373
+ // ../../packages/core/src/credential/legible-trajectory.ts
6374
+ function signalLabel(signal) {
6375
+ if (signal.startsWith("lang:")) {
6376
+ const token = signal.slice("lang:".length);
6377
+ return LANG_LABELS[token] ?? token.toUpperCase();
6378
+ }
6379
+ if (CAP_LABELS[signal]) return CAP_LABELS[signal];
6380
+ if (signal.startsWith("cap:")) return signal.slice("cap:".length).replace(/-/g, " ");
6381
+ return signal;
6382
+ }
6383
+ function joinLabels(labels) {
6384
+ if (labels.length === 0) return "";
6385
+ if (labels.length === 1) return labels[0];
6386
+ return `${labels.slice(0, -1).join(", ")} and ${labels[labels.length - 1]}`;
6387
+ }
6388
+ function mentionable(entries) {
6389
+ return entries.filter((e) => Math.abs(e.delta) >= MENTION_DELTA).slice(0, MAX_NAMED).map((e) => signalLabel(e.signal));
6390
+ }
6391
+ function displayableDrift(entries) {
6392
+ return entries.filter((e) => Math.abs(e.delta) >= DISPLAY_DELTA_FLOOR);
6393
+ }
6394
+ function deriveTrajectoryNarrative(score) {
6395
+ const risingLabels = mentionable(score.headline.rising);
6396
+ const fallingLabels = mentionable(score.headline.falling);
6397
+ let momentum;
6398
+ if (risingLabels.length === 0 && fallingLabels.length === 0) {
6399
+ momentum = "Steady focus \u2014 no major shifts recently.";
6400
+ } else {
6401
+ const parts = [];
6402
+ if (risingLabels.length > 0) parts.push(`Trending toward ${joinLabels(risingLabels)}`);
6403
+ if (fallingLabels.length > 0) {
6404
+ parts.push(
6405
+ risingLabels.length > 0 ? `shifting away from ${joinLabels(fallingLabels)}` : `Shifting away from ${joinLabels(fallingLabels)}`
6406
+ );
6407
+ }
6408
+ momentum = `${parts.join(", ")}.`;
6409
+ }
6410
+ const liveLangs = score.liveStack.filter((s) => s.startsWith("lang:")).map(signalLabel);
6411
+ const liveCaps = score.liveStack.filter((s) => !s.startsWith("lang:")).map(signalLabel);
6412
+ const focusParts = [];
6413
+ if (liveLangs.length > 0) focusParts.push(`Ships in ${joinLabels(liveLangs)}`);
6414
+ if (liveCaps.length > 0) {
6415
+ const verb = liveLangs.length > 0 ? "works with" : "Works with";
6416
+ focusParts.push(`${verb} ${joinLabels(liveCaps)}`);
6417
+ }
6418
+ const focus = focusParts.length > 0 ? `${focusParts.join(" \xB7 ")}.` : "";
6419
+ return { momentum, focus, risingLabels, fallingLabels };
6420
+ }
6421
+ var LANG_LABELS, CAP_LABELS, MENTION_DELTA, DISPLAY_DELTA_FLOOR, MAX_NAMED;
6422
+ var init_legible_trajectory = __esm({
6423
+ "../../packages/core/src/credential/legible-trajectory.ts"() {
6424
+ "use strict";
6425
+ LANG_LABELS = {
6426
+ ts: "TypeScript",
6427
+ js: "JavaScript",
6428
+ py: "Python",
6429
+ rs: "Rust",
6430
+ go: "Go",
6431
+ rb: "Ruby",
6432
+ java: "Java",
6433
+ kt: "Kotlin",
6434
+ sql: "SQL",
6435
+ md: "Documentation"
6436
+ };
6437
+ CAP_LABELS = {
6438
+ "cap:ui-automation": "UI automation",
6439
+ "cap:deploys": "Deployment",
6440
+ "cap:project-mgmt": "Project tracking",
6441
+ "cap:product-research": "Product research",
6442
+ "cap:design": "Design",
6443
+ "cap:3d-modeling": "3D modeling",
6444
+ "cap:workflow-automation": "Workflow automation",
6445
+ "cap:agentic-workflow": "Agent orchestration",
6446
+ "mcp:custom": "Private integrations"
6447
+ };
6448
+ MENTION_DELTA = 0.05;
6449
+ DISPLAY_DELTA_FLOOR = 5e-4;
6450
+ MAX_NAMED = 3;
6451
+ }
6452
+ });
6453
+
6454
+ // ../../packages/core/src/short-token.ts
6455
+ import { createHash as createHash2 } from "crypto";
6456
+ function opportunityShortToken(id) {
6457
+ return createHash2("sha256").update(id, "utf8").digest("base64url").slice(0, 8);
6458
+ }
6459
+ var contributeShortToken;
6460
+ var init_short_token = __esm({
6461
+ "../../packages/core/src/short-token.ts"() {
6462
+ "use strict";
6463
+ contributeShortToken = opportunityShortToken;
6464
+ }
6465
+ });
6466
+
6348
6467
  // ../../packages/core/src/index.ts
6349
6468
  var src_exports = {};
6350
6469
  __export(src_exports, {
6470
+ AI_BAN_DENYLIST: () => AI_BAN_DENYLIST,
6351
6471
  ASHBY_SLUGS_BY_TIER: () => ASHBY_SLUGS_BY_TIER,
6472
+ CAP_LABELS: () => CAP_LABELS,
6352
6473
  DECAY_FLOOR: () => DECAY_FLOOR,
6353
6474
  DEFAULT_ASHBY_SLUGS: () => DEFAULT_ASHBY_SLUGS,
6354
6475
  DEFAULT_BOUNTY_REPOS: () => DEFAULT_BOUNTY_REPOS,
6355
6476
  DEFAULT_GREENHOUSE_SLUGS: () => DEFAULT_GREENHOUSE_SLUGS,
6356
6477
  DEFAULT_LEVER_SLUGS: () => DEFAULT_LEVER_SLUGS,
6357
6478
  DEFAULT_WORKABLE_SLUGS: () => DEFAULT_WORKABLE_SLUGS,
6479
+ DISPLAY_DELTA_FLOOR: () => DISPLAY_DELTA_FLOOR,
6358
6480
  EXAMPLE_BUYER: () => EXAMPLE_BUYER,
6359
6481
  FEEDS: () => FEEDS,
6360
6482
  GRAPH: () => GRAPH,
@@ -6363,7 +6485,9 @@ __export(src_exports, {
6363
6485
  INTRO_ACCEPTED_TTL_MS: () => INTRO_ACCEPTED_TTL_MS,
6364
6486
  INTRO_ALLOWED_FIELDS: () => INTRO_ALLOWED_FIELDS,
6365
6487
  INTRO_PENDING_TTL_MS: () => INTRO_PENDING_TTL_MS,
6488
+ LANG_LABELS: () => LANG_LABELS,
6366
6489
  LEVER_SLUGS_BY_TIER: () => LEVER_SLUGS_BY_TIER,
6490
+ MENTION_DELTA: () => MENTION_DELTA,
6367
6491
  MIN_CONTRIBUTORS: () => MIN_CONTRIBUTORS,
6368
6492
  MIN_STARS: () => MIN_STARS,
6369
6493
  STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
@@ -6388,12 +6512,15 @@ __export(src_exports, {
6388
6512
  composeIntroEmail: () => composeIntroEmail,
6389
6513
  computeAcceptanceCredential: () => computeAcceptanceCredential,
6390
6514
  computeAcceptanceCredentialPublic: () => computeAcceptanceCredentialPublic,
6515
+ contributeShortToken: () => contributeShortToken,
6391
6516
  coreTagsFromTitle: () => coreTagsFromTitle,
6392
6517
  decorate: () => decorate,
6393
6518
  decryptMessage: () => decryptMessage,
6394
6519
  deriveLegibleProfile: () => deriveLegibleProfile,
6395
6520
  deriveResumeTrend: () => deriveResumeTrend,
6396
6521
  deriveSharedKey: () => deriveSharedKey,
6522
+ deriveTrajectoryNarrative: () => deriveTrajectoryNarrative,
6523
+ displayableDrift: () => displayableDrift,
6397
6524
  encryptMessage: () => encryptMessage,
6398
6525
  expandWeighted: () => expandWeighted,
6399
6526
  extractSkillTags: () => extractSkillTags,
@@ -6413,15 +6540,19 @@ __export(src_exports, {
6413
6540
  introActorRole: () => introActorRole,
6414
6541
  introRateLimitCheck: () => introRateLimitCheck,
6415
6542
  introRetentionAction: () => introRetentionAction,
6543
+ isAiBanRepo: () => isAiBanRepo,
6416
6544
  isBounty: () => isBounty,
6417
6545
  isContribution: () => isContribution,
6418
6546
  isOverIntroLimit: () => isOverIntroLimit,
6547
+ joinLabels: () => joinLabels,
6548
+ labelFor: () => labelFor,
6419
6549
  lever: () => lever,
6420
6550
  loadPartnerRoles: () => loadPartnerRoles,
6421
6551
  looksLikeEngRole: () => looksLikeEngRole,
6422
6552
  match: () => match,
6423
6553
  normalize: () => normalize,
6424
6554
  opire: () => opire,
6555
+ opportunityShortToken: () => opportunityShortToken,
6425
6556
  pageMatches: () => pageMatches,
6426
6557
  passesContributionGate: () => passesContributionGate,
6427
6558
  passesMaturityGate: () => passesMaturityGate,
@@ -6433,6 +6564,7 @@ __export(src_exports, {
6433
6564
  safetyNumber: () => safetyNumber,
6434
6565
  sameLogin: () => sameLogin,
6435
6566
  setStatus: () => setStatus,
6567
+ signalLabel: () => signalLabel,
6436
6568
  tokenize: () => tokenize,
6437
6569
  validateGraph: () => validateGraph,
6438
6570
  validateIntroPayload: () => validateIntroPayload,
@@ -6455,6 +6587,8 @@ var init_src = __esm({
6455
6587
  init_chatCrypto();
6456
6588
  init_job_status();
6457
6589
  init_legible();
6590
+ init_legible_trajectory();
6591
+ init_short_token();
6458
6592
  }
6459
6593
  });
6460
6594
 
@@ -6466,9 +6600,9 @@ var init_keytar = __esm({
6466
6600
  }
6467
6601
  });
6468
6602
 
6469
- // node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
6603
+ // node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel2/node_modules/keytar/build/Release/keytar.node
6470
6604
  var require_keytar = __commonJS({
6471
- "node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
6605
+ "node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel2/node_modules/keytar/build/Release/keytar.node"(exports, module) {
6472
6606
  "use strict";
6473
6607
  init_keytar();
6474
6608
  try {
@@ -6758,22 +6892,23 @@ var init_profile = __esm({
6758
6892
  });
6759
6893
 
6760
6894
  // bin/jpi-bounties.js
6895
+ init_src();
6761
6896
  import { readFileSync as readFileSync4 } from "fs";
6762
6897
  import { join as join4 } from "path";
6763
6898
  import { homedir as homedir3 } from "os";
6764
6899
  import { createInterface } from "readline";
6765
6900
 
6766
6901
  // bin/cache-store.js
6767
- import { readFileSync, writeFileSync, mkdirSync, renameSync } from "fs";
6768
- import { join } from "path";
6902
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, renameSync } from "fs";
6903
+ import { join as join2 } from "path";
6769
6904
  import { homedir } from "os";
6770
- var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join(homedir(), ".terminalhire");
6771
- var INDEX_CACHE_FILE = join(TERMINALHIRE_DIR, "index-cache.json");
6772
- var SCHEMA_VERSION = 1;
6905
+ var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join2(homedir(), ".terminalhire");
6906
+ var INDEX_CACHE_FILE = join2(TERMINALHIRE_DIR, "index-cache.json");
6907
+ var SCHEMA_VERSION2 = 1;
6773
6908
  var tmpCounter = 0;
6774
6909
  function readCacheEntry() {
6775
6910
  try {
6776
- return JSON.parse(readFileSync(INDEX_CACHE_FILE, "utf8"));
6911
+ return JSON.parse(readFileSync2(INDEX_CACHE_FILE, "utf8"));
6777
6912
  } catch {
6778
6913
  return null;
6779
6914
  }
@@ -6784,7 +6919,7 @@ function updateIndexCache(patch) {
6784
6919
  const entry = {
6785
6920
  ...existing,
6786
6921
  ...patch,
6787
- schemaVersion: SCHEMA_VERSION,
6922
+ schemaVersion: SCHEMA_VERSION2,
6788
6923
  ts: Date.now()
6789
6924
  };
6790
6925
  const tmp = `${INDEX_CACHE_FILE}.${process.pid}.${tmpCounter++}.tmp`;
@@ -6852,13 +6987,15 @@ function printBounty(i, job, score, reason, matchedTags) {
6852
6987
  const scoreStr = score > 0 ? ` \xB7 match ${Math.round(score * 100)}%` : "";
6853
6988
  const prs = b.competingOpenPRs;
6854
6989
  const contend = prs != null && prs > 0 ? ` \xB7 \u26A0 ${prs} PR${prs === 1 ? "" : "s"} in flight` : "";
6990
+ const ref = opportunityShortToken(job.id);
6855
6991
  console.log(`
6856
- ${i + 1}. ${linkTitle(job.title, job.url)}`);
6992
+ ${i + 1}. ${linkTitle(job.title, job.url)} [${ref}]`);
6857
6993
  console.log(` ${formatAmount(b)}${effort} \xB7 ${b.repoFullName ?? job.company}${stars}${scoreStr}${contend}`);
6858
6994
  if (reason) console.log(` ${reason}`);
6859
6995
  if (matchedTags && matchedTags.length) console.log(` Tags matched: ${matchedTags.slice(0, 5).join(", ")}`);
6860
6996
  console.log(` id: ${job.id}`);
6861
6997
  console.log(` Claim: ${b.claimUrl ?? job.url}`);
6998
+ console.log(` \u2192 terminalhire claim ${ref}`);
6862
6999
  }
6863
7000
  async function run() {
6864
7001
  try {
@@ -422,10 +422,43 @@ var init_vocabulary = __esm({
422
422
  }
423
423
  });
424
424
 
425
+ // ../../packages/core/src/feeds/bounty-gate.ts
426
+ var BOUNTY_REPO_DENYLIST, DENYLIST_LC, AI_BAN_DENYLIST, AI_BAN_LC;
427
+ var init_bounty_gate = __esm({
428
+ "../../packages/core/src/feeds/bounty-gate.ts"() {
429
+ "use strict";
430
+ BOUNTY_REPO_DENYLIST = [
431
+ "SecureBananaLabs/bug-bounty",
432
+ // Meta-farm: a bounty PLATFORM whose own issues are an assignment-gated
433
+ // contributor queue ("please assign me, my chief") — an unsolicited PR won't
434
+ // merge, so it's not a real claimable bounty. Not structurally derivable from
435
+ // any fetched field, so it's a manual entry (also dropped from the allowlist).
436
+ "boundlessfi/boundless"
437
+ ];
438
+ DENYLIST_LC = new Set(BOUNTY_REPO_DENYLIST.map((r) => r.toLowerCase()));
439
+ AI_BAN_DENYLIST = [
440
+ // Gentoo Council voted 6-0 (2024-04-14) to ban AI/ML-generated contributions
441
+ // project-wide. https://wiki.gentoo.org/wiki/Project:Council/AI_policy
442
+ "gentoo",
443
+ // NetBSD Commit Guidelines: code generated by an LLM/similar technology is
444
+ // "presumed to be tainted code, and must not be committed without prior
445
+ // written approval by core". https://www.netbsd.org/developers/commit-guidelines.html
446
+ "NetBSD"
447
+ // NOT listed (checked, deliberately excluded): QEMU's blanket AI-contribution
448
+ // ban is IN FLUX as of 2026-05 — a patch replacing it with a disclosure-based
449
+ // policy ("AI-used-for:" tag) was posted to qemu-devel and appears to have
450
+ // developer buy-in, so it is no longer a clean/current ban to key a hard
451
+ // supply-side drop on. https://www.theregister.com/ai-and-ml/2026/05/29/qemu-mulls-relaxing-ai-contribution-ban/
452
+ ];
453
+ AI_BAN_LC = new Set(AI_BAN_DENYLIST.map((g) => g.toLowerCase()));
454
+ }
455
+ });
456
+
425
457
  // ../../packages/core/src/feeds/contribution-gate.ts
426
458
  var init_contribution_gate = __esm({
427
459
  "../../packages/core/src/feeds/contribution-gate.ts"() {
428
460
  "use strict";
461
+ init_bounty_gate();
429
462
  }
430
463
  });
431
464
 
@@ -519,23 +552,6 @@ var init_hn = __esm({
519
552
  }
520
553
  });
521
554
 
522
- // ../../packages/core/src/feeds/bounty-gate.ts
523
- var BOUNTY_REPO_DENYLIST, DENYLIST_LC;
524
- var init_bounty_gate = __esm({
525
- "../../packages/core/src/feeds/bounty-gate.ts"() {
526
- "use strict";
527
- BOUNTY_REPO_DENYLIST = [
528
- "SecureBananaLabs/bug-bounty",
529
- // Meta-farm: a bounty PLATFORM whose own issues are an assignment-gated
530
- // contributor queue ("please assign me, my chief") — an unsolicited PR won't
531
- // merge, so it's not a real claimable bounty. Not structurally derivable from
532
- // any fetched field, so it's a manual entry (also dropped from the allowlist).
533
- "boundlessfi/boundless"
534
- ];
535
- DENYLIST_LC = new Set(BOUNTY_REPO_DENYLIST.map((r) => r.toLowerCase()));
536
- }
537
- });
538
-
539
555
  // ../../packages/core/src/concurrency.ts
540
556
  var init_concurrency = __esm({
541
557
  "../../packages/core/src/concurrency.ts"() {
@@ -3865,6 +3881,21 @@ var init_legible = __esm({
3865
3881
  }
3866
3882
  });
3867
3883
 
3884
+ // ../../packages/core/src/credential/legible-trajectory.ts
3885
+ var init_legible_trajectory = __esm({
3886
+ "../../packages/core/src/credential/legible-trajectory.ts"() {
3887
+ "use strict";
3888
+ }
3889
+ });
3890
+
3891
+ // ../../packages/core/src/short-token.ts
3892
+ import { createHash as createHash2 } from "crypto";
3893
+ var init_short_token = __esm({
3894
+ "../../packages/core/src/short-token.ts"() {
3895
+ "use strict";
3896
+ }
3897
+ });
3898
+
3868
3899
  // ../../packages/core/src/index.ts
3869
3900
  var init_src = __esm({
3870
3901
  "../../packages/core/src/index.ts"() {
@@ -3881,6 +3912,8 @@ var init_src = __esm({
3881
3912
  init_chatCrypto();
3882
3913
  init_job_status();
3883
3914
  init_legible();
3915
+ init_legible_trajectory();
3916
+ init_short_token();
3884
3917
  }
3885
3918
  });
3886
3919
 
@@ -3892,9 +3925,9 @@ var init_keytar = __esm({
3892
3925
  }
3893
3926
  });
3894
3927
 
3895
- // node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
3928
+ // node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel2/node_modules/keytar/build/Release/keytar.node
3896
3929
  var require_keytar = __commonJS({
3897
- "node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
3930
+ "node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel2/node_modules/keytar/build/Release/keytar.node"(exports, module) {
3898
3931
  "use strict";
3899
3932
  init_keytar();
3900
3933
  try {
@@ -4267,7 +4300,7 @@ var init_chat_client = __esm({
4267
4300
  init_src();
4268
4301
  init_chat_keystore();
4269
4302
  init_web_session();
4270
- CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
4303
+ CHAT_BASE = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
4271
4304
  GH_SESSION_COOKIE = "__jpi_gh_session";
4272
4305
  TERMINALHIRE_DIR3 = join5(homedir4(), ".terminalhire");
4273
4306
  PEERS_FILE = join5(TERMINALHIRE_DIR3, "chat-peers.json");
@@ -4485,7 +4518,7 @@ var init_jpi_chat = __esm({
4485
4518
  init_chat_client();
4486
4519
  init_config();
4487
4520
  init_web_session();
4488
- CHAT_BASE2 = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
4521
+ CHAT_BASE2 = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
4489
4522
  GH_SESSION_COOKIE2 = "__jpi_gh_session";
4490
4523
  ANSI_CSI = /\x1b\[[0-?]*[ -/]*[@-~]/g;
4491
4524
  ANSI_OSC = /\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g;
@@ -4873,7 +4906,7 @@ var init_jpi_chat_read = __esm({
4873
4906
  init_chat_client();
4874
4907
  init_web_session();
4875
4908
  init_jpi_chat();
4876
- CHAT_BASE3 = process.env["TERMINALHIRE_API_URL"] || "https://www.terminalhire.com";
4909
+ CHAT_BASE3 = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
4877
4910
  GH_SESSION_COOKIE3 = "__jpi_gh_session";
4878
4911
  TERMINALHIRE_DIR5 = process.env.TERMINALHIRE_DIR || join8(homedir7(), ".terminalhire");
4879
4912
  READS_FILE = join8(TERMINALHIRE_DIR5, "chat-reads.json");