terminalhire 0.41.2 → 0.42.1

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.
@@ -11184,6 +11184,83 @@ var init_github_auth = __esm({
11184
11184
  }
11185
11185
  });
11186
11186
 
11187
+ // bin/founder-note-sync.js
11188
+ var founder_note_sync_exports = {};
11189
+ __export(founder_note_sync_exports, {
11190
+ acknowledgeFounderNotes: () => acknowledgeFounderNotes,
11191
+ computeFounderNotes: () => computeFounderNotes,
11192
+ fetchFounderNotes: () => fetchFounderNotes,
11193
+ formatNote: () => formatNote,
11194
+ noteKey: () => noteKey,
11195
+ syncFounderNotes: () => syncFounderNotes
11196
+ });
11197
+ async function fetchFounderNotes(pushToken, fetchImpl = fetch) {
11198
+ if (typeof pushToken !== "string" || pushToken.length === 0) return null;
11199
+ try {
11200
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE2}/api/claim/notes`, {
11201
+ method: "POST",
11202
+ headers: { "Content-Type": "application/json" },
11203
+ body: JSON.stringify({ pushToken }),
11204
+ signal: AbortSignal.timeout(15e3)
11205
+ });
11206
+ if (!res?.ok) return null;
11207
+ const body = await res.json();
11208
+ if (!body || !Array.isArray(body.notes)) return null;
11209
+ const notes = body.notes.filter(
11210
+ (n) => n && typeof n.claimId === "string" && n.claimId !== "" && typeof n.note === "string" && n.note !== "" && typeof n.at === "string" && (n.kind === "founder_note" || n.kind === "feedback")
11211
+ );
11212
+ return { notes, latestAt: typeof body.latestAt === "string" ? body.latestAt : null };
11213
+ } catch {
11214
+ return null;
11215
+ }
11216
+ }
11217
+ function noteKey(note) {
11218
+ return `${note.claimId}@${note.at}`;
11219
+ }
11220
+ function computeFounderNotes(notes, previous) {
11221
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
11222
+ const prior = previous && Array.isArray(previous.seen) ? new Set(previous.seen) : /* @__PURE__ */ new Set();
11223
+ const seen = keys.filter((k) => prior.has(k));
11224
+ return { count: keys.length - seen.length, seen };
11225
+ }
11226
+ function acknowledgeFounderNotes(notes) {
11227
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
11228
+ return { count: 0, seen: keys };
11229
+ }
11230
+ async function syncFounderNotes({
11231
+ readAutoMarker: readAutoMarker2,
11232
+ readPushTokenEnc: readPushTokenEnc2,
11233
+ readPrevious,
11234
+ fetchImpl = fetch,
11235
+ timeoutMs = 15e3
11236
+ } = {}) {
11237
+ try {
11238
+ const marker = readAutoMarker2();
11239
+ const token = await readPushTokenEnc2();
11240
+ if (!marker || !token) return null;
11241
+ const answer = await fetchFounderNotes(
11242
+ token,
11243
+ (url, init) => fetchImpl(url, { ...init, signal: AbortSignal.timeout(timeoutMs) })
11244
+ );
11245
+ if (!answer) return null;
11246
+ return computeFounderNotes(answer.notes, readPrevious());
11247
+ } catch {
11248
+ return null;
11249
+ }
11250
+ }
11251
+ function formatNote(note) {
11252
+ const label = note.kind === "feedback" ? "changes requested" : "note";
11253
+ return ` ${note.at.slice(0, 16).replace("T", " ")} [${label}] ${note.claimId}
11254
+ ${note.note.split("\n").join("\n ")}`;
11255
+ }
11256
+ var CLAIM_SYNC_BASE2;
11257
+ var init_founder_note_sync = __esm({
11258
+ "bin/founder-note-sync.js"() {
11259
+ "use strict";
11260
+ CLAIM_SYNC_BASE2 = "https://terminalhire.com";
11261
+ }
11262
+ });
11263
+
11187
11264
  // ../../packages/core/src/policy-audit.ts
11188
11265
  function fence(nonce, body) {
11189
11266
  return `<<<UNTRUSTED-${nonce}
@@ -26339,6 +26416,7 @@ async function syncFounderVerdicts({
26339
26416
  }
26340
26417
 
26341
26418
  // bin/jpi-claim.js
26419
+ init_founder_note_sync();
26342
26420
  var TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join17(homedir11(), ".terminalhire");
26343
26421
  var INDEX_CACHE_FILE2 = join17(TERMINALHIRE_DIR11, "index-cache.json");
26344
26422
  var CLAIM_PUSH_MARKER = join17(TERMINALHIRE_DIR11, "claim-push.json");
@@ -26361,7 +26439,7 @@ function markClaimNudged(id) {
26361
26439
  }
26362
26440
  }
26363
26441
  var API_URL = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
26364
- var CLAIM_SYNC_BASE2 = "https://terminalhire.com";
26442
+ var CLAIM_SYNC_BASE3 = "https://terminalhire.com";
26365
26443
  var CLAIM_CONSENT_VERSION = 1;
26366
26444
  var CLAIM_POLL_INTERVAL_MS = 2e3;
26367
26445
  var CLAIM_POLL_TIMEOUT_MS = 10 * 60 * 1e3;
@@ -27199,7 +27277,7 @@ async function mintRegistrationProof() {
27199
27277
  console.log(" GitHub identity has to be verified once in the browser.");
27200
27278
  let begin;
27201
27279
  try {
27202
- const r = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync/begin`, {
27280
+ const r = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync/begin`, {
27203
27281
  method: "POST",
27204
27282
  headers: { "Content-Type": "application/json" },
27205
27283
  body: JSON.stringify({ hostname: osHostname() }),
@@ -27232,7 +27310,7 @@ async function mintRegistrationProof() {
27232
27310
  let statusRes;
27233
27311
  try {
27234
27312
  statusRes = await fetch(
27235
- `${CLAIM_SYNC_BASE2}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
27313
+ `${CLAIM_SYNC_BASE3}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
27236
27314
  { signal: AbortSignal.timeout(1e4) }
27237
27315
  );
27238
27316
  } catch {
@@ -27359,7 +27437,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
27359
27437
  };
27360
27438
  if (!auth) await acquireProofAuth();
27361
27439
  console.log("\n Registering this claim with terminalhire (founder posting)...");
27362
- const sendRegistration = async (includeExpectation) => fetch(`${CLAIM_SYNC_BASE2}/api/claim/register`, {
27440
+ const sendRegistration = async (includeExpectation) => fetch(`${CLAIM_SYNC_BASE3}/api/claim/register`, {
27363
27441
  method: "POST",
27364
27442
  headers: { "Content-Type": "application/json" },
27365
27443
  body: JSON.stringify({
@@ -27939,7 +28017,7 @@ async function resolveIssueOutcome(c, res, claims) {
27939
28017
  async function fetchFounderApprovals(pushToken, fetchImpl = fetch) {
27940
28018
  if (typeof pushToken !== "string" || pushToken.length === 0) return null;
27941
28019
  try {
27942
- const res = await fetchImpl(`${CLAIM_SYNC_BASE2}/api/claim/approvals`, {
28020
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE3}/api/claim/approvals`, {
27943
28021
  method: "POST",
27944
28022
  headers: { "Content-Type": "application/json" },
27945
28023
  body: JSON.stringify({ pushToken }),
@@ -28798,7 +28876,7 @@ async function cmdSlice(id, flags = {}) {
28798
28876
  const pushToken = await requireReadPushToken("fetching your granted slice");
28799
28877
  let res;
28800
28878
  try {
28801
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/claim/slice`, {
28879
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim/slice`, {
28802
28880
  method: "POST",
28803
28881
  headers: { "Content-Type": "application/json" },
28804
28882
  body: JSON.stringify({
@@ -28906,7 +28984,7 @@ async function cmdRuns(id, flags = {}) {
28906
28984
  const fetchOnce = async () => {
28907
28985
  let res;
28908
28986
  try {
28909
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/patch/runs`, {
28987
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/patch/runs`, {
28910
28988
  method: "POST",
28911
28989
  headers: { "Content-Type": "application/json" },
28912
28990
  body: JSON.stringify({
@@ -29054,7 +29132,7 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
29054
29132
  console.log("\n Submitting the patch through terminalhire...");
29055
29133
  let res;
29056
29134
  try {
29057
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/patch`, {
29135
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/patch`, {
29058
29136
  method: "POST",
29059
29137
  headers: { "Content-Type": "application/json" },
29060
29138
  body: JSON.stringify(submission),
@@ -29627,7 +29705,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
29627
29705
  console.log("\n Starting browser verification...");
29628
29706
  let begin;
29629
29707
  try {
29630
- const r = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync/begin`, {
29708
+ const r = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync/begin`, {
29631
29709
  method: "POST",
29632
29710
  headers: { "Content-Type": "application/json" },
29633
29711
  body: JSON.stringify({ hostname: osHostname() }),
@@ -29670,7 +29748,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
29670
29748
  let statusRes;
29671
29749
  try {
29672
29750
  statusRes = await fetch(
29673
- `${CLAIM_SYNC_BASE2}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
29751
+ `${CLAIM_SYNC_BASE3}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
29674
29752
  { signal: AbortSignal.timeout(1e4) }
29675
29753
  );
29676
29754
  } catch {
@@ -29701,7 +29779,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
29701
29779
  console.log("\n Verified. Sharing your claims...");
29702
29780
  let res;
29703
29781
  try {
29704
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync`, {
29782
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync`, {
29705
29783
  method: "POST",
29706
29784
  headers: { "Content-Type": "application/json" },
29707
29785
  // autoConsent is included ONLY when the dev opted into background updates —
@@ -29828,7 +29906,7 @@ async function cmdRevoke() {
29828
29906
  console.log("\n Requesting deletion...");
29829
29907
  let res;
29830
29908
  try {
29831
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync`, {
29909
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync`, {
29832
29910
  method: "DELETE",
29833
29911
  headers: { "Content-Type": "application/json" },
29834
29912
  body: JSON.stringify({ login, deleteToken }),
@@ -30005,6 +30083,50 @@ async function cmdAudit(id, flags = {}) {
30005
30083
  }
30006
30084
  renderAudit(view);
30007
30085
  }
30086
+ async function cmdNotes(flags) {
30087
+ let pushToken = null;
30088
+ try {
30089
+ pushToken = await readPushTokenEnc();
30090
+ } catch {
30091
+ }
30092
+ if (!pushToken) {
30093
+ console.error("terminalhire claim notes: needs background push enrolment.");
30094
+ console.error(" Enrol once: terminalhire claim --push --keep-updated");
30095
+ process.exit(1);
30096
+ }
30097
+ const answer = await fetchFounderNotes(pushToken);
30098
+ if (answer === null) {
30099
+ console.error("terminalhire claim notes: could not reach terminalhire just now.");
30100
+ console.error(' This is NOT "no notes" \u2014 try again shortly.');
30101
+ process.exit(1);
30102
+ }
30103
+ if (flags.json) {
30104
+ console.log(JSON.stringify(answer, null, 2));
30105
+ await acknowledgeNotesQuietly(answer.notes);
30106
+ return;
30107
+ }
30108
+ if (answer.notes.length === 0) {
30109
+ console.log("\n No notes from founders on your claims.\n");
30110
+ await acknowledgeNotesQuietly(answer.notes);
30111
+ return;
30112
+ }
30113
+ console.log(
30114
+ `
30115
+ ${answer.notes.length} note${answer.notes.length === 1 ? "" : "s"} from founders:
30116
+ `
30117
+ );
30118
+ for (const note of answer.notes) console.log(formatNote(note));
30119
+ console.log("");
30120
+ await acknowledgeNotesQuietly(answer.notes);
30121
+ }
30122
+ async function acknowledgeNotesQuietly(notes) {
30123
+ try {
30124
+ const { acknowledgeFounderNotes: acknowledgeFounderNotes2 } = await Promise.resolve().then(() => (init_founder_note_sync(), founder_note_sync_exports));
30125
+ const { updateIndexCache: updateIndexCache2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
30126
+ updateIndexCache2({ founderNotes: acknowledgeFounderNotes2(notes) });
30127
+ } catch {
30128
+ }
30129
+ }
30008
30130
  async function run() {
30009
30131
  const verb = process.argv[2];
30010
30132
  const rawArgs = process.argv.slice(3).map((a) => a === "-y" ? "--yes" : a);
@@ -30067,9 +30189,12 @@ async function run() {
30067
30189
  case "audit":
30068
30190
  await cmdAudit(positional[0], flags);
30069
30191
  break;
30192
+ case "notes":
30193
+ await cmdNotes(flags);
30194
+ break;
30070
30195
  default:
30071
30196
  console.error(
30072
- `terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | start | attach | slice | list | status | update | submit | runs | audit | release`
30197
+ `terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | start | attach | slice | list | status | update | submit | runs | notes | audit | release`
30073
30198
  );
30074
30199
  process.exit(1);
30075
30200
  }
@@ -16786,6 +16786,83 @@ var init_founder_verdict_sync = __esm({
16786
16786
  }
16787
16787
  });
16788
16788
 
16789
+ // bin/founder-note-sync.js
16790
+ var founder_note_sync_exports = {};
16791
+ __export(founder_note_sync_exports, {
16792
+ acknowledgeFounderNotes: () => acknowledgeFounderNotes,
16793
+ computeFounderNotes: () => computeFounderNotes,
16794
+ fetchFounderNotes: () => fetchFounderNotes,
16795
+ formatNote: () => formatNote,
16796
+ noteKey: () => noteKey,
16797
+ syncFounderNotes: () => syncFounderNotes
16798
+ });
16799
+ async function fetchFounderNotes(pushToken, fetchImpl = fetch) {
16800
+ if (typeof pushToken !== "string" || pushToken.length === 0) return null;
16801
+ try {
16802
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE3}/api/claim/notes`, {
16803
+ method: "POST",
16804
+ headers: { "Content-Type": "application/json" },
16805
+ body: JSON.stringify({ pushToken }),
16806
+ signal: AbortSignal.timeout(15e3)
16807
+ });
16808
+ if (!res?.ok) return null;
16809
+ const body = await res.json();
16810
+ if (!body || !Array.isArray(body.notes)) return null;
16811
+ const notes = body.notes.filter(
16812
+ (n) => n && typeof n.claimId === "string" && n.claimId !== "" && typeof n.note === "string" && n.note !== "" && typeof n.at === "string" && (n.kind === "founder_note" || n.kind === "feedback")
16813
+ );
16814
+ return { notes, latestAt: typeof body.latestAt === "string" ? body.latestAt : null };
16815
+ } catch {
16816
+ return null;
16817
+ }
16818
+ }
16819
+ function noteKey(note) {
16820
+ return `${note.claimId}@${note.at}`;
16821
+ }
16822
+ function computeFounderNotes(notes, previous) {
16823
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
16824
+ const prior = previous && Array.isArray(previous.seen) ? new Set(previous.seen) : /* @__PURE__ */ new Set();
16825
+ const seen = keys.filter((k) => prior.has(k));
16826
+ return { count: keys.length - seen.length, seen };
16827
+ }
16828
+ function acknowledgeFounderNotes(notes) {
16829
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
16830
+ return { count: 0, seen: keys };
16831
+ }
16832
+ async function syncFounderNotes({
16833
+ readAutoMarker: readAutoMarker2,
16834
+ readPushTokenEnc: readPushTokenEnc2,
16835
+ readPrevious,
16836
+ fetchImpl = fetch,
16837
+ timeoutMs = 15e3
16838
+ } = {}) {
16839
+ try {
16840
+ const marker = readAutoMarker2();
16841
+ const token = await readPushTokenEnc2();
16842
+ if (!marker || !token) return null;
16843
+ const answer = await fetchFounderNotes(
16844
+ token,
16845
+ (url, init) => fetchImpl(url, { ...init, signal: AbortSignal.timeout(timeoutMs) })
16846
+ );
16847
+ if (!answer) return null;
16848
+ return computeFounderNotes(answer.notes, readPrevious());
16849
+ } catch {
16850
+ return null;
16851
+ }
16852
+ }
16853
+ function formatNote(note) {
16854
+ const label = note.kind === "feedback" ? "changes requested" : "note";
16855
+ return ` ${note.at.slice(0, 16).replace("T", " ")} [${label}] ${note.claimId}
16856
+ ${note.note.split("\n").join("\n ")}`;
16857
+ }
16858
+ var CLAIM_SYNC_BASE3;
16859
+ var init_founder_note_sync = __esm({
16860
+ "bin/founder-note-sync.js"() {
16861
+ "use strict";
16862
+ CLAIM_SYNC_BASE3 = "https://terminalhire.com";
16863
+ }
16864
+ });
16865
+
16789
16866
  // ../../packages/core/src/policy-audit.ts
16790
16867
  function fence(nonce, body) {
16791
16868
  return `<<<UNTRUSTED-${nonce}
@@ -31796,7 +31873,7 @@ async function mintRegistrationProof() {
31796
31873
  console.log(" GitHub identity has to be verified once in the browser.");
31797
31874
  let begin;
31798
31875
  try {
31799
- const r = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync/begin`, {
31876
+ const r = await fetch(`${CLAIM_SYNC_BASE4}/api/claim-sync/begin`, {
31800
31877
  method: "POST",
31801
31878
  headers: { "Content-Type": "application/json" },
31802
31879
  body: JSON.stringify({ hostname: osHostname() }),
@@ -31829,7 +31906,7 @@ async function mintRegistrationProof() {
31829
31906
  let statusRes;
31830
31907
  try {
31831
31908
  statusRes = await fetch(
31832
- `${CLAIM_SYNC_BASE3}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
31909
+ `${CLAIM_SYNC_BASE4}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
31833
31910
  { signal: AbortSignal.timeout(1e4) }
31834
31911
  );
31835
31912
  } catch {
@@ -31938,7 +32015,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
31938
32015
  };
31939
32016
  if (!auth) await acquireProofAuth();
31940
32017
  console.log("\n Registering this claim with terminalhire (founder posting)...");
31941
- const sendRegistration = async (includeExpectation) => fetch(`${CLAIM_SYNC_BASE3}/api/claim/register`, {
32018
+ const sendRegistration = async (includeExpectation) => fetch(`${CLAIM_SYNC_BASE4}/api/claim/register`, {
31942
32019
  method: "POST",
31943
32020
  headers: { "Content-Type": "application/json" },
31944
32021
  body: JSON.stringify({
@@ -32517,7 +32594,7 @@ async function resolveIssueOutcome(c, res, claims) {
32517
32594
  async function fetchFounderApprovals(pushToken, fetchImpl = fetch) {
32518
32595
  if (typeof pushToken !== "string" || pushToken.length === 0) return null;
32519
32596
  try {
32520
- const res = await fetchImpl(`${CLAIM_SYNC_BASE3}/api/claim/approvals`, {
32597
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE4}/api/claim/approvals`, {
32521
32598
  method: "POST",
32522
32599
  headers: { "Content-Type": "application/json" },
32523
32600
  body: JSON.stringify({ pushToken }),
@@ -33361,7 +33438,7 @@ async function cmdSlice(id, flags = {}) {
33361
33438
  const pushToken = await requireReadPushToken("fetching your granted slice");
33362
33439
  let res;
33363
33440
  try {
33364
- res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim/slice`, {
33441
+ res = await fetch(`${CLAIM_SYNC_BASE4}/api/claim/slice`, {
33365
33442
  method: "POST",
33366
33443
  headers: { "Content-Type": "application/json" },
33367
33444
  body: JSON.stringify({
@@ -33469,7 +33546,7 @@ async function cmdRuns(id, flags = {}) {
33469
33546
  const fetchOnce = async () => {
33470
33547
  let res;
33471
33548
  try {
33472
- res = await fetch(`${CLAIM_SYNC_BASE3}/api/patch/runs`, {
33549
+ res = await fetch(`${CLAIM_SYNC_BASE4}/api/patch/runs`, {
33473
33550
  method: "POST",
33474
33551
  headers: { "Content-Type": "application/json" },
33475
33552
  body: JSON.stringify({
@@ -33617,7 +33694,7 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
33617
33694
  console.log("\n Submitting the patch through terminalhire...");
33618
33695
  let res;
33619
33696
  try {
33620
- res = await fetch(`${CLAIM_SYNC_BASE3}/api/patch`, {
33697
+ res = await fetch(`${CLAIM_SYNC_BASE4}/api/patch`, {
33621
33698
  method: "POST",
33622
33699
  headers: { "Content-Type": "application/json" },
33623
33700
  body: JSON.stringify(submission),
@@ -34190,7 +34267,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
34190
34267
  console.log("\n Starting browser verification...");
34191
34268
  let begin;
34192
34269
  try {
34193
- const r = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync/begin`, {
34270
+ const r = await fetch(`${CLAIM_SYNC_BASE4}/api/claim-sync/begin`, {
34194
34271
  method: "POST",
34195
34272
  headers: { "Content-Type": "application/json" },
34196
34273
  body: JSON.stringify({ hostname: osHostname() }),
@@ -34233,7 +34310,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
34233
34310
  let statusRes;
34234
34311
  try {
34235
34312
  statusRes = await fetch(
34236
- `${CLAIM_SYNC_BASE3}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
34313
+ `${CLAIM_SYNC_BASE4}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
34237
34314
  { signal: AbortSignal.timeout(1e4) }
34238
34315
  );
34239
34316
  } catch {
@@ -34264,7 +34341,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
34264
34341
  console.log("\n Verified. Sharing your claims...");
34265
34342
  let res;
34266
34343
  try {
34267
- res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync`, {
34344
+ res = await fetch(`${CLAIM_SYNC_BASE4}/api/claim-sync`, {
34268
34345
  method: "POST",
34269
34346
  headers: { "Content-Type": "application/json" },
34270
34347
  // autoConsent is included ONLY when the dev opted into background updates —
@@ -34391,7 +34468,7 @@ async function cmdRevoke() {
34391
34468
  console.log("\n Requesting deletion...");
34392
34469
  let res;
34393
34470
  try {
34394
- res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync`, {
34471
+ res = await fetch(`${CLAIM_SYNC_BASE4}/api/claim-sync`, {
34395
34472
  method: "DELETE",
34396
34473
  headers: { "Content-Type": "application/json" },
34397
34474
  body: JSON.stringify({ login, deleteToken }),
@@ -34568,6 +34645,50 @@ async function cmdAudit(id, flags = {}) {
34568
34645
  }
34569
34646
  renderAudit(view);
34570
34647
  }
34648
+ async function cmdNotes(flags) {
34649
+ let pushToken = null;
34650
+ try {
34651
+ pushToken = await readPushTokenEnc();
34652
+ } catch {
34653
+ }
34654
+ if (!pushToken) {
34655
+ console.error("terminalhire claim notes: needs background push enrolment.");
34656
+ console.error(" Enrol once: terminalhire claim --push --keep-updated");
34657
+ process.exit(1);
34658
+ }
34659
+ const answer = await fetchFounderNotes(pushToken);
34660
+ if (answer === null) {
34661
+ console.error("terminalhire claim notes: could not reach terminalhire just now.");
34662
+ console.error(' This is NOT "no notes" \u2014 try again shortly.');
34663
+ process.exit(1);
34664
+ }
34665
+ if (flags.json) {
34666
+ console.log(JSON.stringify(answer, null, 2));
34667
+ await acknowledgeNotesQuietly(answer.notes);
34668
+ return;
34669
+ }
34670
+ if (answer.notes.length === 0) {
34671
+ console.log("\n No notes from founders on your claims.\n");
34672
+ await acknowledgeNotesQuietly(answer.notes);
34673
+ return;
34674
+ }
34675
+ console.log(
34676
+ `
34677
+ ${answer.notes.length} note${answer.notes.length === 1 ? "" : "s"} from founders:
34678
+ `
34679
+ );
34680
+ for (const note of answer.notes) console.log(formatNote(note));
34681
+ console.log("");
34682
+ await acknowledgeNotesQuietly(answer.notes);
34683
+ }
34684
+ async function acknowledgeNotesQuietly(notes) {
34685
+ try {
34686
+ const { acknowledgeFounderNotes: acknowledgeFounderNotes2 } = await Promise.resolve().then(() => (init_founder_note_sync(), founder_note_sync_exports));
34687
+ const { updateIndexCache: updateIndexCache2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
34688
+ updateIndexCache2({ founderNotes: acknowledgeFounderNotes2(notes) });
34689
+ } catch {
34690
+ }
34691
+ }
34571
34692
  async function run7() {
34572
34693
  const verb = process.argv[2];
34573
34694
  const rawArgs = process.argv.slice(3).map((a) => a === "-y" ? "--yes" : a);
@@ -34630,9 +34751,12 @@ async function run7() {
34630
34751
  case "audit":
34631
34752
  await cmdAudit(positional[0], flags);
34632
34753
  break;
34754
+ case "notes":
34755
+ await cmdNotes(flags);
34756
+ break;
34633
34757
  default:
34634
34758
  console.error(
34635
- `terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | start | attach | slice | list | status | update | submit | runs | audit | release`
34759
+ `terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | start | attach | slice | list | status | update | submit | runs | notes | audit | release`
34636
34760
  );
34637
34761
  process.exit(1);
34638
34762
  }
@@ -34641,7 +34765,7 @@ async function run7() {
34641
34765
  process.exit(1);
34642
34766
  }
34643
34767
  }
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;
34768
+ var TERMINALHIRE_DIR17, INDEX_CACHE_FILE5, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL6, CLAIM_SYNC_BASE4, 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;
34645
34769
  var init_jpi_claim = __esm({
34646
34770
  "bin/jpi-claim.js"() {
34647
34771
  "use strict";
@@ -34653,12 +34777,13 @@ var init_jpi_claim = __esm({
34653
34777
  init_state_dir();
34654
34778
  init_claim_push_bg();
34655
34779
  init_founder_verdict_sync();
34780
+ init_founder_note_sync();
34656
34781
  TERMINALHIRE_DIR17 = process.env.TERMINALHIRE_DIR || join30(homedir22(), ".terminalhire");
34657
34782
  INDEX_CACHE_FILE5 = join30(TERMINALHIRE_DIR17, "index-cache.json");
34658
34783
  CLAIM_PUSH_MARKER = join30(TERMINALHIRE_DIR17, "claim-push.json");
34659
34784
  REPO_CONTINUITY_NUDGE_MARKER = join30(TERMINALHIRE_DIR17, "repo-continuity-nudged.json");
34660
34785
  API_URL6 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
34661
- CLAIM_SYNC_BASE3 = "https://terminalhire.com";
34786
+ CLAIM_SYNC_BASE4 = "https://terminalhire.com";
34662
34787
  CLAIM_CONSENT_VERSION = 1;
34663
34788
  CLAIM_POLL_INTERVAL_MS = 2e3;
34664
34789
  CLAIM_POLL_TIMEOUT_MS = 10 * 60 * 1e3;
@@ -65551,7 +65676,7 @@ async function syncApprovedClaims({
65551
65676
  if (!approvalsSyncGate({ autoMarkerExists: !!marker, tokenFileExists: !!token }).sync) {
65552
65677
  return null;
65553
65678
  }
65554
- const res = await fetchImpl(`${CLAIM_SYNC_BASE4}/api/claim/approvals`, {
65679
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE5}/api/claim/approvals`, {
65555
65680
  method: "POST",
65556
65681
  headers: { "Content-Type": "application/json" },
65557
65682
  body: JSON.stringify({ pushToken: token }),
@@ -65566,11 +65691,11 @@ async function syncApprovedClaims({
65566
65691
  return null;
65567
65692
  }
65568
65693
  }
65569
- var CLAIM_SYNC_BASE4;
65694
+ var CLAIM_SYNC_BASE5;
65570
65695
  var init_approved_claims_sync = __esm({
65571
65696
  "bin/approved-claims-sync.js"() {
65572
65697
  "use strict";
65573
- CLAIM_SYNC_BASE4 = "https://terminalhire.com";
65698
+ CLAIM_SYNC_BASE5 = "https://terminalhire.com";
65574
65699
  }
65575
65700
  });
65576
65701
 
@@ -65931,6 +66056,18 @@ async function run28() {
65931
66056
  });
65932
66057
  } catch {
65933
66058
  }
66059
+ let founderNotes;
66060
+ try {
66061
+ const { syncFounderNotes: syncFounderNotes2 } = await Promise.resolve().then(() => (init_founder_note_sync(), founder_note_sync_exports));
66062
+ const { readAutoMarker: readAutoMarker2, readPushTokenEnc: readPushTokenEnc2 } = await Promise.resolve().then(() => (init_claim_push_bg(), claim_push_bg_exports));
66063
+ const { readCacheEntry: readCacheEntry2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
66064
+ founderNotes = await syncFounderNotes2({
66065
+ readAutoMarker: readAutoMarker2,
66066
+ readPushTokenEnc: readPushTokenEnc2,
66067
+ readPrevious: () => (readCacheEntry2() ?? {}).founderNotes
66068
+ });
66069
+ } catch {
66070
+ }
65934
66071
  const previousCache = readCacheEntry() ?? {};
65935
66072
  const effectiveFounderSurface = founderSurface ?? previousCache.founderSurface;
65936
66073
  let surfaceLead = "dev";
@@ -65952,6 +66089,7 @@ async function run28() {
65952
66089
  };
65953
66090
  if (founderPaid) cacheEntry.founderPaid = founderPaid;
65954
66091
  if (approvedClaims) cacheEntry.approvedClaims = approvedClaims;
66092
+ if (founderNotes) cacheEntry.founderNotes = founderNotes;
65955
66093
  if (founderSurface) cacheEntry.founderSurface = founderSurface;
65956
66094
  cacheEntry.indexETag = indexETag ?? "";
65957
66095
  if (pulseLatestPostedAt) {
@@ -11547,6 +11547,83 @@ var init_founder_verdict_sync = __esm({
11547
11547
  }
11548
11548
  });
11549
11549
 
11550
+ // bin/founder-note-sync.js
11551
+ var founder_note_sync_exports = {};
11552
+ __export(founder_note_sync_exports, {
11553
+ acknowledgeFounderNotes: () => acknowledgeFounderNotes,
11554
+ computeFounderNotes: () => computeFounderNotes,
11555
+ fetchFounderNotes: () => fetchFounderNotes,
11556
+ formatNote: () => formatNote,
11557
+ noteKey: () => noteKey,
11558
+ syncFounderNotes: () => syncFounderNotes
11559
+ });
11560
+ async function fetchFounderNotes(pushToken, fetchImpl = fetch) {
11561
+ if (typeof pushToken !== "string" || pushToken.length === 0) return null;
11562
+ try {
11563
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE2}/api/claim/notes`, {
11564
+ method: "POST",
11565
+ headers: { "Content-Type": "application/json" },
11566
+ body: JSON.stringify({ pushToken }),
11567
+ signal: AbortSignal.timeout(15e3)
11568
+ });
11569
+ if (!res?.ok) return null;
11570
+ const body = await res.json();
11571
+ if (!body || !Array.isArray(body.notes)) return null;
11572
+ const notes = body.notes.filter(
11573
+ (n) => n && typeof n.claimId === "string" && n.claimId !== "" && typeof n.note === "string" && n.note !== "" && typeof n.at === "string" && (n.kind === "founder_note" || n.kind === "feedback")
11574
+ );
11575
+ return { notes, latestAt: typeof body.latestAt === "string" ? body.latestAt : null };
11576
+ } catch {
11577
+ return null;
11578
+ }
11579
+ }
11580
+ function noteKey(note) {
11581
+ return `${note.claimId}@${note.at}`;
11582
+ }
11583
+ function computeFounderNotes(notes, previous) {
11584
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
11585
+ const prior = previous && Array.isArray(previous.seen) ? new Set(previous.seen) : /* @__PURE__ */ new Set();
11586
+ const seen = keys.filter((k) => prior.has(k));
11587
+ return { count: keys.length - seen.length, seen };
11588
+ }
11589
+ function acknowledgeFounderNotes(notes) {
11590
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
11591
+ return { count: 0, seen: keys };
11592
+ }
11593
+ async function syncFounderNotes({
11594
+ readAutoMarker: readAutoMarker2,
11595
+ readPushTokenEnc: readPushTokenEnc2,
11596
+ readPrevious,
11597
+ fetchImpl = fetch,
11598
+ timeoutMs = 15e3
11599
+ } = {}) {
11600
+ try {
11601
+ const marker = readAutoMarker2();
11602
+ const token = await readPushTokenEnc2();
11603
+ if (!marker || !token) return null;
11604
+ const answer = await fetchFounderNotes(
11605
+ token,
11606
+ (url, init) => fetchImpl(url, { ...init, signal: AbortSignal.timeout(timeoutMs) })
11607
+ );
11608
+ if (!answer) return null;
11609
+ return computeFounderNotes(answer.notes, readPrevious());
11610
+ } catch {
11611
+ return null;
11612
+ }
11613
+ }
11614
+ function formatNote(note) {
11615
+ const label = note.kind === "feedback" ? "changes requested" : "note";
11616
+ return ` ${note.at.slice(0, 16).replace("T", " ")} [${label}] ${note.claimId}
11617
+ ${note.note.split("\n").join("\n ")}`;
11618
+ }
11619
+ var CLAIM_SYNC_BASE2;
11620
+ var init_founder_note_sync = __esm({
11621
+ "bin/founder-note-sync.js"() {
11622
+ "use strict";
11623
+ CLAIM_SYNC_BASE2 = "https://terminalhire.com";
11624
+ }
11625
+ });
11626
+
11550
11627
  // ../../packages/core/src/policy-audit.ts
11551
11628
  function fence(nonce, body) {
11552
11629
  return `<<<UNTRUSTED-${nonce}
@@ -27274,7 +27351,7 @@ async function mintRegistrationProof() {
27274
27351
  console.log(" GitHub identity has to be verified once in the browser.");
27275
27352
  let begin;
27276
27353
  try {
27277
- const r = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync/begin`, {
27354
+ const r = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync/begin`, {
27278
27355
  method: "POST",
27279
27356
  headers: { "Content-Type": "application/json" },
27280
27357
  body: JSON.stringify({ hostname: osHostname() }),
@@ -27307,7 +27384,7 @@ async function mintRegistrationProof() {
27307
27384
  let statusRes;
27308
27385
  try {
27309
27386
  statusRes = await fetch(
27310
- `${CLAIM_SYNC_BASE2}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
27387
+ `${CLAIM_SYNC_BASE3}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
27311
27388
  { signal: AbortSignal.timeout(1e4) }
27312
27389
  );
27313
27390
  } catch {
@@ -27416,7 +27493,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
27416
27493
  };
27417
27494
  if (!auth) await acquireProofAuth();
27418
27495
  console.log("\n Registering this claim with terminalhire (founder posting)...");
27419
- const sendRegistration = async (includeExpectation) => fetch(`${CLAIM_SYNC_BASE2}/api/claim/register`, {
27496
+ const sendRegistration = async (includeExpectation) => fetch(`${CLAIM_SYNC_BASE3}/api/claim/register`, {
27420
27497
  method: "POST",
27421
27498
  headers: { "Content-Type": "application/json" },
27422
27499
  body: JSON.stringify({
@@ -27995,7 +28072,7 @@ async function resolveIssueOutcome(c, res, claims) {
27995
28072
  async function fetchFounderApprovals(pushToken, fetchImpl = fetch) {
27996
28073
  if (typeof pushToken !== "string" || pushToken.length === 0) return null;
27997
28074
  try {
27998
- const res = await fetchImpl(`${CLAIM_SYNC_BASE2}/api/claim/approvals`, {
28075
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE3}/api/claim/approvals`, {
27999
28076
  method: "POST",
28000
28077
  headers: { "Content-Type": "application/json" },
28001
28078
  body: JSON.stringify({ pushToken }),
@@ -28839,7 +28916,7 @@ async function cmdSlice(id, flags = {}) {
28839
28916
  const pushToken = await requireReadPushToken("fetching your granted slice");
28840
28917
  let res;
28841
28918
  try {
28842
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/claim/slice`, {
28919
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim/slice`, {
28843
28920
  method: "POST",
28844
28921
  headers: { "Content-Type": "application/json" },
28845
28922
  body: JSON.stringify({
@@ -28947,7 +29024,7 @@ async function cmdRuns(id, flags = {}) {
28947
29024
  const fetchOnce = async () => {
28948
29025
  let res;
28949
29026
  try {
28950
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/patch/runs`, {
29027
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/patch/runs`, {
28951
29028
  method: "POST",
28952
29029
  headers: { "Content-Type": "application/json" },
28953
29030
  body: JSON.stringify({
@@ -29095,7 +29172,7 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
29095
29172
  console.log("\n Submitting the patch through terminalhire...");
29096
29173
  let res;
29097
29174
  try {
29098
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/patch`, {
29175
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/patch`, {
29099
29176
  method: "POST",
29100
29177
  headers: { "Content-Type": "application/json" },
29101
29178
  body: JSON.stringify(submission),
@@ -29668,7 +29745,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
29668
29745
  console.log("\n Starting browser verification...");
29669
29746
  let begin;
29670
29747
  try {
29671
- const r = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync/begin`, {
29748
+ const r = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync/begin`, {
29672
29749
  method: "POST",
29673
29750
  headers: { "Content-Type": "application/json" },
29674
29751
  body: JSON.stringify({ hostname: osHostname() }),
@@ -29711,7 +29788,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
29711
29788
  let statusRes;
29712
29789
  try {
29713
29790
  statusRes = await fetch(
29714
- `${CLAIM_SYNC_BASE2}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
29791
+ `${CLAIM_SYNC_BASE3}/api/claim-sync/status?challenge=${encodeURIComponent(challenge)}`,
29715
29792
  { signal: AbortSignal.timeout(1e4) }
29716
29793
  );
29717
29794
  } catch {
@@ -29742,7 +29819,7 @@ async function cmdPush({ keepUpdated = false } = {}) {
29742
29819
  console.log("\n Verified. Sharing your claims...");
29743
29820
  let res;
29744
29821
  try {
29745
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync`, {
29822
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync`, {
29746
29823
  method: "POST",
29747
29824
  headers: { "Content-Type": "application/json" },
29748
29825
  // autoConsent is included ONLY when the dev opted into background updates —
@@ -29869,7 +29946,7 @@ async function cmdRevoke() {
29869
29946
  console.log("\n Requesting deletion...");
29870
29947
  let res;
29871
29948
  try {
29872
- res = await fetch(`${CLAIM_SYNC_BASE2}/api/claim-sync`, {
29949
+ res = await fetch(`${CLAIM_SYNC_BASE3}/api/claim-sync`, {
29873
29950
  method: "DELETE",
29874
29951
  headers: { "Content-Type": "application/json" },
29875
29952
  body: JSON.stringify({ login, deleteToken }),
@@ -30046,6 +30123,50 @@ async function cmdAudit(id, flags = {}) {
30046
30123
  }
30047
30124
  renderAudit(view);
30048
30125
  }
30126
+ async function cmdNotes(flags) {
30127
+ let pushToken = null;
30128
+ try {
30129
+ pushToken = await readPushTokenEnc();
30130
+ } catch {
30131
+ }
30132
+ if (!pushToken) {
30133
+ console.error("terminalhire claim notes: needs background push enrolment.");
30134
+ console.error(" Enrol once: terminalhire claim --push --keep-updated");
30135
+ process.exit(1);
30136
+ }
30137
+ const answer = await fetchFounderNotes(pushToken);
30138
+ if (answer === null) {
30139
+ console.error("terminalhire claim notes: could not reach terminalhire just now.");
30140
+ console.error(' This is NOT "no notes" \u2014 try again shortly.');
30141
+ process.exit(1);
30142
+ }
30143
+ if (flags.json) {
30144
+ console.log(JSON.stringify(answer, null, 2));
30145
+ await acknowledgeNotesQuietly(answer.notes);
30146
+ return;
30147
+ }
30148
+ if (answer.notes.length === 0) {
30149
+ console.log("\n No notes from founders on your claims.\n");
30150
+ await acknowledgeNotesQuietly(answer.notes);
30151
+ return;
30152
+ }
30153
+ console.log(
30154
+ `
30155
+ ${answer.notes.length} note${answer.notes.length === 1 ? "" : "s"} from founders:
30156
+ `
30157
+ );
30158
+ for (const note of answer.notes) console.log(formatNote(note));
30159
+ console.log("");
30160
+ await acknowledgeNotesQuietly(answer.notes);
30161
+ }
30162
+ async function acknowledgeNotesQuietly(notes) {
30163
+ try {
30164
+ const { acknowledgeFounderNotes: acknowledgeFounderNotes2 } = await Promise.resolve().then(() => (init_founder_note_sync(), founder_note_sync_exports));
30165
+ const { updateIndexCache: updateIndexCache2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
30166
+ updateIndexCache2({ founderNotes: acknowledgeFounderNotes2(notes) });
30167
+ } catch {
30168
+ }
30169
+ }
30049
30170
  async function run() {
30050
30171
  const verb = process.argv[2];
30051
30172
  const rawArgs = process.argv.slice(3).map((a) => a === "-y" ? "--yes" : a);
@@ -30108,9 +30229,12 @@ async function run() {
30108
30229
  case "audit":
30109
30230
  await cmdAudit(positional[0], flags);
30110
30231
  break;
30232
+ case "notes":
30233
+ await cmdNotes(flags);
30234
+ break;
30111
30235
  default:
30112
30236
  console.error(
30113
- `terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | start | attach | slice | list | status | update | submit | runs | audit | release`
30237
+ `terminalhire claim: unknown verb '${verb ?? ""}'. Expected: preview | record | start | attach | slice | list | status | update | submit | runs | notes | audit | release`
30114
30238
  );
30115
30239
  process.exit(1);
30116
30240
  }
@@ -30119,7 +30243,7 @@ async function run() {
30119
30243
  process.exit(1);
30120
30244
  }
30121
30245
  }
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;
30246
+ var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE3, 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;
30123
30247
  var init_jpi_claim = __esm({
30124
30248
  "bin/jpi-claim.js"() {
30125
30249
  "use strict";
@@ -30131,12 +30255,13 @@ var init_jpi_claim = __esm({
30131
30255
  init_state_dir();
30132
30256
  init_claim_push_bg();
30133
30257
  init_founder_verdict_sync();
30258
+ init_founder_note_sync();
30134
30259
  TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join18(homedir12(), ".terminalhire");
30135
30260
  INDEX_CACHE_FILE2 = join18(TERMINALHIRE_DIR11, "index-cache.json");
30136
30261
  CLAIM_PUSH_MARKER = join18(TERMINALHIRE_DIR11, "claim-push.json");
30137
30262
  REPO_CONTINUITY_NUDGE_MARKER = join18(TERMINALHIRE_DIR11, "repo-continuity-nudged.json");
30138
30263
  API_URL = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
30139
- CLAIM_SYNC_BASE2 = "https://terminalhire.com";
30264
+ CLAIM_SYNC_BASE3 = "https://terminalhire.com";
30140
30265
  CLAIM_CONSENT_VERSION = 1;
30141
30266
  CLAIM_POLL_INTERVAL_MS = 2e3;
30142
30267
  CLAIM_POLL_TIMEOUT_MS = 10 * 60 * 1e3;
@@ -13089,6 +13089,83 @@ var init_approved_claims_badge = __esm({
13089
13089
  }
13090
13090
  });
13091
13091
 
13092
+ // bin/founder-note-sync.js
13093
+ var founder_note_sync_exports = {};
13094
+ __export(founder_note_sync_exports, {
13095
+ acknowledgeFounderNotes: () => acknowledgeFounderNotes,
13096
+ computeFounderNotes: () => computeFounderNotes,
13097
+ fetchFounderNotes: () => fetchFounderNotes,
13098
+ formatNote: () => formatNote,
13099
+ noteKey: () => noteKey,
13100
+ syncFounderNotes: () => syncFounderNotes
13101
+ });
13102
+ async function fetchFounderNotes(pushToken, fetchImpl = fetch) {
13103
+ if (typeof pushToken !== "string" || pushToken.length === 0) return null;
13104
+ try {
13105
+ const res = await fetchImpl(`${CLAIM_SYNC_BASE3}/api/claim/notes`, {
13106
+ method: "POST",
13107
+ headers: { "Content-Type": "application/json" },
13108
+ body: JSON.stringify({ pushToken }),
13109
+ signal: AbortSignal.timeout(15e3)
13110
+ });
13111
+ if (!res?.ok) return null;
13112
+ const body = await res.json();
13113
+ if (!body || !Array.isArray(body.notes)) return null;
13114
+ const notes = body.notes.filter(
13115
+ (n) => n && typeof n.claimId === "string" && n.claimId !== "" && typeof n.note === "string" && n.note !== "" && typeof n.at === "string" && (n.kind === "founder_note" || n.kind === "feedback")
13116
+ );
13117
+ return { notes, latestAt: typeof body.latestAt === "string" ? body.latestAt : null };
13118
+ } catch {
13119
+ return null;
13120
+ }
13121
+ }
13122
+ function noteKey(note) {
13123
+ return `${note.claimId}@${note.at}`;
13124
+ }
13125
+ function computeFounderNotes(notes, previous) {
13126
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
13127
+ const prior = previous && Array.isArray(previous.seen) ? new Set(previous.seen) : /* @__PURE__ */ new Set();
13128
+ const seen = keys.filter((k) => prior.has(k));
13129
+ return { count: keys.length - seen.length, seen };
13130
+ }
13131
+ function acknowledgeFounderNotes(notes) {
13132
+ const keys = Array.isArray(notes) ? notes.map(noteKey) : [];
13133
+ return { count: 0, seen: keys };
13134
+ }
13135
+ async function syncFounderNotes({
13136
+ readAutoMarker: readAutoMarker2,
13137
+ readPushTokenEnc: readPushTokenEnc2,
13138
+ readPrevious,
13139
+ fetchImpl = fetch,
13140
+ timeoutMs = 15e3
13141
+ } = {}) {
13142
+ try {
13143
+ const marker = readAutoMarker2();
13144
+ const token = await readPushTokenEnc2();
13145
+ if (!marker || !token) return null;
13146
+ const answer = await fetchFounderNotes(
13147
+ token,
13148
+ (url, init) => fetchImpl(url, { ...init, signal: AbortSignal.timeout(timeoutMs) })
13149
+ );
13150
+ if (!answer) return null;
13151
+ return computeFounderNotes(answer.notes, readPrevious());
13152
+ } catch {
13153
+ return null;
13154
+ }
13155
+ }
13156
+ function formatNote(note) {
13157
+ const label = note.kind === "feedback" ? "changes requested" : "note";
13158
+ return ` ${note.at.slice(0, 16).replace("T", " ")} [${label}] ${note.claimId}
13159
+ ${note.note.split("\n").join("\n ")}`;
13160
+ }
13161
+ var CLAIM_SYNC_BASE3;
13162
+ var init_founder_note_sync = __esm({
13163
+ "bin/founder-note-sync.js"() {
13164
+ "use strict";
13165
+ CLAIM_SYNC_BASE3 = "https://terminalhire.com";
13166
+ }
13167
+ });
13168
+
13092
13169
  // bin/version-nudge.js
13093
13170
  var version_nudge_exports = {};
13094
13171
  __export(version_nudge_exports, {
@@ -13883,6 +13960,18 @@ async function run() {
13883
13960
  });
13884
13961
  } catch {
13885
13962
  }
13963
+ let founderNotes;
13964
+ try {
13965
+ const { syncFounderNotes: syncFounderNotes2 } = await Promise.resolve().then(() => (init_founder_note_sync(), founder_note_sync_exports));
13966
+ const { readAutoMarker: readAutoMarker2, readPushTokenEnc: readPushTokenEnc2 } = await Promise.resolve().then(() => (init_claim_push_bg(), claim_push_bg_exports));
13967
+ const { readCacheEntry: readCacheEntry2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
13968
+ founderNotes = await syncFounderNotes2({
13969
+ readAutoMarker: readAutoMarker2,
13970
+ readPushTokenEnc: readPushTokenEnc2,
13971
+ readPrevious: () => (readCacheEntry2() ?? {}).founderNotes
13972
+ });
13973
+ } catch {
13974
+ }
13886
13975
  const previousCache = readCacheEntry() ?? {};
13887
13976
  const effectiveFounderSurface = founderSurface ?? previousCache.founderSurface;
13888
13977
  let surfaceLead = "dev";
@@ -13904,6 +13993,7 @@ async function run() {
13904
13993
  };
13905
13994
  if (founderPaid) cacheEntry.founderPaid = founderPaid;
13906
13995
  if (approvedClaims) cacheEntry.approvedClaims = approvedClaims;
13996
+ if (founderNotes) cacheEntry.founderNotes = founderNotes;
13907
13997
  if (founderSurface) cacheEntry.founderSurface = founderSurface;
13908
13998
  cacheEntry.indexETag = indexETag ?? "";
13909
13999
  if (pulseLatestPostedAt) {
@@ -38,6 +38,10 @@ function approvedClaimsCount(entry) {
38
38
  const n = entry && entry.approvedClaims && entry.approvedClaims.count;
39
39
  return typeof n === "number" && n > 0 ? n : 0;
40
40
  }
41
+ function founderNoteCount(entry) {
42
+ const n = entry && entry.founderNotes && entry.founderNotes.count;
43
+ return typeof n === "number" && n > 0 ? n : 0;
44
+ }
41
45
  function founderNeedsYouCount(entry) {
42
46
  if (!entry || entry.surfaceLead !== "founder") return 0;
43
47
  const n = entry.founderSurface && entry.founderSurface.needsYouCount;
@@ -88,11 +92,15 @@ function render() {
88
92
  const incoming = incomingCount(entry);
89
93
  const paid = founderPaidCount(entry);
90
94
  const approved = approvedClaimsCount(entry);
95
+ const founderNotes = founderNoteCount(entry);
91
96
  const founderNeedsYou = founderNeedsYouCount(entry);
92
97
  const founderOpen = founderOpenCount(entry);
93
98
  const stale = sessionStale(entry) && unread === 0 && incoming === 0;
94
99
  const segments = [];
95
100
  if (approved > 0) segments.push(`\u2705 ${approved} approved \u2014 run: th claim start`);
101
+ if (founderNotes > 0) {
102
+ segments.push(`\u{1F4DD} ${founderNotes} from your founder \u2014 run: th claim notes`);
103
+ }
96
104
  if (founderNeedsYou > 0) {
97
105
  segments.push(
98
106
  `\u{1F9ED} ${founderNeedsYou} claim${founderNeedsYou === 1 ? "" : "s"} await your decision \u2014 run: th bounties`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminalhire",
3
- "version": "0.41.2",
3
+ "version": "0.42.1",
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",