@holoscript/framework 6.0.3

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 (329) hide show
  1. package/ALL-test-results.json +1 -0
  2. package/CHANGELOG.md +8 -0
  3. package/LICENSE +21 -0
  4. package/ROADMAP.md +175 -0
  5. package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
  6. package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
  7. package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
  8. package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
  9. package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
  10. package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
  11. package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
  12. package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
  13. package/dist/agents/index.cjs +4790 -0
  14. package/dist/agents/index.d.cts +1788 -0
  15. package/dist/agents/index.d.ts +1788 -0
  16. package/dist/agents/index.js +4695 -0
  17. package/dist/ai/index.cjs +5347 -0
  18. package/dist/ai/index.d.cts +1753 -0
  19. package/dist/ai/index.d.ts +1753 -0
  20. package/dist/ai/index.js +5244 -0
  21. package/dist/behavior.cjs +449 -0
  22. package/dist/behavior.d.cts +130 -0
  23. package/dist/behavior.d.ts +130 -0
  24. package/dist/behavior.js +407 -0
  25. package/dist/economy/index.cjs +3659 -0
  26. package/dist/economy/index.d.cts +747 -0
  27. package/dist/economy/index.d.ts +747 -0
  28. package/dist/economy/index.js +3617 -0
  29. package/dist/implementations-D9T3un9D.d.cts +236 -0
  30. package/dist/implementations-D9T3un9D.d.ts +236 -0
  31. package/dist/index.cjs +24550 -0
  32. package/dist/index.d.cts +1729 -0
  33. package/dist/index.d.ts +1729 -0
  34. package/dist/index.js +24277 -0
  35. package/dist/learning/index.cjs +219 -0
  36. package/dist/learning/index.d.cts +104 -0
  37. package/dist/learning/index.d.ts +104 -0
  38. package/dist/learning/index.js +189 -0
  39. package/dist/negotiation/index.cjs +970 -0
  40. package/dist/negotiation/index.d.cts +610 -0
  41. package/dist/negotiation/index.d.ts +610 -0
  42. package/dist/negotiation/index.js +931 -0
  43. package/dist/skills/index.cjs +1118 -0
  44. package/dist/skills/index.d.cts +289 -0
  45. package/dist/skills/index.d.ts +289 -0
  46. package/dist/skills/index.js +1079 -0
  47. package/dist/swarm/index.cjs +5268 -0
  48. package/dist/swarm/index.d.cts +2433 -0
  49. package/dist/swarm/index.d.ts +2433 -0
  50. package/dist/swarm/index.js +5221 -0
  51. package/dist/training/index.cjs +2745 -0
  52. package/dist/training/index.d.cts +1734 -0
  53. package/dist/training/index.d.ts +1734 -0
  54. package/dist/training/index.js +2687 -0
  55. package/extract-failures.js +10 -0
  56. package/package.json +82 -0
  57. package/src/__tests__/bounty-marketplace.test.ts +374 -0
  58. package/src/__tests__/delegation.test.ts +144 -0
  59. package/src/__tests__/distributed-claimer.test.ts +147 -0
  60. package/src/__tests__/done-log-audit.test.ts +342 -0
  61. package/src/__tests__/framework.test.ts +865 -0
  62. package/src/__tests__/goal-synthesizer.test.ts +236 -0
  63. package/src/__tests__/presence.test.ts +223 -0
  64. package/src/__tests__/protocol-agent.test.ts +254 -0
  65. package/src/__tests__/revenue-splitter.test.ts +114 -0
  66. package/src/__tests__/scenario-driven-todo.test.ts +197 -0
  67. package/src/__tests__/self-improve.test.ts +349 -0
  68. package/src/__tests__/service-lifecycle.test.ts +237 -0
  69. package/src/__tests__/skill-router.test.ts +121 -0
  70. package/src/agents/AgentManifest.ts +493 -0
  71. package/src/agents/AgentRegistry.ts +475 -0
  72. package/src/agents/AgentTypes.ts +585 -0
  73. package/src/agents/AgentWalletRegistry.ts +83 -0
  74. package/src/agents/AuthenticatedCRDT.ts +388 -0
  75. package/src/agents/CapabilityMatcher.ts +453 -0
  76. package/src/agents/CrossRealityHandoff.ts +305 -0
  77. package/src/agents/CulturalMemory.ts +454 -0
  78. package/src/agents/FederatedRegistryAdapter.ts +429 -0
  79. package/src/agents/NormEngine.ts +450 -0
  80. package/src/agents/OrchestratorAgent.ts +414 -0
  81. package/src/agents/SkillWorkflowEngine.ts +472 -0
  82. package/src/agents/TaskDelegationService.ts +551 -0
  83. package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
  84. package/src/agents/__tests__/AgentManifest.test.ts +182 -0
  85. package/src/agents/__tests__/AgentModule.test.ts +864 -0
  86. package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
  87. package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
  88. package/src/agents/__tests__/AgentTypes.test.ts +534 -0
  89. package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
  90. package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
  91. package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
  92. package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
  93. package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
  94. package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
  95. package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
  96. package/src/agents/__tests__/NormEngine.test.ts +276 -0
  97. package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
  98. package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
  99. package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
  100. package/src/agents/index.ts +107 -0
  101. package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
  102. package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
  103. package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
  104. package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
  105. package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
  106. package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
  107. package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
  108. package/src/agents/spatial-comms/index.ts +66 -0
  109. package/src/ai/AIAdapter.ts +313 -0
  110. package/src/ai/AICopilot.ts +331 -0
  111. package/src/ai/AIOutputValidator.ts +203 -0
  112. package/src/ai/BTNodes.ts +239 -0
  113. package/src/ai/BehaviorSelector.ts +135 -0
  114. package/src/ai/BehaviorTree.ts +153 -0
  115. package/src/ai/Blackboard.ts +165 -0
  116. package/src/ai/GenerationAnalytics.ts +461 -0
  117. package/src/ai/GenerationCache.ts +265 -0
  118. package/src/ai/GoalPlanner.ts +165 -0
  119. package/src/ai/HoloScriptGenerator.ts +580 -0
  120. package/src/ai/InfluenceMap.ts +180 -0
  121. package/src/ai/NavMesh.ts +168 -0
  122. package/src/ai/PerceptionSystem.ts +178 -0
  123. package/src/ai/PromptTemplates.ts +453 -0
  124. package/src/ai/SemanticSearchService.ts +80 -0
  125. package/src/ai/StateMachine.ts +196 -0
  126. package/src/ai/SteeringBehavior.ts +150 -0
  127. package/src/ai/SteeringBehaviors.ts +244 -0
  128. package/src/ai/TrainingDataGenerator.ts +1082 -0
  129. package/src/ai/UtilityAI.ts +145 -0
  130. package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
  131. package/src/ai/__tests__/AIAdapter.test.ts +109 -0
  132. package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
  133. package/src/ai/__tests__/AICopilot.test.ts +178 -0
  134. package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
  135. package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
  136. package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
  137. package/src/ai/__tests__/BTNodes.test.ts +263 -0
  138. package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
  139. package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
  140. package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
  141. package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
  142. package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
  143. package/src/ai/__tests__/Blackboard.test.ts +183 -0
  144. package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
  145. package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
  146. package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
  147. package/src/ai/__tests__/GenerationCache.test.ts +171 -0
  148. package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
  149. package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
  150. package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
  151. package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
  152. package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
  153. package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
  154. package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
  155. package/src/ai/__tests__/NavMesh.test.ts +159 -0
  156. package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
  157. package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
  158. package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
  159. package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
  160. package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
  161. package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
  162. package/src/ai/__tests__/StateMachine.test.ts +163 -0
  163. package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
  164. package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
  165. package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
  166. package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
  167. package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
  168. package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
  169. package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
  170. package/src/ai/__tests__/UtilityAI.test.ts +155 -0
  171. package/src/ai/__tests__/adapters.prod.test.ts +263 -0
  172. package/src/ai/__tests__/adapters.test.ts +320 -0
  173. package/src/ai/adapters.ts +1585 -0
  174. package/src/ai/index.ts +130 -0
  175. package/src/behavior/BehaviorPresets.ts +140 -0
  176. package/src/behavior/BehaviorTree.ts +236 -0
  177. package/src/behavior/StateMachine.ts +176 -0
  178. package/src/behavior/StateTrait.ts +67 -0
  179. package/src/behavior/index.ts +8 -0
  180. package/src/behavior.ts +8 -0
  181. package/src/board/audit.ts +284 -0
  182. package/src/board/board-ops.ts +336 -0
  183. package/src/board/board-types.ts +302 -0
  184. package/src/board/index.ts +69 -0
  185. package/src/define-agent.ts +46 -0
  186. package/src/define-team.ts +33 -0
  187. package/src/delegation.ts +265 -0
  188. package/src/distributed-claimer.ts +228 -0
  189. package/src/economy/AgentBudgetEnforcer.ts +464 -0
  190. package/src/economy/BountyManager.ts +185 -0
  191. package/src/economy/CreatorRevenueAggregator.ts +460 -0
  192. package/src/economy/InvisibleWallet.ts +82 -0
  193. package/src/economy/KnowledgeMarketplace.ts +193 -0
  194. package/src/economy/PaymentWebhookService.ts +512 -0
  195. package/src/economy/RevenueSplitter.ts +156 -0
  196. package/src/economy/SubscriptionManager.ts +546 -0
  197. package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
  198. package/src/economy/UsageMeter.ts +440 -0
  199. package/src/economy/_core-stubs.ts +219 -0
  200. package/src/economy/index.ts +100 -0
  201. package/src/economy/x402-facilitator.ts +1978 -0
  202. package/src/index.ts +348 -0
  203. package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
  204. package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
  205. package/src/knowledge/brain.ts +167 -0
  206. package/src/knowledge/consolidation.ts +581 -0
  207. package/src/knowledge/knowledge-consolidator.ts +510 -0
  208. package/src/knowledge/knowledge-store.ts +616 -0
  209. package/src/learning/MemoryConsolidator.ts +102 -0
  210. package/src/learning/MemoryScorer.ts +69 -0
  211. package/src/learning/ProceduralCompiler.ts +45 -0
  212. package/src/learning/SemanticClusterer.ts +66 -0
  213. package/src/learning/index.ts +8 -0
  214. package/src/llm/llm-adapter.ts +159 -0
  215. package/src/mesh/index.ts +309 -0
  216. package/src/negotiation/NegotiationProtocol.ts +694 -0
  217. package/src/negotiation/NegotiationTypes.ts +473 -0
  218. package/src/negotiation/VotingMechanisms.ts +691 -0
  219. package/src/negotiation/index.ts +49 -0
  220. package/src/protocol/goal-synthesizer.ts +317 -0
  221. package/src/protocol/implementations.ts +474 -0
  222. package/src/protocol/micro-phase-decomposer.ts +299 -0
  223. package/src/protocol/micro-step-decomposer.test.ts +306 -0
  224. package/src/protocol-agent.test.ts +353 -0
  225. package/src/protocol-agent.ts +670 -0
  226. package/src/self-improve/absorb-scanner.ts +252 -0
  227. package/src/self-improve/evolution-engine.ts +149 -0
  228. package/src/self-improve/framework-absorber.ts +214 -0
  229. package/src/self-improve/index.ts +50 -0
  230. package/src/self-improve/prompt-optimizer.ts +212 -0
  231. package/src/self-improve/test-generator.ts +175 -0
  232. package/src/skill-router.ts +186 -0
  233. package/src/skills/index.ts +5 -0
  234. package/src/skills/skill-md-bridge.ts +1699 -0
  235. package/src/swarm/ACOEngine.ts +261 -0
  236. package/src/swarm/CollectiveIntelligence.ts +383 -0
  237. package/src/swarm/ContributionSynthesizer.ts +481 -0
  238. package/src/swarm/LeaderElection.ts +393 -0
  239. package/src/swarm/PSOEngine.ts +206 -0
  240. package/src/swarm/QuorumPolicy.ts +173 -0
  241. package/src/swarm/SwarmCoordinator.ts +335 -0
  242. package/src/swarm/SwarmManager.ts +442 -0
  243. package/src/swarm/SwarmMembership.ts +456 -0
  244. package/src/swarm/VotingRound.ts +255 -0
  245. package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
  246. package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
  247. package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
  248. package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
  249. package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
  250. package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
  251. package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
  252. package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
  253. package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
  254. package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
  255. package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
  256. package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
  257. package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
  258. package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
  259. package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
  260. package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
  261. package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
  262. package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
  263. package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
  264. package/src/swarm/__tests__/VotingRound.test.ts +174 -0
  265. package/src/swarm/analytics/SwarmInspector.ts +476 -0
  266. package/src/swarm/analytics/SwarmMetrics.ts +449 -0
  267. package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
  268. package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
  269. package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
  270. package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
  271. package/src/swarm/analytics/index.ts +7 -0
  272. package/src/swarm/index.ts +69 -0
  273. package/src/swarm/messaging/BroadcastChannel.ts +509 -0
  274. package/src/swarm/messaging/GossipProtocol.ts +565 -0
  275. package/src/swarm/messaging/SwarmEventBus.ts +443 -0
  276. package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
  277. package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
  278. package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
  279. package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
  280. package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
  281. package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
  282. package/src/swarm/messaging/index.ts +8 -0
  283. package/src/swarm/spatial/FlockingBehavior.ts +462 -0
  284. package/src/swarm/spatial/FormationController.ts +500 -0
  285. package/src/swarm/spatial/Vector3.ts +170 -0
  286. package/src/swarm/spatial/ZoneClaiming.ts +509 -0
  287. package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
  288. package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
  289. package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
  290. package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
  291. package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
  292. package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
  293. package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
  294. package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
  295. package/src/swarm/spatial/index.ts +28 -0
  296. package/src/team.ts +1245 -0
  297. package/src/training/LRScheduler.ts +377 -0
  298. package/src/training/QualityScoringPipeline.ts +139 -0
  299. package/src/training/SoftDedup.ts +461 -0
  300. package/src/training/SparsityMonitor.ts +685 -0
  301. package/src/training/SparsityMonitorTypes.ts +209 -0
  302. package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
  303. package/src/training/SpatialTrainingDataTypes.ts +216 -0
  304. package/src/training/TrainingPipelineConfig.ts +215 -0
  305. package/src/training/constants.ts +94 -0
  306. package/src/training/index.ts +138 -0
  307. package/src/training/schema.ts +147 -0
  308. package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
  309. package/src/training/scripts/generate-spatial-dataset.ts +521 -0
  310. package/src/training/training/data/novel-use-cases.jsonl +153 -0
  311. package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
  312. package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
  313. package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
  314. package/src/training/trainingmonkey/index.ts +26 -0
  315. package/src/training/trait-mappings.ts +157 -0
  316. package/src/types/core-stubs.d.ts +113 -0
  317. package/src/types.ts +304 -0
  318. package/test-output.txt +0 -0
  319. package/test-result.json +1 -0
  320. package/tsc-errors.txt +4 -0
  321. package/tsc_output.txt +0 -0
  322. package/tsconfig.json +14 -0
  323. package/tsup-learning-esm.config.ts +12 -0
  324. package/tsup.config.ts +21 -0
  325. package/typescript-errors-2.txt +0 -0
  326. package/typescript-errors.txt +22 -0
  327. package/vitest-log-utf8.txt +268 -0
  328. package/vitest-log.txt +0 -0
  329. package/vitest.config.ts +8 -0
