Skip to content

Extract shared dor/lib code into dor-lib-common#196

Merged
nedtwigg merged 7 commits into
mainfrom
dor-lib-common
Jun 30, 2026
Merged

Extract shared dor/lib code into dor-lib-common#196
nedtwigg merged 7 commits into
mainfrom
dor-lib-common

Conversation

@nedtwigg

Copy link
Copy Markdown
Member

dor (the CLI) and dormouse-lib's agent-browser host had grown several copies of the same logic and contracts. This extracts them into one place so they can't drift.

What moved

A new dor-lib-common workspace package holds the code both packages genuinely share:

  • spawnAndCapture — the hard-won Windows spawn recipe (cross-spawn for PATHEXT/.cmd, windowsHide, resolve-on-exit-with-grace + exit-time output snapshot). Was a ~30-line state machine duplicated in both; both call sites are now thin adapters.
  • parseStreamPortagent-browser stream status --json parsing ({port} | {data:{port}}).
  • sessionForKey — the dormouse.<workspaceId>.<key> session namespace.
  • streamStatusArgs + AGENT_BROWSER_BIN_ENV / DEFAULT_AGENT_BROWSER_BIN — the remaining shared agent-browser invocation/binary constants.

Separately, the eight surface.* control method names moved into dor/protocol.ts (already the shared protocol module lib imports) as SURFACE_CONTROL_METHODS + a SurfaceControlMethod union — they were hardcoded on both the client (control-client.ts) and the webview handler (Wall.tsx) with no single source of truth.

How resolution works

The key constraint: dor deliberately avoids @types/node (hand-rolled ambients), and the lib host is esbuild-only (excluded from every tsc), so dor is the only type-checking consumer. dor-lib-common's package exports therefore point at its built dist — a clean, Node-type-free .d.ts for dor's tsc — while every esbuild/Vite consumer inlines it. dor's prebuild (and lib's pretest) build it first; resolution is a plain workspace:* dependency, no per-bundler alias wiring. dor sheds its hand-rolled cross-spawn/child_process ambients and both packages drop their direct cross-spawn dependency.

Verification

dor-lib-common 7/7, dor 63/63, full lib suite 684/684, sidecar bundle, and the vscode-ext esbuild + standalone Vite frontend bundles all build clean (the latter confirms Wall.tsx's new value import from dor/protocol resolves end-to-end).

🤖 Generated with Claude Code

nedtwigg and others added 7 commits June 29, 2026 19:13
dor and the lib agent-browser host each carried a near-identical copy of the
hard-won Windows spawn recipe (cross-spawn for PATHEXT/.cmd, windowsHide,
exit-vs-close with an exit-time output snapshot). Extract it once into a new
dor-lib-common workspace package as spawnAndCapture, and collapse both
helpers to thin adapters over it.

Resolution respects the type-system split: dor avoids @types/node, and the
lib host is esbuild-only (excluded from every tsc), so dor is the sole
type-checking consumer. dor-lib-common's package exports point at its built
dist — a clean, Node-type-free .d.ts for dor's tsc — while every esbuild/Vite
consumer inlines it. dor's prebuild builds dor-lib-common first.

Drops dor's hand-rolled cross-spawn/child_process ambient decls (no longer
imports either) and both packages' direct cross-spawn dependency. The host
test now mocks the dor-lib-common boundary; spawnAndCapture's own behavior is
covered by dor-lib-common's tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dor (parseStreamPort) and the lib host (inline, inside readStreamPort) each
parsed `agent-browser stream status --json` with the same { port } | { data:
{ port } } shape — the host even noted it "Mirrors the parse in dor". Move it
to dor-lib-common as parseStreamPort and call it from both.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dor's sessionForKey (dormouse.<workspaceId>.<key>) and the lib host's
generateGuiSession both hardcoded the dormouse.1. prefix — the host even
noted it was "mirroring dor ab's namespacing." Move sessionForKey and the
workspace id into dor-lib-common and call it from both; the host's GUI
sessions become sessionForKey(`gui-<hex>`).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The eight surface.* control method strings were hardcoded on both sides of
the wire: dor/src/control-client.ts emits them and lib's Wall.tsx dispatches
on them, with no shared constant and no type safety — a rename had to be
mirrored by hand. Add SURFACE_CONTROL_METHODS (and a SurfaceControlMethod
union) to dor/protocol.ts, already the shared protocol module lib imports,
and reference it from both the client and the webview handler.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dor and the lib host independently hardcoded the same agent-browser
contracts: the DORMOUSE_AGENT_BROWSER_BIN override env var, the 'agent-browser'
default binary name, and the ['--session', s, 'stream', 'status', '--json']
invocation that feeds the already-shared parseStreamPort. Move them to
dor-lib-common as AGENT_BROWSER_BIN_ENV, DEFAULT_AGENT_BROWSER_BIN, and
streamStatusArgs, and reference from both.

Not unified: the binary-resolution algorithm itself stays per-package — dor
stats PATH/PATHEXT, while the host resolves by spawning candidates because it
can't trust the GUI login PATH. Only the shared constants move.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up cleanups on the dor-lib-common extraction:
- Drop speculative barrel exports (AGENT_BROWSER_WORKSPACE_ID, the
  SpawnCaptureSuccess/Failure member types) that no consumer imports; make
  the workspace id module-private so callers go through sessionForKey.
- Inline the single-caller spawnAgentBrowser adapter into
  runWithBinaryFallback, dropping the stringly-typed 'ENOENT' sentinel union.
- Add incremental compilation to dor-lib-common's tsc so dor's prebuild
  doesn't fully recompile it on every build/watch.
- Give lib a pretest that builds dor-lib-common, so the host test's
  importOriginal finds its dist on an isolated `pnpm --filter lib test`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9a40e0b
Status: ✅  Deploy successful!
Preview URL: https://e7fd0db7.mouseterm.pages.dev
Branch Preview URL: https://dor-lib-common.mouseterm.pages.dev

View logs

@nedtwigg nedtwigg merged commit 0be21af into main Jun 30, 2026
9 checks passed
@nedtwigg nedtwigg deleted the dor-lib-common branch June 30, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants