castle-web-cli 0.4.9 → 0.4.11

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/dist/init.js CHANGED
@@ -70,7 +70,6 @@ function makePackageJson(projectDir) {
70
70
  private: true,
71
71
  type: 'module',
72
72
  scripts: {
73
- serve: `node ${cliEntry} serve . --open`,
74
73
  restart: `node ${cliEntry} restart .`,
75
74
  screenshot: `node ${cliEntry} screenshot .`,
76
75
  'save-deck': `node ${cliEntry} save-deck .`,
package/dist/serve.js CHANGED
@@ -74,6 +74,38 @@ function readDeckContext(projectDir) {
74
74
  }
75
75
  const DEFAULT_PORT = 5757;
76
76
  const SCREENSHOT_REQUEST_TTL_MS = 15_000;
77
+ function readServeJson(projectDir) {
78
+ try {
79
+ const raw = fs.readFileSync(path.join(projectDir, '.castle', 'serve.json'), 'utf8');
80
+ const info = JSON.parse(raw);
81
+ if (typeof info.port !== 'number' || typeof info.wsPort !== 'number' || typeof info.pid !== 'number')
82
+ return null;
83
+ return { port: info.port, wsPort: info.wsPort, pid: info.pid };
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ function isPidAlive(pid) {
90
+ try {
91
+ process.kill(pid, 0);
92
+ return true;
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ }
98
+ // Return the live serve already owning this deck, if any. Lets repeated
99
+ // `castle-web serve`/`npm run serve` calls become idempotent instead of
100
+ // piling up independent vite instances on adjacent ports.
101
+ function existingServe(projectDir) {
102
+ const info = readServeJson(projectDir);
103
+ if (!info)
104
+ return null;
105
+ if (!isPidAlive(info.pid))
106
+ return null;
107
+ return info;
108
+ }
77
109
  export async function serve(dir, options = {}) {
78
110
  const projectDir = path.resolve(dir);
79
111
  if (!fs.existsSync(projectDir)) {
@@ -84,6 +116,18 @@ export async function serve(dir, options = {}) {
84
116
  console.error(`No index.html found in ${projectDir}`);
85
117
  process.exit(1);
86
118
  }
119
+ // If a live serve is already running for this deck, reuse it. Skip the
120
+ // dedup when --port / --host are passed (caller wants those specifics, so
121
+ // start a fresh serve even if another is up).
122
+ if (!options.port && !options.host) {
123
+ const existing = existingServe(projectDir);
124
+ if (existing) {
125
+ console.log(`Serve already running for ${projectDir}`);
126
+ console.log(`URL: http://localhost:${existing.port}`);
127
+ console.log(`PID: ${existing.pid}`);
128
+ return;
129
+ }
130
+ }
87
131
  // --detach is kept for back-compat. Agent evals (and any harness running
88
132
  // castle-web in a context that can't manage a foreground process) should
89
133
  // prefer the CASTLE_WEB_CLI_DETACH=1 env var instead.
@@ -210,12 +254,17 @@ async function serveDetached(projectDir, options) {
210
254
  args.push('--host', options.host);
211
255
  if (options.open)
212
256
  args.push('--open');
213
- // We stay in the parent's process group (no detached: true) so that when
257
+ // CASTLE_WEB_CLI_DETACH=1 spawn as a new session leader (fully
258
+ // independent; survives caller). This is the eval-harness mode where the
259
+ // harness manages cleanup itself.
260
+ // Default → child stays in the caller's process group / session, so when
214
261
  // the agent / shell that invoked `castle-web init` exits, SIGHUP reaches
215
- // this serve and it dies with the session. The `.unref()` is what lets
216
- // the calling node process exit while the serve keeps running until then.
262
+ // this serve and it dies with the session.
263
+ // `.unref()` is what lets the calling node process exit either way.
264
+ const fullDetach = process.env.CASTLE_WEB_CLI_DETACH === '1';
217
265
  const child = spawn(process.execPath, [entry, ...args], {
218
266
  cwd: projectDir,
267
+ detached: fullDetach,
219
268
  stdio: ['ignore', logFd, logFd],
220
269
  env: process.env,
221
270
  });
@@ -3,7 +3,6 @@
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "scripts": {
6
- "serve": "node ../../cli/dist/index.js serve . --open",
7
6
  "restart": "node ../../cli/dist/index.js restart .",
8
7
  "screenshot": "node ../../cli/dist/index.js screenshot .",
9
8
  "check": "eslint . && jscpd && node --input-type=module -e \"const { bundleProject } = await import('../../cli/dist/bundle.js'); await bundleProject('.');\""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "castle-web-cli",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "castle-web": "./dist/index.js"