← Tidelines/Releases

TypeGlish 0.7.1: the embedded editor boots

This is a patch with one line in its changelog, and it is the line that turns the embeddable editor from a file in the tarball into a thing that runs. The language server worker had one dependency it never bundled. A browser could not resolve it, so the worker never started.

by TypeGlish team4 min read#releasestypeglish 0.7.1
It boots.

TL;DR 0.7.1 fixes exactly one thing: dist/lsp-worker.js, the language server worker that typeglish/monaco spawns, shipped with import nspell from 'nspell' still at the top of it. A browser resolving a module worker's imports has no node_modules to resolve that from, so the worker failed to load and took hover, completion, and semantic tokens down with it. 0.7.1 bundles the dependency in and the worker boots in a real tab. Nothing in the language, the CLI, or the checker moved: typeglish check --json prints byte-identical output on 0.7.0 and 0.7.1. Upgrade with npm i -D typeglish@latest, and if you do not embed the editor you can skip this one with a clear conscience.

0.7.0 was a big release, and buried in its "also in" list was a small promise: the published package now ships dist/lsp-worker.js, so if you embed typeglish/monaco the language server is in the box. That was true. The file was in the box. It just could not open in a browser, which is the only place typeglish/monaco ever runs. 0.7.1 is the correction, and it is worth writing down because the bug is a good one: a single unbundled import, invisible to every test that runs in Node, fatal in every test that runs in a tab.

§1One bare import, one dead worker

Here is the entire defect. It is the first line of the file, exactly as 0.7.0 published it.

node_modules/typeglish/dist/lsp-worker.js, 0.7.0
# the first line of a 2.93 MB bundle
import nspell from 'nspell';
nspell is the spellchecker behind the prose findings. Note what is not the problem: the dictionaries themselves were already inlined in that 2.93 MB, all of dictionary-en and dictionary-en-gb sitting in the file as text. The bundler swallowed the data and left the small library that reads it outside as a bare specifier.

That is fine in Node, which answers a bare specifier by walking up looking for node_modules. It is fatal in a browser, which does no such thing. And a browser is the whole point of this file, because typeglish/monaco starts it as a module worker off its own URL:

inside dist/monaco.js
worker = new Worker(new URL("./lsp-worker.js", import.meta.url), { type: "module" });
The browser fetches that URL, reads import nspell from 'nspell', has no idea what nspell names, and refuses to start the worker. Nothing in the package is wrong; nothing in your app is wrong; the module graph simply does not close.

The failure mode was worse than an error message, because the editor did not fail loudly. typeglish/monaco handles a dead worker by terminating it, dropping the reference, and rejecting everything in flight with lsp-worker crashed; respawning on next request. Then the next request spawns a fresh worker, which also cannot load. Meanwhile the squiggles kept appearing, because applyDiagnostics compiles on the main thread and never touches the worker at all. So the editor looked half alive: errors underlined correctly, and hover, completion, semantic tokens, reference highlighting, go-to-definition, document symbols, folding, and linked editing were all silently gone. Every one of those nine requests goes through the worker.

0.7.1 bundles nspell in. The published worker now has no top-level imports at all: its only top-level statement is the export on the last line. The cost is 29,166 bytes on a file that was already 2.93 MB, which is about one percent, in exchange for a worker that starts.

§2What booting looks like

Spawn the two published builds the way typeglish/monaco does, as a module worker in a real browser, and the difference is the entire release.

new Worker(url, { type: 'module' })✓ 0.7.1
# 0.7.0
 the worker never loads; every request rejects

# 0.7.1 - the first thing a healthy worker posts, unprompted
{"notification": "hello", "fingerprint": "rhxfep"}
That hello is not decoration. The page compares the worker's wire fingerprint against its own and warns you if they disagree, so a stale cached bundle announces itself instead of returning quietly wrong answers. In 0.7.0 the handshake never happened, because there was no worker to shake hands with.

Once it boots it does the job. Take a prompt with a conflict the compiler can prove, the same shape we pulled apart in Your prompt argues with itself:

