terminalhire 0.2.0 → 0.2.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.
@@ -157,10 +157,12 @@ function clearSpinnerVerbs() {
157
157
  }
158
158
  return { cleared: true, keptUserVerbs };
159
159
  }
160
- function buildTips(topMatches, baseUrl, max = 3) {
160
+ function buildTips(topMatches, baseUrl, max = 8) {
161
161
  const base = String(baseUrl || "https://terminalhire.com").replace(/\/+$/, "");
162
162
  const out = [];
163
- const seen = /* @__PURE__ */ new Set();
163
+ const seenRole = /* @__PURE__ */ new Set();
164
+ const perCompany = /* @__PURE__ */ new Map();
165
+ const COMPANY_CAP = 2;
164
166
  for (const m of Array.isArray(topMatches) ? topMatches : []) {
165
167
  if (!m || !m.title || !m.company || !m.id) continue;
166
168
  const idx = String(m.id).indexOf(":");
@@ -168,14 +170,20 @@ function buildTips(topMatches, baseUrl, max = 3) {
168
170
  const source = String(m.id).slice(0, idx);
169
171
  const ext = String(m.id).slice(idx + 1);
170
172
  if (!source || !ext) continue;
171
- const key = `${source}/${ext}`;
172
- if (seen.has(key)) continue;
173
- seen.add(key);
174
- let title = String(m.title).trim().replace(/\s+/g, " ");
173
+ const companyRaw = String(m.company).trim().replace(/\s+/g, " ");
174
+ const titleRaw = String(m.title).trim().replace(/\s+/g, " ");
175
+ const roleKey = `${titleRaw.toLowerCase()}@${companyRaw.toLowerCase()}`;
176
+ const coKey = companyRaw.toLowerCase();
177
+ if (seenRole.has(roleKey)) continue;
178
+ if ((perCompany.get(coKey) || 0) >= COMPANY_CAP) continue;
179
+ seenRole.add(roleKey);
180
+ perCompany.set(coKey, (perCompany.get(coKey) || 0) + 1);
181
+ let title = titleRaw;
175
182
  if (title.length > 34) title = title.slice(0, 33).trimEnd() + "\u2026";
176
- const company = titleCase(String(m.company).trim().replace(/\s+/g, " "));
183
+ const company = titleCase(companyRaw);
177
184
  const pct = Math.max(1, Math.min(99, Math.round((Number(m.score) || 0) * 100)));
178
- const url = `${base}/j/${source}/${encodeURIComponent(ext)}`;
185
+ const token = Buffer.from(String(m.id)).toString("base64url");
186
+ const url = `${base}/j/${token}`;
179
187
  out.push(`\u2197 ${title} @ ${company} \xB7 ${pct}% \u2014 ${url}`);
180
188
  if (out.length >= max) break;
181
189
  }
package/install.js CHANGED
@@ -310,7 +310,9 @@ async function install() {
310
310
  const backupPath = backupSettings();
311
311
 
312
312
  if (installStrategy === 'direct') {
313
- settings.statusLine = buildDirectEntry(BIN_PATH);
313
+ // Claude Code requires statusLine as an object { type, command } — NOT a bare
314
+ // string (a string fails schema validation and makes Claude skip ALL settings).
315
+ settings.statusLine = { type: 'command', command: buildDirectEntry(BIN_PATH) };
314
316
  writeSettings(settings);
315
317
  console.log(' Set statusLine in ~/.claude/settings.json');
316
318
  console.log(` → node ${BIN_PATH}`);
@@ -322,7 +324,8 @@ async function install() {
322
324
  chmodSync(WRAPPER_PATH, 0o755);
323
325
  console.log(` Created wrapper: ${WRAPPER_PATH}`);
324
326
 
325
- settings.statusLine = `bash ${WRAPPER_PATH}`;
327
+ // Object form { type, command } — a bare string breaks Claude Code's settings schema.
328
+ settings.statusLine = { type: 'command', command: `bash ${WRAPPER_PATH}` };
326
329
  writeSettings(settings);
327
330
  console.log(' Updated statusLine in ~/.claude/settings.json');
328
331
  console.log(` → bash ${WRAPPER_PATH}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminalhire",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Local-first job matching for developers — Claude Code statusLine nudge and ambient spinner job surface",
5
5
  "repository": {
6
6
  "type": "git",