dscord 0.2.0-alpha.1 → 0.4.0-alpha.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 (209) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +22 -0
  3. package/README.md +70 -49
  4. package/bin/dscord.mjs +5 -4
  5. package/cordis.patch.yml +3 -0
  6. package/deploy/synapse/dscord_guard.py +212 -0
  7. package/dist/admin/assets/index-DXyc54Ce.css +1 -0
  8. package/dist/admin/assets/index-vZ7hJNEU.js +10 -0
  9. package/dist/admin/assets/mark-128-C4ed4p0U.png +0 -0
  10. package/dist/admin/index.html +13 -0
  11. package/dist/admin/licenses/bundled-dependencies.txt +421 -0
  12. package/dist/admin/licenses/lucide.txt +43 -0
  13. package/dist/admin/licenses/ui-foundation.txt +336 -0
  14. package/dist/admin/theme.js +66 -0
  15. package/dist/web/assets/apple-touch-icon-C_qAgjR1.png +0 -0
  16. package/dist/web/assets/common-DGlCXKV6.js +5 -0
  17. package/dist/web/assets/favicon-32-CEKpvmlx.png +0 -0
  18. package/dist/web/assets/favicon-6aWeKmcy.ico +0 -0
  19. package/dist/web/assets/index-62nMLjE0.css +1 -0
  20. package/dist/web/assets/index-OaWUoxQD.js +55 -0
  21. package/dist/web/assets/{manifest-eq_1S_IC.webmanifest → manifest-Ca-bIZpP.webmanifest} +2 -8
  22. package/dist/web/assets/mark-128-C4ed4p0U.png +0 -0
  23. package/dist/web/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  24. package/dist/web/client-config.json +3 -0
  25. package/dist/web/icons/apple-touch-icon.png +0 -0
  26. package/dist/web/icons/favicon-32.png +0 -0
  27. package/dist/web/icons/favicon.ico +0 -0
  28. package/dist/web/icons/icon-192.png +0 -0
  29. package/dist/web/icons/icon-512.png +0 -0
  30. package/dist/web/icons/mark-128.png +0 -0
  31. package/dist/web/index.html +9 -7
  32. package/dist/web/licenses/bundled-dependencies.txt +2452 -0
  33. package/dist/web/licenses/ui-foundation.txt +336 -0
  34. package/dist/web/manifest.webmanifest +2 -8
  35. package/dist/web/sw.js +233 -79
  36. package/dist/web/theme.js +27 -5
  37. package/dsh-connect/KERNEL.md +70 -0
  38. package/dsh-connect/client.js +28821 -0
  39. package/dsh-connect/controller.mjs +450 -0
  40. package/dsh-connect/decision-settings.mjs +66 -0
  41. package/dsh-connect/index.mjs +40 -0
  42. package/dsh-connect/kernel-runtime.mjs +120 -0
  43. package/dsh-connect/models.mjs +64 -0
  44. package/dsh-connect/native-bots.mjs +97 -0
  45. package/dsh-connect/native-bridge.mjs +482 -0
  46. package/dsh-connect/native-connections.mjs +160 -0
  47. package/dsh-connect/native-team.mjs +63 -0
  48. package/dsh-connect/processes.mjs +119 -0
  49. package/dsh-connect/work-core.mjs +573 -0
  50. package/dsh-plugin/README.md +32 -31
  51. package/dsh-plugin/index.mjs +18 -11
  52. package/dsh-plugin/model-profile.mjs +73 -0
  53. package/dsh-plugin/runtime-dependencies-lock.json +696 -6
  54. package/dsh-plugin/runtime-dependencies-pnpm-lock.yaml +489 -0
  55. package/dsh-plugin/runtime-dependencies.json +7 -2
  56. package/dsh-plugin/runtime-rules.mjs +9 -0
  57. package/dsh-plugin/runtime.mjs +330 -45
  58. package/dsh-plugin/scoped-work.mjs +73 -0
  59. package/dsh-plugin/work-files.mjs +24 -5
  60. package/memory/contacts.mjs +36 -0
  61. package/memory/ingress.mjs +57 -0
  62. package/memory/model-options.mjs +9 -0
  63. package/memory/native.mjs +374 -0
  64. package/memory/observation-policy.mjs +67 -0
  65. package/memory/ombre.mjs +165 -0
  66. package/memory/panel.mjs +88 -0
  67. package/memory/review.mjs +90 -0
  68. package/memory/service.mjs +429 -0
  69. package/memory/snapshot-context.mjs +95 -0
  70. package/memory/source-query.mjs +87 -0
  71. package/memory/store.mjs +339 -0
  72. package/memory/views.mjs +304 -0
  73. package/memory//345/244/215/347/224/250/344/270/216/350/277/220/350/241/214.md +47 -0
  74. package/memory//345/275/223/345/211/215/344/270/212/344/270/213/346/226/207/344/270/216/345/233/236/351/241/276.md +73 -0
  75. package/package.json +46 -6
  76. package/scripts/admin.mjs +41 -0
  77. package/scripts/central-init.mjs +39 -0
  78. package/scripts/dsh-node.mjs +92 -54
  79. package/scripts/memory-setup.mjs +21 -0
  80. package/scripts/runtime-config.mjs +55 -23
  81. package/scripts/runtime-dependencies.mjs +79 -0
  82. package/scripts/server-admin.mjs +25 -3
  83. package/scripts/server-bootstrap.mjs +55 -9
  84. package/scripts/server-init.mjs +88 -10
  85. package/scripts/service.mjs +39 -14
  86. package/service/ombre/LICENSE +21 -0
  87. package/service/ombre/SOURCE.json +15 -0
  88. package/service/ombre/controlled_store.py +295 -0
  89. package/service/ombre/harrier_profile.py +320 -0
  90. package/service/ombre/protocol.py +67 -0
  91. package/service/ombre/requirements.lock.txt +1100 -0
  92. package/service/ombre/semantic.py +449 -0
  93. package/service/ombre/service.py +204 -0
  94. package/src/accounts.mjs +373 -0
  95. package/src/admin-auth.mjs +246 -0
  96. package/src/admin.mjs +285 -0
  97. package/src/attachment-access.mjs +57 -0
  98. package/src/attention.mjs +140 -0
  99. package/src/bot-node.mjs +839 -48
  100. package/src/bot-work-policy.mjs +77 -0
  101. package/src/bot-work.mjs +276 -0
  102. package/src/budget.mjs +22 -7
  103. package/src/collaboration.mjs +178 -0
  104. package/src/contact-book.mjs +206 -0
  105. package/src/core/attachment-routes.mjs +43 -0
  106. package/src/core/bot-routes.mjs +37 -0
  107. package/src/core/node-routes.mjs +51 -0
  108. package/src/core/room-routes.mjs +285 -0
  109. package/src/core/router.mjs +31 -0
  110. package/src/core/session-routes.mjs +58 -0
  111. package/src/core.mjs +139 -356
  112. package/src/decision-provider.mjs +128 -0
  113. package/src/file-formats.mjs +1 -1
  114. package/src/governance.mjs +350 -0
  115. package/src/http-json.mjs +19 -0
  116. package/src/identity.mjs +100 -0
  117. package/src/kernel-control.mjs +374 -0
  118. package/src/kernel-node-client.mjs +162 -0
  119. package/src/matrix-client.mjs +70 -13
  120. package/src/media.mjs +50 -28
  121. package/src/mentions.mjs +28 -8
  122. package/src/message-context.mjs +105 -0
  123. package/src/model-config.mjs +51 -0
  124. package/src/model-failure.mjs +5 -0
  125. package/src/native-bot-catalog.mjs +75 -0
  126. package/src/native-request.mjs +42 -0
  127. package/src/node-auth.mjs +60 -0
  128. package/src/node-delivery.mjs +2 -2
  129. package/src/node-files.mjs +29 -7
  130. package/src/node-store.mjs +581 -13
  131. package/src/node-work.mjs +43 -0
  132. package/src/participant-labels.mjs +9 -0
  133. package/src/push.mjs +23 -3
  134. package/src/room-media.mjs +122 -0
  135. package/src/synapse-control.mjs +409 -0
  136. package/src/tasks.mjs +19 -5
  137. package/src/verified-media.mjs +283 -0
  138. package/src/web-mode.mjs +9 -0
  139. package/vendor/ds-bot/NOTICE +86 -0
  140. package/vendor/ds-bot/UPSTREAM.json +83 -5
  141. package/vendor/ds-bot/client.js +15079 -9868
  142. package/vendor/ds-bot/index.js +6 -2
  143. package/vendor/ds-bot/package.json +9 -4
  144. package/vendor/ds-bot/src/host/approvals.js +54 -7
  145. package/vendor/ds-bot/src/host/browser/script-child.js +136 -0
  146. package/vendor/ds-bot/src/host/browser/script-runner.js +77 -0
  147. package/vendor/ds-bot/src/host/browser/script.js +1 -0
  148. package/vendor/ds-bot/src/host/browser/session.js +19 -29
  149. package/vendor/ds-bot/src/host/capabilities.js +6 -3
  150. package/vendor/ds-bot/src/host/channel.js +214 -54
  151. package/vendor/ds-bot/src/host/computer/catalog.js +91 -0
  152. package/vendor/ds-bot/src/host/computer/index.js +1213 -0
  153. package/vendor/ds-bot/src/host/computer/leases.js +71 -0
  154. package/vendor/ds-bot/src/host/connectors/catalog.js +96 -0
  155. package/vendor/ds-bot/src/host/connectors/gateway.js +264 -0
  156. package/vendor/ds-bot/src/host/connectors/index.js +863 -0
  157. package/vendor/ds-bot/src/host/connectors/mail/index.js +613 -0
  158. package/vendor/ds-bot/src/host/connectors/mail/presets.js +23 -0
  159. package/vendor/ds-bot/src/host/connectors/mail/transport.js +306 -0
  160. package/vendor/ds-bot/src/host/connectors/oauth.js +191 -0
  161. package/vendor/ds-bot/src/host/constants.js +1 -1
  162. package/vendor/ds-bot/src/host/context-failure.js +11 -0
  163. package/vendor/ds-bot/src/host/delivery.js +6 -3
  164. package/vendor/ds-bot/src/host/feed.js +10 -3
  165. package/vendor/ds-bot/src/host/groups.js +58 -16
  166. package/vendor/ds-bot/src/host/home-lock.js +103 -35
  167. package/vendor/ds-bot/src/host/im/format.js +190 -0
  168. package/vendor/ds-bot/src/host/im/index.js +943 -0
  169. package/vendor/ds-bot/src/host/im/platforms/dingtalk.js +207 -0
  170. package/vendor/ds-bot/src/host/im/platforms/discord.js +234 -0
  171. package/vendor/ds-bot/src/host/im/platforms/feishu.js +352 -0
  172. package/vendor/ds-bot/src/host/im/platforms/index.js +12 -0
  173. package/vendor/ds-bot/src/host/im/platforms/qq.js +216 -0
  174. package/vendor/ds-bot/src/host/im/platforms/slack.js +210 -0
  175. package/vendor/ds-bot/src/host/im/platforms/telegram.js +249 -0
  176. package/vendor/ds-bot/src/host/im/platforms/wecom.js +217 -0
  177. package/vendor/ds-bot/src/host/im/platforms/weixin.js +256 -0
  178. package/vendor/ds-bot/src/host/images.js +22 -7
  179. package/vendor/ds-bot/src/host/learning.js +27 -7
  180. package/vendor/ds-bot/src/host/legacy.mjs +4 -0
  181. package/vendor/ds-bot/src/host/local-agents/acp.js +232 -0
  182. package/vendor/ds-bot/src/host/local-agents/adapter.js +540 -0
  183. package/vendor/ds-bot/src/host/local-agents/claude.js +179 -0
  184. package/vendor/ds-bot/src/host/local-agents/codex.js +175 -0
  185. package/vendor/ds-bot/src/host/local-agents/discover.js +99 -0
  186. package/vendor/ds-bot/src/host/local-agents/engines.js +65 -0
  187. package/vendor/ds-bot/src/host/local-agents/index.js +235 -0
  188. package/vendor/ds-bot/src/host/local-agents/jsonrpc.js +111 -0
  189. package/vendor/ds-bot/src/host/local-agents/mcp.js +141 -0
  190. package/vendor/ds-bot/src/host/memory.js +14 -1
  191. package/vendor/ds-bot/src/host/message-source.js +56 -0
  192. package/vendor/ds-bot/src/host/parts.js +259 -48
  193. package/vendor/ds-bot/src/host/providers.js +142 -17
  194. package/vendor/ds-bot/src/host/resume.js +54 -4
  195. package/vendor/ds-bot/src/host/roster.js +25 -3
  196. package/vendor/ds-bot/src/host/schedules.js +101 -7
  197. package/vendor/ds-bot/src/host/steward.js +2 -1
  198. package/vendor/ds-bot/src/host/store.js +52 -5
  199. package/vendor/ds-bot/src/host/tools.js +102 -15
  200. package/vendor/ds-bot/src/host/turns.js +28 -5
  201. package/vendor/ds-bot/src/host/update.js +3 -0
  202. package/vendor/ds-bot/src/shared/im-platforms.js +86 -0
  203. package//346/250/241/345/236/213/351/205/215/347/275/256/344/270/216/350/277/201/347/247/273.md +66 -0
  204. package/dist/web/assets/apple-touch-icon-BVvy03qx.png +0 -0
  205. package/dist/web/assets/icon-C8lhqe5n.svg +0 -6
  206. package/dist/web/assets/index-D2MsIF_C.js +0 -20
  207. package/dist/web/assets/index-DpwihgYi.css +0 -1
  208. package/dist/web/icons/icon.svg +0 -6
  209. package/vendor/ds-bot/README.md +0 -258
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/NOTICE ADDED
@@ -0,0 +1,22 @@
1
+ DSCord
2
+ Copyright 2026 DSCord contributors
3
+
4
+ DSCord-specific source code and documentation in this package are licensed
5
+ under the Apache License, Version 2.0. See LICENSE.
6
+
7
+ Third-party components retain their own licenses and notices.
8
+
9
+ DS-Bot
10
+ The vendored kernel is based on DS-Bot 0.3.1 by Fei2411 and the DS Bot
11
+ contributors, under Apache-2.0. See vendor/ds-bot/LICENSE,
12
+ vendor/ds-bot/NOTICE and vendor/ds-bot/UPSTREAM.json for provenance,
13
+ additional third-party notices and the DSCord modifications.
14
+
15
+ Ombre
16
+ The optional memory service is distributed under its MIT license.
17
+ See service/ombre/LICENSE and service/ombre/SOURCE.json.
18
+
19
+ Web interfaces
20
+ Bundled UI and icon notices are in web/licenses/ and the corresponding
21
+ licenses/ directory in each prebuilt interface. Other installed dependencies
22
+ retain the licenses provided by their respective packages.
package/README.md CHANGED
@@ -1,87 +1,108 @@
1
- # DSCord
1
+ # DSCord 0.4.0-alpha.2 安装与连接
2
2
 
