The generators or async/await in JS are 'shallow' coroutines because you can only `yield` or `await` in the direct scope of a generator or async function, but the benefit of shallowness is that the control flow is explicit; you don't have to consider whether a function call will suspend the calling context's execution or not. I find the explicit clarity to outweigh the reduced power of shallow coroutines.
As an aside, there exist green threads in JS, namely node-fibers, although it's only a Node.js extension.
You actually can reflect on module exports and dynamically change them with node modules; you can't do it with ES modules, but that has the significant advantage of enabling static analysis.
Proxies absolutely can trap the property assignments you mentioned, but Vue can't take advantage of this because Proxy can't be polyfilled in older browsers.
As for the enumerate handler, it would only have worked with for-in loops, which are a legacy feature. The iteration protocols used by for-of are a much more flexible solution. It might seem silly to have both for-in and for-of loops, but the context of the language is that it can't just go and break older websites. Same goes for == and ===, etc. Linters come in very handy for dealing with this.
Your criticism is better than most, which usually just point out some "wat" moments with mis-features like implicit coercion, but you didn't really make a case for having to do "all things by hand" in JS.