@@ -0,0 +1,456 @@
1
+ /**
2
+ * Swarm Membership
3
+ *
4
+ * Manages agent membership in swarms with join/leave protocol.
5
+ */
6
+
7
+ import { QuorumPolicy, type QuorumConfig, type QuorumState } from './QuorumPolicy';
8
+
9
+ export interface MemberInfo {
10
+ agentId: string;
11
+ joinedAt: number;
12
+ role: 'leader' | 'member' | 'observer';
13
+ status: 'active' | 'inactive' | 'leaving';
14
+ lastHeartbeat: number;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+
18
+ export interface JoinRequest {
19
+ agentId: string;
20
+ requestedRole?: MemberInfo['role'];
21
+ metadata?: Record<string, unknown>;
22
+ }
23
+
24
+ export interface LeaveRequest {
25
+ agentId: string;
26
+ reason?: string;
27
+ graceful: boolean;
28
+ }
29
+
30
+ export interface MembershipEvent {
31
+ type: 'joined' | 'left' | 'role-changed' | 'status-changed' | 'quorum-lost' | 'quorum-gained';
32
+ agentId: string;
33
+ timestamp: number;
34
+ details?: Record<string, unknown>;
35
+ }
36
+
37
+ export interface SwarmMembershipConfig {
38
+ quorum: Partial<QuorumConfig>;
39
+ heartbeatTimeoutMs: number;
40
+ allowObservers: boolean;
41
+ maxObservers: number;
42
+ requireApprovalToJoin: boolean;
43
+ }
44
+
45
+ const DEFAULT_CONFIG: SwarmMembershipConfig = {
46
+ quorum: {},
47
+ heartbeatTimeoutMs: 30000,
48
+ allowObservers: true,
49
+ maxObservers: 10,
50
+ requireApprovalToJoin: false,
51
+ };
52
+
53
+ type MembershipEventHandler = (event: MembershipEvent) => void;
54
+
55
+ /**
56
+ * Manages membership for a single swarm
57
+ */
58
+ export class SwarmMembership {
59
+ private config: SwarmMembershipConfig;
60
+ private members: Map<string, MemberInfo> = new Map();
61
+ private quorumPolicy: QuorumPolicy;
62
+ private eventHandlers: MembershipEventHandler[] = [];
63
+ private pendingJoins: Map<string, JoinRequest> = new Map();
64
+ private leaderId: string | null = null;
65
+
66
+ constructor(config: Partial<SwarmMembershipConfig> = {}) {
67
+ this.config = { ...DEFAULT_CONFIG, ...config };
68
+ this.quorumPolicy = new QuorumPolicy(this.config.quorum);
69
+ }
70
+
71
+ /**
72
+ * Request to join the swarm
73
+ */
74
+ join(request: JoinRequest): boolean {
75
+ const { agentId, requestedRole = 'member', metadata } = request;
76
+
77
+ // Check if already a member
78
+ if (this.members.has(agentId)) {
79
+ return true; // Already joined
80
+ }
81
+
82
+ // Handle observers separately
83
+ if (requestedRole === 'observer') {
84
+ return this.addObserver(agentId, metadata);
85
+ }
86
+
87
+ // Check quorum policy
88
+ if (!this.quorumPolicy.canJoin()) {
89
+ return false;
90
+ }
91
+
92
+ // If approval required, add to pending
93
+ if (this.config.requireApprovalToJoin && this.leaderId) {
94
+ this.pendingJoins.set(agentId, request);
95
+ return false;
96
+ }
97
+
98
+ // Add member
99
+ this.addMember(agentId, requestedRole, metadata);
100
+ return true;
101
+ }
102
+
103
+ /**
104
+ * Approve a pending join request (leader only)
105
+ */
106
+ approveJoin(approverId: string, agentId: string): boolean {
107
+ if (approverId !== this.leaderId) {
108
+ return false;
109
+ }
110
+
111
+ const request = this.pendingJoins.get(agentId);
112
+ if (!request) {
113
+ return false;
114
+ }
115
+
116
+ this.pendingJoins.delete(agentId);
117
+
118
+ if (!this.quorumPolicy.canJoin()) {
119
+ return false;
120
+ }
121
+
122
+ this.addMember(agentId, request.requestedRole ?? 'member', request.metadata);
123
+ return true;
124
+ }
125
+
126
+ /**
127
+ * Leave the swarm
128
+ */
129
+ leave(request: LeaveRequest): boolean {
130
+ const { agentId, graceful } = request;
131
+
132
+ const member = this.members.get(agentId);
133
+ if (!member) {
134
+ return false;
135
+ }
136
+
137
+ // Check if leaving would break quorum
138
+ const isLeader = agentId === this.leaderId;
139
+ const activeMembers = this.getActiveMemberCount();
140
+
141
+ if (graceful && activeMembers <= 1) {
142
+ // Last member, must disband
143
+ this.removeMember(agentId, 'left');
144
+ return true;
145
+ }
146
+
147
+ if (!this.quorumPolicy.canLeave() && member.role !== 'observer') {
148
+ // Mark as leaving but don't remove yet
149
+ member.status = 'leaving';
150
+ this.emit({
151
+ type: 'status-changed',
152
+ agentId,
153
+ timestamp: Date.now(),
154
+ details: { newStatus: 'leaving' },
155
+ });
156
+ return false;
157
+ }
158
+
159
+ // Handle leader leaving
160
+ if (isLeader) {
161
+ this.electNewLeader();
162
+ }
163
+
164
+ this.removeMember(agentId, 'left');
165
+ return true;
166
+ }
167
+
168
+ /**
169
+ * Force remove a member (for leadership or timeouts)
170
+ */
171
+ removeForcefully(agentId: string, _reason: string): void {
172
+ const member = this.members.get(agentId);
173
+ if (!member) {
174
+ return;
175
+ }
176
+
177
+ if (agentId === this.leaderId) {
178
+ this.electNewLeader();
179
+ }
180
+
181
+ this.removeMember(agentId, 'left');
182
+ }
183
+
184
+ /**
185
+ * Update heartbeat for a member
186
+ */
187
+ heartbeat(agentId: string): void {
188
+ const member = this.members.get(agentId);
189
+ if (member) {
190
+ member.lastHeartbeat = Date.now();
191
+ if (member.status === 'inactive') {
192
+ member.status = 'active';
193
+ this.emit({
194
+ type: 'status-changed',
195
+ agentId,
196
+ timestamp: Date.now(),
197
+ details: { newStatus: 'active' },
198
+ });
199
+ }
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Check for timed-out members
205
+ */
206
+ checkTimeouts(): string[] {
207
+ const now = Date.now();
208
+ const timedOut: string[] = [];
209
+
210
+ for (const [agentId, member] of this.members) {
211
+ if (member.role === 'observer') continue;
212
+
213
+ if (now - member.lastHeartbeat > this.config.heartbeatTimeoutMs) {
214
+ if (member.status === 'active') {
215
+ member.status = 'inactive';
216
+ this.emit({
217
+ type: 'status-changed',
218
+ agentId,
219
+ timestamp: now,
220
+ details: { newStatus: 'inactive', reason: 'timeout' },
221
+ });
222
+ }
223
+ timedOut.push(agentId);
224
+ }
225
+ }
226
+
227
+ return timedOut;
228
+ }
229
+
230
+ /**
231
+ * Change a member's role
232
+ */
233
+ changeRole(agentId: string, newRole: MemberInfo['role']): boolean {
234
+ const member = this.members.get(agentId);
235
+ if (!member) {
236
+ return false;
237
+ }
238
+
239
+ const oldRole = member.role;
240
+ member.role = newRole;
241
+
242
+ if (newRole === 'leader') {
243
+ if (this.leaderId && this.leaderId !== agentId) {
244
+ const oldLeader = this.members.get(this.leaderId);
245
+ if (oldLeader) {
246
+ oldLeader.role = 'member';
247
+ this.emit({
248
+ type: 'role-changed',
249
+ agentId: this.leaderId,
250
+ timestamp: Date.now(),
251
+ details: { oldRole: 'leader', newRole: 'member' },
252
+ });
253
+ }
254
+ }
255
+ this.leaderId = agentId;
256
+ }
257
+
258
+ this.emit({
259
+ type: 'role-changed',
260
+ agentId,
261
+ timestamp: Date.now(),
262
+ details: { oldRole, newRole },
263
+ });
264
+
265
+ return true;
266
+ }
267
+
268
+ /**
269
+ * Get member by ID
270
+ */
271
+ getMember(agentId: string): MemberInfo | undefined {
272
+ return this.members.get(agentId);
273
+ }
274
+
275
+ /**
276
+ * Get all members
277
+ */
278
+ getMembers(): MemberInfo[] {
279
+ return [...this.members.values()];
280
+ }
281
+
282
+ /**
283
+ * Get active members (non-observers)
284
+ */
285
+ getActiveMembers(): MemberInfo[] {
286
+ return this.getMembers().filter((m) => m.role !== 'observer' && m.status === 'active');
287
+ }
288
+
289
+ /**
290
+ * Get the current leader
291
+ */
292
+ getLeader(): MemberInfo | undefined {
293
+ return this.leaderId ? this.members.get(this.leaderId) : undefined;
294
+ }
295
+
296
+ /**
297
+ * Get quorum state
298
+ */
299
+ getQuorumState(): QuorumState {
300
+ return this.quorumPolicy.getState();
301
+ }
302
+
303
+ /**
304
+ * Get member count
305
+ */
306
+ getMemberCount(): number {
307
+ return [...this.members.values()].filter((m) => m.role !== 'observer').length;
308
+ }
309
+
310
+ /**
311
+ * Subscribe to membership events
312
+ */
313
+ onEvent(handler: MembershipEventHandler): () => void {
314
+ this.eventHandlers.push(handler);
315
+ return () => {
316
+ const index = this.eventHandlers.indexOf(handler);
317
+ if (index !== -1) {
318
+ this.eventHandlers.splice(index, 1);
319
+ }
320
+ };
321
+ }
322
+
323
+ /**
324
+ * Get pending join requests
325
+ */
326
+ getPendingJoins(): JoinRequest[] {
327
+ return [...this.pendingJoins.values()];
328
+ }
329
+
330
+ private addMember(
331
+ agentId: string,
332
+ role: MemberInfo['role'],
333
+ metadata?: Record<string, unknown>
334
+ ): void {
335
+ const now = Date.now();
336
+ const hadQuorum = this.quorumPolicy.hasQuorum();
337
+
338
+ this.members.set(agentId, {
339
+ agentId,
340
+ joinedAt: now,
341
+ role,
342
+ status: 'active',
343
+ lastHeartbeat: now,
344
+ metadata,
345
+ });
346
+
347
+ // Update quorum
348
+ this.quorumPolicy.setMemberCount(this.getMemberCount());
349
+
350
+ // Set leader if first member
351
+ if (!this.leaderId && role !== 'observer') {
352
+ this.leaderId = agentId;
353
+ this.members.get(agentId)!.role = 'leader';
354
+ }
355
+
356
+ this.emit({
357
+ type: 'joined',
358
+ agentId,
359
+ timestamp: now,
360
+ details: { role },
361
+ });
362
+
363
+ // Check quorum gain
364
+ if (!hadQuorum && this.quorumPolicy.hasQuorum()) {
365
+ this.emit({
366
+ type: 'quorum-gained',
367
+ agentId,
368
+ timestamp: now,
369
+ });
370
+ }
371
+ }
372
+
373
+ private addObserver(agentId: string, metadata?: Record<string, unknown>): boolean {
374
+ if (!this.config.allowObservers) {
375
+ return false;
376
+ }
377
+
378
+ const observerCount = [...this.members.values()].filter((m) => m.role === 'observer').length;
379
+ if (observerCount >= this.config.maxObservers) {
380
+ return false;
381
+ }
382
+
383
+ const now = Date.now();
384
+ this.members.set(agentId, {
385
+ agentId,
386
+ joinedAt: now,
387
+ role: 'observer',
388
+ status: 'active',
389
+ lastHeartbeat: now,
390
+ metadata,
391
+ });
392
+
393
+ this.emit({
394
+ type: 'joined',
395
+ agentId,
396
+ timestamp: now,
397
+ details: { role: 'observer' },
398
+ });
399
+
400
+ return true;
401
+ }
402
+
403
+ private removeMember(agentId: string, type: 'left'): void {
404
+ const hadQuorum = this.quorumPolicy.hasQuorum();
405
+
406
+ this.members.delete(agentId);
407
+ this.quorumPolicy.setMemberCount(this.getMemberCount());
408
+
409
+ if (agentId === this.leaderId) {
410
+ this.leaderId = null;
411
+ }
412
+
413
+ this.emit({
414
+ type,
415
+ agentId,
416
+ timestamp: Date.now(),
417
+ });
418
+
419
+ // Check quorum loss
420
+ if (hadQuorum && !this.quorumPolicy.hasQuorum()) {
421
+ this.emit({
422
+ type: 'quorum-lost',
423
+ agentId,
424
+ timestamp: Date.now(),
425
+ });
426
+ }
427
+ }
428
+
429
+ private electNewLeader(): void {
430
+ const candidates = this.getActiveMembers().filter((m) => m.agentId !== this.leaderId);
431
+ if (candidates.length === 0) {
432
+ this.leaderId = null;
433
+ return;
434
+ }
435
+
436
+ // Select oldest active member
437
+ candidates.sort((a, b) => a.joinedAt - b.joinedAt);
438
+ const newLeader = candidates[0];
439
+ this.changeRole(newLeader.agentId, 'leader');
440
+ }
441
+
442
+ private getActiveMemberCount(): number {
443
+ return [...this.members.values()].filter((m) => m.role !== 'observer' && m.status === 'active')
444
+ .length;
445
+ }
446
+
447
+ private emit(event: MembershipEvent): void {
448
+ for (const handler of this.eventHandlers) {
449
+ try {
450
+ handler(event);
451
+ } catch {
452
+ // Ignore handler errors
453
+ }
454
+ }
455
+ }
456
+ }
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Voting Round
3
+ *
4
+ * Manages voting on contributions in collective intelligence sessions.
5
+ */
6
+
7
+ import type { IHiveContribution } from '@holoscript/core';
8
+
9
+ export interface Vote {
10
+ contributionId: string;
11
+ voterId: string;
12
+ vote: 'support' | 'oppose';
13
+ weight: number;
14
+ timestamp: number;
15
+ }
16
+
17
+ export interface VotingResult {
18
+ contributionId: string;
19
+ supportVotes: number;
20
+ opposeVotes: number;
21
+ netScore: number;
22
+ weightedScore: number;
23
+ voterIds: string[];
24
+ }
25
+
26
+ export interface VotingRoundConfig {
27
+ minVotesRequired: number;
28
+ superMajorityThreshold: number; // 0-1, e.g., 0.67 for 2/3 majority
29
+ allowAbstain: boolean;
30
+ weightByConfidence: boolean;
31
+ }
32
+
33
+ const DEFAULT_CONFIG: VotingRoundConfig = {
34
+ minVotesRequired: 2,
35
+ superMajorityThreshold: 0.5,
36
+ allowAbstain: true,
37
+ weightByConfidence: true,
38
+ };
39
+
40
+ /**
41
+ * Manages voting on a set of contributions
42
+ */
43
+ export class VotingRound {
44
+ private config: VotingRoundConfig;
45
+ private votes: Map<string, Vote[]> = new Map(); // contributionId -> votes
46
+ private contributions: Map<string, IHiveContribution> = new Map();
47
+ private closed = false;
48
+
49
+ constructor(config: Partial<VotingRoundConfig> = {}) {
50
+ this.config = { ...DEFAULT_CONFIG, ...config };
51
+ }
52
+
53
+ /**
54
+ * Register a contribution for voting
55
+ */
56
+ registerContribution(contribution: IHiveContribution): void {
57
+ if (this.closed) {
58
+ throw new Error('Voting round is closed');
59
+ }
60
+ this.contributions.set(contribution.id, contribution);
61
+ this.votes.set(contribution.id, []);
62
+ }
63
+
64
+ /**
65
+ * Cast a vote on a contribution
66
+ */
67
+ castVote(
68
+ contributionId: string,
69
+ voterId: string,
70
+ vote: 'support' | 'oppose',
71
+ voterConfidence?: number
72
+ ): void {
73
+ if (this.closed) {
74
+ throw new Error('Voting round is closed');
75
+ }
76
+
77
+ if (!this.contributions.has(contributionId)) {
78
+ throw new Error(`Contribution ${contributionId} not registered`);
79
+ }
80
+
81
+ const existingVotes = this.votes.get(contributionId) ?? [];
82
+
83
+ // Check for duplicate vote
84
+ if (existingVotes.some((v) => v.voterId === voterId)) {
85
+ throw new Error(`${voterId} has already voted on ${contributionId}`);
86
+ }
87
+
88
+ // Calculate weight
89
+ let weight = 1;
90
+ if (this.config.weightByConfidence && voterConfidence !== undefined) {
91
+ weight = voterConfidence;
92
+ }
93
+
94
+ existingVotes.push({
95
+ contributionId,
96
+ voterId,
97
+ vote,
98
+ weight,
99
+ timestamp: Date.now(),
100
+ });
101
+
102
+ this.votes.set(contributionId, existingVotes);
103
+ }
104
+
105
+ /**
106
+ * Get current results for a contribution
107
+ */
108
+ getResult(contributionId: string): VotingResult | undefined {
109
+ const votes = this.votes.get(contributionId);
110
+ if (!votes) {
111
+ return undefined;
112
+ }
113
+
114
+ let supportVotes = 0;
115
+ let opposeVotes = 0;
116
+ let weightedSupport = 0;
117
+ let weightedOppose = 0;
118
+
119
+ for (const vote of votes) {
120
+ if (vote.vote === 'support') {
121
+ supportVotes++;
122
+ weightedSupport += vote.weight;
123
+ } else {
124
+ opposeVotes++;
125
+ weightedOppose += vote.weight;
126
+ }
127
+ }
128
+
129
+ return {
130
+ contributionId,
131
+ supportVotes,
132
+ opposeVotes,
133
+ netScore: supportVotes - opposeVotes,
134
+ weightedScore: weightedSupport - weightedOppose,
135
+ voterIds: votes.map((v) => v.voterId),
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Get all results, ranked by score
141
+ */
142
+ getAllResults(): VotingResult[] {
143
+ const results: VotingResult[] = [];
144
+
145
+ for (const contributionId of this.contributions.keys()) {
146
+ const result = this.getResult(contributionId);
147
+ if (result) {
148
+ results.push(result);
149
+ }
150
+ }
151
+
152
+ // Sort by weighted score, then by raw vote count
153
+ return results.sort((a, b) => {
154
+ if (b.weightedScore !== a.weightedScore) {
155
+ return b.weightedScore - a.weightedScore;
156
+ }
157
+ return b.netScore - a.netScore;
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Check if a contribution has reached super-majority
163
+ */
164
+ hasSuperMajority(contributionId: string): boolean {
165
+ const result = this.getResult(contributionId);
166
+ if (!result) {
167
+ return false;
168
+ }
169
+
170
+ const totalVotes = result.supportVotes + result.opposeVotes;
171
+ if (totalVotes < this.config.minVotesRequired) {
172
+ return false;
173
+ }
174
+
175
+ const supportRatio = result.supportVotes / totalVotes;
176
+ return supportRatio >= this.config.superMajorityThreshold;
177
+ }
178
+
179
+ /**
180
+ * Get contributions that have reached super-majority
181
+ */
182
+ getApprovedContributions(): IHiveContribution[] {
183
+ const approved: IHiveContribution[] = [];
184
+
185
+ for (const [contributionId, contribution] of this.contributions) {
186
+ if (this.hasSuperMajority(contributionId)) {
187
+ approved.push(contribution);
188
+ }
189
+ }
190
+
191
+ return approved;
192
+ }
193
+
194
+ /**
195
+ * Get the top-ranked contribution
196
+ */
197
+ getWinner(): IHiveContribution | undefined {
198
+ const results = this.getAllResults();
199
+ if (results.length === 0) {
200
+ return undefined;
201
+ }
202
+
203
+ const winnerId = results[0].contributionId;
204
+ return this.contributions.get(winnerId);
205
+ }
206
+
207
+ /**
208
+ * Close the voting round
209
+ */
210
+ close(): void {
211
+ this.closed = true;
212
+ }
213
+
214
+ /**
215
+ * Check if voting is closed
216
+ */
217
+ isClosed(): boolean {
218
+ return this.closed;
219
+ }
220
+
221
+ /**
222
+ * Get voting statistics
223
+ */
224
+ getStatistics(): {
225
+ totalContributions: number;
226
+ totalVotes: number;
227
+ participationRate: number;
228
+ hasConsensus: boolean;
229
+ } {
230
+ let totalVotes = 0;
231
+ for (const votes of this.votes.values()) {
232
+ totalVotes += votes.length;
233
+ }
234
+
235
+ const voterSet = new Set<string>();
236
+ for (const votes of this.votes.values()) {
237
+ for (const vote of votes) {
238
+ voterSet.add(vote.voterId);
239
+ }
240
+ }
241
+
242
+ const results = this.getAllResults();
243
+ const hasConsensus = results.length > 0 && this.hasSuperMajority(results[0].contributionId);
244
+
245
+ return {
246
+ totalContributions: this.contributions.size,
247
+ totalVotes,
248
+ participationRate:
249
+ this.contributions.size > 0
250
+ ? totalVotes / (this.contributions.size * voterSet.size || 1)
251
+ : 0,
252
+ hasConsensus,
253
+ };
254
+ }
255
+ }