Which Twine format are you using ? It definitely sounds doable (at least in Harlowe, and if it is doable in Harlowe, it probably is doable in Sugarcube as well), but it’s difficult to give you a concrete answer on how to do it without knowing the story format.
In general terms, you need a data structure to act as your inventory (in Harlowe, it could be an array or a dataset, for instance depending on what you need). You need to define it as early as possible, and then, anytime the player wants to pick something, you add it to the Inventory.
These data structures have a property called length, you can check it at any time. For instance, before picking something up, you make sure that the length is less than 5, otherwise, you say that the inventory is full and that they can’t pick anything new.
Now, for the good and bad items, you can deal with that by creating, as early as possible, another data-structure, the same as your inventory, but instead of starting empty, you fill it with the name of either your good or your bad things. Contrary to the inventory, you do not want to change the content of that list throughout your game (unless you want good items to turn bad or vice versa), it will just be used as a comparison.
Whenever you want to check the proportions of good/bad items in your inventory, you can create a third, temporary array/dataset/… (should be the same as your first two), and set it to your inventory - (minus sign) your list of bad(good) things, it will now contain all the things that are in your inventory, but which aren’t bad(good), and you can use the length to know how many such items the player has.
Once you know that information, you can print it to the player, or use it to determine which ending to trigger.
I’m sorry if it is not super clear, I promise it is not that complex, but it is difficult to explain that better without knowing which format you use.