@decentnetwork/beagle 0.1.108 → 0.1.110
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/desktop/app.js +434 -40
- package/package.json +2 -2
package/dist/desktop/app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
window.__DK_UI_VERSION="0.1.
|
|
1
|
+
window.__DK_UI_VERSION="0.1.110";
|
|
2
2
|
"use strict";
|
|
3
3
|
(() => {
|
|
4
4
|
// packages/beagle-ui/dist/beagle-ui.js
|
|
@@ -510,23 +510,39 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
510
510
|
name: "help",
|
|
511
511
|
usage: "/help",
|
|
512
512
|
summary: "List what the Assistant can do.",
|
|
513
|
-
params: {
|
|
513
|
+
params: {
|
|
514
|
+
type: "object",
|
|
515
|
+
properties: {},
|
|
516
|
+
required: []
|
|
517
|
+
},
|
|
514
518
|
confirm: "none",
|
|
515
519
|
scope: "assistant"
|
|
516
520
|
},
|
|
517
521
|
{
|
|
518
522
|
name: "friends-list",
|
|
519
523
|
usage: "/friends list [filter\u2026]",
|
|
520
|
-
summary: "Show friends as a
|
|
524
|
+
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.",
|
|
521
525
|
params: {
|
|
522
526
|
type: "object",
|
|
523
527
|
properties: {
|
|
524
528
|
filters: {
|
|
525
529
|
type: "array",
|
|
526
|
-
items: {
|
|
530
|
+
items: {
|
|
531
|
+
enum: [
|
|
532
|
+
"never-messaged",
|
|
533
|
+
"never-replied",
|
|
534
|
+
"silent",
|
|
535
|
+
"pending"
|
|
536
|
+
]
|
|
537
|
+
},
|
|
527
538
|
description: "Several filters are OR'd together."
|
|
528
539
|
},
|
|
529
|
-
silentDays: {
|
|
540
|
+
silentDays: {
|
|
541
|
+
type: "integer",
|
|
542
|
+
minimum: 1,
|
|
543
|
+
default: 90,
|
|
544
|
+
description: "Argument of the silent filter: nothing from them in this many days."
|
|
545
|
+
}
|
|
530
546
|
},
|
|
531
547
|
required: []
|
|
532
548
|
},
|
|
@@ -536,18 +552,94 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
536
552
|
{
|
|
537
553
|
name: "friends-remove",
|
|
538
554
|
usage: "/friends remove <filter\u2026>",
|
|
539
|
-
summary: "Same
|
|
555
|
+
summary: "Same list with a tick per row and a Remove button. Nothing is removed by typing alone. Service peers are never matched.",
|
|
556
|
+
params: {
|
|
557
|
+
type: "object",
|
|
558
|
+
properties: {
|
|
559
|
+
filters: {
|
|
560
|
+
type: "array",
|
|
561
|
+
items: {
|
|
562
|
+
enum: [
|
|
563
|
+
"never-messaged",
|
|
564
|
+
"never-replied",
|
|
565
|
+
"silent",
|
|
566
|
+
"pending"
|
|
567
|
+
]
|
|
568
|
+
},
|
|
569
|
+
minItems: 1
|
|
570
|
+
},
|
|
571
|
+
silentDays: {
|
|
572
|
+
type: "integer",
|
|
573
|
+
minimum: 1,
|
|
574
|
+
default: 90
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
required: [
|
|
578
|
+
"filters"
|
|
579
|
+
]
|
|
580
|
+
},
|
|
581
|
+
confirm: "list",
|
|
582
|
+
scope: "assistant"
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
name: "nodes-list",
|
|
586
|
+
usage: "/nodes list [filter\u2026]",
|
|
587
|
+
summary: "Service peers \u2014 network nodes and agents \u2014 with their kind and role. The same filters as /friends list.",
|
|
588
|
+
params: {
|
|
589
|
+
type: "object",
|
|
590
|
+
properties: {
|
|
591
|
+
filters: {
|
|
592
|
+
type: "array",
|
|
593
|
+
items: {
|
|
594
|
+
enum: [
|
|
595
|
+
"never-messaged",
|
|
596
|
+
"never-replied",
|
|
597
|
+
"silent",
|
|
598
|
+
"pending"
|
|
599
|
+
]
|
|
600
|
+
},
|
|
601
|
+
description: "Several filters are OR'd together."
|
|
602
|
+
},
|
|
603
|
+
silentDays: {
|
|
604
|
+
type: "integer",
|
|
605
|
+
minimum: 1,
|
|
606
|
+
default: 90
|
|
607
|
+
}
|
|
608
|
+
},
|
|
609
|
+
required: []
|
|
610
|
+
},
|
|
611
|
+
confirm: "none",
|
|
612
|
+
scope: "assistant"
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: "nodes-remove",
|
|
616
|
+
usage: "/nodes remove <filter\u2026>",
|
|
617
|
+
summary: "The same table with a tick per row and a Remove button, over service peers only.",
|
|
540
618
|
params: {
|
|
541
619
|
type: "object",
|
|
542
620
|
properties: {
|
|
543
621
|
filters: {
|
|
544
622
|
type: "array",
|
|
545
|
-
items: {
|
|
623
|
+
items: {
|
|
624
|
+
enum: [
|
|
625
|
+
"never-messaged",
|
|
626
|
+
"never-replied",
|
|
627
|
+
"silent",
|
|
628
|
+
"pending"
|
|
629
|
+
]
|
|
630
|
+
},
|
|
631
|
+
description: "Several filters are OR'd together.",
|
|
546
632
|
minItems: 1
|
|
547
633
|
},
|
|
548
|
-
silentDays: {
|
|
634
|
+
silentDays: {
|
|
635
|
+
type: "integer",
|
|
636
|
+
minimum: 1,
|
|
637
|
+
default: 90
|
|
638
|
+
}
|
|
549
639
|
},
|
|
550
|
-
required: [
|
|
640
|
+
required: [
|
|
641
|
+
"filters"
|
|
642
|
+
]
|
|
551
643
|
},
|
|
552
644
|
confirm: "list",
|
|
553
645
|
scope: "assistant"
|
|
@@ -558,8 +650,15 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
558
650
|
summary: "Friends whose name, alias, description or ens name contains the text.",
|
|
559
651
|
params: {
|
|
560
652
|
type: "object",
|
|
561
|
-
properties: {
|
|
562
|
-
|
|
653
|
+
properties: {
|
|
654
|
+
text: {
|
|
655
|
+
type: "string",
|
|
656
|
+
minLength: 1
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
required: [
|
|
660
|
+
"text"
|
|
661
|
+
]
|
|
563
662
|
},
|
|
564
663
|
confirm: "none",
|
|
565
664
|
scope: "assistant"
|
|
@@ -571,10 +670,19 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
571
670
|
params: {
|
|
572
671
|
type: "object",
|
|
573
672
|
properties: {
|
|
574
|
-
friend: {
|
|
575
|
-
|
|
673
|
+
friend: {
|
|
674
|
+
type: "string",
|
|
675
|
+
description: "Matches name, alias or userid prefix. Ambiguous = nothing happens, the candidates are listed."
|
|
676
|
+
},
|
|
677
|
+
alias: {
|
|
678
|
+
type: "string",
|
|
679
|
+
minLength: 1
|
|
680
|
+
}
|
|
576
681
|
},
|
|
577
|
-
required: [
|
|
682
|
+
required: [
|
|
683
|
+
"friend",
|
|
684
|
+
"alias"
|
|
685
|
+
]
|
|
578
686
|
},
|
|
579
687
|
confirm: "none",
|
|
580
688
|
scope: "assistant"
|
|
@@ -585,8 +693,14 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
585
693
|
summary: "Stop alerts from one conversation.",
|
|
586
694
|
params: {
|
|
587
695
|
type: "object",
|
|
588
|
-
properties: {
|
|
589
|
-
|
|
696
|
+
properties: {
|
|
697
|
+
friend: {
|
|
698
|
+
type: "string"
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
required: [
|
|
702
|
+
"friend"
|
|
703
|
+
]
|
|
590
704
|
},
|
|
591
705
|
confirm: "none",
|
|
592
706
|
scope: "assistant"
|
|
@@ -597,8 +711,14 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
597
711
|
summary: "Alerts from that conversation again.",
|
|
598
712
|
params: {
|
|
599
713
|
type: "object",
|
|
600
|
-
properties: {
|
|
601
|
-
|
|
714
|
+
properties: {
|
|
715
|
+
friend: {
|
|
716
|
+
type: "string"
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
required: [
|
|
720
|
+
"friend"
|
|
721
|
+
]
|
|
602
722
|
},
|
|
603
723
|
confirm: "none",
|
|
604
724
|
scope: "assistant"
|
|
@@ -609,8 +729,14 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
609
729
|
summary: "Sound on a new message.",
|
|
610
730
|
params: {
|
|
611
731
|
type: "object",
|
|
612
|
-
properties: {
|
|
613
|
-
|
|
732
|
+
properties: {
|
|
733
|
+
on: {
|
|
734
|
+
type: "boolean"
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
required: [
|
|
738
|
+
"on"
|
|
739
|
+
]
|
|
614
740
|
},
|
|
615
741
|
confirm: "none",
|
|
616
742
|
scope: "assistant"
|
|
@@ -621,8 +747,14 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
621
747
|
summary: "Flash the window on a new message.",
|
|
622
748
|
params: {
|
|
623
749
|
type: "object",
|
|
624
|
-
properties: {
|
|
625
|
-
|
|
750
|
+
properties: {
|
|
751
|
+
on: {
|
|
752
|
+
type: "boolean"
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
required: [
|
|
756
|
+
"on"
|
|
757
|
+
]
|
|
626
758
|
},
|
|
627
759
|
confirm: "none",
|
|
628
760
|
scope: "assistant"
|
|
@@ -630,8 +762,12 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
630
762
|
{
|
|
631
763
|
name: "status",
|
|
632
764
|
usage: "/status",
|
|
633
|
-
summary: "Friends, pending requests, how far back the history on this device goes, app version.",
|
|
634
|
-
params: {
|
|
765
|
+
summary: "Friends and service peers counted separately, pending requests, how far back the history on this device goes, app version.",
|
|
766
|
+
params: {
|
|
767
|
+
type: "object",
|
|
768
|
+
properties: {},
|
|
769
|
+
required: []
|
|
770
|
+
},
|
|
635
771
|
confirm: "none",
|
|
636
772
|
scope: "assistant"
|
|
637
773
|
}
|
|
@@ -654,7 +790,12 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
654
790
|
usage: "silent [days]",
|
|
655
791
|
summary: "Nothing from them for this many days (default 90).",
|
|
656
792
|
guarded: true,
|
|
657
|
-
arg: {
|
|
793
|
+
arg: {
|
|
794
|
+
name: "days",
|
|
795
|
+
type: "integer",
|
|
796
|
+
default: 90,
|
|
797
|
+
minimum: 1
|
|
798
|
+
}
|
|
658
799
|
},
|
|
659
800
|
{
|
|
660
801
|
name: "pending",
|
|
@@ -672,8 +813,148 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
672
813
|
guard: {
|
|
673
814
|
recentDays: 14,
|
|
674
815
|
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."
|
|
816
|
+
},
|
|
817
|
+
servicePeers: {
|
|
818
|
+
file: "service-peers.json",
|
|
819
|
+
loader: "loadServicePeers()",
|
|
820
|
+
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.",
|
|
821
|
+
later: "A dora / ENS / bridge / directory service returns the same shape; the bundled file is v1."
|
|
675
822
|
}
|
|
676
823
|
};
|
|
824
|
+
var service_peers_default = {
|
|
825
|
+
version: 1,
|
|
826
|
+
source: "static",
|
|
827
|
+
updated: "2026-09-24",
|
|
828
|
+
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.",
|
|
829
|
+
peers: [
|
|
830
|
+
{
|
|
831
|
+
userid: "7xmbDbouSYEA5mbAgWxV2BTwjc59XGcVPqXSZx6VibUd",
|
|
832
|
+
name: "lens",
|
|
833
|
+
kind: "node",
|
|
834
|
+
role: "bridge + web host"
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
userid: "4uNnLnAQHVJ7td657MDaz4UnEuhnTW9sRAPSVeAEEQe4",
|
|
838
|
+
name: "tokyo",
|
|
839
|
+
kind: "node",
|
|
840
|
+
role: "exit + relay + dora + meeting"
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
userid: "5Aj6uQMd1cNRb9cGT4AwHCN4RdVZjfaGLtgKGhdP1LzN",
|
|
844
|
+
name: "cn",
|
|
845
|
+
kind: "node",
|
|
846
|
+
role: "exit"
|
|
847
|
+
},
|
|
848
|
+
{
|
|
849
|
+
userid: "DZN2L9RV1YkHjqGHMTA6juZhskKA65AD2RyPt4umZVc7",
|
|
850
|
+
name: "callpass",
|
|
851
|
+
kind: "node",
|
|
852
|
+
role: "server"
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
userid: "BcGvk2h5XCxBZWJrYwzKpZ8GbxaZRoakEzt2pQpathyA",
|
|
856
|
+
name: "gojipower",
|
|
857
|
+
kind: "node",
|
|
858
|
+
role: "server"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
userid: "BeMbuKf1poh3U4rjw3eeUAKZsbN2qBSjVZdPSvehmHsw",
|
|
862
|
+
name: "snoopy",
|
|
863
|
+
kind: "node",
|
|
864
|
+
role: "dora + meeting + openclaw host"
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
userid: "CzwUZv6LfiGM7EXd9vXr6DutG8ASkA3TnNbqQzjKRJN5",
|
|
868
|
+
name: "GFAX",
|
|
869
|
+
kind: "node",
|
|
870
|
+
role: "server"
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
userid: "5SxEBHAx49Hknq1VzrA1HDtZHjW31vetX3iMEi4P6pK3",
|
|
874
|
+
name: "gfax118",
|
|
875
|
+
kind: "node",
|
|
876
|
+
role: "server"
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
userid: "72a4A7awtn6BqZnBt3eNhZH9MdYXRkM6Ht5HG2sqoiKR",
|
|
880
|
+
name: "nv4090-wsl",
|
|
881
|
+
kind: "node",
|
|
882
|
+
role: "GPU node"
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
userid: "6riqxxw18vjwXZEEtFUxbgNBMMe1dcv2kVHqVRQdihjE",
|
|
886
|
+
name: "node-3145",
|
|
887
|
+
kind: "node",
|
|
888
|
+
role: "GPU node (4090w)"
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
userid: "6D1PLSVqbSpcxnDMAd8ZXLWycYveeP2hU4g3igDQEqA7",
|
|
892
|
+
name: "node-5123",
|
|
893
|
+
kind: "node",
|
|
894
|
+
role: "node"
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
userid: "5EU9Ee3Vai1XwTr4pGaJFt4wmNVPUoYnJsdBM9LwNhrJ",
|
|
898
|
+
name: "node-2998",
|
|
899
|
+
kind: "node",
|
|
900
|
+
role: "node"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
userid: "GujioyKQRucQgw8mwMPNWtYTdNdrooCuFq3R1D4RqjCW",
|
|
904
|
+
name: "beagle-help",
|
|
905
|
+
kind: "agent",
|
|
906
|
+
role: "product support"
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
userid: "FhbohSLrj5UjdyFKCEYNeEWAPq3QD9hRg6hsso5ipag2",
|
|
910
|
+
name: "help.beagles.eth",
|
|
911
|
+
kind: "agent",
|
|
912
|
+
role: "bridge agent"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
userid: "9EaFGWuXH2UfREzYMkPPitzjoH6E8tvey4JvqTKtHFJh",
|
|
916
|
+
name: "openclaw",
|
|
917
|
+
kind: "agent",
|
|
918
|
+
role: "OpenClaw agent"
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
userid: "6z2o8ojPVjFGRzcffUdd5btvDYAt4tLuwJ8j1jvMBU8p",
|
|
922
|
+
name: "ClawAlan",
|
|
923
|
+
kind: "agent",
|
|
924
|
+
role: "OpenClaw agent on snoopy"
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
userid: "G7s3YjVfNLTY5pKBd83qQLAdzDddS7ZstsfrUySwK2Cb",
|
|
928
|
+
name: "interview",
|
|
929
|
+
kind: "agent",
|
|
930
|
+
role: "interview"
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
userid: "6jbXjrUWJ4zYvG8BDLnu8KVpoL7rhsdHYSwWER6WTfdt",
|
|
934
|
+
name: "interview editor",
|
|
935
|
+
kind: "agent",
|
|
936
|
+
role: "interview"
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
userid: "8BGemh6uqmh4X7KpnPVMeMSU8hZwAc6ZDo4MBRMFrq2L",
|
|
940
|
+
name: "readyplayer",
|
|
941
|
+
kind: "agent",
|
|
942
|
+
role: "readyplayer"
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
userid: "Ev1XmWRwtjQf8n33wgTwEhzXnYEyfqTyanehuDE6nczF",
|
|
946
|
+
name: "ReadyPlayer membership manager",
|
|
947
|
+
kind: "agent",
|
|
948
|
+
role: "readyplayer"
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
userid: "7xLPH2kjk7Nn8GrsAt7TYwa6b1WMPLkC2XRx7BzhiXYT",
|
|
952
|
+
name: "ai-btc-trader",
|
|
953
|
+
kind: "agent",
|
|
954
|
+
role: "btc signals (245)"
|
|
955
|
+
}
|
|
956
|
+
]
|
|
957
|
+
};
|
|
677
958
|
var ASSISTANT_ID = "__assistant__";
|
|
678
959
|
var DAY_MS = 864e5;
|
|
679
960
|
var RECENT_DAYS = 14;
|
|
@@ -688,11 +969,11 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
688
969
|
if (!parts.length)
|
|
689
970
|
return null;
|
|
690
971
|
const head = parts[0].toLowerCase();
|
|
691
|
-
if (head === "friends") {
|
|
972
|
+
if (head === "friends" || head === "nodes") {
|
|
692
973
|
const sub = (parts[1] || "").toLowerCase();
|
|
693
974
|
if (sub === "list" || sub === "remove")
|
|
694
|
-
return { ok: true, name:
|
|
695
|
-
return { ok: false, name:
|
|
975
|
+
return { ok: true, name: `${head}-${sub}`, args: parts.slice(2) };
|
|
976
|
+
return { ok: false, name: head, args: parts.slice(1), error: `${head}-subcommand` };
|
|
696
977
|
}
|
|
697
978
|
return { ok: true, name: head, args: parts.slice(1) };
|
|
698
979
|
}
|
|
@@ -719,6 +1000,30 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
719
1000
|
}
|
|
720
1001
|
return { filters, silentDays, unknown };
|
|
721
1002
|
}
|
|
1003
|
+
function servicePeerMap(list) {
|
|
1004
|
+
const map = /* @__PURE__ */ new Map();
|
|
1005
|
+
const peers = list && list.peers || [];
|
|
1006
|
+
for (const p of peers) {
|
|
1007
|
+
if (p && typeof p.userid === "string" && p.userid) {
|
|
1008
|
+
map.set(p.userid, { kind: p.kind === "agent" ? "agent" : "node", role: p.role || "", name: p.name || "" });
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
return map;
|
|
1012
|
+
}
|
|
1013
|
+
function partitionPeers(friends, svcMap) {
|
|
1014
|
+
const people = [];
|
|
1015
|
+
const nodes = [];
|
|
1016
|
+
for (const f of friends != null ? friends : []) {
|
|
1017
|
+
if (!f)
|
|
1018
|
+
continue;
|
|
1019
|
+
const svc = svcMap && svcMap.get(f.userid);
|
|
1020
|
+
if (svc)
|
|
1021
|
+
nodes.push(Object.assign({}, f, { kind: svc.kind, role: svc.role, service: true }));
|
|
1022
|
+
else
|
|
1023
|
+
people.push(f);
|
|
1024
|
+
}
|
|
1025
|
+
return { people, nodes };
|
|
1026
|
+
}
|
|
722
1027
|
var acceptedOrRequestedAt = (f) => f.acceptedAt || f.requestedAt || 0;
|
|
723
1028
|
function isRecent(friend, now, recentDays = RECENT_DAYS) {
|
|
724
1029
|
const at = acceptedOrRequestedAt(friend);
|
|
@@ -787,6 +1092,9 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
787
1092
|
return { match: partial[0], candidates: partial };
|
|
788
1093
|
return { match: null, candidates: partial };
|
|
789
1094
|
}
|
|
1095
|
+
function loadServicePeers() {
|
|
1096
|
+
return service_peers_default;
|
|
1097
|
+
}
|
|
790
1098
|
var ASSISTANT_PEER = {
|
|
791
1099
|
id: ASSISTANT_ID,
|
|
792
1100
|
userId: ASSISTANT_ID,
|
|
@@ -829,7 +1137,10 @@ window.__DK_UI_VERSION="0.1.108";
|
|
|
829
1137
|
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)}*`;
|
|
830
1138
|
}
|
|
831
1139
|
function friendTable(rows, now, lang) {
|
|
832
|
-
return rows.map((f) =>
|
|
1140
|
+
return rows.map((f) => {
|
|
1141
|
+
const what = f.service ? ` \`${f.kind}${f.role ? " \xB7 " + f.role : ""}\`` : "";
|
|
1142
|
+
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}`;
|
|
1143
|
+
}).join("\n");
|
|
833
1144
|
}
|
|
834
1145
|
function helpText(lang) {
|
|
835
1146
|
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:";
|
|
@@ -898,7 +1209,15 @@ ${tail}`;
|
|
|
898
1209
|
}, [lang]);
|
|
899
1210
|
const fetchFriends = async () => {
|
|
900
1211
|
const r = await fetch("/api/assistant/friends").then((x) => x.json());
|
|
901
|
-
|
|
1212
|
+
const { people, nodes } = partitionPeers(r.friends || [], servicePeerMap(loadServicePeers()));
|
|
1213
|
+
return {
|
|
1214
|
+
friends: people,
|
|
1215
|
+
nodes,
|
|
1216
|
+
all: r.friends || [],
|
|
1217
|
+
historySince: r.historySince || null,
|
|
1218
|
+
now: r.now || Date.now(),
|
|
1219
|
+
ver: r.beagleVer || ""
|
|
1220
|
+
};
|
|
902
1221
|
};
|
|
903
1222
|
const listReply = (rows, skipped, data, title) => {
|
|
904
1223
|
if (!rows.length) {
|
|
@@ -930,7 +1249,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
930
1249
|
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."));
|
|
931
1250
|
}
|
|
932
1251
|
if (cmd.ok === false) {
|
|
933
|
-
return append(asMsg("them", lang === "zh" ?
|
|
1252
|
+
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\`.`));
|
|
934
1253
|
}
|
|
935
1254
|
try {
|
|
936
1255
|
switch (cmd.name) {
|
|
@@ -938,37 +1257,48 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
938
1257
|
return append(asMsg("them", helpText(lang)));
|
|
939
1258
|
case "status": {
|
|
940
1259
|
const d = await fetchFriends();
|
|
941
|
-
const pending = d.
|
|
1260
|
+
const pending = d.all.filter((f) => f.pending).length;
|
|
1261
|
+
const nodeCount = d.nodes.filter((n) => n.kind === "node").length;
|
|
1262
|
+
const agentCount = d.nodes.length - nodeCount;
|
|
942
1263
|
return append(asMsg("them", lang === "zh" ? `**\u72B6\u6001**
|
|
943
1264
|
|
|
944
1265
|
- \u597D\u53CB\uFF1A${d.friends.length}
|
|
1266
|
+
- \u670D\u52A1\u8282\u70B9\uFF1A${d.nodes.length}\uFF08\u8282\u70B9 ${nodeCount} \xB7 \u667A\u80FD\u4F53 ${agentCount}\uFF09\uFF0C\u7528 \`/nodes list\` \u67E5\u770B
|
|
945
1267
|
- \u5F85\u5BF9\u65B9\u63A5\u53D7\uFF1A${pending}
|
|
946
1268
|
- \u672C\u673A\u5386\u53F2\u8D77\u81EA\uFF1A${fmtDate(d.historySince, lang)}
|
|
947
1269
|
- \u7248\u672C\uFF1A${d.ver}` : `**Status**
|
|
948
1270
|
|
|
949
1271
|
- Friends: ${d.friends.length}
|
|
1272
|
+
- Service peers: ${d.nodes.length} (${nodeCount} node${nodeCount === 1 ? "" : "s"} \xB7 ${agentCount} agent${agentCount === 1 ? "" : "s"}) \u2014 see \`/nodes list\`
|
|
950
1273
|
- Waiting to be accepted: ${pending}
|
|
951
1274
|
- History on this device since: ${fmtDate(d.historySince, lang)}
|
|
952
1275
|
- Version: ${d.ver}`));
|
|
953
1276
|
}
|
|
1277
|
+
case "nodes-list":
|
|
954
1278
|
case "friends-list": {
|
|
1279
|
+
const nodesMode = cmd.name === "nodes-list";
|
|
955
1280
|
const { filters, silentDays, unknown } = parseFilters(cmd.args);
|
|
956
1281
|
if (unknown.length) {
|
|
957
1282
|
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(", ")}.`));
|
|
958
1283
|
}
|
|
959
1284
|
const d = await fetchFriends();
|
|
960
|
-
const
|
|
961
|
-
const
|
|
1285
|
+
const pool = nodesMode ? d.nodes : d.friends;
|
|
1286
|
+
const { matched, skippedRecent } = selectFriends(pool, filters, { now: d.now, silentDays });
|
|
1287
|
+
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}`;
|
|
1288
|
+
const title = filters.length ? `**${nodesMode ? (lang === "zh" ? "\u670D\u52A1\u8282\u70B9" : "service peers") + ": " : ""}${filters.join(" + ")}**${filters.includes("silent") ? ` (${silentDays}d)` : ""} \u2014 ${matched.length}` : all;
|
|
962
1289
|
return append(asMsg("them", listReply(matched, skippedRecent, d, title)));
|
|
963
1290
|
}
|
|
1291
|
+
case "nodes-remove":
|
|
964
1292
|
case "friends-remove": {
|
|
1293
|
+
const nodesMode = cmd.name === "nodes-remove";
|
|
965
1294
|
const { filters, silentDays, unknown } = parseFilters(cmd.args);
|
|
966
1295
|
if (unknown.length || !filters.length) {
|
|
967
1296
|
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(", ")}.`));
|
|
968
1297
|
}
|
|
969
1298
|
const d = await fetchFriends();
|
|
970
|
-
const { matched, skippedRecent } = selectFriends(d.friends, filters, { now: d.now, silentDays });
|
|
971
|
-
const
|
|
1299
|
+
const { matched, skippedRecent } = selectFriends(nodesMode ? d.nodes : d.friends, filters, { now: d.now, silentDays });
|
|
1300
|
+
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"}`;
|
|
1301
|
+
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`;
|
|
972
1302
|
return append(asMsg(
|
|
973
1303
|
"them",
|
|
974
1304
|
listReply(matched, skippedRecent, d, title),
|
|
@@ -980,7 +1310,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
980
1310
|
if (!q)
|
|
981
1311
|
return append(asMsg("them", lang === "zh" ? "\u7528\u6CD5\uFF1A`/find <\u6587\u5B57>`" : "Usage: `/find <text>`"));
|
|
982
1312
|
const d = await fetchFriends();
|
|
983
|
-
const rows = findFriends(d.friends, q);
|
|
1313
|
+
const rows = findFriends(d.friends.concat(d.nodes), q);
|
|
984
1314
|
const title = lang === "zh" ? `**"${q}"** \u2014 ${rows.length} \u4F4D` : `**"${q}"** \u2014 ${rows.length} found`;
|
|
985
1315
|
return append(asMsg("them", listReply(rows, [], d, title)));
|
|
986
1316
|
}
|
|
@@ -990,7 +1320,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
990
1320
|
if (!tok || !alias)
|
|
991
1321
|
return append(asMsg("them", lang === "zh" ? "\u7528\u6CD5\uFF1A`/rename <\u597D\u53CB> <\u65B0\u540D\u5B57>`" : "Usage: `/rename <friend> <new name>`"));
|
|
992
1322
|
const d = await fetchFriends();
|
|
993
|
-
const { match, candidates } = resolveFriend(d.friends, tok);
|
|
1323
|
+
const { match, candidates } = resolveFriend(d.friends.concat(d.nodes), tok);
|
|
994
1324
|
if (!match)
|
|
995
1325
|
return append(asMsg("them", candidates.length ? ambiguous(candidates) : notFound(tok)));
|
|
996
1326
|
const was = nameOf(match);
|
|
@@ -1005,7 +1335,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
1005
1335
|
if (!tok)
|
|
1006
1336
|
return append(asMsg("them", `${lang === "zh" ? "\u7528\u6CD5" : "Usage"}: \`/${cmd.name} <friend>\``));
|
|
1007
1337
|
const d = await fetchFriends();
|
|
1008
|
-
const { match, candidates } = resolveFriend(d.friends, tok);
|
|
1338
|
+
const { match, candidates } = resolveFriend(d.friends.concat(d.nodes), tok);
|
|
1009
1339
|
if (!match)
|
|
1010
1340
|
return append(asMsg("them", candidates.length ? ambiguous(candidates) : notFound(tok)));
|
|
1011
1341
|
const isMuted = (muted || []).includes(match.userid);
|
|
@@ -1053,6 +1383,8 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
1053
1383
|
}, [append, lang, onReloadFriends]);
|
|
1054
1384
|
return { thread, handle, removeFriends };
|
|
1055
1385
|
}
|
|
1386
|
+
var DK_CMD_HIST_KEY = "beagle.assistant.history";
|
|
1387
|
+
var DK_CMD_HIST_MAX = 50;
|
|
1056
1388
|
function RequestsBlock({ T, requests, onAct }) {
|
|
1057
1389
|
const [acted, setActed] = React.useState({});
|
|
1058
1390
|
const [failed, setFailed] = React.useState({});
|
|
@@ -2454,6 +2786,59 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
2454
2786
|
setSelMode(false);
|
|
2455
2787
|
};
|
|
2456
2788
|
const [draft, setDraft] = React.useState("");
|
|
2789
|
+
const [hist, setHist] = React.useState([]);
|
|
2790
|
+
const histIdx = React.useRef(null);
|
|
2791
|
+
const histStash = React.useRef("");
|
|
2792
|
+
React.useEffect(() => {
|
|
2793
|
+
histIdx.current = null;
|
|
2794
|
+
histStash.current = "";
|
|
2795
|
+
if (!peer.app) {
|
|
2796
|
+
setHist([]);
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
try {
|
|
2800
|
+
setHist(JSON.parse(localStorage.getItem(DK_CMD_HIST_KEY) || "[]"));
|
|
2801
|
+
} catch (e) {
|
|
2802
|
+
setHist([]);
|
|
2803
|
+
}
|
|
2804
|
+
}, [peer.id, peer.app]);
|
|
2805
|
+
const rememberCommand = (text) => {
|
|
2806
|
+
setHist((h) => {
|
|
2807
|
+
const next = (h[h.length - 1] === text ? h : h.concat(text)).slice(-DK_CMD_HIST_MAX);
|
|
2808
|
+
if (peer.app) {
|
|
2809
|
+
try {
|
|
2810
|
+
localStorage.setItem(DK_CMD_HIST_KEY, JSON.stringify(next));
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
return next;
|
|
2815
|
+
});
|
|
2816
|
+
histIdx.current = null;
|
|
2817
|
+
histStash.current = "";
|
|
2818
|
+
};
|
|
2819
|
+
const walkHistory = (dir) => {
|
|
2820
|
+
if (!hist.length)
|
|
2821
|
+
return false;
|
|
2822
|
+
let i = histIdx.current;
|
|
2823
|
+
if (i === null) {
|
|
2824
|
+
if (dir > 0)
|
|
2825
|
+
return false;
|
|
2826
|
+
histStash.current = draft;
|
|
2827
|
+
i = hist.length - 1;
|
|
2828
|
+
} else {
|
|
2829
|
+
i += dir;
|
|
2830
|
+
if (i >= hist.length) {
|
|
2831
|
+
histIdx.current = null;
|
|
2832
|
+
setDraft(histStash.current);
|
|
2833
|
+
return true;
|
|
2834
|
+
}
|
|
2835
|
+
if (i < 0)
|
|
2836
|
+
i = 0;
|
|
2837
|
+
}
|
|
2838
|
+
histIdx.current = i;
|
|
2839
|
+
setDraft(hist[i]);
|
|
2840
|
+
return true;
|
|
2841
|
+
};
|
|
2457
2842
|
const [dragOver, setDragOver] = React.useState(false);
|
|
2458
2843
|
const [sending, setSending] = React.useState(null);
|
|
2459
2844
|
const [theater, setTheater] = React.useState(null);
|
|
@@ -2476,6 +2861,7 @@ ${cands.map((c) => `- ${nameOf(c)}`).join("\n")}`;
|
|
|
2476
2861
|
const sendDraft = () => {
|
|
2477
2862
|
if (draft.trim()) {
|
|
2478
2863
|
followScrollRef.current = true;
|
|
2864
|
+
rememberCommand(draft.trim());
|
|
2479
2865
|
onSend(draft);
|
|
2480
2866
|
setDraft("");
|
|
2481
2867
|
requestAnimationFrame(scrollToBottom);
|
|
@@ -2661,11 +3047,19 @@ ${peer.address}`
|
|
|
2661
3047
|
"input",
|
|
2662
3048
|
{
|
|
2663
3049
|
value: draft,
|
|
2664
|
-
onChange: (e) =>
|
|
3050
|
+
onChange: (e) => {
|
|
3051
|
+
histIdx.current = null;
|
|
3052
|
+
setDraft(e.target.value);
|
|
3053
|
+
},
|
|
2665
3054
|
onKeyDown: (e) => {
|
|
2666
3055
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
2667
3056
|
e.preventDefault();
|
|
2668
3057
|
sendDraft();
|
|
3058
|
+
return;
|
|
3059
|
+
}
|
|
3060
|
+
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
3061
|
+
if (walkHistory(e.key === "ArrowUp" ? -1 : 1))
|
|
3062
|
+
e.preventDefault();
|
|
2669
3063
|
}
|
|
2670
3064
|
},
|
|
2671
3065
|
placeholder: phone ? `${T.message}\u2026` : `${T.message} ${peer.alias || shortKey(peer.userId, 6, 4)}\u2026`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/beagle",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.110",
|
|
4
4
|
"description": "Beagle — P2P chat, file transfer and calls for regular users, on the Decent Network. No admin privilege required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"yargs": "^17.7.2"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@decentnetwork/beagle-ui": "^0.2.
|
|
38
|
+
"@decentnetwork/beagle-ui": "^0.2.24",
|
|
39
39
|
"@types/js-yaml": "^4.0.9",
|
|
40
40
|
"@types/node": "^20.11.0",
|
|
41
41
|
"@types/yargs": "^17.0.32",
|