terminalhire 0.42.1 → 0.42.3

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.
@@ -167,7 +167,7 @@ function nowISO() {
167
167
  return (/* @__PURE__ */ new Date()).toISOString();
168
168
  }
169
169
  function defangText(s) {
170
- return typeof s === "string" ? s.replace(CONTROL_CHARS, "") : s;
170
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "") : s;
171
171
  }
172
172
  function finiteAmount(a) {
173
173
  if (typeof a === "number") return Number.isFinite(a) ? a : null;
@@ -305,7 +305,7 @@ function acceptedPRRate(claims = readClaims()) {
305
305
  const merged = claims.filter((c) => c.state === "merged").length;
306
306
  return { merged, total, rate: total === 0 ? 0 : merged / total };
307
307
  }
308
- var TERMINALHIRE_DIR3, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS;
308
+ var TERMINALHIRE_DIR3, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, WHITESPACE_CONTROLS, CONTROL_CHARS;
309
309
  var init_claims = __esm({
310
310
  "src/claims.ts"() {
311
311
  "use strict";
@@ -361,6 +361,7 @@ var init_claims = __esm({
361
361
  ]),
362
362
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
363
363
  };
364
+ WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
364
365
  CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
365
366
  }
366
367
  });
@@ -11339,7 +11339,7 @@ function nowISO2() {
11339
11339
  return (/* @__PURE__ */ new Date()).toISOString();
11340
11340
  }
11341
11341
  function defangText(s) {
11342
- return typeof s === "string" ? s.replace(CONTROL_CHARS2, "") : s;
11342
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS2, " ").replace(CONTROL_CHARS2, "") : s;
11343
11343
  }
11344
11344
  function finiteAmount(a) {
11345
11345
  if (typeof a === "number") return Number.isFinite(a) ? a : null;
@@ -11477,7 +11477,7 @@ function acceptedPRRate(claims = readClaims()) {
11477
11477
  const merged = claims.filter((c) => c.state === "merged").length;
11478
11478
  return { merged, total, rate: total === 0 ? 0 : merged / total };
11479
11479
  }
11480
- var TERMINALHIRE_DIR5, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS2;
11480
+ var TERMINALHIRE_DIR5, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, WHITESPACE_CONTROLS2, CONTROL_CHARS2;
11481
11481
  var init_claims = __esm({
11482
11482
  "src/claims.ts"() {
11483
11483
  "use strict";
@@ -11533,6 +11533,7 @@ var init_claims = __esm({
11533
11533
  ]),
11534
11534
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
11535
11535
  };
11536
+ WHITESPACE_CONTROLS2 = /[\t\n\v\f\r]+/g;
11536
11537
  CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
11537
11538
  }
11538
11539
  });
