yakmesh 2.8.2 → 3.0.0

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 (232) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/Caddyfile +77 -0
  4. package/README.md +119 -29
  5. package/adapters/adapter-mlv-bible/README.md +124 -0
  6. package/adapters/adapter-mlv-bible/index.js +400 -0
  7. package/adapters/chat-mod-adapter.js +532 -0
  8. package/adapters/content-adapter.js +273 -0
  9. package/content/api.js +50 -41
  10. package/content/index.js +2 -2
  11. package/content/store.js +355 -173
  12. package/dashboard/index.html +19 -3
  13. package/database/replication.js +117 -37
  14. package/docs/CRYPTO-AGILITY.md +204 -0
  15. package/docs/MTLS-RESEARCH.md +367 -0
  16. package/docs/NAMCHE-SPEC.md +681 -0
  17. package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
  18. package/docs/PRECISION-DISCLOSURE.md +96 -0
  19. package/docs/README.md +76 -0
  20. package/docs/ROADMAP-2.4.0.md +447 -0
  21. package/docs/ROADMAP-2.5.0.md +244 -0
  22. package/docs/SECURITY-AUDIT-REPORT.md +306 -0
  23. package/docs/SST-INTEGRATION.md +712 -0
  24. package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
  25. package/docs/TERNARY-AUDIT-REPORT.md +247 -0
  26. package/docs/TME-FAQ.md +221 -0
  27. package/docs/WHITEPAPER.md +623 -0
  28. package/docs/adapters.html +1001 -0
  29. package/docs/advanced-systems.html +1045 -0
  30. package/docs/annex.html +1046 -0
  31. package/docs/api.html +970 -0
  32. package/docs/business/response-templates.md +160 -0
  33. package/docs/c2c.html +1225 -0
  34. package/docs/cli.html +1332 -0
  35. package/docs/configuration.html +1248 -0
  36. package/docs/darshan.html +1085 -0
  37. package/docs/dharma.html +966 -0
  38. package/docs/docs-bundle.html +1075 -0
  39. package/docs/docs.css +3120 -0
  40. package/docs/docs.js +556 -0
  41. package/docs/doko.html +969 -0
  42. package/docs/geo-proof.html +858 -0
  43. package/docs/getting-started.html +840 -0
  44. package/docs/gumba-tutorial.html +1144 -0
  45. package/docs/gumba.html +1098 -0
  46. package/docs/index.html +914 -0
  47. package/docs/jhilke.html +1312 -0
  48. package/docs/karma.html +1100 -0
  49. package/docs/katha.html +1037 -0
  50. package/docs/lama.html +978 -0
  51. package/docs/mandala.html +1067 -0
  52. package/docs/mani.html +964 -0
  53. package/docs/mantra.html +967 -0
  54. package/docs/mesh.html +1409 -0
  55. package/docs/nakpak.html +869 -0
  56. package/docs/namche.html +928 -0
  57. package/docs/nav-order.json +53 -0
  58. package/docs/prahari.html +1043 -0
  59. package/docs/prism-bash.min.js +1 -0
  60. package/docs/prism-javascript.min.js +1 -0
  61. package/docs/prism-json.min.js +1 -0
  62. package/docs/prism-tomorrow.min.css +1 -0
  63. package/docs/prism.min.js +1 -0
  64. package/docs/privacy.html +699 -0
  65. package/docs/quick-reference.html +1181 -0
  66. package/docs/sakshi.html +1402 -0
  67. package/docs/sandboxing.md +386 -0
  68. package/docs/seva.html +911 -0
  69. package/docs/sherpa.html +871 -0
  70. package/docs/studio.html +860 -0
  71. package/docs/stupa.html +995 -0
  72. package/docs/tailwind.min.css +2 -0
  73. package/docs/tattva.html +1332 -0
  74. package/docs/terms.html +686 -0
  75. package/docs/time-server-deployment.md +166 -0
  76. package/docs/time-sources.html +1392 -0
  77. package/docs/tivra.html +1127 -0
  78. package/docs/trademark-policy.html +686 -0
  79. package/docs/tribhuj.html +1183 -0
  80. package/docs/trust-security.html +1029 -0
  81. package/docs/tutorials/backup-recovery.html +654 -0
  82. package/docs/tutorials/dashboard.html +604 -0
  83. package/docs/tutorials/domain-setup.html +605 -0
  84. package/docs/tutorials/host-website.html +456 -0
  85. package/docs/tutorials/mesh-network.html +505 -0
  86. package/docs/tutorials/mobile-access.html +445 -0
  87. package/docs/tutorials/privacy.html +467 -0
  88. package/docs/tutorials/raspberry-pi.html +600 -0
  89. package/docs/tutorials/security-basics.html +539 -0
  90. package/docs/tutorials/share-files.html +431 -0
  91. package/docs/tutorials/troubleshooting.html +637 -0
  92. package/docs/tutorials/trust-karma.html +419 -0
  93. package/docs/tutorials/yak-protocol.html +456 -0
  94. package/docs/tutorials.html +1034 -0
  95. package/docs/vani.html +1270 -0
  96. package/docs/webserver.html +809 -0
  97. package/docs/yak-protocol.html +940 -0
  98. package/docs/yak-timeserver-design.md +475 -0
  99. package/docs/yakapp.html +1015 -0
  100. package/docs/ypc27.html +1069 -0
  101. package/docs/yurt.html +1344 -0
  102. package/embedded-docs/bundle.js +334 -74
  103. package/gossip/protocol.js +247 -27
  104. package/identity/key-resolver.js +262 -0
  105. package/identity/machine-seed.js +632 -0
  106. package/identity/node-key.js +669 -368
  107. package/identity/tribhuj-ratchet.js +506 -0
  108. package/knowledge-base.js +37 -8
  109. package/launcher/yakmesh.bat +62 -0
  110. package/launcher/yakmesh.sh +70 -0
  111. package/mesh/annex.js +462 -108
  112. package/mesh/beacon-broadcast.js +113 -1
  113. package/mesh/darshan.js +1718 -0
  114. package/mesh/gumba.js +1567 -0
  115. package/mesh/jhilke.js +651 -0
  116. package/mesh/katha.js +1012 -0
  117. package/mesh/nakpak-routing.js +8 -5
  118. package/mesh/network.js +724 -34
  119. package/mesh/pulse-sync.js +4 -1
  120. package/mesh/rate-limiter.js +127 -15
  121. package/mesh/seva.js +526 -0
  122. package/mesh/sherpa-discovery.js +89 -8
  123. package/mesh/sybil-defense.js +19 -5
  124. package/mesh/temporal-encoder.js +4 -3
  125. package/mesh/vani.js +1364 -0
  126. package/mesh/yurt.js +1340 -0
  127. package/models/entropy-sentinel.onnx +0 -0
  128. package/models/karma-trust.onnx +0 -0
  129. package/models/manifest.json +43 -0
  130. package/models/sakshi-anomaly.onnx +0 -0
  131. package/oracle/code-proof-protocol.js +7 -6
  132. package/oracle/codebase-lock.js +257 -28
  133. package/oracle/index.js +74 -15
  134. package/oracle/ma902-snmp.js +678 -0
  135. package/oracle/module-sealer.js +5 -3
  136. package/oracle/network-identity.js +16 -0
  137. package/oracle/packet-checksum.js +201 -0
  138. package/oracle/sst.js +579 -0
  139. package/oracle/ternary-144t.js +714 -0
  140. package/oracle/ternary-ml.js +481 -0
  141. package/oracle/time-api.js +239 -0
  142. package/oracle/time-source.js +137 -47
  143. package/oracle/validation-oracle-hardened.js +1111 -1071
  144. package/oracle/validation-oracle.js +4 -2
  145. package/oracle/ypc27.js +211 -0
  146. package/package.json +20 -3
  147. package/protocol/yak-handler.js +35 -9
  148. package/protocol/yak-protocol.js +28 -13
  149. package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
  150. package/reference/cpp/yakmesh_ypc27.cpp +179 -0
  151. package/sbom.json +87 -0
  152. package/scripts/security-audit.mjs +264 -0
  153. package/scripts/update-docs-nav.js +194 -0
  154. package/scripts/update-docs-sidebar.cjs +164 -0
  155. package/security/crypto-config.js +4 -3
  156. package/security/dharma-moderation.js +517 -0
  157. package/security/doko-identity.js +193 -143
  158. package/security/domain-consensus.js +86 -85
  159. package/security/fs-hardening.js +620 -0
  160. package/security/hardware-attestation.js +5 -3
  161. package/security/hybrid-trust.js +227 -87
  162. package/security/karma-rate-limiter.js +692 -0
  163. package/security/khata-protocol.js +22 -21
  164. package/security/khata-trust-integration.js +277 -150
  165. package/security/memory-safety.js +635 -0
  166. package/security/mesh-auth.js +11 -10
  167. package/security/mesh-revocation.js +373 -5
  168. package/security/namche-gateway.js +298 -69
  169. package/security/sakshi.js +460 -3
  170. package/security/sangha.js +770 -0
  171. package/security/secure-config.js +473 -0
  172. package/security/silicon-parity.js +13 -10
  173. package/security/steadywatch.js +1142 -0
  174. package/security/strike-system.js +32 -3
  175. package/security/temporal-signing.js +488 -0
  176. package/security/trit-commitment.js +464 -0
  177. package/server/crypto/annex.js +247 -0
  178. package/server/darshan-api.js +343 -0
  179. package/server/index.js +3259 -362
  180. package/server/komm-api.js +668 -0
  181. package/utils/accel.js +2273 -0
  182. package/utils/ternary-id.js +79 -0
  183. package/utils/verify-worker.js +57 -0
  184. package/webserver/index.js +95 -5
  185. package/assets/yakmesh-logo.png +0 -0
  186. package/assets/yakmesh-logo.svg +0 -80
  187. package/assets/yakmesh-logo2.png +0 -0
  188. package/assets/yakmesh-logo2sm.png +0 -0
  189. package/assets/ymsm.png +0 -0
  190. package/website/assets/silhouettes/adapters.svg +0 -107
  191. package/website/assets/silhouettes/api-endpoints.svg +0 -115
  192. package/website/assets/silhouettes/atomic-clock.svg +0 -83
  193. package/website/assets/silhouettes/base-camp.svg +0 -81
  194. package/website/assets/silhouettes/bridge.svg +0 -69
  195. package/website/assets/silhouettes/docs-bundle.svg +0 -113
  196. package/website/assets/silhouettes/doko-basket.svg +0 -70
  197. package/website/assets/silhouettes/fortress.svg +0 -93
  198. package/website/assets/silhouettes/gateway.svg +0 -54
  199. package/website/assets/silhouettes/gears.svg +0 -93
  200. package/website/assets/silhouettes/globe-satellite.svg +0 -67
  201. package/website/assets/silhouettes/karma-wheel.svg +0 -137
  202. package/website/assets/silhouettes/lama-council.svg +0 -141
  203. package/website/assets/silhouettes/mandala-network.svg +0 -169
  204. package/website/assets/silhouettes/mani-stones.svg +0 -149
  205. package/website/assets/silhouettes/mantra-wheel.svg +0 -116
  206. package/website/assets/silhouettes/mesh-nodes.svg +0 -113
  207. package/website/assets/silhouettes/nakpak.svg +0 -56
  208. package/website/assets/silhouettes/peak-lightning.svg +0 -73
  209. package/website/assets/silhouettes/sherpa.svg +0 -69
  210. package/website/assets/silhouettes/stupa-tower.svg +0 -119
  211. package/website/assets/silhouettes/tattva-eye.svg +0 -78
  212. package/website/assets/silhouettes/terminal.svg +0 -74
  213. package/website/assets/silhouettes/webserver.svg +0 -145
  214. package/website/assets/silhouettes/yak.svg +0 -78
  215. package/website/assets/yakmesh-logo.png +0 -0
  216. package/website/assets/yakmesh-logo.webp +0 -0
  217. package/website/assets/yakmesh-logo128x140.webp +0 -0
  218. package/website/assets/yakmesh-logo2.png +0 -0
  219. package/website/assets/yakmesh-logo2.svg +0 -51
  220. package/website/assets/yakmesh-logo40x44.webp +0 -0
  221. package/website/assets/yakmesh.gif +0 -0
  222. package/website/assets/yakmesh.ico +0 -0
  223. package/website/assets/yakmesh.jpg +0 -0
  224. package/website/assets/yakmesh.pdf +0 -0
  225. package/website/assets/yakmesh.png +0 -0
  226. package/website/assets/yakmesh.svg +0 -70
  227. package/website/assets/yakmesh128.webp +0 -0
  228. package/website/assets/yakmesh32.png +0 -0
  229. package/website/assets/yakmesh32.svg +0 -65
  230. package/website/assets/yakmesh32o.ico +0 -2
  231. package/website/assets/yakmesh32o.svg +0 -65
  232. package/website/assets/yakmesh32o.svgz +0 -0
