terminalhire 0.41.1 → 0.41.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.
@@ -166,8 +166,24 @@ function nextPolledState(from, observed) {
166
166
  function nowISO() {
167
167
  return (/* @__PURE__ */ new Date()).toISOString();
168
168
  }
169
+ function defangText(s) {
170
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "") : s;
171
+ }
172
+ function finiteAmount(a) {
173
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
174
+ if (typeof a !== "string" || a.trim() === "") return null;
175
+ const n = Number(a);
176
+ return Number.isFinite(n) ? n : null;
177
+ }
169
178
  function normalizeClaim(c) {
170
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
179
+ return {
180
+ ...c,
181
+ kind: c.kind ?? "bounty",
182
+ policy: c.policy ?? null,
183
+ title: defangText(c.title),
184
+ repoFullName: defangText(c.repoFullName),
185
+ amountUSD: finiteAmount(c.amountUSD)
186
+ };
171
187
  }
172
188
  function readClaims() {
173
189
  try {
@@ -289,7 +305,7 @@ function acceptedPRRate(claims = readClaims()) {
289
305
  const merged = claims.filter((c) => c.state === "merged").length;
290
306
  return { merged, total, rate: total === 0 ? 0 : merged / total };
291
307
  }
292
- 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;
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;
293
309
  var init_claims = __esm({
294
310
  "src/claims.ts"() {
295
311
  "use strict";
@@ -345,6 +361,8 @@ var init_claims = __esm({
345
361
  ]),
346
362
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
347
363
  };
364
+ WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
365
+ CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
348
366
  }
349
367
  });
350
368
 
@@ -11338,8 +11338,24 @@ function nextPolledState(from, observed) {
11338
11338
  function nowISO2() {
11339
11339
  return (/* @__PURE__ */ new Date()).toISOString();
11340
11340
  }
11341
+ function defangText(s) {
11342
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS2, " ").replace(CONTROL_CHARS2, "") : s;
11343
+ }
11344
+ function finiteAmount(a) {
11345
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
11346
+ if (typeof a !== "string" || a.trim() === "") return null;
11347
+ const n = Number(a);
11348
+ return Number.isFinite(n) ? n : null;
11349
+ }
11341
11350
  function normalizeClaim(c) {
11342
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
11351
+ return {
11352
+ ...c,
11353
+ kind: c.kind ?? "bounty",
11354
+ policy: c.policy ?? null,
11355
+ title: defangText(c.title),
11356
+ repoFullName: defangText(c.repoFullName),
11357
+ amountUSD: finiteAmount(c.amountUSD)
11358
+ };
11343
11359
  }
11344
11360
  function readClaims() {
11345
11361
  try {
@@ -11461,7 +11477,7 @@ function acceptedPRRate(claims = readClaims()) {
11461
11477
  const merged = claims.filter((c) => c.state === "merged").length;
11462
11478
  return { merged, total, rate: total === 0 ? 0 : merged / total };
11463
11479
  }
11464
- 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;
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;
11465
11481
  var init_claims = __esm({
11466
11482
  "src/claims.ts"() {
11467
11483
  "use strict";
@@ -11517,6 +11533,8 @@ var init_claims = __esm({
11517
11533
  ]),
11518
11534
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
11519
11535
  };
11536
+ WHITESPACE_CONTROLS2 = /[\t\n\v\f\r]+/g;
11537
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
11520
11538
  }
11521
11539
  });
11522
11540
 
@@ -11738,10 +11756,17 @@ import { homedir as homedir7 } from "os";
11738
11756
  import { createInterface } from "readline";
11739
11757
 
11740
11758
  // bin/sanitize.js
11759
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
11741
11760
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
11742
11761
  function sanitizeText(s) {
11743
11762
  if (s == null) return "";
11744
- return String(s).replace(CONTROL_CHARS, "");
11763
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
11764
+ }
11765
+ function formatUsd(a) {
11766
+ if (typeof a === "number") return Number.isFinite(a) ? "$" + a.toLocaleString() : "$\u2014";
11767
+ if (typeof a !== "string" || a.trim() === "") return "$\u2014";
11768
+ const n = Number(a);
11769
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
11745
11770
  }
11746
11771
  function safeHttpUrl(url) {
11747
11772
  if (url == null) return null;
@@ -11814,7 +11839,7 @@ function prompt(question) {
11814
11839
  });
11815
11840
  }
11816
11841
  function formatAmount(b) {
11817
- return b.amountUSD != null ? "$" + b.amountUSD.toLocaleString() : "$\u2014";
11842
+ return formatUsd(b.amountUSD);
11818
11843
  }
11819
11844
  var EFFORT_LABEL = {
11820
11845
  small: "small (~\xBD day)",
@@ -11963,7 +11988,9 @@ async function run() {
11963
11988
  const rows = founderRows2(surface, "bounties");
11964
11989
  console.log("\n\u26A1 Your TerminalHire postings\n");
11965
11990
  if (!rows.length) {
11966
- console.log(" No current posting data. Run `terminalhire refresh`, or lead with work:");
11991
+ console.log(
11992
+ " No current posting data. Run `terminalhire refresh`, or lead with work:"
11993
+ );
11967
11994
  console.log(" terminalhire config set lead dev\n");
11968
11995
  } else {
11969
11996
  rows.forEach((row, index) => {
@@ -11972,7 +11999,9 @@ async function run() {
11972
11999
  );
11973
12000
  });
11974
12001
  console.log("\n Review and act: https://terminalhire.com/dashboard?tab=postings");
11975
- console.log(" Lead with developer bounties instead: terminalhire config set lead dev\n");
12002
+ console.log(
12003
+ " Lead with developer bounties instead: terminalhire config set lead dev\n"
12004
+ );
11976
12005
  }
11977
12006
  return;
11978
12007
  }
@@ -10638,8 +10638,24 @@ function nextPolledState(from, observed) {
10638
10638
  function nowISO() {
10639
10639
  return (/* @__PURE__ */ new Date()).toISOString();
10640
10640
  }
10641
+ function defangText(s) {
10642
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS2, " ").replace(CONTROL_CHARS2, "") : s;
10643
+ }
10644
+ function finiteAmount(a) {
10645
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
10646
+ if (typeof a !== "string" || a.trim() === "") return null;
10647
+ const n = Number(a);
10648
+ return Number.isFinite(n) ? n : null;
10649
+ }
10641
10650
  function normalizeClaim(c) {
10642
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
10651
+ return {
10652
+ ...c,
10653
+ kind: c.kind ?? "bounty",
10654
+ policy: c.policy ?? null,
10655
+ title: defangText(c.title),
10656
+ repoFullName: defangText(c.repoFullName),
10657
+ amountUSD: finiteAmount(c.amountUSD)
10658
+ };
10643
10659
  }
10644
10660
  function readClaims() {
10645
10661
  try {
@@ -10761,7 +10777,7 @@ function acceptedPRRate(claims = readClaims()) {
10761
10777
  const merged = claims.filter((c) => c.state === "merged").length;
10762
10778
  return { merged, total, rate: total === 0 ? 0 : merged / total };
10763
10779
  }
10764
- 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;
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;
10765
10781
  var init_claims = __esm({
10766
10782
  "src/claims.ts"() {
10767
10783
  "use strict";
@@ -10817,6 +10833,8 @@ var init_claims = __esm({
10817
10833
  ]),
10818
10834
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
10819
10835
  };
10836
+ WHITESPACE_CONTROLS2 = /[\t\n\v\f\r]+/g;
10837
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
10820
10838
  }
10821
10839
  });
10822
10840
 
@@ -26057,10 +26075,17 @@ function openInBrowser(url) {
26057
26075
  }
26058
26076
 
26059
26077
  // bin/sanitize.js
26078
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
26060
26079
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
26061
26080
  function sanitizeText(s) {
26062
26081
  if (s == null) return "";
26063
- return String(s).replace(CONTROL_CHARS, "");
26082
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
26083
+ }
26084
+ function formatUsd(a) {
26085
+ if (typeof a === "number") return Number.isFinite(a) ? "$" + a.toLocaleString() : "$\u2014";
26086
+ if (typeof a !== "string" || a.trim() === "") return "$\u2014";
26087
+ const n = Number(a);
26088
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
26064
26089
  }
26065
26090
 
26066
26091
  // src/policy-acks.ts
@@ -26986,7 +27011,7 @@ async function pollPR(prUrl) {
26986
27011
  }
26987
27012
  }
26988
27013
  function fmtAmount(a) {
26989
- return a != null ? "$" + a.toLocaleString() : "$\u2014";
27014
+ return formatUsd(a);
26990
27015
  }
26991
27016
  function fmtClaimAmount(c) {
26992
27017
  return c.kind === "contribution" ? "contribution" : fmtAmount(c.amountUSD);
@@ -27127,8 +27152,15 @@ async function resolveBounty(arg) {
27127
27152
  return {
27128
27153
  bountyId,
27129
27154
  indexNativeId,
27130
- title,
27131
- repoFullName,
27155
+ // DEFANGED HERE, at the one place every tier of this resolver converges.
27156
+ // `claims.ts` cleans what comes OUT of the local store, which covers every later
27157
+ // read — but this object is printed (the preview card, the record card) and
27158
+ // handed to `recordClaim` BEFORE any store exists for it, so on a claim's first
27159
+ // use the store boundary has not run yet. `repoFullName` also goes on to be
27160
+ // interpolated into GitHub API URLs from here. Found by a cross-model review of
27161
+ // TERM-380; the store fix alone left this path open.
27162
+ title: sanitizeText(title),
27163
+ repoFullName: repoFullName == null ? repoFullName : sanitizeText(repoFullName),
27132
27164
  issueUrl,
27133
27165
  amountUSD,
27134
27166
  source,
@@ -28324,7 +28356,7 @@ function startableRow(c) {
28324
28356
  }
28325
28357
  async function pickStartableClaim(claims, { prompt = ask, isTTY = process.stdin.isTTY } = {}) {
28326
28358
  const active = claims.listClaims({ active: true });
28327
- await syncFounderApprovals(claims, active);
28359
+ const { approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, active);
28328
28360
  const startable = claims.listClaims({ active: true }).filter((c) => c.state === "claimed");
28329
28361
  if (startable.length === 0) {
28330
28362
  console.log("No claims ready to start. Claim one first: terminalhire claim <ref>");
@@ -28352,23 +28384,24 @@ Which one? (1-${startable.length}, or q to quit) `);
28352
28384
  Nothing started \u2014 '${answer}' is not one of 1-${startable.length}.`);
28353
28385
  return null;
28354
28386
  }
28355
- return startable[n - 1].id;
28387
+ return { id: startable[n - 1].id, approvalsChecked, approvalsUnavailable };
28356
28388
  }
28357
28389
  async function cmdStart(id, flags = {}) {
28358
28390
  const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
28391
+ let approvalsChecked = false;
28392
+ let approvalsUnavailable = false;
28359
28393
  if (!id) {
28360
28394
  const picked = await pickStartableClaim(claims);
28361
28395
  if (!picked) return;
28362
- id = picked;
28396
+ ({ id, approvalsChecked, approvalsUnavailable } = picked);
28363
28397
  }
28364
28398
  let claim = claims.findClaim(id);
28365
28399
  if (!claim) {
28366
28400
  console.error(`terminalhire claim: no claim with id '${id}'.`);
28367
28401
  process.exit(1);
28368
28402
  }
28369
- let approvalsChecked = false;
28370
28403
  if (claim.approval?.state === "pending") {
28371
- ({ approvalsChecked } = await syncFounderApprovals(claims, [claim]));
28404
+ ({ approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, [claim]));
28372
28405
  claim = claims.findClaim(id);
28373
28406
  }
28374
28407
  if (claim.worktreePath) {
@@ -28395,6 +28428,10 @@ ${sanitizeText(claim.title)}`);
28395
28428
  console.log(" same way.");
28396
28429
  if (shouldStatePending(claim, approvalsChecked)) {
28397
28430
  console.log("\n Access is pending \u2014 the founder has not approved your claim yet.");
28431
+ } else if (approvalsUnavailable) {
28432
+ console.log(
28433
+ "\n Terminalhire could not check approvals right now; local state was preserved.\n The next step below still works \u2014 it asks the server directly."
28434
+ );
28398
28435
  }
28399
28436
  printNextSteps([claim]);
28400
28437
  return;
@@ -28646,10 +28683,10 @@ var CLAIM_EVENT_LABEL = {
28646
28683
  rejected: "the founder rejected"
28647
28684
  };
28648
28685
  var LINE_BREAKS = /\r\n|[\r\n\v\f\u0085\u2028\u2029]/;
28649
- var CONTROL_CHARS2 = /[\u0000-\u001F\u007F-\u009F]/g;
28686
+ var CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
28650
28687
  function terminalSafeLines(raw) {
28651
28688
  if (typeof raw !== "string" || raw === "") return [];
28652
- return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS2, ""));
28689
+ return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS3, ""));
28653
28690
  }
28654
28691
  function terminalSafeInline(raw) {
28655
28692
  return terminalSafeLines(raw).join(" ");
@@ -3617,8 +3617,24 @@ function nextPolledState(from, observed) {
3617
3617
  function nowISO2() {
3618
3618
  return (/* @__PURE__ */ new Date()).toISOString();
3619
3619
  }
3620
+ function defangText(s) {
3621
+ return typeof s === "string" ? s.replace(WHITESPACE_CONTROLS2, " ").replace(CONTROL_CHARS2, "") : s;
3622
+ }
3623
+ function finiteAmount(a) {
3624
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
3625
+ if (typeof a !== "string" || a.trim() === "") return null;
3626
+ const n = Number(a);
3627
+ return Number.isFinite(n) ? n : null;
3628
+ }
3620
3629
  function normalizeClaim(c) {
3621
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
3630
+ return {
3631
+ ...c,
3632
+ kind: c.kind ?? "bounty",
3633
+ policy: c.policy ?? null,
3634
+ title: defangText(c.title),
3635
+ repoFullName: defangText(c.repoFullName),
3636
+ amountUSD: finiteAmount(c.amountUSD)
3637
+ };
3622
3638
  }
3623
3639
  function readClaims() {
3624
3640
  try {
@@ -3740,7 +3756,7 @@ function acceptedPRRate(claims = readClaims()) {
3740
3756
  const merged = claims.filter((c) => c.state === "merged").length;
3741
3757
  return { merged, total, rate: total === 0 ? 0 : merged / total };
3742
3758
  }
3743
- 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;
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;
3744
3760
  var init_claims = __esm({
3745
3761
  "src/claims.ts"() {
3746
3762
  "use strict";
@@ -3796,6 +3812,8 @@ var init_claims = __esm({
3796
3812
  ]),
3797
3813
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
3798
3814
  };
3815
+ WHITESPACE_CONTROLS2 = /[\t\n\v\f\r]+/g;
3816
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
3799
3817
  }
3800
3818
  });
3801
3819
 
@@ -3879,10 +3897,11 @@ function isContributeEnabled() {
3879
3897
  init_state_dir();
3880
3898
 
3881
3899
  // bin/sanitize.js
3900
+ var WHITESPACE_CONTROLS = /[\t\n\v\f\r]+/g;
3882
3901
  var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
3883
3902
  function sanitizeText(s) {
3884
3903
  if (s == null) return "";
3885
- return String(s).replace(CONTROL_CHARS, "");
3904
+ return String(s).replace(WHITESPACE_CONTROLS, " ").replace(CONTROL_CHARS, "");
3886
3905
  }
3887
3906
  function safeHttpUrl(url) {
3888
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;