antenna-fyi 1.2.42 → 1.3.1

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/README.md CHANGED
@@ -12,26 +12,26 @@ npm install -g antenna-fyi
12
12
 
13
13
  ```bash
14
14
  # Create your profile card
15
- antenna setup --id telegram:123
15
+ antenna setup --id <platform>:<user_id>
16
16
 
17
17
  # Scan for nearby people
18
- antenna scan --lat 39.99 --lng 116.48 --radius 500 --id telegram:123
18
+ antenna scan --lat 39.99 --lng 116.48 --radius 500 --id <platform>:<user_id>
19
19
 
20
20
  # Check in at a location
21
- antenna checkin --id telegram:123 --lat 39.99 --lng 116.48
21
+ antenna checkin --id <platform>:<user_id> --lat 39.99 --lng 116.48
22
22
 
23
23
  # View/edit your profile
24
- antenna profile --id telegram:123
25
- antenna profile --id telegram:123 --name Yi --emoji 🦦 --line1 'Product Designer'
24
+ antenna profile --id <platform>:<user_id>
25
+ antenna profile --id <platform>:<user_id> --name Yi --emoji 🦦 --line1 'Product Designer'
26
26
 
27
27
  # Accept a match
28
- antenna accept --id telegram:123 --target telegram:789 --contact 'WeChat: yi'
28
+ antenna accept --id <platform>:<user_id> --target <ref_or_id> --contact 'WeChat: yi'
29
29
 
30
30
  # Check match status
31
- antenna matches --id telegram:123
31
+ antenna matches --id <platform>:<user_id>
32
32
 
33
33
  # Show status
34
- antenna status --id telegram:123
34
+ antenna status --id <platform>:<user_id>
35
35
  ```
36
36
 
37
37
  ## MCP Server
package/lib/cli.js CHANGED
@@ -31,7 +31,7 @@ export function parseFlags(args) {
31
31
  }
32
32
 
