ugly-app 0.1.422 → 0.1.424

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.
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAMA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA2E9C"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAOA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAiF9C"}
package/dist/cli/build.js CHANGED
@@ -2,6 +2,7 @@ import { execSync } from 'child_process';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { runExportCollections } from './exportCollections.js';
5
+ import { nodeBinCommand } from './resolveBin.js';
5
6
  import { runExportWorkers } from './workerGen.js';
6
7
  export async function runBuild() {
7
8
  // Emit database-collections.json first. Fast, pure TS import — fails
@@ -27,9 +28,15 @@ export const buildId = '${buildId}';
27
28
  fs.rmSync(distDir, { recursive: true, force: true });
28
29
  console.log('[Build] Cleaned dist/');
29
30
  }
30
- // Run vite build
31
+ // Run vite build. `npx vite build` does not work in pnpm-strict
32
+ // worktrees (vite is hoisted into `.pnpm/...` and not linked to
33
+ // top-level `.bin/`); resolve the bin path through Node module
34
+ // resolution instead. Same for esbuild + tsc below.
31
35
  console.log('[Build] Running vite build...');
32
- execSync('npx vite build', { stdio: 'inherit', cwd: process.cwd() });
36
+ execSync(nodeBinCommand('vite', 'build'), {
37
+ stdio: 'inherit',
38
+ cwd: process.cwd(),
39
+ });
33
40
  // Bundle server with esbuild (only for simple projects without custom server build)
34
41
  const serverEntry = path.join(process.cwd(), 'server', 'index.ts');
35
42
  const hasCustomServerBuild = fs.existsSync(path.join(process.cwd(), 'vite.config.server.js'));
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AA0DA,wBAAsB,MAAM,CAAC,IAAI,GAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAqC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoKzH"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AA4DA,wBAAsB,MAAM,CAAC,IAAI,GAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAqC,GAAG,OAAO,CAAC,IAAI,CAAC,CA6MzH"}
package/dist/cli/dev.js CHANGED
@@ -1,7 +1,9 @@
1
- import { exec, execSync, spawn } from 'child_process';
1
+ import { exec, execSync } from 'child_process';
2
2
  import fs from 'fs';
3
3
  import net from 'net';
4
4
  import path from 'path';
