@gachlab/devup 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to `@gachlab/devup` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.9.2] — 2026-05-22
9
+
10
+ Critical hotfix. **All 0.9.x users should upgrade immediately.**
11
+
12
+ ### Fixed
13
+ - **Bundle's top-level `main()` would fire when devup was imported as a library.** When a user's `devup.config.ts` did `import { defineConfig } from '@gachlab/devup'`, Node loaded our compiled `dist/index.js` to satisfy the import — and the bundle's top-level `main()` invocation ran, starting a SECOND, concurrent devup process. Symptoms: every line of output duplicated, three or more racing instances of the same service spawning in milliseconds, ports clobbered, the daemon's socket created but never bound, `devup ctl ping` ECONNREFUSED. Fix: guard `main()` with a `realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)` check so it only fires when the script is invoked directly (as the `devup` binary), not when imported.
14
+ - **`devup ctl` crashed with an unhandled `error` event on ECONNREFUSED.** The socket-error handler was attached to the connection but Node's `readline.createInterface` re-forwarded the error through its own emitter, which had no listener, so the process crashed instead of reporting cleanly. Now we attach the handler on both the socket and the readline interface.
15
+
16
+ ### Why this matters
17
+ Every devup invocation that loaded a config file (i.e. everything except `--version` / `--help`) was silently running two instances of itself. That is the root cause of every weird behaviour reported against 0.9.0 / 0.9.1: duplicated prompts, daemons that "die" right after starting, sockets that exist but refuse connections, port-takeover prompts firing for ports the user expected devup to own.
18
+
8
19
  ## [0.9.1] — 2026-05-22
9
20
 
10
21
  Hotfix for two issues reported moments after 0.9.0 hit:
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/control-plane/client.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAMhF;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CACrB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;+FAC+F;AAC/F,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,EACrC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,GAC7B,MAAM,IAAI,CAqBZ"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/control-plane/client.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAMhF;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CACrB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,OAAO,CAAC,CAyBlB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;+FAC+F;AAC/F,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,EACrC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,GAC7B,MAAM,IAAI,CA0BZ"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.ts
4
4
  import React7 from "react";
5
5
  import { render } from "ink";
6
- import { readFileSync as readFileSync4 } from "fs";
6
+ import { readFileSync as readFileSync4, realpathSync } from "fs";
7
7
  import { dirname as dirname7, join as join10 } from "path";
8
8
  import { fileURLToPath as fileURLToPath2 } from "url";
9
9
  import { homedir as homedir5 } from "os";
@@ -884,17 +884,31 @@ Start it with \`devup\` first.`
884
884
  }
885
885
  function sendRpc(socketPath, method, params = {}) {
886
886
  return new Promise((resolve4, reject) => {
887
+ let settled = false;
888
+ const fail = (err) => {
889
+ if (!settled) {
890
+ settled = true;
891
+ reject(err);
892
+ }
893
+ };
894
+ const ok = (v) => {
895
+ if (!settled) {
896
+ settled = true;
897
+ resolve4(v);
898
+ }
899
+ };
887
900
  const c = createConnection(socketPath);
888
- c.on("error", reject);
889
901
  const rl = createInterface2({ input: c });
902
+ c.on("error", fail);
903
+ rl.on("error", fail);
890
904
  rl.once("line", (l) => {
891
905
  c.end();
892
906
  try {
893
907
  const msg = JSON.parse(l);
894
- if (msg.error) reject(new Error(msg.error.message ?? String(msg.error)));
895
- else resolve4(msg.result);
908
+ if (msg.error) fail(new Error(msg.error.message ?? String(msg.error)));
909
+ else ok(msg.result);
896
910
  } catch (e) {
897
- reject(e);
911
+ fail(e);
898
912
  }
899
913
  });
900
914
  c.write(JSON.stringify({ id: 1, method, params }) + "\n");
@@ -904,7 +918,9 @@ function openStream(socketPath, method, params, onFrame, onError) {
904
918
  const c = createConnection(socketPath);
905
919
  const rl = createInterface2({ input: c });
906
920
  let ackDone = false;
907
- c.on("error", (err) => onError?.(err));
921
+ const onErr = (err) => onError?.(err);
922
+ c.on("error", onErr);
923
+ rl.on("error", onErr);
908
924
  c.write(JSON.stringify({ id: 1, method, params }) + "\n");
909
925
  rl.on("line", (l) => {
910
926
  try {
@@ -4207,10 +4223,22 @@ function askYesNo(question) {
4207
4223
  process.stdin.once("end", onEnd);
4208
4224
  });
4209
4225
  }
4210
- main().catch((e) => {
4211
- console.error(e);
4212
- process.exit(1);
4213
- });
4226
+ function isInvokedDirectly() {
4227
+ const argvPath = process.argv[1];
4228
+ if (!argvPath) return false;
4229
+ const moduleFile = fileURLToPath2(import.meta.url);
4230
+ try {
4231
+ return realpathSync(argvPath) === moduleFile;
4232
+ } catch {
4233
+ return argvPath === moduleFile;
4234
+ }
4235
+ }
4236
+ if (isInvokedDirectly()) {
4237
+ main().catch((e) => {
4238
+ console.error(e);
4239
+ process.exit(1);
4240
+ });
4241
+ }
4214
4242
  export {
4215
4243
  defineConfig
4216
4244
  };