terminalhire 0.22.0 → 0.24.0

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.
@@ -45,9 +45,9 @@ var init_keytar = __esm({
45
45
  }
46
46
  });
47
47
 
48
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/claim-frictionless/node_modules/keytar/build/Release/keytar.node
48
+ // node-file:/Users/ericgang/job-placement-inline-wt/release-v0240/node_modules/keytar/build/Release/keytar.node
49
49
  var require_keytar = __commonJS({
50
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/claim-frictionless/node_modules/keytar/build/Release/keytar.node"(exports, module) {
50
+ "node-file:/Users/ericgang/job-placement-inline-wt/release-v0240/node_modules/keytar/build/Release/keytar.node"(exports, module) {
51
51
  "use strict";
52
52
  init_keytar();
53
53
  try {
@@ -193,7 +193,7 @@ var init_graph_data = __esm({
193
193
  { id: "anthropic", parents: ["llm"], synonyms: ["claude"] },
194
194
  { id: "rag", parents: ["llm"], synonyms: ["retrieval-augmented-generation"] },
195
195
  { id: "mlops", parents: ["ml"], related: [{ to: "devops", w: 0.4 }] },
196
- { id: "agents", parents: ["llm"], synonyms: ["agentic", "ai-agents", "multi-agent"], related: [{ to: "rag", w: 0.4 }] },
196
+ { id: "agents", parents: ["llm"], synonyms: ["agentic", "ai-agents", "multi-agent", "agent-orchestration"], related: [{ to: "rag", w: 0.4 }] },
197
197
  { id: "mcp", parents: ["agents"], synonyms: ["model-context-protocol"], related: [{ to: "llm", w: 0.45 }] },
198
198
  { id: "inference", parents: ["ml"], synonyms: ["model-inference", "llm-inference", "model-serving"], related: [{ to: "mlops", w: 0.5 }, { to: "llm", w: 0.4 }] },
199
199
  { id: "embeddings", parents: ["ml"], synonyms: ["embedding", "vector-embeddings"], related: [{ to: "rag", w: 0.55 }, { to: "llm", w: 0.45 }] },
@@ -459,6 +459,14 @@ var init_extract = __esm({
459
459
  id: "prompt-engineering",
460
460
  cue: /\bprompt[\s-]?engineer(?:ing|s)?\b|\b(llms?|gpt-?[0-9o]*|claude|gemini|llama|mistral|openai|anthropic|langchain|llama[\s-]?index|rag|retrieval[\s-]?augmented|embeddings?|fine[\s-]?tun(?:e|ed|ing)|vector[\s-]?(?:db|database|store)|agentic|ai agents?|chatbots?|generative ai|gen[\s-]?ai|genai|few[\s-]?shot|zero[\s-]?shot)\b/i
461
461
  }
462
+ // Plan-061 note: the AI-eng generic words (orchestration/evals/evaluation/guardrails/
463
+ // governance) were briefly added as raw agents/llm synonyms, but `normalize()` — the
464
+ // context-free firewall shared by the declaration path AND the GitHub bounty/
465
+ // contribution feeds — resolves synonyms with NO cue, so those words false-mined
466
+ // agents/llm from ordinary infra/SRE prose on every normalize() caller. A cue gate
467
+ // here only covers extractSkillTags(), not normalize(). Fix: they are NOT graph
468
+ // synonyms at all (see graph.data.ts) → they fall to the 3-tier SOFT/novel bucket,
469
+ // which is exactly where ambiguous, uncategorizable words belong. Nothing to gate.
462
470
  };
463
471
  ENG_INTENT = /\b(engineer|engineering|developer|dev\b|swe|sde|programmer|architect|full[\s-]?stack|front[\s-]?end|back[\s-]?end|devops|sre|software|coding|codebase|technical staff|tech(?:nical)? lead)\b/i;
464
472
  NON_ENG_TITLE = /\b(account executive|account manager|sales (?:rep|representative|development|manager|lead)|sdr|bdr|recruiter|recruiting|talent|marketing|administrative|business partner|billing coordinator|operations (?:administrator|coordinator)|customer success|project finance|controller|bookkeeper|graphic|brand)\b/i;
@@ -582,6 +590,69 @@ var init_idf_background = __esm({
582
590
  }
583
591
  });
584
592
 
593
+ // ../../packages/core/src/vocab/classify.ts
594
+ function editDistance(a, b, max) {
595
+ if (a === b) return 0;
596
+ if (Math.abs(a.length - b.length) > max) return max + 1;
597
+ const prev = new Array(b.length + 1);
598
+ const cur = new Array(b.length + 1);
599
+ for (let j = 0; j <= b.length; j++) prev[j] = j;
600
+ for (let i = 1; i <= a.length; i++) {
601
+ cur[0] = i;
602
+ let rowMin = cur[0];
603
+ for (let j = 1; j <= b.length; j++) {
604
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
605
+ cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
606
+ if (cur[j] < rowMin) rowMin = cur[j];
607
+ }
608
+ if (rowMin > max) return max + 1;
609
+ for (let j = 0; j <= b.length; j++) prev[j] = cur[j];
610
+ }
611
+ return prev[b.length];
612
+ }
613
+ function canonicalOf(surface, graph) {
614
+ if (graph.ids.has(surface)) return surface;
615
+ return graph.synonyms.get(surface);
616
+ }
617
+ function nearBudget(len) {
618
+ if (len <= 3) return 0;
619
+ if (len <= 6) return 1;
620
+ return 2;
621
+ }
622
+ function classifyToken(raw, graph = GRAPH) {
623
+ const token = String(raw ?? "").toLowerCase().trim();
624
+ const exact = canonicalOf(token, graph);
625
+ if (exact) return { raw: token, tier: "matched", canonical: exact };
626
+ const budget = nearBudget(token.length);
627
+ if (budget > 0) {
628
+ let bestSurface;
629
+ let bestDist = budget + 1;
630
+ const consider = (surface) => {
631
+ const d = editDistance(token, surface, budget);
632
+ if (d <= budget && (d < bestDist || d === bestDist && bestSurface !== void 0 && (surface.length < bestSurface.length || surface.length === bestSurface.length && surface < bestSurface))) {
633
+ bestDist = d;
634
+ bestSurface = surface;
635
+ }
636
+ };
637
+ for (const id of graph.ids) consider(id);
638
+ for (const alias of graph.synonyms.keys()) consider(alias);
639
+ if (bestSurface !== void 0) {
640
+ const suggestion = canonicalOf(bestSurface, graph);
641
+ if (suggestion) return { raw: token, tier: "near-miss", suggestion };
642
+ }
643
+ }
644
+ return { raw: token, tier: "novel", soft: token };
645
+ }
646
+ function classifyTokens(raws, graph = GRAPH) {
647
+ return raws.map((r) => classifyToken(r, graph));
648
+ }
649
+ var init_classify = __esm({
650
+ "../../packages/core/src/vocab/classify.ts"() {
651
+ "use strict";
652
+ init_vocab();
653
+ }
654
+ });
655
+
585
656
  // ../../packages/core/src/vocab/index.ts
586
657
  function normalize(tokens) {
587
658
  const result = /* @__PURE__ */ new Set();
@@ -645,6 +716,7 @@ var init_vocab = __esm({
645
716
  init_graph_data();
646
717
  init_extract();
647
718
  init_idf_background();
719
+ init_classify();
648
720
  GRAPH = buildGraph(VOCAB_NODES);
649
721
  VOCABULARY = [...GRAPH.ids];
650
722
  SYNONYMS = Object.fromEntries(GRAPH.synonyms);
@@ -749,6 +821,30 @@ var init_contribution_gate = __esm({
749
821
  }
750
822
  });
751
823
 
824
+ // ../../packages/core/src/credential/rigor.ts
825
+ function deriveRigorTiers(input) {
826
+ const tiers = {};
827
+ if (input.reviewerAssociations !== void 0) {
828
+ tiers.maintainerReviewed = input.reviewerAssociations.some(
829
+ (a) => MAINTAINER_SET.has(String(a).toUpperCase())
830
+ );
831
+ }
832
+ return tiers;
833
+ }
834
+ var RIGOR, MAINTAINER_SET;
835
+ var init_rigor = __esm({
836
+ "../../packages/core/src/credential/rigor.ts"() {
837
+ "use strict";
838
+ RIGOR = {
839
+ /** `authorAssociation` values that count as a maintainer review. */
840
+ MAINTAINER_ASSOCIATIONS: ["OWNER", "MEMBER", "COLLABORATOR"]
841
+ };
842
+ MAINTAINER_SET = new Set(
843
+ RIGOR.MAINTAINER_ASSOCIATIONS.map((a) => a.toUpperCase())
844
+ );
845
+ }
846
+ });
847
+
752
848
  // ../../packages/core/src/github.ts
753
849
  function ghHeaders(token) {
754
850
  const headers = {
@@ -1027,6 +1123,33 @@ async function computeAcceptanceFromSearch(login, token, ownedOrgs, cache, gates
1027
1123
  if (mergedAt > b.lastMergedAt) b.lastMergedAt = mergedAt;
1028
1124
  }
1029
1125
  }
1126
+ if (token) {
1127
+ const enrichStats = { transient: 0 };
1128
+ const enrichCount = Math.min(qualifyingPRs.length, MAX_ENRICH_PRS);
1129
+ for (let i = 0; i < enrichCount; i++) {
1130
+ const pr = qualifyingPRs[i];
1131
+ const ref = parseGitHubRef(pr.url);
1132
+ if (!ref || ref.kind !== "pull") continue;
1133
+ try {
1134
+ const reviews = await ghFetch(
1135
+ `/repos/${ref.owner}/${ref.repo}/pulls/${ref.number}/reviews?per_page=100`,
1136
+ token
1137
+ );
1138
+ const reviewerAssociations = reviews.map((r) => r.author_association);
1139
+ const tiers = deriveRigorTiers({ reviewerAssociations });
1140
+ if (tiers.maintainerReviewed !== void 0) pr.maintainerReviewed = tiers.maintainerReviewed;
1141
+ } catch (err) {
1142
+ const msg = err instanceof Error ? err.message : String(err);
1143
+ if (TRANSIENT_META_ERROR.test(msg)) {
1144
+ enrichStats.transient += 1;
1145
+ console.warn(
1146
+ `[acceptance] ${login}: per-PR rigor enrichment transient failure (${enrichStats.transient}) \u2014 leaving remaining tiers undefined rather than fabricating a false`
1147
+ );
1148
+ break;
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1030
1153
  const finalDomains = {};
1031
1154
  for (const [d, b] of Object.entries(byDomain)) {
1032
1155
  finalDomains[d] = {
@@ -1233,6 +1356,17 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
1233
1356
  }
1234
1357
  const contributors = await repoContributorCount(owner, repo, token, sig);
1235
1358
  const { closesIssues, linkageSource } = await resolveClosingIssues(owner, repo, number, pr.body ?? "", token, sig);
1359
+ let reviewerAssociations;
1360
+ try {
1361
+ const reviews = await ghFetch(
1362
+ `/repos/${owner}/${repo}/pulls/${number}/reviews?per_page=100`,
1363
+ token,
1364
+ sig
1365
+ );
1366
+ reviewerAssociations = reviews.map((r) => r.author_association);
1367
+ } catch {
1368
+ reviewerAssociations = void 0;
1369
+ }
1236
1370
  return {
1237
1371
  repo: `${owner}/${repo}`,
1238
1372
  prNumber: number,
@@ -1250,17 +1384,24 @@ async function fetchPRScoringFacts(prUrl, token, signal) {
1250
1384
  repoArchived: !!repoMeta?.archived,
1251
1385
  repoFork: !!repoMeta?.fork,
1252
1386
  repoPrivate: !!repoMeta?.private,
1387
+ additions: pr.additions ?? null,
1388
+ deletions: pr.deletions ?? null,
1389
+ changedFiles: pr.changed_files ?? null,
1390
+ repoForks: repoMeta?.forks_count ?? null,
1391
+ reviewerAssociations,
1253
1392
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
1254
1393
  };
1255
1394
  }
1256
- var TRACTION_TOP_N, CANDIDATE_PR_PAGE, OPEN_PR_PAGE, TRANSIENT_META_ERROR, RESUME_DECAY_HALF_LIFE_MS, RESUME_MIN_SCORE;
1395
+ var TRACTION_TOP_N, CANDIDATE_PR_PAGE, MAX_ENRICH_PRS, OPEN_PR_PAGE, TRANSIENT_META_ERROR, RESUME_DECAY_HALF_LIFE_MS, RESUME_MIN_SCORE;
1257
1396
  var init_github = __esm({
1258
1397
  "../../packages/core/src/github.ts"() {
1259
1398
  "use strict";
1260
1399
  init_vocabulary();
1261
1400
  init_contribution_gate();
1401
+ init_rigor();
1262
1402
  TRACTION_TOP_N = 6;
1263
1403
  CANDIDATE_PR_PAGE = 50;
1404
+ MAX_ENRICH_PRS = 12;
1264
1405
  OPEN_PR_PAGE = 20;
1265
1406
  TRANSIENT_META_ERROR = /HTTP 403|HTTP 429|rate limit|HTTP 5\d\d|timeout|network|fetch failed/i;
1266
1407
  RESUME_DECAY_HALF_LIFE_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -6772,10 +6913,13 @@ function deriveLegibleProfile(credential, recency, traction, seniorityBand) {
6772
6913
  if (daysAgo !== void 0) s += ` \u2014 most recent ${daysAgo}d ago`;
6773
6914
  proofSentence = `${s}.`;
6774
6915
  }
6916
+ const enrichedPRs = ok ? credential.qualifyingPRs ?? [] : [];
6917
+ const maintainerReviewedCount = enrichedPRs.some((p) => p.maintainerReviewed !== void 0) ? enrichedPRs.filter((p) => p.maintainerReviewed === true).length : void 0;
6775
6918
  const auditableBadge = ok ? {
6776
6919
  mergedTotal: credential.qualifyingTotal,
6777
6920
  distinctOrgs: orgCount,
6778
- thresholds: { stars: MIN_STARS, contributors: MIN_CONTRIBUTORS }
6921
+ thresholds: { stars: MIN_STARS, contributors: MIN_CONTRIBUTORS },
6922
+ ...maintainerReviewedCount !== void 0 ? { maintainerReviewedCount } : {}
6779
6923
  } : null;
6780
6924
  const profile = {
6781
6925
  headline,
@@ -6971,6 +7115,7 @@ __export(src_exports, {
6971
7115
  MENTION_DELTA: () => MENTION_DELTA,
6972
7116
  MIN_CONTRIBUTORS: () => MIN_CONTRIBUTORS,
6973
7117
  MIN_STARS: () => MIN_STARS,
7118
+ RIGOR: () => RIGOR,
6974
7119
  STRONG_MATCH_THRESHOLD: () => STRONG_MATCH_THRESHOLD,
6975
7120
  SYNONYMS: () => SYNONYMS,
6976
7121
  TRIVIAL_PR_TITLE: () => TRIVIAL_PR_TITLE,
@@ -6989,6 +7134,8 @@ __export(src_exports, {
6989
7134
  buildIntroListItem: () => buildIntroListItem,
6990
7135
  buildIntroPayload: () => buildIntroPayload,
6991
7136
  buildReason: () => buildReason,
7137
+ classifyToken: () => classifyToken,
7138
+ classifyTokens: () => classifyTokens,
6992
7139
  composeIntroAcceptedEmail: () => composeIntroAcceptedEmail,
6993
7140
  composeIntroEmail: () => composeIntroEmail,
6994
7141
  computeAcceptanceCredential: () => computeAcceptanceCredential,
@@ -6999,6 +7146,7 @@ __export(src_exports, {
6999
7146
  decryptMessage: () => decryptMessage,
7000
7147
  deriveLegibleProfile: () => deriveLegibleProfile,
7001
7148
  deriveResumeTrend: () => deriveResumeTrend,
7149
+ deriveRigorTiers: () => deriveRigorTiers,
7002
7150
  deriveSharedKey: () => deriveSharedKey,
7003
7151
  deriveTrajectoryNarrative: () => deriveTrajectoryNarrative,
7004
7152
  displayableDrift: () => displayableDrift,
@@ -7078,6 +7226,7 @@ var init_src = __esm({
7078
7226
  init_job_status();
7079
7227
  init_legible();
7080
7228
  init_legible_trajectory();
7229
+ init_rigor();
7081
7230
  init_short_token();
7082
7231
  }
7083
7232
  });
@@ -7090,9 +7239,9 @@ var init_keytar = __esm({
7090
7239
  }
7091
7240
  });
7092
7241
 
7093
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/claim-frictionless/node_modules/keytar/build/Release/keytar.node
7242
+ // node-file:/Users/ericgang/job-placement-inline-wt/release-v0240/node_modules/keytar/build/Release/keytar.node
7094
7243
  var require_keytar = __commonJS({
7095
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/claim-frictionless/node_modules/keytar/build/Release/keytar.node"(exports, module) {
7244
+ "node-file:/Users/ericgang/job-placement-inline-wt/release-v0240/node_modules/keytar/build/Release/keytar.node"(exports, module) {
7096
7245
  "use strict";
7097
7246
  init_keytar();
7098
7247
  try {
@@ -7512,36 +7661,46 @@ ${i + 1}. ${linkTitle(job.title, job.url)} [${ref}]`);
7512
7661
  console.log(` Claim: ${sanitizeText(b.claimUrl ?? job.url)}`);
7513
7662
  console.log(` \u2192 terminalhire claim ${ref}`);
7514
7663
  }
7664
+ async function getBounties({ quiet = false, offline = false } = {}) {
7665
+ if (!quiet) console.log(`Fetching bounty index from ${API_URL}/api/index...`);
7666
+ const index = offline ? readIndexCache() : await fetchIndex();
7667
+ if (offline && !index) return { status: "no-cache" };
7668
+ let bounties = (index.jobs ?? []).filter((j) => j.source === "bounty");
7669
+ if (PRICED_ONLY) bounties = bounties.filter((j) => j.bounty?.amountUSD != null);
7670
+ if (WINNABLE_ONLY) bounties = bounties.filter((j) => (j.bounty?.competingOpenPRs ?? 0) === 0);
7671
+ if (bounties.length === 0) {
7672
+ return { status: "empty" };
7673
+ }
7674
+ const ranked = /* @__PURE__ */ new Map();
7675
+ try {
7676
+ const { readProfile: readProfile2, profileToFingerprint: profileToFingerprint2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
7677
+ const { match: match2 } = await Promise.resolve().then(() => (init_src(), src_exports));
7678
+ const profile = await readProfile2();
7679
+ if (profile.skillTags.length > 0) {
7680
+ const fp = profileToFingerprint2(profile);
7681
+ for (const r of match2(fp, bounties, bounties.length)) {
7682
+ ranked.set(r.job.id, { score: r.score, reason: r.reason, matchedTags: r.matchedTags });
7683
+ }
7684
+ }
7685
+ } catch {
7686
+ }
7687
+ const score = (j) => ranked.get(j.id)?.score ?? 0;
7688
+ const amt = (j) => j.bounty?.amountUSD ?? -1;
7689
+ const contested = (j) => (j.bounty?.competingOpenPRs ?? 0) > 0 ? 1 : 0;
7690
+ bounties.sort((a, b) => contested(a) - contested(b) || score(b) - score(a) || amt(b) - amt(a));
7691
+ const matchedCount = bounties.filter((j) => score(j) > 0).length;
7692
+ return { status: "ok", bounties, ranked, matchedCount };
7693
+ }
7515
7694
  async function run() {
7516
7695
  try {
7517
- console.log(`Fetching bounty index from ${API_URL}/api/index...`);
7518
- const index = await fetchIndex();
7519
- let bounties = (index.jobs ?? []).filter((j) => j.source === "bounty");
7520
- if (PRICED_ONLY) bounties = bounties.filter((j) => j.bounty?.amountUSD != null);
7521
- if (WINNABLE_ONLY) bounties = bounties.filter((j) => (j.bounty?.competingOpenPRs ?? 0) === 0);
7522
- if (bounties.length === 0) {
7696
+ const result = await getBounties();
7697
+ if (result.status === "empty") {
7523
7698
  console.log("\nNo bounties available right now. Try again later \u2014 supply refreshes through the day.");
7524
7699
  return;
7525
7700
  }
7526
- const ranked = /* @__PURE__ */ new Map();
7527
- try {
7528
- const { readProfile: readProfile2, profileToFingerprint: profileToFingerprint2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
7529
- const { match: match2 } = await Promise.resolve().then(() => (init_src(), src_exports));
7530
- const profile = await readProfile2();
7531
- if (profile.skillTags.length > 0) {
7532
- const fp = profileToFingerprint2(profile);
7533
- for (const r of match2(fp, bounties, bounties.length)) {
7534
- ranked.set(r.job.id, { score: r.score, reason: r.reason, matchedTags: r.matchedTags });
7535
- }
7536
- }
7537
- } catch {
7538
- }
7539
- const score = (j) => ranked.get(j.id)?.score ?? 0;
7540
- const amt = (j) => j.bounty?.amountUSD ?? -1;
7541
- const contested = (j) => (j.bounty?.competingOpenPRs ?? 0) > 0 ? 1 : 0;
7542
- bounties.sort((a, b) => contested(a) - contested(b) || score(b) - score(a) || amt(b) - amt(a));
7701
+ if (result.status !== "ok") return;
7702
+ const { bounties, ranked, matchedCount } = result;
7543
7703
  const shown = SHOW_ALL ? bounties : bounties.slice(0, LIMIT);
7544
- const matchedCount = bounties.filter((j) => score(j) > 0).length;
7545
7704
  console.log(
7546
7705
  `
7547
7706
  \u26A1 ${bounties.length} bount${bounties.length === 1 ? "y" : "ies"} you could knock out` + (matchedCount ? ` \u2014 ${matchedCount} matched to your profile` : "") + ` (local rank \u2014 no data sent)
@@ -7573,6 +7732,7 @@ Open this to claim/work the bounty (you go straight to the source \u2014 we neve
7573
7732
  }
7574
7733
  }
7575
7734
  export {
7735
+ getBounties,
7576
7736
  run
7577
7737
  };
7578
7738
  /*! Bundled license information:
@@ -183,7 +183,7 @@ var init_graph_data = __esm({
183
183
  { id: "anthropic", parents: ["llm"], synonyms: ["claude"] },
184
184
  { id: "rag", parents: ["llm"], synonyms: ["retrieval-augmented-generation"] },
185
185
  { id: "mlops", parents: ["ml"], related: [{ to: "devops", w: 0.4 }] },
186
- { id: "agents", parents: ["llm"], synonyms: ["agentic", "ai-agents", "multi-agent"], related: [{ to: "rag", w: 0.4 }] },
186
+ { id: "agents", parents: ["llm"], synonyms: ["agentic", "ai-agents", "multi-agent", "agent-orchestration"], related: [{ to: "rag", w: 0.4 }] },
187
187
  { id: "mcp", parents: ["agents"], synonyms: ["model-context-protocol"], related: [{ to: "llm", w: 0.45 }] },
188
188
  { id: "inference", parents: ["ml"], synonyms: ["model-inference", "llm-inference", "model-serving"], related: [{ to: "mlops", w: 0.5 }, { to: "llm", w: 0.4 }] },
189
189
  { id: "embeddings", parents: ["ml"], synonyms: ["embedding", "vector-embeddings"], related: [{ to: "rag", w: 0.55 }, { to: "llm", w: 0.45 }] },
@@ -396,6 +396,14 @@ var init_idf_background = __esm({
396
396
  }
397
397
  });
398
398
 
399
+ // ../../packages/core/src/vocab/classify.ts
400
+ var init_classify = __esm({
401
+ "../../packages/core/src/vocab/classify.ts"() {
402
+ "use strict";
403
+ init_vocab();
404
+ }
405
+ });
406
+
399
407
  // ../../packages/core/src/vocab/index.ts
400
408
  var GRAPH, VOCABULARY, SYNONYMS;
401
409
  var init_vocab = __esm({
@@ -408,6 +416,7 @@ var init_vocab = __esm({
408
416
  init_graph_data();
409
417
  init_extract();
410
418
  init_idf_background();
419
+ init_classify();
411
420
  GRAPH = buildGraph(VOCAB_NODES);
412
421
  VOCABULARY = [...GRAPH.ids];
413
422
  SYNONYMS = Object.fromEntries(GRAPH.synonyms);
@@ -462,6 +471,21 @@ var init_contribution_gate = __esm({
462
471
  }
463
472
  });
464
473
 
474
+ // ../../packages/core/src/credential/rigor.ts
475
+ var RIGOR, MAINTAINER_SET;
476
+ var init_rigor = __esm({
477
+ "../../packages/core/src/credential/rigor.ts"() {
478
+ "use strict";
479
+ RIGOR = {
480
+ /** `authorAssociation` values that count as a maintainer review. */
481
+ MAINTAINER_ASSOCIATIONS: ["OWNER", "MEMBER", "COLLABORATOR"]
482
+ };
483
+ MAINTAINER_SET = new Set(
484
+ RIGOR.MAINTAINER_ASSOCIATIONS.map((a) => a.toUpperCase())
485
+ );
486
+ }
487
+ });
488
+
465
489
  // ../../packages/core/src/github.ts
466
490
  var RESUME_DECAY_HALF_LIFE_MS;
467
491
  var init_github = __esm({
@@ -469,6 +493,7 @@ var init_github = __esm({
469
493
  "use strict";
470
494
  init_vocabulary();
471
495
  init_contribution_gate();
496
+ init_rigor();
472
497
  RESUME_DECAY_HALF_LIFE_MS = 30 * 24 * 60 * 60 * 1e3;
473
498
  }
474
499
  });
@@ -3963,6 +3988,7 @@ var init_src = __esm({
3963
3988
  init_job_status();
3964
3989
  init_legible();
3965
3990
  init_legible_trajectory();
3991
+ init_rigor();
3966
3992
  init_short_token();
3967
3993
  }
3968
3994
  });
@@ -3975,9 +4001,9 @@ var init_keytar = __esm({
3975
4001
  }
3976
4002
  });
3977
4003
 
3978
- // node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/claim-frictionless/node_modules/keytar/build/Release/keytar.node
4004
+ // node-file:/Users/ericgang/job-placement-inline-wt/release-v0240/node_modules/keytar/build/Release/keytar.node
3979
4005
  var require_keytar = __commonJS({
3980
- "node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/claim-frictionless/node_modules/keytar/build/Release/keytar.node"(exports, module) {
4006
+ "node-file:/Users/ericgang/job-placement-inline-wt/release-v0240/node_modules/keytar/build/Release/keytar.node"(exports, module) {
3981
4007
  "use strict";
3982
4008
  init_keytar();
3983
4009
  try {
@@ -4439,14 +4465,62 @@ var init_config = __esm({
4439
4465
  }
4440
4466
  });
4441
4467
 
4468
+ // bin/tui-core.js
4469
+ function sanitizeLine(text) {
4470
+ return String(text).replace(ANSI_CSI, "").replace(ANSI_OSC, "").replace(ANSI_OTHER, "").replace(C0_C1_DEL, "");
4471
+ }
4472
+ var ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, PALETTE, COLOR_ROLES;
4473
+ var init_tui_core = __esm({
4474
+ "bin/tui-core.js"() {
4475
+ "use strict";
4476
+ ANSI_CSI = /\x1b\[[0-?]*[ -/]*[@-~]/g;
4477
+ ANSI_OSC = /\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g;
4478
+ ANSI_OTHER = /\x1b[@-_]/g;
4479
+ C0_C1_DEL = /[\x00-\x1f\x7f-\x9f]/g;
4480
+ PALETTE = {
4481
+ truecolor: {
4482
+ bg: "\x1B[48;2;13;17;23m",
4483
+ panel: "\x1B[48;2;22;27;34m",
4484
+ rule: "\x1B[38;2;48;54;61m",
4485
+ text: "\x1B[38;2;201;209;217m",
4486
+ muted: "\x1B[38;2;125;133;144m",
4487
+ accent: "\x1B[38;2;88;166;255m",
4488
+ "accent-bright": "\x1B[38;2;121;192;255m",
4489
+ green: "\x1B[38;2;63;185;80m",
4490
+ amber: "\x1B[38;2;210;153;34m"
4491
+ },
4492
+ 256: {
4493
+ bg: "\x1B[48;5;233m",
4494
+ panel: "\x1B[48;5;235m",
4495
+ rule: "\x1B[38;5;240m",
4496
+ text: "\x1B[38;5;252m",
4497
+ muted: "\x1B[38;5;245m",
4498
+ accent: "\x1B[38;5;75m",
4499
+ "accent-bright": "\x1B[38;5;117m",
4500
+ green: "\x1B[38;5;71m",
4501
+ amber: "\x1B[38;5;178m"
4502
+ },
4503
+ 16: {
4504
+ bg: "\x1B[40m",
4505
+ panel: "\x1B[100m",
4506
+ rule: "\x1B[90m",
4507
+ text: "\x1B[37m",
4508
+ muted: "\x1B[90m",
4509
+ accent: "\x1B[94m",
4510
+ "accent-bright": "\x1B[96m",
4511
+ green: "\x1B[92m",
4512
+ amber: "\x1B[93m"
4513
+ }
4514
+ };
4515
+ COLOR_ROLES = Object.keys(PALETTE.truecolor);
4516
+ }
4517
+ });
4518
+
4442
4519
  // bin/jpi-chat.js
4443
4520
  import { createInterface } from "readline";
4444
4521
  import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
4445
4522
  import { homedir as homedir6 } from "os";
4446
4523
  import { join as join7 } from "path";
4447
- function sanitizeLine(text) {
4448
- return String(text).replace(ANSI_CSI, "").replace(ANSI_OSC, "").replace(ANSI_OTHER, "").replace(C0_C1_DEL, "");
4449
- }
4450
4524
  function defaultPromptAck({ input = process.stdin, output = process.stdout } = {}) {
4451
4525
  if (!input || input.isTTY !== true) return Promise.resolve(false);
4452
4526
  const rl = createInterface({ input, output });
@@ -4565,19 +4639,16 @@ function formatPresence(presence, now = /* @__PURE__ */ new Date()) {
4565
4639
  }
4566
4640
  return "\u25D0 reachable";
4567
4641
  }
4568
- var CHAT_BASE2, GH_SESSION_COOKIE2, ANSI_CSI, ANSI_OSC, ANSI_OTHER, C0_C1_DEL, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, ACTIVE_WINDOW_MS;
4642
+ var CHAT_BASE2, GH_SESSION_COOKIE2, CHAT_DISCLOSURE, CHAT_AT_REST, CHAT_CODE_OF_CONDUCT, CHAT_MIN_AGE, ACTIVE_WINDOW_MS;
4569
4643
  var init_jpi_chat = __esm({
4570
4644
  "bin/jpi-chat.js"() {
4571
4645
  "use strict";
4572
4646
  init_chat_client();
4573
4647
  init_config();
4574
4648
  init_web_session();
4649
+ init_tui_core();
4575
4650
  CHAT_BASE2 = process.env["TERMINALHIRE_API_URL"] || "https://terminalhire.com";
4576
4651
  GH_SESSION_COOKIE2 = "__jpi_gh_session";
4577
- ANSI_CSI = /\x1b\[[0-?]*[ -/]*[@-~]/g;
4578
- ANSI_OSC = /\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g;
4579
- ANSI_OTHER = /\x1b[@-_]/g;
4580
- C0_C1_DEL = /[\x00-\x1f\x7f-\x9f]/g;
4581
4652
  CHAT_DISCLOSURE = "Messages are end-to-end encrypted using keys stored only on your device. Our server cannot read message content. Since we distribute your contact's public key, verify your connection by comparing Safety Numbers to rule out a server-side substitution. We store metadata: who messaged whom, when, and message count. Content is purged after 90 days.";
4582
4653
  CHAT_AT_REST = "Your private key is encrypted against casual access, not full machine compromise.";
4583
4654
  CHAT_CODE_OF_CONDUCT = "Code of conduct: keep it professional \u2014 harassment, spam, or abuse gets you blocked and removed.";