Skip to content

feat(scripts): stop every Builder process with bun run dev:stop - #208

Merged
brianjfox merged 2 commits into
mainfrom
feat/dev-stop
Nov 6, 2026
Merged

brianjfox merged 2 commits into
mainfrom
feat/dev-stop

Conversation

@brianjfox

Copy link
Copy Markdown
Contributor

What

Adds bun run dev:stop, which stops every Builder process on this machine and names whatever else holds a port bun run dev needs.

Why

A bun run dev that was interrupted, or run from another checkout, leaves hubs, migrations, UI dev servers, sidecars and live-app hosts behind, and the next start fails on a taken port with no word on who holds it.

Changes

  • scripts/dev-stop.ts: finds the hub, migration runner, UI dev server and the processes they spawned, from this checkout or any other checkout of the same package, and stops them. Other projects' bun run dev processes and a Docker Compose stack are left alone and named when they hold a needed port. --dry-run only lists.
  • test/integration/dev-stop.test.ts: covers process selection, port parsing and the dotenv reading.
  • package.json: the dev:stop script.
  • CONTRIBUTING.md and the DEV.md scripts table describe it.

Add scripts/dev-stop.ts, which stops the hubs, migrations, UI dev servers
and the sidecars, live-app hosts and build tools they spawned, from this
checkout or any other checkout of the same package, and names whatever
else holds a port bun run dev needs, such as another project's dev server
or the Compose stack. Other projects' processes are left alone.

Document it in CONTRIBUTING.md and the DEV.md scripts table.

@corbits-triage corbits-triage 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.

Triage requests changes:

  • Conventions: added code matches a code pattern
    • scripts/dev-stop.ts:334-338 nested-ternary: Nested ternary; use if statements or a lookup.
  • Errors kept: added code matches a code pattern
    • scripts/dev-stop.ts:150-152 bare-catch: A catch without a binding drops the error; check for the expected failure, or catch it and rethrow the rest.
    • scripts/dev-stop.ts:290-292 bare-catch: A catch without a binding drops the error; check for the expected failure, or catch it and rethrow the rest.
    • scripts/dev-stop.ts:321-323 bare-catch: A catch without a binding drops the error; check for the expected failure, or catch it and rethrow the rest.
    • scripts/dev-stop.ts:345-347 bare-catch: A catch without a binding drops the error; check for the expected failure, or catch it and rethrow the rest.
    • scripts/dev-stop.ts:363-365 bare-catch: A catch without a binding drops the error; check for the expected failure, or catch it and rethrow the rest.
    • test/integration/dev-stop.test.ts:58 interchange-by-path: Reaches vendored Interchange source by path; import the @intx/* package.
    • test/integration/dev-stop.test.ts:64 interchange-by-path: Reaches vendored Interchange source by path; import the @intx/* package.
    • test/integration/dev-stop.test.ts:94 interchange-by-path: Reaches vendored Interchange source by path; import the @intx/* package.
  • Invented fallbacks: added code matches a code pattern
    • scripts/dev-stop.ts:45 empty-fallback: Invented fallback (an empty string, list, object or zero); handle the missing value instead.
    • scripts/dev-stop.ts:139 empty-fallback: Invented fallback (an empty string, list, object or zero); handle the missing value instead.
    • scripts/dev-stop.ts:140 empty-fallback: Invented fallback (an empty string, list, object or zero); handle the missing value instead.
    • scripts/dev-stop.ts:142 empty-fallback: Invented fallback (an empty string, list, object or zero); handle the missing value instead.
    • scripts/dev-stop.ts:206 empty-fallback: Invented fallback (an empty string, list, object or zero); handle the missing value instead.
    • scripts/dev-stop.ts:276 empty-fallback: Invented fallback (an empty string, list, object or zero); handle the missing value instead.

…ted fallbacks

Each catch checks for the failure it expects, a missing file or a gone
process, and rethrows the rest; a missing field is skipped instead of
read as an empty string; the checkout resolver uses if statements. The
test names the sidecar entry points once, outside any call.
@corbits-triage

corbits-triage Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Triage: Unsure

Asking a maintainer about:

  • added code matches a code pattern: scripts/dev-stop.ts:445 hand-rolled-wait: A hand-rolled sleep; wait on an event, or on an Interchange wait, retry or timeout where one exists., scripts/dev-stop.ts:451 hand-rolled-wait: A hand-rolled sleep; wait on an event, or on an Interchange wait, retry or timeout where one exists.

@corbits-triage
corbits-triage Bot dismissed their stale review November 6, 2026 14:00

Nothing triage asked to change still fails, so this request no longer stands.

Comment thread scripts/dev-stop.ts
Comment on lines +232 to +234
return parseSsListeners(run(["ss", "-Hltnp"])).filter((listener) =>
ports.includes(listener.port),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 · On Linux, ports held by root-owned processes such as docker-proxy are never reported

When ss -p runs as an unprivileged user, it leaves out the users:((...pid=N...)) part for sockets owned by other users. parseSsListeners only adds a listener when it finds a pid= match, so the line is dropped. A Docker Compose port published through the root-owned docker-proxy, or any other root listener, is then never named, even though the PR says naming such holders is the goal.

On Linux, run docker compose up with port 8000 published, then run bun run dev:stop as a normal user. Nothing is reported for port 8000.

Resolve this comment. Triage will not finish while it is open.

Comment thread scripts/dev-stop.ts
Comment on lines +106 to +109
const byPath = [...roots].some((root) =>
runsFileOfCheckout(info.command, root),
);
if (byEntry || byPath) selected.add(info.pid);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 · Matching on the command path kills editor language servers and other tools that run from the checkout's node_modules

Any process run by node or bun, or any executable under /node_modules/, whose command line contains <root>/node_modules/ (or apps/, packages/, and so on) is selected, whatever it is. Language servers and linters started by an editor from the workspace, such as typescript-language-server, tsserver or biome lsp, match this and get SIGTERM, then SIGKILL.

Run bun run dev:stop while an editor is running node <checkout>/node_modules/.bin/typescript-language-server --stdio.

Resolve this comment. Triage will not finish while it is open.

@brianjfox
brianjfox added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit 0525b87 Nov 6, 2026
9 checks passed
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