5
+ import { createRequire } from 'module';
6
+ import concurrently from 'concurrently';
5
7
  /**
6
8
  * Return the PID of the process listening on `port`, or null if none.
7
9
  * Cross-platform; shells out to `lsof` on Unix and `netstat` on Windows.
@@ -127,79 +129,108 @@ export async function runDev(opts = { watch: false, verbose: false }) {
127
129
  console.log(`[ugly-app] NODE_ENV: ${process.env['NODE_ENV']}`);
128
130
  console.log(`[ugly-app] POSTGRES_URL: ${process.env['POSTGRES_URL'] ?? '(default)'}`);
129
131
  }
130
- return new Promise((resolve, reject) => {
131
- const isWin = process.platform === 'win32';
132
- const noFail = (cmd) => isWin ? `(${cmd} || (exit /b 0))` : `${cmd} || true`;
133
- const binDir = path.join(process.cwd(), 'node_modules', '.bin') + path.sep;
134
- const bin = (name) => `"${binDir}${name}"`;
135
- const q = (s) => `"${s.replace(/"/g, '\\"')}"`;
136
- const serverCmd = opts.watch
137
- ? `${bin('tsx')} watch --clear-screen=false --ignore ./client --ignore "**/node_modules/**" server/index.ts`
138
- : `${bin('tsx')} server/index.ts`;
139
- const hasEsw = fs.existsSync(path.join(binDir, 'esw'));
140
- const rawFlag = isWin ? '--raw' : '';
141
- const namesFlag = isWin
142
- ? ''
143
- : hasEsw ? '--names server,tsc,eslint' : '--names server,tsc';
144
- const colorsFlag = isWin
145
- ? ''
146
- : hasEsw ? '--prefix-colors green,yellow,magenta' : '--prefix-colors green,yellow';
147
- const cmd = opts.watch
148
- ? [
149
- bin('concurrently'),
150
- namesFlag,
151
- colorsFlag,
152
- rawFlag,
153
- '--kill-others-on-fail',
154
- '--handle-input',
155
- q(serverCmd),
156
- q(noFail(`${bin('tsc')} --watch --noEmit --preserveWatchOutput`)),
157
- ...(hasEsw ? [q(noFail(`${bin('esw')} --watch --changed server client shared`))] : []),
158
- ].filter(Boolean).join(' ')
159
- : [
160
- bin('concurrently'),
161
- '--names server',
162
- '--prefix-colors green',
163
- rawFlag,
164
- '--kill-others-on-fail',
165
- '--handle-input',
166
- q(serverCmd),
167
- ].filter(Boolean).join(' ');
168
- if (verbose) {
169
- console.log(`[ugly-app] Spawning: ${cmd}`);
132
+ const isWin = process.platform === 'win32';
133
+ const noFail = (cmd) => isWin ? `(${cmd} || (exit /b 0))` : `${cmd} || true`;
134
+ // Resolve a tool's executable JS entry through the project's
135
+ // node_modules graph rather than assuming it's hoisted to
136
+ // `node_modules/.bin/`. Under pnpm-strict, transitive bins (e.g.
137
+ // `concurrently`, which is a dep of ugly-app and not of the user
138
+ // project) never land in the top-level `.bin/`, and the old
139
+ // `node_modules/.bin/<name>` path then exits 127. Resolving the
140
+ // package's `bin` entry via Node module resolution works for npm,
141
+ // yarn, pnpm-strict, and pnpm-shamefully-hoist alike, and also
142
+ // sidesteps Windows shebang issues since we invoke `node <jsfile>`
143
+ // directly.
144
+ function resolveBinJs(pkg, binName) {
145
+ try {
146
+ const fromCwd = path.join(process.cwd(), 'package.json');
147
+ const req = createRequire(fromCwd);
148
+ const pkgJsonPath = req.resolve(`${pkg}/package.json`);
149
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
150
+ const pkgDir = path.dirname(pkgJsonPath);
151
+ const binField = pkgJson.bin;
152
+ if (!binField)
153
+ return null;
154
+ const rel = typeof binField === 'string'
155
+ ? binField
156
+ : binField[binName ?? pkgJson.name];
157
+ if (!rel)
158
+ return null;
159
+ return path.join(pkgDir, rel);
170
160
  }
171
- const child = spawn(cmd, [], {
172
- stdio: 'inherit',
173
- cwd: process.cwd(),
174
- shell: true,
175
- });
176
- // Open browser once the server is listening — opt-in only. Most users
177
- // either run ugly-app inside ugly-studio's preview iframe or already
178
- // have the tab open from a previous run, so a system browser window
179
- // popping open on every restart is intrusive. Set UGLY_APP_OPEN_BROWSER=1
180
- // to opt back in.
181
- const openBrowser = process.env['UGLY_APP_OPEN_BROWSER'] === '1';
182
- if (openBrowser) {
183
- const url = `http://localhost:${port}`;
184
- waitForPort(parseInt(port, 10)).then(() => {
185
- const openCmd = process.platform === 'darwin' ? 'open' :
186
- process.platform === 'win32' ? 'start' : 'xdg-open';
187
- exec(`${openCmd} ${url}`);
188
- }).catch(() => { });
161
+ catch {
162
+ return null;
189
163
  }
190
- child.on('error', (err) => {
191
- if (verbose)
192
- console.error('[ugly-app] Spawn error:', err);
193
- reject(err);
164
+ }
165
+ const tsxBin = resolveBinJs('tsx', 'tsx');
166
+ const tscBin = resolveBinJs('typescript', 'tsc');
167
+ const eswBin = resolveBinJs('eslint-watch', 'esw');
168
+ if (!tsxBin) {
169
+ throw new Error(`[ugly-app] Could not resolve 'tsx' from ${process.cwd()}. ` +
170
+ `Run \`npm install\` (or \`pnpm install\`) and try again.`);
171
+ }
172
+ const q = (s) => `"${s.replace(/"/g, '\\"')}"`;
173
+ const node = q(process.execPath);
174
+ const serverCmd = opts.watch
175
+ ? `${node} ${q(tsxBin)} watch --clear-screen=false --ignore ./client --ignore "**/node_modules/**" server/index.ts`
176
+ : `${node} ${q(tsxBin)} server/index.ts`;
177
+ const hasEsw = eswBin !== null;
178
+ const hasTsc = tscBin !== null;
179
+ const commands = [
180
+ { command: serverCmd, name: 'server', prefixColor: 'green' },
181
+ ];
182
+ if (hasTsc) {
183
+ commands.push({
184
+ command: noFail(`${node} ${q(tscBin)} --watch --noEmit --preserveWatchOutput`),
185
+ name: 'tsc',
186
+ prefixColor: 'yellow',
194
187
  });
195
- child.on('close', (code) => {
196
- if (verbose)
197
- console.log(`[ugly-app] Process exited with code ${code}`);
198
- if (code !== 0)
199
- reject(new Error(`dev process exited with code ${code}`));
200
- else
201
- resolve();
188
+ }
189
+ if (opts.watch && hasEsw) {
190
+ commands.push({
191
+ command: noFail(`${node} ${q(eswBin)} --watch --changed server client shared`),
192
+ name: 'eslint',
193
+ prefixColor: 'magenta',
202
194
  });
195
+ }
196
+ // Non-watch mode runs only the server.
197
+ const finalCommands = opts.watch ? commands : commands.slice(0, 1);
198
+ if (verbose) {
199
+ console.log('[ugly-app] Spawning:');
200
+ for (const c of finalCommands) {
201
+ console.log(` [${c.name}] ${c.command}`);
202
+ }
203
+ }
204
+ const { result } = concurrently(finalCommands, {
205
+ killOthersOn: ['failure'],
206
+ handleInput: true,
207
+ raw: !isWin,
203
208
  });
209
+ // Open browser once the server is listening — opt-in only. Most users
210
+ // either run ugly-app inside ugly-studio's preview iframe or already
211
+ // have the tab open from a previous run, so a system browser window
212
+ // popping open on every restart is intrusive. Set UGLY_APP_OPEN_BROWSER=1
213
+ // to opt back in.
214
+ const openBrowser = process.env['UGLY_APP_OPEN_BROWSER'] === '1';
215
+ if (openBrowser) {
216
+ const url = `http://localhost:${port}`;
217
+ waitForPort(parseInt(port, 10)).then(() => {
218
+ const openCmd = process.platform === 'darwin' ? 'open' :
219
+ process.platform === 'win32' ? 'start' : 'xdg-open';
220
+ exec(`${openCmd} ${url}`);
221
+ }).catch(() => { });
222
+ }
223
+ try {
224
+ await result;
225
+ }
226
+ catch (err) {
227
+ // concurrently rejects with an array of CloseEvent on non-zero exits.
228
+ if (Array.isArray(err)) {
229
+ const failed = err.find((e) => e.exitCode !== 0);
230
+ const code = failed?.exitCode ?? 1;
231
+ throw new Error(`dev process exited with code ${code}`);
232
+ }
233
+ throw err;
234
+ }
204
235
  }
205
236
  //# sourceMappingURL=dev.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,YAAY,MAAM,cAAc,CAAC;AACxC;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAAqB;IAC5C,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,QAAQ,CAClB,2BAA2B,IAAI,sBAAsB,EACrD,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAC3D,CAAC,IAAI,EAAE,CAAC;YACT,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChD,IAAI,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC;YAC5B,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;YAChD,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACzC,CAAC;QACD,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,IAAI,eAAe,EAAE;YACpD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,QAAQ,IAAI,IAAI,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,OAAO,GAAG,EAAE,EAAE,UAAU,GAAG,IAAI;IAChE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,SAAS,UAAU;YACjB,MAAM,IAAI,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YACrD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;gBACtB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,IAAI,EAAE,QAAQ,IAAI,OAAO,EAAE,CAAC;oBAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACpE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACrC,CAAC,CAAC,CAAC;QACL,CAAC;QACD,UAAU,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AACD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAA6C,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE;IACxG,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,8EAA8E;IAC9E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC;IACtE,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC;IACvD,IACE,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAC7B,CAAC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,EACnD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,GAAG,KAAK,CAAC;IAC7D,CAAC;IAED,uEAAuE;IACvE,wEAAwE;IACxE,wEAAwE;IACxE,qCAAqC;IACrC,IAAI,CAAC;QACH,MAAM,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,oCAAqC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,4EAA4E;IAC5E,MAAM,WAAW,EAAE,CAAC;IAEpB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAE/D,6EAA6E;IAC7E,EAAE;IACF,4EAA4E;IAC5E,2EAA2E;IAC3E,sEAAsE;IACtE,0EAA0E;IAC1E,yEAAyE;IACzE,iCAAiC;IACjC,EAAE;IACF,uEAAuE;IACvE,+DAA+D;IAC/D,sEAAsE;IACtE,sCAAsC;IACtC,EAAE;IACF,oEAAoE;IACpE,oEAAoE;IACpE,gEAAgE;IAChE,gEAAgE;IAChE,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CACX,mBAAmB,IAAI,6BAA6B,WAAW,KAAK;YAClE,mBAAmB;YACnB,iBAAiB,WAAW,iBAAiB,WAAW,qCAAqC;YAC7F,+FAA+F,CAClG,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,8EAA8E;IAC9E,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAChE,CAAC;IAED,6EAA6E;IAC7E,IAAI,CAAC;QACH,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,6CAA8C,MAAgB,CAAC,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,6EAA6E;IAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,CAAC,8BAA8B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAC7B,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,GAAG,UAAU,CAAC;IAEvD,6DAA6D;IAC7D,0DAA0D;IAC1D,iEAAiE;IACjE,iEAAiE;IACjE,4DAA4D;IAC5D,gEAAgE;IAChE,kEAAkE;IAClE,+DAA+D;IAC/D,mEAAmE;IACnE,YAAY;IACZ,SAAS,YAAY,CAAC,GAAW,EAAE,OAAgB;QACjD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;YACzD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAG/D,CAAC;YACF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;YAC7B,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC3B,MAAM,GAAG,GACP,OAAO,QAAQ,KAAK,QAAQ;gBAC1B,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,YAAY,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAEnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,2CAA2C,OAAO,CAAC,GAAG,EAAE,IAAI;YAC1D,0DAA0D,CAC7D,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;IACvD,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEjC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK;QAC1B,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,6FAA6F;QACnH,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IAE/B,MAAM,QAAQ,GAA6D;QACzE,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE;KAC7D,CAAC;IACF,IAAI,MAAM,EAAE,CAAC;QACX,QAAQ,CAAC,IAAI,CAAC;YACZ,OAAO,EAAE,MAAM,CACb,GAAG,IAAI,IAAI,CAAC,CAAC,MAAO,CAAC,yCAAyC,CAC/D;YACD,IAAI,EAAE,KAAK;YACX,WAAW,EAAE,QAAQ;SACtB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC;YACZ,OAAO,EAAE,MAAM,CACb,GAAG,IAAI,IAAI,CAAC,CAAC,MAAO,CAAC,yCAAyC,CAC/D;YACD,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,SAAS;SACvB,CAAC,CAAC;IACL,CAAC;IACD,uCAAuC;IACvC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEnE,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,aAAa,EAAE;QAC7C,YAAY,EAAE,CAAC,SAAS,CAAC;QACzB,WAAW,EAAE,IAAI;QACjB,GAAG,EAAE,CAAC,KAAK;KACZ,CAAC,CAAC;IAEH,sEAAsE;IACtE,qEAAqE;IACrE,oEAAoE;IACpE,0EAA0E;IAC1E,kBAAkB;IAClB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,GAAG,CAAC;IACjE,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,oBAAoB,IAAI,EAAE,CAAC;QACvC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YACxC,MAAM,OAAO,GACX,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBACxC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;YACtD,IAAI,CAAC,GAAG,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAqB,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,sEAAsE;QACtE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAgC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;YAChF,MAAM,IAAI,GAAG,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Resolve a package's bin entry to an absolute path to the JS file —
3
+ * using Node's module resolution (pnpm-strict-safe) rather than
4
+ * assuming `node_modules/.bin/<name>` exists.
5
+ *
6
+ * Why this matters: `npx <bin>` fails with `Unknown command: <bin>`
7
+ * inside a pnpm-style nested store because the binary lives in
8
+ * `node_modules/.pnpm/...` and was never linked to the top-level
9
+ * `.bin/`. Every `execSync('npx <x>')` call from this CLI broke
10
+ * coding-agent sessions in pnpm-managed apps. Resolve the bin path
11
+ * via require + package.json `bin` field instead.
12
+ *
13
+ * Returns `null` when the package isn't installed or has no bin entry.
14
+ */
15
+ export declare function resolveBinJs(pkg: string, binName?: string): string | null;
16
+ /**
17
+ * Build a `node <abs.js> <args>` command string for execSync. The
18
+ * binary is resolved via `resolveBinJs`; when it can't be found we
19
+ * fall back to `npx <pkg> <args>` and let the user see the original
20
+ * failure mode rather than a confusing error from this helper.
21
+ */
22
+ export declare function nodeBinCommand(pkg: string, args: string, binName?: string): string;
23
+ //# sourceMappingURL=resolveBin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveBin.d.ts","sourceRoot":"","sources":["../../src/cli/resolveBin.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBzE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAOR"}
@@ -0,0 +1,51 @@
1
+ import fs from 'fs';
2
+ import { createRequire } from 'module';
3
+ import path from 'path';
4
+ /**
5
+ * Resolve a package's bin entry to an absolute path to the JS file —
6
+ * using Node's module resolution (pnpm-strict-safe) rather than
7
+ * assuming `node_modules/.bin/<name>` exists.
8
+ *
9
+ * Why this matters: `npx <bin>` fails with `Unknown command: <bin>`
10
+ * inside a pnpm-style nested store because the binary lives in
11
+ * `node_modules/.pnpm/...` and was never linked to the top-level
12
+ * `.bin/`. Every `execSync('npx <x>')` call from this CLI broke
13
+ * coding-agent sessions in pnpm-managed apps. Resolve the bin path
14
+ * via require + package.json `bin` field instead.
15
+ *
16
+ * Returns `null` when the package isn't installed or has no bin entry.
17
+ */
18
+ export function resolveBinJs(pkg, binName) {
19
+ try {
20
+ const fromCwd = path.join(process.cwd(), 'package.json');
21
+ const req = createRequire(fromCwd);
22
+ const pkgJsonPath = req.resolve(`${pkg}/package.json`);
23
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
24
+ const pkgDir = path.dirname(pkgJsonPath);
25
+ const binField = pkgJson.bin;
26
+ if (!binField)
27
+ return null;
28
+ const rel = typeof binField === 'string' ? binField : binField[binName ?? pkgJson.name];
29
+ if (!rel)
30
+ return null;
31
+ return path.join(pkgDir, rel);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ /**
38
+ * Build a `node <abs.js> <args>` command string for execSync. The
39
+ * binary is resolved via `resolveBinJs`; when it can't be found we
40
+ * fall back to `npx <pkg> <args>` and let the user see the original
41
+ * failure mode rather than a confusing error from this helper.
42
+ */
43
+ export function nodeBinCommand(pkg, args, binName) {
44
+ const bin = resolveBinJs(pkg, binName);
45
+ const q = (s) => `"${s.replace(/"/g, '\\"')}"`;
46
+ if (bin) {
47
+ return `${q(process.execPath)} ${q(bin)} ${args}`;
48
+ }
49
+ return `npx ${binName ?? pkg} ${args}`;
50
+ }
51
+ //# sourceMappingURL=resolveBin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveBin.js","sourceRoot":"","sources":["../../src/cli/resolveBin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,OAAgB;IACxD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAG/D,CAAC;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;QAC7B,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,MAAM,GAAG,GACP,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9E,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,IAAY,EACZ,OAAgB;IAEhB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;IACvD,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACpD,CAAC;IACD,OAAO,OAAO,OAAO,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;AACzC,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.422";
1
+ export declare const CLI_VERSION = "0.1.424";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.422";
2
+ export const CLI_VERSION = "0.1.424";
3
3
  //# sourceMappingURL=version.js.map
@@ -40,7 +40,7 @@ export declare const frameworkRequests: {
40
40
  id: string;
41
41
  projectId: string;
42
42
  title: string;
43
- state: "done" | "build" | "plan";
43
+ state: "build" | "done" | "plan";
44
44
  markdown: string;
45
45
  lastModifiedUserId: string | null;
46
46
  sortOrder: number;
@@ -59,7 +59,7 @@ export declare const frameworkRequests: {
59
59
  planId: string;
60
60
  title?: string | undefined;
61
61
  markdown?: string | undefined;
62
- state?: "done" | "build" | "plan" | undefined;
62
+ state?: "build" | "done" | "plan" | undefined;
63
63
  sortOrder?: number | undefined;
64
64
  }, Record<string, never>>;
65
65
  projectPlanDelete: import("./Api.js").AuthRequestDef<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.422",
3
+ "version": "0.1.424",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
package/src/cli/build.ts CHANGED
@@ -2,6 +2,7 @@ import { execSync } from 'child_process';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { runExportCollections } from './exportCollections.js';
5
+ import { nodeBinCommand } from './resolveBin.js';
5
6
  import { runExportWorkers } from './workerGen.js';
6
7
 
7
8
  export async function runBuild(): Promise<void> {
@@ -34,9 +35,15 @@ export const buildId = '${buildId}';
34
35
  console.log('[Build] Cleaned dist/');
35
36
  }
36
37
 
37
- // Run vite build
38
+ // Run vite build. `npx vite build` does not work in pnpm-strict
39
+ // worktrees (vite is hoisted into `.pnpm/...` and not linked to
40
+ // top-level `.bin/`); resolve the bin path through Node module
41
+ // resolution instead. Same for esbuild + tsc below.
38
42
  console.log('[Build] Running vite build...');
39
- execSync('npx vite build', { stdio: 'inherit', cwd: process.cwd() });
43
+ execSync(nodeBinCommand('vite', 'build'), {
44
+ stdio: 'inherit',
45
+ cwd: process.cwd(),
46
+ });
40
47
 
41
48
  // Bundle server with esbuild (only for simple projects without custom server build)
42
49
  const serverEntry = path.join(process.cwd(), 'server', 'index.ts');
@@ -46,7 +53,10 @@ export const buildId = '${buildId}';
46
53
  const serverOutDir = path.join(distDir, 'server');
47
54
  fs.mkdirSync(serverOutDir, { recursive: true });
48
55
  execSync(
49
- `npx esbuild server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.mjs --external:ugly-app --external:ugly-app/*`,
56
+ nodeBinCommand(
57
+ 'esbuild',
58
+ 'server/index.ts --bundle --platform=node --format=esm --outfile=dist/server/index.mjs --external:ugly-app --external:ugly-app/*',
59
+ ),
50
60
  { stdio: 'inherit', cwd: process.cwd() },
51
61
  );
52
62
  }
@@ -68,7 +78,10 @@ export const buildId = '${buildId}';
68
78
  ];
69
79
  const externalFlags = externals.map(e => `--external:${e}`).join(' ');
70
80
  execSync(
71
- `npx esbuild server/task.ts --bundle --platform=node --format=esm --outfile=dist/tasks/task.js ${externalFlags}`,
81
+ nodeBinCommand(
82
+ 'esbuild',
83
+ `server/task.ts --bundle --platform=node --format=esm --outfile=dist/tasks/task.js ${externalFlags}`,
84
+ ),
72
85
  { stdio: 'inherit', cwd: process.cwd() },
73
86
  );
74
87
  console.log('[Build] Task bundle: dist/tasks/task.js');
@@ -76,7 +89,10 @@ export const buildId = '${buildId}';
76
89
 
77
90
  // Run tsc for typecheck
78
91
  console.log('[Build] Running tsc...');
79
- execSync('npx tsc --noEmit', { stdio: 'inherit', cwd: process.cwd() });
92
+ execSync(nodeBinCommand('typescript', '--noEmit', 'tsc'), {
93
+ stdio: 'inherit',
94
+ cwd: process.cwd(),
95
+ });
80
96
 
81
97
  console.log(`[Build] Build complete (${buildId})`);
82
98
  }
