@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,240 @@
1
+ /**
2
+ * FormationController — Production Tests
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { FormationController } from '../FormationController';
6
+ import { Vector3 } from '../Vector3';
7
+
8
+ function make(cfg = {}) {
9
+ return new FormationController(cfg);
10
+ }
11
+ function v(x: number, y = 0, z = 0) {
12
+ return new Vector3(x, y, z);
13
+ }
14
+
15
+ describe('FormationController — defaults', () => {
16
+ it('constructs without args', () => expect(() => make()).not.toThrow());
17
+ it('default type=line', () => expect(make().getConfig().type).toBe('line'));
18
+ it('default spacing=2', () => expect(make().getConfig().spacing).toBe(2));
19
+ it('default scale=1', () => expect(make().getConfig().scale).toBe(1));
20
+ });
21
+
22
+ describe('FormationController — line formation', () => {
23
+ it('generates correct slot count', () => {
24
+ expect(make({ type: 'line' }).generateSlots(5)).toHaveLength(5);
25
+ });
26
+ it('slot[0] is leader', () => {
27
+ expect(make({ type: 'line' }).generateSlots(3)[0].isLeaderSlot).toBe(true);
28
+ });
29
+ it('positions centered at spacing=2', () => {
30
+ const slots = make({ type: 'line', spacing: 2 }).generateSlots(3);
31
+ expect(slots[0].localPosition.x).toBeCloseTo(-2, 5);
32
+ expect(slots[1].localPosition.x).toBeCloseTo(0, 5);
33
+ expect(slots[2].localPosition.x).toBeCloseTo(2, 5);
34
+ });
35
+ it('single slot at origin', () => {
36
+ expect(make({ type: 'line', spacing: 2 }).generateSlots(1)[0].localPosition.x).toBe(0);
37
+ });
38
+ });
39
+
40
+ describe('FormationController — circle formation', () => {
41
+ it('generates correct count', () => {
42
+ expect(make({ type: 'circle' }).generateSlots(6)).toHaveLength(6);
43
+ });
44
+ it('all slots equidistant from center', () => {
45
+ const slots = make({ type: 'circle', spacing: 3 }).generateSlots(8);
46
+ const r = slots[0].localPosition.magnitude();
47
+ for (const s of slots) expect(s.localPosition.magnitude()).toBeCloseTo(r, 3);
48
+ });
49
+ it('y=0 for all slots', () => {
50
+ for (const s of make({ type: 'circle' }).generateSlots(6)) expect(s.localPosition.y).toBe(0);
51
+ });
52
+ });
53
+
54
+ describe('FormationController — grid formation', () => {
55
+ it('generates correct count', () => {
56
+ expect(make({ type: 'grid' }).generateSlots(9)).toHaveLength(9);
57
+ });
58
+ it('y=0 for all slots', () => {
59
+ for (const s of make({ type: 'grid' }).generateSlots(4)) expect(s.localPosition.y).toBe(0);
60
+ });
61
+ });
62
+
63
+ describe('FormationController — wedge formation', () => {
64
+ it('generates correct count', () => {
65
+ expect(make({ type: 'wedge' }).generateSlots(5)).toHaveLength(5);
66
+ });
67
+ it('leader at z=0', () => {
68
+ expect(make({ type: 'wedge' }).generateSlots(5)[0].localPosition.z).toBe(0);
69
+ });
70
+ });
71
+
72
+ describe('FormationController — sphere formation', () => {
73
+ it('generates correct count', () => {
74
+ expect(make({ type: 'sphere' }).generateSlots(10)).toHaveLength(10);
75
+ });
76
+ it('positions unique', () => {
77
+ const slots = make({ type: 'sphere' }).generateSlots(20);
78
+ const keys = slots.map(
79
+ (s) =>
80
+ `${s.localPosition.x.toFixed(2)},${s.localPosition.y.toFixed(2)},${s.localPosition.z.toFixed(2)}`
81
+ );
82
+ expect(new Set(keys).size).toBe(20);
83
+ });
84
+ });
85
+
86
+ describe('FormationController — diamond formation', () => {
87
+ it('generates correct count', () => {
88
+ expect(make({ type: 'diamond' }).generateSlots(7)).toHaveLength(7);
89
+ });
90
+ });
91
+
92
+ describe('FormationController — custom formation', () => {
93
+ it('creates slots from positions', () => {
94
+ const f = make();
95
+ f.setCustomFormation([v(0), v(5), v(10)]);
96
+ expect(f.getAllSlots()).toHaveLength(3);
97
+ });
98
+ it('type becomes custom', () => {
99
+ const f = make({ type: 'line' });
100
+ f.setCustomFormation([v(0)]);
101
+ expect(f.getConfig().type).toBe('custom');
102
+ });
103
+ });
104
+
105
+ describe('FormationController — assignAgent / removeAgent', () => {
106
+ it('first agent gets slot 0', () => {
107
+ const f = make({ type: 'line' });
108
+ f.generateSlots(3);
109
+ expect(f.assignAgent('a1')).toBe(0);
110
+ });
111
+ it('sequential agents get sequential slots', () => {
112
+ const f = make({ type: 'line' });
113
+ f.generateSlots(3);
114
+ expect(f.assignAgent('a1')).toBe(0);
115
+ expect(f.assignAgent('a2')).toBe(1);
116
+ });
117
+ it('assignAgent to specific slot', () => {
118
+ const f = make({ type: 'line' });
119
+ f.generateSlots(3);
120
+ expect(f.assignAgent('a1', 2)).toBe(2);
121
+ });
122
+ it('returns -1 when full', () => {
123
+ const f = make({ type: 'line' });
124
+ f.generateSlots(2);
125
+ f.assignAgent('a1');
126
+ f.assignAgent('a2');
127
+ expect(f.assignAgent('a3')).toBe(-1);
128
+ });
129
+ it('removeAgent frees slot', () => {
130
+ const f = make({ type: 'line' });
131
+ f.generateSlots(2);
132
+ f.assignAgent('a1');
133
+ expect(f.removeAgent('a1')).toBe(true);
134
+ expect(f.getAvailableSlots()).toHaveLength(2);
135
+ });
136
+ it('removeAgent unknown returns false', () => {
137
+ const f = make({ type: 'line' });
138
+ f.generateSlots(2);
139
+ expect(f.removeAgent('ghost')).toBe(false);
140
+ });
141
+ it('getAgentSlot returns assigned slot', () => {
142
+ const f = make({ type: 'line' });
143
+ f.generateSlots(3);
144
+ f.assignAgent('a1', 1);
145
+ expect(f.getAgentSlot('a1')?.index).toBe(1);
146
+ });
147
+ it('getAgentTarget returns world position', () => {
148
+ const f = make({ type: 'line' });
149
+ f.generateSlots(3);
150
+ f.assignAgent('a1');
151
+ expect(f.getAgentTarget('a1')).toBeDefined();
152
+ });
153
+ });
154
+
155
+ describe('FormationController — completeness', () => {
156
+ it('isComplete=false when slots available', () => {
157
+ const f = make({ type: 'line' });
158
+ f.generateSlots(2);
159
+ expect(f.isComplete()).toBe(false);
160
+ });
161
+ it('isComplete=true when all filled', () => {
162
+ const f = make({ type: 'line' });
163
+ f.generateSlots(2);
164
+ f.assignAgent('a1');
165
+ f.assignAgent('a2');
166
+ expect(f.isComplete()).toBe(true);
167
+ });
168
+ it('ratio = assigned/total', () => {
169
+ const f = make({ type: 'line' });
170
+ f.generateSlots(4);
171
+ f.assignAgent('a1');
172
+ f.assignAgent('a2');
173
+ expect(f.getCompletenessRatio()).toBeCloseTo(0.5, 5);
174
+ });
175
+ });
176
+
177
+ describe('FormationController — setCenter/setRotation/tightness', () => {
178
+ it('setCenter offsets world positions', () => {
179
+ const f = make({ type: 'line', spacing: 2 });
180
+ f.generateSlots(3);
181
+ f.setCenter(v(100, 0, 0));
182
+ expect(f.getAllSlots()[1].worldPosition.x).toBeCloseTo(100, 5);
183
+ });
184
+ it('setRotation changes world positions', () => {
185
+ const f = make({ type: 'line', spacing: 2 });
186
+ f.generateSlots(3);
187
+ const before = f.getAllSlots()[2].worldPosition.x;
188
+ f.setRotation(Math.PI / 2);
189
+ expect(f.getAllSlots()[2].worldPosition.x).not.toBeCloseTo(before, 1);
190
+ });
191
+ it('getCenter returns set value', () => {
192
+ const f = make({ type: 'line' });
193
+ f.generateSlots(1);
194
+ f.setCenter(v(7, 0, 0));
195
+ expect(f.getCenter().x).toBe(7);
196
+ });
197
+ it('tightness=1 when agents exactly on target', () => {
198
+ const f = make({ type: 'line', spacing: 2 });
199
+ f.generateSlots(2);
200
+ f.assignAgent('a1', 0);
201
+ f.assignAgent('a2', 1);
202
+ const pos = new Map<string, Vector3>([
203
+ ['a1', f.getAgentTarget('a1')!],
204
+ ['a2', f.getAgentTarget('a2')!],
205
+ ]);
206
+ expect(f.getFormationTightness(pos)).toBeCloseTo(1, 5);
207
+ });
208
+ it('tightness<1 when off target', () => {
209
+ const f = make({ type: 'line', spacing: 2 });
210
+ f.generateSlots(2);
211
+ f.assignAgent('a1', 0);
212
+ const target = f.getAgentTarget('a1')!;
213
+ const pos = new Map<string, Vector3>([['a1', v(target.x + 5)]]);
214
+ expect(f.getFormationTightness(pos)).toBeLessThan(1);
215
+ });
216
+ });
217
+
218
+ describe('FormationController — optimizeAssignments', () => {
219
+ it('assigns all available agents', () => {
220
+ const f = make({ type: 'line', spacing: 2 });
221
+ f.generateSlots(2);
222
+ const slots = f.getAllSlots();
223
+ const positions = new Map<string, Vector3>([
224
+ ['a1', v(slots[1].worldPosition.x)],
225
+ ['a2', v(slots[0].worldPosition.x)],
226
+ ]);
227
+ f.optimizeAssignments(positions);
228
+ expect(f.getAssignedSlots()).toHaveLength(2);
229
+ });
230
+ });
231
+
232
+ describe('FormationController — setConfig', () => {
233
+ it('partial update merges without overwriting others', () => {
234
+ const f = make({ spacing: 2, type: 'line' });
235
+ f.generateSlots(3);
236
+ f.setConfig({ spacing: 5 });
237
+ expect(f.getConfig().spacing).toBe(5);
238
+ expect(f.getConfig().type).toBe('line');
239
+ });
240
+ });
@@ -0,0 +1,297 @@
1
+ /**
2
+ * FormationController Tests
3
+ * HoloScript v3.2 - Autonomous Agent Swarms
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach } from 'vitest';
7
+ import { FormationController } from '../FormationController';
8
+ import { Vector3 } from '../Vector3';
9
+
10
+ describe('FormationController', () => {
11
+ let formation: FormationController;
12
+
13
+ beforeEach(() => {
14
+ formation = new FormationController({
15
+ type: 'line',
16
+ spacing: 2,
17
+ });
18
+ });
19
+
20
+ describe('slot generation', () => {
21
+ it('should generate line formation slots', () => {
22
+ const slots = formation.generateSlots(5);
23
+ expect(slots).toHaveLength(5);
24
+ expect(slots[0].isLeaderSlot).toBe(true);
25
+ });
26
+
27
+ it('should center line formation', () => {
28
+ const slots = formation.generateSlots(3);
29
+ // With spacing 2 and 3 agents: positions at -2, 0, 2
30
+ expect(slots[0].localPosition.x).toBe(-2);
31
+ expect(slots[1].localPosition.x).toBe(0);
32
+ expect(slots[2].localPosition.x).toBe(2);
33
+ });
34
+
35
+ it('should generate circle formation slots', () => {
36
+ formation.setConfig({ type: 'circle' });
37
+ const slots = formation.generateSlots(4);
38
+ expect(slots).toHaveLength(4);
39
+
40
+ // Check positions are distributed around circle
41
+ const positions = slots.map((s) => s.localPosition);
42
+ const firstAngle = Math.atan2(positions[0].z, positions[0].x);
43
+ const secondAngle = Math.atan2(positions[1].z, positions[1].x);
44
+ const angleDiff = Math.abs(secondAngle - firstAngle);
45
+ expect(angleDiff).toBeCloseTo(Math.PI / 2, 1);
46
+ });
47
+
48
+ it('should generate grid formation slots', () => {
49
+ formation.setConfig({ type: 'grid' });
50
+ const slots = formation.generateSlots(4);
51
+ expect(slots).toHaveLength(4);
52
+
53
+ // 4 agents in 2x2 grid
54
+ const positions = slots.map((s) => s.localPosition);
55
+ const uniqueX = new Set(positions.map((p) => Math.round(p.x * 100)));
56
+ const uniqueZ = new Set(positions.map((p) => Math.round(p.z * 100)));
57
+ expect(uniqueX.size).toBe(2);
58
+ expect(uniqueZ.size).toBe(2);
59
+ });
60
+
61
+ it('should generate wedge formation slots', () => {
62
+ formation.setConfig({ type: 'wedge' });
63
+ const slots = formation.generateSlots(5);
64
+ expect(slots).toHaveLength(5);
65
+
66
+ // Leader at front (0,0,0)
67
+ expect(slots[0].localPosition.x).toBe(0);
68
+ expect(slots[0].localPosition.z).toBe(0);
69
+ });
70
+
71
+ it('should generate diamond formation slots', () => {
72
+ formation.setConfig({ type: 'diamond' });
73
+ const slots = formation.generateSlots(5);
74
+ expect(slots).toHaveLength(5);
75
+ });
76
+
77
+ it('should generate sphere formation slots', () => {
78
+ formation.setConfig({ type: 'sphere' });
79
+ const slots = formation.generateSlots(10);
80
+ expect(slots).toHaveLength(10);
81
+
82
+ // Positions should be in 3D (varying y values)
83
+ const yValues = slots.map((s) => s.localPosition.y);
84
+ const minY = Math.min(...yValues);
85
+ const maxY = Math.max(...yValues);
86
+ expect(maxY - minY).toBeGreaterThan(0);
87
+ });
88
+ });
89
+
90
+ describe('custom formation', () => {
91
+ it('should set custom positions', () => {
92
+ const positions = [new Vector3(0, 0, 0), new Vector3(5, 0, 0), new Vector3(0, 5, 0)];
93
+ formation.setCustomFormation(positions);
94
+
95
+ const slots = formation.getAllSlots();
96
+ expect(slots).toHaveLength(3);
97
+ expect(slots[1].localPosition.x).toBe(5);
98
+ });
99
+ });
100
+
101
+ describe('agent assignment', () => {
102
+ beforeEach(() => {
103
+ formation.generateSlots(5);
104
+ });
105
+
106
+ it('should assign agent to first available slot', () => {
107
+ const index = formation.assignAgent('agent-1');
108
+ expect(index).toBe(0);
109
+ });
110
+
111
+ it('should assign agent to specified slot', () => {
112
+ const index = formation.assignAgent('agent-1', 3);
113
+ expect(index).toBe(3);
114
+ });
115
+
116
+ it('should track agent slot', () => {
117
+ formation.assignAgent('agent-1', 2);
118
+ const slot = formation.getAgentSlot('agent-1');
119
+ expect(slot?.index).toBe(2);
120
+ });
121
+
122
+ it('should return -1 when no slots available', () => {
123
+ for (let i = 0; i < 5; i++) {
124
+ formation.assignAgent(`agent-${i}`);
125
+ }
126
+ const index = formation.assignAgent('agent-extra');
127
+ expect(index).toBe(-1);
128
+ });
129
+
130
+ it('should remove agent from slot', () => {
131
+ formation.assignAgent('agent-1');
132
+ expect(formation.removeAgent('agent-1')).toBe(true);
133
+ expect(formation.getAgentSlot('agent-1')).toBeUndefined();
134
+ });
135
+
136
+ it('should make slot available after removal', () => {
137
+ formation.assignAgent('agent-1', 0);
138
+ formation.removeAgent('agent-1');
139
+ expect(formation.getAvailableSlots()).toHaveLength(5);
140
+ });
141
+
142
+ it('should get agent target position', () => {
143
+ formation.assignAgent('agent-1', 0);
144
+ const target = formation.getAgentTarget('agent-1');
145
+ expect(target).toBeDefined();
146
+ });
147
+ });
148
+
149
+ describe('slot queries', () => {
150
+ beforeEach(() => {
151
+ formation.generateSlots(5);
152
+ formation.assignAgent('agent-1', 0);
153
+ formation.assignAgent('agent-2', 1);
154
+ });
155
+
156
+ it('should get available slots', () => {
157
+ expect(formation.getAvailableSlots()).toHaveLength(3);
158
+ });
159
+
160
+ it('should get assigned slots', () => {
161
+ expect(formation.getAssignedSlots()).toHaveLength(2);
162
+ });
163
+ });
164
+
165
+ describe('center and rotation', () => {
166
+ it('should update world positions when center changes', () => {
167
+ formation.generateSlots(3);
168
+ formation.setCenter(new Vector3(100, 0, 0));
169
+
170
+ const slots = formation.getAllSlots();
171
+ // All world positions should be offset by 100 in x
172
+ expect(slots[1].worldPosition.x).toBe(100); // Center slot at x=0 + 100
173
+ });
174
+
175
+ it('should apply rotation', () => {
176
+ formation.generateSlots(2);
177
+ // Line along x axis
178
+ const originalX = formation.getAllSlots()[0].worldPosition.x;
179
+
180
+ formation.setRotation(Math.PI / 2); // 90 degrees
181
+
182
+ // After rotation, x offset should become z offset
183
+ const rotatedSlots = formation.getAllSlots();
184
+ expect(Math.abs(rotatedSlots[0].worldPosition.z)).toBeGreaterThan(0.1);
185
+ });
186
+
187
+ it('should get center', () => {
188
+ formation.setCenter(new Vector3(50, 50, 50));
189
+ const center = formation.getCenter();
190
+ expect(center.x).toBe(50);
191
+ });
192
+ });
193
+
194
+ describe('completeness', () => {
195
+ beforeEach(() => {
196
+ formation.generateSlots(3);
197
+ });
198
+
199
+ it('should detect incomplete formation', () => {
200
+ formation.assignAgent('agent-1');
201
+ expect(formation.isComplete()).toBe(false);
202
+ });
203
+
204
+ it('should detect complete formation', () => {
205
+ formation.assignAgent('agent-1');
206
+ formation.assignAgent('agent-2');
207
+ formation.assignAgent('agent-3');
208
+ expect(formation.isComplete()).toBe(true);
209
+ });
210
+
211
+ it('should calculate completeness ratio', () => {
212
+ formation.assignAgent('agent-1');
213
+ expect(formation.getCompletenessRatio()).toBeCloseTo(0.333, 2);
214
+ });
215
+
216
+ it('should return 0 for empty formation', () => {
217
+ formation = new FormationController();
218
+ expect(formation.getCompletenessRatio()).toBe(0);
219
+ });
220
+ });
221
+
222
+ describe('tightness', () => {
223
+ beforeEach(() => {
224
+ formation.generateSlots(3);
225
+ formation.assignAgent('agent-1', 0);
226
+ formation.assignAgent('agent-2', 1);
227
+ });
228
+
229
+ it('should calculate perfect tightness', () => {
230
+ const slots = formation.getAllSlots();
231
+ const positions = new Map([
232
+ ['agent-1', slots[0].worldPosition.clone()],
233
+ ['agent-2', slots[1].worldPosition.clone()],
234
+ ]);
235
+
236
+ const tightness = formation.getFormationTightness(positions);
237
+ expect(tightness).toBe(1);
238
+ });
239
+
240
+ it('should calculate lower tightness for spread agents', () => {
241
+ const slots = formation.getAllSlots();
242
+ const positions = new Map([
243
+ ['agent-1', slots[0].worldPosition.add(new Vector3(1, 0, 0))],
244
+ ['agent-2', slots[1].worldPosition.add(new Vector3(1, 0, 0))],
245
+ ]);
246
+
247
+ const tightness = formation.getFormationTightness(positions);
248
+ expect(tightness).toBeLessThan(1);
249
+ expect(tightness).toBeGreaterThan(0);
250
+ });
251
+
252
+ it('should return 1 for no assigned agents', () => {
253
+ formation = new FormationController();
254
+ formation.generateSlots(3);
255
+ expect(formation.getFormationTightness(new Map())).toBe(1);
256
+ });
257
+ });
258
+
259
+ describe('optimization', () => {
260
+ it('should optimize assignments to minimize distance', () => {
261
+ formation.generateSlots(3);
262
+
263
+ const positions = new Map([
264
+ ['agent-1', new Vector3(2, 0, 0)], // Closest to slot index 2
265
+ ['agent-2', new Vector3(-2, 0, 0)], // Closest to slot index 0
266
+ ['agent-3', new Vector3(0, 0, 0)], // Closest to slot index 1
267
+ ]);
268
+
269
+ formation.optimizeAssignments(positions);
270
+
271
+ const slot0 = formation.getAllSlots()[0];
272
+ const slot2 = formation.getAllSlots()[2];
273
+
274
+ // slot 0 at x=-2 should have agent-2
275
+ expect(slot0.agentId).toBe('agent-2');
276
+ // slot 2 at x=2 should have agent-1
277
+ expect(slot2.agentId).toBe('agent-1');
278
+ });
279
+ });
280
+
281
+ describe('configuration', () => {
282
+ it('should update config and regenerate slots', () => {
283
+ formation.generateSlots(3);
284
+ formation.setConfig({ spacing: 5 });
285
+
286
+ const slots = formation.getAllSlots();
287
+ // With spacing 5 and 3 agents: -5, 0, 5
288
+ expect(slots[2].localPosition.x - slots[0].localPosition.x).toBe(10);
289
+ });
290
+
291
+ it('should get current config', () => {
292
+ const config = formation.getConfig();
293
+ expect(config.type).toBe('line');
294
+ expect(config.spacing).toBe(2);
295
+ });
296
+ });
297
+ });