terminalhire 0.17.1 → 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,27 +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
+
6348
6454
  // ../../packages/core/src/short-token.ts
6349
6455
  import { createHash as createHash2 } from "crypto";
6350
- function contributeShortToken(id) {
6456
+ function opportunityShortToken(id) {
6351
6457
  return createHash2("sha256").update(id, "utf8").digest("base64url").slice(0, 8);
6352
6458
  }
6459
+ var contributeShortToken;
6353
6460
  var init_short_token = __esm({
6354
6461
  "../../packages/core/src/short-token.ts"() {
6355
6462
  "use strict";
6463
+ contributeShortToken = opportunityShortToken;
6356
6464
  }
6357
6465
  });
6358
6466
 
6359
6467
  // ../../packages/core/src/index.ts
6360
6468
  var src_exports = {};
6361
6469
  __export(src_exports, {
6470
+ AI_BAN_DENYLIST: () => AI_BAN_DENYLIST,
6362
6471
  ASHBY_SLUGS_BY_TIER: () => ASHBY_SLUGS_BY_TIER,
6472
+ CAP_LABELS: () => CAP_LABELS,
6363
6473
  DECAY_FLOOR: () => DECAY_FLOOR,
6364
6474
  DEFAULT_ASHBY_SLUGS: () => DEFAULT_ASHBY_SLUGS,
6365
6475
  DEFAULT_BOUNTY_REPOS: () => DEFAULT_BOUNTY_REPOS,
6366
6476
  DEFAULT_GREENHOUSE_SLUGS: () => DEFAULT_GREENHOUSE_SLUGS,
6367
6477
  DEFAULT_LEVER_SLUGS: () => DEFAULT_LEVER_SLUGS,
6368
6478
  DEFAULT_WORKABLE_SLUGS: () => DEFAULT_WORKABLE_SLUGS,
6479
+ DISPLAY_DELTA_FLOOR: () => DISPLAY_DELTA_FLOOR,
6369
6480
  EXAMPLE_BUYER: () => EXAMPLE_BUYER,
6370
6481
  FEEDS: () => FEEDS,
6371
6482
  GRAPH: () => GRAPH,
@@ -6374,7 +6485,9 @@ __export(src_exports, {
6374
6485
  INTRO_ACCEPTED_TTL_MS: () => INTRO_ACCEPTED_TTL_MS,
6375
6486
  INTRO_ALLOWED_FIELDS: () => INTRO_ALLOWED_FIELDS,
6376
6487
  INTRO_PENDING_TTL_MS: () => INTRO_PENDING_TTL_MS,
6488
+ LANG_LABELS: () => LANG_LABELS,
6377
6489
  LEVER_SLUGS_BY_TIER: () => LEVER_SLUGS_BY_TIER,
6490
+ MENTION_DELTA: () => MENTION_DELTA,
6378
6491
  MIN_CONTRIBUTORS: () => MIN_CONTRIBUTORS,
6379
6492
  MIN_STARS: () => MIN_STARS,
6380
6493
  STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
@@ -6406,6 +6519,8 @@ __export(src_exports, {
6406
6519
  deriveLegibleProfile: () => deriveLegibleProfile,
6407
6520
  deriveResumeTrend: () => deriveResumeTrend,
6408
6521
  deriveSharedKey: () => deriveSharedKey,
6522
+ deriveTrajectoryNarrative: () => deriveTrajectoryNarrative,
6523
+ displayableDrift: () => displayableDrift,
6409
6524
  encryptMessage: () => encryptMessage,
6410
6525
  expandWeighted: () => expandWeighted,
6411
6526
  extractSkillTags: () => extractSkillTags,
@@ -6425,15 +6540,19 @@ __export(src_exports, {
6425
6540
  introActorRole: () => introActorRole,
6426
6541
  introRateLimitCheck: () => introRateLimitCheck,
6427
6542
  introRetentionAction: () => introRetentionAction,
6543
+ isAiBanRepo: () => isAiBanRepo,
6428
6544
  isBounty: () => isBounty,
6429
6545
  isContribution: () => isContribution,
6430
6546
  isOverIntroLimit: () => isOverIntroLimit,
6547
+ joinLabels: () => joinLabels,
6548
+ labelFor: () => labelFor,
6431
6549
  lever: () => lever,
6432
6550
  loadPartnerRoles: () => loadPartnerRoles,
6433
6551
  looksLikeEngRole: () => looksLikeEngRole,
6434
6552
  match: () => match,
6435
6553
  normalize: () => normalize,
6436
6554
  opire: () => opire,
6555
+ opportunityShortToken: () => opportunityShortToken,
6437
6556
  pageMatches: () => pageMatches,
6438
6557
  passesContributionGate: () => passesContributionGate,
6439
6558
  passesMaturityGate: () => passesMaturityGate,
@@ -6445,6 +6564,7 @@ __export(src_exports, {
6445
6564
  safetyNumber: () => safetyNumber,
6446
6565
  sameLogin: () => sameLogin,
6447
6566
  setStatus: () => setStatus,
6567
+ signalLabel: () => signalLabel,
6448
6568
  tokenize: () => tokenize,
6449
6569
  validateGraph: () => validateGraph,
6450
6570
  validateIntroPayload: () => validateIntroPayload,
@@ -6467,6 +6587,7 @@ var init_src = __esm({
6467
6587
  init_chatCrypto();
6468
6588
  init_job_status();
6469
6589
  init_legible();
6590
+ init_legible_trajectory();
6470
6591
  init_short_token();
6471
6592
  }
6472
6593
  });
@@ -6479,9 +6600,9 @@ var init_keytar = __esm({
6479
6600
  }
6480
6601
  });
6481
6602
 
6482
- // node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel/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
6483
6604
  var require_keytar = __commonJS({
6484
- "node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel/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) {
6485
6606
  "use strict";
6486
6607
  init_keytar();
6487
6608
  try {
@@ -6771,22 +6892,23 @@ var init_profile = __esm({
6771
6892
  });
6772
6893
 
6773
6894
  // bin/jpi-bounties.js
6895
+ init_src();
6774
6896
  import { readFileSync as readFileSync4 } from "fs";
6775
6897
  import { join as join4 } from "path";
6776
6898
  import { homedir as homedir3 } from "os";
6777
6899
  import { createInterface } from "readline";
6778
6900
 
6779
6901
  // bin/cache-store.js
6780
- import { readFileSync, writeFileSync, mkdirSync, renameSync } from "fs";
6781
- import { join } from "path";
6902
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, renameSync } from "fs";
6903
+ import { join as join2 } from "path";
6782
6904
  import { homedir } from "os";
6783
- var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join(homedir(), ".terminalhire");
6784
- var INDEX_CACHE_FILE = join(TERMINALHIRE_DIR, "index-cache.json");
6785
- 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;
6786
6908
  var tmpCounter = 0;
6787
6909
  function readCacheEntry() {
6788
6910
  try {
6789
- return JSON.parse(readFileSync(INDEX_CACHE_FILE, "utf8"));
6911
+ return JSON.parse(readFileSync2(INDEX_CACHE_FILE, "utf8"));
6790
6912
  } catch {
6791
6913
  return null;
6792
6914
  }
@@ -6797,7 +6919,7 @@ function updateIndexCache(patch) {
6797
6919
  const entry = {
6798
6920
  ...existing,
6799
6921
  ...patch,
6800
- schemaVersion: SCHEMA_VERSION,
6922
+ schemaVersion: SCHEMA_VERSION2,
6801
6923
  ts: Date.now()
6802
6924
  };
6803
6925
  const tmp = `${INDEX_CACHE_FILE}.${process.pid}.${tmpCounter++}.tmp`;
@@ -6865,13 +6987,15 @@ function printBounty(i, job, score, reason, matchedTags) {
6865
6987
  const scoreStr = score > 0 ? ` \xB7 match ${Math.round(score * 100)}%` : "";
6866
6988
  const prs = b.competingOpenPRs;
6867
6989
  const contend = prs != null && prs > 0 ? ` \xB7 \u26A0 ${prs} PR${prs === 1 ? "" : "s"} in flight` : "";
6990
+ const ref = opportunityShortToken(job.id);
6868
6991
  console.log(`
6869
- ${i + 1}. ${linkTitle(job.title, job.url)}`);
6992
+ ${i + 1}. ${linkTitle(job.title, job.url)} [${ref}]`);
6870
6993
  console.log(` ${formatAmount(b)}${effort} \xB7 ${b.repoFullName ?? job.company}${stars}${scoreStr}${contend}`);
6871
6994
  if (reason) console.log(` ${reason}`);
6872
6995
  if (matchedTags && matchedTags.length) console.log(` Tags matched: ${matchedTags.slice(0, 5).join(", ")}`);
6873
6996
  console.log(` id: ${job.id}`);
6874
6997
  console.log(` Claim: ${b.claimUrl ?? job.url}`);
6998
+ console.log(` \u2192 terminalhire claim ${ref}`);
6875
6999
  }
6876
7000
  async function run() {
6877
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,13 @@ 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
+
3868
3891
  // ../../packages/core/src/short-token.ts
3869
3892
  import { createHash as createHash2 } from "crypto";
3870
3893
  var init_short_token = __esm({
@@ -3889,6 +3912,7 @@ var init_src = __esm({
3889
3912
  init_chatCrypto();
3890
3913
  init_job_status();
3891
3914
  init_legible();
3915
+ init_legible_trajectory();
3892
3916
  init_short_token();
3893
3917
  }
3894
3918
  });
@@ -3901,9 +3925,9 @@ var init_keytar = __esm({
3901
3925
  }
3902
3926
  });
3903
3927
 
3904
- // node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel/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
3905
3929
  var require_keytar = __commonJS({
3906
- "node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel/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) {
3907
3931
  "use strict";
3908
3932
  init_keytar();
3909
3933
  try {
@@ -439,10 +439,43 @@ var init_vocabulary = __esm({
439
439
  }
440
440
  });
441
441
 
442
+ // ../../packages/core/src/feeds/bounty-gate.ts
443
+ var BOUNTY_REPO_DENYLIST, DENYLIST_LC, AI_BAN_DENYLIST, AI_BAN_LC;
444
+ var init_bounty_gate = __esm({
445
+ "../../packages/core/src/feeds/bounty-gate.ts"() {
446
+ "use strict";
447
+ BOUNTY_REPO_DENYLIST = [
448
+ "SecureBananaLabs/bug-bounty",
449
+ // Meta-farm: a bounty PLATFORM whose own issues are an assignment-gated
450
+ // contributor queue ("please assign me, my chief") — an unsolicited PR won't
451
+ // merge, so it's not a real claimable bounty. Not structurally derivable from
452
+ // any fetched field, so it's a manual entry (also dropped from the allowlist).
453
+ "boundlessfi/boundless"
454
+ ];
455
+ DENYLIST_LC = new Set(BOUNTY_REPO_DENYLIST.map((r) => r.toLowerCase()));
456
+ AI_BAN_DENYLIST = [
457
+ // Gentoo Council voted 6-0 (2024-04-14) to ban AI/ML-generated contributions
458
+ // project-wide. https://wiki.gentoo.org/wiki/Project:Council/AI_policy
459
+ "gentoo",
460
+ // NetBSD Commit Guidelines: code generated by an LLM/similar technology is
461
+ // "presumed to be tainted code, and must not be committed without prior
462
+ // written approval by core". https://www.netbsd.org/developers/commit-guidelines.html
463
+ "NetBSD"
464
+ // NOT listed (checked, deliberately excluded): QEMU's blanket AI-contribution
465
+ // ban is IN FLUX as of 2026-05 — a patch replacing it with a disclosure-based
466
+ // policy ("AI-used-for:" tag) was posted to qemu-devel and appears to have
467
+ // developer buy-in, so it is no longer a clean/current ban to key a hard
468
+ // supply-side drop on. https://www.theregister.com/ai-and-ml/2026/05/29/qemu-mulls-relaxing-ai-contribution-ban/
469
+ ];
470
+ AI_BAN_LC = new Set(AI_BAN_DENYLIST.map((g) => g.toLowerCase()));
471
+ }
472
+ });
473
+
442
474
  // ../../packages/core/src/feeds/contribution-gate.ts
443
475
  var init_contribution_gate = __esm({
444
476
  "../../packages/core/src/feeds/contribution-gate.ts"() {
445
477
  "use strict";
478
+ init_bounty_gate();
446
479
  }
447
480
  });
448
481
 
@@ -536,23 +569,6 @@ var init_hn = __esm({
536
569
  }
537
570
  });
538
571
 
539
- // ../../packages/core/src/feeds/bounty-gate.ts
540
- var BOUNTY_REPO_DENYLIST, DENYLIST_LC;
541
- var init_bounty_gate = __esm({
542
- "../../packages/core/src/feeds/bounty-gate.ts"() {
543
- "use strict";
544
- BOUNTY_REPO_DENYLIST = [
545
- "SecureBananaLabs/bug-bounty",
546
- // Meta-farm: a bounty PLATFORM whose own issues are an assignment-gated
547
- // contributor queue ("please assign me, my chief") — an unsolicited PR won't
548
- // merge, so it's not a real claimable bounty. Not structurally derivable from
549
- // any fetched field, so it's a manual entry (also dropped from the allowlist).
550
- "boundlessfi/boundless"
551
- ];
552
- DENYLIST_LC = new Set(BOUNTY_REPO_DENYLIST.map((r) => r.toLowerCase()));
553
- }
554
- });
555
-
556
572
  // ../../packages/core/src/concurrency.ts
557
573
  var init_concurrency = __esm({
558
574
  "../../packages/core/src/concurrency.ts"() {
@@ -3893,6 +3909,13 @@ var init_legible = __esm({
3893
3909
  }
3894
3910
  });
3895
3911
 
3912
+ // ../../packages/core/src/credential/legible-trajectory.ts
3913
+ var init_legible_trajectory = __esm({
3914
+ "../../packages/core/src/credential/legible-trajectory.ts"() {
3915
+ "use strict";
3916
+ }
3917
+ });
3918
+
3896
3919
  // ../../packages/core/src/short-token.ts
3897
3920
  import { createHash as createHash2 } from "crypto";
3898
3921
  var init_short_token = __esm({
@@ -3917,6 +3940,7 @@ var init_src = __esm({
3917
3940
  init_chatCrypto();
3918
3941
  init_job_status();
3919
3942
  init_legible();
3943
+ init_legible_trajectory();
3920
3944
  init_short_token();
3921
3945
  }
3922
3946
  });
@@ -3929,9 +3953,9 @@ var init_keytar = __esm({
3929
3953
  }
3930
3954
  });
3931
3955
 
3932
- // node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel/node_modules/keytar/build/Release/keytar.node
3956
+ // 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
3933
3957
  var require_keytar = __commonJS({
3934
- "node-file:/private/tmp/claude-501/-Users-ericgang-job-placement-inline/3ffac25b-ca95-4a86-9e17-a4cf326551de/scratchpad/rel/node_modules/keytar/build/Release/keytar.node"(exports, module) {
3958
+ "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) {
3935
3959
  "use strict";
3936
3960
  init_keytar();
3937
3961
  try {