@decentnetwork/beagle-ui 0.2.21 → 0.2.23
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/dist/beagle-ui.js +382 -50
- package/package.json +1 -1
package/dist/beagle-ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const BEAGLE_UI_VERSION = "0.2.
|
|
1
|
+
export const BEAGLE_UI_VERSION = "0.2.23";
|
|
2
2
|
// src/icons.jsx
|
|
3
3
|
var ICON_PATHS = {
|
|
4
4
|
// ---- tab bar (the four must feel like one set) ----
|
|
@@ -516,23 +516,39 @@ var actions_default = {
|
|
|
516
516
|
name: "help",
|
|
517
517
|
usage: "/help",
|
|
518
518
|
summary: "List what the Assistant can do.",
|
|
519
|
-
params: {
|
|
519
|
+
params: {
|
|
520
|
+
type: "object",
|
|
521
|
+
properties: {},
|
|
522
|
+
required: []
|
|
523
|
+
},
|
|
520
524
|
confirm: "none",
|
|
521
525
|
scope: "assistant"
|
|
522
526
|
},
|
|
523
527
|
{
|
|
524
528
|
name: "friends-list",
|
|
525
529
|
usage: "/friends list [filter\u2026]",
|
|
526
|
-
summary: "Show friends as a
|
|
530
|
+
summary: "Show friends as a list: name, last heard from, messages in/out. With no filter, everyone. Service peers are never included \u2014 they are /nodes.",
|
|
527
531
|
params: {
|
|
528
532
|
type: "object",
|
|
529
533
|
properties: {
|
|
530
534
|
filters: {
|
|
531
535
|
type: "array",
|
|
532
|
-
items: {
|
|
536
|
+
items: {
|
|
537
|
+
enum: [
|
|
538
|
+
"never-messaged",
|
|
539
|
+
"never-replied",
|
|
540
|
+
"silent",
|
|
541
|
+
"pending"
|
|
542
|
+
]
|
|
543
|
+
},
|
|
533
544
|
description: "Several filters are OR'd together."
|
|
534
545
|
},
|
|
535
|
-
silentDays: {
|
|
546
|
+
silentDays: {
|
|
547
|
+
type: "integer",
|
|
548
|
+
minimum: 1,
|
|
549
|
+
default: 90,
|
|
550
|
+
description: "Argument of the silent filter: nothing from them in this many days."
|
|
551
|
+
}
|
|
536
552
|
},
|
|
537
553
|
required: []
|
|
538
554
|
},
|
|
@@ -542,18 +558,94 @@ var actions_default = {
|
|
|
542
558
|
{
|
|
543
559
|
name: "friends-remove",
|
|
544
560
|
usage: "/friends remove <filter\u2026>",
|
|
545
|
-
summary: "Same
|
|
561
|
+
summary: "Same list with a tick per row and a Remove button. Nothing is removed by typing alone. Service peers are never matched.",
|
|
562
|
+
params: {
|
|
563
|
+
type: "object",
|
|
564
|
+
properties: {
|
|
565
|
+
filters: {
|
|
566
|
+
type: "array",
|
|
567
|
+
items: {
|
|
568
|
+
enum: [
|
|
569
|
+
"never-messaged",
|
|
570
|
+
"never-replied",
|
|
571
|
+
"silent",
|
|
572
|
+
"pending"
|
|
573
|
+
]
|
|
574
|
+
},
|
|
575
|
+
minItems: 1
|
|
576
|
+
},
|
|
577
|
+
silentDays: {
|
|
578
|
+
type: "integer",
|
|
579
|
+
minimum: 1,
|
|
580
|
+
default: 90
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
required: [
|
|
584
|
+
"filters"
|
|
585
|
+
]
|
|
586
|
+
},
|
|
587
|
+
confirm: "list",
|
|
588
|
+
scope: "assistant"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
name: "nodes-list",
|
|
592
|
+
usage: "/nodes list [filter\u2026]",
|
|
593
|
+
summary: "Service peers \u2014 network nodes and agents \u2014 with their kind and role. The same filters as /friends list.",
|
|
594
|
+
params: {
|
|
595
|
+
type: "object",
|
|
596
|
+
properties: {
|
|
597
|
+
filters: {
|
|
598
|
+
type: "array",
|
|
599
|
+
items: {
|
|
600
|
+
enum: [
|
|
601
|
+
"never-messaged",
|
|
602
|
+
"never-replied",
|
|
603
|
+
"silent",
|
|
604
|
+
"pending"
|
|
605
|
+
]
|
|
606
|
+
},
|
|
607
|
+
description: "Several filters are OR'd together."
|
|
608
|
+
},
|
|
609
|
+
silentDays: {
|
|
610
|
+
type: "integer",
|
|
611
|
+
minimum: 1,
|
|
612
|
+
default: 90
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
required: []
|
|
616
|
+
},
|
|
617
|
+
confirm: "none",
|
|
618
|
+
scope: "assistant"
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
name: "nodes-remove",
|
|
622
|
+
usage: "/nodes remove <filter\u2026>",
|
|
623
|
+
summary: "The same table with a tick per row and a Remove button, over service peers only.",
|
|
546
624
|
params: {
|
|
547
625
|
type: "object",
|
|
548
626
|
properties: {
|
|
549
627
|
filters: {
|
|
550
628
|
type: "array",
|
|
551
|
-
items: {
|
|
629
|
+
items: {
|
|
630
|
+
enum: [
|
|
631
|
+
"never-messaged",
|
|
632
|
+
"never-replied",
|
|
633
|
+
"silent",
|
|
634
|
+
"pending"
|
|
635
|
+
]
|
|
636
|
+
},
|
|
637
|
+
description: "Several filters are OR'd together.",
|
|
552
638
|
minItems: 1
|
|
553
639
|
},
|
|
554
|
-
silentDays: {
|
|
640
|
+
silentDays: {
|
|
641
|
+
type: "integer",
|
|
642
|
+
minimum: 1,
|
|
643
|
+
default: 90
|
|
644
|
+
}
|
|
555
645
|
},
|
|
556
|
-
required: [
|
|
646
|
+
required: [
|
|
647
|
+
"filters"
|
|
648
|
+
]
|
|
557
649
|
},
|
|
558
650
|
confirm: "list",
|
|
559
651
|
scope: "assistant"
|
|
@@ -564,8 +656,15 @@ var actions_default = {
|
|
|
564
656
|
summary: "Friends whose name, alias, description or ens name contains the text.",
|
|
565
657
|
params: {
|
|
566
658
|
type: "object",
|
|
567
|
-
properties: {
|
|
568
|
-
|
|
659
|
+
properties: {
|
|
660
|
+
text: {
|
|
661
|
+
type: "string",
|
|
662
|
+
minLength: 1
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
required: [
|
|
666
|
+
"text"
|
|
667
|
+
]
|
|
569
668
|
},
|
|
570
669
|
confirm: "none",
|
|
571
670
|
scope: "assistant"
|
|
@@ -577,10 +676,19 @@ var actions_default = {
|
|
|
577
676
|
params: {
|
|
578
677
|
type: "object",
|
|
579
678
|
properties: {
|
|
580
|
-
friend: {
|
|
581
|
-
|
|
679
|
+
friend: {
|
|
680
|
+
type: "string",
|
|
681
|
+
description: "Matches name, alias or userid prefix. Ambiguous = nothing happens, the candidates are listed."
|
|
682
|
+
},
|
|
683
|
+
alias: {
|
|
684
|
+
type: "string",
|
|
685
|
+
minLength: 1
|
|
686
|
+
}
|
|
582
687
|
},
|
|
583
|
-
required: [
|
|
688
|
+
required: [
|
|
689
|
+
"friend",
|
|
690
|
+
"alias"
|
|
691
|
+
]
|
|
584
692
|
},
|
|
585
693
|
confirm: "none",
|
|
586
694
|
scope: "assistant"
|
|
@@ -591,8 +699,14 @@ var actions_default = {
|
|
|
591
699
|
summary: "Stop alerts from one conversation.",
|
|
592
700
|
params: {
|
|
593
701
|
type: "object",
|
|
594
|
-
properties: {
|
|
595
|
-
|
|
702
|
+
properties: {
|
|
703
|
+
friend: {
|
|
704
|
+
type: "string"
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
required: [
|
|
708
|
+
"friend"
|
|
709
|
+
]
|
|
596
710
|
},
|
|
597
711
|
confirm: "none",
|
|
598
712
|
scope: "assistant"
|
|
@@ -603,8 +717,14 @@ var actions_default = {
|
|
|
603
717
|
summary: "Alerts from that conversation again.",
|
|
604
718
|
params: {
|
|
605
719
|
type: "object",
|
|
606
|
-
properties: {
|
|
607
|
-
|
|
720
|
+
properties: {
|
|
721
|
+
friend: {
|
|
722
|
+
type: "string"
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
required: [
|
|
726
|
+
"friend"
|
|
727
|
+
]
|
|
608
728
|
},
|
|
609
729
|
confirm: "none",
|
|
610
730
|
scope: "assistant"
|
|
@@ -615,8 +735,14 @@ var actions_default = {
|
|
|
615
735
|
summary: "Sound on a new message.",
|
|
616
736
|
params: {
|
|
617
737
|
type: "object",
|
|
618
|
-
properties: {
|
|
619
|
-
|
|
738
|
+
properties: {
|
|
739
|
+
on: {
|
|
740
|
+
type: "boolean"
|
|
741
|
+
}
|
|
742
|
+
},
|
|
743
|
+
required: [
|
|
744
|
+
"on"
|
|
745
|
+
]
|
|
620
746
|
},
|
|
621
747
|
confirm: "none",
|
|
622
748
|
scope: "assistant"
|
|
@@ -627,8 +753,14 @@ var actions_default = {
|
|
|
627
753
|
summary: "Flash the window on a new message.",
|
|
628
754
|
params: {
|
|
629
755
|
type: "object",
|
|
630
|
-
properties: {
|
|
631
|
-
|
|
756
|
+
properties: {
|
|
757
|
+
on: {
|
|
758
|
+
type: "boolean"
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
required: [
|
|
762
|
+
"on"
|
|
763
|
+
]
|
|
632
764
|
},
|
|
633
765
|
confirm: "none",
|
|
634
766
|
scope: "assistant"
|
|
@@ -636,8 +768,12 @@ var actions_default = {
|
|
|
636
768
|
{
|
|
637
769
|
name: "status",
|
|
638
770
|
usage: "/status",
|
|
639
|
-
summary: "Friends, pending requests, how far back the history on this device goes, app version.",
|
|
640
|
-
params: {
|
|
771
|
+
summary: "Friends and service peers counted separately, pending requests, how far back the history on this device goes, app version.",
|
|
772
|
+
params: {
|
|
773
|
+
type: "object",
|
|
774
|
+
properties: {},
|
|
775
|
+
required: []
|
|
776
|
+
},
|
|
641
777
|
confirm: "none",
|
|
642
778
|
scope: "assistant"
|
|
643
779
|
}
|
|
@@ -660,7 +796,12 @@ var actions_default = {
|
|
|
660
796
|
usage: "silent [days]",
|
|
661
797
|
summary: "Nothing from them for this many days (default 90).",
|
|
662
798
|
guarded: true,
|
|
663
|
-
arg: {
|
|
799
|
+
arg: {
|
|
800
|
+
name: "days",
|
|
801
|
+
type: "integer",
|
|
802
|
+
default: 90,
|
|
803
|
+
minimum: 1
|
|
804
|
+
}
|
|
664
805
|
},
|
|
665
806
|
{
|
|
666
807
|
name: "pending",
|
|
@@ -678,9 +819,145 @@ var actions_default = {
|
|
|
678
819
|
guard: {
|
|
679
820
|
recentDays: 14,
|
|
680
821
|
applies: "Filters marked guarded never match a friend accepted (or, with no acceptance stamp, requested) less than recentDays ago; the result says how many were skipped."
|
|
822
|
+
},
|
|
823
|
+
servicePeers: {
|
|
824
|
+
file: "service-peers.json",
|
|
825
|
+
loader: "loadServicePeers()",
|
|
826
|
+
rule: "A peer is a service peer if and only if its userid is in this list. The Assistant never infers it from a name or from having no messages. /friends excludes them entirely; /nodes is only them.",
|
|
827
|
+
later: "A dora / ENS / bridge / directory service returns the same shape; the bundled file is v1."
|
|
681
828
|
}
|
|
682
829
|
};
|
|
683
830
|
|
|
831
|
+
// src/assistant/service-peers.json
|
|
832
|
+
var service_peers_default = {
|
|
833
|
+
version: 1,
|
|
834
|
+
source: "static",
|
|
835
|
+
updated: "2026-09-24",
|
|
836
|
+
note: "Service providers and network nodes: peers that are infrastructure or agents, not people. The Assistant manages them with /nodes, never /friends. Later this list comes from a service (dora / ENS / bridge / directory) in this same shape; until then it ships inside the app.",
|
|
837
|
+
peers: [
|
|
838
|
+
{
|
|
839
|
+
userid: "7xmbDbouSYEA5mbAgWxV2BTwjc59XGcVPqXSZx6VibUd",
|
|
840
|
+
name: "lens",
|
|
841
|
+
kind: "node",
|
|
842
|
+
role: "bridge + web host"
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
userid: "4uNnLnAQHVJ7td657MDaz4UnEuhnTW9sRAPSVeAEEQe4",
|
|
846
|
+
name: "tokyo",
|
|
847
|
+
kind: "node",
|
|
848
|
+
role: "exit + relay + dora + meeting"
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
userid: "5Aj6uQMd1cNRb9cGT4AwHCN4RdVZjfaGLtgKGhdP1LzN",
|
|
852
|
+
name: "cn",
|
|
853
|
+
kind: "node",
|
|
854
|
+
role: "exit"
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
userid: "DZN2L9RV1YkHjqGHMTA6juZhskKA65AD2RyPt4umZVc7",
|
|
858
|
+
name: "callpass",
|
|
859
|
+
kind: "node",
|
|
860
|
+
role: "server"
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
userid: "BcGvk2h5XCxBZWJrYwzKpZ8GbxaZRoakEzt2pQpathyA",
|
|
864
|
+
name: "gojipower",
|
|
865
|
+
kind: "node",
|
|
866
|
+
role: "server"
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
userid: "BeMbuKf1poh3U4rjw3eeUAKZsbN2qBSjVZdPSvehmHsw",
|
|
870
|
+
name: "snoopy",
|
|
871
|
+
kind: "node",
|
|
872
|
+
role: "dora + meeting + openclaw host"
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
userid: "CzwUZv6LfiGM7EXd9vXr6DutG8ASkA3TnNbqQzjKRJN5",
|
|
876
|
+
name: "GFAX",
|
|
877
|
+
kind: "node",
|
|
878
|
+
role: "server"
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
userid: "72a4A7awtn6BqZnBt3eNhZH9MdYXRkM6Ht5HG2sqoiKR",
|
|
882
|
+
name: "nv4090-wsl",
|
|
883
|
+
kind: "node",
|
|
884
|
+
role: "GPU node"
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
userid: "6riqxxw18vjwXZEEtFUxbgNBMMe1dcv2kVHqVRQdihjE",
|
|
888
|
+
name: "node-3145",
|
|
889
|
+
kind: "node",
|
|
890
|
+
role: "GPU node (4090w)"
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
userid: "6D1PLSVqbSpcxnDMAd8ZXLWycYveeP2hU4g3igDQEqA7",
|
|
894
|
+
name: "node-5123",
|
|
895
|
+
kind: "node",
|
|
896
|
+
role: "node"
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
userid: "5EU9Ee3Vai1XwTr4pGaJFt4wmNVPUoYnJsdBM9LwNhrJ",
|
|
900
|
+
name: "node-2998",
|
|
901
|
+
kind: "node",
|
|
902
|
+
role: "node"
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
userid: "GujioyKQRucQgw8mwMPNWtYTdNdrooCuFq3R1D4RqjCW",
|
|
906
|
+
name: "beagle-help",
|
|
907
|
+
kind: "agent",
|
|
908
|
+
role: "product support"
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
userid: "FhbohSLrj5UjdyFKCEYNeEWAPq3QD9hRg6hsso5ipag2",
|
|
912
|
+
name: "help.beagles.eth",
|
|
913
|
+
kind: "agent",
|
|
914
|
+
role: "bridge agent"
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
userid: "9EaFGWuXH2UfREzYMkPPitzjoH6E8tvey4JvqTKtHFJh",
|
|
918
|
+
name: "openclaw",
|
|
919
|
+
kind: "agent",
|
|
920
|
+
role: "OpenClaw agent"
|
|
921
|
+
},
|
|
922
|
+
{
|
|
923
|
+
userid: "6z2o8ojPVjFGRzcffUdd5btvDYAt4tLuwJ8j1jvMBU8p",
|
|
924
|
+
name: "ClawAlan",
|
|
925
|
+
kind: "agent",
|
|
926
|
+
role: "OpenClaw agent on snoopy"
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
userid: "G7s3YjVfNLTY5pKBd83qQLAdzDddS7ZstsfrUySwK2Cb",
|
|
930
|
+
name: "interview",
|
|
931
|
+
kind: "agent",
|
|
932
|
+
role: "interview"
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
userid: "6jbXjrUWJ4zYvG8BDLnu8KVpoL7rhsdHYSwWER6WTfdt",
|
|
936
|
+
name: "interview editor",
|
|
937
|
+
kind: "agent",
|
|
938
|
+
role: "interview"
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
userid: "8BGemh6uqmh4X7KpnPVMeMSU8hZwAc6ZDo4MBRMFrq2L",
|
|
942
|
+
name: "readyplayer",
|
|
943
|
+
kind: "agent",
|
|
944
|
+
role: "readyplayer"
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
userid: "Ev1XmWRwtjQf8n33wgTwEhzXnYEyfqTyanehuDE6nczF",
|
|
948
|
+
name: "ReadyPlayer membership manager",
|
|
949
|
+
kind: "agent",
|
|
950
|
+
role: "readyplayer"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
userid: "7xLPH2kjk7Nn8GrsAt7TYwa6b1WMPLkC2XRx7BzhiXYT",
|
|
954
|
+
name: "ai-btc-trader",
|
|
955
|
+
kind: "agent",
|
|
956
|
+
role: "btc signals (245)"
|
|
957
|
+
}
|
|
958
|
+
]
|
|
959
|
+
};
|
|
960
|
+
|
|
684
961
|
// src/assistant/filters.js
|
|
685
962
|
var ASSISTANT_ID = "__assistant__";
|
|
686
963
|
var DAY_MS = 864e5;
|
|
@@ -696,11 +973,11 @@ function parseCommand(line) {
|
|
|
696
973
|
if (!parts.length)
|
|
697
974
|
return null;
|
|
698
975
|
const head = parts[0].toLowerCase();
|
|
699
|
-
if (head === "friends") {
|
|
976
|
+
if (head === "friends" || head === "nodes") {
|
|
700
977
|
const sub = (parts[1] || "").toLowerCase();
|
|
701
978
|
if (sub === "list" || sub === "remove")
|
|
702
|
-
return { ok: true, name:
|
|
703
|
-
return { ok: false, name:
|
|
979
|
+
return { ok: true, name: `${head}-${sub}`, args: parts.slice(2) };
|
|
980
|
+
return { ok: false, name: head, args: parts.slice(1), error: `${head}-subcommand` };
|
|
704
981
|
}
|
|
705
982
|
return { ok: true, name: head, args: parts.slice(1) };
|
|
706
983
|
}
|
|
@@ -727,6 +1004,30 @@ function parseFilters(args) {
|
|
|
727
1004
|
}
|
|
728
1005
|
return { filters, silentDays, unknown };
|
|
729
1006
|
}
|
|
1007
|
+
function servicePeerMap(list) {
|
|
1008
|
+
const map = /* @__PURE__ */ new Map();
|
|
1009
|
+
const peers = list && list.peers || [];
|
|
1010
|
+
for (const p of peers) {
|
|
1011
|
+
if (p && typeof p.userid === "string" && p.userid) {
|
|
1012
|
+
map.set(p.userid, { kind: p.kind === "agent" ? "agent" : "node", role: p.role || "", name: p.name || "" });
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
return map;
|
|
1016
|
+
}
|
|
1017
|
+
function partitionPeers(friends, svcMap) {
|
|
1018
|
+
const people = [];
|
|
1019
|
+
const nodes = [];
|
|
1020
|
+
for (const f of friends != null ? friends : []) {
|
|
1021
|
+
if (!f)
|
|
1022
|
+
continue;
|
|
1023
|
+
const svc = svcMap && svcMap.get(f.userid);
|
|
1024
|
+
if (svc)
|
|
1025
|
+
nodes.push(Object.assign({}, f, { kind: svc.kind, role: svc.role, service: true }));
|
|
1026
|
+
else
|
|
1027
|
+
people.push(f);
|
|
1028
|
+
}
|
|
1029
|
+
return { people, nodes };
|
|
1030
|
+
}
|
|
730
1031
|
var acceptedOrRequestedAt = (f) => f.acceptedAt || f.requestedAt || 0;
|
|
731
1032
|
function isRecent(friend, now, recentDays = RECENT_DAYS) {
|
|
732
1033
|
const at = acceptedOrRequestedAt(friend);
|
|
@@ -797,6 +1098,9 @@ function resolveFriend(friends, token) {
|
|
|
797
1098
|
}
|
|
798
1099
|
|
|
799
1100
|
// src/assistant.jsx
|
|
1101
|
+
function loadServicePeers() {
|
|
1102
|
+
return service_peers_default;
|
|
1103
|
+
}
|
|
800
1104
|
var ASSISTANT_PEER = {
|
|
801
1105
|
id: ASSISTANT_ID,
|
|
802
1106
|
userId: ASSISTANT_ID,
|
|
@@ -835,11 +1139,14 @@ var fmtAgo = (ts, now, lang) => {
|
|
|
835
1139
|
var nameOf = (f) => f.alias || f.name || f.userid;
|
|
836
1140
|
function sinceLine(historySince, lang) {
|
|
837
1141
|
if (!historySince)
|
|
838
|
-
return lang === "zh" ? "
|
|
839
|
-
return lang === "zh" ?
|
|
1142
|
+
return lang === "zh" ? "*\u57FA\u4E8E\u672C\u8BBE\u5907\u4E0A\u7684\u6D88\u606F\uFF08\u672C\u673A\u6682\u65E0\u5386\u53F2\u8BB0\u5F55\uFF09*" : "*based on messages on this device (no history here yet)*";
|
|
1143
|
+
return lang === "zh" ? `*\u57FA\u4E8E\u672C\u8BBE\u5907\u81EA ${fmtDate(historySince, lang)} \u8D77\u7684\u6D88\u606F*` : `*based on messages on this device since ${fmtDate(historySince, lang)}*`;
|
|
840
1144
|
}
|
|
841
1145
|
function friendTable(rows, now, lang) {
|
|
842
|
-
return rows.map((f) =>
|
|
1146
|
+
return rows.map((f) => {
|
|
1147
|
+
const what = f.service ? ` \`${f.kind}${f.role ? " \xB7 " + f.role : ""}\`` : "";
|
|
1148
|
+
return lang === "zh" ? `- **${nameOf(f)}**${what} \u2014 \u6700\u540E\u6536\u5230 ${fmtAgo(f.lastInboundTs, now, lang)} \xB7 \u6536 ${f.inboundCount || 0} / \u53D1 ${f.outboundCount || 0}` : `- **${nameOf(f)}**${what} \u2014 last heard ${fmtAgo(f.lastInboundTs, now, lang)} \xB7 in ${f.inboundCount || 0} / out ${f.outboundCount || 0}`;
|
|
1149
|
+
}).join("\n");
|
|
843
1150
|
}
|
|
844
1151
|
function helpText(lang) {
|
|
845
1152
|
const intro = lang === "zh" ? "**Beagle \u52A9\u624B** \u2014 \u53EA\u5728\u672C\u673A\u8FD0\u884C\uFF0C\u4E0D\u4F1A\u628A\u4EFB\u4F55\u5185\u5BB9\u53D1\u5230\u7F51\u7EDC\u4E0A\u3002\n\n\u53EF\u7528\u547D\u4EE4\uFF1A" : "**Beagle Assistant** \u2014 runs on this machine only; nothing here is sent over the network.\n\nCommands:";
|
|
@@ -908,7 +1215,15 @@ function useAssistant({ lang, T, muted, onToggleMute, sound, flash, setAlert, on
|
|
|
908
1215
|
}, [lang]);
|
|
909
1216
|
const fetchFriends = async () => {
|
|
910
1217
|
const r = await fetch("/api/assistant/friends").then((x) => x.json());
|
|
911
|
-
|
|
1218
|
+
const { people, nodes } = partitionPeers(r.friends || [], servicePeerMap(loadServicePeers()));
|
|
1219
|
+
return {
|
|
1220
|
+
friends: people,
|
|
1221
|
+
nodes,
|
|
1222
|
+
all: r.friends || [],
|
|
1223
|
+
historySince: r.historySince || null,
|
|
1224
|
+
now: r.now || Date.now(),
|
|
1225
|
+
ver: r.beagleVer || ""
|
|
1226
|
+
};
|
|
912
1227
|
};
|
|
913
1228
|
const listReply = (rows, skipped, data, title) => {
|
|
914
1229
|
if (!rows.length) {
|
|
@@ -920,9 +1235,9 @@ ${sinceLine(data.historySince, lang)}`;
|
|
|
920
1235
|
}
|
|
921
1236
|
const skip = skipped.length ? lang === "zh" ? `
|
|
922
1237
|
|
|
923
|
-
|
|
1238
|
+
*\u8DF3\u8FC7\u4E86 ${skipped.length} \u4F4D\u6700\u8FD1 ${RECENT_DAYS} \u5929\u5185\u6DFB\u52A0\u7684\u597D\u53CB\u3002*` : `
|
|
924
1239
|
|
|
925
|
-
|
|
1240
|
+
*${skipped.length} friend${skipped.length > 1 ? "s" : ""} added in the last ${RECENT_DAYS} days ${skipped.length > 1 ? "were" : "was"} skipped.*` : "";
|
|
926
1241
|
return `${title}
|
|
927
1242
|
|
|
928
1243
|
${friendTable(rows, data.now, lang)}${skip}
|
|
@@ -940,7 +1255,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
940
1255
|
return append(asMsg("them", lang === "zh" ? "\u6211\u53EA\u8BA4\u8BC6\u4EE5 `/` \u5F00\u5934\u7684\u547D\u4EE4\u3002\u8F93\u5165 `/help` \u770B\u770B\u80FD\u505A\u4EC0\u4E48\u3002" : "I only understand commands starting with `/`. Type `/help` to see them."));
|
|
941
1256
|
}
|
|
942
1257
|
if (cmd.ok === false) {
|
|
943
|
-
return append(asMsg("them", lang === "zh" ?
|
|
1258
|
+
return append(asMsg("them", lang === "zh" ? `\`/${cmd.name}\` \u9700\u8981 \`list\` \u6216 \`remove\`\uFF0C\u4F8B\u5982 \`/${cmd.name} list silent 90\`\u3002` : `\`/${cmd.name}\` needs \`list\` or \`remove\`, for example \`/${cmd.name} list silent 90\`.`));
|
|
944
1259
|
}
|
|
945
1260
|
try {
|
|
946
1261
|
switch (cmd.name) {
|
|
@@ -948,37 +1263,48 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
948
1263
|
return append(asMsg("them", helpText(lang)));
|
|
949
1264
|
case "status": {
|
|
950
1265
|
const d = await fetchFriends();
|
|
951
|
-
const pending = d.
|
|
1266
|
+
const pending = d.all.filter((f) => f.pending).length;
|
|
1267
|
+
const nodeCount = d.nodes.filter((n) => n.kind === "node").length;
|
|
1268
|
+
const agentCount = d.nodes.length - nodeCount;
|
|
952
1269
|
return append(asMsg("them", lang === "zh" ? `**\u72B6\u6001**
|
|
953
1270
|
|
|
954
1271
|
- \u597D\u53CB\uFF1A${d.friends.length}
|
|
1272
|
+
- \u670D\u52A1\u8282\u70B9\uFF1A${d.nodes.length}\uFF08\u8282\u70B9 ${nodeCount} \xB7 \u667A\u80FD\u4F53 ${agentCount}\uFF09\uFF0C\u7528 \`/nodes list\` \u67E5\u770B
|
|
955
1273
|
- \u5F85\u5BF9\u65B9\u63A5\u53D7\uFF1A${pending}
|
|
956
1274
|
- \u672C\u673A\u5386\u53F2\u8D77\u81EA\uFF1A${fmtDate(d.historySince, lang)}
|
|
957
1275
|
- \u7248\u672C\uFF1A${d.ver}` : `**Status**
|
|
958
1276
|
|
|
959
1277
|
- Friends: ${d.friends.length}
|
|
1278
|
+
- Service peers: ${d.nodes.length} (${nodeCount} node${nodeCount === 1 ? "" : "s"} \xB7 ${agentCount} agent${agentCount === 1 ? "" : "s"}) \u2014 see \`/nodes list\`
|
|
960
1279
|
- Waiting to be accepted: ${pending}
|
|
961
1280
|
- History on this device since: ${fmtDate(d.historySince, lang)}
|
|
962
1281
|
- Version: ${d.ver}`));
|
|
963
1282
|
}
|
|
1283
|
+
case "nodes-list":
|
|
964
1284
|
case "friends-list": {
|
|
1285
|
+
const nodesMode = cmd.name === "nodes-list";
|
|
965
1286
|
const { filters, silentDays, unknown } = parseFilters(cmd.args);
|
|
966
1287
|
if (unknown.length) {
|
|
967
1288
|
return append(asMsg("them", lang === "zh" ? `\u4E0D\u8BA4\u8BC6\u7684\u7B5B\u9009\u6761\u4EF6\uFF1A${unknown.join(", ")}\u3002\u53EF\u7528\uFF1A${actions_default.filters.map((f) => f.name).join(", ")}\u3002` : `I don't know the filter${unknown.length > 1 ? "s" : ""} ${unknown.join(", ")}. Try: ${actions_default.filters.map((f) => f.name).join(", ")}.`));
|
|
968
1289
|
}
|
|
969
1290
|
const d = await fetchFriends();
|
|
970
|
-
const
|
|
971
|
-
const
|
|
1291
|
+
const pool = nodesMode ? d.nodes : d.friends;
|
|
1292
|
+
const { matched, skippedRecent } = selectFriends(pool, filters, { now: d.now, silentDays });
|
|
1293
|
+
const all = nodesMode ? lang === "zh" ? `**\u5168\u90E8\u670D\u52A1\u8282\u70B9** \u2014 ${matched.length}` : `**All service peers** \u2014 ${matched.length}` : lang === "zh" ? `**\u5168\u90E8\u597D\u53CB** \u2014 ${matched.length}` : `**All friends** \u2014 ${matched.length}`;
|
|
1294
|
+
const title = filters.length ? `**${nodesMode ? (lang === "zh" ? "\u670D\u52A1\u8282\u70B9" : "service peers") + ": " : ""}${filters.join(" + ")}**${filters.includes("silent") ? ` (${silentDays}d)` : ""} \u2014 ${matched.length}` : all;
|
|
972
1295
|
return append(asMsg("them", listReply(matched, skippedRecent, d, title)));
|
|
973
1296
|
}
|
|
1297
|
+
case "nodes-remove":
|
|
974
1298
|
case "friends-remove": {
|
|
1299
|
+
const nodesMode = cmd.name === "nodes-remove";
|
|
975
1300
|
const { filters, silentDays, unknown } = parseFilters(cmd.args);
|
|
976
1301
|
if (unknown.length || !filters.length) {
|
|
977
1302
|
return append(asMsg("them", lang === "zh" ? `\u5220\u9664\u9700\u8981\u7B5B\u9009\u6761\u4EF6\uFF0C\u4F8B\u5982 \`/friends remove never-messaged\`\u3002\u53EF\u7528\uFF1A${actions_default.filters.map((f) => f.name).join(", ")}\u3002` : `Removing needs a filter, for example \`/friends remove never-messaged\`. Available: ${actions_default.filters.map((f) => f.name).join(", ")}.`));
|
|
978
1303
|
}
|
|
979
1304
|
const d = await fetchFriends();
|
|
980
|
-
const { matched, skippedRecent } = selectFriends(d.friends, filters, { now: d.now, silentDays });
|
|
981
|
-
const
|
|
1305
|
+
const { matched, skippedRecent } = selectFriends(nodesMode ? d.nodes : d.friends, filters, { now: d.now, silentDays });
|
|
1306
|
+
const what = nodesMode ? lang === "zh" ? "\u4E2A\u670D\u52A1\u8282\u70B9" : `service peer${matched.length === 1 ? "" : "s"}` : lang === "zh" ? "\u4F4D\u597D\u53CB" : `friend${matched.length === 1 ? "" : "s"}`;
|
|
1307
|
+
const title = lang === "zh" ? `**\u5C06\u8981\u5220\u9664 ${matched.length} ${what}** \u2014 \u8BF7\u5148\u6838\u5BF9\u8FD9\u4EFD\u540D\u5355` : `**${matched.length} ${what} to remove** \u2014 check the list first`;
|
|
982
1308
|
return append(asMsg(
|
|
983
1309
|
"them",
|
|
984
1310
|
listReply(matched, skippedRecent, d, title),
|
|
@@ -990,7 +1316,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
990
1316
|
if (!q)
|
|
991
1317
|
return append(asMsg("them", lang === "zh" ? "\u7528\u6CD5\uFF1A`/find <\u6587\u5B57>`" : "Usage: `/find <text>`"));
|
|
992
1318
|
const d = await fetchFriends();
|
|
993
|
-
const rows = findFriends(d.friends, q);
|
|
1319
|
+
const rows = findFriends(d.friends.concat(d.nodes), q);
|
|
994
1320
|
const title = lang === "zh" ? `**"${q}"** \u2014 ${rows.length} \u4F4D` : `**"${q}"** \u2014 ${rows.length} found`;
|
|
995
1321
|
return append(asMsg("them", listReply(rows, [], d, title)));
|
|
996
1322
|
}
|
|
@@ -1000,7 +1326,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
1000
1326
|
if (!tok || !alias)
|
|
1001
1327
|
return append(asMsg("them", lang === "zh" ? "\u7528\u6CD5\uFF1A`/rename <\u597D\u53CB> <\u65B0\u540D\u5B57>`" : "Usage: `/rename <friend> <new name>`"));
|
|
1002
1328
|
const d = await fetchFriends();
|
|
1003
|
-
const { match, candidates } = resolveFriend(d.friends, tok);
|
|
1329
|
+
const { match, candidates } = resolveFriend(d.friends.concat(d.nodes), tok);
|
|
1004
1330
|
if (!match)
|
|
1005
1331
|
return append(asMsg("them", candidates.length ? ambiguous(candidates) : notFound(tok)));
|
|
1006
1332
|
const was = nameOf(match);
|
|
@@ -1015,7 +1341,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
1015
1341
|
if (!tok)
|
|
1016
1342
|
return append(asMsg("them", `${lang === "zh" ? "\u7528\u6CD5" : "Usage"}: \`/${cmd.name} <friend>\``));
|
|
1017
1343
|
const d = await fetchFriends();
|
|
1018
|
-
const { match, candidates } = resolveFriend(d.friends, tok);
|
|
1344
|
+
const { match, candidates } = resolveFriend(d.friends.concat(d.nodes), tok);
|
|
1019
1345
|
if (!match)
|
|
1020
1346
|
return append(asMsg("them", candidates.length ? ambiguous(candidates) : notFound(tok)));
|
|
1021
1347
|
const isMuted = (muted || []).includes(match.userid);
|
|
@@ -2547,7 +2873,11 @@ function Conversation({ T, peer, lang, peers, onOpenChat, thread: threadProp, on
|
|
|
2547
2873
|
style: { width: 40, height: 44, flexShrink: 0, border: "none", background: "transparent", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", padding: 0 }
|
|
2548
2874
|
},
|
|
2549
2875
|
/* @__PURE__ */ React.createElement(Icon, { name: "chevronLeft", size: 26, stroke: 2.2, color: "var(--accent)" })
|
|
2550
|
-
), /* @__PURE__ */ React.createElement("div", { onClick: () => setPubProfile(true), title: T && T.pubOpen || "View public profile", style: { cursor: "pointer", flexShrink: 0 } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 34, radius: 8 })), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0, flex: phone ? 1 : void 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 } }, /* @__PURE__ */ React.createElement("span", { onClick: () => setPubProfile(true), style: { fontFamily: peer.alias ? "var(--ui)" : "var(--mono)", fontSize: 15, fontWeight: 700, color: "var(--text)", cursor: "pointer", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 } }, peer.alias || shortKey(peer.userId, phone ? 6 : 10, phone ? 4 : 6)), peer.app && !phone && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "APP"), peer.agent && !phone && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "agent"), isGroup && !phone && /* @__PURE__ */ React.createElement(Tag, null, T && T.groupTag || "group"), !phone && !peer.app && /* @__PURE__ */ React.createElement(RouteTag, { peer })),
|
|
2876
|
+
), /* @__PURE__ */ React.createElement("div", { onClick: () => setPubProfile(true), title: T && T.pubOpen || "View public profile", style: { cursor: "pointer", flexShrink: 0 } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 34, radius: 8 })), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0, flex: phone ? 1 : void 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 } }, /* @__PURE__ */ React.createElement("span", { onClick: () => setPubProfile(true), style: { fontFamily: peer.alias ? "var(--ui)" : "var(--mono)", fontSize: 15, fontWeight: 700, color: "var(--text)", cursor: "pointer", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 } }, peer.alias || shortKey(peer.userId, phone ? 6 : 10, phone ? 4 : 6)), peer.app && !phone && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "APP"), peer.agent && !phone && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "agent"), isGroup && !phone && /* @__PURE__ */ React.createElement(Tag, null, T && T.groupTag || "group"), !phone && !peer.app && /* @__PURE__ */ React.createElement(RouteTag, { peer })), peer.app ? (
|
|
2877
|
+
// The internal id is not an address anyone can use and not a name
|
|
2878
|
+
// anyone chose; saying what this row IS is more use than showing it.
|
|
2879
|
+
/* @__PURE__ */ React.createElement("div", { style: { marginTop: 2, fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--faint)" } }, T && T.assistantSub || "Local \xB7 APP")
|
|
2880
|
+
) : phone ? /* @__PURE__ */ React.createElement("div", { style: { marginTop: 2, display: "flex" } }, /* @__PURE__ */ React.createElement(RouteTag, { peer })) : /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 2 } }, /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.userId, title: peer.userId }, shortKey(peer.userId, 10, 6)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement("button", { onClick: () => onOpenNet(peer), title: T && T.openNet || "Network view", style: { background: "none", border: "none", cursor: "pointer", padding: 0, color: "var(--accent)", display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "network", size: 12, stroke: 2 })), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.ip, title: peer.ip }, peer.ip), peer.address && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement(
|
|
2551
2881
|
Mono,
|
|
2552
2882
|
{
|
|
2553
2883
|
size: 11.5,
|
|
@@ -2565,7 +2895,7 @@ ${peer.address}`
|
|
|
2565
2895
|
title: muted ? T && T.unmuteSound || "Turn sound back on for this chat" : T && T.muteSound || "Mute sound for this chat",
|
|
2566
2896
|
onClick: () => onToggleMute(peer.id)
|
|
2567
2897
|
}
|
|
2568
|
-
), onCall && /* @__PURE__ */ React.createElement(Btn, { icon: "phone", title: T && T.audioCall || "Audio call", onClick: () => onCall(peer.userId, false) }), onCall && /* @__PURE__ */ React.createElement(Btn, { icon: "video", title: T && T.videoCall || "Video call", onClick: () => onCall(peer.userId, true) }), onSendRtcFile && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
2898
|
+
), onCall && !peer.app && /* @__PURE__ */ React.createElement(Btn, { icon: "phone", title: T && T.audioCall || "Audio call", onClick: () => onCall(peer.userId, false) }), onCall && !peer.app && /* @__PURE__ */ React.createElement(Btn, { icon: "video", title: T && T.videoCall || "Video call", onClick: () => onCall(peer.userId, true) }), onSendRtcFile && !peer.app && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
2569
2899
|
"input",
|
|
2570
2900
|
{
|
|
2571
2901
|
ref: rtcFileRef,
|
|
@@ -2579,19 +2909,19 @@ ${peer.address}`
|
|
|
2579
2909
|
), !phone && /* @__PURE__ */ React.createElement(Btn, { icon: "file", title: T && T.sendWebrtcFile || "Send file via WebRTC", onClick: () => rtcFileRef.current && rtcFileRef.current.click() })), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(Btn, { icon: "more", onClick: () => setMenu((v) => !v) }), menu && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { onClick: () => setMenu(false), style: { position: "fixed", inset: 0, zIndex: 40 } }), /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", right: 0, top: 36, zIndex: 50, width: 180, background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 9, padding: 6, boxShadow: "0 14px 40px rgba(0,0,0,0.4)" } }, phone && onToggleMute && /* @__PURE__ */ React.createElement(MenuItem, { icon: muted ? "bell" : "bellOff", label: muted ? T && T.unmuteSound || "Turn sound back on" : T && T.muteSound || "Mute sound", onClick: () => {
|
|
2580
2910
|
setMenu(false);
|
|
2581
2911
|
onToggleMute(peer.id);
|
|
2582
|
-
} }), phone && onSendRtcFile && /* @__PURE__ */ React.createElement(MenuItem, { icon: "file", label: T && T.sendWebrtcFile || "Send file via WebRTC", onClick: () => {
|
|
2912
|
+
} }), phone && onSendRtcFile && !peer.app && /* @__PURE__ */ React.createElement(MenuItem, { icon: "file", label: T && T.sendWebrtcFile || "Send file via WebRTC", onClick: () => {
|
|
2583
2913
|
setMenu(false);
|
|
2584
2914
|
rtcFileRef.current && rtcFileRef.current.click();
|
|
2585
|
-
} }), phone && /* @__PURE__ */ React.createElement(MenuItem, { icon: "network", label: T && T.openNet || "Network view", onClick: () => {
|
|
2915
|
+
} }), phone && !peer.app && /* @__PURE__ */ React.createElement(MenuItem, { icon: "network", label: T && T.openNet || "Network view", onClick: () => {
|
|
2586
2916
|
setMenu(false);
|
|
2587
2917
|
onOpenNet(peer);
|
|
2588
|
-
} }), /* @__PURE__ */ React.createElement(MenuItem, { icon: "hash", label: T.alias, onClick: () => {
|
|
2918
|
+
} }), !peer.app && /* @__PURE__ */ React.createElement(MenuItem, { icon: "hash", label: T.alias, onClick: () => {
|
|
2589
2919
|
setMenu(false);
|
|
2590
2920
|
onAlias(peer);
|
|
2591
2921
|
} }), /* @__PURE__ */ React.createElement(MenuItem, { icon: "check", label: T.selectDelete || "Select & delete", onClick: () => {
|
|
2592
2922
|
setMenu(false);
|
|
2593
2923
|
setSelMode(true);
|
|
2594
|
-
} }), /* @__PURE__ */ React.createElement("div", { style: { height: 1, background: "var(--line)", margin: "5px 4px" } }), /* @__PURE__ */ React.createElement(MenuItem, { icon: "trash", label: T.remove, danger: true, onClick: () => {
|
|
2924
|
+
} }), !peer.app && /* @__PURE__ */ React.createElement("div", { style: { height: 1, background: "var(--line)", margin: "5px 4px" } }), !peer.app && /* @__PURE__ */ React.createElement(MenuItem, { icon: "trash", label: T.remove, danger: true, onClick: () => {
|
|
2595
2925
|
setMenu(false);
|
|
2596
2926
|
onRemove(peer);
|
|
2597
2927
|
} }))))),
|
|
@@ -2665,7 +2995,7 @@ ${peer.address}`
|
|
|
2665
2995
|
e.target.value = "";
|
|
2666
2996
|
}
|
|
2667
2997
|
}
|
|
2668
|
-
), /* @__PURE__ */ React.createElement(Btn, { icon: "paperclip", title: T.sendFile, onClick: () => fileRef.current && fileRef.current.click() }), /* @__PURE__ */ React.createElement(
|
|
2998
|
+
), !peer.app && /* @__PURE__ */ React.createElement(Btn, { icon: "paperclip", title: T.sendFile, onClick: () => fileRef.current && fileRef.current.click() }), /* @__PURE__ */ React.createElement(
|
|
2669
2999
|
"input",
|
|
2670
3000
|
{
|
|
2671
3001
|
value: draft,
|
|
@@ -5558,6 +5888,7 @@ var STR = {
|
|
|
5558
5888
|
autoAcceptLabel: "Auto-accept friend requests",
|
|
5559
5889
|
autoAcceptSub: "Off: requests wait in the sidebar for your approval.",
|
|
5560
5890
|
groupSenderUnknown: "The group relays only this display name. Register Beagle as a group agent (/agent add <beagle address> in the group) to receive full member identities you can add as friends.",
|
|
5891
|
+
assistantSub: "Local \xB7 APP",
|
|
5561
5892
|
loadEarlier: "Load earlier messages",
|
|
5562
5893
|
loadingEarlier: "Loading\u2026",
|
|
5563
5894
|
pendingFriend: "Waiting for them to accept your friend request \u2014 messages will queue and deliver once they do.",
|
|
@@ -5752,6 +6083,7 @@ var STR = {
|
|
|
5752
6083
|
autoAcceptLabel: "\u81EA\u52A8\u63A5\u53D7\u597D\u53CB\u8BF7\u6C42",
|
|
5753
6084
|
autoAcceptSub: "\u5173\u95ED\u540E\uFF0C\u597D\u53CB\u8BF7\u6C42\u4F1A\u7B49\u5F85\u4F60\u5728\u4FA7\u8FB9\u680F\u624B\u52A8\u786E\u8BA4\u3002",
|
|
5754
6085
|
groupSenderUnknown: "\u7FA4\u670D\u52A1\u53EA\u8F6C\u53D1\u4E86\u663E\u793A\u540D\uFF0C\u62FF\u4E0D\u5230\u8BE5\u6210\u5458\u7684\u5B8C\u6574\u8EAB\u4EFD\u3002\u5728\u7FA4\u91CC\u6267\u884C /agent add <beagle \u5730\u5740> \u628A Beagle \u6CE8\u518C\u4E3A\u7FA4 agent \u540E\uFF0C\u5373\u53EF\u6536\u5230\u5B8C\u6574\u8EAB\u4EFD\u5E76\u4E00\u952E\u52A0\u597D\u53CB\u3002",
|
|
6086
|
+
assistantSub: "\u672C\u673A \xB7 APP",
|
|
5755
6087
|
loadEarlier: "\u52A0\u8F7D\u66F4\u65E9\u7684\u6D88\u606F",
|
|
5756
6088
|
loadingEarlier: "\u52A0\u8F7D\u4E2D\u2026",
|
|
5757
6089
|
pendingFriend: "\u7B49\u5F85\u5BF9\u65B9\u63A5\u53D7\u597D\u53CB\u8BF7\u6C42 \u2014 \u6D88\u606F\u4F1A\u5148\u6392\u961F\uFF0C\u5BF9\u65B9\u63A5\u53D7\u540E\u81EA\u52A8\u9001\u8FBE\u3002",
|
package/package.json
CHANGED