Skip to content
This repository was archived by the owner on Oct 16, 2026. It is now read-only.

feat(dev): stable per-package ports, client bundle + /_assets, kody.dev.prebuild, faster rebuilds - #59

Merged
kody-bot merged 14 commits into
mainfrom
cursor/kody-dev-ports-assets-speed-354f
Oct 15, 2026
Merged

kody-bot merged 14 commits into
mainfrom
cursor/kody-dev-ports-assets-speed-354f

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Stack: #63 → #58 → #61 → #59 → #60

Intent

Fourth of five stacked kody dev PRs (base: the agent mode PR). Adds stable ports, platform-parity assets (so packages like the slideshow no longer need their own serve.mjs), a prebuild hook, and faster saves.

Door: two-way (kody.dev is new, local-only manifest config; publish ignores it.)

Cleanup: none

Summary

  • Ports.
    • The default port is derived from kody.id (4100–4999), so URLs and OAuth redirect URIs survive restarts. If it is taken, kody dev walks to the next free port (up to 20).
    • An explicit --port is exact. EADDRINUSE becomes dev_port_in_use, with an lsof command and alternatives. --port 0 means any free port. Bad values are rejected (invalid_port).
    • Starting a second kody dev for the same package and target without --port fails with dev_already_running, naming the running URL and pid.
  • Client bundle and assets, same URLs as a published app.
    • kody.app.client (string, or { entry, externals }) is bundled for the browser (esm, es2022, inline source map) and served at <appBasePath>/_assets/client.<16-char base64url sha256>.js.
    • packageContext.clientModuleUrl points at the client bundle, and /_assets/__version.json reports { clientModuleUrl, assetBasePath, publishedCommit: null }.
    • Files in kody.app.assets are served under /_assets/ with the platform's content types, no-store, and traversal protection.
    • Editing an asset reloads open pages.
  • kody.dev.prebuild runs a shell command from the package root before every build, with KODY_DEV=1. Output is tagged [prebuild]. A non-zero exit shows as a build error with the output tail. Its own file writes do not retrigger a build. kody.dev.ignore adds watcher ignore prefixes.
  • Speed. esbuild incremental context()/rebuild() for both bundles, and the debounce drops from 120ms to 30ms. workerd has no config reload, so blue/green restart stays.
  • Fix: a debounce timer that fired after close() used to create an esbuild context that was never disposed, which kept Node alive. There is a regression test.

Measurements

Demo app, --target mock, 15 saves per run, same machine:

startup save → visible p50 non-200 during swaps
1.23.0 ~230ms ~148ms 64–70
this stack ~250–320ms ~58ms 0

Rebuild itself is ~23–27ms. Startup is roughly flat: workerd boot dominates, and the reaper and registry add a few ms.

Testing

  • npm run validate passes.
  • New test/dev-ports-assets.test.ts covers:
    • the stable default port and its range;
    • --port parsing;
    • next-free fallback versus the explicit-port error;
    • asset path decoding and traversal;
    • kody.dev and client object-form manifest parsing;
    • client bundle, clientModuleUrl, __version.json, assets, a client edit changing the hash, and an asset edit;
    • prebuild running before each build without retriggering, plus prebuild failure;
    • the dev_already_running refusal.
  • New regression test: a save just before close() never starts a rebuild after close.
Open in Web Open in Cursor 

Note

Medium Risk
Changes core kody dev listen/bind, rebuild, and request routing; prebuild runs arbitrary shell commands from package.json (local dev only).

Reviewed by Cursor Bugbot for commit 97addf7. Bugbot is set up for automated code reviews on this repo. Configure here.

@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/package-manifest.ts
Comment thread src/package-app-dev.ts
Comment thread src/dev/prebuild.ts Outdated
@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

