@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,391 @@
1
+ /**
2
+ * BTNodes.prod.test.ts — Sprint CLXX
3
+ *
4
+ * Production tests for all behavior-tree node types exported from BTNodes.ts.
5
+ *
6
+ * Node types:
7
+ * Composite: SequenceNode, SelectorNode, ParallelNode
8
+ * Decorator: InverterNode, RepeaterNode, GuardNode
9
+ * Leaf: ActionNode, ConditionNode, WaitNode
10
+ *
11
+ * BTStatus: 'success' | 'failure' | 'running' | 'ready'
12
+ * BTContext: { blackboard: { get, set }, deltaTime: number, entity: string }
13
+ */
14
+
15
+ import { describe, it, expect } from 'vitest';
16
+ import {
17
+ SequenceNode,
18
+ SelectorNode,
19
+ ParallelNode,
20
+ InverterNode,
21
+ RepeaterNode,
22
+ GuardNode,
23
+ ActionNode,
24
+ ConditionNode,
25
+ WaitNode,
26
+ } from '../BTNodes';
27
+ import type { BTContext, BTStatus } from '../BTNodes';
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Helpers
31
+ // ---------------------------------------------------------------------------
32
+
33
+ const store: Record<string, unknown> = {};
34
+
35
+ function makeCtx(deltaTime = 0.016, entity = 'agent'): BTContext {
36
+ const bb = new Map<string, unknown>();
37
+ return {
38
+ blackboard: {
39
+ get: (k: string) => bb.get(k),
40
+ set: (k: string, v: unknown) => {
41
+ bb.set(k, v);
42
+ },
43
+ },
44
+ deltaTime,
45
+ entity,
46
+ };
47
+ }
48
+
49
+ function always(status: BTStatus) {
50
+ return new ActionNode(`always-${status}`, () => status);
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // ActionNode
55
+ // ---------------------------------------------------------------------------
56
+
57
+ describe('ActionNode', () => {
58
+ it('returns the status from the action callback', () => {
59
+ const node = always('success');
60
+ expect(node.tick(makeCtx())).toBe('success');
61
+ });
62
+
63
+ it('can return failure', () => {
64
+ expect(always('failure').tick(makeCtx())).toBe('failure');
65
+ });
66
+
67
+ it('can return running', () => {
68
+ expect(always('running').tick(makeCtx())).toBe('running');
69
+ });
70
+
71
+ it('stores returned status in node.status', () => {
72
+ const n = always('success');
73
+ n.tick(makeCtx());
74
+ expect(n.status).toBe('success');
75
+ });
76
+
77
+ it('context is passed to the action', () => {
78
+ let received: BTContext | null = null;
79
+ const n = new ActionNode('spy', (ctx) => {
80
+ received = ctx;
81
+ return 'success';
82
+ });
83
+ const ctx = makeCtx();
84
+ n.tick(ctx);
85
+ expect(received).toBe(ctx);
86
+ });
87
+ });
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // ConditionNode
91
+ // ---------------------------------------------------------------------------
92
+
93
+ describe('ConditionNode', () => {
94
+ it('returns success when condition is true', () => {
95
+ const n = new ConditionNode('cond', () => true);
96
+ expect(n.tick(makeCtx())).toBe('success');
97
+ });
98
+
99
+ it('returns failure when condition is false', () => {
100
+ const n = new ConditionNode('cond', () => false);
101
+ expect(n.tick(makeCtx())).toBe('failure');
102
+ });
103
+
104
+ it('condition receives context', () => {
105
+ let got: BTContext | null = null;
106
+ const n = new ConditionNode('spy', (ctx) => {
107
+ got = ctx;
108
+ return true;
109
+ });
110
+ const ctx = makeCtx();
111
+ n.tick(ctx);
112
+ expect(got).toBe(ctx);
113
+ });
114
+ });
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // WaitNode
118
+ // ---------------------------------------------------------------------------
119
+
120
+ describe('WaitNode', () => {
121
+ it('returns running before duration elapsed', () => {
122
+ const n = new WaitNode('wait', 2); // 2-second wait
123
+ expect(n.tick(makeCtx(0.5))).toBe('running');
124
+ });
125
+
126
+ it('returns success once duration elapsed', () => {
127
+ const n = new WaitNode('wait', 0.5);
128
+ n.tick(makeCtx(0.3));
129
+ expect(n.tick(makeCtx(0.3))).toBe('success');
130
+ });
131
+
132
+ it('resets elapsed on success so next tick restarts', () => {
133
+ const n = new WaitNode('wait', 0.5);
134
+ n.tick(makeCtx(0.5)); // success, elapsed reset
135
+ expect(n.tick(makeCtx(0.1))).toBe('running'); // not done yet
136
+ });
137
+
138
+ it('reset() resets elapsed', () => {
139
+ const n = new WaitNode('wait', 0.5);
140
+ n.tick(makeCtx(0.4)); // almost done
141
+ n.reset();
142
+ expect(n.tick(makeCtx(0.2))).toBe('running'); // restarted
143
+ });
144
+ });
145
+
146
+ // ---------------------------------------------------------------------------
147
+ // SequenceNode
148
+ // ---------------------------------------------------------------------------
149
+
150
+ describe('SequenceNode', () => {
151
+ it('returns success when all children succeed', () => {
152
+ const n = new SequenceNode('seq', [always('success'), always('success')]);
153
+ expect(n.tick(makeCtx())).toBe('success');
154
+ });
155
+
156
+ it('returns failure on first failing child', () => {
157
+ const n = new SequenceNode('seq', [always('success'), always('failure'), always('success')]);
158
+ expect(n.tick(makeCtx())).toBe('failure');
159
+ });
160
+
161
+ it('returns running when a child is running', () => {
162
+ const n = new SequenceNode('seq', [always('success'), always('running'), always('success')]);
163
+ expect(n.tick(makeCtx())).toBe('running');
164
+ });
165
+
166
+ it('short-circuits after failure (later children not ticked)', () => {
167
+ let thirdCalled = false;
168
+ const n = new SequenceNode('seq', [
169
+ always('failure'),
170
+ new ActionNode('spy', () => {
171
+ thirdCalled = true;
172
+ return 'success';
173
+ }),
174
+ ]);
175
+ n.tick(makeCtx());
176
+ expect(thirdCalled).toBe(false);
177
+ });
178
+
179
+ it('reset() clears currentIndex', () => {
180
+ const n = new SequenceNode('seq', [always('running'), always('success')]);
181
+ n.tick(makeCtx()); // paused at first
182
+ n.reset();
183
+ // After reset, starts fresh — first child is 'running' again
184
+ expect(n.tick(makeCtx())).toBe('running');
185
+ });
186
+
187
+ it('empty sequence returns success', () => {
188
+ const n = new SequenceNode('seq', []);
189
+ expect(n.tick(makeCtx())).toBe('success');
190
+ });
191
+ });
192
+
193
+ // ---------------------------------------------------------------------------
194
+ // SelectorNode
195
+ // ---------------------------------------------------------------------------
196
+
197
+ describe('SelectorNode', () => {
198
+ it('returns success on first successful child', () => {
199
+ const n = new SelectorNode('sel', [always('failure'), always('success')]);
200
+ expect(n.tick(makeCtx())).toBe('success');
201
+ });
202
+
203
+ it('returns failure when all children fail', () => {
204
+ const n = new SelectorNode('sel', [always('failure'), always('failure')]);
205
+ expect(n.tick(makeCtx())).toBe('failure');
206
+ });
207
+
208
+ it('returns running when a child is running', () => {
209
+ const n = new SelectorNode('sel', [always('failure'), always('running')]);
210
+ expect(n.tick(makeCtx())).toBe('running');
211
+ });
212
+
213
+ it('short-circuits after success (later children not ticked)', () => {
214
+ let laterCalled = false;
215
+ const n = new SelectorNode('sel', [
216
+ always('success'),
217
+ new ActionNode('spy', () => {
218
+ laterCalled = true;
219
+ return 'success';
220
+ }),
221
+ ]);
222
+ n.tick(makeCtx());
223
+ expect(laterCalled).toBe(false);
224
+ });
225
+
226
+ it('empty selector returns failure', () => {
227
+ const n = new SelectorNode('sel', []);
228
+ expect(n.tick(makeCtx())).toBe('failure');
229
+ });
230
+ });
231
+
232
+ // ---------------------------------------------------------------------------
233
+ // ParallelNode
234
+ // ---------------------------------------------------------------------------
235
+
236
+ describe('ParallelNode', () => {
237
+ it('returns success when all children succeed (all required)', () => {
238
+ const n = new ParallelNode('par', [always('success'), always('success')]);
239
+ expect(n.tick(makeCtx())).toBe('success');
240
+ });
241
+
242
+ it('returns running if not enough successes yet', () => {
243
+ const n = new ParallelNode('par', [always('running'), always('running')]);
244
+ expect(n.tick(makeCtx())).toBe('running');
245
+ });
246
+
247
+ it('partial-success threshold: 1 of 2 sufficient', () => {
248
+ const n = new ParallelNode('par', [always('success'), always('failure')], 1);
249
+ expect(n.tick(makeCtx())).toBe('success');
250
+ });
251
+
252
+ it('returns failure when too many children fail', () => {
253
+ // requiredSuccesses = 2, but all 2 fail → failures > (2 - 2) = 0
254
+ const n = new ParallelNode('par', [always('failure'), always('failure')], 2);
255
+ expect(n.tick(makeCtx())).toBe('failure');
256
+ });
257
+
258
+ it('ticks ALL children regardless of results', () => {
259
+ let count = 0;
260
+ const n = new ParallelNode('par', [
261
+ new ActionNode('a', () => {
262
+ count++;
263
+ return 'success';
264
+ }),
265
+ new ActionNode('b', () => {
266
+ count++;
267
+ return 'failure';
268
+ }),
269
+ ]);
270
+ n.tick(makeCtx());
271
+ expect(count).toBe(2);
272
+ });
273
+ });
274
+
275
+ // ---------------------------------------------------------------------------
276
+ // InverterNode
277
+ // ---------------------------------------------------------------------------
278
+
279
+ describe('InverterNode', () => {
280
+ it('inverts success to failure', () => {
281
+ const n = new InverterNode('inv', always('success'));
282
+ expect(n.tick(makeCtx())).toBe('failure');
283
+ });
284
+
285
+ it('inverts failure to success', () => {
286
+ const n = new InverterNode('inv', always('failure'));
287
+ expect(n.tick(makeCtx())).toBe('success');
288
+ });
289
+
290
+ it('passes through running unchanged', () => {
291
+ const n = new InverterNode('inv', always('running'));
292
+ expect(n.tick(makeCtx())).toBe('running');
293
+ });
294
+ });
295
+
296
+ // ---------------------------------------------------------------------------
297
+ // RepeaterNode
298
+ // ---------------------------------------------------------------------------
299
+
300
+ describe('RepeaterNode', () => {
301
+ it('repeats the child and returns running until done', () => {
302
+ const n = new RepeaterNode('rep', always('success'), 3);
303
+ expect(n.tick(makeCtx())).toBe('running'); // 1/3
304
+ expect(n.tick(makeCtx())).toBe('running'); // 2/3
305
+ expect(n.tick(makeCtx())).toBe('success'); // 3/3 done
306
+ });
307
+
308
+ it('also repeats on child failure', () => {
309
+ const n = new RepeaterNode('rep', always('failure'), 2);
310
+ n.tick(makeCtx()); // 1/2 → running
311
+ expect(n.tick(makeCtx())).toBe('success'); // 2/2 done
312
+ });
313
+
314
+ it('infinite repeat returns running indefinitely', () => {
315
+ const n = new RepeaterNode('rep', always('success')); // Infinity
316
+ for (let i = 0; i < 100; i++) {
317
+ expect(n.tick(makeCtx())).toBe('running');
318
+ }
319
+ });
320
+
321
+ it('reset() allows repeating again', () => {
322
+ const n = new RepeaterNode('rep', always('success'), 1);
323
+ n.tick(makeCtx()); // done
324
+ n.reset();
325
+ expect(n.tick(makeCtx())).toBe('success'); // done again
326
+ });
327
+ });
328
+
329
+ // ---------------------------------------------------------------------------
330
+ // GuardNode
331
+ // ---------------------------------------------------------------------------
332
+
333
+ describe('GuardNode', () => {
334
+ it('returns failure when condition is false (child not ticked)', () => {
335
+ let childCalled = false;
336
+ const child = new ActionNode('child', () => {
337
+ childCalled = true;
338
+ return 'success';
339
+ });
340
+ const n = new GuardNode('guard', () => false, child);
341
+ expect(n.tick(makeCtx())).toBe('failure');
342
+ expect(childCalled).toBe(false);
343
+ });
344
+
345
+ it('delegates to child when condition is true', () => {
346
+ const n = new GuardNode('guard', () => true, always('success'));
347
+ expect(n.tick(makeCtx())).toBe('success');
348
+ });
349
+
350
+ it('condition receives context', () => {
351
+ let received: BTContext | null = null;
352
+ const n = new GuardNode(
353
+ 'guard',
354
+ (ctx) => {
355
+ received = ctx;
356
+ return true;
357
+ },
358
+ always('success')
359
+ );
360
+ const ctx = makeCtx();
361
+ n.tick(ctx);
362
+ expect(received).toBe(ctx);
363
+ });
364
+
365
+ it('returns child failure when condition passes but child fails', () => {
366
+ const n = new GuardNode('guard', () => true, always('failure'));
367
+ expect(n.tick(makeCtx())).toBe('failure');
368
+ });
369
+ });
370
+
371
+ // ---------------------------------------------------------------------------
372
+ // reset() base behavior
373
+ // ---------------------------------------------------------------------------
374
+
375
+ describe('BTNode.reset()', () => {
376
+ it('sets status back to ready', () => {
377
+ const n = always('success');
378
+ n.tick(makeCtx());
379
+ expect(n.status).toBe('success');
380
+ n.reset();
381
+ expect(n.status).toBe('ready');
382
+ });
383
+
384
+ it('propagates reset to children recursively', () => {
385
+ const child = always('success');
386
+ const n = new SequenceNode('seq', [child]);
387
+ n.tick(makeCtx());
388
+ n.reset();
389
+ expect(child.status).toBe('ready');
390
+ });
391
+ });
@@ -0,0 +1,263 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import {
3
+ BTNode,
4
+ BTContext,
5
+ SequenceNode,
6
+ SelectorNode,
7
+ ParallelNode,
8
+ InverterNode,
9
+ RepeaterNode,
10
+ GuardNode,
11
+ ActionNode,
12
+ ConditionNode,
13
+ WaitNode,
14
+ } from '../BTNodes';
15
+
16
+ const ctx = (dt = 0.016): BTContext => ({
17
+ blackboard: { get: vi.fn(), set: vi.fn() },
18
+ deltaTime: dt,
19
+ entity: 'e',
20
+ });
21
+
22
+ describe('BTNodes', () => {
23
+ // ---------------------------------------------------------------------------
24
+ // ActionNode
25
+ // ---------------------------------------------------------------------------
26
+
27
+ describe('ActionNode', () => {
28
+ it('returns action result as status', () => {
29
+ const node = new ActionNode('act', () => 'success');
30
+ expect(node.tick(ctx())).toBe('success');
31
+ expect(node.status).toBe('success');
32
+ });
33
+
34
+ it('can return running', () => {
35
+ const node = new ActionNode('act', () => 'running');
36
+ expect(node.tick(ctx())).toBe('running');
37
+ });
38
+ });
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // ConditionNode
42
+ // ---------------------------------------------------------------------------
43
+
44
+ describe('ConditionNode', () => {
45
+ it('true → success', () => {
46
+ expect(new ConditionNode('c', () => true).tick(ctx())).toBe('success');
47
+ });
48
+
49
+ it('false → failure', () => {
50
+ expect(new ConditionNode('c', () => false).tick(ctx())).toBe('failure');
51
+ });
52
+ });
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // WaitNode
56
+ // ---------------------------------------------------------------------------
57
+
58
+ describe('WaitNode', () => {
59
+ it('returns running until duration elapsed', () => {
60
+ const w = new WaitNode('wait', 1);
61
+ expect(w.tick(ctx(0.5))).toBe('running');
62
+ expect(w.tick(ctx(0.5))).toBe('success');
63
+ });
64
+
65
+ it('reset clears elapsed time', () => {
66
+ const w = new WaitNode('wait', 1);
67
+ w.tick(ctx(0.5));
68
+ w.reset();
69
+ expect(w.tick(ctx(0.5))).toBe('running'); // started over
70
+ });
71
+ });
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // SequenceNode
75
+ // ---------------------------------------------------------------------------
76
+
77
+ describe('SequenceNode', () => {
78
+ it('runs children in order, succeeds when all succeed', () => {
79
+ const order: string[] = [];
80
+ const seq = new SequenceNode('s', [
81
+ new ActionNode('1', () => {
82
+ order.push('1');
83
+ return 'success';
84
+ }),
85
+ new ActionNode('2', () => {
86
+ order.push('2');
87
+ return 'success';
88
+ }),
89
+ ]);
90
+ expect(seq.tick(ctx())).toBe('success');
91
+ expect(order).toEqual(['1', '2']);
92
+ });
93
+
94
+ it('fails immediately when a child fails', () => {
95
+ const seq = new SequenceNode('s', [
96
+ new ActionNode('ok', () => 'success'),
97
+ new ActionNode('fail', () => 'failure'),
98
+ new ActionNode('skip', () => 'success'),
99
+ ]);
100
+ expect(seq.tick(ctx())).toBe('failure');
101
+ });
102
+
103
+ it('returns running and resumes on next tick', () => {
104
+ let runCount = 0;
105
+ const seq = new SequenceNode('s', [
106
+ new ActionNode('a', () => 'success'),
107
+ new ActionNode('b', () => (++runCount < 2 ? 'running' : 'success')),
108
+ ]);
109
+ expect(seq.tick(ctx())).toBe('running');
110
+ expect(seq.tick(ctx())).toBe('success');
111
+ });
112
+ });
113
+
114
+ // ---------------------------------------------------------------------------
115
+ // SelectorNode
116
+ // ---------------------------------------------------------------------------
117
+
118
+ describe('SelectorNode', () => {
119
+ it('succeeds on first successful child', () => {
120
+ const sel = new SelectorNode('s', [
121
+ new ActionNode('f', () => 'failure'),
122
+ new ActionNode('ok', () => 'success'),
123
+ ]);
124
+ expect(sel.tick(ctx())).toBe('success');
125
+ });
126
+
127
+ it('fails when all children fail', () => {
128
+ const sel = new SelectorNode('s', [
129
+ new ActionNode('f1', () => 'failure'),
130
+ new ActionNode('f2', () => 'failure'),
131
+ ]);
132
+ expect(sel.tick(ctx())).toBe('failure');
133
+ });
134
+ });
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // ParallelNode
138
+ // ---------------------------------------------------------------------------
139
+
140
+ describe('ParallelNode', () => {
141
+ it('succeeds when enough children succeed', () => {
142
+ const par = new ParallelNode(
143
+ 'p',
144
+ [
145
+ new ActionNode('a', () => 'success'),
146
+ new ActionNode('b', () => 'success'),
147
+ new ActionNode('c', () => 'failure'),
148
+ ],
149
+ 2
150
+ );
151
+ expect(par.tick(ctx())).toBe('success');
152
+ });
153
+
154
+ it('fails when too many children fail', () => {
155
+ const par = new ParallelNode(
156
+ 'p',
157
+ [new ActionNode('a', () => 'failure'), new ActionNode('b', () => 'failure')],
158
+ 2
159
+ );
160
+ expect(par.tick(ctx())).toBe('failure');
161
+ });
162
+
163
+ it('running when not yet decided', () => {
164
+ const par = new ParallelNode(
165
+ 'p',
166
+ [new ActionNode('a', () => 'success'), new ActionNode('b', () => 'running')],
167
+ 2
168
+ );
169
+ expect(par.tick(ctx())).toBe('running');
170
+ });
171
+ });
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // InverterNode
175
+ // ---------------------------------------------------------------------------
176
+
177
+ describe('InverterNode', () => {
178
+ it('inverts success to failure', () => {
179
+ const inv = new InverterNode('i', new ActionNode('a', () => 'success'));
180
+ expect(inv.tick(ctx())).toBe('failure');
181
+ });
182
+
183
+ it('inverts failure to success', () => {
184
+ const inv = new InverterNode('i', new ActionNode('a', () => 'failure'));
185
+ expect(inv.tick(ctx())).toBe('success');
186
+ });
187
+
188
+ it('passes running through unchanged', () => {
189
+ const inv = new InverterNode('i', new ActionNode('a', () => 'running'));
190
+ expect(inv.tick(ctx())).toBe('running');
191
+ });
192
+ });
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // RepeaterNode
196
+ // ---------------------------------------------------------------------------
197
+
198
+ describe('RepeaterNode', () => {
199
+ it('repeats child N times', () => {
200
+ let count = 0;
201
+ const rep = new RepeaterNode(
202
+ 'r',
203
+ new ActionNode('a', () => {
204
+ count++;
205
+ return 'success';
206
+ }),
207
+ 3
208
+ );
209
+ // Each tick increments count and returns running until limit
210
+ rep.tick(ctx()); // count=1, returns running
211
+ rep.tick(ctx()); // count=2, returns running
212
+ const status = rep.tick(ctx()); // count=3, returns success
213
+ expect(count).toBe(3);
214
+ expect(status).toBe('success');
215
+ });
216
+
217
+ it('reset clears repeat count', () => {
218
+ let count = 0;
219
+ const rep = new RepeaterNode(
220
+ 'r',
221
+ new ActionNode('a', () => {
222
+ count++;
223
+ return 'success';
224
+ }),
225
+ 1
226
+ );
227
+ rep.tick(ctx()); // count=1
228
+ rep.reset();
229
+ expect(rep.tick(ctx())).toBe('success'); // restarted
230
+ expect(count).toBe(2);
231
+ });
232
+ });
233
+
234
+ // ---------------------------------------------------------------------------
235
+ // GuardNode
236
+ // ---------------------------------------------------------------------------
237
+
238
+ describe('GuardNode', () => {
239
+ it('executes child when condition true', () => {
240
+ const guard = new GuardNode('g', () => true, new ActionNode('a', () => 'success'));
241
+ expect(guard.tick(ctx())).toBe('success');
242
+ });
243
+
244
+ it('returns failure when condition false', () => {
245
+ const guard = new GuardNode('g', () => false, new ActionNode('a', () => 'success'));
246
+ expect(guard.tick(ctx())).toBe('failure');
247
+ });
248
+ });
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // Reset
252
+ // ---------------------------------------------------------------------------
253
+
254
+ it('BTNode.reset cascades to children', () => {
255
+ const child = new ActionNode('a', () => 'success');
256
+ const seq = new SequenceNode('s', [child]);
257
+ seq.tick(ctx());
258
+ expect(seq.status).toBe('success');
259
+ seq.reset();
260
+ expect(seq.status).toBe('ready');
261
+ expect(child.status).toBe('ready');
262
+ });
263
+ });