terminalhire 0.41.1 → 0.41.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.
@@ -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(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, CONTROL_CHARS;
293
309
  var init_claims = __esm({
294
310
  "src/claims.ts"() {
295
311
  "use strict";
@@ -345,6 +361,7 @@ var init_claims = __esm({
345
361
  ]),
346
362
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
347
363
  };
364
+ CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
348
365
  }
349
366
  });
350
367
 
@@ -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(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, CONTROL_CHARS2;
11465
11481
  var init_claims = __esm({
11466
11482
  "src/claims.ts"() {
11467
11483
  "use strict";
@@ -11517,6 +11533,7 @@ var init_claims = __esm({
11517
11533
  ]),
11518
11534
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
11519
11535
  };
11536
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
11520
11537
  }
11521
11538
  });
11522
11539
 
@@ -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(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, CONTROL_CHARS2;
10765
10781
  var init_claims = __esm({
10766
10782
  "src/claims.ts"() {
10767
10783
  "use strict";
@@ -10817,6 +10833,7 @@ var init_claims = __esm({
10817
10833
  ]),
10818
10834
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
10819
10835
  };
10836
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
10820
10837
  }
10821
10838
  });
10822
10839
 
@@ -26986,7 +27003,10 @@ async function pollPR(prUrl) {
26986
27003
  }
26987
27004
  }
26988
27005
  function fmtAmount(a) {
26989
- return a != null ? "$" + a.toLocaleString() : "$\u2014";
27006
+ if (a == null) return "$\u2014";
27007
+ if (typeof a === "string" && a.trim() === "") return "$\u2014";
27008
+ const n = typeof a === "number" ? a : Number(a);
27009
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
26990
27010
  }
26991
27011
  function fmtClaimAmount(c) {
26992
27012
  return c.kind === "contribution" ? "contribution" : fmtAmount(c.amountUSD);
@@ -28324,7 +28344,7 @@ function startableRow(c) {
28324
28344
  }
28325
28345
  async function pickStartableClaim(claims, { prompt = ask, isTTY = process.stdin.isTTY } = {}) {
28326
28346
  const active = claims.listClaims({ active: true });
28327
- await syncFounderApprovals(claims, active);
28347
+ const { approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, active);
28328
28348
  const startable = claims.listClaims({ active: true }).filter((c) => c.state === "claimed");
28329
28349
  if (startable.length === 0) {
28330
28350
  console.log("No claims ready to start. Claim one first: terminalhire claim <ref>");
@@ -28352,23 +28372,24 @@ Which one? (1-${startable.length}, or q to quit) `);
28352
28372
  Nothing started \u2014 '${answer}' is not one of 1-${startable.length}.`);
28353
28373
  return null;
28354
28374
  }
28355
- return startable[n - 1].id;
28375
+ return { id: startable[n - 1].id, approvalsChecked, approvalsUnavailable };
28356
28376
  }
