antenna-fyi 1.3.6 → 1.3.7

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
@@ -1,6 +1,6 @@
1
1
  // antenna CLI command handlers
2
2
 
3
- import { scan, getProfile, setProfile, accept, checkMatches, checkin, createBindToken, discover, createEvent, endEvent, eventCheckin, joinEvent, eventScan, pass as passUser, uploadEventImage, updateEvent, approveParticipant, rejectParticipant, addCohost, getClient } from "./core.js";
3
+ import { scan, getProfile, setProfile, accept, checkMatches, checkin, createBindToken, discover, createEvent, endEvent, eventCheckin, joinEvent, eventScan, pass as passUser, uploadEventImage, updateEvent, approveParticipant, rejectParticipant, addCohost, sendEventMessage, getMyEventMessages, getClient } from "./core.js";
4
4
  import { createInterface } from "readline";
5
5
  import { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, unlinkSync, renameSync } from "fs";
6
6
  import path from "path";
@@ -273,13 +273,25 @@ export async function handleEvent(f) {
273
273
  return;
274
274
  }
275
275
 
276
+ if (f.message || f.msg) {
277
+ if (!f.code || !f.id || !(f.message || f.msg)) return console.error("Usage: antenna event --message 'Hello everyone' --code abc123 --id <platform>:<user_id> [--ref 1]");
278
+ const result = await sendEventMessage({ code: f.code, device_id: f.id, message: f.message || f.msg, target_ref: f.ref || undefined });
279
+ if (result.sent) {
280
+ console.log(`\n✅ Message sent${result.broadcast ? ' (broadcast to all)' : ''}\n`);
281
+ } else {
282
+ console.log(`\n❌ ${result.error}\n`);
283
+ }
284
+ return;
285
+ }
286
+
276
287
  console.log(`Usage:
277
288
  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
289
  antenna event --join --code abc123 --id <platform>:<user_id>
279
290
  antenna event --scan --code abc123 [--id <platform>:<user_id>]
280
291
  antenna event --checkin --code abc123 --id <platform>:<user_id> [--lat 34.05 --lng -118.24]
281
292
  antenna event --end --code abc123 --id <platform>:<user_id>
282
- antenna event --upload-image --code abc123 --file /path/to/image.png`);
293
+ antenna event --upload-image --code abc123 --file /path/to/image.png
294
+ antenna event --message 'Hello everyone' --code abc123 --id <platform>:<user_id> [--ref 1]`);
283
295
  }
284
296
 
285
297
  export async function handleBind(f) {
@@ -855,6 +867,20 @@ export async function handleWatch(f) {
855
867
  }
856
868
  }
857
869
  } catch { /* silent */ }
870
+
871
+ // Poll event messages from hosts
872
+ try {
873
+ const { data: msgs } = await sb.rpc("get_my_event_messages", { p_device_id: id });
874
+ for (const msg of (msgs || [])) {
875
+ const key = `evtmsg:${msg.event_id}:${msg.created_at}`;
876
+ if (!notified.has(key)) {
877
+ notified.add(key);
878
+ saveNotified(notified);
879
+ const role = msg.sender_role === 'creator' ? '组织者' : '协办';
880
+ pushNotify(`📢 来自「${msg.event_name}」${role} ${msg.sender_emoji || ''} ${msg.sender_name}: ${msg.message}`);
881
+ }
882
+ }
883
+ } catch { /* silent */ }
858
884
  }, 2 * 60 * 1000);
859
885
 
860
886
  // Handle Ctrl+C
package/lib/core.js CHANGED
@@ -686,3 +686,30 @@ export async function createBindToken({ device_id, purpose, event_code, supabase
686
686
  : "发送这个链接给用户,在手机浏览器打开即可共享位置。",
687
687
  };
688
688
  }
689
+
690
+ // ─── sendEventMessage (host → participants) ─────────────────────────
691
+
692
+ export async function sendEventMessage({ code, device_id, message, target_ref, supabaseUrl, supabaseKey }) {
693
+ const sb = getClient(supabaseUrl, supabaseKey);
694
+ const params = {
695
+ p_code: code,
696
+ p_device_id: device_id,
697
+ p_message: message,
698
+ };
699
+ if (target_ref) params.p_target_ref = target_ref;
700
+ const { data, error } = await sb.rpc("send_event_message", params);
701
+ if (error) throw new Error(error.message);
702
+ return data;
703
+ }
704
+
705
+ // ─── getMyEventMessages ──────────────────────────────────────────────
706
+
707
+ export async function getMyEventMessages({ device_id, supabaseUrl, supabaseKey }) {
708
+ const sb = getClient(supabaseUrl, supabaseKey);
709
+ const { data, error } = await sb.rpc("get_my_event_messages", { p_device_id: device_id });
710
+ if (error) throw new Error(error.message);
711
+ return {
712
+ messages: data || [],
713
+ count: (data || []).length,
714
+ };
715
+ }
@@ -32,6 +32,7 @@ from .tools import (
32
32
  handle_event_approve,
33
33
  handle_event_reject,
34
34
  handle_event_add_host,
35
+ handle_event_message,
35
36
  _sb,
36
37
  _device_id,
37
38
  _my_device_ids,
@@ -55,6 +56,7 @@ from .schemas import (
55
56
  EVENT_APPROVE_SCHEMA,
56
57
  EVENT_REJECT_SCHEMA,
57
58
  EVENT_ADD_HOST_SCHEMA,
59
+ EVENT_MESSAGE_SCHEMA,
58
60
  )
59
61
  import re
60
62
  import time
@@ -89,6 +91,7 @@ def register(ctx):
89
91
  ctx.register_tool("antenna_event_approve", EVENT_APPROVE_SCHEMA, handle_event_approve)
90
92
  ctx.register_tool("antenna_event_reject", EVENT_REJECT_SCHEMA, handle_event_reject)
91
93
  ctx.register_tool("antenna_event_add_host", EVENT_ADD_HOST_SCHEMA, handle_event_add_host)
94
+ ctx.register_tool("antenna_event_message", EVENT_MESSAGE_SCHEMA, handle_event_message)
92
95
 
93
96
  # ── Hook: auto-detect location + check web GPS events ─────────
94
97
  def on_pre_llm(messages, **kwargs):
@@ -179,6 +182,19 @@ def register(ctx):
179
182
  hints.append(
180
183
  f"[Antenna] ❌ 你的申请未通过「{name}」"
181
184
  )
185
+
186
+ # Check event messages from hosts
187
+ msg_resp = sb.rpc("get_my_event_messages", {"p_device_id": did}).execute()
188
+ for msg in (msg_resp.data or []):
189
+ key = f"evtmsg:{msg.get('event_id')}:{msg.get('created_at')}"
190
+ if key in _notified_match_keys:
191
+ continue
192
+ _notified_match_keys.add(key)
193
+ role_label = '组织者' if msg.get('sender_role') == 'creator' else '协办'
194
+ hints.append(
195
+ f"[Antenna] 📢 来自「{msg.get('event_name')}」{role_label} {msg.get('sender_emoji', '')} {msg.get('sender_name', '')}: {msg.get('message', '')}\n"
196
+ f"请立即通知用户这条消息。"
197
+ )
182
198
  except Exception:
183
199
  pass
184
200
  now = time.time()
@@ -1,5 +1,5 @@
1
1
  name: antenna
2
- version: "1.3.6"
2
+ version: "1.3.7"
3
3
  description: |
4
4
  Nearby people discovery + events — scan for people, set up your profile card,
5
5
  accept matches, create/join events, and get real-time notifications.
@@ -359,3 +359,20 @@ EVENT_ADD_HOST_SCHEMA = {
359
359
  "required": ["code", "sender_id", "channel", "ref", "chat_id"],
360
360
  },
361
361
  }
362
+
363
+ EVENT_MESSAGE_SCHEMA = {
364
+ "name": "antenna_event_message",
365
+ "description": "Send a message to event participants. Only creator or co-host can send. Omit ref to broadcast to all.",
366
+ "parameters": {
367
+ "type": "object",
368
+ "properties": {
369
+ "code": {"type": "string", "description": "Event code"},
370
+ "sender_id": {"type": "string"},
371
+ "channel": {"type": "string"},
372
+ "chat_id": {"type": "string", "description": "REQUIRED for notifications. Pass chat/channel ID from message context."},
373
+ "message": {"type": "string", "description": "Message to send to participants"},
374
+ "ref": {"type": "string", "description": "Ref number of specific participant (omit for broadcast)"},
375
+ },
376
+ "required": ["code", "sender_id", "channel", "message", "chat_id"],
377
+ },
378
+ }
@@ -680,3 +680,18 @@ def handle_event_add_host(params: dict) -> str:
680
680
  "p_code": params["code"], "p_device_id": did, "p_target_ref": params["ref"],
681
681
  }).execute()
682
682
  return _ok(resp.data or {"error": "add_cohost failed"})
683
+
684
+
685
+ def handle_event_message(params: dict) -> str:
686
+ """Send a message to event participants. Only creator or co-host can send."""
687
+ sb = _sb()
688
+ did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
689
+ rpc_params = {
690
+ "p_code": params["code"],
691
+ "p_device_id": did,
692
+ "p_message": params["message"],
693
+ }
694
+ if params.get("ref"):
695
+ rpc_params["p_target_ref"] = params["ref"]
696
+ resp = sb.rpc("send_event_message", rpc_params).execute()
697
+ return _ok(resp.data or {"error": "send_event_message failed"})
package/lib/mcp.js CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  approveParticipant,
24
24
  rejectParticipant,
25
25
  addCohost,
26
+ sendEventMessage,
26
27
  deriveDeviceId,
27
28
  } from "./core.js";
28
29
 
@@ -478,6 +479,27 @@ export async function startMcpServer() {
478
479
  }
479
480
  );
480
481
 
482
+ // ─── antenna_event_message ────────────────────────────────
483
+
484
+ server.tool(
485
+ "antenna_event_message",
486
+ "Send a message to event participants. Only creator or co-host can send. Omit ref to broadcast to all.",
487
+ {
488
+ code: z.string().describe("Event code"),
489
+ sender_id: z.string().describe("The sender's user ID"),
490
+ channel: z.string().describe("Channel name"),
491
+ chat_id: z.string().describe("REQUIRED for notifications"),
492
+ message: z.string().describe("Message to send"),
493
+ ref: z.string().optional().describe("Ref number of specific participant (omit for broadcast)"),
494
+ },
495
+ async ({ code, sender_id, channel, chat_id, message, ref }) => {
496
+ try {
497
+ const result = await sendEventMessage({ code, device_id: deriveDeviceId(sender_id, channel), message, target_ref: ref });
498
+ return jsonResult(result);
499
+ } catch (e) { return jsonResult({ error: e.message }); }
500
+ }
501
+ );
502
+
481
503
  const transport = new StdioServerTransport();
482
504
  await server.connect(transport);
483
505
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antenna-fyi",
3
- "version": "1.3.6",
3
+ "version": "1.3.7",
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
@@ -388,6 +388,16 @@ Add a co-host to the event. Only creator can add.
388
388
  - `chat_id`: REQUIRED for notifications
389
389
  - `ref`: participant ref number to promote to co-host
390
390
 
391
+ ### `antenna_event_message`
392
+ Send a message to event participants. Only creator or co-host can send.
393
+ - `code`: event code
394
+ - `sender_id`, `channel`: from context
395
+ - `chat_id`: REQUIRED for notifications
396
+ - `message`: the message text
397
+ - `ref`: optional — ref number of specific participant. Omit to broadcast to all active participants.
398
+ - Use when the host needs to notify participants about logistics, changes, or requests (e.g. "please share your WeChat in your profile").
399
+ - One-way: participants receive the message but cannot reply through this channel.
400
+
391
401
  ---
392
402
 
393
403
  ## Event Behavior Guide