vipcare 0.6.0 → 0.6.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.
- package/CLAUDE.md +0 -1
- package/bin/vip.js +20 -7
- package/lib/card.js +10 -0
- package/lib/synthesizer.js +1 -1
- package/package.json +1 -1
- package/web/index.html +0 -229
package/CLAUDE.md
CHANGED
package/bin/vip.js
CHANGED
|
@@ -64,14 +64,16 @@ function gatherData(person) {
|
|
|
64
64
|
|
|
65
65
|
if (person.linkedinUrl) sources.push(person.linkedinUrl);
|
|
66
66
|
|
|
67
|
+
// Collect all search results into one consolidated file
|
|
68
|
+
const searchEntries = [];
|
|
69
|
+
|
|
67
70
|
if (person.rawSnippets.length) {
|
|
68
71
|
rawParts.push('=== Web Search Results ===');
|
|
69
|
-
rawParts.push(...person.rawSnippets);
|
|
70
|
-
// Save each snippet as a raw source file
|
|
71
72
|
person.rawSnippets.forEach((snippet, i) => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
if (!snippet.trim()) return; // skip empty
|
|
74
|
+
rawParts.push(snippet);
|
|
75
|
+
const url = person.otherUrls?.[i] || '';
|
|
76
|
+
if (url) searchEntries.push({ url, snippet });
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
79
|
|
|
@@ -79,13 +81,24 @@ function gatherData(person) {
|
|
|
79
81
|
console.log(c.dim(` Searching the web for ${person.name}...`));
|
|
80
82
|
const results = searchPerson(person.name);
|
|
81
83
|
for (const r of results) {
|
|
84
|
+
if (!r.body?.trim() && !r.title?.trim()) continue; // skip empty
|
|
82
85
|
rawParts.push(`${r.title}\n${r.body}`);
|
|
83
86
|
if (!sources.includes(r.url)) sources.push(r.url);
|
|
84
|
-
|
|
85
|
-
saveRawSource(personSlug, safeName, `# ${r.title}\n\nSource: ${r.url}\nFetched: ${new Date().toISOString()}\n\n${r.body}`);
|
|
87
|
+
searchEntries.push({ url: r.url, snippet: `${r.title}\n${r.body}` });
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
|
|
91
|
+
// Save all search results in ONE file
|
|
92
|
+
if (searchEntries.length) {
|
|
93
|
+
const timestamp = new Date().toISOString();
|
|
94
|
+
const content = `# Web Search Results\n\nFetched: ${timestamp}\nQuery: ${person.name}\n\n` +
|
|
95
|
+
searchEntries
|
|
96
|
+
.filter(e => e.snippet.trim())
|
|
97
|
+
.map(e => `---\n\n**Source:** ${e.url}\n\n${e.snippet}`)
|
|
98
|
+
.join('\n\n');
|
|
99
|
+
saveRawSource(personSlug, 'web_search', content);
|
|
100
|
+
}
|
|
101
|
+
|
|
89
102
|
console.log(c.dim(` Raw data saved to ${path.join(getProfilesDir(), '.raw', personSlug)}/`));
|
|
90
103
|
return [rawParts.join('\n\n'), sources];
|
|
91
104
|
}
|
package/lib/card.js
CHANGED
|
@@ -234,6 +234,7 @@ header .count { color: #94a3b8; font-size: 0.85em; }
|
|
|
234
234
|
<div class="main" id="main">
|
|
235
235
|
<header>
|
|
236
236
|
<h1>VIPCare</h1>
|
|
237
|
+
<input type="text" id="search" placeholder="Search by name or tag..." style="padding:8px 14px;border:1px solid #e2e8f0;border-radius:8px;font-size:0.9em;width:260px;outline:none;color:#1e293b;background:#fff;" onfocus="this.style.borderColor='#2563eb'" onblur="this.style.borderColor='#e2e8f0'">
|
|
237
238
|
<span class="count" id="count"></span>
|
|
238
239
|
</header>
|
|
239
240
|
<div class="grid" id="grid"></div>
|
|
@@ -419,6 +420,15 @@ cards.sort((a, b) => (b.updated || '').localeCompare(a.updated || ''));
|
|
|
419
420
|
const grid = document.getElementById('grid');
|
|
420
421
|
grid.innerHTML = cards.map((card, i) => renderCard(card, i)).join('');
|
|
421
422
|
document.getElementById('count').textContent = cards.length + ' contacts';
|
|
423
|
+
|
|
424
|
+
document.getElementById('search').addEventListener('input', (e) => {
|
|
425
|
+
const q = e.target.value.toLowerCase();
|
|
426
|
+
cards.forEach((card, i) => {
|
|
427
|
+
const el = document.getElementById('card-' + i);
|
|
428
|
+
const text = [card.name, card.company, card.title, ...(card.tags || [])].join(' ').toLowerCase();
|
|
429
|
+
el.style.display = text.includes(q) ? '' : 'none';
|
|
430
|
+
});
|
|
431
|
+
});
|
|
422
432
|
</script>
|
|
423
433
|
</body>
|
|
424
434
|
</html>`;
|
package/lib/synthesizer.js
CHANGED
|
@@ -12,8 +12,8 @@ function getBackend() {
|
|
|
12
12
|
const config = loadConfig();
|
|
13
13
|
if (config.ai_backend) return config.ai_backend.toLowerCase();
|
|
14
14
|
|
|
15
|
-
if (checkTool('claude')) return 'claude-cli';
|
|
16
15
|
if (process.env.ANTHROPIC_API_KEY || config.anthropic_api_key) return 'anthropic';
|
|
16
|
+
if (checkTool('claude')) return 'claude-cli';
|
|
17
17
|
if (checkTool('gh') && copilotAvailable()) return 'copilot-cli';
|
|
18
18
|
|
|
19
19
|
throw new Error(
|
package/package.json
CHANGED
package/web/index.html
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>VIPCare - Baseball Cards</title>
|
|
7
|
-
<style>
|
|
8
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
-
html { scroll-behavior: smooth; }
|
|
10
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; padding: 20px; padding: max(20px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right)) max(20px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left)); }
|
|
11
|
-
h1 { text-align: center; font-size: 1.8em; margin: 20px 0 30px; color: #38bdf8; }
|
|
12
|
-
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; max-width: 1200px; margin: 0 auto; }
|
|
13
|
-
|
|
14
|
-
.card {
|
|
15
|
-
background: linear-gradient(145deg, #1e293b, #334155);
|
|
16
|
-
border-radius: 16px;
|
|
17
|
-
padding: 24px;
|
|
18
|
-
border: 1px solid #475569;
|
|
19
|
-
cursor: pointer;
|
|
20
|
-
transition: transform 0.2s, box-shadow 0.2s;
|
|
21
|
-
position: relative;
|
|
22
|
-
overflow: hidden;
|
|
23
|
-
min-height: 44px;
|
|
24
|
-
-webkit-tap-highlight-color: transparent;
|
|
25
|
-
}
|
|
26
|
-
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 40px rgba(56,189,248,0.15); }
|
|
27
|
-
.card:active { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(56,189,248,0.1); }
|
|
28
|
-
.card::before {
|
|
29
|
-
content: '';
|
|
30
|
-
position: absolute;
|
|
31
|
-
top: 0; left: 0; right: 0;
|
|
32
|
-
height: 4px;
|
|
33
|
-
background: linear-gradient(90deg, #38bdf8, #818cf8, #c084fc);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
|
|
37
|
-
.card-name { font-size: 1.4em; font-weight: 700; color: #f1f5f9; }
|
|
38
|
-
.card-role { font-size: 0.85em; color: #94a3b8; margin-top: 2px; }
|
|
39
|
-
.card-badges { display: flex; gap: 6px; }
|
|
40
|
-
.badge { padding: 4px 10px; border-radius: 6px; font-size: 0.75em; font-weight: 700; min-height: 28px; display: inline-flex; align-items: center; }
|
|
41
|
-
.badge-disc { background: #38bdf8; color: #0f172a; }
|
|
42
|
-
.badge-mbti { background: #818cf8; color: #0f172a; }
|
|
43
|
-
|
|
44
|
-
.card-quote { font-style: italic; color: #94a3b8; font-size: 0.8em; margin: 10px 0; padding: 8px 12px; border-left: 3px solid #475569; }
|
|
45
|
-
|
|
46
|
-
.radar-container { display: flex; justify-content: center; margin: 16px 0; }
|
|
47
|
-
.radar { width: 200px; height: 200px; max-width: 100%; }
|
|
48
|
-
|
|
49
|
-
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0; }
|
|
50
|
-
.tag { background: #1e3a5f; color: #38bdf8; padding: 4px 12px; border-radius: 12px; font-size: 0.75em; min-height: 28px; display: inline-flex; align-items: center; }
|
|
51
|
-
|
|
52
|
-
.expertise { margin: 10px 0; }
|
|
53
|
-
.expertise-title { font-size: 0.75em; color: #64748b; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; }
|
|
54
|
-
.expertise-item { font-size: 0.8em; color: #cbd5e1; padding: 2px 0; }
|
|
55
|
-
.superpower { color: #fbbf24; font-weight: 600; font-size: 0.85em; margin: 6px 0; }
|
|
56
|
-
|
|
57
|
-
.tips { margin-top: 12px; border-top: 1px solid #475569; padding-top: 12px; }
|
|
58
|
-
.tip-row { display: flex; gap: 4px; font-size: 0.8em; margin: 4px 0; color: #cbd5e1; min-height: 44px; align-items: center; }
|
|
59
|
-
.tip-icon { width: 20px; text-align: center; }
|
|
60
|
-
.tip-label { color: #64748b; min-width: 55px; }
|
|
61
|
-
|
|
62
|
-
/* Modal */
|
|
63
|
-
.modal-overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7); z-index: 100; justify-content: center; align-items: center; padding: 20px; }
|
|
64
|
-
.modal-overlay.active { display: flex; }
|
|
65
|
-
.modal {
|
|
66
|
-
background: #1e293b; border-radius: 16px; max-width: 600px; width: 100%; max-height: 90vh; overflow-y: auto; padding: 32px;
|
|
67
|
-
border: 1px solid #475569;
|
|
68
|
-
-webkit-overflow-scrolling: touch;
|
|
69
|
-
}
|
|
70
|
-
.modal-close { float: right; background: none; border: none; color: #94a3b8; font-size: 1.5em; cursor: pointer; min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
|
|
71
|
-
.modal h2 { color: #38bdf8; margin: 16px 0 8px; font-size: 1.1em; }
|
|
72
|
-
.modal p, .modal li { color: #cbd5e1; font-size: 0.9em; line-height: 1.6; }
|
|
73
|
-
.modal ul { padding-left: 20px; }
|
|
74
|
-
|
|
75
|
-
/* Mobile: screens < 480px */
|
|
76
|
-
@media (max-width: 480px) {
|
|
77
|
-
body { padding: max(12px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right)) max(12px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left)); }
|
|
78
|
-
h1 { font-size: 1.5em; margin: 12px 0 20px; }
|
|
79
|
-
.grid { grid-template-columns: 1fr; gap: 16px; }
|
|
80
|
-
.card { padding: 18px; }
|
|
81
|
-
.card-name { font-size: 1.25em; }
|
|
82
|
-
.card-role { font-size: 0.9em; }
|
|
83
|
-
.card-quote { font-size: 0.85em; }
|
|
84
|
-
.tip-row { font-size: 0.85em; }
|
|
85
|
-
.radar { width: 180px; height: 180px; }
|
|
86
|
-
.badge { font-size: 0.8em; padding: 5px 12px; }
|
|
87
|
-
.tag { font-size: 0.8em; padding: 5px 14px; }
|
|
88
|
-
|
|
89
|
-
.modal-overlay { padding: 0; align-items: stretch; }
|
|
90
|
-
.modal { max-width: 100%; max-height: 100vh; height: 100%; border-radius: 0; padding: 20px; padding-top: max(20px, env(safe-area-inset-top)); padding-bottom: max(20px, env(safe-area-inset-bottom)); }
|
|
91
|
-
.modal h2 { font-size: 1.15em; }
|
|
92
|
-
.modal p, .modal li { font-size: 0.95em; line-height: 1.7; }
|
|
93
|
-
}
|
|
94
|
-
</style>
|
|
95
|
-
</head>
|
|
96
|
-
<body>
|
|
97
|
-
|
|
98
|
-
<h1>VIPCare</h1>
|
|
99
|
-
<div class="grid" id="grid"></div>
|
|
100
|
-
|
|
101
|
-
<div class="modal-overlay" id="modal" onclick="if(event.target===this)closeModal()">
|
|
102
|
-
<div class="modal" id="modal-content"></div>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
<script>
|
|
106
|
-
const cards = [{"name":"Compare JSON","title":"VP","company":"ACME","location":"","disc":"?","mbti":"?","scores":{},"tags":[],"icebreakers":[],"dos":[],"donts":[],"gifts":[],"expertise":[],"superpower":"","quote":"Test"},{"name":"Sam Altman","title":"","company":"","location":"","disc":"?","mbti":"?","scores":{},"tags":[],"icebreakers":[],"dos":[],"donts":[],"gifts":[],"expertise":[],"superpower":"","quote":""}];
|
|
107
|
-
|
|
108
|
-
const SCORE_LABELS = {
|
|
109
|
-
openness: 'Openness',
|
|
110
|
-
conscientiousness: 'Conscientiousness',
|
|
111
|
-
extraversion: 'Extraversion',
|
|
112
|
-
agreeableness: 'Agreeableness',
|
|
113
|
-
resilience: 'Resilience',
|
|
114
|
-
decision_style: 'Decision',
|
|
115
|
-
risk_appetite: 'Risk',
|
|
116
|
-
communication: 'Communication',
|
|
117
|
-
influence: 'Influence',
|
|
118
|
-
leadership: 'Leadership'
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
function radarSvg(scores, size = 200) {
|
|
122
|
-
const keys = Object.keys(SCORE_LABELS);
|
|
123
|
-
const cx = size / 2, cy = size / 2, r = size * 0.38;
|
|
124
|
-
const n = keys.length;
|
|
125
|
-
|
|
126
|
-
let gridLines = '';
|
|
127
|
-
for (let level = 1; level <= 5; level++) {
|
|
128
|
-
const lr = r * level / 5;
|
|
129
|
-
let pts = [];
|
|
130
|
-
for (let i = 0; i < n; i++) {
|
|
131
|
-
const angle = (Math.PI * 2 * i / n) - Math.PI / 2;
|
|
132
|
-
pts.push(`${cx + lr * Math.cos(angle)},${cy + lr * Math.sin(angle)}`);
|
|
133
|
-
}
|
|
134
|
-
gridLines += `<polygon points="${pts.join(' ')}" fill="none" stroke="#334155" stroke-width="0.5"/>`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
let axes = '', labels = '', dataPoints = [];
|
|
138
|
-
for (let i = 0; i < n; i++) {
|
|
139
|
-
const angle = (Math.PI * 2 * i / n) - Math.PI / 2;
|
|
140
|
-
const x = cx + r * Math.cos(angle);
|
|
141
|
-
const y = cy + r * Math.sin(angle);
|
|
142
|
-
axes += `<line x1="${cx}" y1="${cy}" x2="${x}" y2="${y}" stroke="#334155" stroke-width="0.5"/>`;
|
|
143
|
-
|
|
144
|
-
const lx = cx + (r + 22) * Math.cos(angle);
|
|
145
|
-
const ly = cy + (r + 22) * Math.sin(angle);
|
|
146
|
-
const label = SCORE_LABELS[keys[i]] || keys[i];
|
|
147
|
-
labels += `<text x="${lx}" y="${ly}" text-anchor="middle" dominant-baseline="middle" fill="#64748b" font-size="9">${label}</text>`;
|
|
148
|
-
|
|
149
|
-
const val = (scores[keys[i]] || 0) / 5;
|
|
150
|
-
const dx = cx + r * val * Math.cos(angle);
|
|
151
|
-
const dy = cy + r * val * Math.sin(angle);
|
|
152
|
-
dataPoints.push(`${dx},${dy}`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const dataPolygon = `<polygon points="${dataPoints.join(' ')}" fill="rgba(56,189,248,0.2)" stroke="#38bdf8" stroke-width="1.5"/>`;
|
|
156
|
-
|
|
157
|
-
return `<svg viewBox="0 0 ${size} ${size}" class="radar">${gridLines}${axes}${dataPolygon}${labels}</svg>`;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function renderCard(card, index) {
|
|
161
|
-
const scores = card.scores || {};
|
|
162
|
-
const radar = radarSvg(scores);
|
|
163
|
-
|
|
164
|
-
return `
|
|
165
|
-
<div class="card" onclick="openModal(${index})">
|
|
166
|
-
<div class="card-header">
|
|
167
|
-
<div>
|
|
168
|
-
<div class="card-name">${card.name || 'Unknown'}</div>
|
|
169
|
-
<div class="card-role">${card.title || ''}${card.company ? ' @ ' + card.company : ''}</div>
|
|
170
|
-
</div>
|
|
171
|
-
<div class="card-badges">
|
|
172
|
-
<span class="badge badge-disc">${card.disc || '?'}</span>
|
|
173
|
-
<span class="badge badge-mbti">${card.mbti || '?'}</span>
|
|
174
|
-
</div>
|
|
175
|
-
</div>
|
|
176
|
-
${card.quote ? `<div class="card-quote">"${card.quote.slice(0, 120)}${card.quote.length > 120 ? '...' : ''}"</div>` : ''}
|
|
177
|
-
<div class="radar-container">${radar}</div>
|
|
178
|
-
${card.superpower ? `<div class="superpower">⚡ ${card.superpower}</div>` : ''}
|
|
179
|
-
${card.tags?.length ? `<div class="tags">${card.tags.map(t => `<span class="tag">${t}</span>`).join('')}</div>` : ''}
|
|
180
|
-
<div class="tips">
|
|
181
|
-
${card.icebreakers?.length ? `<div class="tip-row"><span class="tip-icon">💡</span><span class="tip-label">Icebreaker</span>${card.icebreakers[0]}</div>` : ''}
|
|
182
|
-
${card.dos?.length ? `<div class="tip-row"><span class="tip-icon">✅</span><span class="tip-label">Do</span>${card.dos[0]}</div>` : ''}
|
|
183
|
-
${card.donts?.length ? `<div class="tip-row"><span class="tip-icon">❌</span><span class="tip-label">Don't</span>${card.donts[0]}</div>` : ''}
|
|
184
|
-
</div>
|
|
185
|
-
</div>`;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function openModal(index) {
|
|
189
|
-
const card = cards[index];
|
|
190
|
-
const s = card.scores || {};
|
|
191
|
-
const modal = document.getElementById('modal-content');
|
|
192
|
-
|
|
193
|
-
modal.innerHTML = `
|
|
194
|
-
<button class="modal-close" onclick="closeModal()">×</button>
|
|
195
|
-
<h1 style="color:#38bdf8;margin-bottom:4px">${card.name}</h1>
|
|
196
|
-
<p style="color:#94a3b8">${card.title || ''}${card.company ? ' @ ' + card.company : ''}${card.location ? ' · ' + card.location : ''}</p>
|
|
197
|
-
${card.quote ? `<div class="card-quote" style="margin:16px 0">"${card.quote}"</div>` : ''}
|
|
198
|
-
|
|
199
|
-
<h2>Personality</h2>
|
|
200
|
-
<p><strong>DISC:</strong> ${card.disc || '?'} <strong>MBTI:</strong> ${card.mbti || '?'}</p>
|
|
201
|
-
<div style="display:flex;justify-content:center;margin:16px 0">${radarSvg(s, 260)}</div>
|
|
202
|
-
|
|
203
|
-
${card.expertise?.length ? `<h2>Expertise</h2><ul>${card.expertise.map(e => `<li>${e}</li>`).join('')}</ul>` : ''}
|
|
204
|
-
${card.superpower ? `<p><strong>⚡ Superpower:</strong> ${card.superpower}</p>` : ''}
|
|
205
|
-
|
|
206
|
-
<h2>How to Work With Them</h2>
|
|
207
|
-
${card.icebreakers?.length ? `<p><strong>💡 Icebreakers:</strong> ${card.icebreakers.join(', ')}</p>` : ''}
|
|
208
|
-
${card.dos?.length ? `<p><strong>✅ Do:</strong> ${card.dos.join(' · ')}</p>` : ''}
|
|
209
|
-
${card.donts?.length ? `<p><strong>❌ Don't:</strong> ${card.donts.join(' · ')}</p>` : ''}
|
|
210
|
-
${card.gifts?.length ? `<p><strong>🎁 Gifts:</strong> ${card.gifts.join(', ')}</p>` : ''}
|
|
211
|
-
|
|
212
|
-
${card.tags?.length ? `<h2>Tags</h2><div class="tags">${card.tags.map(t => `<span class="tag">${t}</span>`).join('')}</div>` : ''}
|
|
213
|
-
`;
|
|
214
|
-
|
|
215
|
-
document.getElementById('modal').classList.add('active');
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function closeModal() {
|
|
219
|
-
document.getElementById('modal').classList.remove('active');
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });
|
|
223
|
-
|
|
224
|
-
// Render
|
|
225
|
-
const grid = document.getElementById('grid');
|
|
226
|
-
grid.innerHTML = cards.map((card, i) => renderCard(card, i)).join('');
|
|
227
|
-
</script>
|
|
228
|
-
</body>
|
|
229
|
-
</html>
|