@awiki/cli 0.0.1-beta.2

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.
Files changed (119) hide show
  1. package/.github/workflows/release.yml +44 -0
  2. package/.goreleaser.yml +44 -0
  3. package/AGENTS.md +60 -0
  4. package/CLAUDE.md +192 -0
  5. package/README.md +2 -0
  6. package/docs/architecture/awiki-command-v2.md +955 -0
  7. package/docs/architecture/awiki-skill-architecture.md +475 -0
  8. package/docs/architecture/awiki-v2-architecture.md +1063 -0
  9. package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/cli-init.md +1008 -0
  10. package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/output-format.md +407 -0
  11. package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/overall-init.md +741 -0
  12. package/docs/harness/review-spec.md +474 -0
  13. package/docs/installation.md +372 -0
  14. package/docs/plan/awiki-v2-implementation-plan.md +903 -0
  15. package/docs/plan/phase-0/adr-index.md +56 -0
  16. package/docs/plan/phase-0/audit-findings.md +251 -0
  17. package/docs/plan/phase-0/capability-mapping.md +108 -0
  18. package/docs/plan/phase-0/implementation-constraints.md +363 -0
  19. package/docs/publish.md +169 -0
  20. package/go.mod +29 -0
  21. package/go.sum +73 -0
  22. package/internal/anpsdk/registry.go +63 -0
  23. package/internal/authsdk/session.go +351 -0
  24. package/internal/buildinfo/buildinfo.go +34 -0
  25. package/internal/cli/app.go +136 -0
  26. package/internal/cli/app_test.go +88 -0
  27. package/internal/cli/debug.go +104 -0
  28. package/internal/cli/group.go +263 -0
  29. package/internal/cli/id.go +473 -0
  30. package/internal/cli/init.go +134 -0
  31. package/internal/cli/msg.go +228 -0
  32. package/internal/cli/page.go +267 -0
  33. package/internal/cli/root.go +499 -0
  34. package/internal/cli/runtime.go +232 -0
  35. package/internal/cli/upgrade.go +60 -0
  36. package/internal/cmdmeta/catalog.go +203 -0
  37. package/internal/cmdmeta/catalog_test.go +21 -0
  38. package/internal/config/config.go +399 -0
  39. package/internal/config/config_test.go +104 -0
  40. package/internal/config/write.go +37 -0
  41. package/internal/content/service.go +314 -0
  42. package/internal/content/service_test.go +165 -0
  43. package/internal/content/types.go +44 -0
  44. package/internal/docs/topics.go +110 -0
  45. package/internal/doctor/doctor.go +306 -0
  46. package/internal/identity/client.go +267 -0
  47. package/internal/identity/did.go +85 -0
  48. package/internal/identity/did_test.go +50 -0
  49. package/internal/identity/layout.go +206 -0
  50. package/internal/identity/legacy.go +378 -0
  51. package/internal/identity/public.go +70 -0
  52. package/internal/identity/public_test.go +73 -0
  53. package/internal/identity/readiness.go +74 -0
  54. package/internal/identity/service.go +826 -0
  55. package/internal/identity/store.go +385 -0
  56. package/internal/identity/store_test.go +180 -0
  57. package/internal/identity/types.go +204 -0
  58. package/internal/message/auth.go +167 -0
  59. package/internal/message/group_service.go +838 -0
  60. package/internal/message/group_wire.go +350 -0
  61. package/internal/message/group_wire_test.go +67 -0
  62. package/internal/message/helpers.go +61 -0
  63. package/internal/message/http_client.go +334 -0
  64. package/internal/message/proof.go +156 -0
  65. package/internal/message/proof_test.go +61 -0
  66. package/internal/message/service.go +696 -0
  67. package/internal/message/service_test.go +97 -0
  68. package/internal/message/types.go +155 -0
  69. package/internal/message/wire.go +100 -0
  70. package/internal/message/wire_test.go +49 -0
  71. package/internal/message/ws_proxy_client.go +151 -0
  72. package/internal/output/output.go +350 -0
  73. package/internal/output/output_test.go +48 -0
  74. package/internal/runtime/config.go +117 -0
  75. package/internal/runtime/config_test.go +46 -0
  76. package/internal/runtime/listener/files.go +65 -0
  77. package/internal/runtime/listener/manager.go +142 -0
  78. package/internal/runtime/listener/server.go +983 -0
  79. package/internal/runtime/listener/server_test.go +319 -0
  80. package/internal/runtime/listener/sysproc_unix.go +17 -0
  81. package/internal/runtime/listener/sysproc_windows.go +13 -0
  82. package/internal/runtime/listener/types.go +21 -0
  83. package/internal/runtime/listener/wsclient.go +299 -0
  84. package/internal/runtime/listener/wsclient_test.go +41 -0
  85. package/internal/store/dao.go +632 -0
  86. package/internal/store/dao_test.go +87 -0
  87. package/internal/store/helpers.go +197 -0
  88. package/internal/store/import.go +499 -0
  89. package/internal/store/import_test.go +103 -0
  90. package/internal/store/open.go +71 -0
  91. package/internal/store/query.go +151 -0
  92. package/internal/store/schema.go +277 -0
  93. package/internal/store/schema_test.go +56 -0
  94. package/internal/store/types.go +177 -0
  95. package/internal/update/update.go +368 -0
  96. package/package.json +17 -0
  97. package/scripts/install.js +171 -0
  98. package/scripts/release/release-prerelease.sh +86 -0
  99. package/scripts/release/tag-release.sh +66 -0
  100. package/scripts/release/withdraw-release.sh +78 -0
  101. package/scripts/run.js +69 -0
  102. package/skills/README.md +32 -0
  103. package/skills/awiki-bundle/SKILL.md +76 -0
  104. package/skills/awiki-debug/SKILL.md +80 -0
  105. package/skills/awiki-group/SKILL.md +111 -0
  106. package/skills/awiki-id/SKILL.md +123 -0
  107. package/skills/awiki-msg/SKILL.md +131 -0
  108. package/skills/awiki-page/SKILL.md +93 -0
  109. package/skills/awiki-people/SKILL.md +66 -0
  110. package/skills/awiki-runtime/SKILL.md +137 -0
  111. package/skills/awiki-shared/SKILL.md +124 -0
  112. package/skills/awiki-workflow-discovery/SKILL.md +93 -0
  113. package/skills/awiki-workflow-onboarding/SKILL.md +119 -0
  114. package/skills/manifests/skills.yaml +260 -0
  115. package/skills/templates/bundle-skill-template.md +42 -0
  116. package/skills/templates/debug-skill-template.md +44 -0
  117. package/skills/templates/domain-skill-template.md +56 -0
  118. package/skills/templates/shared-skill-template.md +46 -0
  119. package/skills/templates/workflow-skill-template.md +46 -0
