server-studio 1.0.1 → 1.1.0

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/README.md CHANGED
@@ -25,19 +25,20 @@ Node.js is the only requirement. No npm install inside the app, no Electron, no
25
25
 
26
26
  ## Install
27
27
 
28
- Installing the package only puts the `server-studio` command on your PATH. Setting up the app and
29
- the skill is a second, explicit step, because it writes outside the package. Either of these works:
30
-
31
28
  ```bash
32
- npx server-studio install
29
+ npm install -g server-studio
33
30
  ```
34
31
 
32
+ That is the whole thing. A global install sets up the app and the skill for you.
33
+
34
+ If you would rather not install globally, this does the same without leaving anything behind:
35
+
35
36
  ```bash
36
- npm install -g server-studio && server-studio install
37
+ npx server-studio install
37
38
  ```
38
39
 
39
- Running `server-studio` with no arguments does the same thing as `server-studio install`, so if you
40
- installed globally and typed the bare command, you are already set up.
40
+ Installing this as a project dependency deliberately does **not** set anything up, since that would
41
+ write outside the package on a machine that only wanted the library.
41
42
 
42
43
  **macOS**
43
44
 
@@ -154,6 +155,22 @@ node ~/.claude/skills/server-studio/register-server.js \
154
155
  for a project that already exists updates the other fields but keeps the port locked, which is the
155
156
  whole point.
156
157
 
158
+ ### Using it from any editor or script
159
+
160
+ The Claude skill is a convenience wrapper, not the mechanism. Registering a server is a plain
161
+ command with no AI involved, so any tool that can run a shell command can use it. That includes
162
+ Cursor, Copilot, Windsurf, a Makefile, a shell alias, or you:
163
+
164
+ ```bash
165
+ server-studio add --name "Portfolio Site" --cwd "$PWD" --command "npm run dev" --assign
166
+ ```
167
+
168
+ `--assign` picks a port nothing else uses and prints `PORT <n>`, so a script can read that line and
169
+ write the port into the project config. Re-running for the same project updates its fields and keeps
170
+ its port locked, which is what makes this safe to call from a build step.
171
+
172
+ Run `server-studio add` with no arguments for the full list of fields.
173
+
157
174
  ### Backups
158
175
 
159
176
  **Export** saves your whole list to `server-studio-backup.json`. **Import** loads one back.
@@ -165,7 +182,8 @@ have anything you care about.
165
182
 
166
183
  **The app**, a dashboard served at `127.0.0.1:4587`.
167
184
 
168
- **The Claude Code skill**, so Claude can register servers for you.
185
+ **The Claude Code skill**, so Claude can register servers for you. It wraps
186
+ `server-studio add`, which works on its own from any tool.
169
187
 
170
188
  **The Cowork plugin**, the same skill as a `/server-studio` command. The installer copies it next to
171
189
  your data file and prints the path, then you open that file to install it. To rebuild it from source,
package/bin/cli.js CHANGED
@@ -139,6 +139,35 @@ function uninstall() {
139
139
  }
140
140
  }
141
141
 