28357
28377
  async function cmdStart(id, flags = {}) {
28358
28378
  const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
28379
+ let approvalsChecked = false;
28380
+ let approvalsUnavailable = false;
28359
28381
  if (!id) {
28360
28382
  const picked = await pickStartableClaim(claims);
28361
28383
  if (!picked) return;
28362
- id = picked;
28384
+ ({ id, approvalsChecked, approvalsUnavailable } = picked);
28363
28385
  }
28364
28386
  let claim = claims.findClaim(id);
28365
28387
  if (!claim) {
28366
28388
  console.error(`terminalhire claim: no claim with id '${id}'.`);
28367
28389
  process.exit(1);
28368
28390
  }
28369
- let approvalsChecked = false;
28370
- if (claim.approval?.state === "pending") {
28371
- ({ approvalsChecked } = await syncFounderApprovals(claims, [claim]));
28391
+ if (claim.approval?.state === "pending" && !approvalsChecked) {
28392
+ ({ approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, [claim]));
28372
28393
  claim = claims.findClaim(id);
28373
28394
  }
28374
28395
  if (claim.worktreePath) {
@@ -28395,6 +28416,10 @@ ${sanitizeText(claim.title)}`);
28395
28416
  console.log(" same way.");
28396
28417
  if (shouldStatePending(claim, approvalsChecked)) {
28397
28418
  console.log("\n Access is pending \u2014 the founder has not approved your claim yet.");
28419
+ } else if (approvalsUnavailable) {
28420
+ console.log(
28421
+ "\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."
28422
+ );
28398
28423
  }
28399
28424
  printNextSteps([claim]);
28400
28425
  return;
@@ -28646,10 +28671,10 @@ var CLAIM_EVENT_LABEL = {
28646
28671
  rejected: "the founder rejected"
28647
28672
  };
28648
28673
  var LINE_BREAKS = /\r\n|[\r\n\v\f\u0085\u2028\u2029]/;
28649
- var CONTROL_CHARS2 = /[\u0000-\u001F\u007F-\u009F]/g;
28674
+ var CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
28650
28675
  function terminalSafeLines(raw) {
28651
28676
  if (typeof raw !== "string" || raw === "") return [];
28652
- return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS2, ""));
28677
+ return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS3, ""));
28653
28678
  }
28654
28679
  function terminalSafeInline(raw) {
28655
28680
  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(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, CONTROL_CHARS2;
3744
3760
  var init_claims = __esm({
3745
3761
  "src/claims.ts"() {
3746
3762
  "use strict";
@@ -3796,6 +3812,7 @@ var init_claims = __esm({
3796
3812
  ]),
3797
3813
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
3798
3814
  };
3815
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
3799
3816
  }
3800
3817
  });
3801
3818
 
@@ -15181,8 +15181,24 @@ function nextPolledState(from, observed) {
15181
15181
  function nowISO2() {
15182
15182
  return (/* @__PURE__ */ new Date()).toISOString();
15183
15183
  }
15184
+ function defangText(s) {
15185
+ return typeof s === "string" ? s.replace(CONTROL_CHARS2, "") : s;
15186
+ }
15187
+ function finiteAmount(a) {
15188
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
15189
+ if (typeof a !== "string" || a.trim() === "") return null;
15190
+ const n = Number(a);
15191
+ return Number.isFinite(n) ? n : null;
15192
+ }
15184
15193
  function normalizeClaim(c) {
15185
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
15194
+ return {
15195
+ ...c,
15196
+ kind: c.kind ?? "bounty",
15197
+ policy: c.policy ?? null,
15198
+ title: defangText(c.title),
15199
+ repoFullName: defangText(c.repoFullName),
15200
+ amountUSD: finiteAmount(c.amountUSD)
15201
+ };
15186
15202
  }
15187
15203
  function readClaims() {
15188
15204
  try {
@@ -15304,7 +15320,7 @@ function acceptedPRRate(claims = readClaims()) {
15304
15320
  const merged = claims.filter((c) => c.state === "merged").length;
15305
15321
  return { merged, total, rate: total === 0 ? 0 : merged / total };
15306
15322
  }
15307
- var TERMINALHIRE_DIR11, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS2, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS;
15323
+ var TERMINALHIRE_DIR11, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS2, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS2;
15308
15324
  var init_claims = __esm({
15309
15325
  "src/claims.ts"() {
15310
15326
  "use strict";
@@ -15360,6 +15376,7 @@ var init_claims = __esm({
15360
15376
  ]),
15361
15377
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
15362
15378
  };
15379
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
15363
15380
  }
15364
15381
  });
15365
15382
 
@@ -31585,7 +31602,10 @@ async function pollPR(prUrl) {
31585
31602
  }
31586
31603
  }
31587
31604
  function fmtAmount(a) {
31588
- return a != null ? "$" + a.toLocaleString() : "$\u2014";
31605
+ if (a == null) return "$\u2014";
31606
+ if (typeof a === "string" && a.trim() === "") return "$\u2014";
31607
+ const n = typeof a === "number" ? a : Number(a);
31608
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
31589
31609
  }
31590
31610
  function fmtClaimAmount(c) {
31591
31611
  return c.kind === "contribution" ? "contribution" : fmtAmount(c.amountUSD);
@@ -32902,7 +32922,7 @@ function startableRow(c) {
32902
32922
  }
32903
32923
  async function pickStartableClaim(claims, { prompt: prompt5 = ask, isTTY = process.stdin.isTTY } = {}) {
32904
32924
  const active = claims.listClaims({ active: true });
32905
- await syncFounderApprovals(claims, active);
32925
+ const { approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, active);
32906
32926
  const startable = claims.listClaims({ active: true }).filter((c) => c.state === "claimed");
32907
32927
  if (startable.length === 0) {
32908
32928
  console.log("No claims ready to start. Claim one first: terminalhire claim <ref>");
@@ -32930,23 +32950,24 @@ Which one? (1-${startable.length}, or q to quit) `);
32930
32950
  Nothing started \u2014 '${answer}' is not one of 1-${startable.length}.`);
32931
32951
  return null;
32932
32952
  }
32933
- return startable[n - 1].id;
32953
+ return { id: startable[n - 1].id, approvalsChecked, approvalsUnavailable };
32934
32954
  }
32935
32955
  async function cmdStart(id, flags = {}) {
32936
32956
  const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
32957
+ let approvalsChecked = false;
32958
+ let approvalsUnavailable = false;
32937
32959
  if (!id) {
32938
32960
  const picked = await pickStartableClaim(claims);
32939
32961
  if (!picked) return;
32940
- id = picked;
32962
+ ({ id, approvalsChecked, approvalsUnavailable } = picked);
32941
32963
  }
32942
32964
  let claim = claims.findClaim(id);
32943
32965
  if (!claim) {
32944
32966
  console.error(`terminalhire claim: no claim with id '${id}'.`);
32945
32967
  process.exit(1);
32946
32968
  }
32947
- let approvalsChecked = false;
32948
- if (claim.approval?.state === "pending") {
32949
- ({ approvalsChecked } = await syncFounderApprovals(claims, [claim]));
32969
+ if (claim.approval?.state === "pending" && !approvalsChecked) {
32970
+ ({ approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, [claim]));
32950
32971
  claim = claims.findClaim(id);
32951
32972
  }
32952
32973
  if (claim.worktreePath) {
@@ -32973,6 +32994,10 @@ ${sanitizeText(claim.title)}`);
32973
32994
  console.log(" same way.");
32974
32995
  if (shouldStatePending(claim, approvalsChecked)) {
32975
32996
  console.log("\n Access is pending \u2014 the founder has not approved your claim yet.");
32997
+ } else if (approvalsUnavailable) {
32998
+ console.log(
32999
+ "\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."
33000
+ );
32976
33001
  }
32977
33002
  printNextSteps([claim]);
32978
33003
  return;
@@ -33212,7 +33237,7 @@ function renderRunView(run32, message) {
33212
33237
  }
33213
33238
  function terminalSafeLines(raw) {
33214
33239
  if (typeof raw !== "string" || raw === "") return [];
33215
- return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS2, ""));
33240
+ return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS3, ""));
33216
33241
  }