3
- 人类与独立 Bot 共同参与的聊天协作框架,原项目名为 DS-Group。npm 包包含 Node 服务端、预构建 React PWA、Matrix 接入器、DSH 桥接和固定 DS-Bot 0.2.7。
3
+ > [!WARNING]
4
+ > **实验性项目。** DSCord 目前是实验性质的项目,接口、数据格式和行为随时可能变化,不保证兼容旧版本。项目不考虑安全问题,因此将别人加入到你的服务器当中的时候,请确认你有线下找他喝茶的能力。
4
5
 
5
- 当前为 `0.2.0-alpha.1`,使用 `alpha` 标签发布。服务器发行目标为 Linux amd64/arm64,要求 Node 24.19.0 及以上的 24.x。Bot 节点另外需要 DSH 0.2.1-rc.5 和 `opencode-go/deepseek-v4.1-flash` 模型配置。
6
+ DSCord 的 npm 包包含 Core、预构建网页/PWA、Matrix 适配器和 DSCord Bot 内核。完整服务器源码发行包另含 Compose 部署文件;同一部署的 Core、客户端和节点使用同一发行版本。
7
+
8
+ 本指南对应预发布版本 0.4.0-alpha.2,npm 安装包由该版本的 GitHub Release 提供。Node 支持范围由 [package.json](package.json) 声明为 `>=24.19.0 <25`。Bot 宿主固定使用 DSH `0.2.2-rc.1` 的 SDK 契约,见[内核说明](dsh-connect/KERNEL.md)。Docker 服务器无需在宿主另装 Node。
6
9
 