@@ -0,0 +1,97 @@
1
+ package message
2
+
3
+ import (
4
+ "errors"
5
+ "path/filepath"
6
+ "testing"
7
+
8
+ appconfig "github.com/agentconnect/awiki-cli/internal/config"
9
+ "github.com/agentconnect/awiki-cli/internal/identity"
10
+ )
11
+
12
+ func TestRequireActiveIdentityRejectsLocalOnlyIdentity(t *testing.T) {
13
+ t.Parallel()
14
+
15
+ resolved := testResolvedConfig(t)
16
+ manager := identity.NewManager(resolved.Paths)
17
+ createTestIdentity(t, manager, identity.SaveInput{
18
+ IdentityName: "default",
19
+ DisplayName: "Alice",
20
+ })
21
+
22
+ service, err := NewService(resolved)
23
+ if err != nil {
24
+ t.Fatalf("NewService() error = %v", err)
25
+ }
26
+
27
+ _, err = service.requireActiveIdentity("")
28
+ if !errors.Is(err, identity.ErrUserRegistrationRequired) {
29
+ t.Fatalf("requireActiveIdentity() error = %v, want %v", err, identity.ErrUserRegistrationRequired)
30
+ }
31
+ }
32
+
33
+ func TestRequireActiveIdentityAcceptsRegisteredUser(t *testing.T) {
34
+ t.Parallel()
35
+
36
+ resolved := testResolvedConfig(t)
37
+ manager := identity.NewManager(resolved.Paths)
38
+ createTestIdentity(t, manager, identity.SaveInput{
39
+ IdentityName: "alice",
40
+ UserID: "user-123",
41
+ DisplayName: "Alice",
42
+ Handle: "alice",
43
+ })
44
+ resolved.ActiveIdentity = "alice"
45
+
46
+ service, err := NewService(resolved)
47
+ if err != nil {
48
+ t.Fatalf("NewService() error = %v", err)
49
+ }
50
+
51
+ record, err := service.requireActiveIdentity("")
52
+ if err != nil {
53
+ t.Fatalf("requireActiveIdentity() error = %v", err)
54
+ }
55
+ if record.Handle != "alice" || record.UserID != "user-123" {
56
+ t.Fatalf("unexpected record = %#v", record)
57
+ }
58
+ }
59
+
60
+ func testResolvedConfig(t *testing.T) *appconfig.Resolved {
61
+ t.Helper()
62
+ root := t.TempDir()
63
+ return &appconfig.Resolved{
64
+ Paths: appconfig.Paths{
65
+ IdentityDir: filepath.Join(root, "identities"),
66
+ LegacyCredentialsDir: filepath.Join(root, "legacy"),
67
+ DataDir: filepath.Join(root, "data"),
68
+ StateDir: filepath.Join(root, "state"),
69
+ DatabaseFile: filepath.Join(root, "data", "awiki-cli.db"),
70
+ },
71
+ UserServiceURL: "https://awiki.test",
72
+ MessageServiceURL: "https://awiki.test",
73
+ DIDDomain: "awiki.ai",
74
+ }
75
+ }
76
+
77
+ func createTestIdentity(t *testing.T, manager *identity.Manager, input identity.SaveInput) {
78
+ t.Helper()
79
+ generated, err := identity.GenerateIdentity(identity.GenerateOptions{
80
+ Hostname: "awiki.ai",
81
+ PathPrefix: []string{"user"},
82
+ ProofDomain: "awiki.ai",
83
+ })
84
+ if err != nil {
85
+ t.Fatalf("GenerateIdentity() error = %v", err)
86
+ }
87
+ input.DID = generated.DID
88
+ input.UniqueID = generated.UniqueID
89
+ input.DIDDocument = generated.DIDDocument
90
+ input.Key1PrivatePEM = generated.Key1PrivatePEM
91
+ input.Key1PublicPEM = generated.Key1PublicPEM
92
+ input.E2EESigningPrivatePEM = generated.E2EESigningPrivatePEM
93
+ input.E2EEAgreementPrivatePEM = generated.E2EEAgreementPrivatePEM
94
+ if _, err := manager.Save(input); err != nil {
95
+ t.Fatalf("Save() error = %v", err)
96
+ }
97
+ }
@@ -0,0 +1,155 @@
1
+ package message
2
+
3
+ import "errors"
4
+
5
+ const (
6
+ MessageRPCEndpoint = "/rpc"
7
+ MessageWSEndpoint = "/ws"
8
+ )
9
+
10
+ var (
11
+ ErrTargetRequired = errors.New("direct message target is required")
12
+ ErrGroupRequired = errors.New("group target is required")
13
+ ErrMemberRequired = errors.New("group member target is required")
14
+ ErrTextRequired = errors.New("message text is required")
15
+ ErrTransportUnavailable = errors.New("message transport is unavailable")
16
+ ErrSecureNotSupported = errors.New("direct secure messaging is not implemented yet")
17
+ ErrMessageNotFound = errors.New("message not found")
18
+ )
19
+
20
+ type CommandResult struct {
21
+ Data map[string]any
22
+ Summary string
23
+ Warnings []string
24
+ }
25
+
26
+ type SendRequest struct {
27
+ IdentityName string
28
+ Target string
29
+ Group string
30
+ Text string
31
+ MessageType string
32
+ SecureMode string
33
+ }
34
+
35
+ type InboxRequest struct {
36
+ IdentityName string
37
+ Scope string
38
+ With string
39
+ Group string
40
+ Limit int
41
+ UnreadOnly bool
42
+ MarkRead bool
43
+ }
44
+
45
+ type HistoryRequest struct {
46
+ IdentityName string
47
+ With string
48
+ Limit int
49
+ Cursor string
50
+ }
51
+
52
+ type MarkReadRequest struct {
53
+ IdentityName string
54
+ MessageIDs []string
55
+ }
56
+
57
+ type directSendResult struct {
58
+ Accepted bool `json:"accepted"`
59
+ MessageID string `json:"message_id"`
60
+ OperationID string `json:"operation_id"`
61
+ TargetDID string `json:"target_did"`
62
+ AcceptedAt string `json:"accepted_at"`
63
+ FinalAcceptance bool `json:"final_acceptance"`
64
+ DeliveryState string `json:"delivery_state"`
65
+ }
66
+
67
+ type GroupCreateRequest struct {
68
+ IdentityName string
69
+ Name string
70
+ Description string
71
+ Discoverability string
72
+ AdmissionMode string
73
+ Slug string
74
+ Goal string
75
+ Rules string
76
+ MessagePrompt string
77
+ DocURL string
78
+ AttachmentsAllowed *bool
79
+ MaxMembers string
80
+ MemberMaxMessages *int64
81
+ MemberMaxTotalChars *int64
82
+ }
83
+
84
+ type GroupGetRequest struct {
85
+ IdentityName string
86
+ Group string
87
+ }
88
+
89
+ type GroupInfoRequest struct {
90
+ IdentityName string
91
+ Group string
92
+ IncludePolicy bool
93
+ IncludeMemberList bool
94
+ }
95
+
96
+ type GroupJoinRequest struct {
97
+ IdentityName string
98
+ Group string
99
+ ReasonText string
100
+ }
101
+
102
+ type GroupMemberRequest struct {
103
+ IdentityName string
104
+ Group string
105
+ Member string
106
+ Role string
107
+ ReasonText string
108
+ }
109
+
110
+ type GroupLeaveRequest struct {
111
+ IdentityName string
112
+ Group string
113
+ }
114
+
115
+ type GroupUpdateRequest struct {
116
+ IdentityName string
117
+ Group string
118
+ Name string
119
+ Description string
120
+ Discoverability string
121
+ AdmissionMode string
122
+ Slug string
123
+ Goal string
124
+ Rules string
125
+ MessagePrompt string
126
+ DocURL string
127
+ AttachmentsAllowed *bool
128
+ MaxMembers string
129
+ MemberMaxMessages *int64
130
+ MemberMaxTotalChars *int64
131
+ }
132
+
133
+ type GroupMembersRequest struct {
134
+ IdentityName string
135
+ Group string
136
+ Limit int
137
+ }
138
+
139
+ type GroupMessagesRequest struct {
140
+ IdentityName string
141
+ Group string
142
+ Limit int
143
+ Cursor string
144
+ }
145
+
146
+ type groupSendResult struct {
147
+ Accepted bool `json:"accepted"`
148
+ FinalAcceptance bool `json:"final_acceptance"`
149
+ GroupDID string `json:"group_did"`
150
+ MessageID string `json:"message_id"`
151
+ OperationID string `json:"operation_id"`
152
+ GroupEventSeq string `json:"group_event_seq"`
153
+ GroupStateVersion string `json:"group_state_version"`
154
+ AcceptedAt string `json:"accepted_at"`
155
+ }
@@ -0,0 +1,100 @@
1
+ package message
2
+
3
+ import (
4
+ "fmt"
5
+
6
+ "github.com/agentconnect/awiki-cli/internal/identity"
7
+ )
8
+
9
+ func BuildDirectSendRPCParams(record *identity.StoredIdentity, manager *identity.Manager, targetDID string, text string, messageType string) (map[string]any, error) {
10
+ auth, err := newAuthContext(record, manager)
11
+ if err != nil {
12
+ return nil, err
13
+ }
14
+ payload, err := buildDirectTextPayload(record.DID, targetDID, text, contentTypeForMessageType(messageType))
15
+ if err != nil {
16
+ return nil, err
17
+ }
18
+ senderProof, err := buildSenderProof(auth, payload, targetDID)
19
+ if err != nil {
20
+ return nil, err
21
+ }
22
+ return map[string]any{
23
+ "meta": payload.Meta,
24
+ "auth": map[string]any{
25
+ "scheme": OriginProofScheme,
26
+ "sender_proof": senderProof,
27
+ },
28
+ "body": payload.Body,
29
+ }, nil
30
+ }
31
+
32
+ func BuildInboxRPCParams(record *identity.StoredIdentity, request InboxRequest) map[string]any {
33
+ limit := request.Limit
34
+ if limit <= 0 {
35
+ limit = 20
36
+ }
37
+ return map[string]any{
38
+ "meta": map[string]any{
39
+ "anp_version": "1.0",
40
+ "profile": "anp.inbox.local.v1",
41
+ "security_profile": "transport-protected",
42
+ "sender_did": record.DID,
43
+ "operation_id": "op-" + generateOperationID(),
44
+ "created_at": nowRFC3339(),
45
+ },
46
+ "body": map[string]any{
47
+ "user_did": record.DID,
48
+ "limit": limit,
49
+ },
50
+ }
51
+ }
52
+
53
+ func BuildHistoryRPCParams(record *identity.StoredIdentity, request HistoryRequest) (map[string]any, error) {
54
+ if request.With == "" {
55
+ return nil, ErrTargetRequired
56
+ }
57
+ limit := request.Limit
58
+ if limit <= 0 {
59
+ limit = 50
60
+ }
61
+ body := map[string]any{
62
+ "user_did": record.DID,
63
+ "peer_did": request.With,
64
+ "limit": limit,
65
+ }
66
+ if request.Cursor != "" {
67
+ body["since_seq"] = request.Cursor
68
+ }
69
+ return map[string]any{
70
+ "meta": map[string]any{
71
+ "anp_version": "1.0",
72
+ "profile": "anp.direct.local.v1",
73
+ "security_profile": "transport-protected",
74
+ "sender_did": record.DID,
75
+ "operation_id": "op-" + generateOperationID(),
76
+ "created_at": nowRFC3339(),
77
+ },
78
+ "body": body,
79
+ }, nil
80
+ }
81
+
82
+ func BuildMarkReadRPCParams(record *identity.StoredIdentity, request MarkReadRequest) (map[string]any, error) {
83
+ if len(request.MessageIDs) == 0 {
84
+ return nil, fmt.Errorf("%w: message_ids are required", ErrMessageNotFound)
85
+ }
86
+ return map[string]any{
87
+ "meta": map[string]any{
88
+ "anp_version": "1.0",
89
+ "profile": "anp.inbox.local.v1",
90
+ "security_profile": "transport-protected",
91
+ "sender_did": record.DID,
92
+ "operation_id": "op-" + generateOperationID(),
93
+ "created_at": nowRFC3339(),
94
+ },
95
+ "body": map[string]any{
96
+ "user_did": record.DID,
97
+ "message_ids": request.MessageIDs,
98
+ },
99
+ }, nil
100
+ }
@@ -0,0 +1,49 @@
1
+ package message
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/agentconnect/awiki-cli/internal/identity"
7
+ )
8
+
9
+ func TestBuildDirectSendRPCParamsUsesOriginProofScheme(t *testing.T) {
10
+ t.Parallel()
11
+
12
+ generated, err := identity.GenerateIdentity(identity.GenerateOptions{
13
+ Hostname: "awiki.ai",
14
+ PathPrefix: []string{"user"},
15
+ ProofDomain: "awiki.ai",
16
+ })
17
+ if err != nil {
18
+ t.Fatalf("GenerateIdentity() error = %v", err)
19
+ }
20
+ record := &identity.StoredIdentity{
21
+ IdentityName: "alice",
22
+ DID: generated.DID,
23
+ DIDDocument: generated.DIDDocument,
24
+ Key1PrivatePEM: generated.Key1PrivatePEM,
25
+ }
26
+
27
+ params, err := BuildDirectSendRPCParams(record, nil, "did:wba:awiki.ai:user:bob", "hello", "text")
28
+ if err != nil {
29
+ t.Fatalf("BuildDirectSendRPCParams() error = %v", err)
30
+ }
31
+ auth, ok := params["auth"].(map[string]any)
32
+ if !ok {
33
+ t.Fatalf("params[auth] = %#v, want map", params["auth"])
34
+ }
35
+ if got := stringFromAny(auth["scheme"]); got != OriginProofScheme {
36
+ t.Fatalf("auth.scheme = %q, want %q", got, OriginProofScheme)
37
+ }
38
+ meta, ok := params["meta"].(map[string]any)
39
+ if !ok {
40
+ t.Fatalf("params[meta] = %#v, want map", params["meta"])
41
+ }
42
+ target, ok := meta["target"].(map[string]any)
43
+ if !ok {
44
+ t.Fatalf("meta[target] = %#v, want map", meta["target"])
45
+ }
46
+ if got := stringFromAny(target["kind"]); got != "agent" {
47
+ t.Fatalf("meta.target.kind = %q, want %q", got, "agent")
48
+ }
49
+ }
@@ -0,0 +1,151 @@
1
+ package message
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+
7
+ appconfig "github.com/agentconnect/awiki-cli/internal/config"
8
+ "github.com/agentconnect/awiki-cli/internal/runtime"
9
+ )
10
+
11
+ type WSProxyTransport struct {
12
+ resolved *appconfig.Resolved
13
+ identityName string
14
+ }
15
+
16
+ func NewWSProxyTransport(resolved *appconfig.Resolved, identityName string) *WSProxyTransport {
17
+ return &WSProxyTransport{resolved: resolved, identityName: identityName}
18
+ }
19
+
20
+ func (t *WSProxyTransport) SendDirect(ctx context.Context, request SendRequest) (*directSendResult, error) {
21
+ result, err := t.call("direct.send", map[string]any{
22
+ "target": request.Target,
23
+ "text": request.Text,
24
+ "type": request.MessageType,
25
+ })
26
+ if err != nil {
27
+ return nil, err
28
+ }
29
+ sendResult := &directSendResult{}
30
+ decodeMapInto(result, sendResult)
31
+ return sendResult, nil
32
+ }
33
+
34
+ func (t *WSProxyTransport) SendGroup(ctx context.Context, request SendRequest) (*groupSendResult, error) {
35
+ result, err := t.call("group.send", map[string]any{
36
+ "group": request.Group,
37
+ "text": request.Text,
38
+ "type": request.MessageType,
39
+ })
40
+ if err != nil {
41
+ return nil, err
42
+ }
43
+ sendResult := &groupSendResult{}
44
+ decodeMapInto(result, sendResult)
45
+ return sendResult, nil
46
+ }
47
+
48
+ func (t *WSProxyTransport) GetInbox(ctx context.Context, request InboxRequest) (map[string]any, error) {
49
+ return t.call("inbox.get", map[string]any{
50
+ "with": request.With,
51
+ "limit": request.Limit,
52
+ "scope": request.Scope,
53
+ "mark_read": request.MarkRead,
54
+ "unread": request.UnreadOnly,
55
+ })
56
+ }
57
+
58
+ func (t *WSProxyTransport) GetHistory(ctx context.Context, request HistoryRequest) (map[string]any, error) {
59
+ return t.call("direct.get_history", map[string]any{
60
+ "with": request.With,
61
+ "limit": request.Limit,
62
+ "cursor": request.Cursor,
63
+ })
64
+ }
65
+
66
+ func (t *WSProxyTransport) MarkRead(ctx context.Context, request MarkReadRequest) (map[string]any, error) {
67
+ return t.call("inbox.mark_read", map[string]any{"message_ids": request.MessageIDs})
68
+ }
69
+
70
+ func (t *WSProxyTransport) CreateGroup(ctx context.Context, request GroupCreateRequest) (map[string]any, error) {
71
+ return t.call("group.create", map[string]any{
72
+ "name": request.Name,
73
+ "description": request.Description,
74
+ "discoverability": request.Discoverability,
75
+ "admission_mode": request.AdmissionMode,
76
+ "slug": request.Slug,
77
+ "goal": request.Goal,
78
+ "rules": request.Rules,
79
+ "message_prompt": request.MessagePrompt,
80
+ "doc_url": request.DocURL,
81
+ "attachments_allowed": request.AttachmentsAllowed,
82
+ "max_members": request.MaxMembers,
83
+ "member_max_messages": request.MemberMaxMessages,
84
+ "member_max_total_chars": request.MemberMaxTotalChars,
85
+ })
86
+ }
87
+
88
+ func (t *WSProxyTransport) GetGroupInfo(ctx context.Context, request GroupInfoRequest) (map[string]any, error) {
89
+ return t.call("group.get_info", map[string]any{
90
+ "group": request.Group,
91
+ "include_policy": request.IncludePolicy,
92
+ "include_member_list": request.IncludeMemberList,
93
+ })
94
+ }
95
+
96
+ func (t *WSProxyTransport) JoinGroup(ctx context.Context, request GroupJoinRequest) (map[string]any, error) {
97
+ return t.call("group.join", map[string]any{"group": request.Group, "reason_text": request.ReasonText})
98
+ }
99
+
100
+ func (t *WSProxyTransport) AddGroupMember(ctx context.Context, request GroupMemberRequest) (map[string]any, error) {
101
+ return t.call("group.add", map[string]any{
102
+ "group": request.Group,
103
+ "member": request.Member,
104
+ "role": request.Role,
105
+ "reason_text": request.ReasonText,
106
+ })
107
+ }
108
+
109
+ func (t *WSProxyTransport) RemoveGroupMember(ctx context.Context, request GroupMemberRequest) (map[string]any, error) {
110
+ return t.call("group.remove", map[string]any{
111
+ "group": request.Group,
112
+ "member": request.Member,
113
+ "reason_text": request.ReasonText,
114
+ })
115
+ }
116
+
117
+ func (t *WSProxyTransport) LeaveGroup(ctx context.Context, request GroupLeaveRequest) (map[string]any, error) {
118
+ return t.call("group.leave", map[string]any{"group": request.Group})
119
+ }
120
+
121
+ func (t *WSProxyTransport) GetGroup(ctx context.Context, request GroupGetRequest) (map[string]any, error) {
122
+ return t.call("group.get", map[string]any{"group": request.Group})
123
+ }
124
+
125
+ func (t *WSProxyTransport) ListGroupMembers(ctx context.Context, request GroupMembersRequest) (map[string]any, error) {
126
+ return t.call("group.list_members", map[string]any{"group": request.Group, "limit": request.Limit})
127
+ }
128
+
129
+ func (t *WSProxyTransport) ListGroupMessages(ctx context.Context, request GroupMessagesRequest) (map[string]any, error) {
130
+ return t.call("group.list_messages", map[string]any{"group": request.Group, "limit": request.Limit, "cursor": request.Cursor})
131
+ }
132
+
133
+ func (t *WSProxyTransport) UpdateGroupProfile(ctx context.Context, request GroupGetRequest, patch map[string]any) (map[string]any, error) {
134
+ return t.call("group.update_profile", map[string]any{"group": request.Group, "patch": patch})
135
+ }
136
+
137
+ func (t *WSProxyTransport) UpdateGroupPolicy(ctx context.Context, request GroupGetRequest, patch map[string]any) (map[string]any, error) {
138
+ return t.call("group.update_policy", map[string]any{"group": request.Group, "patch": patch})
139
+ }
140
+
141
+ func (t *WSProxyTransport) call(method string, params map[string]any) (map[string]any, error) {
142
+ result, err := runtime.CallLocalBridge(runtime.BridgeRequest{
143
+ Method: method,
144
+ Params: params,
145
+ IdentityName: t.identityName,
146
+ }, t.resolved)
147
+ if err != nil {
148
+ return nil, fmt.Errorf("%w: %v", ErrTransportUnavailable, err)
149
+ }
150
+ return result, nil
151
+ }