142
+ // The registration script has nothing Claude-specific in it, so it is exposed as a
143
+ // plain command too. Any editor, agent or shell script can call this.
144
+ function add() {
145
+ const { spawnSync } = require('child_process');
146
+ const script = path.join(ROOT, 'skill', 'register-server.js');
147
+ const passthrough = args.filter(a => a !== 'add');
148
+ if (!passthrough.length) {
149
+ console.log(`Add or update a server from the command line.
150
+
151
+ server-studio add --name "Portfolio Site" --cwd "$PWD" --command "npm run dev" --assign
152
+
153
+ --name what to call it
154
+ --project a line of context
155
+ --category groups cards into filter tabs
156
+ --cwd the project folder
157
+ --command how to start it
158
+ --url address or bare port; omit with --assign
159
+ --tag small label, usually the stack
160
+ --note anything to remember
161
+ --assign pick a free port nothing else uses, and print it
162
+ --force allow an existing project to move to a different port
163
+
164
+ Re-running for the same project updates its fields but keeps its port locked.`);
165
+ return;
166
+ }
167
+ const r = spawnSync(process.execPath, [script, ...passthrough], { stdio: 'inherit' });
168
+ process.exit(r.status === null ? 1 : r.status);
169
+ }
170
+
142
171
  function start() {
143
172
  DATA_DIR = dataDir();
144
173
  const { spawn } = require('child_process');
@@ -153,6 +182,7 @@ function help() {
153
182
 
154
183
  npx server-studio install install the app + Claude Code skill
155
184
  npx server-studio start run the dashboard (works on macOS, Windows and Linux)
185
+ npx server-studio add ... save a server from the command line
156
186
  npx server-studio uninstall remove them (keeps your saved servers)
157
187
 
158
188
  Options
@@ -166,5 +196,6 @@ Options
166
196
  if (cmd === 'help') help();
167
197
  else if (cmd === 'install') install();
168
198
  else if (cmd === 'start') start();
199
+ else if (cmd === 'add') add();
169
200
  else if (cmd === 'uninstall') uninstall();
170
201
  else { console.error('unknown command: ' + cmd + '\n'); help(); process.exit(1); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-studio",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
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",
@@ -1,25 +1,39 @@
1
1
  #!/usr/bin/env node
2
- // npm only puts the command on PATH. Setting up the app and the skill writes outside
3
- // the package, so it stays an explicit step rather than a silent side effect of install.
4
- // This just makes sure nobody is left wondering why nothing appeared.
2
+ // Runs the setup automatically after `npm install -g server-studio`, so one command
3
+ // is enough. Deliberately narrow: only a global install triggers it, because setting
4
+ // up writes outside the package and that should never happen to someone who merely
5
+ // pulled this in as a dependency.
6
+ //
7
+ // This must never fail the install. Every path exits 0.
5
8
  'use strict';
6
9
 
7
10
  const path = require('path');
11
+ const { execFileSync } = require('child_process');
8
12
 
9
- // Quiet in CI, and quiet while developing this repo itself.
10
- if (process.env.CI) process.exit(0);
11
- if (process.env.INIT_CWD && path.resolve(process.env.INIT_CWD) === path.resolve(__dirname, '..')) {
13
+ function skip(why) {
14
+ if (process.env.SERVER_STUDIO_DEBUG) console.log('server-studio: skipped setup (' + why + ')');
12
15
  process.exit(0);
13
16
  }
14
- // npx runs the command straight after installing, so the hint would be noise.
15
- if ((process.env.npm_command === 'exec') || /_npx/.test(__dirname)) process.exit(0);
16
-
17
- console.log(`
18
- Server Studio: the command is installed, but nothing is set up yet.
19
17
 
20
- Finish with:
21
- server-studio install
18
+ if (process.env.CI) skip('CI');
19
+ // A dependency install must not touch /Applications or ~/.claude.
20
+ if (process.env.npm_config_global !== 'true') skip('not a global install');
21
+ // Do not run while developing this repo itself.
22
+ if (process.env.INIT_CWD && path.resolve(process.env.INIT_CWD) === path.resolve(__dirname, '..')) {
23
+ skip('local checkout');
24
+ }
22
25
 
23
- That adds the app and the Claude Code skill. See what it will do first with:
24
- server-studio install --dry-run
25
- `);
26
+ try {
27
+ const out = execFileSync(process.execPath, [path.join(__dirname, '..', 'bin', 'cli.js'), 'install'], {
28
+ encoding: 'utf8',
29
+ });
30
+ console.log(out.trim());
31
+ } catch (e) {
32
+ // Setup failing is not a reason for `npm install` to fail. Say so and move on.
33
+ console.log(
34
+ 'server-studio: could not finish setup automatically.\n' +
35
+ ' Run it yourself with: server-studio install\n' +
36
+ ' Reason: ' + (e && e.message ? e.message.split('\n')[0] : 'unknown')
37
+ );
38
+ }
39
+ process.exit(0);