@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,246 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { ZoneClaiming } from '../ZoneClaiming';
|
|
3
|
+
import { Vector3 } from '../Vector3';
|
|
4
|
+
|
|
5
|
+
// ─── helpers ────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
function mkZC(cfg?: ConstructorParameters<typeof ZoneClaiming>[0]) {
|
|
8
|
+
return new ZoneClaiming(cfg);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function v(x: number, y = 0, z = 0) {
|
|
12
|
+
return new Vector3(x, y, z);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function makeZone(zc: ZoneClaiming, id = 'z1', center = v(0), radius = 10) {
|
|
16
|
+
return zc.createZone(id, center, radius);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ─── tests ───────────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
describe('ZoneClaiming — defaultConfig', () => {
|
|
22
|
+
it('claimThreshold = 0.3', () => expect(mkZC().getConfig().claimThreshold).toBe(0.3));
|
|
23
|
+
it('captureThreshold = 0.7', () => expect(mkZC().getConfig().captureThreshold).toBe(0.7));
|
|
24
|
+
it('strengthDecayRate = 0.05', () => expect(mkZC().getConfig().strengthDecayRate).toBe(0.05));
|
|
25
|
+
it('reinforceRate = 0.1', () => expect(mkZC().getConfig().reinforceRate).toBe(0.1));
|
|
26
|
+
it('defenseBonus = 0.15', () => expect(mkZC().getConfig().defenseBonus).toBe(0.15));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('ZoneClaiming — zone CRUD', () => {
|
|
30
|
+
it('createZone stores zone', () => {
|
|
31
|
+
const zc = mkZC();
|
|
32
|
+
zc.createZone('z1', v(0), 10);
|
|
33
|
+
expect(zc.getZone('z1')).toBeDefined();
|
|
34
|
+
});
|
|
35
|
+
it('createZone initial state = unclaimed', () => {
|
|
36
|
+
const zc = mkZC();
|
|
37
|
+
zc.createZone('z2', v(0), 10);
|
|
38
|
+
expect(zc.getZone('z2')!.state).toBe('unclaimed');
|
|
39
|
+
});
|
|
40
|
+
it('createZone sets value', () => {
|
|
41
|
+
const zc = mkZC();
|
|
42
|
+
zc.createZone('z3', v(0), 10, { value: 5 });
|
|
43
|
+
expect(zc.getZone('z3')!.value).toBe(5);
|
|
44
|
+
});
|
|
45
|
+
it('createZone default value = 1', () => {
|
|
46
|
+
const zc = mkZC();
|
|
47
|
+
makeZone(zc);
|
|
48
|
+
expect(zc.getZone('z1')!.value).toBe(1);
|
|
49
|
+
});
|
|
50
|
+
it('removeZone returns true', () => {
|
|
51
|
+
const zc = mkZC();
|
|
52
|
+
makeZone(zc);
|
|
53
|
+
expect(zc.removeZone('z1')).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it('removeZone deletes zone', () => {
|
|
56
|
+
const zc = mkZC();
|
|
57
|
+
makeZone(zc);
|
|
58
|
+
zc.removeZone('z1');
|
|
59
|
+
expect(zc.getZone('z1')).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
it('removeZone missing id returns false', () => {
|
|
62
|
+
expect(mkZC().removeZone('nope')).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it('getAllZones returns all', () => {
|
|
65
|
+
const zc = mkZC();
|
|
66
|
+
zc.createZone('a', v(0), 5);
|
|
67
|
+
zc.createZone('b', v(10), 5);
|
|
68
|
+
expect(zc.getAllZones()).toHaveLength(2);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('ZoneClaiming — spatial queries', () => {
|
|
73
|
+
it('findZonesAt finds overlapping zone', () => {
|
|
74
|
+
const zc = mkZC();
|
|
75
|
+
makeZone(zc, 'z1', v(0), 10);
|
|
76
|
+
expect(zc.findZonesAt(v(5))).toHaveLength(1);
|
|
77
|
+
});
|
|
78
|
+
it('findZonesAt excludes non-overlapping zones', () => {
|
|
79
|
+
const zc = mkZC();
|
|
80
|
+
makeZone(zc, 'z1', v(0), 5);
|
|
81
|
+
expect(zc.findZonesAt(v(100))).toHaveLength(0);
|
|
82
|
+
});
|
|
83
|
+
it('isAgentInZone true when inside', () => {
|
|
84
|
+
const zc = mkZC();
|
|
85
|
+
makeZone(zc, 'z1', v(0), 10);
|
|
86
|
+
expect(zc.isAgentInZone('a1', 'z1', v(5))).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
it('isAgentInZone false when outside', () => {
|
|
89
|
+
const zc = mkZC();
|
|
90
|
+
makeZone(zc, 'z1', v(0), 5);
|
|
91
|
+
expect(zc.isAgentInZone('a1', 'z1', v(100))).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('ZoneClaiming — claimZone', () => {
|
|
96
|
+
it('creates a claim', () => {
|
|
97
|
+
const zc = mkZC();
|
|
98
|
+
makeZone(zc);
|
|
99
|
+
zc.claimZone('agent1', 'z1', { strength: 0.5 });
|
|
100
|
+
expect(zc.getClaimStrength('agent1', 'z1')).toBeCloseTo(0.5, 5);
|
|
101
|
+
});
|
|
102
|
+
it('reinforces existing claim', () => {
|
|
103
|
+
const zc = mkZC();
|
|
104
|
+
makeZone(zc);
|
|
105
|
+
zc.claimZone('a', 'z1', { strength: 0.3 });
|
|
106
|
+
zc.claimZone('a', 'z1', { strength: 0.3 });
|
|
107
|
+
expect(zc.getClaimStrength('a', 'z1')).toBeCloseTo(0.6, 5);
|
|
108
|
+
});
|
|
109
|
+
it('returns null for missing zone', () => {
|
|
110
|
+
expect(mkZC().claimZone('a', 'nonexistent')).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
it('zone state = claimed after sufficient strength', () => {
|
|
113
|
+
const zc = mkZC({ claimThreshold: 0.3, captureThreshold: 0.7 });
|
|
114
|
+
makeZone(zc);
|
|
115
|
+
zc.claimZone('a', 'z1', { strength: 0.8 });
|
|
116
|
+
expect(zc.getZone('z1')!.state).toBe('claimed');
|
|
117
|
+
});
|
|
118
|
+
it('zone owner set after claim', () => {
|
|
119
|
+
const zc = mkZC({ captureThreshold: 0.5 });
|
|
120
|
+
makeZone(zc);
|
|
121
|
+
zc.claimZone('agent1', 'z1', { strength: 0.9 });
|
|
122
|
+
expect(zc.getZone('z1')!.owner).toBe('agent1');
|
|
123
|
+
});
|
|
124
|
+
it('zone = contested when two agents have similar strength', () => {
|
|
125
|
+
const zc = mkZC({ claimThreshold: 0.1, captureThreshold: 0.9 });
|
|
126
|
+
makeZone(zc);
|
|
127
|
+
zc.claimZone('a', 'z1', { strength: 0.5 });
|
|
128
|
+
zc.claimZone('b', 'z1', { strength: 0.4 });
|
|
129
|
+
// secondStrength (0.4) >= highestStrength (0.5) * 0.5 → contested
|
|
130
|
+
expect(zc.getZone('z1')!.state).toBe('contested');
|
|
131
|
+
});
|
|
132
|
+
it('getAgentClaims returns zones agent has claims in', () => {
|
|
133
|
+
const zc = mkZC();
|
|
134
|
+
zc.createZone('z1', v(0), 5);
|
|
135
|
+
zc.createZone('z2', v(10), 5);
|
|
136
|
+
zc.claimZone('ag', 'z1', { strength: 0.5 });
|
|
137
|
+
zc.claimZone('ag', 'z2', { strength: 0.5 });
|
|
138
|
+
expect(zc.getAgentClaims('ag')).toHaveLength(2);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('ZoneClaiming — releaseClaim', () => {
|
|
143
|
+
it('release removes claim', () => {
|
|
144
|
+
const zc = mkZC();
|
|
145
|
+
makeZone(zc);
|
|
146
|
+
zc.claimZone('a', 'z1', { strength: 0.5 });
|
|
147
|
+
zc.releaseClaim('a', 'z1');
|
|
148
|
+
expect(zc.getClaimStrength('a', 'z1')).toBe(0);
|
|
149
|
+
});
|
|
150
|
+
it('release on missing zone returns false', () => {
|
|
151
|
+
expect(mkZC().releaseClaim('a', 'nope')).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
it('release on missing claim returns false', () => {
|
|
154
|
+
const zc = mkZC();
|
|
155
|
+
makeZone(zc);
|
|
156
|
+
expect(zc.releaseClaim('nobody', 'z1')).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
it('release by owner emits abandoned event', () => {
|
|
159
|
+
const zc = mkZC({ captureThreshold: 0.5 });
|
|
160
|
+
makeZone(zc);
|
|
161
|
+
zc.claimZone('owner', 'z1', { strength: 0.9 });
|
|
162
|
+
const events: any[] = [];
|
|
163
|
+
zc.onEvent((e) => events.push(e));
|
|
164
|
+
zc.releaseClaim('owner', 'z1');
|
|
165
|
+
expect(events.some((e) => e.type === 'abandoned')).toBe(true);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('ZoneClaiming — events', () => {
|
|
170
|
+
it('onEvent fires claimed event when zone first captured', () => {
|
|
171
|
+
const zc = mkZC({ captureThreshold: 0.5 });
|
|
172
|
+
makeZone(zc);
|
|
173
|
+
const events: any[] = [];
|
|
174
|
+
zc.onEvent((e) => events.push(e));
|
|
175
|
+
zc.claimZone('agent', 'z1', { strength: 0.9 });
|
|
176
|
+
expect(events.some((e) => e.type === 'claimed')).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
it('onEvent unsubscribe stops receiving events', () => {
|
|
179
|
+
const zc = mkZC({ captureThreshold: 0.5 });
|
|
180
|
+
makeZone(zc);
|
|
181
|
+
const events: any[] = [];
|
|
182
|
+
const unsub = zc.onEvent((e) => events.push(e));
|
|
183
|
+
unsub();
|
|
184
|
+
zc.claimZone('agent', 'z1', { strength: 0.9 });
|
|
185
|
+
expect(events).toHaveLength(0);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('ZoneClaiming — applyDecay', () => {
|
|
190
|
+
it('decays claim strength over time', () => {
|
|
191
|
+
const zc = mkZC({ strengthDecayRate: 0.1 });
|
|
192
|
+
makeZone(zc);
|
|
193
|
+
zc.claimZone('a', 'z1', { strength: 0.5 });
|
|
194
|
+
zc.applyDecay(1); // 1 second → -0.1
|
|
195
|
+
expect(zc.getClaimStrength('a', 'z1')).toBeCloseTo(0.4, 5);
|
|
196
|
+
});
|
|
197
|
+
it('removes claim when strength reaches 0', () => {
|
|
198
|
+
const zc = mkZC({ strengthDecayRate: 1 });
|
|
199
|
+
makeZone(zc);
|
|
200
|
+
zc.claimZone('a', 'z1', { strength: 0.5 });
|
|
201
|
+
zc.applyDecay(1); // strength → -0.5 → removed
|
|
202
|
+
expect(zc.getClaimStrength('a', 'z1')).toBe(0);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('ZoneClaiming — statistics', () => {
|
|
207
|
+
it('getStatistics returns total count', () => {
|
|
208
|
+
const zc = mkZC();
|
|
209
|
+
zc.createZone('z1', v(0), 5);
|
|
210
|
+
zc.createZone('z2', v(10), 5);
|
|
211
|
+
expect(zc.getStatistics().total).toBe(2);
|
|
212
|
+
});
|
|
213
|
+
it('getStatistics counts unclaimed', () => {
|
|
214
|
+
const zc = mkZC();
|
|
215
|
+
makeZone(zc);
|
|
216
|
+
expect(zc.getStatistics().unclaimed).toBe(1);
|
|
217
|
+
});
|
|
218
|
+
it('getTotalValue sums owned zone values', () => {
|
|
219
|
+
const zc = mkZC({ captureThreshold: 0.5 });
|
|
220
|
+
zc.createZone('z1', v(0), 5, { value: 3 });
|
|
221
|
+
zc.createZone('z2', v(10), 5, { value: 7 });
|
|
222
|
+
zc.claimZone('owner', 'z1', { strength: 0.9 });
|
|
223
|
+
zc.claimZone('owner', 'z2', { strength: 0.9 });
|
|
224
|
+
expect(zc.getTotalValue('owner')).toBe(10);
|
|
225
|
+
});
|
|
226
|
+
it('getContestedZones only returns contested', () => {
|
|
227
|
+
const zc = mkZC({ claimThreshold: 0.1, captureThreshold: 0.9 });
|
|
228
|
+
makeZone(zc);
|
|
229
|
+
zc.claimZone('a', 'z1', { strength: 0.5 });
|
|
230
|
+
zc.claimZone('b', 'z1', { strength: 0.4 });
|
|
231
|
+
expect(zc.getContestedZones()).toHaveLength(1);
|
|
232
|
+
});
|
|
233
|
+
it('getUnclaimedZones returns unclaimed', () => {
|
|
234
|
+
const zc = mkZC();
|
|
235
|
+
makeZone(zc);
|
|
236
|
+
expect(zc.getUnclaimedZones()).toHaveLength(1);
|
|
237
|
+
});
|
|
238
|
+
it('getZonesByState filters by state', () => {
|
|
239
|
+
const zc = mkZC({ captureThreshold: 0.5 });
|
|
240
|
+
zc.createZone('z1', v(0), 5);
|
|
241
|
+
zc.createZone('z2', v(10), 5);
|
|
242
|
+
zc.claimZone('a', 'z1', { strength: 0.9 });
|
|
243
|
+
expect(zc.getZonesByState('claimed')).toHaveLength(1);
|
|
244
|
+
expect(zc.getZonesByState('unclaimed')).toHaveLength(1);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZoneClaiming Tests
|
|
3
|
+
* HoloScript v3.2 - Autonomous Agent Swarms
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
7
|
+
import { ZoneClaiming, IZoneEvent } from '../ZoneClaiming';
|
|
8
|
+
import { Vector3 } from '../Vector3';
|
|
9
|
+
|
|
10
|
+
describe('ZoneClaiming', () => {
|
|
11
|
+
let zoning: ZoneClaiming;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
zoning = new ZoneClaiming({
|
|
15
|
+
claimThreshold: 0.3,
|
|
16
|
+
captureThreshold: 0.7,
|
|
17
|
+
strengthDecayRate: 0.05,
|
|
18
|
+
reinforceRate: 0.1,
|
|
19
|
+
swarmBonus: 0.2,
|
|
20
|
+
defenseBonus: 0.15,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('zone management', () => {
|
|
25
|
+
it('should create a zone', () => {
|
|
26
|
+
const zone = zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
27
|
+
expect(zone.id).toBe('zone-1');
|
|
28
|
+
expect(zone.radius).toBe(50);
|
|
29
|
+
expect(zone.state).toBe('unclaimed');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should create zone with value and metadata', () => {
|
|
33
|
+
const zone = zoning.createZone('zone-1', new Vector3(0, 0, 0), 50, {
|
|
34
|
+
value: 10,
|
|
35
|
+
metadata: { type: 'resource' },
|
|
36
|
+
});
|
|
37
|
+
expect(zone.value).toBe(10);
|
|
38
|
+
expect(zone.metadata.type).toBe('resource');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should remove a zone', () => {
|
|
42
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
43
|
+
expect(zoning.removeZone('zone-1')).toBe(true);
|
|
44
|
+
expect(zoning.getZone('zone-1')).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should get all zones', () => {
|
|
48
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
49
|
+
zoning.createZone('zone-2', new Vector3(100, 0, 0), 50);
|
|
50
|
+
expect(zoning.getAllZones()).toHaveLength(2);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('zone queries', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
57
|
+
zoning.createZone('zone-2', new Vector3(100, 0, 0), 50);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should find zones at position', () => {
|
|
61
|
+
const zones = zoning.findZonesAt(new Vector3(25, 0, 0));
|
|
62
|
+
expect(zones).toHaveLength(1);
|
|
63
|
+
expect(zones[0].id).toBe('zone-1');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should find overlapping zones', () => {
|
|
67
|
+
zoning.createZone('zone-3', new Vector3(30, 0, 0), 50);
|
|
68
|
+
const zones = zoning.findZonesAt(new Vector3(25, 0, 0));
|
|
69
|
+
expect(zones).toHaveLength(2);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should check if agent is in zone', () => {
|
|
73
|
+
expect(zoning.isAgentInZone('agent-1', 'zone-1', new Vector3(25, 0, 0))).toBe(true);
|
|
74
|
+
expect(zoning.isAgentInZone('agent-1', 'zone-1', new Vector3(100, 0, 0))).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('claiming', () => {
|
|
79
|
+
beforeEach(() => {
|
|
80
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should create a claim', () => {
|
|
84
|
+
const claim = zoning.claimZone('agent-1', 'zone-1');
|
|
85
|
+
expect(claim).not.toBeNull();
|
|
86
|
+
expect(claim!.agentId).toBe('agent-1');
|
|
87
|
+
expect(claim!.strength).toBe(0.1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should reinforce existing claim', () => {
|
|
91
|
+
zoning.claimZone('agent-1', 'zone-1');
|
|
92
|
+
zoning.claimZone('agent-1', 'zone-1');
|
|
93
|
+
|
|
94
|
+
const strength = zoning.getClaimStrength('agent-1', 'zone-1');
|
|
95
|
+
expect(strength).toBe(0.2);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should cap claim strength at 1', () => {
|
|
99
|
+
for (let i = 0; i < 20; i++) {
|
|
100
|
+
zoning.claimZone('agent-1', 'zone-1');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const strength = zoning.getClaimStrength('agent-1', 'zone-1');
|
|
104
|
+
expect(strength).toBe(1);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should track swarm ID in claim', () => {
|
|
108
|
+
const claim = zoning.claimZone('agent-1', 'zone-1', { swarmId: 'swarm-1' });
|
|
109
|
+
expect(claim!.swarmId).toBe('swarm-1');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return null for non-existent zone', () => {
|
|
113
|
+
const claim = zoning.claimZone('agent-1', 'invalid');
|
|
114
|
+
expect(claim).toBeNull();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('zone state transitions', () => {
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should transition to claimed when threshold reached', () => {
|
|
124
|
+
// Claim enough to pass threshold (0.3)
|
|
125
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.35 });
|
|
126
|
+
|
|
127
|
+
const zone = zoning.getZone('zone-1')!;
|
|
128
|
+
expect(zone.state).toBe('claimed');
|
|
129
|
+
expect(zone.owner).toBe('agent-1');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should become contested when multiple claimants', () => {
|
|
133
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.4 });
|
|
134
|
+
zoning.claimZone('agent-2', 'zone-1', { strength: 0.3 });
|
|
135
|
+
|
|
136
|
+
const zone = zoning.getZone('zone-1')!;
|
|
137
|
+
expect(zone.state).toBe('contested');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should become defended when owner has clear lead', () => {
|
|
141
|
+
// First claim establishes ownership as 'claimed'
|
|
142
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.8 });
|
|
143
|
+
|
|
144
|
+
const zone = zoning.getZone('zone-1')!;
|
|
145
|
+
// Initial claim is 'claimed', becomes 'defended' after reinforcement when already owner
|
|
146
|
+
expect(['claimed', 'defended']).toContain(zone.state);
|
|
147
|
+
expect(zone.owner).toBe('agent-1');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe('releasing claims', () => {
|
|
152
|
+
beforeEach(() => {
|
|
153
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
154
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.5 });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should release a claim', () => {
|
|
158
|
+
expect(zoning.releaseClaim('agent-1', 'zone-1')).toBe(true);
|
|
159
|
+
expect(zoning.getClaimStrength('agent-1', 'zone-1')).toBe(0);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should emit abandoned event when owner releases', () => {
|
|
163
|
+
const events: IZoneEvent[] = [];
|
|
164
|
+
zoning.onEvent((e) => events.push(e));
|
|
165
|
+
|
|
166
|
+
zoning.releaseClaim('agent-1', 'zone-1');
|
|
167
|
+
|
|
168
|
+
const abandoned = events.find((e) => e.type === 'abandoned');
|
|
169
|
+
expect(abandoned).toBeDefined();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should return false for non-existent claim', () => {
|
|
173
|
+
expect(zoning.releaseClaim('agent-2', 'zone-1')).toBe(false);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe('swarm bonuses', () => {
|
|
178
|
+
beforeEach(() => {
|
|
179
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('should track swarm strength', () => {
|
|
183
|
+
zoning.claimZone('agent-1', 'zone-1', { swarmId: 'swarm-1', strength: 0.3 });
|
|
184
|
+
zoning.claimZone('agent-2', 'zone-1', { swarmId: 'swarm-1', strength: 0.3 });
|
|
185
|
+
|
|
186
|
+
const swarmStrength = zoning.getSwarmStrength('swarm-1', 'zone-1');
|
|
187
|
+
expect(swarmStrength).toBe(0.6);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should apply swarm bonus for multiple members', () => {
|
|
191
|
+
// Two swarm members vs one solo agent
|
|
192
|
+
zoning.claimZone('agent-1', 'zone-1', { swarmId: 'swarm-1', strength: 0.3 });
|
|
193
|
+
zoning.claimZone('agent-2', 'zone-1', { swarmId: 'swarm-1', strength: 0.3 });
|
|
194
|
+
zoning.claimZone('agent-3', 'zone-1', { strength: 0.5 }); // Solo agent
|
|
195
|
+
|
|
196
|
+
const zone = zoning.getZone('zone-1')!;
|
|
197
|
+
// Swarm should own due to bonus (0.6 + 0.2 = 0.8 vs 0.5)
|
|
198
|
+
expect(zone.ownerSwarm).toBe('swarm-1');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe('decay', () => {
|
|
203
|
+
beforeEach(() => {
|
|
204
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should apply decay to claims', () => {
|
|
208
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.5 });
|
|
209
|
+
zoning.applyDecay(2); // 2 seconds worth of decay
|
|
210
|
+
|
|
211
|
+
const strength = zoning.getClaimStrength('agent-1', 'zone-1');
|
|
212
|
+
expect(strength).toBeCloseTo(0.4); // 0.5 - (0.05 * 2)
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should remove claims that decay to zero', () => {
|
|
216
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.05 });
|
|
217
|
+
zoning.applyDecay(2);
|
|
218
|
+
|
|
219
|
+
expect(zoning.getClaimStrength('agent-1', 'zone-1')).toBe(0);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should update zone state after decay', () => {
|
|
223
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.4 });
|
|
224
|
+
zoning.applyDecay(10); // Complete decay
|
|
225
|
+
|
|
226
|
+
const zone = zoning.getZone('zone-1')!;
|
|
227
|
+
expect(zone.state).toBe('unclaimed');
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe('zone queries by state', () => {
|
|
232
|
+
beforeEach(() => {
|
|
233
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
234
|
+
zoning.createZone('zone-2', new Vector3(100, 0, 0), 50);
|
|
235
|
+
zoning.createZone('zone-3', new Vector3(200, 0, 0), 50);
|
|
236
|
+
|
|
237
|
+
zoning.claimZone('agent-1', 'zone-2', { strength: 0.8 });
|
|
238
|
+
zoning.claimZone('agent-2', 'zone-3', { strength: 0.4 });
|
|
239
|
+
zoning.claimZone('agent-3', 'zone-3', { strength: 0.35 });
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should get unclaimed zones', () => {
|
|
243
|
+
const unclaimed = zoning.getUnclaimedZones();
|
|
244
|
+
expect(unclaimed).toHaveLength(1);
|
|
245
|
+
expect(unclaimed[0].id).toBe('zone-1');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should get contested zones', () => {
|
|
249
|
+
const contested = zoning.getContestedZones();
|
|
250
|
+
expect(contested).toHaveLength(1);
|
|
251
|
+
expect(contested[0].id).toBe('zone-3');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should get zones by state', () => {
|
|
255
|
+
// zone-2 has single strong claim - either 'claimed' or 'defended'
|
|
256
|
+
const claimedOrDefended =
|
|
257
|
+
zoning.getZonesByState('claimed').length + zoning.getZonesByState('defended').length;
|
|
258
|
+
expect(claimedOrDefended).toBeGreaterThanOrEqual(1);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('ownership queries', () => {
|
|
263
|
+
beforeEach(() => {
|
|
264
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50, { value: 10 });
|
|
265
|
+
zoning.createZone('zone-2', new Vector3(100, 0, 0), 50, { value: 20 });
|
|
266
|
+
|
|
267
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.8 });
|
|
268
|
+
zoning.claimZone('agent-1', 'zone-2', { strength: 0.8 });
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should get owned zones', () => {
|
|
272
|
+
const owned = zoning.getOwnedZones('agent-1');
|
|
273
|
+
expect(owned).toHaveLength(2);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should get agent claims', () => {
|
|
277
|
+
const claims = zoning.getAgentClaims('agent-1');
|
|
278
|
+
expect(claims).toHaveLength(2);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should calculate total value', () => {
|
|
282
|
+
const value = zoning.getTotalValue('agent-1');
|
|
283
|
+
expect(value).toBe(30);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('events', () => {
|
|
288
|
+
beforeEach(() => {
|
|
289
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should emit claimed event', () => {
|
|
293
|
+
const events: IZoneEvent[] = [];
|
|
294
|
+
zoning.onEvent((e) => events.push(e));
|
|
295
|
+
|
|
296
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.5 });
|
|
297
|
+
|
|
298
|
+
const claimed = events.find((e) => e.type === 'claimed');
|
|
299
|
+
expect(claimed).toBeDefined();
|
|
300
|
+
expect(claimed!.agentId).toBe('agent-1');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should emit captured event when changing owner', () => {
|
|
304
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.8 });
|
|
305
|
+
|
|
306
|
+
const events: IZoneEvent[] = [];
|
|
307
|
+
zoning.onEvent((e) => events.push(e));
|
|
308
|
+
|
|
309
|
+
// Need to significantly overpower existing claim to capture
|
|
310
|
+
zoning.claimZone('agent-2', 'zone-1', { strength: 1.0 });
|
|
311
|
+
|
|
312
|
+
// Either captured or zone is now contested
|
|
313
|
+
const zone = zoning.getZone('zone-1')!;
|
|
314
|
+
const captured = events.find((e) => e.type === 'captured');
|
|
315
|
+
const isContested = zone.state === 'contested';
|
|
316
|
+
|
|
317
|
+
// Either there was a capture event OR the zone became contested
|
|
318
|
+
expect(captured || isContested).toBeTruthy();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should emit defended event when holding contested zone', () => {
|
|
322
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.5 });
|
|
323
|
+
zoning.claimZone('agent-2', 'zone-1', { strength: 0.4 }); // Makes it contested
|
|
324
|
+
|
|
325
|
+
const events: IZoneEvent[] = [];
|
|
326
|
+
zoning.onEvent((e) => events.push(e));
|
|
327
|
+
|
|
328
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.5 }); // Reinforce to defend
|
|
329
|
+
|
|
330
|
+
const defended = events.find((e) => e.type === 'defended');
|
|
331
|
+
expect(defended).toBeDefined();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('should unsubscribe from events', () => {
|
|
335
|
+
const events: IZoneEvent[] = [];
|
|
336
|
+
const unsubscribe = zoning.onEvent((e) => events.push(e));
|
|
337
|
+
|
|
338
|
+
unsubscribe();
|
|
339
|
+
zoning.claimZone('agent-1', 'zone-1', { strength: 0.5 });
|
|
340
|
+
|
|
341
|
+
expect(events).toHaveLength(0);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
describe('statistics', () => {
|
|
346
|
+
beforeEach(() => {
|
|
347
|
+
zoning.createZone('zone-1', new Vector3(0, 0, 0), 50, { value: 10 });
|
|
348
|
+
zoning.createZone('zone-2', new Vector3(100, 0, 0), 50, { value: 20 });
|
|
349
|
+
zoning.createZone('zone-3', new Vector3(200, 0, 0), 50, { value: 30 });
|
|
350
|
+
|
|
351
|
+
zoning.claimZone('agent-1', 'zone-2', { strength: 0.8 });
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('should get zone statistics', () => {
|
|
355
|
+
const stats = zoning.getStatistics();
|
|
356
|
+
expect(stats.total).toBe(3);
|
|
357
|
+
expect(stats.unclaimed).toBe(2);
|
|
358
|
+
expect(stats.totalValue).toBe(60);
|
|
359
|
+
expect(stats.claimedValue).toBe(20);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
describe('configuration', () => {
|
|
364
|
+
it('should update config', () => {
|
|
365
|
+
zoning.setConfig({ claimThreshold: 0.5 });
|
|
366
|
+
expect(zoning.getConfig().claimThreshold).toBe(0.5);
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('should preserve existing config', () => {
|
|
370
|
+
zoning.setConfig({ claimThreshold: 0.5 });
|
|
371
|
+
expect(zoning.getConfig().captureThreshold).toBe(0.7);
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spatial Swarm Behaviors - Index
|
|
3
|
+
* HoloScript v3.2 - Autonomous Agent Swarms
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Vector utilities
|
|
7
|
+
export { Vector3 } from './Vector3';
|
|
8
|
+
|
|
9
|
+
// Boid-based flocking
|
|
10
|
+
export { FlockingBehavior, type IBoid, type IFlockingConfig } from './FlockingBehavior';
|
|
11
|
+
|
|
12
|
+
// Geometric formations
|
|
13
|
+
export {
|
|
14
|
+
FormationController,
|
|
15
|
+
type FormationType,
|
|
16
|
+
type IFormationSlot,
|
|
17
|
+
type IFormationConfig,
|
|
18
|
+
} from './FormationController';
|
|
19
|
+
|
|
20
|
+
// Territory control
|
|
21
|
+
export {
|
|
22
|
+
ZoneClaiming,
|
|
23
|
+
type ZoneState,
|
|
24
|
+
type IZone,
|
|
25
|
+
type IZoneClaim,
|
|
26
|
+
type IZoneEvent,
|
|
27
|
+
type IZoneClaimingConfig,
|
|
28
|
+
} from './ZoneClaiming';
|