refunds.tg✗ 2 errors
You are a support agent for Acme Analytics.
- You MUST escalate refund requests over $500.
- You NEVER escalate refund requests over $500.
The guard on this post re-runs the real checker on that source every build and asserts it emits logic/contradiction, so the claim below is proven rather than pasted.
typeglish check refunds.tg✗ exit 1
refunds.tg:2:1  error  logic/contradiction  Logical conflict — "escalate refund requests over $500." is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). (conflicts with line 3)
refunds.tg:3:1  error  logic/contradiction  Logical conflict — "escalate refund requests over $500." is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). (conflicts with line 2)

 1 file — 2 error, 0 warning, 0 info
Post that same source to the 0.7.1 worker in a browser tab and it answers with those two findings: both logic/contradiction, both error, one per offending line, each naming the other. One engine, two front doors, and as of this release the browser door opens.

§3Whether this is your release

Two questions decide it, and both have short answers.

Do you embed typeglish/monaco? Then yes, take this one, because on 0.7.0 the editor you shipped was running on diagnostics alone. Nothing changes in your code: setupTypeGlish(monaco) once per instance and attachTypeGlish(monaco, editor) per editor are the same two calls they were.

Do you use the CLI, the MCP server, or typeglish lsp? Then no, nothing you run was affected. The broken file is referenced by exactly one other module in the package, dist/monaco.js, and the CLI bundle never touches it. We checked the same prompt with both versions and diffed the machine output: typeglish check --json is identical on 0.7.0 and 0.7.1, down to the byte. Upgrade whenever it is convenient.

upgrade
npm i -D typeglish@latest              # 0.7.1
npx typeglish@latest check prompts/    # or no install at all
The editor surface itself has not changed since 0.5.0 shipped the language server. What changed is that the browser build of it can now start.
Field note

Energy check: this is a patch, and it reads like one. One changelog entry, one import, no language surface touched. It is a big deal only if you embed the editor, in which case it is the difference between a working product and a puzzling one, and it is nothing at all if you do not. Two honest notes on the reporting. First, the before-and-after here is from loading both published tarballs as module workers in a headless Chrome and diffing the CLI output between the two versions, not from a benchmark, and there are no adoption numbers in this post because we do not have any to report. Second, what we tested is the published artifact, not anybody's build: the claim is that the 0.7.0 worker does not load as a module worker and the 0.7.1 worker does, and we have not tried to characterize which build setups did or did not paper over it in between. The full changelog lives on GitHub. For the release this one repairs, read the 0.7.0 notes.

FAQQuestions about 0.7.1

Do I need 0.7.1 if I only use the typeglish CLI?
No. The file this release fixes, dist/lsp-worker.js, is referenced by exactly one other thing in the package: dist/monaco.js. The CLI never loads it, and Node resolves bare imports out of node_modules anyway. Checked against the same file, typeglish check --json prints identical output on 0.7.0 and 0.7.1. Upgrade because it is free, not because anything you run is broken.
What exactly was broken in 0.7.0?
Line 1 of the published dist/lsp-worker.js was: import nspell from 'nspell'. typeglish/monaco starts that file with new Worker(new URL('./lsp-worker.js', import.meta.url), { type: 'module' }), and a browser resolving a module worker's imports has no node_modules to look in, so the specifier nspell means nothing and the worker never starts. 0.7.1 bundles nspell into the worker, which leaves it with no top-level imports at all.
How did the failure show up in an app?
As a crash-and-respawn loop rather than a clean error. The worker's onerror handler in typeglish/monaco terminates it, clears the worker reference, and rejects everything in flight with lsp-worker crashed; respawning on next request, and the next request spawns a worker that cannot load either. Squiggles kept working, because applyDiagnostics compiles on the main thread. Hover, completion, semantic tokens, reference highlights, go-to-definition, document symbols, folding, and linked editing all go through the worker, and all of them were dead.
Did 0.7.1 change the language, the diagnostics, or the score?
No. The 0.7.1 changelog has exactly one entry, and it is the Monaco worker fix. The cross-file program pass, $REQUIRE section, typeglish fmt, and the 99-code reference all landed in 0.7.0 and behave the same here. If a prompt checked clean yesterday it checks clean today.
How much bigger is the worker now?
29,166 bytes, on a file that was already 2.93 MB. The spelling dictionaries were always inlined in the worker; it was the small library that reads them that was left outside. That is the whole size cost of the fix: about one percent, in exchange for a worker that starts.
∿ washed up Jul 31, 2026 ∿