@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.
- package/ALL-test-results.json +1 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/ROADMAP.md +175 -0
- package/dist/AgentManifest-CB4xM-Ma.d.cts +704 -0
- package/dist/AgentManifest-CB4xM-Ma.d.ts +704 -0
- package/dist/BehaviorTree-BrBFECv5.d.cts +103 -0
- package/dist/BehaviorTree-BrBFECv5.d.ts +103 -0
- package/dist/InvisibleWallet-BB6tFvRA.d.cts +1732 -0
- package/dist/InvisibleWallet-rtRrBOA8.d.ts +1732 -0
- package/dist/OrchestratorAgent-BvWgf9uw.d.cts +798 -0
- package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +798 -0
- package/dist/agents/index.cjs +4790 -0
- package/dist/agents/index.d.cts +1788 -0
- package/dist/agents/index.d.ts +1788 -0
- package/dist/agents/index.js +4695 -0
- package/dist/ai/index.cjs +5347 -0
- package/dist/ai/index.d.cts +1753 -0
- package/dist/ai/index.d.ts +1753 -0
- package/dist/ai/index.js +5244 -0
- package/dist/behavior.cjs +449 -0
- package/dist/behavior.d.cts +130 -0
- package/dist/behavior.d.ts +130 -0
- package/dist/behavior.js +407 -0
- package/dist/economy/index.cjs +3659 -0
- package/dist/economy/index.d.cts +747 -0
- package/dist/economy/index.d.ts +747 -0
- package/dist/economy/index.js +3617 -0
- package/dist/implementations-D9T3un9D.d.cts +236 -0
- package/dist/implementations-D9T3un9D.d.ts +236 -0
- package/dist/index.cjs +24550 -0
- package/dist/index.d.cts +1729 -0
- package/dist/index.d.ts +1729 -0
- package/dist/index.js +24277 -0
- package/dist/learning/index.cjs +219 -0
- package/dist/learning/index.d.cts +104 -0
- package/dist/learning/index.d.ts +104 -0
- package/dist/learning/index.js +189 -0
- package/dist/negotiation/index.cjs +970 -0
- package/dist/negotiation/index.d.cts +610 -0
- package/dist/negotiation/index.d.ts +610 -0
- package/dist/negotiation/index.js +931 -0
- package/dist/skills/index.cjs +1118 -0
- package/dist/skills/index.d.cts +289 -0
- package/dist/skills/index.d.ts +289 -0
- package/dist/skills/index.js +1079 -0
- package/dist/swarm/index.cjs +5268 -0
- package/dist/swarm/index.d.cts +2433 -0
- package/dist/swarm/index.d.ts +2433 -0
- package/dist/swarm/index.js +5221 -0
- package/dist/training/index.cjs +2745 -0
- package/dist/training/index.d.cts +1734 -0
- package/dist/training/index.d.ts +1734 -0
- package/dist/training/index.js +2687 -0
- package/extract-failures.js +10 -0
- package/package.json +82 -0
- package/src/__tests__/bounty-marketplace.test.ts +374 -0
- package/src/__tests__/delegation.test.ts +144 -0
- package/src/__tests__/distributed-claimer.test.ts +147 -0
- package/src/__tests__/done-log-audit.test.ts +342 -0
- package/src/__tests__/framework.test.ts +865 -0
- package/src/__tests__/goal-synthesizer.test.ts +236 -0
- package/src/__tests__/presence.test.ts +223 -0
- package/src/__tests__/protocol-agent.test.ts +254 -0
- package/src/__tests__/revenue-splitter.test.ts +114 -0
- package/src/__tests__/scenario-driven-todo.test.ts +197 -0
- package/src/__tests__/self-improve.test.ts +349 -0
- package/src/__tests__/service-lifecycle.test.ts +237 -0
- package/src/__tests__/skill-router.test.ts +121 -0
- package/src/agents/AgentManifest.ts +493 -0
- package/src/agents/AgentRegistry.ts +475 -0
- package/src/agents/AgentTypes.ts +585 -0
- package/src/agents/AgentWalletRegistry.ts +83 -0
- package/src/agents/AuthenticatedCRDT.ts +388 -0
- package/src/agents/CapabilityMatcher.ts +453 -0
- package/src/agents/CrossRealityHandoff.ts +305 -0
- package/src/agents/CulturalMemory.ts +454 -0
- package/src/agents/FederatedRegistryAdapter.ts +429 -0
- package/src/agents/NormEngine.ts +450 -0
- package/src/agents/OrchestratorAgent.ts +414 -0
- package/src/agents/SkillWorkflowEngine.ts +472 -0
- package/src/agents/TaskDelegationService.ts +551 -0
- package/src/agents/__tests__/AgentManifest.prod.test.ts +134 -0
- package/src/agents/__tests__/AgentManifest.test.ts +182 -0
- package/src/agents/__tests__/AgentModule.test.ts +864 -0
- package/src/agents/__tests__/AgentRegistry.prod.test.ts +125 -0
- package/src/agents/__tests__/AgentRegistry.test.ts +148 -0
- package/src/agents/__tests__/AgentTypes.test.ts +534 -0
- package/src/agents/__tests__/AgentWalletRegistry.test.ts +152 -0
- package/src/agents/__tests__/AuthenticatedCRDT.test.ts +558 -0
- package/src/agents/__tests__/CapabilityMatcher.prod.test.ts +117 -0
- package/src/agents/__tests__/CapabilityMatcher.test.ts +178 -0
- package/src/agents/__tests__/CrossRealityHandoff.test.ts +402 -0
- package/src/agents/__tests__/CulturalMemory.test.ts +200 -0
- package/src/agents/__tests__/FederatedRegistryAdapter.test.ts +409 -0
- package/src/agents/__tests__/NormEngine.test.ts +276 -0
- package/src/agents/__tests__/OrchestratorAgent.test.ts +182 -0
- package/src/agents/__tests__/SkillWorkflowEngine.test.ts +357 -0
- package/src/agents/__tests__/TaskDelegationService.test.ts +446 -0
- package/src/agents/index.ts +107 -0
- package/src/agents/spatial-comms/Layer1RealTime.ts +621 -0
- package/src/agents/spatial-comms/Layer2A2A.ts +661 -0
- package/src/agents/spatial-comms/Layer3MCP.ts +651 -0
- package/src/agents/spatial-comms/ProtocolTypes.ts +543 -0
- package/src/agents/spatial-comms/SpatialCommClient.ts +483 -0
- package/src/agents/spatial-comms/__tests__/performance-benchmark.test.ts +465 -0
- package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +409 -0
- package/src/agents/spatial-comms/index.ts +66 -0
- package/src/ai/AIAdapter.ts +313 -0
- package/src/ai/AICopilot.ts +331 -0
- package/src/ai/AIOutputValidator.ts +203 -0
- package/src/ai/BTNodes.ts +239 -0
- package/src/ai/BehaviorSelector.ts +135 -0
- package/src/ai/BehaviorTree.ts +153 -0
- package/src/ai/Blackboard.ts +165 -0
- package/src/ai/GenerationAnalytics.ts +461 -0
- package/src/ai/GenerationCache.ts +265 -0
- package/src/ai/GoalPlanner.ts +165 -0
- package/src/ai/HoloScriptGenerator.ts +580 -0
- package/src/ai/InfluenceMap.ts +180 -0
- package/src/ai/NavMesh.ts +168 -0
- package/src/ai/PerceptionSystem.ts +178 -0
- package/src/ai/PromptTemplates.ts +453 -0
- package/src/ai/SemanticSearchService.ts +80 -0
- package/src/ai/StateMachine.ts +196 -0
- package/src/ai/SteeringBehavior.ts +150 -0
- package/src/ai/SteeringBehaviors.ts +244 -0
- package/src/ai/TrainingDataGenerator.ts +1082 -0
- package/src/ai/UtilityAI.ts +145 -0
- package/src/ai/__tests__/AIAdapter.prod.test.ts +259 -0
- package/src/ai/__tests__/AIAdapter.test.ts +109 -0
- package/src/ai/__tests__/AICopilot.prod.test.ts +341 -0
- package/src/ai/__tests__/AICopilot.test.ts +178 -0
- package/src/ai/__tests__/AIOutputValidator.prod.test.ts +226 -0
- package/src/ai/__tests__/AIOutputValidator.test.ts +138 -0
- package/src/ai/__tests__/BTNodes.prod.test.ts +391 -0
- package/src/ai/__tests__/BTNodes.test.ts +263 -0
- package/src/ai/__tests__/BehaviorSelector.prod.test.ts +129 -0
- package/src/ai/__tests__/BehaviorSelector.test.ts +132 -0
- package/src/ai/__tests__/BehaviorTree.prod.test.ts +266 -0
- package/src/ai/__tests__/BehaviorTree.test.ts +216 -0
- package/src/ai/__tests__/Blackboard.prod.test.ts +339 -0
- package/src/ai/__tests__/Blackboard.test.ts +183 -0
- package/src/ai/__tests__/GenerationAnalytics.prod.test.ts +141 -0
- package/src/ai/__tests__/GenerationAnalytics.test.ts +165 -0
- package/src/ai/__tests__/GenerationCache.prod.test.ts +144 -0
- package/src/ai/__tests__/GenerationCache.test.ts +171 -0
- package/src/ai/__tests__/GoalPlanner.prod.test.ts +189 -0
- package/src/ai/__tests__/GoalPlanner.test.ts +137 -0
- package/src/ai/__tests__/GoalPlannerDepth.prod.test.ts +217 -0
- package/src/ai/__tests__/HoloScriptGenerator.test.ts +125 -0
- package/src/ai/__tests__/InfluenceMap.prod.test.ts +146 -0
- package/src/ai/__tests__/InfluenceMap.test.ts +149 -0
- package/src/ai/__tests__/NavMesh.prod.test.ts +141 -0
- package/src/ai/__tests__/NavMesh.test.ts +159 -0
- package/src/ai/__tests__/PerceptionSystem.prod.test.ts +135 -0
- package/src/ai/__tests__/PerceptionSystem.test.ts +250 -0
- package/src/ai/__tests__/PromptTemplates.prod.test.ts +313 -0
- package/src/ai/__tests__/PromptTemplates.test.ts +146 -0
- package/src/ai/__tests__/SemanticSearch.test.ts +37 -0
- package/src/ai/__tests__/StateMachine.prod.test.ts +162 -0
- package/src/ai/__tests__/StateMachine.test.ts +163 -0
- package/src/ai/__tests__/SteeringBehavior.prod.test.ts +251 -0
- package/src/ai/__tests__/SteeringBehavior.test.ts +135 -0
- package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +133 -0
- package/src/ai/__tests__/SteeringBehaviors.test.ts +151 -0
- package/src/ai/__tests__/TrainingDataGenerator.prod.test.ts +286 -0
- package/src/ai/__tests__/TrainingDataGenerator.test.ts +286 -0
- package/src/ai/__tests__/UtilityAI.prod.test.ts +207 -0
- package/src/ai/__tests__/UtilityAI.test.ts +155 -0
- package/src/ai/__tests__/adapters.prod.test.ts +263 -0
- package/src/ai/__tests__/adapters.test.ts +320 -0
- package/src/ai/adapters.ts +1585 -0
- package/src/ai/index.ts +130 -0
- package/src/behavior/BehaviorPresets.ts +140 -0
- package/src/behavior/BehaviorTree.ts +236 -0
- package/src/behavior/StateMachine.ts +176 -0
- package/src/behavior/StateTrait.ts +67 -0
- package/src/behavior/index.ts +8 -0
- package/src/behavior.ts +8 -0
- package/src/board/audit.ts +284 -0
- package/src/board/board-ops.ts +336 -0
- package/src/board/board-types.ts +302 -0
- package/src/board/index.ts +69 -0
- package/src/define-agent.ts +46 -0
- package/src/define-team.ts +33 -0
- package/src/delegation.ts +265 -0
- package/src/distributed-claimer.ts +228 -0
- package/src/economy/AgentBudgetEnforcer.ts +464 -0
- package/src/economy/BountyManager.ts +185 -0
- package/src/economy/CreatorRevenueAggregator.ts +460 -0
- package/src/economy/InvisibleWallet.ts +82 -0
- package/src/economy/KnowledgeMarketplace.ts +193 -0
- package/src/economy/PaymentWebhookService.ts +512 -0
- package/src/economy/RevenueSplitter.ts +156 -0
- package/src/economy/SubscriptionManager.ts +546 -0
- package/src/economy/UnifiedBudgetOptimizer.ts +635 -0
- package/src/economy/UsageMeter.ts +440 -0
- package/src/economy/_core-stubs.ts +219 -0
- package/src/economy/index.ts +100 -0
- package/src/economy/x402-facilitator.ts +1978 -0
- package/src/index.ts +348 -0
- package/src/knowledge/__tests__/knowledge-consolidator.test.ts +444 -0
- package/src/knowledge/__tests__/knowledge-store-vector.test.ts +291 -0
- package/src/knowledge/brain.ts +167 -0
- package/src/knowledge/consolidation.ts +581 -0
- package/src/knowledge/knowledge-consolidator.ts +510 -0
- package/src/knowledge/knowledge-store.ts +616 -0
- package/src/learning/MemoryConsolidator.ts +102 -0
- package/src/learning/MemoryScorer.ts +69 -0
- package/src/learning/ProceduralCompiler.ts +45 -0
- package/src/learning/SemanticClusterer.ts +66 -0
- package/src/learning/index.ts +8 -0
- package/src/llm/llm-adapter.ts +159 -0
- package/src/mesh/index.ts +309 -0
- package/src/negotiation/NegotiationProtocol.ts +694 -0
- package/src/negotiation/NegotiationTypes.ts +473 -0
- package/src/negotiation/VotingMechanisms.ts +691 -0
- package/src/negotiation/index.ts +49 -0
- package/src/protocol/goal-synthesizer.ts +317 -0
- package/src/protocol/implementations.ts +474 -0
- package/src/protocol/micro-phase-decomposer.ts +299 -0
- package/src/protocol/micro-step-decomposer.test.ts +306 -0
- package/src/protocol-agent.test.ts +353 -0
- package/src/protocol-agent.ts +670 -0
- package/src/self-improve/absorb-scanner.ts +252 -0
- package/src/self-improve/evolution-engine.ts +149 -0
- package/src/self-improve/framework-absorber.ts +214 -0
- package/src/self-improve/index.ts +50 -0
- package/src/self-improve/prompt-optimizer.ts +212 -0
- package/src/self-improve/test-generator.ts +175 -0
- package/src/skill-router.ts +186 -0
- package/src/skills/index.ts +5 -0
- package/src/skills/skill-md-bridge.ts +1699 -0
- package/src/swarm/ACOEngine.ts +261 -0
- package/src/swarm/CollectiveIntelligence.ts +383 -0
- package/src/swarm/ContributionSynthesizer.ts +481 -0
- package/src/swarm/LeaderElection.ts +393 -0
- package/src/swarm/PSOEngine.ts +206 -0
- package/src/swarm/QuorumPolicy.ts +173 -0
- package/src/swarm/SwarmCoordinator.ts +335 -0
- package/src/swarm/SwarmManager.ts +442 -0
- package/src/swarm/SwarmMembership.ts +456 -0
- package/src/swarm/VotingRound.ts +255 -0
- package/src/swarm/__tests__/ACOEngine.prod.test.ts +164 -0
- package/src/swarm/__tests__/ACOEngine.test.ts +117 -0
- package/src/swarm/__tests__/CollectiveIntelligence.prod.test.ts +296 -0
- package/src/swarm/__tests__/CollectiveIntelligence.test.ts +457 -0
- package/src/swarm/__tests__/ContributionSynthesizer.prod.test.ts +269 -0
- package/src/swarm/__tests__/ContributionSynthesizer.test.ts +254 -0
- package/src/swarm/__tests__/LeaderElection.prod.test.ts +196 -0
- package/src/swarm/__tests__/LeaderElection.test.ts +151 -0
- package/src/swarm/__tests__/PSOEngine.prod.test.ts +162 -0
- package/src/swarm/__tests__/PSOEngine.test.ts +106 -0
- package/src/swarm/__tests__/QuorumPolicy.prod.test.ts +216 -0
- package/src/swarm/__tests__/QuorumPolicy.test.ts +177 -0
- package/src/swarm/__tests__/SwarmCoordinator.prod.test.ts +186 -0
- package/src/swarm/__tests__/SwarmCoordinator.test.ts +167 -0
- package/src/swarm/__tests__/SwarmManager.prod.test.ts +308 -0
- package/src/swarm/__tests__/SwarmManager.test.ts +373 -0
- package/src/swarm/__tests__/SwarmMembership.prod.test.ts +273 -0
- package/src/swarm/__tests__/SwarmMembership.test.ts +264 -0
- package/src/swarm/__tests__/VotingRound.prod.test.ts +233 -0
- package/src/swarm/__tests__/VotingRound.test.ts +174 -0
- package/src/swarm/analytics/SwarmInspector.ts +476 -0
- package/src/swarm/analytics/SwarmMetrics.ts +449 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.prod.test.ts +366 -0
- package/src/swarm/analytics/__tests__/SwarmInspector.test.ts +454 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.prod.test.ts +254 -0
- package/src/swarm/analytics/__tests__/SwarmMetrics.test.ts +370 -0
- package/src/swarm/analytics/index.ts +7 -0
- package/src/swarm/index.ts +69 -0
- package/src/swarm/messaging/BroadcastChannel.ts +509 -0
- package/src/swarm/messaging/GossipProtocol.ts +565 -0
- package/src/swarm/messaging/SwarmEventBus.ts +443 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +331 -0
- package/src/swarm/messaging/__tests__/BroadcastChannel.test.ts +333 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +356 -0
- package/src/swarm/messaging/__tests__/GossipProtocol.test.ts +437 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +191 -0
- package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +247 -0
- package/src/swarm/messaging/index.ts +8 -0
- package/src/swarm/spatial/FlockingBehavior.ts +462 -0
- package/src/swarm/spatial/FormationController.ts +500 -0
- package/src/swarm/spatial/Vector3.ts +170 -0
- package/src/swarm/spatial/ZoneClaiming.ts +509 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.prod.test.ts +239 -0
- package/src/swarm/spatial/__tests__/FlockingBehavior.test.ts +298 -0
- package/src/swarm/spatial/__tests__/FormationController.prod.test.ts +240 -0
- package/src/swarm/spatial/__tests__/FormationController.test.ts +297 -0
- package/src/swarm/spatial/__tests__/Vector3.prod.test.ts +283 -0
- package/src/swarm/spatial/__tests__/Vector3.test.ts +224 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.prod.test.ts +246 -0
- package/src/swarm/spatial/__tests__/ZoneClaiming.test.ts +374 -0
- package/src/swarm/spatial/index.ts +28 -0
- package/src/team.ts +1245 -0
- package/src/training/LRScheduler.ts +377 -0
- package/src/training/QualityScoringPipeline.ts +139 -0
- package/src/training/SoftDedup.ts +461 -0
- package/src/training/SparsityMonitor.ts +685 -0
- package/src/training/SparsityMonitorTypes.ts +209 -0
- package/src/training/SpatialTrainingDataGenerator.ts +1526 -0
- package/src/training/SpatialTrainingDataTypes.ts +216 -0
- package/src/training/TrainingPipelineConfig.ts +215 -0
- package/src/training/constants.ts +94 -0
- package/src/training/index.ts +138 -0
- package/src/training/schema.ts +147 -0
- package/src/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
- package/src/training/scripts/generate-spatial-dataset.ts +521 -0
- package/src/training/training/data/novel-use-cases.jsonl +153 -0
- package/src/training/training/data/spatial-reasoning-10k.jsonl +9354 -0
- package/src/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
- package/src/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
- package/src/training/trainingmonkey/index.ts +26 -0
- package/src/training/trait-mappings.ts +157 -0
- package/src/types/core-stubs.d.ts +113 -0
- package/src/types.ts +304 -0
- package/test-output.txt +0 -0
- package/test-result.json +1 -0
- package/tsc-errors.txt +4 -0
- package/tsc_output.txt +0 -0
- package/tsconfig.json +14 -0
- package/tsup-learning-esm.config.ts +12 -0
- package/tsup.config.ts +21 -0
- package/typescript-errors-2.txt +0 -0
- package/typescript-errors.txt +22 -0
- package/vitest-log-utf8.txt +268 -0
- package/vitest-log.txt +0 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const res = JSON.parse(fs.readFileSync('test-result.json', 'utf8'));
|
|
3
|
+
const fails = res.testResults.flatMap(tr =>
|
|
4
|
+
tr.assertionResults.filter(a => a.status === 'failed').map(f => ({
|
|
5
|
+
file: tr.name,
|
|
6
|
+
title: f.title,
|
|
7
|
+
msg: f.failureMessages
|
|
8
|
+
}))
|
|
9
|
+
);
|
|
10
|
+
console.log(JSON.stringify(fails, null, 2));
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@holoscript/framework",
|
|
3
|
+
"version": "6.0.3",
|
|
4
|
+
"description": "The framework where agents remember, learn, and earn. Knowledge-compounding team orchestration.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./bt": {
|
|
15
|
+
"import": "./dist/behavior.js",
|
|
16
|
+
"require": "./dist/behavior.cjs",
|
|
17
|
+
"types": "./dist/behavior.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./agents": {
|
|
20
|
+
"import": "./dist/agents/index.js",
|
|
21
|
+
"require": "./dist/agents/index.cjs",
|
|
22
|
+
"types": "./dist/agents/index.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./economy": {
|
|
25
|
+
"import": "./dist/economy/index.js",
|
|
26
|
+
"require": "./dist/economy/index.cjs",
|
|
27
|
+
"types": "./dist/economy/index.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"./swarm": {
|
|
30
|
+
"import": "./dist/swarm/index.js",
|
|
31
|
+
"require": "./dist/swarm/index.cjs",
|
|
32
|
+
"types": "./dist/swarm/index.d.ts"
|
|
33
|
+
},
|
|
34
|
+
"./ai": {
|
|
35
|
+
"import": "./dist/ai/index.js",
|
|
36
|
+
"require": "./dist/ai/index.cjs",
|
|
37
|
+
"types": "./dist/ai/index.d.ts"
|
|
38
|
+
},
|
|
39
|
+
"./training": {
|
|
40
|
+
"import": "./dist/training/index.js",
|
|
41
|
+
"require": "./dist/training/index.cjs",
|
|
42
|
+
"types": "./dist/training/index.d.ts"
|
|
43
|
+
},
|
|
44
|
+
"./learning": {
|
|
45
|
+
"import": "./dist/learning/index.js",
|
|
46
|
+
"require": "./dist/learning/index.cjs",
|
|
47
|
+
"types": "./dist/learning/index.d.ts"
|
|
48
|
+
},
|
|
49
|
+
"./skills": {
|
|
50
|
+
"import": "./dist/skills/index.js",
|
|
51
|
+
"require": "./dist/skills/index.cjs",
|
|
52
|
+
"types": "./dist/skills/index.d.ts"
|
|
53
|
+
},
|
|
54
|
+
"./negotiation": {
|
|
55
|
+
"import": "./dist/negotiation/index.js",
|
|
56
|
+
"require": "./dist/negotiation/index.cjs",
|
|
57
|
+
"types": "./dist/negotiation/index.d.ts"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"keywords": [
|
|
61
|
+
"holoscript",
|
|
62
|
+
"agent",
|
|
63
|
+
"framework",
|
|
64
|
+
"multi-agent",
|
|
65
|
+
"knowledge",
|
|
66
|
+
"mcp"
|
|
67
|
+
],
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"@holoscript/core": "6.0.3"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"tsup": "^8.0.0",
|
|
74
|
+
"typescript": "^5.7.0",
|
|
75
|
+
"vitest": "^3.2.4"
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"build": "tsup",
|
|
79
|
+
"test": "vitest run --passWithNoTests",
|
|
80
|
+
"test:watch": "vitest"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { BountyManager } from '../economy/BountyManager';
|
|
3
|
+
import { KnowledgeMarketplace } from '../economy/KnowledgeMarketplace';
|
|
4
|
+
import { KnowledgeStore } from '../knowledge/knowledge-store';
|
|
5
|
+
import type { StoredEntry } from '../knowledge/knowledge-store';
|
|
6
|
+
import { defineAgent } from '../define-agent';
|
|
7
|
+
import { Team } from '../team';
|
|
8
|
+
|
|
9
|
+
// ── BountyManager ──
|
|
10
|
+
|
|
11
|
+
describe('BountyManager', () => {
|
|
12
|
+
it('creates a bounty', () => {
|
|
13
|
+
const mgr = new BountyManager();
|
|
14
|
+
const bounty = mgr.createBounty('task-1', { amount: 5, currency: 'USDC' }, 'alice');
|
|
15
|
+
expect(bounty.id).toMatch(/^bounty_/);
|
|
16
|
+
expect(bounty.taskId).toBe('task-1');
|
|
17
|
+
expect(bounty.status).toBe('open');
|
|
18
|
+
expect(bounty.reward.amount).toBe(5);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('rejects zero or negative reward', () => {
|
|
22
|
+
const mgr = new BountyManager();
|
|
23
|
+
expect(() => mgr.createBounty('t1', { amount: 0, currency: 'credits' }, 'a')).toThrow('positive');
|
|
24
|
+
expect(() => mgr.createBounty('t1', { amount: -1, currency: 'credits' }, 'a')).toThrow('positive');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('claims an open bounty', () => {
|
|
28
|
+
const mgr = new BountyManager();
|
|
29
|
+
const bounty = mgr.createBounty('task-1', { amount: 1, currency: 'credits' }, 'alice');
|
|
30
|
+
const result = mgr.claimBounty(bounty.id, 'bob');
|
|
31
|
+
expect(result.success).toBe(true);
|
|
32
|
+
expect(mgr.getBounty(bounty.id)?.status).toBe('claimed');
|
|
33
|
+
expect(mgr.getBounty(bounty.id)?.claimedBy).toBe('bob');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('rejects claiming a non-open bounty', () => {
|
|
37
|
+
const mgr = new BountyManager();
|
|
38
|
+
const bounty = mgr.createBounty('task-1', { amount: 1, currency: 'credits' }, 'alice');
|
|
39
|
+
mgr.claimBounty(bounty.id, 'bob');
|
|
40
|
+
const result = mgr.claimBounty(bounty.id, 'charlie');
|
|
41
|
+
expect(result.success).toBe(false);
|
|
42
|
+
expect(result.error).toContain('claimed');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('rejects claiming an expired bounty', () => {
|
|
46
|
+
const mgr = new BountyManager();
|
|
47
|
+
// Deadline in the past
|
|
48
|
+
const bounty = mgr.createBounty('task-1', { amount: 1, currency: 'credits' }, 'alice', Date.now() - 1000);
|
|
49
|
+
const result = mgr.claimBounty(bounty.id, 'bob');
|
|
50
|
+
expect(result.success).toBe(false);
|
|
51
|
+
expect(result.error).toContain('expired');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('completes a claimed bounty with proof', () => {
|
|
55
|
+
const mgr = new BountyManager();
|
|
56
|
+
const bounty = mgr.createBounty('task-1', { amount: 0.05, currency: 'USDC' }, 'alice');
|
|
57
|
+
mgr.claimBounty(bounty.id, 'bob');
|
|
58
|
+
const payout = mgr.completeBounty(bounty.id, { summary: 'Fixed the bug', commitHash: 'abc123' });
|
|
59
|
+
expect(payout.success).toBe(true);
|
|
60
|
+
expect(payout.amount).toBe(0.05);
|
|
61
|
+
expect(payout.settlement).toBe('ledger'); // < 0.10 USDC = ledger
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('uses on_chain settlement for larger USDC amounts', () => {
|
|
65
|
+
const mgr = new BountyManager();
|
|
66
|
+
const bounty = mgr.createBounty('task-1', { amount: 5, currency: 'USDC' }, 'alice');
|
|
67
|
+
mgr.claimBounty(bounty.id, 'bob');
|
|
68
|
+
const payout = mgr.completeBounty(bounty.id, { summary: 'Shipped feature' });
|
|
69
|
+
expect(payout.settlement).toBe('on_chain');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('uses ledger settlement for credits', () => {
|
|
73
|
+
const mgr = new BountyManager();
|
|
74
|
+
const bounty = mgr.createBounty('task-1', { amount: 100, currency: 'credits' }, 'alice');
|
|
75
|
+
mgr.claimBounty(bounty.id, 'bob');
|
|
76
|
+
const payout = mgr.completeBounty(bounty.id, { summary: 'Done' });
|
|
77
|
+
expect(payout.settlement).toBe('ledger');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('rejects completion without summary', () => {
|
|
81
|
+
const mgr = new BountyManager();
|
|
82
|
+
const bounty = mgr.createBounty('task-1', { amount: 1, currency: 'credits' }, 'alice');
|
|
83
|
+
mgr.claimBounty(bounty.id, 'bob');
|
|
84
|
+
const payout = mgr.completeBounty(bounty.id, { summary: '' });
|
|
85
|
+
expect(payout.success).toBe(false);
|
|
86
|
+
expect(payout.error).toContain('summary');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('lists bounties by status', () => {
|
|
90
|
+
const mgr = new BountyManager();
|
|
91
|
+
mgr.createBounty('t1', { amount: 1, currency: 'credits' }, 'a');
|
|
92
|
+
mgr.createBounty('t2', { amount: 2, currency: 'credits' }, 'a');
|
|
93
|
+
const b3 = mgr.createBounty('t3', { amount: 3, currency: 'credits' }, 'a');
|
|
94
|
+
mgr.claimBounty(b3.id, 'bob');
|
|
95
|
+
expect(mgr.list('open')).toHaveLength(2);
|
|
96
|
+
expect(mgr.list('claimed')).toHaveLength(1);
|
|
97
|
+
expect(mgr.list()).toHaveLength(3);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('calculates total open value', () => {
|
|
101
|
+
const mgr = new BountyManager();
|
|
102
|
+
mgr.createBounty('t1', { amount: 5, currency: 'USDC' }, 'a');
|
|
103
|
+
mgr.createBounty('t2', { amount: 3, currency: 'credits' }, 'a');
|
|
104
|
+
mgr.createBounty('t3', { amount: 10, currency: 'USDC' }, 'a');
|
|
105
|
+
expect(mgr.totalOpen('USDC')).toBe(15);
|
|
106
|
+
expect(mgr.totalOpen('credits')).toBe(3);
|
|
107
|
+
expect(mgr.totalOpen()).toBe(18);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('expires stale bounties', () => {
|
|
111
|
+
const mgr = new BountyManager();
|
|
112
|
+
mgr.createBounty('t1', { amount: 1, currency: 'credits' }, 'a', Date.now() - 1000);
|
|
113
|
+
mgr.createBounty('t2', { amount: 2, currency: 'credits' }, 'a', Date.now() + 100_000);
|
|
114
|
+
expect(mgr.expireStale()).toBe(1);
|
|
115
|
+
expect(mgr.list('expired')).toHaveLength(1);
|
|
116
|
+
expect(mgr.list('open')).toHaveLength(1);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('returns bounties by task', () => {
|
|
120
|
+
const mgr = new BountyManager();
|
|
121
|
+
mgr.createBounty('task-A', { amount: 1, currency: 'credits' }, 'a');
|
|
122
|
+
mgr.createBounty('task-A', { amount: 2, currency: 'credits' }, 'b');
|
|
123
|
+
mgr.createBounty('task-B', { amount: 3, currency: 'credits' }, 'a');
|
|
124
|
+
expect(mgr.byTask('task-A')).toHaveLength(2);
|
|
125
|
+
expect(mgr.byTask('task-B')).toHaveLength(1);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// ── KnowledgeMarketplace ──
|
|
130
|
+
|
|
131
|
+
describe('KnowledgeMarketplace', () => {
|
|
132
|
+
const mockEntry = (overrides?: Partial<StoredEntry>): StoredEntry => ({
|
|
133
|
+
id: 'W.TEST.001',
|
|
134
|
+
type: 'wisdom',
|
|
135
|
+
content: 'Always test before shipping',
|
|
136
|
+
domain: 'engineering',
|
|
137
|
+
confidence: 0.9,
|
|
138
|
+
source: 'experience',
|
|
139
|
+
queryCount: 12,
|
|
140
|
+
reuseCount: 6,
|
|
141
|
+
createdAt: new Date().toISOString(),
|
|
142
|
+
authorAgent: 'alice',
|
|
143
|
+
...overrides,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('prices knowledge based on type, confidence, and reuse', () => {
|
|
147
|
+
const mp = new KnowledgeMarketplace();
|
|
148
|
+
const wisdom = mockEntry(); // high confidence, high reuse, high query
|
|
149
|
+
const price = mp.priceKnowledge(wisdom);
|
|
150
|
+
// wisdom base=0.05, confidence>=0.8 *1.5=0.075, reuse>=5 *2=0.15, query>=10 *1.25=0.1875
|
|
151
|
+
expect(price).toBe(0.1875);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('prices gotchas lower than wisdom', () => {
|
|
155
|
+
const mp = new KnowledgeMarketplace();
|
|
156
|
+
const gotcha = mockEntry({ type: 'gotcha', confidence: 0.5, reuseCount: 0, queryCount: 0 });
|
|
157
|
+
const price = mp.priceKnowledge(gotcha);
|
|
158
|
+
expect(price).toBe(0.02); // base gotcha, no multipliers
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('lists and buys knowledge', () => {
|
|
162
|
+
const mp = new KnowledgeMarketplace();
|
|
163
|
+
const entry = mockEntry();
|
|
164
|
+
const listing = mp.sellKnowledge(entry, 0.10, 'alice');
|
|
165
|
+
expect(listing.success).toBe(true);
|
|
166
|
+
|
|
167
|
+
const purchase = mp.buyKnowledge(listing.listingId, 'bob');
|
|
168
|
+
expect(purchase.success).toBe(true);
|
|
169
|
+
expect(purchase.price).toBe(0.10);
|
|
170
|
+
expect(purchase.entryId).toBe('W.TEST.001');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('prevents duplicate listings', () => {
|
|
174
|
+
const mp = new KnowledgeMarketplace();
|
|
175
|
+
const entry = mockEntry();
|
|
176
|
+
mp.sellKnowledge(entry, 0.10, 'alice');
|
|
177
|
+
const dup = mp.sellKnowledge(entry, 0.20, 'alice');
|
|
178
|
+
expect(dup.success).toBe(false);
|
|
179
|
+
expect(dup.error).toContain('already listed');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('prevents buying your own listing', () => {
|
|
183
|
+
const mp = new KnowledgeMarketplace();
|
|
184
|
+
const entry = mockEntry();
|
|
185
|
+
const listing = mp.sellKnowledge(entry, 0.10, 'alice');
|
|
186
|
+
const purchase = mp.buyKnowledge(listing.listingId, 'alice');
|
|
187
|
+
expect(purchase.success).toBe(false);
|
|
188
|
+
expect(purchase.error).toContain('own listing');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('prevents buying a sold listing', () => {
|
|
192
|
+
const mp = new KnowledgeMarketplace();
|
|
193
|
+
const entry = mockEntry();
|
|
194
|
+
const listing = mp.sellKnowledge(entry, 0.10, 'alice');
|
|
195
|
+
mp.buyKnowledge(listing.listingId, 'bob');
|
|
196
|
+
const second = mp.buyKnowledge(listing.listingId, 'charlie');
|
|
197
|
+
expect(second.success).toBe(false);
|
|
198
|
+
expect(second.error).toContain('sold');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('rejects zero price', () => {
|
|
202
|
+
const mp = new KnowledgeMarketplace();
|
|
203
|
+
const result = mp.sellKnowledge(mockEntry(), 0, 'alice');
|
|
204
|
+
expect(result.success).toBe(false);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('delists an active listing', () => {
|
|
208
|
+
const mp = new KnowledgeMarketplace();
|
|
209
|
+
const entry = mockEntry();
|
|
210
|
+
const listing = mp.sellKnowledge(entry, 0.10, 'alice');
|
|
211
|
+
expect(mp.delist(listing.listingId, 'alice')).toBe(true);
|
|
212
|
+
expect(mp.activeListings()).toHaveLength(0);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('only seller can delist', () => {
|
|
216
|
+
const mp = new KnowledgeMarketplace();
|
|
217
|
+
const entry = mockEntry();
|
|
218
|
+
const listing = mp.sellKnowledge(entry, 0.10, 'alice');
|
|
219
|
+
expect(mp.delist(listing.listingId, 'bob')).toBe(false);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('tracks seller revenue', () => {
|
|
223
|
+
const mp = new KnowledgeMarketplace();
|
|
224
|
+
const e1 = mockEntry({ id: 'W.TEST.001' });
|
|
225
|
+
const e2 = mockEntry({ id: 'W.TEST.002' });
|
|
226
|
+
const l1 = mp.sellKnowledge(e1, 0.10, 'alice');
|
|
227
|
+
const l2 = mp.sellKnowledge(e2, 0.25, 'alice');
|
|
228
|
+
mp.buyKnowledge(l1.listingId, 'bob');
|
|
229
|
+
mp.buyKnowledge(l2.listingId, 'charlie');
|
|
230
|
+
expect(mp.sellerRevenue('alice')).toBe(0.35);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('tracks purchase history', () => {
|
|
234
|
+
const mp = new KnowledgeMarketplace();
|
|
235
|
+
const e1 = mockEntry({ id: 'W.TEST.001' });
|
|
236
|
+
const listing = mp.sellKnowledge(e1, 0.10, 'alice');
|
|
237
|
+
mp.buyKnowledge(listing.listingId, 'bob');
|
|
238
|
+
expect(mp.purchaseHistory('bob')).toHaveLength(1);
|
|
239
|
+
expect(mp.purchaseHistory('charlie')).toHaveLength(0);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('reports total volume', () => {
|
|
243
|
+
const mp = new KnowledgeMarketplace();
|
|
244
|
+
const e1 = mockEntry({ id: 'W.TEST.001' });
|
|
245
|
+
const e2 = mockEntry({ id: 'W.TEST.002' });
|
|
246
|
+
const l1 = mp.sellKnowledge(e1, 0.10, 'alice');
|
|
247
|
+
const l2 = mp.sellKnowledge(e2, 0.20, 'bob');
|
|
248
|
+
mp.buyKnowledge(l1.listingId, 'bob');
|
|
249
|
+
mp.buyKnowledge(l2.listingId, 'alice');
|
|
250
|
+
expect(mp.totalVolume()).toBeCloseTo(0.30);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// ── KnowledgeStore marketplace integration ──
|
|
255
|
+
|
|
256
|
+
describe('KnowledgeStore marketplace integration', () => {
|
|
257
|
+
it('prices and lists entries via store', () => {
|
|
258
|
+
const store = new KnowledgeStore({ persist: false });
|
|
259
|
+
const entry = store.publish(
|
|
260
|
+
{ type: 'wisdom', content: 'Cache invalidation matters', domain: 'engineering', confidence: 0.9, source: 'test' },
|
|
261
|
+
'alice'
|
|
262
|
+
);
|
|
263
|
+
const price = store.priceEntry(entry.id);
|
|
264
|
+
expect(price).toBeGreaterThan(0);
|
|
265
|
+
|
|
266
|
+
const listing = store.listForSale(entry.id, 'alice');
|
|
267
|
+
expect(listing.success).toBe(true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('buys a listed entry and increments reuseCount', () => {
|
|
271
|
+
const store = new KnowledgeStore({ persist: false });
|
|
272
|
+
const entry = store.publish(
|
|
273
|
+
{ type: 'pattern', content: 'Use dependency injection', domain: 'architecture', confidence: 0.8, source: 'test' },
|
|
274
|
+
'alice'
|
|
275
|
+
);
|
|
276
|
+
const listing = store.listForSale(entry.id, 'alice', 0.05);
|
|
277
|
+
const { purchase, entry: bought } = store.buyListed(listing.listingId, 'bob');
|
|
278
|
+
expect(purchase.success).toBe(true);
|
|
279
|
+
expect(bought).toBeDefined();
|
|
280
|
+
expect(bought!.reuseCount).toBe(1); // was 0, now 1
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('returns active listings', () => {
|
|
284
|
+
const store = new KnowledgeStore({ persist: false });
|
|
285
|
+
const e1 = store.publish(
|
|
286
|
+
{ type: 'gotcha', content: 'Watch out for NaN', domain: 'js', confidence: 0.7, source: 'test' },
|
|
287
|
+
'alice'
|
|
288
|
+
);
|
|
289
|
+
store.listForSale(e1.id, 'alice');
|
|
290
|
+
expect(store.activeListings()).toHaveLength(1);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('returns null price for nonexistent entry', () => {
|
|
294
|
+
const store = new KnowledgeStore({ persist: false });
|
|
295
|
+
expect(store.priceEntry('nonexistent')).toBeNull();
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('returns error for listing nonexistent entry', () => {
|
|
299
|
+
const store = new KnowledgeStore({ persist: false });
|
|
300
|
+
const result = store.listForSale('nonexistent', 'alice');
|
|
301
|
+
expect(result.success).toBe(false);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// ── Team bounty integration ──
|
|
306
|
+
|
|
307
|
+
describe('Team bounty integration', () => {
|
|
308
|
+
const coder = defineAgent({
|
|
309
|
+
name: 'Coder',
|
|
310
|
+
role: 'coder',
|
|
311
|
+
model: { provider: 'anthropic', model: 'claude-sonnet-4' },
|
|
312
|
+
capabilities: ['code-generation'],
|
|
313
|
+
claimFilter: { roles: ['coder'], maxPriority: 8 },
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
function makeTeam(): Team {
|
|
317
|
+
return new Team({ name: 'test-team', agents: [coder] });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
it('creates a bounty for a board task', async () => {
|
|
321
|
+
const team = makeTeam();
|
|
322
|
+
await team.addTasks([{ title: 'Fix bug', description: 'Fix the crash', priority: 3 }]);
|
|
323
|
+
const tasks = team['board']; // access private for test
|
|
324
|
+
const bounty = team.createBounty(tasks[0].id, { amount: 10, currency: 'credits' }, 'owner');
|
|
325
|
+
expect(bounty.status).toBe('open');
|
|
326
|
+
expect(bounty.taskId).toBe(tasks[0].id);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('rejects bounty for nonexistent task', () => {
|
|
330
|
+
const team = makeTeam();
|
|
331
|
+
expect(() => team.createBounty('nope', { amount: 1, currency: 'credits' }, 'a')).toThrow('not found');
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('claims bounty for a team agent', async () => {
|
|
335
|
+
const team = makeTeam();
|
|
336
|
+
await team.addTasks([{ title: 'Ship it', description: 'Deploy', priority: 2 }]);
|
|
337
|
+
const tasks = team['board'];
|
|
338
|
+
const bounty = team.createBounty(tasks[0].id, { amount: 5, currency: 'USDC' }, 'owner');
|
|
339
|
+
const result = team.claimBountyForAgent(bounty.id, 'Coder');
|
|
340
|
+
expect(result.success).toBe(true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('rejects claim from non-team agent', async () => {
|
|
344
|
+
const team = makeTeam();
|
|
345
|
+
await team.addTasks([{ title: 'Task', description: 'Desc', priority: 3 }]);
|
|
346
|
+
const tasks = team['board'];
|
|
347
|
+
const bounty = team.createBounty(tasks[0].id, { amount: 1, currency: 'credits' }, 'owner');
|
|
348
|
+
expect(() => team.claimBountyForAgent(bounty.id, 'stranger')).toThrow('not on team');
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('completes bounty with proof', async () => {
|
|
352
|
+
const team = makeTeam();
|
|
353
|
+
await team.addTasks([{ title: 'Build', description: 'Build it', priority: 1 }]);
|
|
354
|
+
const tasks = team['board'];
|
|
355
|
+
const bounty = team.createBounty(tasks[0].id, { amount: 2, currency: 'credits' }, 'owner');
|
|
356
|
+
team.claimBountyForAgent(bounty.id, 'Coder');
|
|
357
|
+
const payout = team.completeBountyWithProof(bounty.id, { summary: 'Done', commitHash: 'abc' });
|
|
358
|
+
expect(payout.success).toBe(true);
|
|
359
|
+
expect(payout.amount).toBe(2);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('lists bounties', async () => {
|
|
363
|
+
const team = makeTeam();
|
|
364
|
+
await team.addTasks([
|
|
365
|
+
{ title: 'A', description: 'a', priority: 3 },
|
|
366
|
+
{ title: 'B', description: 'b', priority: 4 },
|
|
367
|
+
]);
|
|
368
|
+
const tasks = team['board'];
|
|
369
|
+
team.createBounty(tasks[0].id, { amount: 1, currency: 'credits' }, 'owner');
|
|
370
|
+
team.createBounty(tasks[1].id, { amount: 2, currency: 'credits' }, 'owner');
|
|
371
|
+
expect(team.listBounties()).toHaveLength(2);
|
|
372
|
+
expect(team.listBounties('open')).toHaveLength(2);
|
|
373
|
+
});
|
|
374
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
DelegationManager,
|
|
4
|
+
InProcessBoardAdapter,
|
|
5
|
+
} from '../delegation';
|
|
6
|
+
import type { TaskDef } from '../types';
|
|
7
|
+
|
|
8
|
+
function makeTask(overrides: Partial<TaskDef> = {}): TaskDef {
|
|
9
|
+
return {
|
|
10
|
+
id: 'task-1',
|
|
11
|
+
title: 'Fix the parser bug',
|
|
12
|
+
description: 'Parser fails on nested objects',
|
|
13
|
+
status: 'open',
|
|
14
|
+
priority: 3,
|
|
15
|
+
createdAt: new Date().toISOString(),
|
|
16
|
+
...overrides,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('DelegationManager', () => {
|
|
21
|
+
let adapter: InProcessBoardAdapter;
|
|
22
|
+
let managerA: DelegationManager;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
adapter = new InProcessBoardAdapter();
|
|
26
|
+
|
|
27
|
+
// Register team-b's addTasks
|
|
28
|
+
adapter.registerTeam('team-b', async (tasks) => {
|
|
29
|
+
return tasks.map((t, i) => ({
|
|
30
|
+
id: `tb-${i}`,
|
|
31
|
+
title: t.title,
|
|
32
|
+
description: t.description ?? '',
|
|
33
|
+
status: 'open' as const,
|
|
34
|
+
priority: t.priority ?? 5,
|
|
35
|
+
role: t.role,
|
|
36
|
+
source: t.source,
|
|
37
|
+
createdAt: new Date().toISOString(),
|
|
38
|
+
}));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
managerA = new DelegationManager('team-a', adapter);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('delegates a task to another team', async () => {
|
|
45
|
+
const task = makeTask();
|
|
46
|
+
const result = await managerA.delegate(task, 'team-b');
|
|
47
|
+
expect(result.success).toBe(true);
|
|
48
|
+
expect(result.fromTeam).toBe('team-a');
|
|
49
|
+
expect(result.toTeam).toBe('team-b');
|
|
50
|
+
expect(result.chain).toEqual(['team-a']);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('rejects self-delegation', async () => {
|
|
54
|
+
const task = makeTask();
|
|
55
|
+
const result = await managerA.delegate(task, 'team-a');
|
|
56
|
+
expect(result.success).toBe(false);
|
|
57
|
+
expect(result.reason).toContain('Cannot delegate to self');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('detects cycles in delegation chain', async () => {
|
|
61
|
+
const task = makeTask();
|
|
62
|
+
// Simulate: team-b already delegated to team-a, now team-a tries to delegate back
|
|
63
|
+
const result = await managerA.delegate(task, 'team-b', ['team-b']);
|
|
64
|
+
// Chain becomes ['team-b', 'team-a'], and target is 'team-b' which is in the chain
|
|
65
|
+
expect(result.success).toBe(false);
|
|
66
|
+
expect(result.reason).toContain('Cycle detected');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('enforces max chain length', async () => {
|
|
70
|
+
const manager = new DelegationManager('team-a', adapter, { maxChainLength: 3 });
|
|
71
|
+
const task = makeTask();
|
|
72
|
+
// Existing chain of 3 means we're at the limit
|
|
73
|
+
const result = await manager.delegate(task, 'team-b', ['team-x', 'team-y', 'team-z']);
|
|
74
|
+
// Chain becomes ['team-x', 'team-y', 'team-z', 'team-a'] = length 4 >= max 3
|
|
75
|
+
expect(result.success).toBe(false);
|
|
76
|
+
expect(result.reason).toContain('chain too long');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('fails when target team not found', async () => {
|
|
80
|
+
const task = makeTask();
|
|
81
|
+
const result = await managerA.delegate(task, 'team-unknown');
|
|
82
|
+
expect(result.success).toBe(false);
|
|
83
|
+
expect(result.reason).toContain('not found');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('tracks outbound delegations', async () => {
|
|
87
|
+
const task1 = makeTask({ id: 'task-1' });
|
|
88
|
+
const task2 = makeTask({ id: 'task-2', title: 'Another task' });
|
|
89
|
+
await managerA.delegate(task1, 'team-b');
|
|
90
|
+
await managerA.delegate(task2, 'team-b');
|
|
91
|
+
const outbound = managerA.getOutboundDelegations();
|
|
92
|
+
expect(outbound).toHaveLength(2);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('marks delegation as completed', async () => {
|
|
96
|
+
const task = makeTask();
|
|
97
|
+
await managerA.delegate(task, 'team-b');
|
|
98
|
+
const completed = await managerA.completeDelegation('task-1', 'team-b', 'Done!');
|
|
99
|
+
expect(completed).toBe(true);
|
|
100
|
+
expect(managerA.getPendingDelegations()).toHaveLength(0);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('returns false for unknown completion', async () => {
|
|
104
|
+
const completed = await managerA.completeDelegation('nonexistent', 'team-b', 'Done!');
|
|
105
|
+
expect(completed).toBe(false);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('InProcessBoardAdapter', () => {
|
|
110
|
+
it('sends tasks to registered teams', async () => {
|
|
111
|
+
const adapter = new InProcessBoardAdapter();
|
|
112
|
+
const received: unknown[] = [];
|
|
113
|
+
adapter.registerTeam('team-b', async (tasks) => {
|
|
114
|
+
received.push(...tasks);
|
|
115
|
+
return tasks.map((t, i) => ({
|
|
116
|
+
id: `t-${i}`,
|
|
117
|
+
title: t.title,
|
|
118
|
+
description: t.description ?? '',
|
|
119
|
+
status: 'open' as const,
|
|
120
|
+
priority: t.priority ?? 5,
|
|
121
|
+
createdAt: new Date().toISOString(),
|
|
122
|
+
}));
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const result = await adapter.sendTask('team-b', {
|
|
126
|
+
title: 'Test task',
|
|
127
|
+
description: 'Desc',
|
|
128
|
+
priority: 3,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(result.accepted).toBe(true);
|
|
132
|
+
expect(received).toHaveLength(1);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('rejects tasks for unregistered teams', async () => {
|
|
136
|
+
const adapter = new InProcessBoardAdapter();
|
|
137
|
+
const result = await adapter.sendTask('nonexistent', {
|
|
138
|
+
title: 'Test',
|
|
139
|
+
description: 'Desc',
|
|
140
|
+
priority: 3,
|
|
141
|
+
});
|
|
142
|
+
expect(result.accepted).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
});
|