package/src/cli/dev.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { exec, execSync, spawn } from 'child_process';
1
+ import { exec, execSync } from 'child_process';
2
2
  import fs from 'fs';
3
3
  import net from 'net';
4
4
  import path from 'path';
5
+ import { createRequire } from 'module';
6
+ import concurrently from 'concurrently';
5
7
  /**
6
8
  * Return the PID of the process listening on `port`, or null if none.
7
9
  * Cross-platform; shells out to `lsof` on Unix and `netstat` on Windows.
@@ -139,85 +141,126 @@ export async function runDev(opts: { watch: boolean; verbose: boolean } = { watc
139
141
  console.log(`[ugly-app] POSTGRES_URL: ${process.env['POSTGRES_URL'] ?? '(default)'}`);
140
142
  }
141
143
 
142
- return new Promise<void>((resolve, reject) => {
143
- const isWin = process.platform === 'win32';
144
- const noFail = (cmd: string) =>
145
- isWin ? `(${cmd} || (exit /b 0))` : `${cmd} || true`;
146
-
147
- const binDir = path.join(process.cwd(), 'node_modules', '.bin') + path.sep;
148
- const bin = (name: string) => `"${binDir}${name}"`;
149
- const q = (s: string) => `"${s.replace(/"/g, '\\"')}"`;
150
-
151
- const serverCmd = opts.watch
152
- ? `${bin('tsx')} watch --clear-screen=false --ignore ./client --ignore "**/node_modules/**" server/index.ts`
153
- : `${bin('tsx')} server/index.ts`;
154
-
155
- const hasEsw = fs.existsSync(path.join(binDir, 'esw'));
156
-
157
- const rawFlag = isWin ? '--raw' : '';
158
- const namesFlag = isWin
159
- ? ''
160
- : hasEsw ? '--names server,tsc,eslint' : '--names server,tsc';
161
- const colorsFlag = isWin
162
- ? ''
163
- : hasEsw ? '--prefix-colors green,yellow,magenta' : '--prefix-colors green,yellow';
164
-
165
- const cmd = opts.watch
166
- ? [
167
- bin('concurrently'),
168
- namesFlag,
169
- colorsFlag,
170
- rawFlag,
171
- '--kill-others-on-fail',
172
- '--handle-input',
173
- q(serverCmd),
174
- q(noFail(`${bin('tsc')} --watch --noEmit --preserveWatchOutput`)),
175
- ...(hasEsw ? [q(noFail(`${bin('esw')} --watch --changed server client shared`))] : []),
176
- ].filter(Boolean).join(' ')
177
- : [
178
- bin('concurrently'),
179
- '--names server',
180
- '--prefix-colors green',
181
- rawFlag,
182
- '--kill-others-on-fail',
183
- '--handle-input',
184
- q(serverCmd),
185
- ].filter(Boolean).join(' ');
186
-
187
- if (verbose) {
188
- console.log(`[ugly-app] Spawning: ${cmd}`);
144
+ const isWin = process.platform === 'win32';
145
+ const noFail = (cmd: string) =>
146
+ isWin ? `(${cmd} || (exit /b 0))` : `${cmd} || true`;
147
+
148
+ // Resolve a tool's executable JS entry through the project's
149
+ // node_modules graph rather than assuming it's hoisted to
150
+ // `node_modules/.bin/`. Under pnpm-strict, transitive bins (e.g.
151
+ // `concurrently`, which is a dep of ugly-app and not of the user
152
+ // project) never land in the top-level `.bin/`, and the old
153
+ // `node_modules/.bin/<name>` path then exits 127. Resolving the
154
+ // package's `bin` entry via Node module resolution works for npm,
155
+ // yarn, pnpm-strict, and pnpm-shamefully-hoist alike, and also
156
+ // sidesteps Windows shebang issues since we invoke `node <jsfile>`
157
+ // directly.
158
+ function resolveBinJs(pkg: string, binName?: string): string | null {
159
+ try {
160
+ const fromCwd = path.join(process.cwd(), 'package.json');
161
+ const req = createRequire(fromCwd);
162
+ const pkgJsonPath = req.resolve(`${pkg}/package.json`);
163
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')) as {
164
+ name: string;
165
+ bin?: string | Record<string, string>;
166
+ };
167
+ const pkgDir = path.dirname(pkgJsonPath);
168
+ const binField = pkgJson.bin;
169
+ if (!binField) return null;
170
+ const rel =
171
+ typeof binField === 'string'
172
+ ? binField
173
+ : binField[binName ?? pkgJson.name];
174
+ if (!rel) return null;
175
+ return path.join(pkgDir, rel);
176
+ } catch {
177
+ return null;
189
178
  }
179
+ }
190
180
 
191
- const child = spawn(cmd, [], {
192
- stdio: 'inherit',
193
- cwd: process.cwd(),
194
- shell: true,
195
- });
181
+ const tsxBin = resolveBinJs('tsx', 'tsx');
182
+ const tscBin = resolveBinJs('typescript', 'tsc');
183
+ const eswBin = resolveBinJs('eslint-watch', 'esw');
196
184
 
197
- // Open browser once the server is listening — opt-in only. Most users
198
- // either run ugly-app inside ugly-studio's preview iframe or already
199
- // have the tab open from a previous run, so a system browser window
200
- // popping open on every restart is intrusive. Set UGLY_APP_OPEN_BROWSER=1
201
- // to opt back in.
202
- const openBrowser = process.env['UGLY_APP_OPEN_BROWSER'] === '1';
203
- if (openBrowser) {
204
- const url = `http://localhost:${port}`;
205
- waitForPort(parseInt(port, 10)).then(() => {
206
- const openCmd =
207
- process.platform === 'darwin' ? 'open' :
208
- process.platform === 'win32' ? 'start' : 'xdg-open';
209
- exec(`${openCmd} ${url}`);
210
- }).catch(() => { /* best effort */ });
211
- }
185
+ if (!tsxBin) {
186
+ throw new Error(
187
+ `[ugly-app] Could not resolve 'tsx' from ${process.cwd()}. ` +
188
+ `Run \`npm install\` (or \`pnpm install\`) and try again.`,
189
+ );
190
+ }
212
191
 