@@ -0,0 +1,532 @@
1
+ /**
2
+ * Yakmesh - Chat Mod Adapter Framework
3
+ *
4
+ * Secure framework for chat modification plugins that integrate with KATHA.
5
+ * Designed to prevent manipulation and abuse by malicious adapters.
6
+ *
7
+ * KEY SECURITY PRINCIPLES:
8
+ * 1. Capability Declaration - Adapters MUST declare what they can do
9
+ * 2. Sandboxed Execution - Adapters cannot access raw message content without permission
10
+ * 3. Content Signing - All adapter-generated content is signed and verifiable
11
+ * 4. Rate Limiting - Prevents spam/flooding
12
+ * 5. GUMBA Integration - Respects room role permissions
13
+ * 6. DHARMA Moderation - Behavior-based content filtering (v3.0)
14
+ *
15
+ * @module adapters/chat-mod-adapter
16
+ * @version 1.1.0
17
+ */
18
+
19
+ import { EventEmitter } from 'events';
20
+ import { createHash } from 'crypto';
21
+ import { DharmaModerator, MODERATION_ACTIONS } from '../security/dharma-moderation.js';
22
+
23
+ /**
24
+ * Chat modification capabilities
25
+ * Adapters MUST declare their capabilities upfront
26
+ */
27
+ export const CHAT_MOD_CAPABILITIES = {
28
+ // Message handling
29
+ MSG_READ: 'msg:read', // Can read message content (requires consent)
30
+ MSG_RESPOND: 'msg:respond', // Can send responses to messages
31
+ MSG_EMBED: 'msg:embed', // Can embed rich content in messages
32
+ MSG_REACT: 'msg:react', // Can add reactions
33
+
34
+ // Command handling
35
+ CMD_SLASH: 'cmd:slash', // Can register slash commands (e.g., /bible)
36
+ CMD_MENTION: 'cmd:mention', // Can respond to @mentions
37
+ CMD_PREFIX: 'cmd:prefix', // Can handle custom prefixes
38
+
39
+ // Content generation
40
+ GEN_QUOTE: 'gen:quote', // Can generate quotes
41
+ GEN_CARD: 'gen:card', // Can generate rich cards
42
+ GEN_LINK: 'gen:link', // Can generate links
43
+
44
+ // Special permissions (require explicit user opt-in)
45
+ SPECIAL_DM: 'special:dm', // Can send direct messages
46
+ SPECIAL_THREAD: 'special:thread',// Can create threads
47
+ SPECIAL_PIN: 'special:pin', // Can pin messages (requires ADMIN)
48
+ };
49
+
50
+ /**
51
+ * Security levels for chat mods
52
+ */
53
+ export const SECURITY_LEVELS = {
54
+ SANDBOX: 'sandbox', // Maximum restrictions, no raw content access
55
+ STANDARD: 'standard', // Normal restrictions, declared capabilities only
56
+ TRUSTED: 'trusted', // Reduced restrictions (user explicitly trusts)
57
+ };
58
+
59
+ /**
60
+ * Adapter manifest - security declaration
61
+ */
62
+ export class ChatModManifest {
63
+ constructor({
64
+ id,
65
+ name,
66
+ version = '1.0.0',
67
+ author = null,
68
+ description = '',
69
+ capabilities = [],
70
+ commands = [], // Slash commands this adapter handles
71
+ triggers = [], // Message patterns that trigger this adapter
72
+ rateLimit = { messages: 10, window: 60000 }, // 10 messages per minute
73
+ securityLevel = SECURITY_LEVELS.SANDBOX,
74
+ } = {}) {
75
+ this.id = id;
76
+ this.name = name;
77
+ this.version = version;
78
+ this.author = author;
79
+ this.description = description;
80
+ this.capabilities = new Set(capabilities);
81
+ this.commands = commands;
82
+ this.triggers = triggers;
83
+ this.rateLimit = rateLimit;
84
+ this.securityLevel = securityLevel;
85
+
86
+ // Generate manifest hash for verification
87
+ this.hash = this._computeHash();
88
+ }
89
+
90
+ _computeHash() {
91
+ const data = JSON.stringify({
92
+ id: this.id,
93
+ name: this.name,
94
+ version: this.version,
95
+ capabilities: Array.from(this.capabilities).sort(),
96
+ commands: this.commands,
97
+ });
98
+ return createHash('sha256').update(data).digest('hex').slice(0, 16);
99
+ }
100
+
101
+ toJSON() {
102
+ return {
103
+ ...this,
104
+ capabilities: Array.from(this.capabilities),
105
+ };
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Abstract base class for chat modification adapters
111
+ */
112
+ export class ChatModAdapter extends EventEmitter {
113
+ /**
114
+ * @param {ChatModManifest} manifest - Security manifest
115
+ * @param {Object} config - Adapter configuration
116
+ */
117
+ constructor(manifest, config = {}) {
118
+ super();
119
+
120
+ if (new.target === ChatModAdapter) {
121
+ throw new Error('ChatModAdapter is abstract and cannot be instantiated directly');
122
+ }
123
+
124
+ if (!(manifest instanceof ChatModManifest)) {
125
+ throw new Error('ChatModAdapter requires a ChatModManifest');
126
+ }
127
+
128
+ this.manifest = manifest;
129
+ this.config = config;
130
+ this.katha = config.katha || null;
131
+ this.gumba = config.gumba || null;
132
+
133
+ // DHARMA content moderation (v3.0)
134
+ // Behavior-based filtering - no identity discrimination
135
+ this.moderator = config.moderator || new DharmaModerator();
136
+ this.enableModeration = config.enableModeration !== false; // Default: enabled
137
+
138
+ // Rate limiting state
139
+ this._rateLimitWindow = [];
140
+ this._rateLimitMax = manifest.rateLimit.messages;
141
+ this._rateLimitWindowMs = manifest.rateLimit.window;
142
+
143
+ // Statistics
144
+ this.stats = {
145
+ messagesProcessed: 0,
146
+ commandsHandled: 0,
147
+ responsesGenerated: 0,
148
+ rateLimitHits: 0,
149
+ moderationBlocks: 0,
150
+ errors: [],
151
+ };
152
+
153
+ // Validate manifest
154
+ this._validateManifest();
155
+ }
156
+
157
+ /**
158
+ * Initialize the adapter
159
+ * @abstract
160
+ */
161
+ async init() {
162
+ throw new Error('init() must be implemented by subclass');
163
+ }
164
+
165
+ /**
166
+ * Handle an incoming message
167
+ * Called by KATHA when messages match triggers
168
+ * @param {Object} context - Message context (sanitized based on capabilities)
169
+ * @returns {Promise<Object|null>} Response to send, or null
170
+ */
171
+ async handleMessage(context) {
172
+ // Rate limit check
173
+ if (!this._checkRateLimit()) {
174
+ this.stats.rateLimitHits++;
175
+ this.emit('rate-limited', { adapterId: this.manifest.id });
176
+ return null;
177
+ }
178
+
179
+ // Security: Strip sensitive data based on capabilities
180
+ const sanitizedContext = this._sanitizeContext(context);
181
+
182
+ // Call subclass implementation
183
+ const response = await this.onMessage(sanitizedContext);
184
+
185
+ if (response) {
186
+ this.stats.responsesGenerated++;
187
+ // DHARMA moderation check on output
188
+ const moderated = await this._moderateResponse(response, context);
189
+ if (moderated && moderated.blocked) {
190
+ return moderated; // Return moderation notice
191
+ }
192
+ return this._signResponse(moderated || response);
193
+ }
194
+
195
+ return null;
196
+ }
197
+
198
+ /**
199
+ * Handle a slash command
200
+ * @param {string} command - Command name (without /)
201
+ * @param {string[]} args - Command arguments
202
+ * @param {Object} context - Command context
203
+ * @returns {Promise<Object|null>}
204
+ */
205
+ async handleCommand(command, args, context) {
206
+ if (!this.manifest.capabilities.has(CHAT_MOD_CAPABILITIES.CMD_SLASH)) {
207
+ throw new Error('Adapter does not have slash command capability');
208
+ }
209
+
210
+ if (!this.manifest.commands.includes(command)) {
211
+ return null; // Not our command
212
+ }
213
+
214
+ if (!this._checkRateLimit()) {
215
+ this.stats.rateLimitHits++;
216
+ return null;
217
+ }
218
+
219
+ this.stats.commandsHandled++;
220
+
221
+ const response = await this.onCommand(command, args, this._sanitizeContext(context));
222
+
223
+ if (response) {
224
+ // DHARMA moderation check on output
225
+ const moderated = await this._moderateResponse(response, context);
226
+ if (moderated && moderated.blocked) {
227
+ return moderated; // Return moderation notice
228
+ }
229
+ return this._signResponse(moderated || response);
230
+ }
231
+
232
+ return null;
233
+ }
234
+
235
+ /**
236
+ * Handle incoming message (implement in subclass)
237
+ * @abstract
238
+ * @param {Object} context - Sanitized message context
239
+ * @returns {Promise<Object|null>}
240
+ */
241
+ async onMessage(context) {
242
+ // Default: no response
243
+ return null;
244
+ }
245
+
246
+ /**
247
+ * Handle slash command (implement in subclass)
248
+ * @abstract
249
+ * @param {string} command - Command name
250
+ * @param {string[]} args - Arguments
251
+ * @param {Object} context - Context
252
+ * @returns {Promise<Object|null>}
253
+ */
254
+ async onCommand(command, args, context) {
255
+ throw new Error('onCommand() must be implemented for slash command adapters');
256
+ }
257
+
258
+ /**
259
+ * Rate limit check
260
+ * @private
261
+ */
262
+ _checkRateLimit() {
263
+ const now = Date.now();
264
+
265
+ // Remove expired entries
266
+ this._rateLimitWindow = this._rateLimitWindow.filter(
267
+ t => now - t < this._rateLimitWindowMs
268
+ );
269
+
270
+ if (this._rateLimitWindow.length >= this._rateLimitMax) {
271
+ return false;
272
+ }
273
+
274
+ this._rateLimitWindow.push(now);
275
+ return true;
276
+ }
277
+
278
+ /**
279
+ * Sanitize context based on declared capabilities
280
+ * @private
281
+ */
282
+ _sanitizeContext(context) {
283
+ const sanitized = {
284
+ roomId: context.roomId,
285
+ senderId: context.senderId,
286
+ senderRole: context.senderRole,
287
+ timestamp: context.timestamp,
288
+ };
289
+
290
+ // Only include message content if adapter has read permission
291
+ if (this.manifest.capabilities.has(CHAT_MOD_CAPABILITIES.MSG_READ)) {
292
+ sanitized.content = context.content;
293
+ sanitized.messageId = context.messageId;
294
+ }
295
+
296
+ // Only include thread info if adapter has thread permission
297
+ if (this.manifest.capabilities.has(CHAT_MOD_CAPABILITIES.SPECIAL_THREAD)) {
298
+ sanitized.threadId = context.threadId;
299
+ sanitized.parentId = context.parentId;
300
+ }
301
+
302
+ return sanitized;
303
+ }
304
+
305
+ /**
306
+ * Sign a response for verification
307
+ * @private
308
+ */
309
+ _signResponse(response) {
310
+ return {
311
+ ...response,
312
+ _adapter: {
313
+ id: this.manifest.id,
314
+ name: this.manifest.name,
315
+ version: this.manifest.version,
316
+ manifestHash: this.manifest.hash,
317
+ timestamp: Date.now(),
318
+ },
319
+ };
320
+ }
321
+
322
+ /**
323
+ * Check content against DHARMA moderation rules
324
+ * @private
325
+ * @param {string} content - Content to check
326
+ * @param {Object} context - Context for logging
327
+ * @returns {Promise<Object>} Moderation result
328
+ */
329
+ async _moderateContent(content, context = {}) {
330
+ if (!this.enableModeration || !content) {
331
+ return { allowed: true };
332
+ }
333
+
334
+ const result = await this.moderator.checkContent(content, {
335
+ adapterId: this.manifest.id,
336
+ ...context,
337
+ });
338
+
339
+ if (!result.allowed) {
340
+ this.stats.moderationBlocks++;
341
+ this.emit('content-blocked', {
342
+ adapterId: this.manifest.id,
343
+ violationCount: result.violationCount,
344
+ highestSeverity: result.highestSeverity,
345
+ timestamp: Date.now(),
346
+ });
347
+ }
348
+
349
+ return result;
350
+ }
351
+
352
+ /**
353
+ * Moderate adapter output before sending
354
+ * @param {Object} response - Response to moderate
355
+ * @param {Object} context - Context
356
+ * @returns {Promise<Object|null>} Moderated response or null if blocked
357
+ */
358
+ async _moderateResponse(response, context = {}) {
359
+ if (!response) return null;
360
+
361
+ // Extract text content from response
362
+ const textContent = response.content || response.text ||
363
+ (response.card && response.card.title) ||
364
+ '';
365
+
366
+ const result = await this._moderateContent(textContent, context);
367
+
368
+ if (!result.allowed) {
369
+ return {
370
+ type: 'moderation-notice',
371
+ content: 'Content blocked by community standards',
372
+ blocked: true,
373
+ _adapter: {
374
+ id: this.manifest.id,
375
+ moderated: true,
376
+ timestamp: Date.now(),
377
+ },
378
+ };
379
+ }
380
+
381
+ return response;
382
+ }
383
+ _verified: true,
384
+ };
385
+ }
386
+
387
+ /**
388
+ * Validate manifest against known capabilities
389
+ * @private
390
+ */
391
+ _validateManifest() {
392
+ const validCaps = new Set(Object.values(CHAT_MOD_CAPABILITIES));
393
+
394
+ for (const cap of this.manifest.capabilities) {
395
+ if (!validCaps.has(cap)) {
396
+ console.warn(\[ChatModAdapter] Unknown capability: \\);
397
+ }
398
+ }
399
+
400
+ // Warn about dangerous combinations
401
+ if (this.manifest.capabilities.has(CHAT_MOD_CAPABILITIES.MSG_READ) &&
402
+ this.manifest.capabilities.has(CHAT_MOD_CAPABILITIES.SPECIAL_DM)) {
403
+ console.warn(\[ChatModAdapter] \ has MSG_READ + SPECIAL_DM - potential privacy concern\);
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Check if adapter has a capability
409
+ */
410
+ hasCapability(capability) {
411
+ return this.manifest.capabilities.has(capability);
412
+ }
413
+
414
+ /**
415
+ * Get adapter statistics
416
+ */
417
+ getStats() {
418
+ return {
419
+ ...this.stats,
420
+ manifest: this.manifest.toJSON(),
421
+ };
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Chat Mod Registry - manages installed adapters
427
+ */
428
+ export class ChatModRegistry extends EventEmitter {
429
+ constructor() {
430
+ super();
431
+ this.adapters = new Map(); // id -> ChatModAdapter
432
+ this.commandMap = new Map(); // command -> adapter id
433
+ this.triggerPatterns = []; // { pattern, adapterId }
434
+ }
435
+
436
+ /**
437
+ * Register an adapter
438
+ * @param {ChatModAdapter} adapter
439
+ */
440
+ register(adapter) {
441
+ if (this.adapters.has(adapter.manifest.id)) {
442
+ throw new Error(\Adapter already registered: \\);
443
+ }
444
+
445
+ this.adapters.set(adapter.manifest.id, adapter);
446
+
447
+ // Register commands
448
+ for (const cmd of adapter.manifest.commands) {
449
+ if (this.commandMap.has(cmd)) {
450
+ console.warn(\Command \/\ already registered by \\);
451
+ } else {
452
+ this.commandMap.set(cmd, adapter.manifest.id);
453
+ }
454
+ }
455
+
456
+ // Register triggers
457
+ for (const trigger of adapter.manifest.triggers) {
458
+ this.triggerPatterns.push({
459
+ pattern: new RegExp(trigger, 'i'),
460
+ adapterId: adapter.manifest.id,
461
+ });
462
+ }
463
+
464
+ this.emit('adapter-registered', adapter.manifest);
465
+ }
466
+
467
+ /**
468
+ * Unregister an adapter
469
+ */
470
+ unregister(adapterId) {
471
+ const adapter = this.adapters.get(adapterId);
472
+ if (!adapter) return;
473
+
474
+ // Remove commands
475
+ for (const cmd of adapter.manifest.commands) {
476
+ if (this.commandMap.get(cmd) === adapterId) {
477
+ this.commandMap.delete(cmd);
478
+ }
479
+ }
480
+
481
+ // Remove triggers
482
+ this.triggerPatterns = this.triggerPatterns.filter(
483
+ t => t.adapterId !== adapterId
484
+ );
485
+
486
+ this.adapters.delete(adapterId);
487
+ this.emit('adapter-unregistered', adapterId);
488
+ }
489
+
490
+ /**
491
+ * Route a slash command to the appropriate adapter
492
+ */
493
+ async routeCommand(command, args, context) {
494
+ const adapterId = this.commandMap.get(command);
495
+ if (!adapterId) return null;
496
+
497
+ const adapter = this.adapters.get(adapterId);
498
+ if (!adapter) return null;
499
+
500
+ return adapter.handleCommand(command, args, context);
501
+ }
502
+
503
+ /**
504
+ * Route a message to matching adapters
505
+ */
506
+ async routeMessage(content, context) {
507
+ const responses = [];
508
+
509
+ for (const { pattern, adapterId } of this.triggerPatterns) {
510
+ if (pattern.test(content)) {
511
+ const adapter = this.adapters.get(adapterId);
512
+ if (adapter) {
513
+ const response = await adapter.handleMessage({ ...context, content });
514
+ if (response) {
515
+ responses.push(response);
516
+ }
517
+ }
518
+ }
519
+ }
520
+
521
+ return responses;
522
+ }
523
+
524
+ /**
525
+ * List all registered adapters
526
+ */
527
+ list() {
528
+ return Array.from(this.adapters.values()).map(a => a.manifest.toJSON());
529
+ }
530
+ }
531
+
532
+ export default ChatModAdapter;