1 similar comment
@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/dev/dev-watcher.ts Outdated
@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/dev/prebuild.ts
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from fd47e44 to 7b70202 Compare October 15, 2026 06:27
@cursor
cursor Bot force-pushed the cursor/kody-dev-agent-json-354f branch from 9b119c7 to 26c9bff Compare October 15, 2026 06:27
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch 3 times, most recently from 38abb9c to e813630 Compare October 15, 2026 06:46
@cursor
cursor Bot force-pushed the cursor/kody-dev-agent-json-354f branch from 57fe438 to cf978e1 Compare October 15, 2026 06:48
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from e813630 to 03b005d Compare October 15, 2026 06:48
@cursor
cursor Bot force-pushed the cursor/kody-dev-agent-json-354f branch from cf978e1 to 4fdadfe Compare October 15, 2026 06:50
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from 03b005d to 7d9acfa Compare October 15, 2026 06:50
@cursor
cursor Bot force-pushed the cursor/kody-dev-agent-json-354f branch from 4fdadfe to 3440bc9 Compare October 15, 2026 06:51
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from 7d9acfa to 5aa3010 Compare October 15, 2026 06:51

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/dev-command.ts
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from 5aa3010 to 758da87 Compare October 15, 2026 07:05

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/package-app-dev.ts Outdated
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from de17017 to 9a61a64 Compare October 15, 2026 07:18
@cursor
cursor Bot force-pushed the cursor/kody-dev-agent-json-354f branch from cb20f60 to d5bb07a Compare October 15, 2026 07:18
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from 9a61a64 to f1dd581 Compare October 15, 2026 07:19
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch 5 times, most recently from 69a01dd to e1d1de4 Compare October 15, 2026 07:57
Base automatically changed from cursor/kody-dev-agent-json-354f to main October 15, 2026 07:59
cursoragent and others added 11 commits October 15, 2026 08:00
…ev.prebuild, faster rebuilds

- Default port is derived from kody.id (4100-4999) and walks to the next
  free port; an explicit --port is exact and EADDRINUSE explains the fix.
  A second kody dev for the same package/target fails with the running URL.
- Serve kody.app.client at /_assets/client.<hash>.js (packageContext.
  clientModuleUrl), kody.app.assets under /_assets/, and __version.json,
  matching published apps. Asset edits reload open pages.
- kody.dev.prebuild runs before every build (KODY_DEV=1); failures are
  build errors; its own writes don't retrigger. kody.dev.ignore adds
  watcher ignore prefixes.
- esbuild incremental contexts and a 30ms debounce: save-to-visible p50
  ~148ms -> ~58ms on the demo app.
…he server

A debounce timer that fired after close() created a fresh incremental
context that was never disposed and kept Node alive.
… partial prebuild lines

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Bugbot: detached prebuild trees survived hard CLI death because the
reaper only SIGKILLed the shell pid. trackGroup/untrackGroup tell the
reaper to kill -pid so sh and its children die together.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Use /bin/kill -s KILL -- -pid for tracked groups, and wait for both
the shell and grandchild to die in the regression test (CI flake).

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Prebuild rewrites generated inputs; absorbing those fingerprints before
esbuild runs keeps track()'s mid-build detection from queuing an extra
rebuild (gen-3) on every edit.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Bugbot: write the registry entry from onListening (before the first
build) so a second kody dev during startup hits dev_already_running
instead of claiming the next port and overwriting the registration.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
A failing kody.dev.prebuild still writes files; absorb them into the
watcher baseline in runPrebuildStep's finally so the 1s poll cannot
loop rebuilds off that output.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Rebase onto the ready-file shutdown fix left conflict markers; keep
onListening early registration plus shutdown-on-ready-file-error.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Keep prebuild settle gating and fold mid-build watcher events into the
active rebuild loop.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@cursor
cursor Bot force-pushed the cursor/kody-dev-ports-assets-speed-354f branch from e1d1de4 to fb400c0 Compare October 15, 2026 08:00
Clear changedFiles/rebuildAgain and the debounce queue after rebaseline on
prebuild failure so chokidar events from the failed run cannot restart the
rebuild loop (CI: failed prebuild must not retrigger).

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread src/dev-command.ts
Comment thread src/package-app-dev.ts Outdated
… throws

Explicit --port starts a second server and must not overwrite the primary
attach registry. If onListening fails after the port is bound, close the
HTTP listen handle so the process does not leak.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

Resolve package-app-dev import conflict: keep client-asset helpers from
ports and the gatewayFetchStream local runtime bridge from main.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 97addf7. Configure here.

@kody-bot
kody-bot merged commit 3e212c0 into main Oct 15, 2026
7 checks passed
@kody-bot
kody-bot deleted the cursor/kody-dev-ports-assets-speed-354f branch October 15, 2026 08:35
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.26.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants