@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,236 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { GoalSynthesizer, GENERIC_GOALS, DOMAIN_GOALS } from '../protocol/goal-synthesizer';
3
+ import type { GoalContext, SynthesizedGoal } from '../protocol/goal-synthesizer';
4
+ import type { KnowledgeStore, StoredEntry } from '../knowledge/knowledge-store';
5
+
6
+ // ── Helpers ──
7
+
8
+ function mockKnowledgeStore(entries: Partial<StoredEntry>[] = []): KnowledgeStore {
9
+ return {
10
+ search: vi.fn().mockReturnValue(entries),
11
+ } as unknown as KnowledgeStore;
12
+ }
13
+
14
+ function mockLLMConfig() {
15
+ return {
16
+ provider: 'anthropic' as const,
17
+ model: 'claude-sonnet-4',
18
+ apiKey: 'test-key',
19
+ };
20
+ }
21
+
22
+ // ── Tests ──
23
+
24
+ describe('GoalSynthesizer', () => {
25
+ describe('constructor', () => {
26
+ it('creates without options (no LLM, no knowledge)', () => {
27
+ const gs = new GoalSynthesizer();
28
+ expect(gs).toBeDefined();
29
+ });
30
+
31
+ it('creates with LLM and knowledge store', () => {
32
+ const gs = new GoalSynthesizer({
33
+ llm: mockLLMConfig(),
34
+ knowledge: mockKnowledgeStore(),
35
+ });
36
+ expect(gs).toBeDefined();
37
+ });
38
+ });
39
+
40
+ describe('synthesize (backward-compatible sync API)', () => {
41
+ it('returns a valid Goal with defaults', () => {
42
+ const gs = new GoalSynthesizer();
43
+ const goal = gs.synthesize();
44
+ expect(goal).toHaveProperty('id');
45
+ expect(goal).toHaveProperty('description');
46
+ expect(goal).toHaveProperty('category');
47
+ expect(goal).toHaveProperty('priority');
48
+ expect(goal).toHaveProperty('estimatedComplexity');
49
+ expect(goal).toHaveProperty('generatedAt');
50
+ expect(goal).toHaveProperty('source');
51
+ expect(goal.id).toMatch(/^GOAL-/);
52
+ expect(goal.source).toBe('autonomous-boredom');
53
+ });
54
+
55
+ it('respects custom domain', () => {
56
+ const gs = new GoalSynthesizer();
57
+ const goal = gs.synthesize('coding');
58
+ expect(goal.description).toBeTruthy();
59
+ });
60
+
61
+ it('respects custom source', () => {
62
+ const gs = new GoalSynthesizer();
63
+ const goal = gs.synthesize('general', 'system-mandate');
64
+ expect(goal.source).toBe('system-mandate');
65
+ });
66
+
67
+ it('generates goals with complexity 1-5', () => {
68
+ const gs = new GoalSynthesizer();
69
+ for (let i = 0; i < 20; i++) {
70
+ const goal = gs.synthesize();
71
+ expect(goal.estimatedComplexity).toBeGreaterThanOrEqual(1);
72
+ expect(goal.estimatedComplexity).toBeLessThanOrEqual(5);
73
+ }
74
+ });
75
+ });
76
+
77
+ describe('synthesizeMultiple (async, context-aware)', () => {
78
+ it('returns requested number of goals via heuristic', async () => {
79
+ const gs = new GoalSynthesizer();
80
+ const context: GoalContext = { domain: 'coding' };
81
+ const goals = await gs.synthesizeMultiple(context, 3);
82
+ expect(goals).toHaveLength(3);
83
+ for (const g of goals) {
84
+ expect(g).toHaveProperty('rationale');
85
+ expect(g).toHaveProperty('relevanceScore');
86
+ expect(g.relevanceScore).toBeGreaterThan(0);
87
+ expect(g.relevanceScore).toBeLessThanOrEqual(1);
88
+ }
89
+ });
90
+
91
+ it('returns domain-specific goals for coding', async () => {
92
+ const gs = new GoalSynthesizer();
93
+ const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 5);
94
+ expect(goals.length).toBeGreaterThan(0);
95
+ expect(goals.length).toBeLessThanOrEqual(5);
96
+ });
97
+
98
+ it('returns domain-specific goals for security', async () => {
99
+ const gs = new GoalSynthesizer();
100
+ const goals = await gs.synthesizeMultiple({ domain: 'security' }, 3);
101
+ expect(goals).toHaveLength(3);
102
+ });
103
+
104
+ it('returns domain-specific goals for research', async () => {
105
+ const gs = new GoalSynthesizer();
106
+ const goals = await gs.synthesizeMultiple({ domain: 'research' }, 3);
107
+ expect(goals).toHaveLength(3);
108
+ });
109
+
110
+ it('falls back to generic goals for unknown domains', async () => {
111
+ const gs = new GoalSynthesizer();
112
+ const goals = await gs.synthesizeMultiple({ domain: 'quantum-knitting' }, 2);
113
+ expect(goals).toHaveLength(2);
114
+ // Should still produce valid goals
115
+ for (const g of goals) {
116
+ expect(g.description).toBeTruthy();
117
+ }
118
+ });
119
+
120
+ it('uses knowledge store gotchas to derive goals', async () => {
121
+ const store = mockKnowledgeStore([
122
+ {
123
+ id: 'G.TEST.001',
124
+ type: 'gotcha',
125
+ content: 'Memory leak in WebSocket reconnection handler',
126
+ domain: 'coding',
127
+ confidence: 0.9,
128
+ source: 'test',
129
+ queryCount: 0,
130
+ reuseCount: 0,
131
+ createdAt: new Date().toISOString(),
132
+ authorAgent: 'test-agent',
133
+ },
134
+ ]);
135
+ const gs = new GoalSynthesizer({ knowledge: store });
136
+ const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 3);
137
+ expect(goals.length).toBeGreaterThan(0);
138
+ // Knowledge store should have been queried
139
+ expect(store.search).toHaveBeenCalledWith('coding', 5);
140
+ });
141
+
142
+ it('filters out recently completed tasks', async () => {
143
+ const gs = new GoalSynthesizer();
144
+ const completed = GENERIC_GOALS.slice(0, 4);
145
+ const goals = await gs.synthesizeMultiple({
146
+ domain: 'general',
147
+ recentCompletedTasks: completed,
148
+ }, 3);
149
+ // None of the returned goals should match completed tasks
150
+ for (const g of goals) {
151
+ expect(completed.map(c => c.toLowerCase())).not.toContain(g.description.toLowerCase());
152
+ }
153
+ });
154
+
155
+ it('first goal has highest relevance score', async () => {
156
+ const gs = new GoalSynthesizer();
157
+ const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 3);
158
+ if (goals.length >= 2) {
159
+ expect(goals[0].relevanceScore).toBeGreaterThanOrEqual(goals[1].relevanceScore);
160
+ }
161
+ });
162
+
163
+ it('includes rationale for each goal', async () => {
164
+ const gs = new GoalSynthesizer();
165
+ const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 2);
166
+ for (const g of goals) {
167
+ expect(g.rationale).toBeTruthy();
168
+ expect(typeof g.rationale).toBe('string');
169
+ }
170
+ });
171
+ });
172
+
173
+ describe('LLM-based synthesis', () => {
174
+ it('falls back to heuristic when LLM call fails', async () => {
175
+ // Mock callLLM to throw
176
+ vi.doMock('../llm/llm-adapter', () => ({
177
+ callLLM: vi.fn().mockRejectedValue(new Error('API key invalid')),
178
+ }));
179
+
180
+ const gs = new GoalSynthesizer({
181
+ llm: mockLLMConfig(),
182
+ });
183
+
184
+ const goals = await gs.synthesizeMultiple({ domain: 'coding' }, 2);
185
+ // Should still return goals via heuristic fallback
186
+ expect(goals.length).toBeGreaterThan(0);
187
+ });
188
+ });
189
+
190
+ describe('knowledge-derived goals', () => {
191
+ it('marks knowledge-derived goals with knowledge-gap category', async () => {
192
+ const store = mockKnowledgeStore([
193
+ {
194
+ id: 'G.SEC.001',
195
+ type: 'gotcha',
196
+ content: 'SQL injection in search endpoint',
197
+ domain: 'security',
198
+ confidence: 0.95,
199
+ source: 'audit',
200
+ queryCount: 0,
201
+ reuseCount: 0,
202
+ createdAt: new Date().toISOString(),
203
+ authorAgent: 'scanner',
204
+ },
205
+ ]);
206
+
207
+ const gs = new GoalSynthesizer({ knowledge: store });
208
+ // Request enough goals to ensure the knowledge-derived one is included
209
+ const goals = await gs.synthesizeMultiple({ domain: 'security' }, 15);
210
+
211
+ const knowledgeGapGoals = goals.filter(g => g.category === 'knowledge-gap');
212
+ // At least one goal should be derived from the gotcha
213
+ expect(knowledgeGapGoals.length).toBeGreaterThanOrEqual(1);
214
+ const derived = knowledgeGapGoals[0];
215
+ expect(derived.description).toContain('SQL injection');
216
+ expect(derived.rationale).toContain('knowledge store');
217
+ });
218
+ });
219
+
220
+ describe('exported constants', () => {
221
+ it('GENERIC_GOALS is a non-empty array of strings', () => {
222
+ expect(Array.isArray(GENERIC_GOALS)).toBe(true);
223
+ expect(GENERIC_GOALS.length).toBeGreaterThan(0);
224
+ for (const g of GENERIC_GOALS) {
225
+ expect(typeof g).toBe('string');
226
+ }
227
+ });
228
+
229
+ it('DOMAIN_GOALS has expected domains', () => {
230
+ expect(DOMAIN_GOALS).toHaveProperty('coding');
231
+ expect(DOMAIN_GOALS).toHaveProperty('research');
232
+ expect(DOMAIN_GOALS).toHaveProperty('security');
233
+ expect(DOMAIN_GOALS).toHaveProperty('reviewer');
234
+ });
235
+ });
236
+ });
@@ -0,0 +1,223 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { defineAgent } from '../define-agent';
3
+ import { defineTeam } from '../define-team';
4
+ import type { AgentConfig } from '../types';
5
+
6
+ // Mock protocol-agent so runCycle doesn't hit real LLMs
7
+ vi.mock('../protocol-agent', () => ({
8
+ runProtocolCycle: vi.fn().mockResolvedValue({
9
+ summary: 'Done',
10
+ insights: [],
11
+ }),
12
+ }));
13
+
14
+ function makeAgent(name: string, role: AgentConfig['role'] = 'coder'): AgentConfig {
15
+ return defineAgent({
16
+ name,
17
+ role,
18
+ model: { provider: 'anthropic', model: 'claude-sonnet-4' },
19
+ capabilities: ['code-generation'],
20
+ claimFilter: { roles: ['coder'], maxPriority: 10 },
21
+ });
22
+ }
23
+
24
+ describe('Local Presence Tracking (FW-0.3)', () => {
25
+ describe('localHeartbeat()', () => {
26
+ it('registers an agent on first heartbeat', () => {
27
+ const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
28
+ team.localHeartbeat('Alice');
29
+ const agents = team.localPresence();
30
+ expect(agents).toHaveLength(1);
31
+ expect(agents[0].name).toBe('Alice');
32
+ expect(agents[0].status).toBe('online');
33
+ });
34
+
35
+ it('updates lastSeen on subsequent heartbeats', () => {
36
+ const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
37
+ team.localHeartbeat('Alice');
38
+ const first = team.localPresence()[0].lastSeen;
39
+
40
+ // Advance time slightly
41
+ vi.useFakeTimers();
42
+ vi.advanceTimersByTime(100);
43
+ team.localHeartbeat('Alice');
44
+ const second = team.localPresence()[0].lastSeen;
45
+ expect(second).toBeGreaterThanOrEqual(first);
46
+ vi.useRealTimers();
47
+ });
48
+
49
+ it('tracks currentTask when provided', () => {
50
+ const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
51
+ team.localHeartbeat('Alice', 'Fix auth bug');
52
+ const agents = team.localPresence();
53
+ expect(agents[0].currentTask).toBe('Fix auth bug');
54
+ });
55
+
56
+ it('clears currentTask when heartbeat has no task', () => {
57
+ const team = defineTeam({ name: 'presence-test', agents: [makeAgent('Alice')] });
58
+ team.localHeartbeat('Alice', 'Fix auth bug');
59
+ team.localHeartbeat('Alice');
60
+ const agents = team.localPresence();
61
+ expect(agents[0].currentTask).toBeUndefined();
62
+ });
63
+
64
+ it('tracks multiple agents independently', () => {
65
+ const team = defineTeam({
66
+ name: 'presence-test',
67
+ agents: [makeAgent('Alice'), makeAgent('Bob', 'reviewer')],
68
+ });
69
+ team.localHeartbeat('Alice', 'Task A');
70
+ team.localHeartbeat('Bob', 'Task B');
71
+ const agents = team.localPresence();
72
+ expect(agents).toHaveLength(2);
73
+ const names = agents.map(a => a.name).sort();
74
+ expect(names).toEqual(['Alice', 'Bob']);
75
+ });
76
+ });
77
+
78
+ describe('localPresence() status transitions', () => {
79
+ it('marks agent as idle after idleTimeout', () => {
80
+ vi.useFakeTimers();
81
+ const team = defineTeam({
82
+ name: 'idle-test',
83
+ agents: [makeAgent('Alice')],
84
+ presence: { idleTimeoutMs: 1000, offlineTimeoutMs: 5000 },
85
+ });
86
+
87
+ team.localHeartbeat('Alice');
88
+ expect(team.localPresence()[0].status).toBe('online');
89
+
90
+ vi.advanceTimersByTime(1500); // past idle threshold
91
+ expect(team.localPresence()[0].status).toBe('idle');
92
+
93
+ vi.useRealTimers();
94
+ });
95
+
96
+ it('marks agent as offline after offlineTimeout', () => {
97
+ vi.useFakeTimers();
98
+ const team = defineTeam({
99
+ name: 'offline-test',
100
+ agents: [makeAgent('Alice')],
101
+ presence: { idleTimeoutMs: 1000, offlineTimeoutMs: 5000 },
102
+ });
103
+
104
+ team.localHeartbeat('Alice');
105
+ vi.advanceTimersByTime(6000); // past offline threshold
106
+ expect(team.localPresence()[0].status).toBe('offline');
107
+
108
+ vi.useRealTimers();
109
+ });
110
+
111
+ it('returns to online after a fresh heartbeat', () => {
112
+ vi.useFakeTimers();
113
+ const team = defineTeam({
114
+ name: 'recover-test',
115
+ agents: [makeAgent('Alice')],
116
+ presence: { idleTimeoutMs: 1000, offlineTimeoutMs: 5000 },
117
+ });
118
+
119
+ team.localHeartbeat('Alice');
120
+ vi.advanceTimersByTime(6000);
121
+ expect(team.localPresence()[0].status).toBe('offline');
122
+
123
+ // Agent comes back
124
+ team.localHeartbeat('Alice');
125
+ expect(team.localPresence()[0].status).toBe('online');
126
+
127
+ vi.useRealTimers();
128
+ });
129
+
130
+ it('uses default timeouts (60s idle, 300s offline) when not configured', () => {
131
+ vi.useFakeTimers();
132
+ const team = defineTeam({
133
+ name: 'default-timeout-test',
134
+ agents: [makeAgent('Alice')],
135
+ });
136
+
137
+ team.localHeartbeat('Alice');
138
+ expect(team.localPresence()[0].status).toBe('online');
139
+
140
+ vi.advanceTimersByTime(61_000); // past default 60s idle
141
+ expect(team.localPresence()[0].status).toBe('idle');
142
+
143
+ vi.advanceTimersByTime(240_000); // total ~301s, past default 300s offline
144
+ expect(team.localPresence()[0].status).toBe('offline');
145
+
146
+ vi.useRealTimers();
147
+ });
148
+ });
149
+
150
+ describe('uptime tracking', () => {
151
+ it('computes uptime from first heartbeat', () => {
152
+ vi.useFakeTimers();
153
+ const team = defineTeam({
154
+ name: 'uptime-test',
155
+ agents: [makeAgent('Alice')],
156
+ presence: { idleTimeoutMs: 60_000, offlineTimeoutMs: 300_000 },
157
+ });
158
+
159
+ team.localHeartbeat('Alice');
160
+ vi.advanceTimersByTime(10_000);
161
+ team.localHeartbeat('Alice'); // refresh lastSeen but firstSeen stays
162
+
163
+ const agents = team.localPresence();
164
+ expect(agents[0].uptime).toBeGreaterThanOrEqual(10_000);
165
+
166
+ vi.useRealTimers();
167
+ });
168
+ });
169
+
170
+ describe('auto-heartbeat during runCycle', () => {
171
+ it('automatically heartbeats agents that claim tasks during a cycle', async () => {
172
+ const team = defineTeam({
173
+ name: 'auto-hb-test',
174
+ agents: [makeAgent('Alice')],
175
+ });
176
+
177
+ await team.addTasks([
178
+ { title: 'Fix bug', description: 'Important', priority: 1, role: 'coder' },
179
+ ]);
180
+
181
+ // Before cycle — no presence data
182
+ expect(team.localPresence()).toHaveLength(0);
183
+
184
+ await team.runCycle();
185
+
186
+ // After cycle — agent should have been auto-heartbeated
187
+ const agents = team.localPresence();
188
+ expect(agents).toHaveLength(1);
189
+ expect(agents[0].name).toBe('Alice');
190
+ expect(agents[0].status).toBe('online');
191
+ expect(agents[0].currentTask).toBe('Fix bug');
192
+ });
193
+
194
+ it('does not heartbeat agents that skip (no matching task)', async () => {
195
+ const team = defineTeam({
196
+ name: 'skip-hb-test',
197
+ agents: [makeAgent('Alice')],
198
+ });
199
+
200
+ // No tasks on board, but more than threshold so no synthesis
201
+ await team.addTasks([
202
+ { title: 'Task 1', description: '', priority: 1, role: 'reviewer' as const },
203
+ { title: 'Task 2', description: '', priority: 2, role: 'reviewer' as const },
204
+ { title: 'Task 3', description: '', priority: 3, role: 'reviewer' as const },
205
+ ]);
206
+
207
+ await team.runCycle();
208
+
209
+ // Alice is a coder, all tasks are reviewer-only — she should have skipped
210
+ expect(team.localPresence()).toHaveLength(0);
211
+ });
212
+ });
213
+
214
+ describe('empty presence', () => {
215
+ it('returns empty array when no heartbeats recorded', () => {
216
+ const team = defineTeam({
217
+ name: 'empty-test',
218
+ agents: [makeAgent('Alice')],
219
+ });
220
+ expect(team.localPresence()).toEqual([]);
221
+ });
222
+ });
223
+ });