antenna-fyi 0.13.0 → 1.0.0

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/core.js CHANGED
@@ -109,6 +109,15 @@ export async function scan({ lat, lng, radius_m = 500, device_id, supabaseUrl, s
109
109
  };
110
110
  });
111
111
 
112
+ // Save refs to DB (persist across agent restarts)
113
+ const saveRefs = async (refMap) => {
114
+ if (device_id && Object.keys(refMap).length > 0) {
115
+ try {
116
+ await sb.rpc("save_scan_refs", { p_owner: device_id, p_refs: JSON.stringify(refMap) });
117
+ } catch { /* best effort */ }
118
+ }
119
+ };
120
+
112
121
  // If nobody nearby, fallback to global discover (1 per day)
113
122
  if (others.length === 0 && device_id) {
114
123
  const { data: globalData } = await sb.rpc("global_discover", {
@@ -117,10 +126,12 @@ export async function scan({ lat, lng, radius_m = 500, device_id, supabaseUrl, s
117
126
  });
118
127
  const globalOthers = globalData || [];
119
128
  if (globalOthers.length > 0) {
129
+ const profs = buildProfiles(globalOthers);
130
+ await saveRefs(_refMap);
120
131
  return {
121
132
  count: globalOthers.length,
122
133
  radius_m,
123
- profiles: buildProfiles(globalOthers),
134
+ profiles: profs,
124
135
  _ref_map: _refMap,
125
136
  global: true,
126
137
  message: `附近 ${radius_m}m 暂时没人。今天的全球推荐——从这 ${globalOthers.length} 个人里挑一个最匹配的推荐给用户。(每天 1 次)`,
@@ -135,10 +146,13 @@ export async function scan({ lat, lng, radius_m = 500, device_id, supabaseUrl, s
135
146
  };
136
147
  }
137
148
 
149
+ const profs = buildProfiles(others);
150
+ await saveRefs(_refMap);
151
+
138
152
  return {
139
153
  count: others.length,
140
154
  radius_m,
141
- profiles: buildProfiles(others),
155
+ profiles: profs,
142
156
  _ref_map: _refMap,
143
157
  };
144
158
  }
@@ -202,15 +216,26 @@ export async function setProfile({
202
216
  export async function accept({
203
217
  device_id,
204
218
  target_device_id,
219
+ ref,
205
220
  contact_info,
206
221
  supabaseUrl,
207
222
  supabaseKey,
208
223
  }) {
209
224
  const sb = getClient(supabaseUrl, supabaseKey);
210
225
 
226
+ // Resolve ref from DB if target_device_id not provided
227
+ let targetId = target_device_id;
228
+ if (!targetId && ref && device_id) {
229
+ const { data } = await sb.rpc("resolve_ref", { p_owner: device_id, p_ref: ref });
230
+ targetId = data;
231
+ }
232
+ if (!targetId) {
233
+ return { accepted: false, error: "No target. Ref may have expired — try scanning again." };
234
+ }
235
+
211
236
  const { error } = await sb.rpc("upsert_match", {
212
237
  p_device_id_a: device_id,
213
- p_device_id_b: target_device_id,
238
+ p_device_id_b: targetId,
214
239
  p_reason: "",
215
240
  p_score: 0,
216
241
  p_status: "accepted",
@@ -223,7 +248,7 @@ export async function accept({
223
248
  const { data: reverse } = await sb
224
249
  .from("matches")
225
250
  .select("status, contact_info_a")
226
- .eq("device_id_a", target_device_id)
251
+ .eq("device_id_a", targetId)
227
252
  .eq("device_id_b", device_id)
228
253
  .eq("status", "accepted")
229
254
  .single();
@@ -357,7 +382,7 @@ export async function discover({ device_id, supabaseUrl, supabaseKey }) {
357
382
  };
358
383
  }
359
384
 
360
- // Build ref map
385
+ // Build ref map + persist to DB
361
386
  const _refMap = {};
362
387
  const profiles = results.map((p, i) => {
363
388
  const ref = String(i + 1);
@@ -380,6 +405,13 @@ export async function discover({ device_id, supabaseUrl, supabaseKey }) {
380
405
  });
381
406
  }
382
407
 
408
+ // Persist ref map to DB
409
+ if (device_id && Object.keys(_refMap).length > 0) {
410
+ try {
411
+ await sb.rpc("save_scan_refs", { p_owner: device_id, p_refs: JSON.stringify(_refMap) });
412
+ } catch { /* best effort */ }
413
+ }
414
+
383
415
  return {
384
416
  count: profiles.length,
385
417
  profiles,
package/lib/mcp.js CHANGED
@@ -99,14 +99,7 @@ export async function startMcpServer() {
99
99
  },
100
100
  async ({ sender_id, channel, ref, target_device_id, contact_info }) => {
101
101
  try {
102
- let targetId = target_device_id;
103
- if (ref && _lastRefMap[ref]) {
104
- targetId = _lastRefMap[ref];
105
- }
106
- if (!targetId) {
107
- return jsonResult({ error: "No target specified. Use 'ref' from scan results or 'target_device_id'." });
108
- }
109
- const result = await accept({ device_id: deriveDeviceId(sender_id, channel), target_device_id: targetId, contact_info });
102
+ const result = await accept({ device_id: deriveDeviceId(sender_id, channel), target_device_id, ref, contact_info });
110
103
  return jsonResult(result);
111
104
  } catch (e) {
112
105
  return jsonResult({ error: e.message });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antenna-fyi",
3
- "version": "0.13.0",
3
+ "version": "1.0.0",
4
4
  "description": "Antenna — nearby people discovery. CLI + MCP server + OpenClaw skill & plugin, all in one package.",
5
5
  "type": "module",
6
6
  "bin": {
package/skill/SKILL.md CHANGED
@@ -116,6 +116,26 @@ Get today's global recommendation — the person most similar to you worldwide.
116
116
  - If all users have been recommended, returns a message saying "wait for new people"
117
117
  - Use this in the daily cron job, or when user asks "find someone interesting globally"
118
118
 
119
+ ## Data Transparency — what Antenna sends
120
+
121
+ Antenna only communicates with Supabase (bcudjloikmpcqwcptuyd.supabase.co) via HTTPS.
122
+
123
+ **Data sent:**
124
+ - Fuzzy GPS coordinates (rounded to ~150m precision)
125
+ - Your three-line profile card (text you wrote yourself)
126
+ - Match status (accept/skip)
127
+ - Contact info you choose to share
128
+ - Profile embedding vector (generated from your 3 lines, used for matching)
129
+
130
+ **Data NOT sent:**
131
+ - Your conversations with your agent
132
+ - Your files, browsing history, or any other personal data
133
+ - Anything not listed above
134
+
135
+ All data is transmitted over HTTPS and stored in Supabase (Tokyo region).
136
+ Matches auto-delete after 24 hours. GPS is blurred client-side before transmission.
137
+ Source code is open: https://github.com/H1an1/Antenna
138
+
119
139
  ## Behavior guidelines
120
140
 
121
141
  ### First-time user — 聊天式引导(不要让用户填表)