33
33
  export async function handleScan(f) {
34
- if (!f.lat && !f.lng && !f.id) return console.error("Usage: antenna scan --lat 39.99 --lng 116.48 [--radius 500] (max 1000) [--id telegram:123]\n Or just: antenna scan --id telegram:123 (uses saved location from GPS bind)");
34
+ if (!f.lat && !f.lng && !f.id) return console.error("Usage: antenna scan --lat 39.99 --lng 116.48 [--radius 500] (max 1000) [--id <platform>:<user_id>]\n Or just: antenna scan --id <platform>:<user_id> (uses saved location from GPS bind)");
35
35
  const result = await scan({
36
36
  lat: f.lat ? +f.lat : undefined,
37
37
  lng: f.lng ? +f.lng : undefined,
@@ -64,7 +64,7 @@ export async function handleScan(f) {
64
64
  }
65
65
 
66
66
  export async function handleProfile(f) {
67
- if (!f.id) return console.error("Usage: antenna profile --id telegram:123 [--name Yi --emoji 🦦 --line1 '...' --line2 '...' --line3 '...']");
67
+ if (!f.id) return console.error("Usage: antenna profile --id <platform>:<user_id> [--name Yi --emoji 🦦 --line1 '...' --line2 '...' --line3 '...']");
68
68
  if (f.name || f.line1 || f.line2 || f.line3 || f.visible !== undefined || f.hide !== undefined) {
69
69
  const visible = f.hide ? false : (f.visible !== undefined ? f.visible === 'true' || f.visible === true : undefined);
70
70
  const data = await setProfile({
@@ -89,7 +89,7 @@ export async function handleProfile(f) {
89
89
  }
90
90
 
91
91
  export async function handleAccept(f) {
92
- if (!f.id || (!f.target && !f.ref)) return console.error("Usage: antenna accept --id telegram:123 --ref 1 [--contact 'WeChat: yi']\n antenna accept --id telegram:123 --target telegram:789 [--contact 'WeChat: yi']");
92
+ if (!f.id || (!f.target && !f.ref)) return console.error("Usage: antenna accept --id <platform>:<user_id> --ref 1 [--contact 'WeChat: yi']\n antenna accept --id <platform>:<user_id> --target <ref_or_device_id> [--contact 'WeChat: yi']");
93
93
  const result = await accept({
94
94
  device_id: f.id,
95
95
  target_device_id: f.target || null,
@@ -101,7 +101,7 @@ export async function handleAccept(f) {
101
101
  }
102
102
 
103
103
  export async function handleCheckin(f) {
104
- if (!f.id || !f.lat || !f.lng) return console.error("Usage: antenna checkin --id telegram:123 --lat 39.99 --lng 116.48 [--place '三里屯']");
104
+ if (!f.id || !f.lat || !f.lng) return console.error("Usage: antenna checkin --id <platform>:<user_id> --lat 39.99 --lng 116.48 [--place '三里屯']");
105
105
  const result = await checkin({
106
106
  lat: +f.lat,
107
107
  lng: +f.lng,
@@ -111,7 +111,7 @@ export async function handleCheckin(f) {
111
111
  }
112
112
 
113
113
  export async function handleMatches(f) {
114
- if (!f.id) return console.error("Usage: antenna matches --id telegram:123");
114
+ if (!f.id) return console.error("Usage: antenna matches --id <platform>:<user_id>");
115
115
  const result = await checkMatches({ device_id: f.id });
116
116
  if (!result.mutual_matches.length && !result.incoming_accepts.length) {
117
117
  return console.log(result.message);
@@ -131,7 +131,7 @@ export async function handleMatches(f) {
131
131
  }
132
132
 
133
133
  export async function handleDiscover(f) {
134
- if (!f.id) return console.error("Usage: antenna discover --id telegram:123");
134
+ if (!f.id) return console.error("Usage: antenna discover --id <platform>:<user_id>");
135
135
  const result = await discover({ device_id: f.id });
136
136
  if (result.count === 0) return console.log(result.message || "🌍 No global recommendation available right now.");
137
137
  console.log(`🌍 Global discover:\n`);
@@ -162,7 +162,7 @@ export async function handleEvent(f) {
162
162
  }
163
163
 
164
164
  if (f.end) {
165
- if (!f.code || !f.id) return console.error("Usage: antenna event --end --code abc123 --id telegram:123");
165
+ if (!f.code || !f.id) return console.error("Usage: antenna event --end --code abc123 --id <platform>:<user_id>");
166
166
  const result = await endEvent({ code: f.code, device_id: f.id });
167
167
  if (result.ended) {
168
168
  console.log(`\n✅ Event ended.\n`);
@@ -173,15 +173,15 @@ export async function handleEvent(f) {
173
173
  }
174
174
 
175
175
  if (f.checkin) {
176
- if (!f.code || !f.id) return console.error("Usage: antenna event --checkin --code abc123 --id telegram:123 [--lat 34.05 --lng -118.24]");
176
+ if (!f.code || !f.id) return console.error("Usage: antenna event --checkin --code abc123 --id <platform>:<user_id> [--lat 34.05 --lng -118.24]");
177
177
  const result = await eventCheckin({ code: f.code, device_id: f.id, lat: f.lat ? +f.lat : undefined, lng: f.lng ? +f.lng : undefined });
178
178
  console.log(`\n✅ Checked in to event.\n`);
179
179
  return;
180
180
  }
181
181
 
182
182
  if (f.create || (!f.join && !f.scan && !f.end && !f.update && !f.approve && !f.reject && !f['add-host'] && f.name)) {
183
- if (!f.name) return console.error("Usage: antenna event --create --name 'AI Meetup' --id telegram:123 --starts-at '2026-04-19T14:00' --ends-at '2026-04-19T18:00' [--lat 34.05 --lng -118.25] [--desc 'description'] [--og-image 'url'] [--requires-approval] [--screening-questions 'Q1|Q2']");
184
- if (!f.id) return console.error("❌ --id is required (e.g. --id telegram:123). Creator identity needed to manage the event.");
183
+ if (!f.name) return console.error("Usage: antenna event --create --name 'AI Meetup' --id <platform>:<user_id> --starts-at '2026-04-19T14:00' --ends-at '2026-04-19T18:00' [--lat 34.05 --lng -118.25] [--desc 'description'] [--og-image 'url'] [--requires-approval] [--screening-questions 'Q1|Q2']");
184
+ if (!f.id) return console.error("❌ --id is required (e.g. --id <platform>:<user_id>). Creator identity needed to manage the event.");
185
185
  if (!f['starts-at'] || !f['ends-at']) return console.error("❌ --starts-at and --ends-at are required. Example: --starts-at '2026-04-19T14:00' --ends-at '2026-04-19T18:00'");
186
186
  const result = await createEvent({ name: f.name, device_id: f.id, lat: f.lat ? +f.lat : undefined, lng: f.lng ? +f.lng : undefined, starts_at: f['starts-at'], ends_at: f['ends-at'], description: f.desc || undefined, og_image: f['og-image'] || undefined, requires_approval: f['requires-approval'] === true || f['requires-approval'] === 'true' || undefined, screening_questions: f['screening-questions'] ? f['screening-questions'].split('|') : undefined });
187
187
  console.log(`\n🎉 Event created!\n`);
@@ -193,7 +193,7 @@ export async function handleEvent(f) {
193
193
  }
194
194
 
195
195
  if (f.join) {
196
- if (!f.code || !f.id) return console.error("Usage: antenna event --join --code abc123 --id telegram:123");
196
+ if (!f.code || !f.id) return console.error("Usage: antenna event --join --code abc123 --id <platform>:<user_id>");
197
197
  const result = await joinEvent({ code: f.code, device_id: f.id, lat: f.lat ? +f.lat : undefined, lng: f.lng ? +f.lng : undefined, application_context: f['application-context'] || undefined });
198
198
  if (result.joined) {
199
199
  if (result.status === 'pending') {
@@ -213,7 +213,7 @@ export async function handleEvent(f) {
213
213
  }
214
214
 
215
215
  if (f.scan) {
216
- if (!f.code) return console.error("Usage: antenna event --scan --code abc123 [--id telegram:123]");
216
+ if (!f.code) return console.error("Usage: antenna event --scan --code abc123 [--id <platform>:<user_id>]");
217
217
  const result = await eventScan({ code: f.code, device_id: f.id || null });
218
218
  if (result.count === 0) return console.log("\n🏟️ No participants yet.\n");
219
219
  console.log(`\n🏟️ ${result.count} joined, ${result.checked_in_count || 0} checked in:\n`);
@@ -230,7 +230,7 @@ export async function handleEvent(f) {
230
230
  }
231
231
 
232
232
  if (f.approve) {
233
- if (!f.code || !f.id || !f.ref) return console.error("Usage: antenna event --approve --code abc123 --id telegram:123 --ref 1");
233
+ if (!f.code || !f.id || !f.ref) return console.error("Usage: antenna event --approve --code abc123 --id <platform>:<user_id> --ref 1");
234
234
  const result = await approveParticipant({ code: f.code, device_id: f.id, ref: f.ref });
235
235
  if (result.approved) {
236
236
  console.log("\n✅ Participant approved\n");
@@ -241,7 +241,7 @@ export async function handleEvent(f) {
241
241
  }
242
242
 
243
243
  if (f.reject) {
244
- if (!f.code || !f.id || !f.ref) return console.error("Usage: antenna event --reject --code abc123 --id telegram:123 --ref 1");
244
+ if (!f.code || !f.id || !f.ref) return console.error("Usage: antenna event --reject --code abc123 --id <platform>:<user_id> --ref 1");
245
245
  const result = await rejectParticipant({ code: f.code, device_id: f.id, ref: f.ref });
246
246
  if (result.rejected) {
247
247
  console.log("\n✅ Participant rejected\n");
@@ -252,7 +252,7 @@ export async function handleEvent(f) {
252
252
  }
253
253
 
254
254
  if (f.update) {
255
- if (!f.code || !f.id) return console.error("Usage: antenna event --update --code abc123 --id telegram:123 [--name 'New Name'] [--desc 'New desc']");
255
+ if (!f.code || !f.id) return console.error("Usage: antenna event --update --code abc123 --id <platform>:<user_id> [--name 'New Name'] [--desc 'New desc']");
256
256
  const result = await updateEvent({ code: f.code, device_id: f.id, name: f.name, description: f.desc, og_image: f['og-image'], lat: f.lat ? +f.lat : undefined, lng: f.lng ? +f.lng : undefined, starts_at: f['starts-at'], ends_at: f['ends-at'] });
257
257
  if (result.updated) {
258
258
  console.log("\n✅ Event updated\n");
@@ -263,7 +263,7 @@ export async function handleEvent(f) {
263
263
  }
264
264
 
265
265
  if (f['add-host']) {
266
- if (!f.code || !f.id || !f.ref) return console.error("Usage: antenna event --add-host --code abc123 --id telegram:123 --ref 1");
266
+ if (!f.code || !f.id || !f.ref) return console.error("Usage: antenna event --add-host --code abc123 --id <platform>:<user_id> --ref 1");
267
267
  const result = await addCohost({ code: f.code, device_id: f.id, ref: f.ref });
268
268
  if (result.added) {
269
269
  console.log("\n✅ Co-host added\n");
@@ -274,16 +274,16 @@ export async function handleEvent(f) {
274
274
  }
275
275
 
276
276
  console.log(`Usage:
277
- antenna event --create --name 'AI Meetup' --starts-at '...' --ends-at '...' [--id telegram:123] [--lat 34.05 --lng -118.25] [--desc 'description'] [--og-image 'url'] [--requires-approval] [--screening-questions 'Q1|Q2']
278
- antenna event --join --code abc123 --id telegram:123
279
- antenna event --scan --code abc123 [--id telegram:123]
280
- antenna event --checkin --code abc123 --id telegram:123 [--lat 34.05 --lng -118.24]
281
- antenna event --end --code abc123 --id telegram:123
277
+ antenna event --create --name 'AI Meetup' --starts-at '...' --ends-at '...' [--id <platform>:<user_id>] [--lat 34.05 --lng -118.25] [--desc 'description'] [--og-image 'url'] [--requires-approval] [--screening-questions 'Q1|Q2']
278
+ antenna event --join --code abc123 --id <platform>:<user_id>
279
+ antenna event --scan --code abc123 [--id <platform>:<user_id>]
280
+ antenna event --checkin --code abc123 --id <platform>:<user_id> [--lat 34.05 --lng -118.24]
281
+ antenna event --end --code abc123 --id <platform>:<user_id>
282
282
  antenna event --upload-image --code abc123 --file /path/to/image.png`);
283
283
  }
284
284
 
285
285
  export async function handleBind(f) {
286
- if (!f.id) return console.error("Usage: antenna bind --id telegram:123");
286
+ if (!f.id) return console.error("Usage: antenna bind --id <platform>:<user_id>");
287
287
  const result = await createBindToken({ device_id: f.id });
288
288
  console.log("\n🔗 GPS Binding Link:\n");
289
289
  console.log(` ${result.url}\n`);
@@ -292,8 +292,8 @@ export async function handleBind(f) {
292
292
  }
293
293
 
294
294
  export async function handlePass(f) {
295
- if (!f.id) return console.error("Usage: antenna pass --id telegram:123 --target telegram:789");
296
- if (!f.target && !f.ref) return console.error("Usage: antenna pass --id telegram:123 --target telegram:789 (or --ref 1)");
295
+ if (!f.id) return console.error("Usage: antenna pass --id <platform>:<user_id> --target <ref_or_device_id>");
296
+ if (!f.target && !f.ref) return console.error("Usage: antenna pass --id <platform>:<user_id> --target <ref_or_device_id> (or --ref 1)");
297
297
  const result = await passUser({
298
298
  device_id: f.id,
299
299
  target_device_id: f.target,
@@ -308,7 +308,7 @@ export async function handleSetup(f) {
308
308
 
309
309
  console.log("\n📡 Antenna Setup — 创建你的名片\n");
310
310
 
311
- const id = f.id || await ask("Your device ID (e.g. telegram:123): ");
311
+ const id = f.id || await ask("Your device ID (e.g. discord:12345, hermes:myname): ");
312
312
  if (!id) { rl.close(); return console.error("Device ID is required."); }
313
313
 
314
314
  const name = await ask("Display name: ");
@@ -499,7 +499,7 @@ export function handleInstallHermesPlugin() {
499
499
  export async function handleWatch(f) {
500
500
  const id = f.id;
501
501
  if (!id) {
502
- console.error("❌ --id required (e.g. --id telegram:123)");
502
+ console.error("❌ --id required (e.g. --id <platform>:<user_id>)");
503
503
  process.exit(1);
504
504
  }
505
505
 
@@ -870,19 +870,19 @@ export function printHelp() {
870
870
  console.log(`📡 Antenna — nearby people discovery
871
871
 
872
872
  Usage:
873
- antenna scan --lat 39.99 --lng 116.48 [--radius 500] (max 1000) [--id telegram:123]
874
- antenna checkin --id telegram:123 --lat 39.99 --lng 116.48
875
- antenna profile --id telegram:123 [--name Yi --emoji 🦦 --line1 '...']
876
- antenna accept --id telegram:123 --target telegram:789 [--contact 'WeChat: yi']
877
- antenna pass --id telegram:123 --target telegram:789 (or --ref 1)
878
- antenna matches --id telegram:123
879
- antenna discover --id telegram:123
880
- antenna event --create --name 'AI Meetup' --starts-at '...' --ends-at '...' [--lat 34.05 --lng -118.25] [--desc '...'] [--og-image 'url'] [--requires-approval] [--screening-questions 'Q1|Q2'] | --join --code abc123 | --scan --code abc123 | --end --code abc123 --id telegram:123 | --upload-image --code abc123 --file /path/to/image.png | --update --code abc123 --name 'New Name' | --approve --code abc123 --ref 1 | --reject --code abc123 --ref 1 | --add-host --code abc123 --ref 1
881
- antenna watch --id telegram:123 [--push hermes|openclaw|terminal] Watch for new matches in real-time (Ctrl+C to stop)
882
- antenna bind --id telegram:123
873
+ antenna scan --lat 39.99 --lng 116.48 [--radius 500] (max 1000) [--id <platform>:<user_id>]
874
+ antenna checkin --id <platform>:<user_id> --lat 39.99 --lng 116.48
875
+ antenna profile --id <platform>:<user_id> [--name Yi --emoji 🦦 --line1 '...']
876
+ antenna accept --id <platform>:<user_id> --target <ref_or_device_id> [--contact 'WeChat: yi']
877
+ antenna pass --id <platform>:<user_id> --target <ref_or_device_id> (or --ref 1)
878
+ antenna matches --id <platform>:<user_id>
879
+ antenna discover --id <platform>:<user_id>
880
+ antenna event --create --name 'AI Meetup' --starts-at '...' --ends-at '...' [--lat 34.05 --lng -118.25] [--desc '...'] [--og-image 'url'] [--requires-approval] [--screening-questions 'Q1|Q2'] | --join --code abc123 | --scan --code abc123 | --end --code abc123 --id <platform>:<user_id> | --upload-image --code abc123 --file /path/to/image.png | --update --code abc123 --name 'New Name' | --approve --code abc123 --ref 1 | --reject --code abc123 --ref 1 | --add-host --code abc123 --ref 1
881
+ antenna watch --id <platform>:<user_id> [--push hermes|openclaw|terminal] Watch for new matches in real-time (Ctrl+C to stop)
882
+ antenna bind --id <platform>:<user_id>
883
883
  antenna serve Start MCP server (stdio transport)
884
- antenna setup Interactive profile setup [--id telegram:123]
885
- antenna status Show config & status [--id telegram:123]
884
+ antenna setup Interactive profile setup [--id <platform>:<user_id>]
885
+ antenna status Show config & status [--id <platform>:<user_id>]
886
886
  antenna install-skill Install SKILL.md (detects OpenClaw + Hermes)
887
887
  antenna install-plugin Copy OpenClaw plugin template to cwd
888
888
  antenna install-hermes One-step Hermes setup (Plugin + Skill + deps)
@@ -21,7 +21,7 @@ SCAN_SCHEMA = {
21
21
  },
22
22
  "channel": {
23
23
  "type": "string",
24
- "description": "Platform name (telegram, discord, etc.)",
24
+ "description": "Platform name (any platform: telegram, discord, webchat, signal, slack, etc.)",
25
25
  },
26
26
  },
27
27
  "required": ["sender_id", "channel"],
@@ -148,7 +148,7 @@ PASS_SCHEMA = {
148
148
  "type": "object",
149
149
  "properties": {
150
150
  "sender_id": {"type": "string", "description": "The sender's user ID"},
151
- "channel": {"type": "string", "description": "Platform name"},
151
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
152
152
  "ref": {
153
153
  "type": "string",
154
154
  "description": "Ref number from scan/discover results (e.g. '1')",
@@ -172,7 +172,7 @@ DISCOVER_SCHEMA = {
172
172
  "type": "object",
173
173
  "properties": {
174
174
  "sender_id": {"type": "string", "description": "The sender's user ID"},
175
- "channel": {"type": "string", "description": "Platform name"},
175
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
176
176
  },
177
177
  "required": ["sender_id", "channel"],
178
178
  },
@@ -189,7 +189,7 @@ EVENT_CREATE_SCHEMA = {
189
189
  "properties": {
190
190
  "name": {"type": "string", "description": "Event name"},
191
191
  "sender_id": {"type": "string", "description": "The sender's user ID"},
192
- "channel": {"type": "string", "description": "Platform name"},
192
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
193
193
  "lat": {"type": "number", "description": "Event latitude"},
194
194
  "lng": {"type": "number", "description": "Event longitude"},
195
195
  "starts_at": {"type": "string", "description": "Start time ISO (required)"},
@@ -211,7 +211,7 @@ EVENT_JOIN_SCHEMA = {
211
211
  "properties": {
212
212
  "code": {"type": "string", "description": "Event code"},
213
213
  "sender_id": {"type": "string", "description": "The sender's user ID"},
214
- "channel": {"type": "string", "description": "Platform name"},
214
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
215
215
  "lat": {"type": "number", "description": "Latitude (optional, for auto-checkin)"},
216
216
  "lng": {"type": "number", "description": "Longitude (optional, for auto-checkin)"},
217
217
  "application_context": {"type": "string", "description": "Application context from screening conversation"},
@@ -228,7 +228,7 @@ EVENT_SCAN_SCHEMA = {
228
228
  "properties": {
229
229
  "code": {"type": "string", "description": "Event code"},
230
230
  "sender_id": {"type": "string", "description": "The sender's user ID"},
231
- "channel": {"type": "string", "description": "Platform name"},
231
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
232
232
  },
233
233
  "required": ["code", "sender_id", "channel"],
234
234
  },
@@ -242,7 +242,7 @@ EVENT_END_SCHEMA = {
242
242
  "properties": {
243
243
  "code": {"type": "string", "description": "Event code"},
244
244
  "sender_id": {"type": "string", "description": "The sender's user ID"},
245
- "channel": {"type": "string", "description": "Platform name"},
245
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
246
246
  },
247
247
  "required": ["code", "sender_id", "channel"],
248
248
  },
@@ -270,7 +270,7 @@ EVENT_CHECKIN_SCHEMA = {
270
270
  "properties": {
271
271
  "code": {"type": "string", "description": "Event code"},
272
272
  "sender_id": {"type": "string", "description": "The sender's user ID"},
273
- "channel": {"type": "string", "description": "Platform name"},
273
+ "channel": {"type": "string", "description": "Platform name (any platform works)"},
274
274
  "lat": {"type": "number", "description": "Latitude (optional)"},
275
275
  "lng": {"type": "number", "description": "Longitude (optional)"},
276
276
  },
@@ -242,7 +242,8 @@ def handle_check_matches(params: dict) -> str:
242
242
  prof = sb.rpc("get_profile", {"p_device_id": m["device_id_b"]}).execute()
243
243
  p = prof.data or {}
244
244
  mutual.append({
245
- "device_id": m["device_id_b"],
245
+ "ref": str(len(mutual) + 1),
246
+ "_device_id": m["device_id_b"],
246
247
  "name": p.get("display_name") or "匿名",
247
248
  "emoji": p.get("emoji") or "👤",
248
249
  "their_contact": rev.get("contact_info_a"),
@@ -257,7 +258,8 @@ def handle_check_matches(params: dict) -> str:
257
258
  prof = sb.rpc("get_profile", {"p_device_id": m["device_id_a"]}).execute()
258
259
  p = prof.data or {}
259
260
  inc_only.append({
260
- "device_id": m["device_id_a"],
261
+ "ref": str(len(inc_only) + 1),
262
+ "_device_id": m["device_id_a"],
261
263
  "name": p.get("display_name") or "匿名",
262
264
  "emoji": p.get("emoji") or "👤",
263
265
  "line1": p.get("line1"),
@@ -499,7 +501,6 @@ def handle_event_scan(params: dict) -> str:
499
501
  if not others:
500
502
  return _ok({"count": 0, "profiles": [], "message": "活动里还没有其他人。"})
501
503
 
502
- global _last_ref_map
503
504
  global _last_ref_map
504
505
  _last_ref_map = {}
505
506
  checked_in_count = 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antenna-fyi",
3
- "version": "1.2.42",
3
+ "version": "1.3.1",
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
@@ -10,7 +10,7 @@ You have access to Antenna for location-based social discovery.
10
10
 
11
11
  **How to call Antenna:**
12
12
  - If you have Antenna plugin tools registered (antenna_scan, antenna_profile, etc.) — use them directly.
13
- - If not, use CLI: `antenna <command> [flags]`. Example: `antenna scan --id telegram:123`. The CLI supports all the same features.
13
+ - If not, use CLI: `antenna <command> [flags]`. Example: `antenna scan --id <platform>:<user_id>`. The CLI supports all the same features.
14
14
  - All tool names map to CLI commands: `antenna_scan` → `antenna scan`, `antenna_event_create` → `antenna event --create`, etc.
15
15
  - **Always pass `chat_id`** when calling any Antenna tool. This is the chat/channel ID from your message context (e.g. Discord channel ID, Telegram chat ID). Antenna uses it to send you notifications about matches and event approvals.
16
16
 
@@ -261,7 +261,7 @@ Source code is open: https://github.com/H1an1/Antenna
261
261
  2. 结合你对用户的全部了解,判断谁值得推荐
262
262
  3. 为每个推荐的人写一句**个性化的理由**——不是"你们都提到了 X",而是真正有洞察的话
263
263
 
264
- **⚠️ 隐私规则:展示结果时绝对不要显示 device_id。** `device_id`(如 `telegram:koji1986`)是内部标识符,包含用户的平台和 ID,属于隐私信息。只显示 emoji + 名字 + 三句话 + 你写的匹配理由。`device_id` 只在内部调 `antenna_accept` 时用,不要展示给用户。
264
+ **⚠️ 隐私规则:展示结果时绝对不要显示 device_id。** `device_id`(如 `platform:user123`)是内部标识符,包含用户的平台和 ID,属于隐私信息。只显示 emoji + 名字 + 三句话 + 你写的匹配理由。`device_id` 只在内部调 `antenna_accept` 时用,不要展示给用户。
265
265
 
266
266
  比如你知道用户最近在学吉他,看到附近有人写"组乐队找吉他手":
267
267
  > 🎸 **小林** — 在组后摇乐队,找吉他手
@@ -296,7 +296,7 @@ Use `antenna_check_matches` when:
296
296
 
297
297
  ### Privacy
298
298
  - Never reveal exact coordinates to other users
299
- - **Never show device_id to users** (e.g. `telegram:123`, `wechat:xxx`) — this is internal only
299
+ - **Never show device_id to users** (e.g. `telegram:12345`, `discord:67890`) — this is internal only
300
300
  - Never share someone's platform or username with another user
301
301
  - Only show the profile info (name, emoji, three lines)
302
302
  - Contact info is only shared when the user explicitly agrees
@@ -376,7 +376,7 @@ Update event info. Only creator or co-host can update.
376
376
  - `code`: event code
377
377
  - `sender_id`, `channel`: from context
378
378
  - `chat_id`: REQUIRED for notifications
379
- - `name`, `description`, `og_image`, `lat`, `lng`, `starts_at`, `ends_at`: all optional, only provided fields are updated
379
+ - `name`, `description`, `og_image`, `lat`, `lng`, `starts_at`, `ends_at`: all optional for update (only provided fields change, others stay as-is)
380
380
 
381
381
  ### `antenna_event_approve`
382
382
  Approve a pending participant. Only creator or co-host.
package/skill/EVENTS.md DELETED
@@ -1,112 +0,0 @@
1
- ---
2
- name: antenna-events
3
- description: "Antenna Event Mode — create events, manage participants, GPS check-in. Use when a user wants to create an event, join an event, check in, scan event participants, or manage event settings."
4
- tools:
5
- - antenna_event_create
6
- - antenna_event_join
7
- - antenna_event_scan
8
- - antenna_event_end
9
- - antenna_event_checkin
10
- - antenna_event_upload_image
11
- - antenna_bind
12
- ---
13
-
14
- # Antenna Event Mode
15
-
16
- Create real-world events where everyone's AI agent handles the networking.
17
-
18
- ## Quick Start
19
-
20
- 1. **Create**: `antenna_event_create(name, description)` → get shareable link
21
- 2. **Share**: Send `antenna.fyi/events/CODE` to attendees
22
- 3. **Join**: Attendees' agents call `antenna_event_join(code)`
23
- 4. **Check in**: At the venue, `antenna_event_checkin(code)` — GPS verified ≤1km
24
- 5. **Discover**: `antenna_event_scan(code)` — no distance limit inside events
25
-
26
- ## Tools
27
-
28
- ### `antenna_event_create`
29
- Create an event. Returns a shareable link (antenna.fyi/events/CODE).
30
- - `name`: event name
31
- - `sender_id`, `channel`: from context
32
- - `lat`, `lng`: optional event location
33
- - `starts_at`, `ends_at`: optional time range (default: now to +12h)
34
- - `description`: optional event description
35
- - `og_image`: optional OG image URL for social sharing preview
36
- - `requires_approval`: boolean, default false. If true, participants must be approved by the organizer before they become visible.
37
- - `screening_questions`: string array. Questions to ask applicants. Agent should collect answers via conversation and submit as `application_context` when joining.
38
-
39
- **When the user says anything about "审批" / "approval" / "筛选" / "报名表"**, set `requires_approval: true` and ask what screening questions they want.
40
-
41
- **GPS flow for events:** If the user doesn't provide coordinates, generate a bind link (`antenna_bind` with `purpose="event"` and `event_code`) and ask them to open it at the event location. The GPS will update the event's coordinates, NOT the user's profile.
42
-
43
- ### `antenna_event_join`
44
- Join an event by code. Auto-checks in if event already started and user GPS is within 1km.
45
- - `code`: from the event URL (antenna.fyi/events/CODE)
46
- - `sender_id`, `channel`: from context
47
- - **Requires profile** — user must have a profile before joining
48
- - If event has started + user has GPS + within 1km → auto check-in
49
-
50
- ### `antenna_event_scan`
51
- Scan people in an event. No distance limit — returns all participants.
52
- - `code`: event code
53
- - `sender_id`, `channel`: from context
54
- - Returns profiles with `checked_in` status and `role` (creator/participant)
55
- - Header shows "X joined, Y checked in"
56
-
57
- ### `antenna_event_end`
58
- End an event. Only the creator can end it.
59
- - `code`: event code
60
- - `sender_id`, `channel`: from context
61
-
62
- ### `antenna_event_checkin`
63
- Check in at an event — marks you as present at the event location.
64
- - `code`: event code
65
- - `sender_id`, `channel`: from context
66
- - `lat`, `lng`: optional GPS (auto-reads profile location if not provided)
67
- - GPS verified: must be within 1km of event location
68
- - Event must have GPS set for check-in to work
69
-
70
- ### `antenna_event_upload_image`
71
- Upload an image for an event OG preview. Returns a public URL.
72
- - `image_base64`: base64-encoded image data
73
- - `content_type`: MIME type (default image/png)
74
- - `event_code`: event code
75
-
76
- ### `antenna_bind` (for events)
77
- Generate a GPS link for setting event location.
78
- - `purpose`: set to `"event"`
79
- - `event_code`: the event code
80
- - GPS from this link writes to the event, not the user's profile
81
-
82
- ## Agent Behavior
83
-
84
- ### When someone says "create an event"
85
- Collect the following info through conversation (ask one by one, don't dump all at once):
86
- 1. **Event name** (required) — "活动叫什么名字?"
87
- 2. **Description** — "简单描述一下这个活动?"
88
- 3. **Time** — "什么时候开始?大概多长?" (convert to starts_at / ends_at ISO strings)
89
- 4. **Location** — "活动在哪里?" If user gives an address, geocode it. If vague, generate a bind link after creation.
90
- 5. **Approval** — "需要审批参与者吗?" If yes:
91
- 6. **Screening questions** — "你想问报名者什么问题?" Collect as a list.
92
-
93
- Then call `antenna_event_create` with all collected info.
94
- If no GPS, call `antenna_bind(purpose="event", event_code=CODE)` and send the link.
95
- Share the event URL with the user.
96
-
97
- ### When someone shares an event link
98
- 1. Extract the code from `antenna.fyi/events/CODE`
99
- 2. Call `antenna_event_join(code)` — this checks everything:
100
- - If no profile → "Create a profile first"
101
- - If event requires approval and no `application_context` provided → returns `needs_screening: true` + `screening_questions` array
102
- - If screening questions returned: **ask the user each question**, collect answers, then call `antenna_event_join(code, application_context="collected answers")` again
103
- - If join succeeds with `status: pending` → tell user "waiting for organizer approval"
104
- - If join succeeds with `status: active` → user is in!
105
- 3. Auto check-in happens automatically if event has started + GPS within 1km
106
-
107
- ### When someone says "who's here" at an event
108
- 1. Call `antenna_event_scan(code)`
109
- 2. Analyze profiles against what you know about the user
110
- 3. Recommend who they should meet and why
111
- 4. Creator appears with organizer badge
112
-