7
10
  ## 安装
8
11
 
12
+ 从发行页下载 `dscord-0.4.0-alpha.2.tgz` 后,可在 DSH 的 `Plugins → Add plugin` 中安装并启用 `dscord`,再登录服务器连接 Bot。发行页同时提供 `SHA256SUMS` 校验文件。[下载发行包](https://github.com/MixGeekers/dscord/releases/tag/ds-group-v0.4.0-alpha.2)
13
+
14
+ 全局安装 CLI 用于服务器与独立节点管理。npm 可以直接安装同一发行包,安装后核对 `dscord --version`。
15
+
9
16
  ```sh
10
- npm install --global dscord@alpha
17
+ npm install --global https://github.com/MixGeekers/dscord/releases/download/ds-group-v0.4.0-alpha.2/dscord-0.4.0-alpha.2.tgz
11
18
  dscord --help
12
19
  dscord --version
13
20
  ```
14
21
 
15
- 服务端与网页已经随包提供。运行时通过 `DS_GROUP_DATA_DIR` 指定数据目录,默认使用执行命令时所在目录下的 `.dscord`。在多个终端管理同一实例时,设置相同的绝对数据路径。`DS_GROUP_*` 是当前配置接口。
22
+ Core、CLI 和 DSH 插件使用同一发行版本。已有全局安装可用上述命令升级。
16
23
 
17
- ## 启动本机服务器
18
-
19
- 以下步骤使用 Docker 运行独立 Synapse,核心通过 Node 启动。先安装 Docker Engine 并启动 Docker 服务。
24
+ 从源码构建 npm 包,在 `apps/ds-group/` 中执行:
20
25
 
21
26
  ```sh
22
- export DS_GROUP_DATA_DIR="$HOME/.local/share/dscord"
23
- export DS_GROUP_SERVER_NAME=localhost
24
- export DS_GROUP_MATRIX_URL=http://127.0.0.1:18008
25
- export DS_GROUP_MATRIX_PUBLIC_URL=http://localhost:18008
26
- export DS_GROUP_PUBLIC_URL=http://localhost:18100
27
- dscord init
28
-
29
- docker run --detach --name dscord-synapse \
30
- --user "$(id -u):$(id -g)" \
31
- --publish 127.0.0.1:18008:8008 \
32
- --mount "type=bind,source=$DS_GROUP_DATA_DIR/synapse,target=/data" \
33
- ghcr.io/element-hq/synapse@sha256:f0df87cff259872637b4b5e5174b9977e5e3046dd421505407803b5e45c5f842
27
+ npm ci --ignore-scripts
28
+ npm run npm:pack
34
29
  ```
35
30
 
36
- 等待 Synapse 的 `http://127.0.0.1:18008/_matrix/client/versions` 返回成功,再执行。
31
+ 该版本默认生成 `.local/npm-release/dscord-0.4.0-alpha.2.tgz`,仍应核对命令实际输出的版本、路径与校验值。构建需要开发依赖,运行已提供的预构建包不需要重新构建界面。
32
+
33
+ ## 部署服务器
34
+
35
+ 完整服务器采用[Compose 部署指南](https://github.com/MixGeekers/dscord/blob/ds-group-v0.4.0-alpha.2/apps/ds-group/deploy/README.md),先配置自己的 Matrix 身份域、公开地址和持久存储。npm CLI 不代替 Synapse 或反向代理。需要 `dscord server`、初始化及节点导入等命令时,在各终端保持同一个绝对数据路径:
37
36
 
38
37
  ```sh
39
- dscord bootstrap
40
- dscord admin credentials alice
41
- dscord server
38
+ export DS_GROUP_DATA_DIR="$HOME/.local/share/dscord-server"
39
+ dscord --version
42
40
  ```
43
41
 
44
- 浏览器访问 `http://localhost:18100`,使用上一步在管理员终端显示的 Alice 登录信息。初始化会创建 Alice、Bob、财务和人事四个独立成员。Bot 在各自节点接入后上线。服务端通过 `Ctrl+C` 停止,Synapse 可通过 `docker stop dscord-synapse` 停止,并通过 `docker start dscord-synapse` 再次启动。
42
+ 上面的路径可自行替换。npm CLI 未设置数据目录时使用当前工作目录下的 `.dscord/`,在不同目录执行管理命令可能选中不同实例。
43
+
44
+ ## 在 DSH 中连接
45
+
46
+ 1. 准备固定基线的官方 CLI,或提供相同 SDK 服务的 DSH 宿主。CLI 可执行 `npm install --global @deepseek-ai/dsh@0.2.2-rc.1`。在 DSH 中配置自己的业务模型和凭据。
47
+ 2. 安装同版本 `dscord` 插件并启用,打开左侧 **DSCord**,填写 Core/PWA 的地址和自己的账号,登录服务器。
48
+ 3. 在“此节点的 Bot”中创建 Bot,选择 DSH 已配置的模型并填写职责,或选择已有 Bot。纯读取状态不会自动创建 Bot。
49
+ 4. 点击“加入服务器”。网页“我的 Bot → 添加已有 Bot”也可选择这个已连接节点公布的 Bot。两端必须是同一账号。
50
+ 5. 在网页打开私聊或邀请 Bot 进入需要参与的群聊。参与方式、来源记忆和当前工作在 Bot 设置中查看。
45
51
 
46
- HTTPS、Docker Compose、备份恢复与 systemd 的完整部署流程见源码仓库中的部署指南。手机 PWA 安装和通知需要可信 HTTPS。[服务器部署指南](https://github.com/MixGeekers/ds_group/blob/main/apps/ds-group/deploy/README.md)
52
+ 地址、账号、模型和路径都来自部署者自己的配置。业务模型没有指定服务商;自然参与的单独判断服务是可选功能,见[模型与参与设置](模型配置与迁移.md)。
47
53
 
48
- ## 连接 Bot 节点
54
+ Core 提供的 Matrix 公开地址必须能从节点访问。一个连接页使用一个归属账号,可管理多个本机 Bot。连接数据默认位于实际 DSH home 的 `dscord/<profile>/`,Bot 数据保留在该 home 的 `bot/`。断开服务器、退出连接页或关闭网页不删除本机 Bot;DSH 停止后,Bot 也无法继续工作。
49
55
 
50
- 先按服务器部署指南配置 HTTPS 反向代理,使核心 API 和 Matrix API 可从 Bot 机器访问。然后将 `DS_GROUP_PUBLIC_URL` 和 `DS_GROUP_MATRIX_PUBLIC_URL` 配置为对应的外部地址,再执行 `dscord init` 和 `dscord bootstrap` 更新地址。使用目标 Bot 的名称导出节点配置。
56
+ ## 升级和已有 Bot
57
+
58
+ 先备份服务器数据和各 DSH Bot home,再停止当前工作并升级到同一发行版本。已有 `ds-bot` 插件必须先停用,DSCord 才能在同一目录接管;同时启动两个内核会报冲突。接管会保存迁移快照,保留 Bot 与 Session 身份。[生命周期与迁移](https://github.com/MixGeekers/dscord/blob/ds-group-v0.4.0-alpha.2/apps/ds-group/deploy/kernel-runtime.md)
59
+
60
+ 旧服务器 Bot 可在连接页绑定已有本机 Bot,保留 Matrix 身份;两套独立 Session 或记忆不会自动合并。已有原生绑定的 Bot 应从所属 DSH 连接,导出其配置不能在另一台机器创建身份副本。
61
+
62
+ ## 独立 CLI 节点
63
+
64
+ CLI 适用于没有已有原生绑定的独立 Bot。已绑定本机 Bot 的成员必须使用所属 DSH 的连接页,启动器会拒绝复制其身份。
65
+
66
+ 在服务器端导出目标 Bot,参数使用完整 Matrix ID 中 `@` 与 `:` 之间的账号部分,不是显示名称:
51
67
 
52
68
  ```sh
69
+ BOT_ACCOUNT='your-bot-account'
53
70
  umask 077
54
- dscord admin export-node finance > finance-node.json
71
+ dscord admin export-node "$BOT_ACCOUNT" > bot-node.json
55
72
  ```
56
73
 
57
- 将配置文件传到 Bot 机器,在该机器安装 `dscord@alpha` 和 DSH,再执行。
74
+ 将私有导出文件传到节点,安装同版本程序和兼容 DSH。以下数据目录、空闲端口、来源 profile 和 `provider/model-id` 均须替换为自己的配置:
58
75
 
59
76
  ```sh
60
- npm install --global @deepseek-ai/dsh@0.2.1-rc.5
61
- export DS_GROUP_DATA_DIR="$HOME/.local/share/dscord-finance"
62
- dscord admin import-node finance-node.json "$DS_GROUP_DATA_DIR"
63
- read -r -s OPENCODE_API_KEY
64
- export OPENCODE_API_KEY
65
- dscord service up finance
77
+ BOT_ACCOUNT='your-bot-account'
78
+ export DS_GROUP_DATA_DIR="$HOME/.local/share/dscord-nodes/$BOT_ACCOUNT"
79
+ export DS_GROUP_BRIDGE_PORT=23100
80
+ dscord admin import-node bot-node.json "$DS_GROUP_DATA_DIR"
81
+ export DS_GROUP_DSH_SOURCE_HOME='/absolute/path/to/your/dsh-home'
82
+ export DS_GROUP_DSH_SOURCE_PROFILE='your-profile'
83
+ export DS_GROUP_MODEL='provider/model-id'
84
+ dscord service up "$BOT_ACCOUNT"
66
85
  ```
67
86
 
68
- `OPENCODE_API_KEY` 在本地终端输入。人事节点使用 `hr` 及独立数据目录。使用以下命令停止财务节点及其 DSH。
87
+ 若 DSH 不在 PATH,用 `DS_GROUP_DSH_CLI` 指定可执行文件、`DS_GROUP_DSH_RUNTIME` 指定实际 SDK 包根或安装前缀。启动器按锁准备自己的运行依赖,不需要手工复制库目录。独立节点会复制所选模型配置所需的凭据到私有数据目录,行为与直接复用宿主的图形节点不同。[模型与凭据](模型配置与迁移.md)
88
+
89
+ 在同一组环境变量下停止:
69
90
 
70
91
  ```sh
71
- dscord service down finance
72
- dscord dsh stop finance
92
+ dscord service down "$BOT_ACCOUNT"
93
+ dscord dsh stop "$BOT_ACCOUNT"
73
94
  ```
74
95
 
75
- 当前 npm 入口提供 CLI 部署。DSH 桌面“添加插件”中的直接安装与自动接入仍待实现。
96
+ 每个 Bot 同时运行一个节点,每个独立节点使用自己的数据目录和桥接端口。Linux 常驻服务见 [systemd](https://github.com/MixGeekers/dscord/blob/ds-group-v0.4.0-alpha.2/apps/ds-group/deploy/systemd/README.md)。
97
+
98
+ ## 存储与组件
99
+
100
+ 附件默认使用 Synapse 本地媒体目录,可选 S3-compatible 后端。[存储配置](https://github.com/MixGeekers/dscord/blob/ds-group-v0.4.0-alpha.2/apps/ds-group/deploy/storage/README.md)说明远端对象、缓存和备份关系;已有云盘扫描与历史迁移不是自动功能。
101
+
102
+ `dscord server` 运行 Core/PWA,`init` 和 `bootstrap` 初始化服务器,`admin` 管理导出与导入,`node` 运行 Matrix 适配器,`dsh` 管理独立宿主,`service` 管理本机进程,`path` 显示安装目录。
76
103
 
77
- ## 包内组件
104
+ DS-Bot 的 Apache-2.0 LICENSE 与 NOTICE 位于 `vendor/ds-bot/`,界面图标许可随 `dist/web/licenses/` 提供。
78
105
 
79
- - `dscord server` 启动核心 API 和预构建 PWA。
80
- - `dscord init` 与 `dscord bootstrap` 管理服务器初始化和 Matrix 成员。
81
- - `dscord admin` 读取账号、导出和导入节点配置。
82
- - `dscord node` 运行 Matrix 适配进程。
83
- - `dscord dsh` 管理独立 DSH 运行时。
84
- - `dscord service` 管理本机核心和 Bot 进程。
85
- - `dscord path` 显示安装目录。
106
+ ## 许可证
86
107
 
87
- 上游 DS-Bot 的 Apache-2.0 LICENSE 与 NOTICE 位于 `vendor/ds-bot/`。Lucide 的 ISC 与 Feather MIT 许可位于 `dist/web/licenses/lucide.txt`。
108
+ DSCord 自有代码和文档采用 Apache-2.0。安装包包含本体许可及第三方声明,预构建界面的依赖许可位于各自的 `licenses/` 目录。[LICENSE](LICENSE) · [NOTICE](NOTICE)
package/bin/dscord.mjs CHANGED
@@ -17,8 +17,8 @@ const entries = new Map([
17
17
  ]);
18
18
  const help = `Usage: dscord <command> [arguments]
19
19
 
20
- server Run the core server and PWA
21
- init Prepare server and Synapse configuration
20
+ server Run the core server in its configured web mode
21
+ init [--web-mode MODE] Prepare configuration (MODE: bundled or api-only)
22
22
  bootstrap Register initial members on the configured Synapse
23
23
  admin <arguments> Manage server credentials and node exports
24
24
  node <arguments> Run a Matrix Bot adapter
@@ -29,6 +29,7 @@ const help = `Usage: dscord <command> [arguments]
29
29
  help Show this help
30
30
 
31
31
  DS_GROUP_DATA_DIR defaults to .dscord in the current directory.
32
+ DS_GROUP_WEB_MODE overrides web hosting; init persists it in core-config.json.
32
33
  `;
33
34
 
34
35
  async function run() {
@@ -48,10 +49,10 @@ async function run() {
48
49
  const entry = entries.get(command);
49
50
  if (!entry) throw new Error(`Unknown command "${command}". Run dscord help.`);
50
51
  if (command === 'service' && ['up', 'down', 'restart'].includes(args[0]) && !args[1]) {
51
- throw new Error('Choose a service component explicitly: all, core, finance, or hr.');
52
+ throw new Error('Choose a service component explicitly: all, core, or a local Bot account name.');
52
53
  }
53
54
  if (command === 'dsh' && args.length < 2) {
54
- throw new Error('Use dscord dsh <start|run|stop|status|prepare> <finance|hr>.');
55
+ throw new Error('Use dscord dsh <start|run|stop|status|prepare> <bot-account>.');
55
56
  }
56
57
 
57
58
  const env = { ...process.env };
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: dscord-connect
3
+ name: dscord
@@ -0,0 +1,212 @@
1
+ """DSCord private federation admission. Pinned and tested with Synapse 1.164.2.
2
+
3
+ Policy is local authority, never instructions from room content. Each host enforces
4
+ its own local users and rooms; remote message history is not rewritten by this module.
5
+ """
6
+ import json
7
+ import hashlib
8
+ import os
9
+ import time
10
+ import uuid
11
+
12
+ from synapse.module_api import NOT_SPAM
13
+ from synapse.module_api.errors import Codes, SynapseError
14
+ from twisted.web.resource import Resource
15
+
16
+
17
+ def domain(user_id):
18
+ return user_id.split(":", 1)[1] if isinstance(user_id, str) and ":" in user_id else None
19
+
20
+
21
+ def acl_host(server):
22
+ return server.split(":", 1)[0]
23
+
24
+
25
+ class GovernanceStatus(Resource):
26
+ isLeaf = True
27
+
28
+ def __init__(self, guard):
29
+ super().__init__()
30
+ self.guard = guard
31
+
32
+ def render_GET(self, request):
33
+ self.guard.policy()
34
+ request.setHeader(b"Content-Type", b"application/json")
35
+ request.setHeader(b"Cache-Control", b"no-store")
36
+ if self.guard.document["error"]:
37
+ request.setResponseCode(503)
38
+ return json.dumps(self.guard.document).encode("utf-8")
39
+
40
+
41
+ class GovernanceModule:
42
+ def __init__(self, config, api):
43
+ self.api = api
44
+ self.config = config
45
+ self.server = config["server_name"]
46
+ self.boot_id = str(uuid.uuid4())
47
+ with open(__file__, "rb") as stream:
48
+ self.source_hash = hashlib.sha256(stream.read()).hexdigest()
49
+ self.last_status = None
50
+ self.document = {}
51
+ api.register_spam_checker_callbacks(user_may_invite=self.may_invite, user_may_join_room=self.may_join)
52
+ api.register_third_party_rules_callbacks(check_event_allowed=self.check_event, on_create_room=self.on_create)
53
+ api.register_web_resource("/_synapse/client/dscord-governance/status", GovernanceStatus(self))
54
+ self.policy()
55
+
56
+ @staticmethod
57
+ def parse_config(config):
58
+ for key in ("server_name", "policy_path", "status_path"):
59
+ if not isinstance(config.get(key), str) or not config[key]:
60
+ raise ValueError("Missing DSCord guard " + key)
61
+ return config
62
+
63
+ def policy(self):
64
+ try:
65
+ with open(self.config["policy_path"], encoding="utf-8") as stream:
66
+ policy = json.load(stream)
67
+ if policy["schemaVersion"] != 1 or policy["serverName"] != self.server or not isinstance(policy["revision"], int):
68
+ raise ValueError("Invalid policy identity")
69
+ # Fail closed on missing or malformed configuration, including local operations.
70
+ for key in ("partners", "members", "rooms", "botPolicies"):
71
+ if not isinstance(policy[key], list):
72
+ raise ValueError("Invalid policy collection")
73
+ revision = policy["revision"]
74
+ error = None
75
+ except (OSError, ValueError, KeyError, TypeError):
76
+ policy = None
77
+ revision = None
78
+ error = "POLICY_UNAVAILABLE"
79
+ status = (revision, error)
80
+ self.document = {"serverName": self.server, "bootId": self.boot_id, "synapseVersion": "1.164.2",
81
+ "sourceSha256": self.source_hash,
82
+ "liveRevision": revision, "loadedPartners": self.config.get("loaded_partners", []),
83
+ "observedAt": int(time.time() * 1000), "error": error}
84
+ if status != self.last_status:
85
+ self.last_status = status
86
+ filename = self.config["status_path"]
87
+ temporary = filename + "." + str(os.getpid()) + ".tmp"
88
+ try:
89
+ with open(temporary, "w", encoding="utf-8") as stream:
90
+ json.dump(self.document, stream)
91
+ os.chmod(temporary, 0o600)
92
+ os.replace(temporary, filename)
93
+ except OSError:
94
+ self.last_status = None
95
+ return policy
96
+
97
+ def partners(self, policy):
98
+ return [row["serverName"] for row in policy["partners"] if row.get("enabled") is True]
99
+
100
+ def admitted(self, policy, user):
101
+ return domain(user) == self.server or domain(user) in self.partners(policy) and any(
102
+ row["id"] == user and row.get("enabled") is True for row in policy["members"])
103
+
104
+ def rule(self, policy, room):
105
+ return next((row for row in policy["rooms"] if row["roomId"] == room), None)
106
+
107
+ def allowed(self, policy, room, user):
108
+ row = self.rule(policy, room)
109
+ return bool(row and row.get("enabled") is True and self.admitted(policy, user)
110
+ and (user in row.get("memberIds", []) or domain(user) == self.server and row["authority"] == self.server))
111
+
112
+ async def may_invite(self, inviter, invitee, room_id):
113
+ policy = self.policy()
114
+ if not policy:
115
+ return Codes.FORBIDDEN
116
+ if domain(inviter) == self.server and domain(invitee) == self.server:
117
+ return NOT_SPAM
118
+ # Both participating servers approve the exact room and external identity.
119
+ if not self.admitted(policy, inviter) or not self.admitted(policy, invitee):
120
+ return Codes.FORBIDDEN
121
+ row = self.rule(policy, room_id)
122
+ if not row or not row.get("enabled"):
123
+ return Codes.FORBIDDEN
124
+ if row["authority"] == self.server:
125
+ return NOT_SPAM if self.allowed(policy, room_id, invitee) else Codes.FORBIDDEN
126
+ return NOT_SPAM if row["authority"] in self.partners(policy) and invitee in row.get("memberIds", []) else Codes.FORBIDDEN
127
+
128
+ async def may_join(self, user, room, is_invited):
129
+ policy = self.policy()
130
+ if not policy:
131
+ return Codes.FORBIDDEN
132
+ row = self.rule(policy, room)
133
+ if row:
134
+ return NOT_SPAM if self.allowed(policy, room, user) and (row["authority"] == self.server or is_invited) else Codes.FORBIDDEN
135
+ # Legacy local-only rooms retain their membership behavior. Foreign rooms
136
+ # need an explicit policy even when a user bypasses Core and calls /join.
137
+ state = await self.api.get_room_state(room, [("m.room.create", "")])
138
+ creator = state.get(("m.room.create", ""))
139
+ return NOT_SPAM if creator and domain(creator.sender) == self.server and domain(user) == self.server else Codes.FORBIDDEN
140
+
141
+ async def on_create(self, requester, request_content, is_requester_admin):
142
+ policy = self.policy()
143
+ if not policy:
144
+ raise SynapseError(403, "DSCord admission policy unavailable", Codes.FORBIDDEN)
145
+ for target in request_content.get("invite", []):
146
+ if domain(target) != self.server:
147
+ # Register the room rule first, then invite. There is no stable
148
+ # room ID before creation to which an external grant can bind.
149
+ raise SynapseError(403, "Create the room, approve its rule, then invite external members", Codes.FORBIDDEN)
150
+ states = [row for row in request_content.get("initial_state", []) if row.get("type") not in ("m.room.server_acl", "m.room.join_rules")]
151
+ states.extend([{"type": "m.room.server_acl", "state_key": "", "content": {
152
+ "allow": sorted({acl_host(self.server), self.server}), "deny": [], "allow_ip_literals": False}},
153
+ {"type": "m.room.join_rules", "state_key": "", "content": {"join_rule": "invite"}}])
154
+ request_content["initial_state"] = states
155
+ request_content["visibility"] = "private"
156
+
157
+ async def check_event(self, event, state_events):
158
+ policy = self.policy()
159
+ # Incoming federated history is governed by Matrix auth; rejecting its
160
+ # messages here would create divergent room DAGs. Revoke through bans.
161
+ if domain(event.sender) != self.server:
162
+ if event.type == "m.room.member" and event.content.get("membership") in ("invite", "join"):
163
+ creator = state_events.get(("m.room.create", ""))
164
+ row = self.rule(policy, event.room_id) if policy else None
165
+ local_authority = row["authority"] == self.server if row else creator and domain(creator.sender) == self.server
166
+ if local_authority:
167
+ return bool(policy and self.allowed(policy, event.room_id, event.state_key)), None
168
+ return True, None
169
+ if not policy:
170
+ return False, None
171
+ row = self.rule(policy, event.room_id)
172
+ creator = state_events.get(("m.room.create", ""))
173
+ local_room = row["authority"] == self.server if row else not creator or domain(creator.sender) == self.server
174
+ if not local_room and event.type not in ("m.room.member", "m.room.server_acl", "m.room.join_rules", "org.dscord.work_policy"):
175
+ return bool(row and self.allowed(policy, event.room_id, event.sender)), None
176
+ if event.type == "m.room.member":
177
+ membership = event.content.get("membership")
178
+ if membership in ("leave", "ban"):
179
+ return True, None
180
+ if domain(event.state_key) != self.server:
181
+ return self.allowed(policy, event.room_id, event.state_key), None
182
+ if not local_room:
183
+ return self.allowed(policy, event.room_id, event.state_key), None
184
+ if event.type == "m.room.join_rules":
185
+ return event.content.get("join_rule") == "invite", None
186
+ if event.type == "m.room.server_acl":
187
+ # Host patterns enforce the specification. The full local name also
188
+ # satisfies Synapse 1.164.2's validator, which checks the port-bearing
189
+ # local server name without stripping its port.
190
+ permitted = {acl_host(self.server), self.server}
191
+ if row and row.get("enabled"):
192
+ if row["authority"] == self.server or row["authority"] in self.partners(policy):
193
+ permitted.add(acl_host(row["authority"]))
194
+ permitted.add(row["authority"])
195
+ for user in row["memberIds"]:
196
+ if self.admitted(policy, user):
197
+ permitted.update({acl_host(domain(user)), domain(user)})
198
+ allow = event.content.get("allow", [])
199
+ return bool(allow and set(allow).issubset(permitted) and event.content.get("allow_ip_literals") is False), None
200
+ if event.type == "org.dscord.work_policy":
201
+ if not local_room:
202
+ return False, None
203
+ expected = {"schemaVersion": 1, "roomId": event.room_id,
204
+ "revision": policy["revision"], "authority": self.server,
205
+ "issuerId": "@dscord-control:" + self.server,
206
+ "localMemberAdmission": "matrix-membership",
207
+ "enabled": bool(row and row.get("enabled")),
208
+ "botIds": [user for user in row.get("botIds", []) if self.admitted(policy, user)] if row else [],
209
+ "tools": row.get("tools", []) if row else [],
210
+ "memberIds": [user for user in row.get("memberIds", []) if self.admitted(policy, user)] if row else []}
211
+ return event.sender == expected["issuerId"] and event.content == expected, None
212
+ return True, None