| feature | interactive-shell | ||||||
|---|---|---|---|---|---|---|---|
| kind | notes | ||||||
| status | active | ||||||
| prs |
|
||||||
| verified | 2026-09-22 | ||||||
| code |
|
Status: shipped · Verified: 2026-09-22
How the in-terminal DocumentDB REPL was built, and why it behaves like a shell rather than a webview.
The Interactive Shell is a REPL inside a VS Code terminal, wired to the extension's connection
management and to the shell-runtime evaluation engine. Users type one command at a time, use shell
helpers (show dbs, use db, it, help, exit), keep variables across commands, and navigate
history with the arrow keys.
It is one of three query surfaces built on a shared foundation. See iterations/00-program-roadmap.md for the program-level narrative, and the sibling areas query-playground and completions-and-schema.
src/documentdb/shell/**— the pseudoterminal, session manager, input line, and highlightingsrc/commands/openInteractiveShell/**— entry pointspackages/documentdb-js-shell-runtime/**— the evaluation enginepackages/documentdb-js-shell-api-types/**— the shell API type definitions
- docs/user-manual/interactive-shell.md
- docs/user-manual/query-runtime.md — "Running Several Sessions at Once" covers how shells and playgrounds share worker threads
- Each shell terminal owns a dedicated worker thread. That is what makes infinite loops survivable and keeps clients isolated. The user-visible consequences are documented in the user manual; the reasoning for the shell/playground split is in query-playground/multi-connection-behavior.md.
- Startup diagnostics are shared with Query Playground. Each startup produces one
ext.outputChanneltiming summary, not a message per stage. It includes a random attempt ID, outcome, surface, auth method, timeout, last stage, total elapsed milliseconds, andstageDurationsMsfor worker startup, driver loading, connection setup, token acquisition, authentication, and runtime initialization. Only visited stages are included; repeated visits accumulate. Reported stage names sort in execution order:stage01StartingWorker,stage02LoadingDriver,stage03Connecting,stage04AcquiringToken,stage05Authenticating, andstage06InitializingRuntime. Failures, timeouts, and unexpected exits use Error level; success and intentional cancellation use Trace. Timeout errors also name the last stage and its elapsed time. Connection setup is one stage, not a separate measurement of DNS, TCP, and TLS. The existing startup deadline and authentication behavior are unchanged. - One
worker.startuptelemetry event covers each actual startup attempt, including worker construction failures. Reusing a connected worker emits no new startup event; retrying does. Properties arestartupCorrelationId(the log/IPC attempt ID),surface,authMethod,startupOutcome(succeeded,failed,timedOut,exited, orcanceled), andlastStage. The framework suppliesresultand totaldurationin seconds. MeasurementstimeoutMs,lastStageDurationMs(the last visit), and<stage>DurationMs(accumulated across visits) are milliseconds. Shell events carry the existingshellSessionIdand, when already cached at shell creation, the parentconnectionCorrelationIdas a link to that client's cluster metadata. It is captured once at shell creation and is not the worker's attempt ID; that isstartupCorrelationId. Playground carries its existingsessionId. Successful events are retained for rate/latency analysis. Tracking summaries contain no connection strings, tokens, hostnames, account details, database names, or raw errors. The telemetry wrapper receives only a fixed failure with no original stack, and masks error fields; the original error is preserved for the caller. Existing worker/session lifecycle events remain separate. Regular extension clients use the relatedconnect.startupdiagnostics. SRV, authentication, and worker log lines carry the worker'sstartup=<UUID>for its whole lifetime, including later token refreshes. See the connection IDs. - Entra and database costs are measured separately in that same event.
tokenAcquireDurationMsmeasures the actual host-side token-provider call, including its cache, refresh, SDK setup, and any interactive wait.databaseConnectDurationMsmeasures the connect window excluding token-provider and token-relay waiting.tokenRelayDurationMsmeasures worker token waiting outside the provider call, including module loading, IPC, and scheduling overhead. These values are also included ascostTimingsMsin the existing single summary line. The host clocks worker boundaries when their IPC messages arrive, so the worker measurements include delivery/scheduling effects; they are not wire-level network latency or Entra HTTP latency. Server selection, TLS, and server-side token validation remain part of database connection work. Overlapping token requests count once as wall-clock waiting, and only overlap with the connect window is subtracted from database time. Failure/cancellation/timeout snapshots retain partial elapsed time and ignore late completion. Unvisited activities are omitted, so non-Entra paths have database timing but no token timing. These costs are an alternative breakdown, not additional time to sum with the numbered stage timings. Cached reuse and later token refreshes emit no new startup event. - The connection summary keeps multi-host seed lists compact. A single host is shown unchanged;
when the connection string contains several hosts, the summary shows the first seed followed by
+N more. This display rule is independent of terminal width and does not imply that the first seed is the active primary. - Highlighting reuses the Monarch tokenizer extracted for the query editors rather than a second grammar, so the input line and the result formatter colorize the same way.
- Completions are terminal-native. Tab completion and ghost text are driven from the same
operator registry and
SchemaStorethat feed the editors, and shell query results feed documents back intoSchemaStore. Collection names are refreshed after connect and afteruse <database>only when the extension host already has a client for that cluster; completion never creates a second connection. Having the connected worker supply this data is tracked in #938. - Inline assistance has two user-controlled affordances. Insertable suggestions and Tab
completion are governed by
documentDB.shell.display.autocompletion; informational lines marked🛈are governed independently bydocumentDB.shell.display.inlineHints. Candidate previews, completions, and fully-typed descriptions precede thedb.collection count, then history, missing-schema hints, and closing brackets. The count falls through when hints are disabled; candidate branches do not. A future history-first UX change is explicitly deferred in future-work.md. - Clickable action sentinels after query results are registered through VS Code's
TerminalLinkProvider. VS Code offers no way to style terminal links at rest, which is why visibility had to be solved in the emitted text itself. The same provider turns compact setting markers in shellhelpinto links that open a filtered VS Code Settings view. Shell help uses one link for the complete Interactive Shell settings group rather than linking each setting separately. - Shell help stays structured through the worker boundary. The runtime owns help content,
width-aware layout, semantic line kinds and link spans. It sends that plain object through the
existing EJSON printable channel. The extension host maps those semantic roles to
shellStyles; it does not infer headers, commands or detail text from prefixes and whitespace. - Shell
helpis English by design today. Width-sensitive help is generated in the worker bydocumentdb-js-shell-runtime, a package that cannot depend onvscodeand therefore cannot callvscode.l10n.t(). A reusable localization mechanism for vscode-free worker packages is tracked in #940; moving help rendering back to the host is not the chosen workaround.
| Date | PR | What changed | Docs |
|---|---|---|---|
| Step 8 | #561 | The Interactive Shell itself, plus the #508 umbrella review | iterations/08-interactive-shell/ |
| Step 9 | #576 | Tab completion and ghost text | iterations/09-shell-autocompletion.md |
| Step 9.1 | #576 | Shell results feed SchemaStore | iterations/09.1-shell-schema-feeding.md |
| Step 10 | #580 | Input-line syntax highlighting | iterations/10-syntax-highlighting.md |
| Step 11 | #631 | Visible underline for terminal links | iterations/11-visible-underline-shell-links.md |
| Step 12 | #937 | Startup, connection, styling, cache warming and settings UX | iterations/12-shell-session-ux.md |
| Step 13 | #937 | Ghost text clipped to terminal width (input-line corruption) | iterations/13-ghost-text-wrap-clipping.md |
| Step 14 | #937 | Bracket-notation completion now removes the db. dot |
iterations/14-bracket-notation-dot-removal.md |
| Step 15 | #937 | Liveness audit: nine planned items plus four follow-up fixes | iterations/15-shell-liveness-audit-fixes.md |
Iteration numbers 8, 9 and 9.1 are the original step numbers of the shell-integration program and are preserved. Steps 10 and 11 are new numbers for work that had none.
PR #937 also deliberately includes the reintroduced schema-analyzer work from PR #933: static BSON imports, foreign-wrapper inference, and its package metadata/tests. The ordinary-document guard, collection refresh, help fixes, and precedence clarification from the Copilot follow-up are recorded in iteration 17, including per-finding fix references.
shell-liveness-audit.md — an audit of the first minutes of shell use,
written after Steps 13 and 14 both turned out to be reachable within the first three keystrokes. It
lists verified findings (resize can strand the cursor, ghost text can paint over real text,
String.length used for width in two remaining places) alongside rated quality-of-life proposals,
grouped into Fix, Deferred and Won't fix.
All nine original Fix items shipped in Step 15. Using that build raised N1–N4: completion lists losing to ghost text, inconsistent hint markers, inert display settings, and suggestion chains ending after an accepted completion. All four follow-ups also shipped and carry their commit and decision record inline in the audit.
Deferred and Won't fix items remain the live backlog. I7 (Tab-cycling as menu-select) and its prerequisite I10 are the largest, and I4 (persisting history) is blocked on a redaction decision rather than on storage.
No separate decisions.md yet. The reviewed alternatives are inside the iteration documents; the
most decision-dense is iterations/08-interactive-shell/pr-review-508.md,
a three-model consolidated review with each finding verified against the source.
- future-work.md — terminal-surface items deferred deliberately, including
autocompletion through
TerminalCompletionProvider.