33217
33242
  function terminalSafeInline(raw) {
33218
33243
  return terminalSafeLines(raw).join(" ");
@@ -34616,7 +34641,7 @@ async function run7() {
34616
34641
  process.exit(1);
34617
34642
  }
34618
34643
  }
34619
- var TERMINALHIRE_DIR17, INDEX_CACHE_FILE5, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL6, CLAIM_SYNC_BASE3, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, GH_API3, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS2;
34644
+ var TERMINALHIRE_DIR17, INDEX_CACHE_FILE5, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL6, CLAIM_SYNC_BASE3, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, GH_API3, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3;
34620
34645
  var init_jpi_claim = __esm({
34621
34646
  "bin/jpi-claim.js"() {
34622
34647
  "use strict";
@@ -34685,7 +34710,7 @@ var init_jpi_claim = __esm({
34685
34710
  rejected: "the founder rejected"
34686
34711
  };
34687
34712
  LINE_BREAKS = /\r\n|[\r\n\v\f\u0085\u2028\u2029]/;
34688
- CONTROL_CHARS2 = /[\u0000-\u001F\u007F-\u009F]/g;
34713
+ CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
34689
34714
  }
34690
34715
  });
34691
34716
 
@@ -538,8 +538,24 @@ function nextPolledState(from, observed) {
538
538
  function nowISO() {
539
539
  return (/* @__PURE__ */ new Date()).toISOString();
540
540
  }
541
+ function defangText(s) {
542
+ return typeof s === "string" ? s.replace(CONTROL_CHARS, "") : s;
543
+ }
544
+ function finiteAmount(a) {
545
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
546
+ if (typeof a !== "string" || a.trim() === "") return null;
547
+ const n = Number(a);
548
+ return Number.isFinite(n) ? n : null;
549
+ }
541
550
  function normalizeClaim(c) {
542
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
551
+ return {
552
+ ...c,
553
+ kind: c.kind ?? "bounty",
554
+ policy: c.policy ?? null,
555
+ title: defangText(c.title),
556
+ repoFullName: defangText(c.repoFullName),
557
+ amountUSD: finiteAmount(c.amountUSD)
558
+ };
543
559
  }
544
560
  function readClaims() {
545
561
  try {
@@ -661,7 +677,7 @@ function acceptedPRRate(claims = readClaims()) {
661
677
  const merged = claims.filter((c) => c.state === "merged").length;
662
678
  return { merged, total, rate: total === 0 ? 0 : merged / total };
663
679
  }
664
- var TERMINALHIRE_DIR, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS;
680
+ var TERMINALHIRE_DIR, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS;
665
681
  var init_claims = __esm({
666
682
  "src/claims.ts"() {
667
683
  "use strict";
@@ -717,6 +733,7 @@ var init_claims = __esm({
717
733
  ]),
718
734
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
719
735
  };
736
+ CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
720
737
  }
721
738
  });
722
739
 
@@ -11140,8 +11140,24 @@ function nextPolledState(from, observed) {
11140
11140
  function nowISO() {
11141
11141
  return (/* @__PURE__ */ new Date()).toISOString();
11142
11142
  }
11143
+ function defangText(s) {
11144
+ return typeof s === "string" ? s.replace(CONTROL_CHARS2, "") : s;
11145
+ }
11146
+ function finiteAmount(a) {
11147
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
11148
+ if (typeof a !== "string" || a.trim() === "") return null;
11149
+ const n = Number(a);
11150
+ return Number.isFinite(n) ? n : null;
11151
+ }
11143
11152
  function normalizeClaim(c) {
11144
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
11153
+ return {
11154
+ ...c,
11155
+ kind: c.kind ?? "bounty",
11156
+ policy: c.policy ?? null,
11157
+ title: defangText(c.title),
11158
+ repoFullName: defangText(c.repoFullName),
11159
+ amountUSD: finiteAmount(c.amountUSD)
11160
+ };
11145
11161
  }
11146
11162
  function readClaims() {
11147
11163
  try {
@@ -11263,7 +11279,7 @@ function acceptedPRRate(claims = readClaims()) {
11263
11279
  const merged = claims.filter((c) => c.state === "merged").length;
11264
11280
  return { merged, total, rate: total === 0 ? 0 : merged / total };
11265
11281
  }
11266
- 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;
11282
+ 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;
11267
11283
  var init_claims = __esm({
11268
11284
  "src/claims.ts"() {
11269
11285
  "use strict";
@@ -11319,6 +11335,7 @@ var init_claims = __esm({
11319
11335
  ]),
11320
11336
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
11321
11337
  };
11338
+ CONTROL_CHARS2 = /[\x00-\x1f\x7f-\x9f]/g;
11322
11339
  }
11323
11340
  });
11324
11341
 
@@ -27063,7 +27080,10 @@ async function pollPR(prUrl) {
27063
27080
  }
27064
27081
  }
27065
27082
  function fmtAmount(a) {
27066
- return a != null ? "$" + a.toLocaleString() : "$\u2014";
27083
+ if (a == null) return "$\u2014";
27084
+ if (typeof a === "string" && a.trim() === "") return "$\u2014";
27085
+ const n = typeof a === "number" ? a : Number(a);
27086
+ return Number.isFinite(n) ? "$" + n.toLocaleString() : "$\u2014";
27067
27087
  }
27068
27088
  function fmtClaimAmount(c) {
27069
27089
  return c.kind === "contribution" ? "contribution" : fmtAmount(c.amountUSD);
@@ -28380,7 +28400,7 @@ function startableRow(c) {
28380
28400
  }
28381
28401
  async function pickStartableClaim(claims, { prompt = ask, isTTY = process.stdin.isTTY } = {}) {
28382
28402
  const active = claims.listClaims({ active: true });
28383
- await syncFounderApprovals(claims, active);
28403
+ const { approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, active);
28384
28404
  const startable = claims.listClaims({ active: true }).filter((c) => c.state === "claimed");
28385
28405
  if (startable.length === 0) {
28386
28406
  console.log("No claims ready to start. Claim one first: terminalhire claim <ref>");
@@ -28408,23 +28428,24 @@ Which one? (1-${startable.length}, or q to quit) `);
28408
28428
  Nothing started \u2014 '${answer}' is not one of 1-${startable.length}.`);
28409
28429
  return null;
28410
28430
  }
28411
- return startable[n - 1].id;
28431
+ return { id: startable[n - 1].id, approvalsChecked, approvalsUnavailable };
28412
28432
  }
28413
28433
  async function cmdStart(id, flags = {}) {
28414
28434
  const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
28435
+ let approvalsChecked = false;
28436
+ let approvalsUnavailable = false;
28415
28437
  if (!id) {
28416
28438
  const picked = await pickStartableClaim(claims);
28417
28439
  if (!picked) return;
28418
- id = picked;
28440
+ ({ id, approvalsChecked, approvalsUnavailable } = picked);
28419
28441
  }
28420
28442
  let claim = claims.findClaim(id);
28421
28443
  if (!claim) {
28422
28444
  console.error(`terminalhire claim: no claim with id '${id}'.`);
28423
28445
  process.exit(1);
28424
28446
  }
28425
- let approvalsChecked = false;
28426
- if (claim.approval?.state === "pending") {
28427
- ({ approvalsChecked } = await syncFounderApprovals(claims, [claim]));
28447
+ if (claim.approval?.state === "pending" && !approvalsChecked) {
28448
+ ({ approvalsChecked, approvalsUnavailable } = await syncFounderApprovals(claims, [claim]));
28428
28449
  claim = claims.findClaim(id);
28429
28450
  }
28430
28451
  if (claim.worktreePath) {
@@ -28451,6 +28472,10 @@ ${sanitizeText(claim.title)}`);
28451
28472
  console.log(" same way.");
28452
28473
  if (shouldStatePending(claim, approvalsChecked)) {
28453
28474
  console.log("\n Access is pending \u2014 the founder has not approved your claim yet.");
28475
+ } else if (approvalsUnavailable) {
28476
+ console.log(
28477
+ "\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."
28478
+ );
28454
28479
  }
28455
28480
  printNextSteps([claim]);
28456
28481
  return;
@@ -28690,7 +28715,7 @@ function renderRunView(run3, message) {
28690
28715
  }
28691
28716
  function terminalSafeLines(raw) {
28692
28717
  if (typeof raw !== "string" || raw === "") return [];
28693
- return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS2, ""));
28718
+ return raw.split(LINE_BREAKS).map((l) => l.replace(CONTROL_CHARS3, ""));
28694
28719
  }
28695
28720
  function terminalSafeInline(raw) {
28696
28721
  return terminalSafeLines(raw).join(" ");
@@ -30094,7 +30119,7 @@ async function run() {
30094
30119
  process.exit(1);
30095
30120
  }
30096
30121
  }
30097
- var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE2, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, GH_API2, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS2;
30122
+ var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE2, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, GH_API2, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3;
30098
30123
  var init_jpi_claim = __esm({
30099
30124
  "bin/jpi-claim.js"() {
30100
30125
  "use strict";
@@ -30163,7 +30188,7 @@ var init_jpi_claim = __esm({
30163
30188
  rejected: "the founder rejected"
30164
30189
  };
30165
30190
  LINE_BREAKS = /\r\n|[\r\n\v\f\u0085\u2028\u2029]/;
30166
- CONTROL_CHARS2 = /[\u0000-\u001F\u007F-\u009F]/g;
30191
+ CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
30167
30192
  }
30168
30193
  });
30169
30194
 
@@ -12562,8 +12562,24 @@ function nextPolledState(from, observed) {
12562
12562
  function nowISO() {
12563
12563
  return (/* @__PURE__ */ new Date()).toISOString();
12564
12564
  }
12565
+ function defangText(s) {
12566
+ return typeof s === "string" ? s.replace(CONTROL_CHARS, "") : s;
12567
+ }
12568
+ function finiteAmount(a) {
12569
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
12570
+ if (typeof a !== "string" || a.trim() === "") return null;
12571
+ const n = Number(a);
12572
+ return Number.isFinite(n) ? n : null;
12573
+ }
12565
12574
  function normalizeClaim(c) {
12566
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
12575
+ return {
12576
+ ...c,
12577
+ kind: c.kind ?? "bounty",
12578
+ policy: c.policy ?? null,
12579
+ title: defangText(c.title),
12580
+ repoFullName: defangText(c.repoFullName),
12581
+ amountUSD: finiteAmount(c.amountUSD)
12582
+ };
12567
12583
  }
12568
12584
  function readClaims() {
12569
12585
  try {
@@ -12685,7 +12701,7 @@ function acceptedPRRate(claims = readClaims()) {
12685
12701
  const merged = claims.filter((c) => c.state === "merged").length;
12686
12702
  return { merged, total, rate: total === 0 ? 0 : merged / total };
12687
12703
  }
12688
- var TERMINALHIRE_DIR8, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS2, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS;
12704
+ var TERMINALHIRE_DIR8, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS2, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS;
12689
12705
  var init_claims = __esm({
12690
12706
  "src/claims.ts"() {
12691
12707
  "use strict";
@@ -12741,6 +12757,7 @@ var init_claims = __esm({
12741
12757
  ]),
12742
12758
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
12743
12759
  };
12760
+ CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
12744
12761
  }
12745
12762
  });
12746
12763
 
@@ -1909,8 +1909,24 @@ function nextPolledState(from, observed) {
1909
1909
  function nowISO2() {
1910
1910
  return (/* @__PURE__ */ new Date()).toISOString();
1911
1911
  }
1912
+ function defangText(s) {
1913
+ return typeof s === "string" ? s.replace(CONTROL_CHARS, "") : s;
1914
+ }
1915
+ function finiteAmount(a) {
1916
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
1917
+ if (typeof a !== "string" || a.trim() === "") return null;
1918
+ const n = Number(a);
1919
+ return Number.isFinite(n) ? n : null;
1920
+ }
1912
1921
  function normalizeClaim(c) {
1913
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
1922
+ return {
1923
+ ...c,
1924
+ kind: c.kind ?? "bounty",
1925
+ policy: c.policy ?? null,
1926
+ title: defangText(c.title),
1927
+ repoFullName: defangText(c.repoFullName),
1928
+ amountUSD: finiteAmount(c.amountUSD)
1929
+ };
1914
1930
  }
1915
1931
  function readClaims() {
1916
1932
  try {
@@ -2032,7 +2048,7 @@ function acceptedPRRate(claims = readClaims()) {
2032
2048
  const merged = claims.filter((c) => c.state === "merged").length;
2033
2049
  return { merged, total, rate: total === 0 ? 0 : merged / total };
2034
2050
  }
2035
- var TERMINALHIRE_DIR4, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS;
2051
+ var TERMINALHIRE_DIR4, CLAIMS_FILE, LOCK_DIR, LOCK_STALE_MS, LOCK_RETRY_MS, LOCK_TIMEOUT_MS, CLAIM_STATES, PUSHED_CLAIM_FIELDS, TERMINAL_STATES, POLL_TRANSITIONS, CONTROL_CHARS;
2036
2052
  var init_claims = __esm({
2037
2053
  "src/claims.ts"() {
2038
2054
  "use strict";
@@ -2088,6 +2104,7 @@ var init_claims = __esm({
2088
2104
  ]),
2089
2105
  submitted: /* @__PURE__ */ new Set(["claimed", "working", "in-review", "ready"])
2090
2106
  };
2107
+ CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
2091
2108
  }
2092
2109
  });
2093
2110
 
@@ -161,8 +161,25 @@ function nextPolledState(from, observed) {
161
161
  function nowISO() {
162
162
  return (/* @__PURE__ */ new Date()).toISOString();
163
163
  }
164
+ var CONTROL_CHARS = /[\x00-\x1f\x7f-\x9f]/g;
165
+ function defangText(s) {
166
+ return typeof s === "string" ? s.replace(CONTROL_CHARS, "") : s;
167
+ }
168
+ function finiteAmount(a) {
169
+ if (typeof a === "number") return Number.isFinite(a) ? a : null;
170
+ if (typeof a !== "string" || a.trim() === "") return null;
171
+ const n = Number(a);
172
+ return Number.isFinite(n) ? n : null;
173
+ }
164
174
  function normalizeClaim(c) {
165
- return { ...c, kind: c.kind ?? "bounty", policy: c.policy ?? null };
175
+ return {
176
+ ...c,
177
+ kind: c.kind ?? "bounty",
178
+ policy: c.policy ?? null,
179
+ title: defangText(c.title),
180
+ repoFullName: defangText(c.repoFullName),
181
+ amountUSD: finiteAmount(c.amountUSD)
182
+ };
166
183
  }
167
184
  function readClaims() {
168
185
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminalhire",
3
- "version": "0.41.1",
3
+ "version": "0.41.2",
4
4
  "description": "Local-first job matching for developers — ambient job matches in the Claude Code spinner. Your profile never leaves your machine.",
5
5
  "repository": {
6
6
  "type": "git",