@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,156 @@
1
+ /**
2
+ * RevenueSplitter — Deterministic revenue splitting using bigint arithmetic.
3
+ *
4
+ * Splits revenue among multiple recipients with exact-sum invariant:
5
+ * sum(shares) === total (no rounding leakage).
6
+ *
7
+ * Moved from core into framework as part of FW-0.6.
8
+ *
9
+ * @module economy/RevenueSplitter
10
+ */
11
+
12
+ // =============================================================================
13
+ // TYPES
14
+ // =============================================================================
15
+
16
+ export interface SplitRecipient {
17
+ /** Unique recipient ID (agent, creator, platform) */
18
+ id: string;
19
+ /** Basis points (1/10000) — e.g., 5000 = 50% */
20
+ basisPoints: number;
21
+ }
22
+
23
+ export interface SplitResult {
24
+ /** Individual shares keyed by recipient ID */
25
+ shares: Map<string, bigint>;
26
+ /** Total input amount */
27
+ total: bigint;
28
+ /** Any dust (remainder) allocated to the first recipient */
29
+ dust: bigint;
30
+ /** Human-readable breakdown */
31
+ breakdown: SplitBreakdownEntry[];
32
+ }
33
+
34
+ export interface SplitBreakdownEntry {
35
+ recipientId: string;
36
+ basisPoints: number;
37
+ amount: bigint;
38
+ percentage: string;
39
+ }
40
+
41
+ // =============================================================================
42
+ // CONSTANTS
43
+ // =============================================================================
44
+
45
+ /** Total basis points (100%) */
46
+ const TOTAL_BASIS_POINTS = 10_000;
47
+
48
+ // =============================================================================
49
+ // REVENUE SPLITTER
50
+ // =============================================================================
51
+
52
+ export class RevenueSplitter {
53
+ private recipients: SplitRecipient[];
54
+
55
+ /**
56
+ * Create a revenue splitter.
57
+ *
58
+ * @param recipients — Array of recipients with basis points.
59
+ * Basis points must sum to exactly 10000 (100%).
60
+ * @throws Error if basis points don't sum to 10000 or any are negative.
61
+ */
62
+ constructor(recipients: SplitRecipient[]) {
63
+ if (recipients.length === 0) {
64
+ throw new Error('At least one recipient is required');
65
+ }
66
+
67
+ const sum = recipients.reduce((acc, r) => acc + r.basisPoints, 0);
68
+ if (sum !== TOTAL_BASIS_POINTS) {
69
+ throw new Error(
70
+ `Basis points must sum to ${TOTAL_BASIS_POINTS} (got ${sum})`
71
+ );
72
+ }
73
+
74
+ for (const r of recipients) {
75
+ if (r.basisPoints < 0) {
76
+ throw new Error(`Negative basis points for "${r.id}": ${r.basisPoints}`);
77
+ }
78
+ }
79
+
80
+ // Check for duplicate IDs
81
+ const ids = new Set(recipients.map(r => r.id));
82
+ if (ids.size !== recipients.length) {
83
+ throw new Error('Duplicate recipient IDs');
84
+ }
85
+
86
+ this.recipients = [...recipients];
87
+ }
88
+
89
+ /**
90
+ * Split an amount among recipients.
91
+ *
92
+ * Uses bigint arithmetic for exact splitting.
93
+ * Dust (remainder from integer division) goes to the first recipient.
94
+ *
95
+ * @param totalAmount — Total amount to split (in base units, e.g., USDC 6 decimals)
96
+ * @returns SplitResult with exact shares summing to totalAmount
97
+ */
98
+ split(totalAmount: bigint): SplitResult {
99
+ if (totalAmount < 0n) {
100
+ throw new Error('Cannot split negative amount');
101
+ }
102
+
103
+ const shares = new Map<string, bigint>();
104
+ const breakdown: SplitBreakdownEntry[] = [];
105
+ let allocated = 0n;
106
+
107
+ for (const recipient of this.recipients) {
108
+ const share = (totalAmount * BigInt(recipient.basisPoints)) / BigInt(TOTAL_BASIS_POINTS);
109
+ shares.set(recipient.id, share);
110
+ allocated += share;
111
+ breakdown.push({
112
+ recipientId: recipient.id,
113
+ basisPoints: recipient.basisPoints,
114
+ amount: share,
115
+ percentage: `${(recipient.basisPoints / 100).toFixed(2)}%`,
116
+ });
117
+ }
118
+
119
+ // Allocate dust to first recipient (sum invariant)
120
+ const dust = totalAmount - allocated;
121
+ if (dust > 0n) {
122
+ const firstId = this.recipients[0].id;
123
+ const current = shares.get(firstId)!;
124
+ shares.set(firstId, current + dust);
125
+ breakdown[0].amount = current + dust;
126
+ }
127
+
128
+ return { shares, total: totalAmount, dust, breakdown };
129
+ }
130
+
131
+ /**
132
+ * Split a numeric amount (convenience wrapper).
133
+ * Converts to bigint internally.
134
+ */
135
+ splitNumeric(totalAmount: number): SplitResult {
136
+ return this.split(BigInt(Math.floor(totalAmount)));
137
+ }
138
+
139
+ /**
140
+ * Get the configured recipients.
141
+ */
142
+ getRecipients(): readonly SplitRecipient[] {
143
+ return this.recipients;
144
+ }
145
+
146
+ /**
147
+ * Validate that a split result sums correctly.
148
+ */
149
+ static validate(result: SplitResult): boolean {
150
+ let sum = 0n;
151
+ for (const amount of result.shares.values()) {
152
+ sum += amount;
153
+ }
154
+ return sum === result.total;
155
+ }
156
+ }
@@ -0,0 +1,546 @@
1
+ /**
2
+ * SubscriptionManager — Recurring subscription lifecycle management
3
+ *
4
+ * Manages subscription states: create → renew → cancel → suspend → reactivate.
5
+ * Supports trial periods, grace periods on failed renewal, and links to
6
+ * X402PaymentGateway for recurring authorization.
7
+ *
8
+ * Part of HoloScript v5.8 "Live Economy".
9
+ *
10
+ * @version 1.0.0
11
+ */
12
+
13
+ import type { TelemetryCollector } from './_core-stubs';
14
+
15
+ // =============================================================================
16
+ // TYPES
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Subscription lifecycle state.
21
+ */
22
+ export type SubscriptionState =
23
+ | 'trial'
24
+ | 'active'
25
+ | 'past_due'
26
+ | 'suspended'
27
+ | 'cancelled'
28
+ | 'expired';
29
+
30
+ /**
31
+ * Billing interval.
32
+ */
33
+ export type BillingInterval = 'daily' | 'weekly' | 'monthly' | 'yearly';
34
+
35
+ /**
36
+ * A subscription record.
37
+ */
38
+ export interface Subscription {
39
+ /** Unique subscription ID */
40
+ id: string;
41
+ /** Subscriber (agent or user) ID */
42
+ subscriberId: string;
43
+ /** Plan ID */
44
+ planId: string;
45
+ /** Current state */
46
+ state: SubscriptionState;
47
+ /** Billing amount per period (USDC base units, 6 decimals) */
48
+ amount: number;
49
+ /** Billing interval */
50
+ interval: BillingInterval;
51
+ /** When the subscription was created (ISO 8601) */
52
+ createdAt: string;
53
+ /** Current period start (ISO 8601) */
54
+ currentPeriodStart: string;
55
+ /** Current period end (ISO 8601) */
56
+ currentPeriodEnd: string;
57
+ /** Trial end date (ISO 8601, null if no trial) */
58
+ trialEnd: string | null;
59
+ /** Whether currently in trial */
60
+ inTrial: boolean;
61
+ /** Number of failed renewal attempts */
62
+ failedRenewals: number;
63
+ /** Grace period end (ISO 8601, null if not in grace period) */
64
+ gracePeriodEnd: string | null;
65
+ /** When cancelled (ISO 8601, null if not cancelled) */
66
+ cancelledAt: string | null;
67
+ /** Cancel at period end (vs immediate) */
68
+ cancelAtPeriodEnd: boolean;
69
+ /** Metadata */
70
+ metadata?: Record<string, unknown>;
71
+ }
72
+
73
+ /**
74
+ * Subscription plan definition.
75
+ */
76
+ export interface SubscriptionPlan {
77
+ /** Plan ID */
78
+ id: string;
79
+ /** Plan name */
80
+ name: string;
81
+ /** Plan description */
82
+ description: string;
83
+ /** Billing amount per period (USDC base units) */
84
+ amount: number;
85
+ /** Billing interval */
86
+ interval: BillingInterval;
87
+ /** Trial duration in days (0 = no trial) */
88
+ trialDays: number;
89
+ /** Features included */
90
+ features: string[];
91
+ }
92
+
93
+ /**
94
+ * SubscriptionManager configuration.
95
+ */
96
+ export interface SubscriptionManagerConfig {
97
+ /** Grace period duration in days (default: 3) */
98
+ gracePeriodDays?: number;
99
+ /** Maximum failed renewals before suspension (default: 3) */
100
+ maxFailedRenewals?: number;
101
+ /** Telemetry collector */
102
+ telemetry?: TelemetryCollector;
103
+ }
104
+
105
+ /**
106
+ * Renewal result.
107
+ */
108
+ export interface RenewalResult {
109
+ /** Whether renewal succeeded */
110
+ success: boolean;
111
+ /** Updated subscription */
112
+ subscription: Subscription;
113
+ /** Error message if failed */
114
+ error?: string;
115
+ /** Whether grace period was entered */
116
+ enteredGracePeriod?: boolean;
117
+ }
118
+
119
+ // =============================================================================
120
+ // SUBSCRIPTION MANAGER
121
+ // =============================================================================
122
+
123
+ export class SubscriptionManager {
124
+ private config: Required<Omit<SubscriptionManagerConfig, 'telemetry'>> & {
125
+ telemetry?: TelemetryCollector;
126
+ };
127
+ private subscriptions: Map<string, Subscription> = new Map();
128
+ private plans: Map<string, SubscriptionPlan> = new Map();
129
+ private renewalCallback?: (subscriptionId: string, amount: number) => Promise<boolean>;
130
+ private subCounter = 0;
131
+
132
+ constructor(config?: SubscriptionManagerConfig) {
133
+ this.config = {
134
+ gracePeriodDays: config?.gracePeriodDays ?? 3,
135
+ maxFailedRenewals: config?.maxFailedRenewals ?? 3,
136
+ telemetry: config?.telemetry,
137
+ };
138
+ }
139
+
140
+ // ===========================================================================
141
+ // PLAN MANAGEMENT
142
+ // ===========================================================================
143
+
144
+ /**
145
+ * Register a subscription plan.
146
+ */
147
+ registerPlan(plan: SubscriptionPlan): void {
148
+ this.plans.set(plan.id, { ...plan });
149
+ }
150
+
151
+ /**
152
+ * Get a plan by ID.
153
+ */
154
+ getPlan(planId: string): SubscriptionPlan | undefined {
155
+ return this.plans.get(planId);
156
+ }
157
+
158
+ /**
159
+ * List all plans.
160
+ */
161
+ listPlans(): SubscriptionPlan[] {
162
+ return [...this.plans.values()];
163
+ }
164
+
165
+ // ===========================================================================
166
+ // LIFECYCLE: CREATE
167
+ // ===========================================================================
168
+
169
+ /**
170
+ * Create a new subscription.
171
+ */
172
+ create(subscriberId: string, planId: string, metadata?: Record<string, unknown>): Subscription {
173
+ const plan = this.plans.get(planId);
174
+ if (!plan) {
175
+ throw new Error(`Plan "${planId}" not found`);
176
+ }
177
+
178
+ const id = `sub-${++this.subCounter}`;
179
+ const now = new Date();
180
+ const hasTrial = plan.trialDays > 0;
181
+ const trialEnd = hasTrial
182
+ ? new Date(now.getTime() + plan.trialDays * 86400_000).toISOString()
183
+ : null;
184
+
185
+ const periodEnd = this.computePeriodEnd(now, plan.interval);
186
+
187
+ const subscription: Subscription = {
188
+ id,
189
+ subscriberId,
190
+ planId,
191
+ state: hasTrial ? 'trial' : 'active',
192
+ amount: plan.amount,
193
+ interval: plan.interval,
194
+ createdAt: now.toISOString(),
195
+ currentPeriodStart: now.toISOString(),
196
+ currentPeriodEnd: periodEnd.toISOString(),
197
+ trialEnd,
198
+ inTrial: hasTrial,
199
+ failedRenewals: 0,
200
+ gracePeriodEnd: null,
201
+ cancelledAt: null,
202
+ cancelAtPeriodEnd: false,
203
+ metadata,
204
+ };
205
+
206
+ this.subscriptions.set(id, subscription);
207
+ this.emitTelemetry('subscription_created', {
208
+ subscriptionId: id,
209
+ subscriberId,
210
+ planId,
211
+ state: subscription.state,
212
+ });
213
+
214
+ return subscription;
215
+ }
216
+
217
+ // ===========================================================================
218
+ // LIFECYCLE: RENEW
219
+ // ===========================================================================
220
+
221
+ /**
222
+ * Attempt to renew a subscription.
223
+ */
224
+ async renew(subscriptionId: string): Promise<RenewalResult> {
225
+ const sub = this.requireSubscription(subscriptionId);
226
+
227
+ if (sub.state === 'cancelled' || sub.state === 'expired') {
228
+ return {
229
+ success: false,
230
+ subscription: sub,
231
+ error: `Cannot renew ${sub.state} subscription`,
232
+ };
233
+ }
234
+
235
+ // Check if trial just ended
236
+ if (sub.inTrial && sub.trialEnd) {
237
+ const trialEndMs = new Date(sub.trialEnd).getTime();
238
+ if (Date.now() >= trialEndMs) {
239
+ sub.inTrial = false;
240
+ sub.state = 'active';
241
+ }
242
+ }
243
+
244
+ // Attempt payment
245
+ let paymentSuccess = true;
246
+ if (this.renewalCallback) {
247
+ try {
248
+ paymentSuccess = await this.renewalCallback(subscriptionId, sub.amount);
249
+ } catch {
250
+ paymentSuccess = false;
251
+ }
252
+ }
253
+
254
+ if (paymentSuccess) {
255
+ // Successful renewal
256
+ const now = new Date();
257
+ sub.currentPeriodStart = now.toISOString();
258
+ sub.currentPeriodEnd = this.computePeriodEnd(now, sub.interval).toISOString();
259
+ sub.state = 'active';
260
+ sub.failedRenewals = 0;
261
+ sub.gracePeriodEnd = null;
262
+
263
+ // Check if set to cancel at period end
264
+ if (sub.cancelAtPeriodEnd) {
265
+ sub.state = 'cancelled';
266
+ sub.cancelledAt = now.toISOString();
267
+ sub.cancelAtPeriodEnd = false;
268
+ this.emitTelemetry('subscription_cancelled_at_period_end', { subscriptionId });
269
+ return { success: true, subscription: sub };
270
+ }
271
+
272
+ this.emitTelemetry('subscription_renewed', { subscriptionId });
273
+ return { success: true, subscription: sub };
274
+ }
275
+
276
+ // Failed renewal
277
+ sub.failedRenewals++;
278
+
279
+ if (sub.failedRenewals >= this.config.maxFailedRenewals) {
280
+ sub.state = 'suspended';
281
+ this.emitTelemetry('subscription_suspended', {
282
+ subscriptionId,
283
+ failedRenewals: sub.failedRenewals,
284
+ });
285
+ return {
286
+ success: false,
287
+ subscription: sub,
288
+ error: `Subscription suspended after ${sub.failedRenewals} failed renewals`,
289
+ };
290
+ }
291
+
292
+ // Enter grace period
293
+ sub.state = 'past_due';
294
+ const gracePeriodEnd = new Date(
295
+ Date.now() + this.config.gracePeriodDays * 86400_000
296
+ ).toISOString();
297
+ sub.gracePeriodEnd = gracePeriodEnd;
298
+
299
+ this.emitTelemetry('subscription_renewal_failed', {
300
+ subscriptionId,
301
+ failedRenewals: sub.failedRenewals,
302
+ gracePeriodEnd,
303
+ });
304
+
305
+ return {
306
+ success: false,
307
+ subscription: sub,
308
+ error: `Renewal failed (attempt ${sub.failedRenewals}/${this.config.maxFailedRenewals})`,
309
+ enteredGracePeriod: true,
310
+ };
311
+ }
312
+
313
+ // ===========================================================================
314
+ // LIFECYCLE: CANCEL
315
+ // ===========================================================================
316
+
317
+ /**
318
+ * Cancel a subscription.
319
+ * @param immediate If true, cancel immediately; otherwise cancel at period end.
320
+ */
321
+ cancel(subscriptionId: string, immediate = false): Subscription {
322
+ const sub = this.requireSubscription(subscriptionId);
323
+
324
+ if (sub.state === 'cancelled' || sub.state === 'expired') {
325
+ throw new Error(`Subscription already ${sub.state}`);
326
+ }
327
+
328
+ if (immediate) {
329
+ sub.state = 'cancelled';
330
+ sub.cancelledAt = new Date().toISOString();
331
+ sub.cancelAtPeriodEnd = false;
332
+ } else {
333
+ sub.cancelAtPeriodEnd = true;
334
+ }
335
+
336
+ this.emitTelemetry('subscription_cancel_requested', {
337
+ subscriptionId,
338
+ immediate,
339
+ });
340
+
341
+ return sub;
342
+ }
343
+
344
+ // ===========================================================================
345
+ // LIFECYCLE: SUSPEND / REACTIVATE
346
+ // ===========================================================================
347
+
348
+ /**
349
+ * Suspend a subscription (e.g., after payment failures).
350
+ */
351
+ suspend(subscriptionId: string): Subscription {
352
+ const sub = this.requireSubscription(subscriptionId);
353
+ sub.state = 'suspended';
354
+ this.emitTelemetry('subscription_suspended', { subscriptionId });
355
+ return sub;
356
+ }
357
+
358
+ /**
359
+ * Reactivate a suspended or cancelled subscription.
360
+ */
361
+ reactivate(subscriptionId: string): Subscription {
362
+ const sub = this.requireSubscription(subscriptionId);
363
+
364
+ if (sub.state !== 'suspended' && sub.state !== 'cancelled' && sub.state !== 'past_due') {
365
+ throw new Error(`Cannot reactivate subscription in state: ${sub.state}`);
366
+ }
367
+
368
+ const now = new Date();
369
+ sub.state = 'active';
370
+ sub.failedRenewals = 0;
371
+ sub.gracePeriodEnd = null;
372
+ sub.cancelledAt = null;
373
+ sub.cancelAtPeriodEnd = false;
374
+ sub.currentPeriodStart = now.toISOString();
375
+ sub.currentPeriodEnd = this.computePeriodEnd(now, sub.interval).toISOString();
376
+
377
+ this.emitTelemetry('subscription_reactivated', { subscriptionId });
378
+ return sub;
379
+ }
380
+
381
+ // ===========================================================================
382
+ // RENEWAL CALLBACK
383
+ // ===========================================================================
384
+
385
+ /**
386
+ * Set callback for renewal payment processing.
387
+ * Should return true if payment succeeded.
388
+ */
389
+ onRenewal(callback: (subscriptionId: string, amount: number) => Promise<boolean>): void {
390
+ this.renewalCallback = callback;
391
+ }
392
+
393
+ // ===========================================================================
394
+ // QUERIES
395
+ // ===========================================================================
396
+
397
+ /**
398
+ * Get a subscription by ID.
399
+ */
400
+ getSubscription(id: string): Subscription | undefined {
401
+ return this.subscriptions.get(id);
402
+ }
403
+
404
+ /**
405
+ * Get all subscriptions for a subscriber.
406
+ */
407
+ getSubscriberSubscriptions(subscriberId: string): Subscription[] {
408
+ return [...this.subscriptions.values()].filter((s) => s.subscriberId === subscriberId);
409
+ }
410
+
411
+ /**
412
+ * Get subscriptions by state.
413
+ */
414
+ getByState(state: SubscriptionState): Subscription[] {
415
+ return [...this.subscriptions.values()].filter((s) => s.state === state);
416
+ }
417
+
418
+ /**
419
+ * Get subscriptions due for renewal.
420
+ */
421
+ getDueForRenewal(): Subscription[] {
422
+ const now = Date.now();
423
+ return [...this.subscriptions.values()].filter((s) => {
424
+ if (s.state === 'cancelled' || s.state === 'expired' || s.state === 'suspended') {
425
+ return false;
426
+ }
427
+ return new Date(s.currentPeriodEnd).getTime() <= now;
428
+ });
429
+ }
430
+
431
+ /**
432
+ * Get subscriptions in grace period.
433
+ */
434
+ getInGracePeriod(): Subscription[] {
435
+ return [...this.subscriptions.values()].filter(
436
+ (s) => s.state === 'past_due' && s.gracePeriodEnd !== null
437
+ );
438
+ }
439
+
440
+ /**
441
+ * Check if grace period has expired for past_due subscriptions.
442
+ */
443
+ processExpiredGracePeriods(): Subscription[] {
444
+ const now = Date.now();
445
+ const expired: Subscription[] = [];
446
+
447
+ for (const sub of this.subscriptions.values()) {
448
+ if (sub.state === 'past_due' && sub.gracePeriodEnd) {
449
+ if (new Date(sub.gracePeriodEnd).getTime() <= now) {
450
+ sub.state = 'suspended';
451
+ sub.gracePeriodEnd = null;
452
+ expired.push(sub);
453
+ this.emitTelemetry('subscription_grace_expired', { subscriptionId: sub.id });
454
+ }
455
+ }
456
+ }
457
+
458
+ return expired;
459
+ }
460
+
461
+ /**
462
+ * Get stats.
463
+ */
464
+ getStats(): {
465
+ total: number;
466
+ byState: Record<string, number>;
467
+ totalMRR: number; // Monthly Recurring Revenue (USDC base units)
468
+ planCount: number;
469
+ } {
470
+ const byState: Record<string, number> = {};
471
+ let totalMRR = 0;
472
+
473
+ for (const sub of this.subscriptions.values()) {
474
+ byState[sub.state] = (byState[sub.state] || 0) + 1;
475
+
476
+ if (sub.state === 'active' || sub.state === 'trial') {
477
+ totalMRR += this.normalizeToMonthly(sub.amount, sub.interval);
478
+ }
479
+ }
480
+
481
+ return {
482
+ total: this.subscriptions.size,
483
+ byState,
484
+ totalMRR,
485
+ planCount: this.plans.size,
486
+ };
487
+ }
488
+
489
+ /**
490
+ * Total subscription count.
491
+ */
492
+ getSubscriptionCount(): number {
493
+ return this.subscriptions.size;
494
+ }
495
+
496
+ // ===========================================================================
497
+ // INTERNALS
498
+ // ===========================================================================
499
+
500
+ private requireSubscription(id: string): Subscription {
501
+ const sub = this.subscriptions.get(id);
502
+ if (!sub) throw new Error(`Subscription "${id}" not found`);
503
+ return sub;
504
+ }
505
+
506
+ private computePeriodEnd(start: Date, interval: BillingInterval): Date {
507
+ const end = new Date(start);
508
+ switch (interval) {
509
+ case 'daily':
510
+ end.setDate(end.getDate() + 1);
511
+ break;
512
+ case 'weekly':
513
+ end.setDate(end.getDate() + 7);
514
+ break;
515
+ case 'monthly':
516
+ end.setMonth(end.getMonth() + 1);
517
+ break;
518
+ case 'yearly':
519
+ end.setFullYear(end.getFullYear() + 1);
520
+ break;
521
+ }
522
+ return end;
523
+ }
524
+
525
+ private normalizeToMonthly(amount: number, interval: BillingInterval): number {
526
+ switch (interval) {
527
+ case 'daily':
528
+ return amount * 30;
529
+ case 'weekly':
530
+ return amount * 4;
531
+ case 'monthly':
532
+ return amount;
533
+ case 'yearly':
534
+ return Math.floor(amount / 12);
535
+ }
536
+ }
537
+
538
+ private emitTelemetry(type: string, data?: Record<string, unknown>): void {
539
+ this.config.telemetry?.record({
540
+ type,
541
+ severity: type.includes('failed') || type.includes('suspended') ? 'warning' : 'info',
542
+ agentId: 'subscription-manager',
543
+ data,
544
+ });
545
+ }
546
+ }