The page's identifiers, as something a keystroke can read.
Completion has to be instant and the answer lives in ANOTHER PROCESS — session.completions()
is a CDP round trip to a browser — so this keeps the last answer and asks for the next in the
background. That is the whole reason it exists, and the reason it is a cache rather than a
lookup: a miss is not a stall. CompletionCache.lookup says what it knows right now, the
request lands a moment later, and subscribers redraw with the answer.
Going stale is deliberately not the same as being emptied. An evaluation may have declared a name, but everything already known is still true, so the old list stays on offer until the new one arrives rather than suggestions blinking out after every line.
lookup(base: string): readonly string[]
Names on base as of the last answer — empty while the first one is in flight.
ask(base: string): Promise<readonly string[]>
The page's answer for base, waited for. What TAB uses, where a moment is affordable.
stale(): void
Marks every answer worth asking for again.
subscribe(listener: () => void): void
Called whenever a late answer arrives, so what is on screen can be drawn again.