ugly-app 0.1.921 → 0.1.923

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":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AA2CA,wBAAsB,MAAM,CAC1B,IAAI,GAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAqC,GAC5E,OAAO,CAAC,IAAI,CAAC,CAqOf"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AAkDA,wBAAsB,MAAM,CAC1B,IAAI,GAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAqC,GAC5E,OAAO,CAAC,IAAI,CAAC,CAkQf"}
package/dist/cli/dev.js CHANGED
@@ -37,6 +37,7 @@ import { runExportCollections } from './exportCollections.js';
37
37
  import { ensureLocalInfra } from '../native/server/binaries/index.js';
38
38
  import { readUglyAppConfig } from './uglyappConfig.js';
39
39
  import { lintSummaryAsync } from './lint.js';
40
+ import { checkDevLock, releaseDevLock, setAllowMultiple, stopHint, writeDevLock, } from './devLock.js';
40
41
  import { backgroundWait } from '../server/backgroundWait.js';
41
42
  export async function runDev(opts = { watch: false, verbose: false }) {
42
43
  // ── Set universal dev env vars ─────────────────────────────────────────────
@@ -74,6 +75,32 @@ export async function runDev(opts = { watch: false, verbose: false }) {
74
75
  ` 2. Re-run with a free port, e.g. \`PORT=5555 npx ugly-app dev\`.`);
75
76
  process.exit(1);
76
77
  }
78
+ // ── 1b. Refuse to stack a second dev server on this project ───────────────
79
+ // The port check above only sees a *healthy* predecessor. A dev server whose
80
+ // server/index.ts crashed binds nothing, yet its tsx/tsc watchers and minio
81
+ // keep running — so without this the next run starts a whole second stack.
82
+ // See devLock.ts for the pile-up this prevents.
83
+ const allowMultipleDev = Boolean(process.env['UGLY_APP_ALLOW_MULTIPLE_DEV']);
84
+ setAllowMultiple(process.cwd(), allowMultipleDev);
85
+ const runningDev = allowMultipleDev ? null : checkDevLock(process.cwd());
86
+ if (runningDev) {
87
+ console.error(`[ugly-app] A dev server is already running for this project (PID ${runningDev.pid}, started ${runningDev.startedAt}).\n` +
88
+ `It may not be serving — a crashed server still leaves its watchers and minio up.\n` +
89
+ `To fix, either:\n` +
90
+ ` 1. Stop it, then re-run \`ugly-app dev\`:\n` +
91
+ ` ${stopHint(runningDev)}\n` +
92
+ ` 2. Run this copy from a separate checkout.\n` +
93
+ `If you really do want two stacks on one project, set UGLY_APP_ALLOW_MULTIPLE_DEV=1\n` +
94
+ `(they will share .ugly-studio/minio/data and the local Postgres).`);
95
+ process.exit(1);
96
+ }
97
+ if (!allowMultipleDev) {
98
+ // Skipped when stacking is opted into: several stacks cannot each own one lock.
99
+ writeDevLock(process.cwd(), port);
100
+ // Best-effort: a lock left behind by a SIGKILL is detected as stale on the
101
+ // next run anyway, so this need not catch every exit path.
102
+ process.on('exit', () => releaseDevLock(process.cwd()));
103
+ }
77
104
  // ── 2. Provision local dev infra (docker-free) ────────────────────────────
78
105
  // Start a bundled Postgres (and MinIO S3/R2) when DATABASE_URL / R2_BUCKET are
79
106
  // unset, and inject their connection details into env for the spawned server.
