antenna-fyi 1.3.26 → 1.3.28

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/lib/cli.js CHANGED
@@ -66,12 +66,11 @@ export async function handleScan(f) {
66
66
 
67
67
  export async function handleProfile(f) {
68
68
  const id = resolveId(f);
69
- if (!id) return console.error("Usage: antenna profile --id <platform>:<user_id> [--name Yi --emoji 🦦 --personal-description '...' --looking-for '...' --conversation-style '...'].']");
69
+ if (!id) return console.error("Usage: antenna profile --id <platform>:<user_id> [--name Yi --personal-description '...' --looking-for '...' --conversation-style '...'].']");
70
70
  if (f.name || f["personal-description"] || f["looking-for"] || f["conversation-style"] || f["more-information"] || f.visible !== undefined || f.hide !== undefined) {
71
71
  const visible = f.hide ? false : (f.visible !== undefined ? f.visible === 'true' || f.visible === true : undefined);
72
72
  const payload = { device_id: id };
73
73
  if (f.name) payload.display_name = f.name;
74
- if (f.emoji) payload.emoji = f.emoji;
75
74
  if (f["personal-description"] !== undefined) payload.line1 = f["personal-description"];
76
75
  if (f["looking-for"] !== undefined) payload.line2 = f["looking-for"];
77
76
  if (f["conversation-style"] !== undefined) payload.line3 = f["conversation-style"];
@@ -337,7 +336,6 @@ export async function handleSetup(f) {
337
336
  if (!id) { rl.close(); return console.error("Device ID is required."); }
338
337
 
339
338
  const name = await ask("Display name: ");
340
- const emoji = (await ask("Emoji (default šŸ‘¤): ")) || "šŸ‘¤";
341
339
  const personalDesc = await ask("Personal description — who you are, what you do: ");
342
340
  const lookingFor = await ask("Looking for — the kind of people you want to meet: ");
343
341
  const convStyle = await ask("Conversation style — the type of conversations you want: ");
@@ -347,14 +345,14 @@ export async function handleSetup(f) {
347
345
  const data = await setProfile({
348
346
  device_id: id,
349
347
  display_name: name || null,
350
- emoji,
348
+
351
349
  line1: personalDesc || null,
352
350
  line2: lookingFor || null,
353
351
  line3: convStyle || null,
354
352
  });
355
353
 
356
354
  console.log("\nāœ… Profile saved!\n");
357
- console.log(` ${emoji} ${name || "Anonymous"}`);
355
+ console.log(` ${name || "Anonymous"}`);
358
356
  if (personalDesc) console.log(` ${personalDesc}`);
359
357
  if (lookingFor) console.log(` ${lookingFor}`);
360
358
  if (convStyle) console.log(` ${convStyle}`);
@@ -997,7 +995,7 @@ export function printHelp() {
997
995
  Usage:
998
996
  antenna scan --lat 39.99 --lng 116.48 [--radius 500] (max 1000) [--id <platform>:<user_id>]
999
997
  antenna checkin --id <platform>:<user_id> --lat 39.99 --lng 116.48
1000
- antenna profile --id <platform>:<user_id> [--name Yi --emoji 🦦 --personal-description '...']
998
+ antenna profile --id <platform>:<user_id> [--name Yi --personal-description '...']
1001
999
  antenna accept --id <platform>:<user_id> --target <ref_or_device_id> [--contact 'WeChat: yi']
1002
1000
  antenna pass --id <platform>:<user_id> --target <ref_or_device_id> (or --ref 1)
1003
1001
  antenna matches --id <platform>:<user_id>
package/lib/core.js CHANGED
@@ -45,6 +45,22 @@ async function generateMatchReason(myLines, theirLines) {
45
45
  } catch { return null; }
46
46
  }
47
47
 
48
+ async function generateArchetypeReason(archetype, profileText) {
49
+ try {
50
+ const res = await fetch(`${_url || DEFAULT_URL}/functions/v1/generate-archetype`, {
51
+ method: "POST",
52
+ headers: {
53
+ "Content-Type": "application/json",
54
+ "Authorization": `Bearer ${process.env.ANTENNA_SUPABASE_KEY || process.env.ANTENNA_KEY || DEFAULT_KEY}`,
55
+ },
56
+ body: JSON.stringify({ archetype, profile_text: profileText }),
57
+ });
58
+ if (!res.ok) return null;
59
+ const data = await res.json();
60
+ return data || null;
61
+ } catch { return null; }
62
+ }
63
+
48
64
  export function getClient(url, key) {
49
65
  const u = url || process.env.ANTENNA_SUPABASE_URL || process.env.ANTENNA_URL || DEFAULT_URL;
50
66
  const k = key || process.env.ANTENNA_SUPABASE_KEY || process.env.ANTENNA_KEY || DEFAULT_KEY;
@@ -311,6 +327,7 @@ export async function setProfile({
311
327
  // Read back profile to get slug for public page link
312
328
  let publicUrl = null;
313
329
  let bindUrl = null;
330
+ let archetypeResult = null;
314
331
  try {
315
332
  const profile = await getProfile({ device_id, supabaseUrl, supabaseKey });
316
333
  if (profile?.profile_slug) {
@@ -318,6 +335,50 @@ export async function setProfile({
318
335
  }
319
336
  } catch {}
320
337
 
338
+ // Generate personalized archetype description via LLM
339
+ try {
340
+ const profileText = [line1, line2, line3, matching_context].filter(Boolean).join(". ");
341
+ if (profileText) {
342
+ // Simple keyword-based archetype detection (same logic as frontend)
343
+ const corpus = profileText.toLowerCase();
344
+ const archetypeKeywords = {
345
+ Prometheus: ["ai", "agent", "llm", "founder", "startup", "build", "developer", "hacker", "tools", "\u667a\u80fd\u4f53", "\u521b\u4e1a", "\u5f00\u53d1"],
346
+ Athena: ["product", "strategy", "research", "design", "craft", "pm", "ux", "\u4ea7\u54c1", "\u8bbe\u8ba1", "\u7814\u7a76"],
347
+ Hermes: ["network", "connect", "community", "social", "bridge", "\u793e\u4ea4", "\u8fde\u63a5", "\u793e\u533a"],
348
+ Apollo: ["music", "media", "content", "creator", "writing", "taste", "\u97f3\u4e50", "\u5185\u5bb9", "\u521b\u4f5c"],
349
+ Artemis: ["independent", "explore", "freelance", "health", "outdoor", "\u72ec\u7acb", "\u63a2\u7d22"],
350
+ Aphrodite: ["beauty", "brand", "fashion", "relationship", "\u7f8e", "\u54c1\u724c", "\u65f6\u5c1a"],
351
+ Dionysus: ["event", "culture", "party", "art", "festival", "\u6d3b\u52a8", "\u6587\u5316", "\u827a\u672f"],
352
+ Hades: ["finance", "invest", "infrastructure", "backend", "security", "\u6295\u8d44", "\u91d1\u878d", "\u67b6\u6784"],
353
+ Persephone: ["transform", "cross", "research", "academic", "bridge", "\u8de8\u754c", "\u7814\u7a76", "\u5b66\u672f"],
354
+ Odysseus: ["founder", "journey", "resilience", "travel", "startup", "\u521b\u4e1a", "\u65c5\u884c"],
355
+ };
356
+ let bestArchetype = "Prometheus";
357
+ let bestScore = 0;
358
+ for (const [role, keywords] of Object.entries(archetypeKeywords)) {
359
+ const score = keywords.reduce((s, kw) => s + (corpus.includes(kw) ? 1 : 0), 0);
360
+ if (score > bestScore) { bestScore = score; bestArchetype = role; }
361
+ }
362
+ archetypeResult = await generateArchetypeReason(bestArchetype, profileText);
363
+ if (archetypeResult?.reason) {
364
+ archetypeResult.archetype = bestArchetype;
365
+ // Write archetype back to matching_context so dashboard can display it
366
+ try {
367
+ const profile = await getProfile({ device_id, supabaseUrl, supabaseKey });
368
+ let ctx = {};
369
+ try { ctx = JSON.parse(profile?.matching_context || "{}"); } catch {}
370
+ ctx.archetypeOverride = { name: bestArchetype, reason: archetypeResult.reason, reasonZh: archetypeResult.reasonZh };
371
+ await sb.rpc("upsert_profile", {
372
+ p_device_id: device_id,
373
+ p_matching_context: JSON.stringify(ctx),
374
+ });
375
+ } catch {}
376
+ }
377
+ }
378
+ } catch (e) {
379
+ console.error("Archetype generation failed (non-fatal):", e.message);
380
+ }
381
+
321
382
  // Auto-generate GPS bind link
322
383
  try {
323
384
  const bind = await createBindToken({ device_id, supabaseUrl, supabaseKey });
@@ -328,6 +389,7 @@ export async function setProfile({
328
389
  ...data,
329
390
  public_url: publicUrl,
330
391
  gps_bind_url: bindUrl,
392
+ archetype: archetypeResult || null,
331
393
  next_step: "Send the public_url and gps_bind_url to the user. The GPS link should be opened on their phone to share location.",
332
394
  };
333
395
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antenna-fyi",
3
- "version": "1.3.26",
3
+ "version": "1.3.28",
4
4
  "description": "Antenna \u2014 nearby people discovery. CLI + MCP server + OpenClaw skill & plugin, all in one package.",
5
5
  "type": "module",
6
6
  "bin": {