terminalhire 0.42.4 → 0.42.5

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.
@@ -0,0 +1,117 @@
1
+ // bin/founder-bounty-notify.js
2
+ import { spawn } from "child_process";
3
+
4
+ // bin/founder-pin.js
5
+ function isPinnedFounderBounty(j) {
6
+ return j?.bounty?.bountySource === "founder" && j?.bounty?.claimable === true;
7
+ }
8
+
9
+ // bin/founder-paid-badge.js
10
+ function openPaidIds(index) {
11
+ const jobs = index && index.jobs || [];
12
+ const ids = [];
13
+ for (const j of jobs) {
14
+ if (!j || typeof j.id !== "string") continue;
15
+ if (isPinnedFounderBounty(j)) ids.push(j.id);
16
+ }
17
+ return [...new Set(ids)].sort();
18
+ }
19
+
20
+ // bin/founder-bounty-notify.js
21
+ function nextFounderBountyNotifyState(index, previous) {
22
+ const open = openPaidIds(index);
23
+ const prior = previous && Array.isArray(previous.ids) ? previous.ids : null;
24
+ if (prior === null) {
25
+ return { ids: open, fire: [], seeded: true };
26
+ }
27
+ const seen = new Set(prior);
28
+ const fire = open.filter((id) => !seen.has(id));
29
+ const ids = [.../* @__PURE__ */ new Set([...prior.filter((id) => open.includes(id)), ...fire])].sort();
30
+ return { ids, fire, seeded: false };
31
+ }
32
+ function formatFounderBountyNotifyBody(index, fireIds) {
33
+ const jobs = index && index.jobs || [];
34
+ const byId = /* @__PURE__ */ new Map();
35
+ for (const j of jobs) {
36
+ if (j && typeof j.id === "string") byId.set(j.id, j);
37
+ }
38
+ if (fireIds.length === 1) {
39
+ const j = byId.get(fireIds[0]);
40
+ const amount = j && j.bounty && typeof j.bounty.amountUSD === "number" ? j.bounty.amountUSD : null;
41
+ const price = typeof amount === "number" && Number.isFinite(amount) && amount > 0 ? `$${Math.round(amount)} ` : "";
42
+ return `${price}founder bounty available \u2014 run: terminalhire bounties`;
43
+ }
44
+ return `${fireIds.length} founder bounties available \u2014 run: terminalhire bounties`;
45
+ }
46
+ function escapeAppleScriptString(s) {
47
+ return String(s).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
48
+ }
49
+ function displayLocalNotification({
50
+ title = "Terminalhire",
51
+ body,
52
+ platform = process.platform,
53
+ spawnFn = spawn
54
+ } = {}) {
55
+ if (!body || typeof body !== "string") return false;
56
+ try {
57
+ if (platform === "darwin") {
58
+ const t = escapeAppleScriptString(title);
59
+ const b = escapeAppleScriptString(body);
60
+ const child = spawnFn("osascript", ["-e", `display notification "${b}" with title "${t}"`], {
61
+ detached: true,
62
+ stdio: "ignore"
63
+ });
64
+ if (child && typeof child.unref === "function") child.unref();
65
+ return true;
66
+ }
67
+ if (platform === "win32") {
68
+ const safeTitle = String(title).replace(/'/g, "''");
69
+ const safeBody = String(body).replace(/'/g, "''");
70
+ const ps = `
71
+ Add-Type -AssemblyName System.Windows.Forms
72
+ $n = New-Object System.Windows.Forms.NotifyIcon
73
+ $n.Icon = [System.Drawing.SystemIcons]::Information
74
+ $n.Visible = $true
75
+ $n.ShowBalloonTip(8000, '${safeTitle}', '${safeBody}', [System.Windows.Forms.ToolTipIcon]::Info)
76
+ Start-Sleep -Seconds 9
77
+ $n.Dispose()
78
+ `.trim();
79
+ const child = spawnFn("powershell.exe", ["-NoProfile", "-Command", ps], {
80
+ detached: true,
81
+ stdio: "ignore",
82
+ windowsHide: true
83
+ });
84
+ if (child && typeof child.unref === "function") child.unref();
85
+ return true;
86
+ }
87
+ return false;
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+ function maybeNotifyFounderBounties({
93
+ index,
94
+ previous,
95
+ optedIn,
96
+ display = displayLocalNotification
97
+ } = {}) {
98
+ if (!optedIn) {
99
+ const ids = previous && Array.isArray(previous.ids) ? [...previous.ids].sort() : [];
100
+ return { state: { ids }, fired: [] };
101
+ }
102
+ const next = nextFounderBountyNotifyState(index, previous);
103
+ if (next.fire.length > 0) {
104
+ display({
105
+ title: "Terminalhire",
106
+ body: formatFounderBountyNotifyBody(index, next.fire)
107
+ });
108
+ }
109
+ return { state: { ids: next.ids }, fired: next.fire };
110
+ }
111
+ export {
112
+ displayLocalNotification,
113
+ escapeAppleScriptString,
114
+ formatFounderBountyNotifyBody,
115
+ maybeNotifyFounderBounties,
116
+ nextFounderBountyNotifyState
117
+ };
@@ -11546,6 +11546,7 @@ __export(config_exports, {
11546
11546
  getSurfaceMix: () => getSurfaceMix,
11547
11547
  isBetaOptIn: () => isBetaOptIn,
11548
11548
  isContributeEnabled: () => isContributeEnabled,
11549
+ isFounderBountyNotifyEnabled: () => isFounderBountyNotifyEnabled,
11549
11550
  isInboundNudgeMuted: () => isInboundNudgeMuted,
11550
11551
  isPeerConnectEnabled: () => isPeerConnectEnabled,
11551
11552
  parseNudgeMode: () => parseNudgeMode,
@@ -11630,6 +11631,9 @@ function isContributeEnabled() {
11630
11631
  function isBetaOptIn() {
11631
11632
  return readConfig().betaOptIn === true;
11632
11633
  }
11634
+ function isFounderBountyNotifyEnabled() {
11635
+ return readConfig().founderBountyNotify === true;
11636
+ }
11633
11637
  var TERMINALHIRE_DIR6, CONFIG_FILE, DEFAULT_CONFIG;
11634
11638
  var init_config = __esm({
11635
11639
  "src/config.ts"() {
@@ -11651,7 +11655,8 @@ var init_config = __esm({
11651
11655
  lastFullFeedbackAt: null,
11652
11656
  lastPulseAskAt: null,
11653
11657
  pulseDisclosed: false,
11654
- mix: "balanced"
11658
+ mix: "balanced",
11659
+ founderBountyNotify: false
11655
11660
  };
11656
11661
  }
11657
11662
  });
@@ -4911,7 +4911,8 @@ var init_config = __esm({
4911
4911
  lastFullFeedbackAt: null,
4912
4912
  lastPulseAskAt: null,
4913
4913
  pulseDisclosed: false,
4914
- mix: "balanced"
4914
+ mix: "balanced",
4915
+ founderBountyNotify: false
4915
4916
  };
4916
4917
  }
4917
4918
  });
@@ -4940,7 +4940,8 @@ var init_config = __esm({
4940
4940
  lastFullFeedbackAt: null,
4941
4941
  lastPulseAskAt: null,
4942
4942
  pulseDisclosed: false,
4943
- mix: "balanced"
4943
+ mix: "balanced",
4944
+ founderBountyNotify: false
4944
4945
  };
4945
4946
  }
4946
4947
  });
@@ -1,21 +1,16 @@
1
1
  #!/usr/bin/env node
2
-
3
- // bin/jpi-config.js
4
- import { join as join2 } from "path";
5
- import { homedir as homedir2 } from "os";
6
-
7
- // src/config.ts
8
- import { readFileSync, writeFileSync, existsSync } from "fs";
9
- import { join } from "path";
10
- import { homedir } from "os";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
11
 
12
12
  // src/state-dir.ts
13
13
  import { closeSync, constants, fchmodSync, fstatSync, mkdirSync, openSync } from "fs";
14
- var STATE_DIR_MODE = 448;
15
- var STATE_DIR_OK = "ok";
16
- var STATE_DIR_SYMLINK = "symlink";
17
- var STATE_DIR_UNVERIFIED = "unverified";
18
- var warnedDirs = /* @__PURE__ */ new Set();
19
14
  function warnStateDirOnce(dir, message) {
20
15
  if (warnedDirs.has(dir)) return;
21
16
  warnedDirs.add(dir);
@@ -56,8 +51,116 @@ function ensureStateDir(dir) {
56
51
  }
57
52
  }
58
53
  }
54
+ var STATE_DIR_MODE, STATE_DIR_OK, STATE_DIR_SYMLINK, STATE_DIR_UNVERIFIED, warnedDirs;
55
+ var init_state_dir = __esm({
56
+ "src/state-dir.ts"() {
57
+ "use strict";
58
+ STATE_DIR_MODE = 448;
59
+ STATE_DIR_OK = "ok";
60
+ STATE_DIR_SYMLINK = "symlink";
61
+ STATE_DIR_UNVERIFIED = "unverified";
62
+ warnedDirs = /* @__PURE__ */ new Set();
63
+ }
64
+ });
65
+
66
+ // bin/founder-pin.js
67
+ function isPinnedFounderBounty(j) {
68
+ return j?.bounty?.bountySource === "founder" && j?.bounty?.claimable === true;
69
+ }
70
+ var init_founder_pin = __esm({
71
+ "bin/founder-pin.js"() {
72
+ "use strict";
73
+ }
74
+ });
75
+
76
+ // bin/founder-paid-badge.js
77
+ var founder_paid_badge_exports = {};
78
+ __export(founder_paid_badge_exports, {
79
+ acknowledgeFounderPaid: () => acknowledgeFounderPaid,
80
+ computeFounderPaid: () => computeFounderPaid,
81
+ openPaidIds: () => openPaidIds
82
+ });
83
+ function openPaidIds(index) {
84
+ const jobs = index && index.jobs || [];
85
+ const ids = [];
86
+ for (const j of jobs) {
87
+ if (!j || typeof j.id !== "string") continue;
88
+ if (isPinnedFounderBounty(j)) ids.push(j.id);
89
+ }
90
+ return [...new Set(ids)].sort();
91
+ }
92
+ function gate(openIds, seenIds) {
93
+ const seen = new Set(seenIds);
94
+ const acknowledged = openIds.filter((id) => seen.has(id));
95
+ return { count: openIds.length - acknowledged.length, acknowledged };
96
+ }
97
+ function computeFounderPaid(index, previous) {
98
+ const open = openPaidIds(index);
99
+ const prior = previous && previous.acknowledged;
100
+ return gate(open, Array.isArray(prior) ? prior : []);
101
+ }
102
+ function acknowledgeFounderPaid({ shown = [], open = [], previous } = {}) {
103
+ const prior = previous && Array.isArray(previous.acknowledged) ? previous.acknowledged : [];
104
+ return gate(openPaidIds({ jobs: open }), [...prior, ...openPaidIds({ jobs: shown })]);
105
+ }
106
+ var init_founder_paid_badge = __esm({
107
+ "bin/founder-paid-badge.js"() {
108
+ "use strict";
109
+ init_founder_pin();
110
+ }
111
+ });
112
+
113
+ // bin/cache-store.js
114
+ var cache_store_exports = {};
115
+ __export(cache_store_exports, {
116
+ readCacheEntry: () => readCacheEntry,
117
+ updateIndexCache: () => updateIndexCache
118
+ });
119
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync } from "fs";
120
+ import { join as join2 } from "path";
121
+ import { homedir as homedir2 } from "os";
122
+ function readCacheEntry() {
123
+ try {
124
+ return JSON.parse(readFileSync2(INDEX_CACHE_FILE, "utf8"));
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+ function updateIndexCache(patch) {
130
+ ensureStateDir(TERMINALHIRE_DIR2);
131
+ const existing = readCacheEntry() ?? {};
132
+ const entry = {
133
+ ...existing,
134
+ ...patch,
135
+ schemaVersion: SCHEMA_VERSION,
136
+ ts: Date.now()
137
+ };
138
+ const tmp = `${INDEX_CACHE_FILE}.${process.pid}.${tmpCounter++}.tmp`;
139
+ writeFileSync2(tmp, JSON.stringify(entry), "utf8");
140
+ renameSync(tmp, INDEX_CACHE_FILE);
141
+ return entry;
142
+ }
143
+ var TERMINALHIRE_DIR2, INDEX_CACHE_FILE, SCHEMA_VERSION, tmpCounter;
144
+ var init_cache_store = __esm({
145
+ "bin/cache-store.js"() {
146
+ "use strict";
147
+ init_state_dir();
148
+ TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join2(homedir2(), ".terminalhire");
149
+ INDEX_CACHE_FILE = join2(TERMINALHIRE_DIR2, "index-cache.json");
150
+ SCHEMA_VERSION = 1;
151
+ tmpCounter = 0;
152
+ }
153
+ });
154
+
155
+ // bin/jpi-config.js
156
+ import { join as join3 } from "path";
157
+ import { homedir as homedir3 } from "os";
59
158
 
60
159
  // src/config.ts
160
+ init_state_dir();
161
+ import { readFileSync, writeFileSync, existsSync } from "fs";
162
+ import { join } from "path";
163
+ import { homedir } from "os";
61
164
  var TERMINALHIRE_DIR = process.env.TERMINALHIRE_DIR || join(homedir(), ".terminalhire");
62
165
  var CONFIG_FILE = join(TERMINALHIRE_DIR, "config.json");
63
166
  var DEFAULT_CONFIG = {
@@ -74,7 +177,8 @@ var DEFAULT_CONFIG = {
74
177
  lastFullFeedbackAt: null,
75
178
  lastPulseAskAt: null,
76
179
  pulseDisclosed: false,
77
- mix: "balanced"
180
+ mix: "balanced",
181
+ founderBountyNotify: false
78
182
  };
79
183
  function readConfig() {
80
184
  try {
@@ -107,8 +211,8 @@ function parseSurfaceLead(raw) {
107
211
  }
108
212
 
109
213
  // bin/jpi-config.js
110
- var TERMINALHIRE_DIR2 = process.env.TERMINALHIRE_DIR || join2(homedir2(), ".terminalhire");
111
- var CONFIG_FILE2 = join2(TERMINALHIRE_DIR2, "config.json");
214
+ var TERMINALHIRE_DIR3 = process.env.TERMINALHIRE_DIR || join3(homedir3(), ".terminalhire");
215
+ var CONFIG_FILE2 = join3(TERMINALHIRE_DIR3, "config.json");
112
216
  function parseNudgeMode(raw) {
113
217
  if (raw === "session" || raw === "always") return raw;
114
218
  const m = /^every:(\d+)$/.exec(raw);
@@ -186,13 +290,20 @@ async function run() {
186
290
  if (envOverride) {
187
291
  console.log(` (overridden by TERMINALHIRE_NUDGE=${envOverride} at runtime)`);
188
292
  }
189
- console.log(` peer-connect: ${cfg.peerConnect ? "on" : "off"} (ambient peer & founder surfacing; default off)`);
293
+ console.log(
294
+ ` peer-connect: ${cfg.peerConnect ? "on" : "off"} (ambient peer & founder surfacing; default off)`
295
+ );
190
296
  const mixEnv = process.env["TH_MIX"];
191
- console.log(` mix: ${cfg.mix} (roles vs. contributions on the ambient surface; default balanced)`);
297
+ console.log(
298
+ ` mix: ${cfg.mix} (roles vs. contributions on the ambient surface; default balanced)`
299
+ );
192
300
  if (mixEnv) {
193
301
  console.log(` (mix overridden by TH_MIX=${mixEnv} at runtime)`);
194
302
  }
195
303
  console.log(` lead: ${cfg.surfaceLead ?? "auto"} (auto derives from your open postings)`);
304
+ console.log(
305
+ ` founder-notify: ${cfg.founderBountyNotify ? "on" : "off"} (OS ping when a paid founder bounty drops; default off)`
306
+ );
196
307
  console.log(` config file: ${CONFIG_FILE2}`);
197
308
  console.log("");
198
309
  console.log(" Valid nudge values:");
@@ -204,9 +315,15 @@ async function run() {
204
315
  console.log(" (set with: config set mix <value> \xB7 read with: config get mix)");
205
316
  console.log("");
206
317
  console.log(" Peer-connect (--connect on|off):");
207
- console.log(" on \u2014 surface peers & founders in the spinner + send an anonymous matched signal");
318
+ console.log(
319
+ " on \u2014 surface peers & founders in the spinner + send an anonymous matched signal"
320
+ );
208
321
  console.log(" off \u2014 no peer matching, no directory fetch, no signal (default)");
209
322
  console.log("");
323
+ console.log(" Founder bounty OS notify (--founder-notify on|off):");
324
+ console.log(" on \u2014 ping when a NEW claimable founder bounty appears (TERM-228)");
325
+ console.log(" off \u2014 no OS toast for founder supply (default)");
326
+ console.log("");
210
327
  return;
211
328
  }
212
329
  const nudgeIdx = filtered.indexOf("--nudge");
@@ -238,8 +355,38 @@ async function run() {
238
355
  console.log(` (saved to ${CONFIG_FILE2})`);
239
356
  return;
240
357
  }
358
+ const founderNotifyIdx = filtered.indexOf("--founder-notify");
359
+ if (founderNotifyIdx !== -1) {
360
+ const value = filtered[founderNotifyIdx + 1];
361
+ if (value !== "on" && value !== "off") {
362
+ console.error("Error: --founder-notify requires a value: on | off");
363
+ process.exit(1);
364
+ }
365
+ writeConfig({ founderBountyNotify: value === "on" });
366
+ if (value === "on") {
367
+ try {
368
+ const { openPaidIds: openPaidIds2 } = await Promise.resolve().then(() => (init_founder_paid_badge(), founder_paid_badge_exports));
369
+ const { readCacheEntry: readCacheEntry2, updateIndexCache: updateIndexCache2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
370
+ const entry = readCacheEntry2() ?? {};
371
+ const ids = openPaidIds2(entry.index);
372
+ updateIndexCache2({ founderPaidOsNotified: { ids } });
373
+ console.log(` founder-notify set to: on`);
374
+ console.log(
375
+ ` (seeded ${ids.length} existing open bounty id(s) \u2014 only NEW ones will ping)`
376
+ );
377
+ } catch {
378
+ console.log(` founder-notify set to: on`);
379
+ console.log(" (could not seed from cache \u2014 first refresh will silent-seed)");
380
+ }
381
+ } else {
382
+ console.log(` founder-notify set to: off`);
383
+ }
384
+ console.log(` (saved to ${CONFIG_FILE2})`);
385
+ return;
386
+ }
241
387
  console.error("Usage: terminalhire config --nudge <session|always|every:N>");
242
388
  console.error(" terminalhire config --connect <on|off>");
389
+ console.error(" terminalhire config --founder-notify <on|off>");
243
390
  console.error(" terminalhire config set mix <jobs|balanced|credential>");
244
391
  console.error(" terminalhire config get mix");
245
392
  console.error(" terminalhire config set lead <auto|dev|founder>");
@@ -3876,7 +3876,8 @@ var DEFAULT_CONFIG = {
3876
3876
  lastFullFeedbackAt: null,
3877
3877
  lastPulseAskAt: null,
3878
3878
  pulseDisclosed: false,
3879
- mix: "balanced"
3879
+ mix: "balanced",
3880
+ founderBountyNotify: false
3880
3881
  };
3881
3882
  function readConfig() {
3882
3883
  try {
@@ -175,6 +175,7 @@ __export(config_exports, {
175
175
  getSurfaceMix: () => getSurfaceMix,
176
176
  isBetaOptIn: () => isBetaOptIn,
177
177
  isContributeEnabled: () => isContributeEnabled,
178
+ isFounderBountyNotifyEnabled: () => isFounderBountyNotifyEnabled,
178
179
  isInboundNudgeMuted: () => isInboundNudgeMuted,
179
180
  isPeerConnectEnabled: () => isPeerConnectEnabled,
180
181
  parseNudgeMode: () => parseNudgeMode,
@@ -259,6 +260,9 @@ function isContributeEnabled() {
259
260
  function isBetaOptIn() {
260
261
  return readConfig().betaOptIn === true;
261
262
  }
263
+ function isFounderBountyNotifyEnabled() {
264
+ return readConfig().founderBountyNotify === true;
265
+ }
262
266
  var TERMINALHIRE_DIR, CONFIG_FILE, DEFAULT_CONFIG;
263
267
  var init_config = __esm({
264
268
  "src/config.ts"() {
@@ -280,7 +284,8 @@ var init_config = __esm({
280
284
  lastFullFeedbackAt: null,
281
285
  lastPulseAskAt: null,
282
286
  pulseDisclosed: false,
283
- mix: "balanced"
287
+ mix: "balanced",
288
+ founderBountyNotify: false
284
289
  };
285
290
  }
286
291
  });
@@ -30923,8 +30928,8 @@ function shStream(cmd, args5, opts = {}) {
30923
30928
  const cap = opts.maxStderrBytes ?? 64 * 1024;
30924
30929
  return new Promise((resolve7, reject) => {
30925
30930
  void (async () => {
30926
- const spawn4 = opts.spawnFn ?? (await import("child_process")).spawn;
30927
- const child = spawn4(cmd, args5, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
30931
+ const spawn5 = opts.spawnFn ?? (await import("child_process")).spawn;
30932
+ const child = spawn5(cmd, args5, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
30928
30933
  let stdout = "";
30929
30934
  let stderr = "";
30930
30935
  child.stdout?.setEncoding("utf8");
@@ -65167,13 +65172,20 @@ async function run24() {
65167
65172
  if (envOverride) {
65168
65173
  console.log(` (overridden by TERMINALHIRE_NUDGE=${envOverride} at runtime)`);
65169
65174
  }
65170
- console.log(` peer-connect: ${cfg.peerConnect ? "on" : "off"} (ambient peer & founder surfacing; default off)`);
65175
+ console.log(
65176
+ ` peer-connect: ${cfg.peerConnect ? "on" : "off"} (ambient peer & founder surfacing; default off)`
65177
+ );
65171
65178
  const mixEnv = process.env["TH_MIX"];
65172
- console.log(` mix: ${cfg.mix} (roles vs. contributions on the ambient surface; default balanced)`);
65179
+ console.log(
65180
+ ` mix: ${cfg.mix} (roles vs. contributions on the ambient surface; default balanced)`
65181
+ );
65173
65182
  if (mixEnv) {
65174
65183
  console.log(` (mix overridden by TH_MIX=${mixEnv} at runtime)`);
65175
65184
  }
65176
65185
  console.log(` lead: ${cfg.surfaceLead ?? "auto"} (auto derives from your open postings)`);
65186
+ console.log(
65187
+ ` founder-notify: ${cfg.founderBountyNotify ? "on" : "off"} (OS ping when a paid founder bounty drops; default off)`
65188
+ );
65177
65189
  console.log(` config file: ${CONFIG_FILE2}`);
65178
65190
  console.log("");
65179
65191
  console.log(" Valid nudge values:");
@@ -65185,9 +65197,15 @@ async function run24() {
65185
65197
  console.log(" (set with: config set mix <value> \xB7 read with: config get mix)");
65186
65198
  console.log("");
65187
65199
  console.log(" Peer-connect (--connect on|off):");
65188
- console.log(" on \u2014 surface peers & founders in the spinner + send an anonymous matched signal");
65200
+ console.log(
65201
+ " on \u2014 surface peers & founders in the spinner + send an anonymous matched signal"
65202
+ );
65189
65203
  console.log(" off \u2014 no peer matching, no directory fetch, no signal (default)");
65190
65204
  console.log("");
65205
+ console.log(" Founder bounty OS notify (--founder-notify on|off):");
65206
+ console.log(" on \u2014 ping when a NEW claimable founder bounty appears (TERM-228)");
65207
+ console.log(" off \u2014 no OS toast for founder supply (default)");
65208
+ console.log("");
65191
65209
  return;
65192
65210
  }
65193
65211
  const nudgeIdx = filtered.indexOf("--nudge");
@@ -65219,8 +65237,38 @@ async function run24() {
65219
65237
  console.log(` (saved to ${CONFIG_FILE2})`);
65220
65238
  return;
65221
65239
  }
65240
+ const founderNotifyIdx = filtered.indexOf("--founder-notify");
65241
+ if (founderNotifyIdx !== -1) {
65242
+ const value = filtered[founderNotifyIdx + 1];
65243
+ if (value !== "on" && value !== "off") {
65244
+ console.error("Error: --founder-notify requires a value: on | off");
65245
+ process.exit(1);
65246
+ }
65247
+ writeConfig({ founderBountyNotify: value === "on" });
65248
+ if (value === "on") {
65249
+ try {
65250
+ const { openPaidIds: openPaidIds2 } = await Promise.resolve().then(() => (init_founder_paid_badge(), founder_paid_badge_exports));
65251
+ const { readCacheEntry: readCacheEntry2, updateIndexCache: updateIndexCache2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
65252
+ const entry = readCacheEntry2() ?? {};
65253
+ const ids = openPaidIds2(entry.index);
65254
+ updateIndexCache2({ founderPaidOsNotified: { ids } });
65255
+ console.log(` founder-notify set to: on`);
65256
+ console.log(
65257
+ ` (seeded ${ids.length} existing open bounty id(s) \u2014 only NEW ones will ping)`
65258
+ );
65259
+ } catch {
65260
+ console.log(` founder-notify set to: on`);
65261
+ console.log(" (could not seed from cache \u2014 first refresh will silent-seed)");
65262
+ }
65263
+ } else {
65264
+ console.log(` founder-notify set to: off`);
65265
+ }
65266
+ console.log(` (saved to ${CONFIG_FILE2})`);
65267
+ return;
65268
+ }
65222
65269
  console.error("Usage: terminalhire config --nudge <session|always|every:N>");
65223
65270
  console.error(" terminalhire config --connect <on|off>");
65271
+ console.error(" terminalhire config --founder-notify <on|off>");
65224
65272
  console.error(" terminalhire config set mix <jobs|balanced|credential>");
65225
65273
  console.error(" terminalhire config get mix");
65226
65274
  console.error(" terminalhire config set lead <auto|dev|founder>");
@@ -66187,6 +66235,113 @@ var init_job_status_suppress = __esm({
66187
66235
  }
66188
66236
  });
66189
66237
 
66238
+ // bin/founder-bounty-notify.js
66239
+ var founder_bounty_notify_exports = {};
66240
+ __export(founder_bounty_notify_exports, {
66241
+ displayLocalNotification: () => displayLocalNotification,
66242
+ escapeAppleScriptString: () => escapeAppleScriptString2,
66243
+ formatFounderBountyNotifyBody: () => formatFounderBountyNotifyBody,
66244
+ maybeNotifyFounderBounties: () => maybeNotifyFounderBounties,
66245
+ nextFounderBountyNotifyState: () => nextFounderBountyNotifyState
66246
+ });
66247
+ import { spawn as spawn4 } from "child_process";
66248
+ function nextFounderBountyNotifyState(index, previous) {
66249
+ const open3 = openPaidIds(index);
66250
+ const prior = previous && Array.isArray(previous.ids) ? previous.ids : null;
66251
+ if (prior === null) {
66252
+ return { ids: open3, fire: [], seeded: true };
66253
+ }
66254
+ const seen = new Set(prior);
66255
+ const fire = open3.filter((id) => !seen.has(id));
66256
+ const ids = [.../* @__PURE__ */ new Set([...prior.filter((id) => open3.includes(id)), ...fire])].sort();
66257
+ return { ids, fire, seeded: false };
66258
+ }
66259
+ function formatFounderBountyNotifyBody(index, fireIds) {
66260
+ const jobs = index && index.jobs || [];
66261
+ const byId = /* @__PURE__ */ new Map();
66262
+ for (const j of jobs) {
66263
+ if (j && typeof j.id === "string") byId.set(j.id, j);
66264
+ }
66265
+ if (fireIds.length === 1) {
66266
+ const j = byId.get(fireIds[0]);
66267
+ const amount = j && j.bounty && typeof j.bounty.amountUSD === "number" ? j.bounty.amountUSD : null;
66268
+ const price = typeof amount === "number" && Number.isFinite(amount) && amount > 0 ? `$${Math.round(amount)} ` : "";
66269
+ return `${price}founder bounty available \u2014 run: terminalhire bounties`;
66270
+ }
66271
+ return `${fireIds.length} founder bounties available \u2014 run: terminalhire bounties`;
66272
+ }
66273
+ function escapeAppleScriptString2(s) {
66274
+ return String(s).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
66275
+ }
66276
+ function displayLocalNotification({
66277
+ title = "Terminalhire",
66278
+ body,
66279
+ platform = process.platform,
66280
+ spawnFn = spawn4
66281
+ } = {}) {
66282
+ if (!body || typeof body !== "string") return false;
66283
+ try {
66284
+ if (platform === "darwin") {
66285
+ const t = escapeAppleScriptString2(title);
66286
+ const b = escapeAppleScriptString2(body);
66287
+ const child = spawnFn("osascript", ["-e", `display notification "${b}" with title "${t}"`], {
66288
+ detached: true,
66289
+ stdio: "ignore"
66290
+ });
66291
+ if (child && typeof child.unref === "function") child.unref();
66292
+ return true;
66293
+ }
66294
+ if (platform === "win32") {
66295
+ const safeTitle = String(title).replace(/'/g, "''");
66296
+ const safeBody = String(body).replace(/'/g, "''");
66297
+ const ps = `
66298
+ Add-Type -AssemblyName System.Windows.Forms
66299
+ $n = New-Object System.Windows.Forms.NotifyIcon
66300
+ $n.Icon = [System.Drawing.SystemIcons]::Information
66301
+ $n.Visible = $true
66302
+ $n.ShowBalloonTip(8000, '${safeTitle}', '${safeBody}', [System.Windows.Forms.ToolTipIcon]::Info)
66303
+ Start-Sleep -Seconds 9
66304
+ $n.Dispose()
66305
+ `.trim();
66306
+ const child = spawnFn("powershell.exe", ["-NoProfile", "-Command", ps], {
66307
+ detached: true,
66308
+ stdio: "ignore",
66309
+ windowsHide: true
66310
+ });
66311
+ if (child && typeof child.unref === "function") child.unref();
66312
+ return true;
66313
+ }
66314
+ return false;
66315
+ } catch {
66316
+ return false;
66317
+ }
66318
+ }
66319
+ function maybeNotifyFounderBounties({
66320
+ index,
66321
+ previous,
66322
+ optedIn,
66323
+ display = displayLocalNotification
66324
+ } = {}) {
66325
+ if (!optedIn) {
66326
+ const ids = previous && Array.isArray(previous.ids) ? [...previous.ids].sort() : [];
66327
+ return { state: { ids }, fired: [] };
66328
+ }
66329
+ const next = nextFounderBountyNotifyState(index, previous);
66330
+ if (next.fire.length > 0) {
66331
+ display({
66332
+ title: "Terminalhire",
66333
+ body: formatFounderBountyNotifyBody(index, next.fire)
66334
+ });
66335
+ }
66336
+ return { state: { ids: next.ids }, fired: next.fire };
66337
+ }
66338
+ var init_founder_bounty_notify = __esm({
66339
+ "bin/founder-bounty-notify.js"() {
66340
+ "use strict";
66341
+ init_founder_paid_badge();
66342
+ }
66343
+ });
66344
+
66190
66345
  // bin/approved-claims-sync.js
66191
66346
  var approved_claims_sync_exports = {};
66192
66347
  __export(approved_claims_sync_exports, {
@@ -66589,6 +66744,20 @@ async function run28() {
66589
66744
  founderPaid = computeFounderPaid2(index, (readCacheEntry2() ?? {}).founderPaid);
66590
66745
  } catch {
66591
66746
  }
66747
+ let founderPaidOsNotified;
66748
+ try {
66749
+ if (isFounderBountyNotifyEnabled()) {
66750
+ const { maybeNotifyFounderBounties: maybeNotifyFounderBounties2 } = await Promise.resolve().then(() => (init_founder_bounty_notify(), founder_bounty_notify_exports));
66751
+ const { readCacheEntry: readCacheEntry2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
66752
+ const result = maybeNotifyFounderBounties2({
66753
+ index,
66754
+ previous: (readCacheEntry2() ?? {}).founderPaidOsNotified,
66755
+ optedIn: true
66756
+ });
66757
+ founderPaidOsNotified = result.state;
66758
+ }
66759
+ } catch {
66760
+ }
66592
66761
  let approvedClaims;
66593
66762
  try {
66594
66763
  const { syncApprovedClaims: syncApprovedClaims2 } = await Promise.resolve().then(() => (init_approved_claims_sync(), approved_claims_sync_exports));
@@ -66635,6 +66804,7 @@ async function run28() {
66635
66804
  surfaceLead
66636
66805
  };
66637
66806
  if (founderPaid) cacheEntry.founderPaid = founderPaid;
66807
+ if (founderPaidOsNotified) cacheEntry.founderPaidOsNotified = founderPaidOsNotified;
66638
66808
  if (approvedClaims) cacheEntry.approvedClaims = approvedClaims;
66639
66809
  if (founderNotes) cacheEntry.founderNotes = founderNotes;
66640
66810
  if (founderSurface) cacheEntry.founderSurface = founderSurface;
@@ -11666,7 +11666,8 @@ var init_config = __esm({
11666
11666
  lastFullFeedbackAt: null,
11667
11667
  lastPulseAskAt: null,
11668
11668
  pulseDisclosed: false,
11669
- mix: "balanced"
11669
+ mix: "balanced",
11670
+ founderBountyNotify: false
11670
11671
  };
11671
11672
  }
11672
11673
  });
@@ -4940,7 +4940,8 @@ var init_config = __esm({
4940
4940
  lastFullFeedbackAt: null,
4941
4941
  lastPulseAskAt: null,
4942
4942
  pulseDisclosed: false,
4943
- mix: "balanced"
4943
+ mix: "balanced",
4944
+ founderBountyNotify: false
4944
4945
  };
4945
4946
  }
4946
4947
  });
@@ -11932,6 +11932,7 @@ __export(config_exports, {
11932
11932
  getSurfaceMix: () => getSurfaceMix,
11933
11933
  isBetaOptIn: () => isBetaOptIn,
11934
11934
  isContributeEnabled: () => isContributeEnabled,
11935
+ isFounderBountyNotifyEnabled: () => isFounderBountyNotifyEnabled,
11935
11936
  isInboundNudgeMuted: () => isInboundNudgeMuted,
11936
11937
  isPeerConnectEnabled: () => isPeerConnectEnabled,
11937
11938
  parseNudgeMode: () => parseNudgeMode,
@@ -12016,6 +12017,9 @@ function isContributeEnabled() {
12016
12017
  function isBetaOptIn() {
12017
12018
  return readConfig().betaOptIn === true;
12018
12019
  }
12020
+ function isFounderBountyNotifyEnabled() {
12021
+ return readConfig().founderBountyNotify === true;
12022
+ }
12019
12023
  var TERMINALHIRE_DIR5, CONFIG_FILE, DEFAULT_CONFIG;
12020
12024
  var init_config = __esm({
12021
12025
  "src/config.ts"() {
@@ -12037,7 +12041,8 @@ var init_config = __esm({
12037
12041
  lastFullFeedbackAt: null,
12038
12042
  lastPulseAskAt: null,
12039
12043
  pulseDisclosed: false,
12040
- mix: "balanced"
12044
+ mix: "balanced",
12045
+ founderBountyNotify: false
12041
12046
  };
12042
12047
  }
12043
12048
  });
@@ -177,7 +177,8 @@ var init_config = __esm({
177
177
  lastFullFeedbackAt: null,
178
178
  lastPulseAskAt: null,
179
179
  pulseDisclosed: false,
180
- mix: "balanced"
180
+ mix: "balanced",
181
+ founderBountyNotify: false
181
182
  };
182
183
  }
183
184
  });
@@ -11277,7 +11277,8 @@ var init_config = __esm({
11277
11277
  lastFullFeedbackAt: null,
11278
11278
  lastPulseAskAt: null,
11279
11279
  pulseDisclosed: false,
11280
- mix: "balanced"
11280
+ mix: "balanced",
11281
+ founderBountyNotify: false
11281
11282
  };
11282
11283
  }
11283
11284
  });
@@ -4939,7 +4939,8 @@ var init_config = __esm({
4939
4939
  lastFullFeedbackAt: null,
4940
4940
  lastPulseAskAt: null,
4941
4941
  pulseDisclosed: false,
4942
- mix: "balanced"
4942
+ mix: "balanced",
4943
+ founderBountyNotify: false
4943
4944
  };
4944
4945
  }
4945
4946
  });
@@ -52521,6 +52521,7 @@ __export(config_exports, {
52521
52521
  getSurfaceMix: () => getSurfaceMix,
52522
52522
  isBetaOptIn: () => isBetaOptIn,
52523
52523
  isContributeEnabled: () => isContributeEnabled,
52524
+ isFounderBountyNotifyEnabled: () => isFounderBountyNotifyEnabled,
52524
52525
  isInboundNudgeMuted: () => isInboundNudgeMuted,
52525
52526
  isPeerConnectEnabled: () => isPeerConnectEnabled,
52526
52527
  parseNudgeMode: () => parseNudgeMode,
@@ -52605,6 +52606,9 @@ function isContributeEnabled() {
52605
52606
  function isBetaOptIn() {
52606
52607
  return readConfig().betaOptIn === true;
52607
52608
  }
52609
+ function isFounderBountyNotifyEnabled() {
52610
+ return readConfig().founderBountyNotify === true;
52611
+ }
52608
52612
  var TERMINALHIRE_DIR12, CONFIG_FILE, DEFAULT_CONFIG;
52609
52613
  var init_config = __esm({
52610
52614
  "src/config.ts"() {
@@ -52626,7 +52630,8 @@ var init_config = __esm({
52626
52630
  lastFullFeedbackAt: null,
52627
52631
  lastPulseAskAt: null,
52628
52632
  pulseDisclosed: false,
52629
- mix: "balanced"
52633
+ mix: "balanced",
52634
+ founderBountyNotify: false
52630
52635
  };
52631
52636
  }
52632
52637
  });
@@ -148,6 +148,7 @@ __export(config_exports, {
148
148
  getSurfaceMix: () => getSurfaceMix,
149
149
  isBetaOptIn: () => isBetaOptIn,
150
150
  isContributeEnabled: () => isContributeEnabled,
151
+ isFounderBountyNotifyEnabled: () => isFounderBountyNotifyEnabled,
151
152
  isInboundNudgeMuted: () => isInboundNudgeMuted,
152
153
  isPeerConnectEnabled: () => isPeerConnectEnabled,
153
154
  parseNudgeMode: () => parseNudgeMode,
@@ -232,6 +233,9 @@ function isContributeEnabled() {
232
233
  function isBetaOptIn() {
233
234
  return readConfig().betaOptIn === true;
234
235
  }
236
+ function isFounderBountyNotifyEnabled() {
237
+ return readConfig().founderBountyNotify === true;
238
+ }
235
239
  var TERMINALHIRE_DIR3, CONFIG_FILE, DEFAULT_CONFIG;
236
240
  var init_config = __esm({
237
241
  "src/config.ts"() {
@@ -253,7 +257,8 @@ var init_config = __esm({
253
257
  lastFullFeedbackAt: null,
254
258
  lastPulseAskAt: null,
255
259
  pulseDisclosed: false,
256
- mix: "balanced"
260
+ mix: "balanced",
261
+ founderBountyNotify: false
257
262
  };
258
263
  }
259
264
  });
@@ -13121,6 +13126,113 @@ var init_founder_paid_badge = __esm({
13121
13126
  }
13122
13127
  });
13123
13128
 
13129
+ // bin/founder-bounty-notify.js
13130
+ var founder_bounty_notify_exports = {};
13131
+ __export(founder_bounty_notify_exports, {
13132
+ displayLocalNotification: () => displayLocalNotification,
13133
+ escapeAppleScriptString: () => escapeAppleScriptString,
13134
+ formatFounderBountyNotifyBody: () => formatFounderBountyNotifyBody,
13135
+ maybeNotifyFounderBounties: () => maybeNotifyFounderBounties,
13136
+ nextFounderBountyNotifyState: () => nextFounderBountyNotifyState
13137
+ });
13138
+ import { spawn } from "child_process";
13139
+ function nextFounderBountyNotifyState(index, previous) {
13140
+ const open = openPaidIds(index);
13141
+ const prior = previous && Array.isArray(previous.ids) ? previous.ids : null;
13142
+ if (prior === null) {
13143
+ return { ids: open, fire: [], seeded: true };
13144
+ }
13145
+ const seen = new Set(prior);
13146
+ const fire = open.filter((id) => !seen.has(id));
13147
+ const ids = [.../* @__PURE__ */ new Set([...prior.filter((id) => open.includes(id)), ...fire])].sort();
13148
+ return { ids, fire, seeded: false };
13149
+ }
13150
+ function formatFounderBountyNotifyBody(index, fireIds) {
13151
+ const jobs = index && index.jobs || [];
13152
+ const byId = /* @__PURE__ */ new Map();
13153
+ for (const j of jobs) {
13154
+ if (j && typeof j.id === "string") byId.set(j.id, j);
13155
+ }
13156
+ if (fireIds.length === 1) {
13157
+ const j = byId.get(fireIds[0]);
13158
+ const amount = j && j.bounty && typeof j.bounty.amountUSD === "number" ? j.bounty.amountUSD : null;
13159
+ const price = typeof amount === "number" && Number.isFinite(amount) && amount > 0 ? `$${Math.round(amount)} ` : "";
13160
+ return `${price}founder bounty available \u2014 run: terminalhire bounties`;
13161
+ }
13162
+ return `${fireIds.length} founder bounties available \u2014 run: terminalhire bounties`;
13163
+ }
13164
+ function escapeAppleScriptString(s) {
13165
+ return String(s).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
13166
+ }
13167
+ function displayLocalNotification({
13168
+ title = "Terminalhire",
13169
+ body,
13170
+ platform = process.platform,
13171
+ spawnFn = spawn
13172
+ } = {}) {
13173
+ if (!body || typeof body !== "string") return false;
13174
+ try {
13175
+ if (platform === "darwin") {
13176
+ const t = escapeAppleScriptString(title);
13177
+ const b = escapeAppleScriptString(body);
13178
+ const child = spawnFn("osascript", ["-e", `display notification "${b}" with title "${t}"`], {
13179
+ detached: true,
13180
+ stdio: "ignore"
13181
+ });
13182
+ if (child && typeof child.unref === "function") child.unref();
13183
+ return true;
13184
+ }
13185
+ if (platform === "win32") {
13186
+ const safeTitle = String(title).replace(/'/g, "''");
13187
+ const safeBody = String(body).replace(/'/g, "''");
13188
+ const ps = `
13189
+ Add-Type -AssemblyName System.Windows.Forms
13190
+ $n = New-Object System.Windows.Forms.NotifyIcon
13191
+ $n.Icon = [System.Drawing.SystemIcons]::Information
13192
+ $n.Visible = $true
13193
+ $n.ShowBalloonTip(8000, '${safeTitle}', '${safeBody}', [System.Windows.Forms.ToolTipIcon]::Info)
13194
+ Start-Sleep -Seconds 9
13195
+ $n.Dispose()
13196
+ `.trim();
13197
+ const child = spawnFn("powershell.exe", ["-NoProfile", "-Command", ps], {
13198
+ detached: true,
13199
+ stdio: "ignore",
13200
+ windowsHide: true
13201
+ });
13202
+ if (child && typeof child.unref === "function") child.unref();
13203
+ return true;
13204
+ }
13205
+ return false;
13206
+ } catch {
13207
+ return false;
13208
+ }
13209
+ }
13210
+ function maybeNotifyFounderBounties({
13211
+ index,
13212
+ previous,
13213
+ optedIn,
13214
+ display = displayLocalNotification
13215
+ } = {}) {
13216
+ if (!optedIn) {
13217
+ const ids = previous && Array.isArray(previous.ids) ? [...previous.ids].sort() : [];
13218
+ return { state: { ids }, fired: [] };
13219
+ }
13220
+ const next = nextFounderBountyNotifyState(index, previous);
13221
+ if (next.fire.length > 0) {
13222
+ display({
13223
+ title: "Terminalhire",
13224
+ body: formatFounderBountyNotifyBody(index, next.fire)
13225
+ });
13226
+ }
13227
+ return { state: { ids: next.ids }, fired: next.fire };
13228
+ }
13229
+ var init_founder_bounty_notify = __esm({
13230
+ "bin/founder-bounty-notify.js"() {
13231
+ "use strict";
13232
+ init_founder_paid_badge();
13233
+ }
13234
+ });
13235
+
13124
13236
  // bin/approved-claims-sync.js
13125
13237
  var approved_claims_sync_exports = {};
13126
13238
  __export(approved_claims_sync_exports, {
@@ -14071,6 +14183,20 @@ async function run() {
14071
14183
  founderPaid = computeFounderPaid2(index, (readCacheEntry2() ?? {}).founderPaid);
14072
14184
  } catch {
14073
14185
  }
14186
+ let founderPaidOsNotified;
14187
+ try {
14188
+ if (isFounderBountyNotifyEnabled()) {
14189
+ const { maybeNotifyFounderBounties: maybeNotifyFounderBounties2 } = await Promise.resolve().then(() => (init_founder_bounty_notify(), founder_bounty_notify_exports));
14190
+ const { readCacheEntry: readCacheEntry2 } = await Promise.resolve().then(() => (init_cache_store(), cache_store_exports));
14191
+ const result = maybeNotifyFounderBounties2({
14192
+ index,
14193
+ previous: (readCacheEntry2() ?? {}).founderPaidOsNotified,
14194
+ optedIn: true
14195
+ });
14196
+ founderPaidOsNotified = result.state;
14197
+ }
14198
+ } catch {
14199
+ }
14074
14200
  let approvedClaims;
14075
14201
  try {
14076
14202
  const { syncApprovedClaims: syncApprovedClaims2 } = await Promise.resolve().then(() => (init_approved_claims_sync(), approved_claims_sync_exports));
@@ -14117,6 +14243,7 @@ async function run() {
14117
14243
  surfaceLead
14118
14244
  };
14119
14245
  if (founderPaid) cacheEntry.founderPaid = founderPaid;
14246
+ if (founderPaidOsNotified) cacheEntry.founderPaidOsNotified = founderPaidOsNotified;
14120
14247
  if (approvedClaims) cacheEntry.approvedClaims = approvedClaims;
14121
14248
  if (founderNotes) cacheEntry.founderNotes = founderNotes;
14122
14249
  if (founderSurface) cacheEntry.founderSurface = founderSurface;
@@ -73,7 +73,8 @@ var DEFAULT_CONFIG = {
73
73
  lastFullFeedbackAt: null,
74
74
  lastPulseAskAt: null,
75
75
  pulseDisclosed: false,
76
- mix: "balanced"
76
+ mix: "balanced",
77
+ founderBountyNotify: false
77
78
  };
78
79
  function readConfig() {
79
80
  try {
@@ -103,7 +103,8 @@ var DEFAULT_CONFIG = {
103
103
  lastFullFeedbackAt: null,
104
104
  lastPulseAskAt: null,
105
105
  pulseDisclosed: false,
106
- mix: "balanced"
106
+ mix: "balanced",
107
+ founderBountyNotify: false
107
108
  };
108
109
  function readConfig() {
109
110
  try {
@@ -68,7 +68,8 @@ var DEFAULT_CONFIG = {
68
68
  lastFullFeedbackAt: null,
69
69
  lastPulseAskAt: null,
70
70
  pulseDisclosed: false,
71
- mix: "balanced"
71
+ mix: "balanced",
72
+ founderBountyNotify: false
72
73
  };
73
74
  function readConfig() {
74
75
  try {
@@ -143,12 +144,16 @@ function isContributeEnabled() {
143
144
  function isBetaOptIn() {
144
145
  return readConfig().betaOptIn === true;
145
146
  }
147
+ function isFounderBountyNotifyEnabled() {
148
+ return readConfig().founderBountyNotify === true;
149
+ }
146
150
  export {
147
151
  getNudgeMode,
148
152
  getSurfaceLeadOverride,
149
153
  getSurfaceMix,
150
154
  isBetaOptIn,
151
155
  isContributeEnabled,
156
+ isFounderBountyNotifyEnabled,
152
157
  isInboundNudgeMuted,
153
158
  isPeerConnectEnabled,
154
159
  parseNudgeMode,
package/dist/src/link.js CHANGED
@@ -176,7 +176,8 @@ var DEFAULT_CONFIG = {
176
176
  lastFullFeedbackAt: null,
177
177
  lastPulseAskAt: null,
178
178
  pulseDisclosed: false,
179
- mix: "balanced"
179
+ mix: "balanced",
180
+ founderBountyNotify: false
180
181
  };
181
182
  function readConfig() {
182
183
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminalhire",
3
- "version": "0.42.4",
3
+ "version": "0.42.5",
4
4
  "description": "Local-first job matching for developers \u2014 ambient job matches in the Claude Code spinner. Your profile never leaves your machine.",
5
5
  "repository": {
6
6
  "type": "git",