@@ -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":"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"}
@@ -0,0 +1,39 @@
1
+ export interface DevLockInfo {
2
+ /** pid of the `ugly-app dev` process itself (not the launcher). */
3
+ pid: number;
4
+ /** Process group to signal to take the whole stack down; null on Windows. */
5
+ pgid: number | null;
6
+ port: string;
7
+ startedAt: string;
8
+ }
9
+ /**
10
+ * Returns the full command line of `pid`, or null when it isn't running.
11
+ * Injected in tests so lock logic is exercised without spawning processes.
12
+ */
13
+ export type CommandProbe = (pid: number) => string | null;
14
+ export declare function devLockPath(projectDir: string): string;
15
+ export declare function readDevLock(projectDir: string): DevLockInfo | null;
16
+ /**
17
+ * Returns the lock of a dev server that is genuinely still running for
18
+ * `projectDir`, or null. A lock naming a dead or recycled pid is deleted so the
19
+ * caller can proceed.
20
+ */
21
+ export declare function checkDevLock(projectDir: string, probe?: CommandProbe): DevLockInfo | null;
22
+ export declare function writeDevLock(projectDir: string, port: string): void;
23
+ /** Remove the lock, but only if it is still ours (never clobber a successor). */
24
+ export declare function releaseDevLock(projectDir: string): void;
25
+ /**
26
+ * On-disk trace of `UGLY_APP_ALLOW_MULTIPLE_DEV`, so the machine-level reaper
27
+ * doesn't undo the opt-out by killing the "duplicate" stacks it names. macOS
28
+ * `ps -E` can't read another process's environment, hence a file. Any ordinary
29
+ * (non-opt-out) `ugly-app dev` clears it, so it can't linger and silently
30
+ * disable duplicate-reaping for a project forever.
31
+ */
32
+ export declare function setAllowMultiple(projectDir: string, allow: boolean): void;
33
+ /**
34
+ * How to stop the stack described by `lock` — the process *group*, so the
35
+ * launcher, tsx, tsc, esbuild and minio all go down together rather than
36
+ * leaving minio behind.
37
+ */
38
+ export declare function stopHint(lock: DevLockInfo): string;
39
+ //# sourceMappingURL=devLock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devLock.d.ts","sourceRoot":"","sources":["../../src/cli/devLock.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAK1D,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAsCD,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAelE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,YAAwB,GAC9B,WAAW,GAAG,IAAI,CAUpB;AAUD,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAYnE;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAYzE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAIlD"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Cross-process singleton guard for `ugly-app dev`.
3
+ *
4
+ * Why this exists: `runDev`'s PORT-in-use check only catches a *healthy*
5
+ * previous dev server — one that actually bound PORT. When `server/index.ts`
6
+ * crashes (a TS error, a bad import), `tsx watch` deliberately stays up waiting
7
+ * for the next file change, `tsc --watch` never exits, and minio keeps serving
8
+ * — but nothing is listening on PORT. The next `ugly-app dev` then sails past
9
+ * the port check and spawns a *second* complete stack, minio and all.
10
+ *
11
+ * Neither existing cleanup mechanism catches that: the self-reap watchdog in
12
+ * dev.ts and the machine-level launchd reaper both key on PPID==1, which never
13
+ * happens while the launching shell (e.g. an agent's background task) is alive.
14
+ * So the stacks accumulate — 2026-07-27 found eight of them for one project,
15
+ * 55 processes and 1.15 GB, each with its own minio writing the same data dir.
16
+ *
17
+ * The lock keys on the one signal a broken-but-running stack still emits: its
18
+ * own process. Staleness is decided by probing the recorded pid, so a crashed
19
+ * or SIGKILLed dev server never leaves a lock that blocks the next run — which
20
+ * is why releasing the lock is best-effort rather than load-bearing.
21
+ */
22
+ import { execSync } from 'child_process';
23
+ import fs from 'fs';
24
+ import path from 'path';
25
+ /** Windows has no `ps`; we can prove liveness but not identity. */
26
+ const WIN32_ALIVE = '\0win32-alive';
27
+ export function devLockPath(projectDir) {
28
+ return path.join(projectDir, '.ugly-studio', 'dev.lock');
29
+ }
30
+ function psField(pid, field) {
31
+ try {
32
+ const out = execSync(`ps -o ${field}= -p ${pid}`, {
33
+ encoding: 'utf-8',
34
+ stdio: ['ignore', 'pipe', 'ignore'],
35
+ }).trim();
36
+ return out || null;
37
+ }
38
+ catch {
39
+ // `ps` exits non-zero when the pid is gone — that is the answer, not an error.
40
+ return null;
41
+ }
42
+ }
43
+ const psCommand = (pid) => {
44
+ if (process.platform === 'win32') {
45
+ try {
46
+ process.kill(pid, 0); // signal 0 only tests for existence
47
+ return WIN32_ALIVE;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ return psField(pid, 'command');
54
+ };
55
+ /**
56
+ * Does `command` belong to an `ugly-app dev` process? Guards against pid reuse:
57
+ * a recycled pid is alive but is some unrelated program, and killing its process
58
+ * group would take down whatever now owns that number.
59
+ */
60
+ function isDevCommand(command) {
61
+ if (command === WIN32_ALIVE)
62
+ return true; // best effort, see WIN32_ALIVE
63
+ // `dev` stays a regex — it must be a whole word, so `dev-server` etc. miss.
64
+ return command.includes('ugly-app') && /\bdev\b/.test(command);
65
+ }
66
+ export function readDevLock(projectDir) {
67
+ try {
68
+ const raw = fs.readFileSync(devLockPath(projectDir), 'utf-8');
69
+ const parsed = JSON.parse(raw);
70
+ if (typeof parsed.pid !== 'number')
71
+ return null;
72
+ return {
73
+ pid: parsed.pid,
74
+ pgid: typeof parsed.pgid === 'number' ? parsed.pgid : null,
75
+ port: String(parsed.port ?? ''),
76
+ startedAt: String(parsed.startedAt ?? ''),
77
+ };
78
+ }
79
+ catch {
80
+ // Missing or corrupt: both mean "no usable lock".
81
+ return null;
82
+ }
83
+ }
84
+ /**
85
+ * Returns the lock of a dev server that is genuinely still running for
86
+ * `projectDir`, or null. A lock naming a dead or recycled pid is deleted so the
87
+ * caller can proceed.
88
+ */
89
+ export function checkDevLock(projectDir, probe = psCommand) {
90
+ const lock = readDevLock(projectDir);
91
+ if (!lock) {
92
+ clearLockFile(projectDir);
93
+ return null;
94
+ }
95
+ const command = probe(lock.pid);
96
+ if (command !== null && isDevCommand(command))
97
+ return lock;
98
+ clearLockFile(projectDir);
99
+ return null;
100
+ }
101
+ function clearLockFile(projectDir) {
102
+ try {
103
+ fs.rmSync(devLockPath(projectDir), { force: true });
104
+ }
105
+ catch {
106
+ /* best effort — a lock we cannot delete is re-validated by probe next run */
107
+ }
108
+ }
109
+ export function writeDevLock(projectDir, port) {
110
+ const file = devLockPath(projectDir);
111
+ const pgidRaw = process.platform === 'win32' ? null : psField(process.pid, 'pgid');
112
+ const lock = {
113
+ pid: process.pid,
114
+ pgid: pgidRaw ? Number(pgidRaw) : null,
115
+ port,
116
+ startedAt: new Date().toISOString(),
117
+ };
118
+ fs.mkdirSync(path.dirname(file), { recursive: true });
119
+ fs.writeFileSync(file, JSON.stringify(lock, null, 2));
120
+ }
121
+ /** Remove the lock, but only if it is still ours (never clobber a successor). */
122
+ export function releaseDevLock(projectDir) {
123
+ const lock = readDevLock(projectDir);
124
+ if (lock?.pid !== process.pid)
125
+ return;
126
+ clearLockFile(projectDir);
127
+ }
128
+ /**
129
+ * On-disk trace of `UGLY_APP_ALLOW_MULTIPLE_DEV`, so the machine-level reaper
130
+ * doesn't undo the opt-out by killing the "duplicate" stacks it names. macOS
131
+ * `ps -E` can't read another process's environment, hence a file. Any ordinary
132
+ * (non-opt-out) `ugly-app dev` clears it, so it can't linger and silently
133
+ * disable duplicate-reaping for a project forever.
134
+ */
135
+ export function setAllowMultiple(projectDir, allow) {
136
+ const marker = path.join(projectDir, '.ugly-studio', 'dev-allow-multiple');
137
+ try {
138
+ if (!allow) {
139
+ fs.rmSync(marker, { force: true });
140
+ return;
141
+ }
142
+ fs.mkdirSync(path.dirname(marker), { recursive: true });
143
+ fs.writeFileSync(marker, `${new Date().toISOString()}\n`);
144
+ }
145
+ catch {
146
+ /* advisory only — never block `dev` on it */
147
+ }
148
+ }
149
+ /**
150
+ * How to stop the stack described by `lock` — the process *group*, so the
151
+ * launcher, tsx, tsc, esbuild and minio all go down together rather than
152
+ * leaving minio behind.
153
+ */
154
+ export function stopHint(lock) {
155
+ return lock.pgid !== null
156
+ ? `kill -TERM -${lock.pgid} # the whole dev stack (server, tsc, minio)`
157
+ : `kill ${lock.pid}`;
158
+ }
159
+ //# sourceMappingURL=devLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devLock.js","sourceRoot":"","sources":["../../src/cli/devLock.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"uglyappConfig.d.ts","sourceRoot":"","sources":["../../src/cli/uglyappConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"uglyappConfig.d.ts","sourceRoot":"","sources":["../../src/cli/uglyappConfig.ts"],"names":[],"mappings":"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"}
@@ -79,8 +79,16 @@ export function readUglyAppConfig(cwd) {
79
79
  if (entries.length)
80
80
  tasks = Object.fromEntries(entries);
81
81
  }
82
+ // `cache` and `queue` are whitelisted here like every other field. Anything
83
+ // NOT parsed below is silently dropped from the returned object, so a key can
84
+ // sit in `.uglyapp` looking configured while every reader sees `undefined` —
85
+ // which is exactly what happened to `queue.maxConcurrency`.
86
+ const cache = parseCacheConfig(config.cache);
87
+ const queue = parseQueueConfig(config.queue);
82
88
  return {
83
89
  projectId: config.projectId,
90
+ ...(cache !== undefined && { cache }),
91
+ ...(queue !== undefined && { queue }),
84
92
  ...(domain !== undefined && { domain }),
85
93
  ...(uglyBotToken !== undefined && { uglyBotToken }),
86
94
  ...(localToken !== undefined && { localToken }),
@@ -99,6 +107,57 @@ export function readUglyAppConfig(cwd) {
99
107
  ...(requireLatestUglyApp !== undefined && { requireLatestUglyApp }),
100
108
  };
101
109
  }
110
+ /** Parse the `cache` block. Returns undefined when absent. */
111
+ function parseCacheConfig(raw) {
112
+ if (raw === undefined || raw === null)
113
+ return undefined;
114
+ if (typeof raw !== 'object' || Array.isArray(raw)) {
115
+ throw new Error('[uglyapp] cache must be an object.');
116
+ }
117
+ const c = raw;
118
+ const enabled = typeof c.enabled === 'boolean' ? c.enabled : undefined;
119
+ const crossVersionCache = typeof c.crossVersionCache === 'boolean' ? c.crossVersionCache : undefined;
120
+ if (enabled === undefined && crossVersionCache === undefined)
121
+ return undefined;
122
+ return {
123
+ ...(enabled !== undefined && { enabled }),
124
+ ...(crossVersionCache !== undefined && { crossVersionCache }),
125
+ };
126
+ }
127
+ /** Parse the `queue` block (Cloudflare Queue consumer settings). */
128
+ function parseQueueConfig(raw) {
129
+ if (raw === undefined || raw === null)
130
+ return undefined;
131
+ if (typeof raw !== 'object' || Array.isArray(raw)) {
132
+ throw new Error('[uglyapp] queue must be an object.');
133
+ }
134
+ const q = raw;
135
+ const num = (key, min, max) => {
136
+ const v = q[key];
137
+ if (v === undefined)
138
+ return undefined;
139
+ if (typeof v !== 'number' || !Number.isInteger(v) || v < min || v > max) {
140
+ throw new Error(`[uglyapp] queue.${key} must be an integer between ${min} and ${max} (got ${JSON.stringify(v)})`);
141
+ }
142
+ return v;
143
+ };
144
+ const maxConcurrency = num('maxConcurrency', 1, 250);
145
+ const batchSize = num('batchSize', 1, 100);
146
+ const maxRetries = num('maxRetries', 0, 100);
147
+ const maxWaitTimeMs = num('maxWaitTimeMs', 0, 60_000);
148
+ if (maxConcurrency === undefined &&
149
+ batchSize === undefined &&
150
+ maxRetries === undefined &&
151
+ maxWaitTimeMs === undefined) {
152
+ return undefined;
153
+ }
154
+ return {
155
+ ...(maxConcurrency !== undefined && { maxConcurrency }),
156
+ ...(batchSize !== undefined && { batchSize }),
157
+ ...(maxRetries !== undefined && { maxRetries }),
158
+ ...(maxWaitTimeMs !== undefined && { maxWaitTimeMs }),
159
+ };
160
+ }
102
161
  /**
103
162
  * Parse and validate the `auth` block from raw .uglyapp JSON.
104
163
  * Returns undefined when no auth block is present.
@@ -1 +1 @@
1
- {"version":3,"file":"uglyappConfig.js","sourceRoot":"","sources":["../../src/cli/uglyappConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"uglyappConfig.js","sourceRoot":"","sources":["../../src/cli/uglyappConfig.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.921";
1
+ export declare const CLI_VERSION = "0.1.923";
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.921";
2
+ export const CLI_VERSION = "0.1.923";
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ugly-app",
3
3
  "packageManager": "pnpm@10.34.5",
4
- "version": "0.1.921",
4
+ "version": "0.1.923",
5
5
  "type": "module",
6
6
  "comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
7
7
  "files": [
package/src/cli/dev.ts CHANGED
@@ -39,6 +39,13 @@ import { runExportCollections } from './exportCollections.js';
39
39
  import { ensureLocalInfra } from '../native/server/binaries/index.js';
40
40
  import { readUglyAppConfig } from './uglyappConfig.js';
41
41
  import { lintSummaryAsync } from './lint.js';
42
+ import {
43
+ checkDevLock,
44
+ releaseDevLock,
45
+ setAllowMultiple,
46
+ stopHint,
47
+ writeDevLock,
48
+ } from './devLock.js';
42
49
  import { backgroundWait } from '../server/backgroundWait.js';
43
50
 
44
51
  export async function runDev(
@@ -84,6 +91,35 @@ export async function runDev(
84
91
  process.exit(1);
85
92
  }
86
93
 
94
+ // ── 1b. Refuse to stack a second dev server on this project ───────────────
95
+ // The port check above only sees a *healthy* predecessor. A dev server whose
96
+ // server/index.ts crashed binds nothing, yet its tsx/tsc watchers and minio
97
+ // keep running — so without this the next run starts a whole second stack.
98
+ // See devLock.ts for the pile-up this prevents.
99
+ const allowMultipleDev = Boolean(process.env['UGLY_APP_ALLOW_MULTIPLE_DEV']);
100
+ setAllowMultiple(process.cwd(), allowMultipleDev);
101
+ const runningDev = allowMultipleDev ? null : checkDevLock(process.cwd());
102
+ if (runningDev) {
103
+ console.error(
104
+ `[ugly-app] A dev server is already running for this project (PID ${runningDev.pid}, started ${runningDev.startedAt}).\n` +
105
+ `It may not be serving — a crashed server still leaves its watchers and minio up.\n` +
106
+ `To fix, either:\n` +
107
+ ` 1. Stop it, then re-run \`ugly-app dev\`:\n` +
108
+ ` ${stopHint(runningDev)}\n` +
109
+ ` 2. Run this copy from a separate checkout.\n` +
110
+ `If you really do want two stacks on one project, set UGLY_APP_ALLOW_MULTIPLE_DEV=1\n` +
111
+ `(they will share .ugly-studio/minio/data and the local Postgres).`,
112
+ );
113
+ process.exit(1);
114
+ }
115
+ if (!allowMultipleDev) {
116
+ // Skipped when stacking is opted into: several stacks cannot each own one lock.
117
+ writeDevLock(process.cwd(), port);
118
+ // Best-effort: a lock left behind by a SIGKILL is detected as stale on the
119
+ // next run anyway, so this need not catch every exit path.
120
+ process.on('exit', () => releaseDevLock(process.cwd()));
121
+ }
122
+
87
123
  // ── 2. Provision local dev infra (docker-free) ────────────────────────────
88
124
  // Start a bundled Postgres (and MinIO S3/R2) when DATABASE_URL / R2_BUCKET are
89
125
  // unset, and inject their connection details into env for the spawned server.
@@ -0,0 +1,115 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'fs';
3
+ import os from 'os';
4
+ import path from 'path';
5
+ import {
6
+ checkDevLock,
7
+ devLockPath,
8
+ readDevLock,
9
+ releaseDevLock,
10
+ setAllowMultiple,
11
+ writeDevLock,
12
+ } from './devLock.js';
13
+
14
+ /** A probe standing in for `ps`: maps pid → command line, or null if dead. */
15
+ const probeFrom =
16
+ (table: Record<number, string>) =>
17
+ (pid: number): string | null =>
18
+ table[pid] ?? null;
19
+
20
+ const DEV_CMD =
21
+ 'node /repo/node_modules/ugly-app/dist/cli/index.js dev --watch';
22
+
23
+ describe('devLock', () => {
24
+ let projectDir: string;
25
+
26
+ beforeEach(() => {
27
+ projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'devlock-'));
28
+ });
29
+ afterEach(() => {
30
+ fs.rmSync(projectDir, { recursive: true, force: true });
31
+ });
32
+
33
+ it('reads back what it wrote', () => {
34
+ writeDevLock(projectDir, '4321');
35
+ const lock = readDevLock(projectDir);
36
+ expect(lock).not.toBeNull();
37
+ expect(lock?.pid).toBe(process.pid);
38
+ expect(lock?.port).toBe('4321');
39
+ });
40
+
41
+ it('reports no running dev server when there is no lock file', () => {
42
+ expect(checkDevLock(projectDir, probeFrom({}))).toBeNull();
43
+ });
44
+
45
+ it('treats a lock whose process is gone as stale and removes it', () => {
46
+ writeDevLock(projectDir, '4321');
47
+ // Probe knows about no pids at all → the recorded process is dead.
48
+ expect(checkDevLock(projectDir, probeFrom({}))).toBeNull();
49
+ expect(fs.existsSync(devLockPath(projectDir))).toBe(false);
50
+ });
51
+
52
+ it('treats a recycled pid as stale rather than a live dev server', () => {
53
+ writeDevLock(projectDir, '4321');
54
+ // The pid is alive, but it is some unrelated process that inherited the
55
+ // number after the dev server died. Must not be mistaken for the server.
56
+ const probe = probeFrom({ [process.pid]: '/usr/sbin/cupsd -l' });
57
+ expect(checkDevLock(projectDir, probe)).toBeNull();
58
+ expect(fs.existsSync(devLockPath(projectDir))).toBe(false);
59
+ });
60
+
61
+ it('reports a live dev server and keeps the lock file', () => {
62
+ writeDevLock(projectDir, '4321');
63
+ const probe = probeFrom({ [process.pid]: DEV_CMD });
64
+ const live = checkDevLock(projectDir, probe);
65
+ expect(live?.pid).toBe(process.pid);
66
+ expect(fs.existsSync(devLockPath(projectDir))).toBe(true);
67
+ });
68
+
69
+ // The regression this whole module exists for: a dev server whose
70
+ // `server/index.ts` crashed binds no port, so the PORT-in-use guard sees a
71
+ // free port and waves the second stack through. The lock keys on the
72
+ // process instead, so a broken-but-running stack is still detected.
73
+ it('detects a dev server that never bound its port', () => {
74
+ writeDevLock(projectDir, '4321');
75
+ // No listener anywhere — only tsx/tsc/minio survive under this pid.
76
+ const probe = probeFrom({ [process.pid]: DEV_CMD });
77
+ expect(checkDevLock(projectDir, probe)?.pid).toBe(process.pid);
78
+ });
79
+
80
+ it('releases only its own lock', () => {
81
+ writeDevLock(projectDir, '4321');
82
+ // Someone else's lock (different pid) must survive our release.
83
+ const lockFile = devLockPath(projectDir);
84
+ const foreign = { ...readDevLock(projectDir)!, pid: process.pid + 1 };
85
+ fs.writeFileSync(lockFile, JSON.stringify(foreign));
86
+ releaseDevLock(projectDir);
87
+ expect(fs.existsSync(lockFile)).toBe(true);
88
+
89
+ writeDevLock(projectDir, '4321');
90
+ releaseDevLock(projectDir);
91
+ expect(fs.existsSync(lockFile)).toBe(false);
92
+ });
93
+
94
+ // The reaper reads this file because macOS `ps -E` cannot see another
95
+ // process's env; a normal dev run must clear it so it never lingers and
96
+ // silently disables duplicate-reaping for the project.
97
+ it('writes and self-heals the allow-multiple marker', () => {
98
+ const marker = path.join(projectDir, '.ugly-studio', 'dev-allow-multiple');
99
+ setAllowMultiple(projectDir, true);
100
+ expect(fs.existsSync(marker)).toBe(true);
101
+ setAllowMultiple(projectDir, false);
102
+ expect(fs.existsSync(marker)).toBe(false);
103
+ });
104
+
105
+ it('clearing the allow-multiple marker is safe when absent', () => {
106
+ expect(() => setAllowMultiple(projectDir, false)).not.toThrow();
107
+ });
108
+
109
+ it('survives a corrupt lock file instead of throwing', () => {
110
+ fs.mkdirSync(path.dirname(devLockPath(projectDir)), { recursive: true });
111
+ fs.writeFileSync(devLockPath(projectDir), 'not json {');
112
+ expect(readDevLock(projectDir)).toBeNull();
113
+ expect(checkDevLock(projectDir, probeFrom({}))).toBeNull();
114
+ });
115
+ });
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Cross-process singleton guard for `ugly-app dev`.
3
+ *
4
+ * Why this exists: `runDev`'s PORT-in-use check only catches a *healthy*
5
+ * previous dev server — one that actually bound PORT. When `server/index.ts`
6
+ * crashes (a TS error, a bad import), `tsx watch` deliberately stays up waiting
7
+ * for the next file change, `tsc --watch` never exits, and minio keeps serving
8
+ * — but nothing is listening on PORT. The next `ugly-app dev` then sails past
9
+ * the port check and spawns a *second* complete stack, minio and all.
10
+ *
11
+ * Neither existing cleanup mechanism catches that: the self-reap watchdog in
12
+ * dev.ts and the machine-level launchd reaper both key on PPID==1, which never
13
+ * happens while the launching shell (e.g. an agent's background task) is alive.
14
+ * So the stacks accumulate — 2026-07-27 found eight of them for one project,
15
+ * 55 processes and 1.15 GB, each with its own minio writing the same data dir.
16
+ *
17
+ * The lock keys on the one signal a broken-but-running stack still emits: its
18
+ * own process. Staleness is decided by probing the recorded pid, so a crashed
19
+ * or SIGKILLed dev server never leaves a lock that blocks the next run — which
20
+ * is why releasing the lock is best-effort rather than load-bearing.
21
+ */
22
+ import { execSync } from 'child_process';
23
+ import fs from 'fs';
24
+ import path from 'path';
25
+
26
+ export interface DevLockInfo {
27
+ /** pid of the `ugly-app dev` process itself (not the launcher). */
28
+ pid: number;
29
+ /** Process group to signal to take the whole stack down; null on Windows. */
30
+ pgid: number | null;
31
+ port: string;
32
+ startedAt: string;
33
+ }
34
+
35
+ /**
36
+ * Returns the full command line of `pid`, or null when it isn't running.
37
+ * Injected in tests so lock logic is exercised without spawning processes.
38
+ */
39
+ export type CommandProbe = (pid: number) => string | null;
40
+
41
+ /** Windows has no `ps`; we can prove liveness but not identity. */
42
+ const WIN32_ALIVE = '\0win32-alive';
43
+
44
+ export function devLockPath(projectDir: string): string {
45
+ return path.join(projectDir, '.ugly-studio', 'dev.lock');
46
+ }
47
+
48
+ function psField(pid: number, field: 'command' | 'pgid'): string | null {
49
+ try {
50
+ const out = execSync(`ps -o ${field}= -p ${pid}`, {
51
+ encoding: 'utf-8',
52
+ stdio: ['ignore', 'pipe', 'ignore'],
53
+ }).trim();
54
+ return out || null;
55
+ } catch {
56
+ // `ps` exits non-zero when the pid is gone — that is the answer, not an error.
57
+ return null;
58
+ }
59
+ }
60
+
61
+ const psCommand: CommandProbe = (pid) => {
62
+ if (process.platform === 'win32') {
63
+ try {
64
+ process.kill(pid, 0); // signal 0 only tests for existence
65
+ return WIN32_ALIVE;
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ return psField(pid, 'command');
71
+ };
72
+
73
+ /**
74
+ * Does `command` belong to an `ugly-app dev` process? Guards against pid reuse:
75
+ * a recycled pid is alive but is some unrelated program, and killing its process
76
+ * group would take down whatever now owns that number.
77
+ */
78
+ function isDevCommand(command: string): boolean {
79
+ if (command === WIN32_ALIVE) return true; // best effort, see WIN32_ALIVE
80
+ // `dev` stays a regex — it must be a whole word, so `dev-server` etc. miss.
81
+ return command.includes('ugly-app') && /\bdev\b/.test(command);
82
+ }
83
+
84
+ export function readDevLock(projectDir: string): DevLockInfo | null {
85
+ try {
86
+ const raw = fs.readFileSync(devLockPath(projectDir), 'utf-8');
87
+ const parsed = JSON.parse(raw) as Partial<DevLockInfo>;
88
+ if (typeof parsed.pid !== 'number') return null;
89
+ return {
90
+ pid: parsed.pid,
91
+ pgid: typeof parsed.pgid === 'number' ? parsed.pgid : null,
92
+ port: String(parsed.port ?? ''),
93
+ startedAt: String(parsed.startedAt ?? ''),
94
+ };
95
+ } catch {
96
+ // Missing or corrupt: both mean "no usable lock".
97
+ return null;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Returns the lock of a dev server that is genuinely still running for
103
+ * `projectDir`, or null. A lock naming a dead or recycled pid is deleted so the
104
+ * caller can proceed.
105
+ */
106
+ export function checkDevLock(
107
+ projectDir: string,
108
+ probe: CommandProbe = psCommand,
109
+ ): DevLockInfo | null {
110
+ const lock = readDevLock(projectDir);
111
+ if (!lock) {
112
+ clearLockFile(projectDir);
113
+ return null;
114
+ }
115
+ const command = probe(lock.pid);
116
+ if (command !== null && isDevCommand(command)) return lock;
117
+ clearLockFile(projectDir);
118
+ return null;
119
+ }
120
+
121
+ function clearLockFile(projectDir: string): void {
122
+ try {
123
+ fs.rmSync(devLockPath(projectDir), { force: true });
124
+ } catch {
125
+ /* best effort — a lock we cannot delete is re-validated by probe next run */
126
+ }
127
+ }
128
+
129
+ export function writeDevLock(projectDir: string, port: string): void {
130
+ const file = devLockPath(projectDir);
131
+ const pgidRaw =
132
+ process.platform === 'win32' ? null : psField(process.pid, 'pgid');
133
+ const lock: DevLockInfo = {
134
+ pid: process.pid,
135
+ pgid: pgidRaw ? Number(pgidRaw) : null,
136
+ port,
137
+ startedAt: new Date().toISOString(),
138
+ };
139
+ fs.mkdirSync(path.dirname(file), { recursive: true });
140
+ fs.writeFileSync(file, JSON.stringify(lock, null, 2));
141
+ }
142
+
143
+ /** Remove the lock, but only if it is still ours (never clobber a successor). */
144
+ export function releaseDevLock(projectDir: string): void {
145
+ const lock = readDevLock(projectDir);
146
+ if (lock?.pid !== process.pid) return;
147
+ clearLockFile(projectDir);
148
+ }
149
+
150
+ /**
151
+ * On-disk trace of `UGLY_APP_ALLOW_MULTIPLE_DEV`, so the machine-level reaper
152
+ * doesn't undo the opt-out by killing the "duplicate" stacks it names. macOS
153
+ * `ps -E` can't read another process's environment, hence a file. Any ordinary
154
+ * (non-opt-out) `ugly-app dev` clears it, so it can't linger and silently
155
+ * disable duplicate-reaping for a project forever.
156
+ */
157
+ export function setAllowMultiple(projectDir: string, allow: boolean): void {
158
+ const marker = path.join(projectDir, '.ugly-studio', 'dev-allow-multiple');
159
+ try {
160
+ if (!allow) {
161
+ fs.rmSync(marker, { force: true });
162
+ return;
163
+ }
164
+ fs.mkdirSync(path.dirname(marker), { recursive: true });
165
+ fs.writeFileSync(marker, `${new Date().toISOString()}\n`);
166
+ } catch {
167
+ /* advisory only — never block `dev` on it */
168
+ }
169
+ }
170
+
171
+ /**
172
+ * How to stop the stack described by `lock` — the process *group*, so the
173
+ * launcher, tsx, tsc, esbuild and minio all go down together rather than
174
+ * leaving minio behind.
175
+ */
176
+ export function stopHint(lock: DevLockInfo): string {
177
+ return lock.pgid !== null
178
+ ? `kill -TERM -${lock.pgid} # the whole dev stack (server, tsc, minio)`
179
+ : `kill ${lock.pid}`;
180
+ }
@@ -264,8 +264,17 @@ export function readUglyAppConfig(cwd: string): UglyAppConfig | null {
264
264
  if (entries.length) tasks = Object.fromEntries(entries);
265
265
  }
266
266
 
267
+ // `cache` and `queue` are whitelisted here like every other field. Anything
268
+ // NOT parsed below is silently dropped from the returned object, so a key can
269
+ // sit in `.uglyapp` looking configured while every reader sees `undefined` —
270
+ // which is exactly what happened to `queue.maxConcurrency`.
271
+ const cache = parseCacheConfig(config.cache);
272
+ const queue = parseQueueConfig(config.queue);
273
+
267
274
  return {
268
275
  projectId: config.projectId,
276
+ ...(cache !== undefined && { cache }),
277
+ ...(queue !== undefined && { queue }),
269
278
  ...(domain !== undefined && { domain }),
270
279
  ...(uglyBotToken !== undefined && { uglyBotToken }),
271
280
  ...(localToken !== undefined && { localToken }),
@@ -285,6 +294,61 @@ export function readUglyAppConfig(cwd: string): UglyAppConfig | null {
285
294
  };
286
295
  }
287
296
 
297
+ /** Parse the `cache` block. Returns undefined when absent. */
298
+ function parseCacheConfig(raw: unknown): UglyAppCacheConfig | undefined {
299
+ if (raw === undefined || raw === null) return undefined;
300
+ if (typeof raw !== 'object' || Array.isArray(raw)) {
301
+ throw new Error('[uglyapp] cache must be an object.');
302
+ }
303
+ const c = raw as Record<string, unknown>;
304
+ const enabled = typeof c.enabled === 'boolean' ? c.enabled : undefined;
305
+ const crossVersionCache =
306
+ typeof c.crossVersionCache === 'boolean' ? c.crossVersionCache : undefined;
307
+ if (enabled === undefined && crossVersionCache === undefined)
308
+ return undefined;
309
+ return {
310
+ ...(enabled !== undefined && { enabled }),
311
+ ...(crossVersionCache !== undefined && { crossVersionCache }),
312
+ };
313
+ }
314
+
315
+ /** Parse the `queue` block (Cloudflare Queue consumer settings). */
316
+ function parseQueueConfig(raw: unknown): UglyAppQueueConfig | undefined {
317
+ if (raw === undefined || raw === null) return undefined;
318
+ if (typeof raw !== 'object' || Array.isArray(raw)) {
319
+ throw new Error('[uglyapp] queue must be an object.');
320
+ }
321
+ const q = raw as Record<string, unknown>;
322
+ const num = (key: string, min: number, max: number): number | undefined => {
323
+ const v = q[key];
324
+ if (v === undefined) return undefined;
325
+ if (typeof v !== 'number' || !Number.isInteger(v) || v < min || v > max) {
326
+ throw new Error(
327
+ `[uglyapp] queue.${key} must be an integer between ${min} and ${max} (got ${JSON.stringify(v)})`,
328
+ );
329
+ }
330
+ return v;
331
+ };
332
+ const maxConcurrency = num('maxConcurrency', 1, 250);
333
+ const batchSize = num('batchSize', 1, 100);
334
+ const maxRetries = num('maxRetries', 0, 100);
335
+ const maxWaitTimeMs = num('maxWaitTimeMs', 0, 60_000);
336
+ if (
337
+ maxConcurrency === undefined &&
338
+ batchSize === undefined &&
339
+ maxRetries === undefined &&
340
+ maxWaitTimeMs === undefined
341
+ ) {
342
+ return undefined;
343
+ }
344
+ return {
345
+ ...(maxConcurrency !== undefined && { maxConcurrency }),
346
+ ...(batchSize !== undefined && { batchSize }),
347
+ ...(maxRetries !== undefined && { maxRetries }),
348
+ ...(maxWaitTimeMs !== undefined && { maxWaitTimeMs }),
349
+ };
350
+ }
351
+
288
352
  /**
289
353
  * Parse and validate the `auth` block from raw .uglyapp JSON.
290
354
  * Returns undefined when no auth block is present.
@@ -0,0 +1,56 @@
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import fs from 'fs';
3
+ import os from 'os';
4
+ import path from 'path';
5
+ import { readUglyAppConfig } from './uglyappConfig.js';
6
+
7
+ const dirs: string[] = [];
8
+
9
+ function projectWith(config: Record<string, unknown>): string {
10
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'uglyapp-cfg-'));
11
+ dirs.push(dir);
12
+ fs.writeFileSync(
13
+ path.join(dir, '.uglyapp'),
14
+ JSON.stringify({ projectId: 'p1', ...config }),
15
+ );
16
+ return dir;
17
+ }
18
+
19
+ afterEach(() => {
20
+ while (dirs.length) fs.rmSync(dirs.pop()!, { recursive: true, force: true });
21
+ });
22
+
23
+ describe('readUglyAppConfig — blocks that must survive the whitelist', () => {
24
+ // Regression: readUglyAppConfig rebuilds its result field-by-field, so a block
25
+ // present in .uglyapp but absent from that construction is silently dropped and
26
+ // every reader sees `undefined` — the config looks applied but never is.
27
+ it('round-trips the queue block', () => {
28
+ const cfg = readUglyAppConfig(
29
+ projectWith({ queue: { maxConcurrency: 1 } }),
30
+ );
31
+ expect(cfg?.queue?.maxConcurrency).toBe(1);
32
+ });
33
+
34
+ it('round-trips the cache block', () => {
35
+ const cfg = readUglyAppConfig(
36
+ projectWith({ cache: { enabled: false, crossVersionCache: true } }),
37
+ );
38
+ expect(cfg?.cache?.enabled).toBe(false);
39
+ expect(cfg?.cache?.crossVersionCache).toBe(true);
40
+ });
41
+
42
+ it('omits both blocks when absent', () => {
43
+ const cfg = readUglyAppConfig(projectWith({}));
44
+ expect(cfg?.queue).toBeUndefined();
45
+ expect(cfg?.cache).toBeUndefined();
46
+ });
47
+
48
+ it('rejects a non-integer maxConcurrency instead of dropping it', () => {
49
+ expect(() =>
50
+ readUglyAppConfig(projectWith({ queue: { maxConcurrency: 0 } })),
51
+ ).toThrow(/maxConcurrency/);
52
+ expect(() =>
53
+ readUglyAppConfig(projectWith({ queue: { maxConcurrency: 'many' } })),
54
+ ).toThrow(/maxConcurrency/);
55
+ });
56
+ });
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.921";
2
+ export const CLI_VERSION = "0.1.923";