server-studio 1.2.2 → 1.2.4

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
@@ -2,6 +2,20 @@
2
2
 
3
3
  Notable changes to Server Studio. Dates are release dates.
4
4
 
5
+ ## 1.2.4 — 2026-08-30
6
+
7
+ - **Fixed:** on Windows, stopping a server could kill an unrelated process. The port was matched
8
+ with `findstr :5173`, which also matches `0.0.0.0:51730`, so a longer port sharing the prefix was
9
+ caught too. Reported and patched by @anupamme in #1.
10
+ - `killPort` no longer builds a shell command at all, on any platform. The port was already
11
+ sanitised by `Number()`, so this is hardening rather than a fix.
12
+
13
+ ## 1.2.3 — 2026-08-30
14
+
15
+ - The badge shown after an update now says **quit & reopen** rather than "restart to finish".
16
+ Reloading the page kept the old process serving it, so the old wording sent people to do the
17
+ one thing that could not work.
18
+
5
19
  ## 1.2.2 — 2026-08-30
6
20
 
7
21
  - The version badge no longer keeps offering an update you have already installed. Once you start
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-studio",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "A tiny dashboard for your local dev servers. One click to run, stop and open them, with one permanent port per project.",
5
5
  "author": "Md Mahdi Hasan",
6
6
  "license": "MIT",
package/src/index.html CHANGED
@@ -859,9 +859,12 @@ async function checkUpdate() {
859
859
  pending = null;
860
860
  }
861
861
  if (pending) {
862
+ // "restart" alone reads as reloading the page, which changes nothing: the old
863
+ // process is still serving it. Say which thing has to be restarted.
862
864
  pill.className = 'ver pending';
863
- pill.textContent = 'restart to finish ' + pending;
864
- pill.title = 'Version ' + pending + ' has been installed. Quit and reopen Server Studio to run it.';
865
+ pill.textContent = 'quit & reopen for ' + pending;
866
+ pill.title = pending + ' is installed. Quit Server Studio itself and open it again, ' +
867
+ 'reloading this page keeps the old version running.';
865
868
  pill.onclick = null;
866
869
  return;
867
870
  }
@@ -895,7 +898,7 @@ async function runUpdate() {
895
898
  // update. Continuing to show it after a successful update reads as a failure.
896
899
  try { localStorage.setItem('ss_updating_to', updateInfo.latest); } catch (e) {}
897
900
  checkUpdate();
898
- toast('Updating in ' + TERM_NAME + '. Restart Server Studio when it finishes.');
901
+ toast('Updating in ' + TERM_NAME + '. Quit Server Studio and open it again when it finishes.');
899
902
  }
900
903
  else toast('Could not start the update. Run this yourself: npm install -g server-studio', true);
901
904
  }
package/src/platform.js CHANGED
@@ -4,7 +4,7 @@
4
4
  const fs = require('fs');
5
5
  const os = require('os');
6
6
  const path = require('path');
7
- const { execFile, exec } = require('child_process');
7
+ const { execFile } = require('child_process');
8
8
 
9
9
  const WIN = process.platform === 'win32';
10
10
  const MAC = process.platform === 'darwin';
@@ -86,15 +86,21 @@ function killPort(port, cb) {
86
86
  if (!p) return cb(new Error('bad port'));
87
87
  if (WIN) {
88
88
  // netstat lists the owning PID in the last column of LISTENING rows.
89
- return exec('netstat -ano -p tcp | findstr LISTENING | findstr :' + p, (err, stdout) => {
89
+ // execFile (no shell) avoids ever building a shell command string from `port`.
90
+ return execFile('netstat', ['-ano', '-p', 'tcp'], (err, stdout) => {
90
91
  const pids = new Set(String(stdout || '').trim().split(/\r?\n/)
92
+ .filter(l => /LISTENING/.test(l) && l.includes(':' + p + ' '))
91
93
  .map(l => l.trim().split(/\s+/).pop())
92
94
  .filter(x => /^\d+$/.test(x) && x !== '0'));
93
95
  if (!pids.size) return cb(null);
94
- exec([...pids].map(id => 'taskkill /PID ' + id + ' /T /F').join(' & '), () => cb(null));
96
+ execFile('taskkill', ['/T', '/F', ...[...pids].flatMap(id => ['/PID', id])], () => cb(null));
95
97
  });
96
98
  }
97
- return exec('lsof -nti tcp:' + p + ' | xargs kill 2>/dev/null', () => cb(null));
99
+ return execFile('lsof', ['-nti', 'tcp:' + p], (err, stdout) => {
100
+ const pids = String(stdout || '').trim().split(/\r?\n/).filter(Boolean);
101
+ if (!pids.length) return cb(null);
102
+ execFile('kill', pids, () => cb(null));
103
+ });
98
104
  }
99
105
 
100
106
  /* ---------- native "choose a folder" dialog ---------- */