antenna-fyi 1.2.24 → 1.2.25
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 +63 -26
- package/lib/core.js +1 -1
- package/lib/hermes-plugin/schemas.py +9 -0
- package/lib/hermes-plugin/tools.py +36 -21
- package/package.json +1 -1
- package/skill/SKILL.md +10 -0
package/lib/cli.js
CHANGED
|
@@ -501,42 +501,35 @@ export async function handleWatch(f) {
|
|
|
501
501
|
console.log(` Press Ctrl+C to stop.\n`);
|
|
502
502
|
|
|
503
503
|
// Push notification helper
|
|
504
|
-
function pushNotify(message) {
|
|
504
|
+
async function pushNotify(message) {
|
|
505
505
|
console.log(message); // always print to terminal
|
|
506
506
|
|
|
507
507
|
if (pushMethod === "openclaw") {
|
|
508
508
|
try {
|
|
509
|
+
// Try to get chat_id from DB for direct message send
|
|
510
|
+
const profile = await getProfile({ device_id: id });
|
|
511
|
+
const chatId = profile?.last_chat_id;
|
|
509
512
|
const parts = id.split(":");
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
513
|
+
const chan = parts[0];
|
|
514
|
+
if (chatId) {
|
|
515
|
+
execSync(
|
|
516
|
+
`openclaw message send --channel ${chan} --target ${chatId} -m ${JSON.stringify(message)}`,
|
|
517
|
+
{ timeout: 30_000, stdio: "pipe" }
|
|
518
|
+
);
|
|
519
|
+
} else {
|
|
520
|
+
execSync(
|
|
521
|
+
`openclaw agent --message ${JSON.stringify(message)} --deliver --agent main --to ${id}`,
|
|
522
|
+
{ timeout: 30_000, stdio: "pipe" }
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
} catch (err) { /* terminal output is the fallback */ }
|
|
523
526
|
} else if (pushMethod === "hermes") {
|
|
524
527
|
try {
|
|
525
|
-
// Use hermes cron to create a one-shot notification
|
|
526
|
-
const parts = id.split(":");
|
|
527
|
-
const channel = parts[0];
|
|
528
528
|
execSync(
|
|
529
|
-
`hermes cron create
|
|
530
|
-
` --name "Antenna notification"` +
|
|
531
|
-
` --run-now` +
|
|
532
|
-
` --once` +
|
|
533
|
-
` --message ${JSON.stringify(message)}` +
|
|
534
|
-
` --deliver ${channel}`,
|
|
529
|
+
`hermes cron create --name "Antenna notification" --run-now --once --message ${JSON.stringify(message)}`,
|
|
535
530
|
{ timeout: 30_000, stdio: "pipe" }
|
|
536
531
|
);
|
|
537
|
-
} catch (err) {
|
|
538
|
-
// silent — terminal output is the fallback
|
|
539
|
-
}
|
|
532
|
+
} catch (err) { /* terminal output is the fallback */ }
|
|
540
533
|
}
|
|
541
534
|
}
|
|
542
535
|
|
|
@@ -620,6 +613,50 @@ export async function handleWatch(f) {
|
|
|
620
613
|
}
|
|
621
614
|
});
|
|
622
615
|
|
|
616
|
+
// Subscribe to event_participants changes (approval notifications)
|
|
617
|
+
sb
|
|
618
|
+
.channel("antenna-cli-watch-events")
|
|
619
|
+
.on("postgres_changes",
|
|
620
|
+
{ event: "INSERT", schema: "public", table: "event_participants" },
|
|
621
|
+
async (payload) => {
|
|
622
|
+
try {
|
|
623
|
+
const row = payload.new;
|
|
624
|
+
if (!row || row.status !== "pending") return;
|
|
625
|
+
// Someone applied to my event — check if I'm the creator
|
|
626
|
+
const event = await sb.rpc("get_event_by_id", { p_event_id: row.event_id }).then(r => r.data);
|
|
627
|
+
if (!event?.found || event.created_by !== id) return;
|
|
628
|
+
const applicant = await getProfile({ device_id: row.device_id });
|
|
629
|
+
const name = applicant?.display_name || "Someone";
|
|
630
|
+
const emoji = applicant?.emoji || "👤";
|
|
631
|
+
pushNotify(`📩 ${emoji} ${name} applied to join \"${event.name}\"! Run: antenna event --scan --code ${event.code} --id ${id}`);
|
|
632
|
+
} catch {}
|
|
633
|
+
}
|
|
634
|
+
)
|
|
635
|
+
.on("postgres_changes",
|
|
636
|
+
{ event: "UPDATE", schema: "public", table: "event_participants" },
|
|
637
|
+
async (payload) => {
|
|
638
|
+
try {
|
|
639
|
+
const row = payload.new;
|
|
640
|
+
const old = payload.old;
|
|
641
|
+
if (!row || !old) return;
|
|
642
|
+
// My application was approved/rejected
|
|
643
|
+
if (row.device_id !== id) return;
|
|
644
|
+
if (old.status === "pending" && row.status === "active") {
|
|
645
|
+
const event = await sb.rpc("get_event_by_id", { p_event_id: row.event_id }).then(r => r.data);
|
|
646
|
+
pushNotify(`✅ Your application to \"${event?.name || 'an event'}\" was approved! You're in.`);
|
|
647
|
+
} else if (old.status === "pending" && row.status === "rejected") {
|
|
648
|
+
const event = await sb.rpc("get_event_by_id", { p_event_id: row.event_id }).then(r => r.data);
|
|
649
|
+
pushNotify(`❌ Your application to \"${event?.name || 'an event'}\" was not approved.`);
|
|
650
|
+
}
|
|
651
|
+
} catch {}
|
|
652
|
+
}
|
|
653
|
+
)
|
|
654
|
+
.subscribe((status) => {
|
|
655
|
+
if (status === "SUBSCRIBED") {
|
|
656
|
+
console.log("✅ Connected — listening for event notifications.");
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
|
|
623
660
|
// Keep alive — also poll every 2 minutes as fallback
|
|
624
661
|
const pollInterval = setInterval(async () => {
|
|
625
662
|
try {
|
package/lib/core.js
CHANGED
|
@@ -502,7 +502,7 @@ export async function createEvent({ name, lat, lng, device_id, starts_at, ends_a
|
|
|
502
502
|
p_description: description || null,
|
|
503
503
|
p_og_image: og_image || null,
|
|
504
504
|
p_requires_approval: requires_approval || false,
|
|
505
|
-
p_screening_questions: screening_questions || null,
|
|
505
|
+
p_screening_questions: screening_questions ? screening_questions.flatMap(q => q.includes('|') || q.includes('|') ? q.split(/[|\uff5c]/).map(s => s.trim()).filter(Boolean) : [q]) : null,
|
|
506
506
|
});
|
|
507
507
|
if (error) throw new Error(error.message);
|
|
508
508
|
return data;
|
|
@@ -44,6 +44,7 @@ PROFILE_SCHEMA = {
|
|
|
44
44
|
},
|
|
45
45
|
"sender_id": {"type": "string"},
|
|
46
46
|
"channel": {"type": "string"},
|
|
47
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
47
48
|
"display_name": {"type": "string", "description": "Display name"},
|
|
48
49
|
"emoji": {"type": "string", "description": "Profile emoji"},
|
|
49
50
|
"line1": {"type": "string", "description": "Who you are / what you do"},
|
|
@@ -66,6 +67,7 @@ ACCEPT_SCHEMA = {
|
|
|
66
67
|
"properties": {
|
|
67
68
|
"sender_id": {"type": "string"},
|
|
68
69
|
"channel": {"type": "string"},
|
|
70
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
69
71
|
"ref": {
|
|
70
72
|
"type": "string",
|
|
71
73
|
"description": "Ref number from scan results (e.g. '1')",
|
|
@@ -95,6 +97,7 @@ CHECKIN_SCHEMA = {
|
|
|
95
97
|
"lng": {"type": "number", "description": "Longitude"},
|
|
96
98
|
"sender_id": {"type": "string"},
|
|
97
99
|
"channel": {"type": "string"},
|
|
100
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
98
101
|
"place_name": {
|
|
99
102
|
"type": "string",
|
|
100
103
|
"description": "Name of the place (optional)",
|
|
@@ -114,6 +117,7 @@ CHECK_MATCHES_SCHEMA = {
|
|
|
114
117
|
"properties": {
|
|
115
118
|
"sender_id": {"type": "string"},
|
|
116
119
|
"channel": {"type": "string"},
|
|
120
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
117
121
|
},
|
|
118
122
|
"required": ["sender_id", "channel"],
|
|
119
123
|
},
|
|
@@ -129,6 +133,7 @@ BIND_SCHEMA = {
|
|
|
129
133
|
"properties": {
|
|
130
134
|
"sender_id": {"type": "string"},
|
|
131
135
|
"channel": {"type": "string"},
|
|
136
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
132
137
|
"purpose": {"type": "string", "description": "'profile' (default) or 'event'"},
|
|
133
138
|
"event_code": {"type": "string", "description": "Event code (when purpose=event)"},
|
|
134
139
|
},
|
|
@@ -282,6 +287,7 @@ EVENT_UPDATE_SCHEMA = {
|
|
|
282
287
|
"code": {"type": "string"},
|
|
283
288
|
"sender_id": {"type": "string"},
|
|
284
289
|
"channel": {"type": "string"},
|
|
290
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
285
291
|
"name": {"type": "string"},
|
|
286
292
|
"description": {"type": "string"},
|
|
287
293
|
"og_image": {"type": "string"},
|
|
@@ -303,6 +309,7 @@ EVENT_APPROVE_SCHEMA = {
|
|
|
303
309
|
"code": {"type": "string"},
|
|
304
310
|
"sender_id": {"type": "string"},
|
|
305
311
|
"channel": {"type": "string"},
|
|
312
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
306
313
|
"ref": {"type": "string"},
|
|
307
314
|
},
|
|
308
315
|
"required": ["code", "sender_id", "channel", "ref"],
|
|
@@ -318,6 +325,7 @@ EVENT_REJECT_SCHEMA = {
|
|
|
318
325
|
"code": {"type": "string"},
|
|
319
326
|
"sender_id": {"type": "string"},
|
|
320
327
|
"channel": {"type": "string"},
|
|
328
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
321
329
|
"ref": {"type": "string"},
|
|
322
330
|
},
|
|
323
331
|
"required": ["code", "sender_id", "channel", "ref"],
|
|
@@ -333,6 +341,7 @@ EVENT_ADD_HOST_SCHEMA = {
|
|
|
333
341
|
"code": {"type": "string"},
|
|
334
342
|
"sender_id": {"type": "string"},
|
|
335
343
|
"channel": {"type": "string"},
|
|
344
|
+
"chat_id": {"type": "string", "description": "Chat/channel ID for notifications"},
|
|
336
345
|
"ref": {"type": "string"},
|
|
337
346
|
},
|
|
338
347
|
"required": ["code", "sender_id", "channel", "ref"],
|
|
@@ -54,9 +54,16 @@ def _sb():
|
|
|
54
54
|
return _client
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def _device_id(sender_id: str, channel: str) -> str:
|
|
57
|
+
def _device_id(sender_id: str, channel: str, chat_id: str = None) -> str:
|
|
58
58
|
did = f"{channel}:{sender_id}"
|
|
59
59
|
_my_device_ids.add(did)
|
|
60
|
+
# Persist chat_id for notifications
|
|
61
|
+
if chat_id:
|
|
62
|
+
try:
|
|
63
|
+
sb = _sb()
|
|
64
|
+
sb.rpc("upsert_profile", {"p_device_id": did, "p_last_chat_id": chat_id}).execute()
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
60
67
|
return did
|
|
61
68
|
|
|
62
69
|
|
|
@@ -72,7 +79,7 @@ def _ok(data) -> str:
|
|
|
72
79
|
|
|
73
80
|
def handle_scan(params: dict) -> str:
|
|
74
81
|
sb = _sb()
|
|
75
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
82
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
76
83
|
radius = params.get("radius_m", 500)
|
|
77
84
|
|
|
78
85
|
# Rate limit
|
|
@@ -137,7 +144,7 @@ def handle_scan(params: dict) -> str:
|
|
|
137
144
|
|
|
138
145
|
def handle_profile(params: dict) -> str:
|
|
139
146
|
sb = _sb()
|
|
140
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
147
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
141
148
|
|
|
142
149
|
if params["action"] == "get":
|
|
143
150
|
resp = sb.rpc("get_profile", {"p_device_id": did}).execute()
|
|
@@ -163,7 +170,7 @@ def handle_profile(params: dict) -> str:
|
|
|
163
170
|
|
|
164
171
|
def handle_accept(params: dict) -> str:
|
|
165
172
|
sb = _sb()
|
|
166
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
173
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
167
174
|
|
|
168
175
|
# Resolve ref to device_id
|
|
169
176
|
ref = params.get("ref")
|
|
@@ -202,7 +209,7 @@ def handle_accept(params: dict) -> str:
|
|
|
202
209
|
|
|
203
210
|
def handle_checkin(params: dict) -> str:
|
|
204
211
|
sb = _sb()
|
|
205
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
212
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
206
213
|
flat, flng = _fuzzy(params["lat"], params["lng"])
|
|
207
214
|
|
|
208
215
|
# Check profile exists
|
|
@@ -220,7 +227,7 @@ def handle_checkin(params: dict) -> str:
|
|
|
220
227
|
|
|
221
228
|
def handle_check_matches(params: dict) -> str:
|
|
222
229
|
sb = _sb()
|
|
223
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
230
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
224
231
|
|
|
225
232
|
resp = sb.rpc("get_my_matches", {"p_device_id": did}).execute()
|
|
226
233
|
all_matches = resp.data or []
|
|
@@ -280,7 +287,7 @@ BASE_URL = "https://www.antenna.fyi"
|
|
|
280
287
|
|
|
281
288
|
def handle_pass(params: dict) -> str:
|
|
282
289
|
sb = _sb()
|
|
283
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
290
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
284
291
|
|
|
285
292
|
ref = params.get("ref")
|
|
286
293
|
target = params.get("target_device_id")
|
|
@@ -307,7 +314,7 @@ def handle_pass(params: dict) -> str:
|
|
|
307
314
|
|
|
308
315
|
def handle_discover(params: dict) -> str:
|
|
309
316
|
sb = _sb()
|
|
310
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
317
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
311
318
|
|
|
312
319
|
resp = sb.rpc("global_discover", {"p_device_id": did}).execute()
|
|
313
320
|
results = resp.data or []
|
|
@@ -365,7 +372,7 @@ def handle_discover(params: dict) -> str:
|
|
|
365
372
|
|
|
366
373
|
def handle_event_create(params: dict) -> str:
|
|
367
374
|
sb = _sb()
|
|
368
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
375
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
369
376
|
|
|
370
377
|
rpc_params = {
|
|
371
378
|
"p_created_by": did,
|
|
@@ -403,7 +410,7 @@ def handle_event_create(params: dict) -> str:
|
|
|
403
410
|
|
|
404
411
|
def handle_event_join(params: dict) -> str:
|
|
405
412
|
sb = _sb()
|
|
406
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
413
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
407
414
|
|
|
408
415
|
# Profile gate
|
|
409
416
|
prof = sb.rpc("get_profile", {"p_device_id": did}).execute()
|
|
@@ -484,10 +491,10 @@ def handle_event_join(params: dict) -> str:
|
|
|
484
491
|
|
|
485
492
|
def handle_event_scan(params: dict) -> str:
|
|
486
493
|
sb = _sb()
|
|
487
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
494
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
488
495
|
|
|
489
496
|
resp = sb.rpc("event_participants_list", {
|
|
490
|
-
"p_code": params["code"],
|
|
497
|
+
"p_code": params["code"], "p_device_id": did,
|
|
491
498
|
}).execute()
|
|
492
499
|
results = resp.data or []
|
|
493
500
|
|
|
@@ -496,32 +503,40 @@ def handle_event_scan(params: dict) -> str:
|
|
|
496
503
|
if not others:
|
|
497
504
|
return _ok({"count": 0, "profiles": [], "message": "活动里还没有其他人。"})
|
|
498
505
|
|
|
506
|
+
global _last_ref_map
|
|
499
507
|
global _last_ref_map
|
|
500
508
|
_last_ref_map = {}
|
|
509
|
+
checked_in_count = 0
|
|
501
510
|
profiles = []
|
|
502
511
|
for i, p in enumerate(others):
|
|
503
512
|
ref = str(i + 1)
|
|
504
513
|
_last_ref_map[ref] = p.get("device_id")
|
|
514
|
+
if p.get("checked_in"):
|
|
515
|
+
checked_in_count += 1
|
|
505
516
|
profiles.append({
|
|
506
517
|
"ref": ref,
|
|
507
|
-
"emoji": p.get("emoji") or "
|
|
518
|
+
"emoji": p.get("emoji") or "👤",
|
|
508
519
|
"name": p.get("display_name") or "匿名",
|
|
509
520
|
"line1": p.get("line1"),
|
|
510
521
|
"line2": p.get("line2"),
|
|
511
522
|
"line3": p.get("line3"),
|
|
523
|
+
"checked_in": bool(p.get("checked_in")),
|
|
524
|
+
"role": p.get("role") or "participant",
|
|
525
|
+
"status": p.get("status") or "active",
|
|
526
|
+
"application_context": p.get("application_context"),
|
|
512
527
|
"source": "event",
|
|
513
528
|
})
|
|
514
529
|
|
|
515
530
|
return _ok({
|
|
516
531
|
"count": len(profiles),
|
|
532
|
+
"checked_in_count": checked_in_count,
|
|
517
533
|
"profiles": profiles,
|
|
518
534
|
"instruction": "这些是活动参加者。根据你对用户的了解,推荐值得认识的人。使用 ref 编号引用。",
|
|
519
535
|
})
|
|
520
536
|
|
|
521
|
-
|
|
522
537
|
def handle_bind(params: dict) -> str:
|
|
523
538
|
sb = _sb()
|
|
524
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
539
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
525
540
|
purpose = params.get("purpose", "profile")
|
|
526
541
|
event_code = params.get("event_code")
|
|
527
542
|
|
|
@@ -549,7 +564,7 @@ def handle_bind(params: dict) -> str:
|
|
|
549
564
|
|
|
550
565
|
def handle_event_end(params: dict) -> str:
|
|
551
566
|
sb = _sb()
|
|
552
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
567
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
553
568
|
|
|
554
569
|
resp = sb.rpc("end_event", {
|
|
555
570
|
"p_code": params["code"],
|
|
@@ -576,7 +591,7 @@ def handle_event_upload_image(params: dict) -> str:
|
|
|
576
591
|
|
|
577
592
|
def handle_event_checkin(params: dict) -> str:
|
|
578
593
|
sb = _sb()
|
|
579
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
594
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
580
595
|
|
|
581
596
|
lat = params.get("lat")
|
|
582
597
|
lng = params.get("lng")
|
|
@@ -596,7 +611,7 @@ def handle_event_checkin(params: dict) -> str:
|
|
|
596
611
|
|
|
597
612
|
def handle_event_update(params: dict) -> str:
|
|
598
613
|
sb = _sb()
|
|
599
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
614
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
600
615
|
resp = sb.rpc("update_event", {
|
|
601
616
|
"p_code": params["code"], "p_device_id": did,
|
|
602
617
|
"p_name": params.get("name"), "p_description": params.get("description"),
|
|
@@ -609,7 +624,7 @@ def handle_event_update(params: dict) -> str:
|
|
|
609
624
|
|
|
610
625
|
def handle_event_approve(params: dict) -> str:
|
|
611
626
|
sb = _sb()
|
|
612
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
627
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
613
628
|
resp = sb.rpc("approve_participant", {
|
|
614
629
|
"p_code": params["code"], "p_device_id": did, "p_target_ref": params["ref"],
|
|
615
630
|
}).execute()
|
|
@@ -618,7 +633,7 @@ def handle_event_approve(params: dict) -> str:
|
|
|
618
633
|
|
|
619
634
|
def handle_event_reject(params: dict) -> str:
|
|
620
635
|
sb = _sb()
|
|
621
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
636
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
622
637
|
resp = sb.rpc("reject_participant", {
|
|
623
638
|
"p_code": params["code"], "p_device_id": did, "p_target_ref": params["ref"],
|
|
624
639
|
}).execute()
|
|
@@ -627,7 +642,7 @@ def handle_event_reject(params: dict) -> str:
|
|
|
627
642
|
|
|
628
643
|
def handle_event_add_host(params: dict) -> str:
|
|
629
644
|
sb = _sb()
|
|
630
|
-
did = _device_id(params["sender_id"], params["channel"])
|
|
645
|
+
did = _device_id(params["sender_id"], params["channel"], params.get("chat_id"))
|
|
631
646
|
resp = sb.rpc("add_cohost", {
|
|
632
647
|
"p_code": params["code"], "p_device_id": did, "p_target_ref": params["ref"],
|
|
633
648
|
}).execute()
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -60,6 +60,16 @@ cron 设完后,问用户一句:
|
|
|
60
60
|
用户说要 → cron 每天调 `antenna_discover` 推送。
|
|
61
61
|
用户说不要 → 只在 scan 没人时 fallback。
|
|
62
62
|
|
|
63
|
+
**第六步:启动实时通知**
|
|
64
|
+
|
|
65
|
+
onboarding 完成后,启动 `antenna watch` 后台进程,实时接收匹配通知和活动审批通知:
|
|
66
|
+
```
|
|
67
|
+
antenna watch --id <device_id> &
|
|
68
|
+
```
|
|
69
|
+
这会保持一个 WebSocket 连接,有新匹配或活动审批变更时立即通知。比 cron 更实时。
|
|
70
|
+
|
|
71
|
+
如果 exec 不支持后台进程,cron 是 fallback。
|
|
72
|
+
|
|
63
73
|
## When to use
|
|
64
74
|
|
|
65
75
|
- **首次安装后**: 主动开始 onboarding(名片 → 位置)
|