213
- child.on('error', (err) => {
214
- if (verbose) console.error('[ugly-app] Spawn error:', err);
215
- reject(err);
192
+ const q = (s: string) => `"${s.replace(/"/g, '\\"')}"`;
193
+ const node = q(process.execPath);
194
+
195
+ const serverCmd = opts.watch
196
+ ? `${node} ${q(tsxBin)} watch --clear-screen=false --ignore ./client --ignore "**/node_modules/**" server/index.ts`
197
+ : `${node} ${q(tsxBin)} server/index.ts`;
198
+
199
+ const hasEsw = eswBin !== null;
200
+ const hasTsc = tscBin !== null;
201
+
202
+ const commands: { command: string; name: string; prefixColor: string }[] = [
203
+ { command: serverCmd, name: 'server', prefixColor: 'green' },
204
+ ];
205
+ if (hasTsc) {
206
+ commands.push({
207
+ command: noFail(
208
+ `${node} ${q(tscBin!)} --watch --noEmit --preserveWatchOutput`,
209
+ ),
210
+ name: 'tsc',
211
+ prefixColor: 'yellow',
216
212
  });
217
- child.on('close', (code) => {
218
- if (verbose) console.log(`[ugly-app] Process exited with code ${code}`);
219
- if (code !== 0) reject(new Error(`dev process exited with code ${code}`));
220
- else resolve();
213
+ }
214
+ if (opts.watch && hasEsw) {
215
+ commands.push({
216
+ command: noFail(
217
+ `${node} ${q(eswBin!)} --watch --changed server client shared`,
218
+ ),
219
+ name: 'eslint',
220
+ prefixColor: 'magenta',
221
221
  });
222
+ }
223
+ // Non-watch mode runs only the server.
224
+ const finalCommands = opts.watch ? commands : commands.slice(0, 1);
225
+
226
+ if (verbose) {
227
+ console.log('[ugly-app] Spawning:');
228
+ for (const c of finalCommands) {
229
+ console.log(` [${c.name}] ${c.command}`);
230
+ }
231
+ }
232
+
233
+ const { result } = concurrently(finalCommands, {
234
+ killOthersOn: ['failure'],
235
+ handleInput: true,
236
+ raw: !isWin,
222
237
  });
238
+
239
+ // Open browser once the server is listening — opt-in only. Most users
240
+ // either run ugly-app inside ugly-studio's preview iframe or already
241
+ // have the tab open from a previous run, so a system browser window
242
+ // popping open on every restart is intrusive. Set UGLY_APP_OPEN_BROWSER=1
243
+ // to opt back in.
244
+ const openBrowser = process.env['UGLY_APP_OPEN_BROWSER'] === '1';
245
+ if (openBrowser) {
246
+ const url = `http://localhost:${port}`;
247
+ waitForPort(parseInt(port, 10)).then(() => {
248
+ const openCmd =
249
+ process.platform === 'darwin' ? 'open' :
250
+ process.platform === 'win32' ? 'start' : 'xdg-open';
251
+ exec(`${openCmd} ${url}`);
252
+ }).catch(() => { /* best effort */ });
253
+ }
254
+
255
+ try {
256
+ await result;
257
+ } catch (err) {
258
+ // concurrently rejects with an array of CloseEvent on non-zero exits.
259
+ if (Array.isArray(err)) {
260
+ const failed = err.find((e: { exitCode: number | string }) => e.exitCode !== 0);
261
+ const code = failed?.exitCode ?? 1;
262
+ throw new Error(`dev process exited with code ${code}`);
263
+ }
264
+ throw err;
265
+ }
223
266
  }
@@ -0,0 +1,57 @@
1
+ import fs from 'fs';
2
+ import { createRequire } from 'module';
3
+ import path from 'path';
4
+
5
+ /**
6
+ * Resolve a package's bin entry to an absolute path to the JS file —
7
+ * using Node's module resolution (pnpm-strict-safe) rather than
8
+ * assuming `node_modules/.bin/<name>` exists.
9
+ *
10
+ * Why this matters: `npx <bin>` fails with `Unknown command: <bin>`
11
+ * inside a pnpm-style nested store because the binary lives in
12
+ * `node_modules/.pnpm/...` and was never linked to the top-level
13
+ * `.bin/`. Every `execSync('npx <x>')` call from this CLI broke
14
+ * coding-agent sessions in pnpm-managed apps. Resolve the bin path
15
+ * via require + package.json `bin` field instead.
16
+ *
17
+ * Returns `null` when the package isn't installed or has no bin entry.
18
+ */
19
+ export function resolveBinJs(pkg: string, binName?: string): string | null {
20
+ try {
21
+ const fromCwd = path.join(process.cwd(), 'package.json');
22
+ const req = createRequire(fromCwd);
23
+ const pkgJsonPath = req.resolve(`${pkg}/package.json`);
24
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')) as {
25
+ name: string;
26
+ bin?: string | Record<string, string>;
27
+ };
28
+ const pkgDir = path.dirname(pkgJsonPath);
29
+ const binField = pkgJson.bin;
30
+ if (!binField) return null;
31
+ const rel =
32
+ typeof binField === 'string' ? binField : binField[binName ?? pkgJson.name];
33
+ if (!rel) return null;
34
+ return path.join(pkgDir, rel);
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Build a `node <abs.js> <args>` command string for execSync. The
42
+ * binary is resolved via `resolveBinJs`; when it can't be found we
43
+ * fall back to `npx <pkg> <args>` and let the user see the original
44
+ * failure mode rather than a confusing error from this helper.
45
+ */
46
+ export function nodeBinCommand(
47
+ pkg: string,
48
+ args: string,
49
+ binName?: string,
50
+ ): string {
51
+ const bin = resolveBinJs(pkg, binName);
52
+ const q = (s: string) => `"${s.replace(/"/g, '\\"')}"`;
53
+ if (bin) {
54
+ return `${q(process.execPath)} ${q(bin)} ${args}`;
55
+ }
56
+ return `npx ${binName ?? pkg} ${args}`;
57
+ }
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.422";
2
+ export const CLI_VERSION = "0.1.424";