@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,341 @@
1
+ /**
2
+ * AICopilot Production Tests
3
+ * Sprint CLXVI — adapter management, context, chat, generate, explain, autoFix
4
+ */
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+ import { AICopilot } from '../AICopilot';
7
+ import type { AIAdapter } from '../AIAdapter';
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Mock adapters
11
+ // ---------------------------------------------------------------------------
12
+
13
+ function makeGenerateAdapter(overrides: Partial<AIAdapter> = {}): AIAdapter {
14
+ return {
15
+ id: 'mock-gen',
16
+ name: 'Mock Generate',
17
+ isReady: () => true,
18
+ generateHoloScript: vi.fn().mockResolvedValue({
19
+ holoScript: 'scene { @Renderable }',
20
+ objectCount: 3,
21
+ confidence: 0.9,
22
+ warnings: [],
23
+ }),
24
+ ...overrides,
25
+ } as AIAdapter;
26
+ }
27
+
28
+ function makeFullAdapter(): AIAdapter {
29
+ return {
30
+ id: 'mock-full',
31
+ name: 'Mock Full',
32
+ isReady: () => true,
33
+ generateHoloScript: vi.fn().mockResolvedValue({
34
+ holoScript: 'scene { @Physics }',
35
+ objectCount: 1,
36
+ confidence: 0.85,
37
+ warnings: ['large scene'],
38
+ }),
39
+ explainHoloScript: vi.fn().mockResolvedValue({
40
+ explanation: 'This is a physics scene.',
41
+ concepts: [],
42
+ }),
43
+ fixHoloScript: vi.fn().mockResolvedValue({
44
+ holoScript: 'fixed code',
45
+ fixes: [{ line: 5, issue: 'missing type', fix: 'added type' }],
46
+ }),
47
+ chat: vi.fn().mockResolvedValue('HoloScript is a spatial programming language.'),
48
+ } as AIAdapter;
49
+ }
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Constructor and adapter management
53
+ // ---------------------------------------------------------------------------
54
+
55
+ describe('AICopilot', () => {
56
+ let copilot: AICopilot;
57
+
58
+ beforeEach(() => {
59
+ copilot = new AICopilot();
60
+ });
61
+
62
+ describe('adapter management', () => {
63
+ it('starts with no adapter', () => {
64
+ expect(copilot.getAdapter()).toBeNull();
65
+ expect(copilot.isReady()).toBe(false);
66
+ });
67
+
68
+ it('setAdapter makes it ready', () => {
69
+ copilot.setAdapter(makeGenerateAdapter());
70
+ expect(copilot.isReady()).toBe(true);
71
+ });
72
+
73
+ it('getAdapter returns set adapter', () => {
74
+ const adapter = makeGenerateAdapter();
75
+ copilot.setAdapter(adapter);
76
+ expect(copilot.getAdapter()).toBe(adapter);
77
+ });
78
+
79
+ it('constructor accepts adapter directly', () => {
80
+ const adapter = makeGenerateAdapter();
81
+ const c = new AICopilot(adapter);
82
+ expect(c.isReady()).toBe(true);
83
+ });
84
+ });
85
+
86
+ // -------------------------------------------------------------------------
87
+ // Context management
88
+ // -------------------------------------------------------------------------
89
+
90
+ describe('context management', () => {
91
+ it('starts with empty context', () => {
92
+ expect(copilot.getContext()).toEqual({});
93
+ });
94
+
95
+ it('updateContext merges partial context', () => {
96
+ copilot.updateContext({ stateKeys: ['hp', 'mana'] });
97
+ copilot.updateContext({ selectedEntity: { id: 'hero', type: 'player' } });
98
+ const ctx = copilot.getContext();
99
+ expect(ctx.stateKeys).toEqual(['hp', 'mana']);
100
+ expect(ctx.selectedEntity?.id).toBe('hero');
101
+ });
102
+
103
+ it('getContext returns a copy', () => {
104
+ copilot.updateContext({ entity: 'hero' } as any);
105
+ const ctx1 = copilot.getContext();
106
+ const ctx2 = copilot.getContext();
107
+ expect(ctx1).not.toBe(ctx2);
108
+ });
109
+ });
110
+
111
+ // -------------------------------------------------------------------------
112
+ // History management
113
+ // -------------------------------------------------------------------------
114
+
115
+ describe('history', () => {
116
+ it('starts with empty history', () => {
117
+ expect(copilot.getHistory()).toHaveLength(0);
118
+ });
119
+
120
+ it('clearHistory empties history', async () => {
121
+ copilot.setAdapter(makeFullAdapter());
122
+ await copilot.chat('hello');
123
+ copilot.clearHistory();
124
+ expect(copilot.getHistory()).toHaveLength(0);
125
+ });
126
+
127
+ it('getHistory returns a copy', async () => {
128
+ copilot.setAdapter(makeFullAdapter());
129
+ await copilot.chat('hello');
130
+ expect(copilot.getHistory()).not.toBe(copilot.getHistory());
131
+ });
132
+ });
133
+
134
+ // -------------------------------------------------------------------------
135
+ // generateFromPrompt
136
+ // -------------------------------------------------------------------------
137
+
138
+ describe('generateFromPrompt', () => {
139
+ it('returns NO_ADAPTER error when no adapter is set', async () => {
140
+ const r = await copilot.generateFromPrompt('make a scene');
141
+ expect(r.error).toBe('NO_ADAPTER');
142
+ });
143
+
144
+ it('returns UNSUPPORTED when adapter lacks generateHoloScript', async () => {
145
+ copilot.setAdapter({} as AIAdapter);
146
+ const r = await copilot.generateFromPrompt('make a scene');
147
+ expect(r.error).toBe('UNSUPPORTED');
148
+ });
149
+
150
+ it('returns response with suggestion on success', async () => {
151
+ copilot.setAdapter(makeGenerateAdapter());
152
+ const r = await copilot.generateFromPrompt('make a scene');
153
+ expect(r.suggestions).toHaveLength(1);
154
+ expect(r.suggestions[0].type).toBe('create');
155
+ expect(r.suggestions[0].holoScript).toBeTruthy();
156
+ });
157
+
158
+ it('includes confidence in suggestion', async () => {
159
+ copilot.setAdapter(makeGenerateAdapter());
160
+ const r = await copilot.generateFromPrompt('test');
161
+ expect(r.suggestions[0].confidence).toBeGreaterThan(0);
162
+ });
163
+
164
+ it('calls adapter.generateHoloScript with prompt and options', async () => {
165
+ const adapter = makeGenerateAdapter();
166
+ copilot.setAdapter(adapter);
167
+ await copilot.generateFromPrompt('hello', { complexity: 'high' } as any);
168
+ expect(adapter.generateHoloScript).toHaveBeenCalledWith(
169
+ 'hello',
170
+ expect.objectContaining({ complexity: 'high' })
171
+ );
172
+ });
173
+
174
+ it('includes warnings in response text', async () => {
175
+ const adapter = makeFullAdapter();
176
+ copilot.setAdapter(adapter);
177
+ const r = await copilot.generateFromPrompt('large scene');
178
+ expect(r.text).toContain('large scene');
179
+ });
180
+
181
+ it('adds user and assistant messages to history', async () => {
182
+ copilot.setAdapter(makeGenerateAdapter());
183
+ await copilot.generateFromPrompt('prompt text');
184
+ const h = copilot.getHistory();
185
+ expect(h.length).toBe(2);
186
+ expect(h[0].role).toBe('user');
187
+ expect(h[1].role).toBe('assistant');
188
+ });
189
+
190
+ it('returns error response on adapter throw', async () => {
191
+ const adapter = makeGenerateAdapter({
192
+ generateHoloScript: vi.fn().mockRejectedValue(new Error('network error')),
193
+ });
194
+ copilot.setAdapter(adapter);
195
+ const r = await copilot.generateFromPrompt('boom');
196
+ expect(r.error).toBe('network error');
197
+ expect(r.text).toContain('network error');
198
+ });
199
+ });
200
+
201
+ // -------------------------------------------------------------------------
202
+ // suggestFromSelection
203
+ // -------------------------------------------------------------------------
204
+
205
+ describe('suggestFromSelection', () => {
206
+ it('returns NO_ADAPTER when no adapter', async () => {
207
+ const r = await copilot.suggestFromSelection();
208
+ expect(r.error).toBe('NO_ADAPTER');
209
+ });
210
+
211
+ it('returns message when no entity selected', async () => {
212
+ copilot.setAdapter(makeGenerateAdapter());
213
+ const r = await copilot.suggestFromSelection();
214
+ expect(r.text).toContain('No entity selected');
215
+ expect(r.error).toBeUndefined();
216
+ });
217
+
218
+ it('returns modify suggestion for selected entity', async () => {
219
+ copilot.setAdapter(makeGenerateAdapter());
220
+ copilot.updateContext({
221
+ selectedEntity: { id: 'hero', type: 'player', properties: { hp: 100 } },
222
+ });
223
+ const r = await copilot.suggestFromSelection();
224
+ expect(r.suggestions[0].type).toBe('modify');
225
+ expect(r.text).toContain('player');
226
+ });
227
+ });
228
+
229
+ // -------------------------------------------------------------------------
230
+ // explainScene
231
+ // -------------------------------------------------------------------------
232
+
233
+ describe('explainScene', () => {
234
+ it('returns NO_ADAPTER when no adapter', async () => {
235
+ const r = await copilot.explainScene('code');
236
+ expect(r.error).toBe('NO_ADAPTER');
237
+ });
238
+
239
+ it('returns UNSUPPORTED when adapter lacks explainHoloScript', async () => {
240
+ copilot.setAdapter(makeGenerateAdapter()); // no explainHoloScript
241
+ const r = await copilot.explainScene('code');
242
+ expect(r.error).toBe('UNSUPPORTED');
243
+ });
244
+
245
+ it('returns explanation text on success', async () => {
246
+ copilot.setAdapter(makeFullAdapter());
247
+ const r = await copilot.explainScene('scene {}');
248
+ expect(r.text).toBe('This is a physics scene.');
249
+ });
250
+
251
+ it('returns error response on adapter throw', async () => {
252
+ const adapter = makeFullAdapter();
253
+ (adapter.explainHoloScript as any) = vi.fn().mockRejectedValue(new Error('fail'));
254
+ copilot.setAdapter(adapter);
255
+ const r = await copilot.explainScene('code');
256
+ expect(r.error).toBeTruthy();
257
+ });
258
+ });
259
+
260
+ // -------------------------------------------------------------------------
261
+ // autoFix
262
+ // -------------------------------------------------------------------------
263
+
264
+ describe('autoFix', () => {
265
+ it('returns NO_ADAPTER when no adapter', async () => {
266
+ const r = await copilot.autoFix('code', ['err']);
267
+ expect(r.error).toBe('NO_ADAPTER');
268
+ });
269
+
270
+ it('returns UNSUPPORTED when adapter lacks fixHoloScript', async () => {
271
+ copilot.setAdapter(makeGenerateAdapter()); // no fixHoloScript
272
+ const r = await copilot.autoFix('code', ['err']);
273
+ expect(r.error).toBe('UNSUPPORTED');
274
+ });
275
+
276
+ it('returns fix suggestions on success', async () => {
277
+ copilot.setAdapter(makeFullAdapter());
278
+ const r = await copilot.autoFix('broken code', ['type error']);
279
+ expect(r.suggestions).toHaveLength(1);
280
+ expect(r.suggestions[0].type).toBe('fix');
281
+ expect(r.text).toContain('1 issue');
282
+ });
283
+
284
+ it('includes line info in fix suggestion description', async () => {
285
+ copilot.setAdapter(makeFullAdapter());
286
+ const r = await copilot.autoFix('bad', ['err']);
287
+ expect(r.suggestions[0].description).toContain('Line 5');
288
+ });
289
+ });
290
+
291
+ // -------------------------------------------------------------------------
292
+ // chat
293
+ // -------------------------------------------------------------------------
294
+
295
+ describe('chat', () => {
296
+ it('returns NO_ADAPTER when no adapter', async () => {
297
+ const r = await copilot.chat('hello');
298
+ expect(r.error).toBe('NO_ADAPTER');
299
+ });
300
+
301
+ it('returns UNSUPPORTED when adapter lacks chat', async () => {
302
+ copilot.setAdapter(makeGenerateAdapter()); // no chat
303
+ const r = await copilot.chat('hello');
304
+ expect(r.error).toBe('UNSUPPORTED');
305
+ });
306
+
307
+ it('returns assistant response text', async () => {
308
+ copilot.setAdapter(makeFullAdapter());
309
+ const r = await copilot.chat('What is HoloScript?');
310
+ expect(r.text).toContain('HoloScript');
311
+ });
312
+
313
+ it('adds messages to history with correct roles', async () => {
314
+ copilot.setAdapter(makeFullAdapter());
315
+ await copilot.chat('first question');
316
+ const h = copilot.getHistory();
317
+ expect(h[0].role).toBe('user');
318
+ expect(h[0].content).toBe('first question');
319
+ expect(h[1].role).toBe('assistant');
320
+ });
321
+
322
+ it('passes history to adapter on multi-turn', async () => {
323
+ const adapter = makeFullAdapter();
324
+ copilot.setAdapter(adapter);
325
+ await copilot.chat('turn 1');
326
+ await copilot.chat('turn 2');
327
+ expect(adapter.chat).toHaveBeenCalledTimes(2);
328
+ const secondCall = (adapter.chat as any).mock.calls[1];
329
+ // Third arg is chat history
330
+ expect(secondCall[2].length).toBeGreaterThan(0);
331
+ });
332
+
333
+ it('returns error on adapter throw', async () => {
334
+ const adapter = makeFullAdapter();
335
+ (adapter.chat as any) = vi.fn().mockRejectedValue(new Error('timeout'));
336
+ copilot.setAdapter(adapter);
337
+ const r = await copilot.chat('hello');
338
+ expect(r.error).toBe('timeout');
339
+ });
340
+ });
341
+ });
@@ -0,0 +1,178 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { AICopilot } from '../AICopilot';
3
+ import type { AIAdapter } from '../AIAdapter';
4
+
5
+ function mockAdapter(overrides = {}): AIAdapter {
6
+ return {
7
+ id: 'mock',
8
+ name: 'Mock Adapter',
9
+ isReady: () => true,
10
+ generateHoloScript: vi.fn(async () => ({
11
+ holoScript: 'scene { }',
12
+ confidence: 0.9,
13
+ objectCount: 1,
14
+ })),
15
+ explainHoloScript: vi.fn(async () => ({
16
+ explanation: 'This is a scene.',
17
+ })),
18
+ fixHoloScript: vi.fn(async () => ({
19
+ holoScript: 'scene { }',
20
+ fixes: [{ line: 1, issue: 'typo', fix: 'fixed typo' }],
21
+ })),
22
+ chat: vi.fn(async () => 'Hello from AI'),
23
+ ...overrides,
24
+ };
25
+ }
26
+
27
+ describe('AICopilot', () => {
28
+ let copilot: AICopilot;
29
+ let adapter: AIAdapter;
30
+
31
+ beforeEach(() => {
32
+ adapter = mockAdapter();
33
+ copilot = new AICopilot();
34
+ });
35
+
36
+ // --- Adapter management ---
37
+ it('isReady returns false without adapter', () => {
38
+ expect(copilot.isReady()).toBe(false);
39
+ });
40
+
41
+ it('setAdapter makes copilot ready', () => {
42
+ copilot.setAdapter(adapter);
43
+ expect(copilot.isReady()).toBe(true);
44
+ expect(copilot.getAdapter()).toBe(adapter);
45
+ });
46
+
47
+ it('constructor with adapter sets it', () => {
48
+ const c2 = new AICopilot(adapter);
49
+ expect(c2.isReady()).toBe(true);
50
+ });
51
+
52
+ // --- Context management ---
53
+ it('getContext returns empty initially', () => {
54
+ expect(copilot.getContext()).toEqual({});
55
+ });
56
+
57
+ it('updateContext merges context', () => {
58
+ copilot.updateContext({ selectedEntity: { id: 'e1', type: 'mesh' } });
59
+ copilot.updateContext({ stateKeys: ['health', 'score'] });
60
+ const ctx = copilot.getContext();
61
+ expect(ctx.selectedEntity!.id).toBe('e1');
62
+ expect(ctx.stateKeys).toContain('health');
63
+ });
64
+
65
+ it('getContext returns shallow copy', () => {
66
+ copilot.updateContext({ stateKeys: ['a'] });
67
+ const c1 = copilot.getContext();
68
+ // Shallow copy: mutating the top-level object doesn't affect original
69
+ c1.selectedEntity = { id: 'injected', type: 'test' };
70
+ expect(copilot.getContext().selectedEntity).toBeUndefined();
71
+ });
72
+
73
+ // --- History management ---
74
+ it('getHistory returns empty initially', () => {
75
+ expect(copilot.getHistory()).toHaveLength(0);
76
+ });
77
+
78
+ it('clearHistory empties history', async () => {
79
+ copilot.setAdapter(adapter);
80
+ await copilot.generateFromPrompt('hello');
81
+ expect(copilot.getHistory().length).toBeGreaterThan(0);
82
+ copilot.clearHistory();
83
+ expect(copilot.getHistory()).toHaveLength(0);
84
+ });
85
+
86
+ // --- generateFromPrompt ---
87
+ it('generateFromPrompt returns error without adapter', async () => {
88
+ const result = await copilot.generateFromPrompt('make a box');
89
+ expect(result.error).toBe('NO_ADAPTER');
90
+ });
91
+
92
+ it('generateFromPrompt calls adapter and returns suggestions', async () => {
93
+ copilot.setAdapter(adapter);
94
+ const result = await copilot.generateFromPrompt('make a box');
95
+ expect(result.suggestions).toHaveLength(1);
96
+ expect(result.suggestions[0].type).toBe('create');
97
+ expect(adapter.generateHoloScript).toHaveBeenCalled();
98
+ });
99
+
100
+ it('generateFromPrompt adds to history', async () => {
101
+ copilot.setAdapter(adapter);
102
+ await copilot.generateFromPrompt('test');
103
+ const history = copilot.getHistory();
104
+ expect(history.length).toBeGreaterThanOrEqual(2);
105
+ expect(history[0].role).toBe('user');
106
+ expect(history[1].role).toBe('assistant');
107
+ });
108
+
109
+ it('generateFromPrompt handles adapter error', async () => {
110
+ const errorAdapter = mockAdapter({
111
+ generateHoloScript: vi.fn(async () => {
112
+ throw new Error('API down');
113
+ }),
114
+ });
115
+ copilot.setAdapter(errorAdapter);
116
+ const result = await copilot.generateFromPrompt('test');
117
+ expect(result.error).toContain('API down');
118
+ });
119
+
120
+ // --- suggestFromSelection ---
121
+ it('suggestFromSelection returns error without adapter', async () => {
122
+ const result = await copilot.suggestFromSelection();
123
+ expect(result.error).toBe('NO_ADAPTER');
124
+ });
125
+
126
+ it('suggestFromSelection returns message when no entity selected', async () => {
127
+ copilot.setAdapter(adapter);
128
+ const result = await copilot.suggestFromSelection();
129
+ expect(result.text).toContain('No entity selected');
130
+ });
131
+
132
+ it('suggestFromSelection works with entity', async () => {
133
+ copilot.setAdapter(adapter);
134
+ copilot.updateContext({
135
+ selectedEntity: { id: 'box1', type: 'mesh', properties: { color: 'red' } },
136
+ });
137
+ const result = await copilot.suggestFromSelection();
138
+ expect(result.suggestions).toHaveLength(1);
139
+ expect(result.suggestions[0].type).toBe('modify');
140
+ });
141
+
142
+ // --- explainScene ---
143
+ it('explainScene returns error without adapter', async () => {
144
+ const result = await copilot.explainScene('scene {}');
145
+ expect(result.error).toBe('NO_ADAPTER');
146
+ });
147
+
148
+ it('explainScene calls adapter', async () => {
149
+ copilot.setAdapter(adapter);
150
+ const result = await copilot.explainScene('scene { box {} }');
151
+ expect(result.text).toBe('This is a scene.');
152
+ });
153
+
154
+ // --- autoFix ---
155
+ it('autoFix returns error without adapter', async () => {
156
+ const result = await copilot.autoFix('broken', ['err1']);
157
+ expect(result.error).toBe('NO_ADAPTER');
158
+ });
159
+
160
+ it('autoFix returns fix suggestions', async () => {
161
+ copilot.setAdapter(adapter);
162
+ const result = await copilot.autoFix('broken code', ['syntax error']);
163
+ expect(result.suggestions).toHaveLength(1);
164
+ expect(result.suggestions[0].type).toBe('fix');
165
+ });
166
+
167
+ // --- chat ---
168
+ it('chat returns error without adapter', async () => {
169
+ const result = await copilot.chat('hi');
170
+ expect(result.error).toBe('NO_ADAPTER');
171
+ });
172
+
173
+ it('chat returns AI response', async () => {
174
+ copilot.setAdapter(adapter);
175
+ const result = await copilot.chat('how do I add physics?');
176
+ expect(result.text).toBe('Hello from AI');
177
+ });
178
+ });