@@ -11748,17 +11749,38 @@ var init_founder_paid_badge = __esm({
11748
11749
 
11749
11750
  // bin/jpi-bounties.js
11750
11751
  init_src();
11751
- init_cache_store();
11752
11752
  import { readFileSync as readFileSync7 } from "fs";
11753
11753
  import { join as join10 } from "path";
11754
11754
  import { homedir as homedir7 } from "os";
11755
11755
  import { createInterface } from "readline";
11756
11756
 
11757
+ // ../../packages/core/src/payout-split.ts
11758
+ var PLATFORM_TAKE_BPS = 1e3;
11759
+ function platformFeeCents(totalCents) {
11760
+ return Math.ceil(totalCents * PLATFORM_TAKE_BPS / 1e4);
11761
+ }
11762
+ function developerShareCents(totalCents) {
11763
+ return totalCents - platformFeeCents(totalCents);
11764
+ }
11765
+ function formatCents(cents) {
11766
+ return cents % 100 === 0 ? `$${cents / 100}` : `$${(cents / 100).toFixed(2)}`;
11767
+ }
11768
+
11769
+ // bin/jpi-bounties.js
11770
+ init_cache_store();
11771
+
11757
11772
  // bin/sanitize.js
11773
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
11758
11774
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
11759
11775
  function sanitizeText(s) {
11760
11776
  if (s == null) return "";
11761
- return String(s).replace(CONTROL_CHARS, "");
11777
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
11778
+ }
11779
+ function formatUsd(a) {
11780
+ if (typeof a === "number") return Number.isFinite(a) ? "$" + a.toLocaleString() : "$\u2014";
11781
+ if (typeof a !== "string" || a.trim() === "") return "$\u2014";
11782
+ const n = Number(a);
11783
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
11762
11784
  }
11763
11785
  function safeHttpUrl(url) {
11764
11786
  if (url == null) return null;
@@ -11831,13 +11853,33 @@ function prompt(question) {
11831
11853
  });
11832
11854
  }
11833
11855
  function formatAmount(b) {
11834
- return b.amountUSD != null ? "$" + b.amountUSD.toLocaleString() : "$\u2014";
11856
+ return formatUsd(b.amountUSD);
11835
11857
  }
11836
11858
  var EFFORT_LABEL = {
11837
11859
  small: "small (~\xBD day)",
11838
11860
  medium: "medium (~1 day)",
11839
11861
  large: "large (multi-day)"
11840
11862
  };
11863
+ function founderClaimBlurb(amountUSD, paidWork) {
11864
+ if (paidWork === false) {
11865
+ return "Claim it from here \u2014 this posting records a credential for the work, not a payment. Take it for the credential, not the money.";
11866
+ }
11867
+ if (paidWork !== true) {
11868
+ return "Claim it from here \u2014 this listing is missing its payment status, so it is not safe to say whether the work pays. Try `terminalhire refresh`; if it is still missing, do not count on being paid for this one.";
11869
+ }
11870
+ let share = "";
11871
+ if (typeof amountUSD === "number" && Number.isFinite(amountUSD) && amountUSD > 0) {
11872
+ share = ` You'd receive ${formatCents(developerShareCents(Math.round(amountUSD * 100)))} of the ${formatCents(Math.round(amountUSD * 100))} posted; terminalhire keeps 10%.`;
11873
+ }
11874
+ return `Claim it from here \u2014 the founder pays through terminalhire rather than off-platform, and their acceptance is what triggers your payout.${share}`;
11875
+ }
11876
+ function founderClaimBlock(job) {
11877
+ const ref = opportunityShortToken(job.id);
11878
+ return `
11879
+ ${founderClaimBlurb(job.bounty?.amountUSD, job.bounty?.paidWork)}
11880
+ terminalhire claim ${ref}
11881
+ ${sanitizeText(job.bounty?.claimUrl ?? job.url)}`;
11882
+ }
11841
11883
  function printBounty(i, job, score, reason, matchedTags, claimedIds = /* @__PURE__ */ new Set(), continuityNote = null) {
11842
11884
  const b = job.bounty ?? {};
11843
11885
  const stars = b.repoStars != null ? ` \xB7 ${b.repoStars}\u2605` : "";
@@ -11980,7 +12022,9 @@ async function run() {
11980
12022
  const rows = founderRows2(surface, "bounties");
11981
12023
  console.log("\n\u26A1 Your TerminalHire postings\n");
11982
12024
  if (!rows.length) {
11983
- console.log(" No current posting data. Run `terminalhire refresh`, or lead with work:");
12025
+ console.log(
12026
+ " No current posting data. Run `terminalhire refresh`, or lead with work:"
12027
+ );
11984
12028
  console.log(" terminalhire config set lead dev\n");
11985
12029
  } else {
11986
12030
  rows.forEach((row, index) => {
@@ -11989,7 +12033,9 @@ async function run() {
11989
12033
  );
11990
12034
  });
11991
12035
  console.log("\n Review and act: https://terminalhire.com/dashboard?tab=postings");
11992
- console.log(" Lead with developer bounties instead: terminalhire config set lead dev\n");
12036
+ console.log(
12037
+ " Lead with developer bounties instead: terminalhire config set lead dev\n"
12038
+ );
11993
12039
  }
11994
12040
  return;
11995
12041
  }
@@ -12064,6 +12110,10 @@ Enter a number to open a bounty's claim page, or press Enter to exit: `
12064
12110
  const idx = parseInt(pick, 10) - 1;
12065
12111
  if (Number.isNaN(idx) || idx < 0 || idx >= shown.length) return;
12066
12112
  const chosen = shown[idx];
12113
+ if (chosen.bounty?.bountySource === "founder") {
12114
+ console.log(founderClaimBlock(chosen));
12115
+ return;
12116
+ }
12067
12117
  console.log(
12068
12118
  `
12069
12119
  Open this to claim/work the bounty (you go straight to the source \u2014 we never touch payment):
@@ -12079,6 +12129,8 @@ export {
12079
12129
  classifyEmptyStatus,
12080
12130
  continuityNoteForRow,
12081
12131
  filterPaidVisibility,
12132
+ founderClaimBlock,
12133
+ founderClaimBlurb,
12082
12134
  getBounties,
12083
12135
  isPinnedFounderBounty,
12084
12136
  printBounty,
@@ -10639,7 +10639,7 @@ function nowISO() {
10639
10639
  return (/* @__PURE__ */ new Date()).toISOString();
10640
10640
  }
10641
10641
  function defangText(s) {
10642
- return typeof s === "string" ? s.replace(CONTROL_CHARS2, "") : s;
10642
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS2, " ").replace(CONTROL_CHARS2, "") : s;
10643
10643
  }
10644
10644
  function finiteAmount(a) {
10645
10645
  if (typeof a === "number") return Number.isFinite(a) ? a : null;
@@ -10777,7 +10777,7 @@ function acceptedPRRate(claims = readClaims()) {
10777
10777
  const merged = claims.filter((c) => c.state === "merged").length;
10778
10778
  return { merged, total, rate: total === 0 ? 0 : merged / total };
10779
10779
  }
10780
- var TERMINALHIRE_DIR2, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS2;
10780
+ var TERMINALHIRE_DIR2, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, WHITESPACE_CONTROLS2, CONTROL_CHARS2;
10781
10781
  var init_claims = __esm({
10782
10782
  "src/claims.ts"() {
10783
10783
  "use strict";
@@ -10833,6 +10833,7 @@ var init_claims = __esm({
10833
10833
  ]),
10834
10834
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
10835
10835
  };
10836
+ WHITESPACE_CONTROLS2 = /[\t\n\v\f\r]+/g;
10836
10837
  CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
10837
10838
  }
10838
10839
  });
@@ -26151,10 +26152,17 @@ function openInBrowser(url) {
26151
26152
  }
26152
26153
 
26153
26154
  // bin/sanitize.js
26155
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
26154
26156
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
26155
26157
  function sanitizeText(s) {
26156
26158
  if (s == null) return "";
26157
- return String(s).replace(CONTROL_CHARS, "");
26159
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
26160
+ }
26161
+ function formatUsd(a) {
26162
+ if (typeof a === "number") return Number.isFinite(a) ? "$" + a.toLocaleString() : "$\u2014";
26163
+ if (typeof a !== "string" || a.trim() === "") return "$\u2014";
26164
+ const n = Number(a);
26165
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
26158
26166
  }
26159
26167
 
26160
26168
  // src/policy-acks.ts
@@ -27081,10 +27089,7 @@ async function pollPR(prUrl) {
27081
27089
  }
27082
27090
  }
27083
27091
  function fmtAmount(a) {
27084
- if (a == null) return "$\u2014";
27085
- if (typeof a === "string" && a.trim() === "") return "$\u2014";
27086
- const n = typeof a === "number" ? a : Number(a);
27087
- return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
27092
+ return formatUsd(a);
27088
27093
  }
27089
27094
  function fmtClaimAmount(c) {
27090
27095
  return c.kind === "contribution" ? "contribution" : fmtAmount(c.amountUSD);
@@ -27225,8 +27230,15 @@ async function resolveBounty(arg) {
27225
27230
  return {
27226
27231
  bountyId,
27227
27232
  indexNativeId,
27228
- title,
27229
- repoFullName,
27233
+ // DEFANGED HERE, at the one place every tier of this resolver converges.
27234
+ // `claims.ts` cleans what comes OUT of the local store, which covers every later
27235
+ // read — but this object is printed (the preview card, the record card) and
27236
+ // handed to `recordClaim` BEFORE any store exists for it, so on a claim's first
27237
+ // use the store boundary has not run yet. `repoFullName` also goes on to be
27238
+ // interpolated into GitHub API URLs from here. Found by a cross-model review of
27239
+ // TERM-380; the store fix alone left this path open.
27240
+ title: sanitizeText(title),
27241
+ repoFullName: repoFullName == null ? repoFullName : sanitizeText(repoFullName),
27230
27242
  issueUrl,
27231
27243
  amountUSD,
27232
27244
  source,
@@ -28466,7 +28478,7 @@ async function cmdStart(id, flags = {}) {
28466
28478
  console.error(`terminalhire claim: no claim with id '${id}'.`);
28467
28479
  process.exit(1);
28468
28480
  }
28469
- if (claim.approval?.state === "pending" && !approvalsChecked) {
28481
+ if (claim.approval?.state === "pending") {
28470
28482
  ({ approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, [claim]));
28471
28483
  claim = claims.findClaim(id);
28472
28484
  }
@@ -3618,7 +3618,7 @@ function nowISO2() {
3618
3618
  return (/* @__PURE__ */ new Date()).toISOString();
3619
3619
  }
3620
3620
  function defangText(s) {
3621
- return typeof s === "string" ? s.replace(CONTROL_CHARS2, "") : s;
3621
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS2, " ").replace(CONTROL_CHARS2, "") : s;
3622
3622
  }
3623
3623
  function finiteAmount(a) {
3624
3624
  if (typeof a === "number") return Number.isFinite(a) ? a : null;
@@ -3756,7 +3756,7 @@ function acceptedPRRate(claims = readClaims()) {
3756
3756
  const merged = claims.filter((c) => c.state === "merged").length;
3757
3757
  return { merged, total, rate: total === 0 ? 0 : merged / total };
3758
3758
  }
3759
- var TERMINALHIRE_DIR7, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS2;
3759
+ var TERMINALHIRE_DIR7, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, WHITESPACE_CONTROLS2, CONTROL_CHARS2;
3760
3760
  var init_claims = __esm({
3761
3761
  "src/claims.ts"() {
3762
3762
  "use strict";
@@ -3812,6 +3812,7 @@ var init_claims = __esm({
3812
3812
  ]),
3813
3813
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
3814
3814
  };
3815
+ WHITESPACE_CONTROLS2 = /[\t\n\v\f\r]+/g;
3815
3816
  CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
3816
3817
  }
3817
3818
  });
@@ -3896,10 +3897,11 @@ function isContributeEnabled() {
3896
3897
  init_state_dir();
3897
3898
 
3898
3899
  // bin/sanitize.js
3900
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
3899
3901
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
3900
3902
  function sanitizeText(s) {
3901
3903
  if (s == null) return "";
3902
- return String(s).replace(CONTROL_CHARS, "");
3904
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
3903
3905
  }
3904
3906
  function safeHttpUrl(url) {
3905
3907
  if (url == null) return null;
@@ -11053,10 +11053,11 @@ function excludeOwnCard(results, ownLogin) {
11053
11053
  }
11054
11054
 
11055
11055
  // bin/sanitize.js
11056
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
11056
11057
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
11057
11058
  function sanitizeText(s) {
11058
11059
  if (s == null) return "";
11059
- return String(s).replace(CONTROL_CHARS, "");
11060
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
11060
11061
  }
11061
11062
  function safeHttpUrl(url) {
11062
11063
  if (url == null) return null;