@specific.dev/cli 0.1.126 → 0.1.127
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/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +1 -1
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +1 -1
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_not-found/__next._full.txt +1 -1
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/databases/__next._full.txt +1 -1
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +1 -1
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +1 -1
- package/dist/admin/fullscreen/__next._full.txt +1 -1
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +1 -1
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +1 -1
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/mail/__next._full.txt +1 -1
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +1 -1
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +1 -1
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +1 -1
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +1 -1
- package/dist/cli.js +369 -75
- package/package.json +4 -4
- /package/dist/admin/_next/static/{xkQQHpz09QHzHXw5WkFYT → tWkoycW-NhVqIuvprR9OV}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{xkQQHpz09QHzHXw5WkFYT → tWkoycW-NhVqIuvprR9OV}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{xkQQHpz09QHzHXw5WkFYT → tWkoycW-NhVqIuvprR9OV}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -185179,25 +185179,26 @@ var chokidar_default = { watch, FSWatcher };
|
|
|
185179
185179
|
var import_code_frame = __toESM(require_lib2(), 1);
|
|
185180
185180
|
import * as fs5 from "fs";
|
|
185181
185181
|
import * as path5 from "path";
|
|
185182
|
-
import * as
|
|
185182
|
+
import * as net2 from "net";
|
|
185183
185183
|
import { spawn } from "child_process";
|
|
185184
185184
|
import * as fs4 from "fs";
|
|
185185
185185
|
import * as path4 from "path";
|
|
185186
185186
|
import * as os2 from "os";
|
|
185187
185187
|
import { createReadStream } from "fs";
|
|
185188
185188
|
import { createTarExtractor, extractTo } from "tar-vern";
|
|
185189
|
+
import * as net from "net";
|
|
185190
|
+
import { execFile } from "child_process";
|
|
185191
|
+
import { promisify } from "util";
|
|
185189
185192
|
import { spawn as spawn2 } from "child_process";
|
|
185190
185193
|
import { readFile, writeFile } from "fs/promises";
|
|
185191
185194
|
import { existsSync as existsSync5 } from "fs";
|
|
185192
185195
|
import * as fs6 from "fs";
|
|
185193
185196
|
import * as path6 from "path";
|
|
185194
|
-
import { execFile } from "child_process";
|
|
185195
|
-
import { promisify } from "util";
|
|
185196
185197
|
import * as http from "http";
|
|
185197
185198
|
import * as fs7 from "fs";
|
|
185198
185199
|
import * as path7 from "path";
|
|
185199
185200
|
import { fileURLToPath } from "url";
|
|
185200
|
-
import * as
|
|
185201
|
+
import * as net3 from "net";
|
|
185201
185202
|
import * as fs8 from "fs";
|
|
185202
185203
|
import * as path9 from "path";
|
|
185203
185204
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -185207,7 +185208,7 @@ import * as path8 from "path";
|
|
|
185207
185208
|
import * as crypto from "crypto";
|
|
185208
185209
|
import * as http2 from "http";
|
|
185209
185210
|
import * as crypto2 from "crypto";
|
|
185210
|
-
import * as
|
|
185211
|
+
import * as net4 from "net";
|
|
185211
185212
|
import * as fs9 from "fs";
|
|
185212
185213
|
import * as path10 from "path";
|
|
185213
185214
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -185217,14 +185218,14 @@ import * as path11 from "path";
|
|
|
185217
185218
|
import { spawnSync } from "child_process";
|
|
185218
185219
|
import * as fs11 from "fs";
|
|
185219
185220
|
import * as path12 from "path";
|
|
185220
|
-
import * as net4 from "net";
|
|
185221
|
-
import { spawn as spawn5 } from "child_process";
|
|
185222
185221
|
import * as net5 from "net";
|
|
185222
|
+
import { spawn as spawn5 } from "child_process";
|
|
185223
|
+
import * as net6 from "net";
|
|
185223
185224
|
import * as fs12 from "fs";
|
|
185224
185225
|
import * as path13 from "path";
|
|
185225
185226
|
import { generateSlug } from "random-word-slugs";
|
|
185226
185227
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
185227
|
-
import * as
|
|
185228
|
+
import * as net7 from "node:net";
|
|
185228
185229
|
import { EventEmitter as EventEmitter22 } from "events";
|
|
185229
185230
|
import { execSync as execSync2 } from "child_process";
|
|
185230
185231
|
import * as path15 from "path";
|
|
@@ -369275,14 +369276,22 @@ var temporalBinary = {
|
|
|
369275
369276
|
stripComponents: 0,
|
|
369276
369277
|
executables: ["temporal"]
|
|
369277
369278
|
};
|
|
369278
|
-
function killProcess(proc) {
|
|
369279
|
+
function killProcess(proc, opts = {}) {
|
|
369279
369280
|
return new Promise((resolve52) => {
|
|
369280
369281
|
if (proc.killed || proc.exitCode !== null) {
|
|
369281
369282
|
resolve52();
|
|
369282
369283
|
return;
|
|
369283
369284
|
}
|
|
369284
369285
|
proc.once("exit", () => resolve52());
|
|
369285
|
-
proc.
|
|
369286
|
+
if (opts.detached && proc.pid) {
|
|
369287
|
+
try {
|
|
369288
|
+
process.kill(-proc.pid, "SIGKILL");
|
|
369289
|
+
} catch {
|
|
369290
|
+
proc.kill("SIGKILL");
|
|
369291
|
+
}
|
|
369292
|
+
} else {
|
|
369293
|
+
proc.kill("SIGKILL");
|
|
369294
|
+
}
|
|
369286
369295
|
});
|
|
369287
369296
|
}
|
|
369288
369297
|
function killProcessGroup(pid) {
|
|
@@ -369291,6 +369300,143 @@ function killProcessGroup(pid) {
|
|
|
369291
369300
|
} catch {
|
|
369292
369301
|
}
|
|
369293
369302
|
}
|
|
369303
|
+
var execFileAsync = promisify(execFile);
|
|
369304
|
+
function isPortInUse(host, port) {
|
|
369305
|
+
return new Promise((resolve52) => {
|
|
369306
|
+
const socket = new net.Socket();
|
|
369307
|
+
socket.setTimeout(1e3);
|
|
369308
|
+
socket.on("connect", () => {
|
|
369309
|
+
socket.destroy();
|
|
369310
|
+
resolve52(true);
|
|
369311
|
+
});
|
|
369312
|
+
socket.on("timeout", () => {
|
|
369313
|
+
socket.destroy();
|
|
369314
|
+
resolve52(false);
|
|
369315
|
+
});
|
|
369316
|
+
socket.on("error", () => {
|
|
369317
|
+
socket.destroy();
|
|
369318
|
+
resolve52(false);
|
|
369319
|
+
});
|
|
369320
|
+
socket.connect(port, host);
|
|
369321
|
+
});
|
|
369322
|
+
}
|
|
369323
|
+
async function waitForPortFree(host, port, timeoutMs = 3e3) {
|
|
369324
|
+
const deadline = Date.now() + timeoutMs;
|
|
369325
|
+
while (Date.now() < deadline) {
|
|
369326
|
+
if (!await isPortInUse(host, port)) return true;
|
|
369327
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
369328
|
+
}
|
|
369329
|
+
return !await isPortInUse(host, port);
|
|
369330
|
+
}
|
|
369331
|
+
async function getListenersOnPort(port) {
|
|
369332
|
+
let pids = [];
|
|
369333
|
+
try {
|
|
369334
|
+
const { stdout } = await execFileAsync(
|
|
369335
|
+
"lsof",
|
|
369336
|
+
["-i", `:${port}`, "-sTCP:LISTEN", "-t"],
|
|
369337
|
+
{ timeout: 5e3 }
|
|
369338
|
+
);
|
|
369339
|
+
pids = stdout.trim().split("\n").map((l) => parseInt(l.trim(), 10)).filter((n) => !isNaN(n));
|
|
369340
|
+
} catch {
|
|
369341
|
+
return [];
|
|
369342
|
+
}
|
|
369343
|
+
const results = [];
|
|
369344
|
+
for (const pid of pids) {
|
|
369345
|
+
results.push({ pid, command: await resolveCommand(pid) });
|
|
369346
|
+
}
|
|
369347
|
+
return results;
|
|
369348
|
+
}
|
|
369349
|
+
async function resolveCommand(pid) {
|
|
369350
|
+
try {
|
|
369351
|
+
const { stdout } = await execFileAsync(
|
|
369352
|
+
"ps",
|
|
369353
|
+
["-p", String(pid), "-o", "command="],
|
|
369354
|
+
{ timeout: 1e3 }
|
|
369355
|
+
);
|
|
369356
|
+
return stdout.trim();
|
|
369357
|
+
} catch {
|
|
369358
|
+
return "";
|
|
369359
|
+
}
|
|
369360
|
+
}
|
|
369361
|
+
async function reclaimSpecificOrphanOnPort(port) {
|
|
369362
|
+
const listeners = await getListenersOnPort(port);
|
|
369363
|
+
let killed = false;
|
|
369364
|
+
for (const { pid, command } of listeners) {
|
|
369365
|
+
if (!isOwnedBySpecific(command)) continue;
|
|
369366
|
+
try {
|
|
369367
|
+
process.kill(-pid, "SIGKILL");
|
|
369368
|
+
killed = true;
|
|
369369
|
+
} catch {
|
|
369370
|
+
try {
|
|
369371
|
+
process.kill(pid, "SIGKILL");
|
|
369372
|
+
killed = true;
|
|
369373
|
+
} catch {
|
|
369374
|
+
}
|
|
369375
|
+
}
|
|
369376
|
+
}
|
|
369377
|
+
return killed;
|
|
369378
|
+
}
|
|
369379
|
+
function isOwnedBySpecific(argv) {
|
|
369380
|
+
return argv.includes("/.specific/bin/") || argv.includes("/.burrito/electric_");
|
|
369381
|
+
}
|
|
369382
|
+
async function killSpecificProcessesReferencing(needle) {
|
|
369383
|
+
if (!needle) return 0;
|
|
369384
|
+
let stdout = "";
|
|
369385
|
+
try {
|
|
369386
|
+
const result = await execFileAsync("ps", ["-A", "-o", "pid=,command="], {
|
|
369387
|
+
timeout: 5e3,
|
|
369388
|
+
maxBuffer: 10 * 1024 * 1024
|
|
369389
|
+
});
|
|
369390
|
+
stdout = result.stdout;
|
|
369391
|
+
} catch {
|
|
369392
|
+
return 0;
|
|
369393
|
+
}
|
|
369394
|
+
const self2 = process.pid;
|
|
369395
|
+
const candidates = [];
|
|
369396
|
+
for (const raw of stdout.split("\n")) {
|
|
369397
|
+
const line = raw.trim();
|
|
369398
|
+
if (!line) continue;
|
|
369399
|
+
const space = line.indexOf(" ");
|
|
369400
|
+
if (space <= 0) continue;
|
|
369401
|
+
const pid = parseInt(line.slice(0, space), 10);
|
|
369402
|
+
if (isNaN(pid) || pid === self2) continue;
|
|
369403
|
+
const command = line.slice(space + 1);
|
|
369404
|
+
if (!isOwnedBySpecific(command)) continue;
|
|
369405
|
+
if (command.includes(needle) || await processOpensPathUnder(pid, needle)) {
|
|
369406
|
+
candidates.push(pid);
|
|
369407
|
+
}
|
|
369408
|
+
}
|
|
369409
|
+
let killed = 0;
|
|
369410
|
+
for (const pid of candidates) {
|
|
369411
|
+
try {
|
|
369412
|
+
process.kill(-pid, "SIGKILL");
|
|
369413
|
+
killed++;
|
|
369414
|
+
} catch {
|
|
369415
|
+
try {
|
|
369416
|
+
process.kill(pid, "SIGKILL");
|
|
369417
|
+
killed++;
|
|
369418
|
+
} catch {
|
|
369419
|
+
}
|
|
369420
|
+
}
|
|
369421
|
+
}
|
|
369422
|
+
return killed;
|
|
369423
|
+
}
|
|
369424
|
+
async function processOpensPathUnder(pid, prefix) {
|
|
369425
|
+
try {
|
|
369426
|
+
const { stdout } = await execFileAsync("lsof", ["-p", String(pid), "-F", "n"], {
|
|
369427
|
+
timeout: 3e3,
|
|
369428
|
+
maxBuffer: 5 * 1024 * 1024
|
|
369429
|
+
});
|
|
369430
|
+
for (const raw of stdout.split("\n")) {
|
|
369431
|
+
if (raw.length > 1 && raw[0] === "n" && raw.slice(1).startsWith(prefix)) {
|
|
369432
|
+
return true;
|
|
369433
|
+
}
|
|
369434
|
+
}
|
|
369435
|
+
} catch {
|
|
369436
|
+
return false;
|
|
369437
|
+
}
|
|
369438
|
+
return false;
|
|
369439
|
+
}
|
|
369294
369440
|
async function startPostgres(pg, port, dataDir, onProgress) {
|
|
369295
369441
|
const binary = await ensureBinary(postgresBinary, void 0, onProgress);
|
|
369296
369442
|
const dbDataPath = path5.join(process.cwd(), dataDir, pg.name);
|
|
@@ -369299,6 +369445,7 @@ async function startPostgres(pg, port, dataDir, onProgress) {
|
|
|
369299
369445
|
const password = "postgres";
|
|
369300
369446
|
const libraryEnv = getLibraryEnv(binary);
|
|
369301
369447
|
const env2 = { ...process.env, ...libraryEnv };
|
|
369448
|
+
reclaimOrphanedPostmaster(dbDataPath);
|
|
369302
369449
|
const pgConfPath = path5.join(dbDataPath, "postgresql.conf");
|
|
369303
369450
|
const dataValid = fs5.existsSync(pgConfPath);
|
|
369304
369451
|
if (!dataValid) {
|
|
@@ -369314,6 +369461,10 @@ async function startPostgres(pg, port, dataDir, onProgress) {
|
|
|
369314
369461
|
} catch {
|
|
369315
369462
|
}
|
|
369316
369463
|
}
|
|
369464
|
+
if (await isPortInUse(host, port)) {
|
|
369465
|
+
await reclaimSpecificOrphanOnPort(port);
|
|
369466
|
+
await waitForPortFree(host, port, 1e3);
|
|
369467
|
+
}
|
|
369317
369468
|
const postgres = spawn(
|
|
369318
369469
|
binary.executables["postgres"],
|
|
369319
369470
|
[
|
|
@@ -369332,9 +369483,11 @@ async function startPostgres(pg, port, dataDir, onProgress) {
|
|
|
369332
369483
|
],
|
|
369333
369484
|
{
|
|
369334
369485
|
stdio: ["ignore", "pipe", "pipe"],
|
|
369335
|
-
env: env2
|
|
369486
|
+
env: env2,
|
|
369487
|
+
detached: true
|
|
369336
369488
|
}
|
|
369337
369489
|
);
|
|
369490
|
+
postgres.unref();
|
|
369338
369491
|
pipeProcess("postgres", postgres);
|
|
369339
369492
|
await Promise.race([
|
|
369340
369493
|
waitForTcpPort(host, port),
|
|
@@ -369358,21 +369511,28 @@ async function startPostgres(pg, port, dataDir, onProgress) {
|
|
|
369358
369511
|
dbName: pg.name,
|
|
369359
369512
|
url: `postgres://${user}:${password}@${host}:${port}/${pg.name}`,
|
|
369360
369513
|
pid: postgres.pid,
|
|
369514
|
+
detached: true,
|
|
369361
369515
|
async stop() {
|
|
369362
|
-
return killProcess(postgres);
|
|
369516
|
+
return killProcess(postgres, { detached: true });
|
|
369363
369517
|
}
|
|
369364
369518
|
};
|
|
369365
369519
|
}
|
|
369366
369520
|
async function startRedis(redis, port, onProgress) {
|
|
369367
369521
|
const binary = await ensureBinary(redisBinary, void 0, onProgress);
|
|
369368
369522
|
const host = "127.0.0.1";
|
|
369523
|
+
if (await isPortInUse(host, port)) {
|
|
369524
|
+
await reclaimSpecificOrphanOnPort(port);
|
|
369525
|
+
await waitForPortFree(host, port, 1e3);
|
|
369526
|
+
}
|
|
369369
369527
|
const redisProc = spawn(
|
|
369370
369528
|
binary.executables["redis-server"],
|
|
369371
369529
|
["--port", String(port), "--bind", host, "--daemonize", "no"],
|
|
369372
369530
|
{
|
|
369373
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
369531
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
369532
|
+
detached: true
|
|
369374
369533
|
}
|
|
369375
369534
|
);
|
|
369535
|
+
redisProc.unref();
|
|
369376
369536
|
pipeProcess("redis", redisProc);
|
|
369377
369537
|
await waitForTcpPort(host, port);
|
|
369378
369538
|
return {
|
|
@@ -369385,8 +369545,9 @@ async function startRedis(redis, port, onProgress) {
|
|
|
369385
369545
|
dbName: redis.name,
|
|
369386
369546
|
url: `redis://${host}:${port}`,
|
|
369387
369547
|
pid: redisProc.pid,
|
|
369548
|
+
detached: true,
|
|
369388
369549
|
async stop() {
|
|
369389
|
-
return killProcess(redisProc);
|
|
369550
|
+
return killProcess(redisProc, { detached: true });
|
|
369390
369551
|
}
|
|
369391
369552
|
};
|
|
369392
369553
|
}
|
|
@@ -369474,6 +369635,39 @@ async function createPostgresDatabase(postgresPath, dataDir, dbName, env2) {
|
|
|
369474
369635
|
proc.stdin?.end();
|
|
369475
369636
|
});
|
|
369476
369637
|
}
|
|
369638
|
+
function reclaimOrphanedPostmaster(dbDataPath) {
|
|
369639
|
+
const pidFile = path5.join(dbDataPath, "postmaster.pid");
|
|
369640
|
+
if (!fs5.existsSync(pidFile)) return;
|
|
369641
|
+
let pid;
|
|
369642
|
+
try {
|
|
369643
|
+
const firstLine = fs5.readFileSync(pidFile, "utf-8").split("\n")[0] ?? "";
|
|
369644
|
+
pid = parseInt(firstLine.trim(), 10);
|
|
369645
|
+
} catch {
|
|
369646
|
+
return;
|
|
369647
|
+
}
|
|
369648
|
+
if (isNaN(pid) || pid <= 0) return;
|
|
369649
|
+
let alive = false;
|
|
369650
|
+
try {
|
|
369651
|
+
process.kill(pid, 0);
|
|
369652
|
+
alive = true;
|
|
369653
|
+
} catch (e) {
|
|
369654
|
+
alive = e.code !== "ESRCH";
|
|
369655
|
+
}
|
|
369656
|
+
if (alive) {
|
|
369657
|
+
try {
|
|
369658
|
+
process.kill(-pid, "SIGKILL");
|
|
369659
|
+
} catch {
|
|
369660
|
+
try {
|
|
369661
|
+
process.kill(pid, "SIGKILL");
|
|
369662
|
+
} catch {
|
|
369663
|
+
}
|
|
369664
|
+
}
|
|
369665
|
+
}
|
|
369666
|
+
try {
|
|
369667
|
+
fs5.unlinkSync(pidFile);
|
|
369668
|
+
} catch {
|
|
369669
|
+
}
|
|
369670
|
+
}
|
|
369477
369671
|
async function waitForTcpPort(host, port, timeoutMs = 3e4) {
|
|
369478
369672
|
const startTime = Date.now();
|
|
369479
369673
|
while (Date.now() - startTime < timeoutMs) {
|
|
@@ -369487,7 +369681,7 @@ async function waitForTcpPort(host, port, timeoutMs = 3e4) {
|
|
|
369487
369681
|
}
|
|
369488
369682
|
function checkTcpPort(host, port) {
|
|
369489
369683
|
return new Promise((resolve52) => {
|
|
369490
|
-
const socket = new
|
|
369684
|
+
const socket = new net2.Socket();
|
|
369491
369685
|
socket.setTimeout(1e3);
|
|
369492
369686
|
socket.on("connect", () => {
|
|
369493
369687
|
socket.destroy();
|
|
@@ -370015,7 +370209,6 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
|
|
|
370015
370209
|
}
|
|
370016
370210
|
};
|
|
370017
370211
|
}
|
|
370018
|
-
var execFileAsync = promisify(execFile);
|
|
370019
370212
|
var InstanceStateManager = class {
|
|
370020
370213
|
stateDir;
|
|
370021
370214
|
statePath;
|
|
@@ -370107,8 +370300,20 @@ var InstanceStateManager = class {
|
|
|
370107
370300
|
releaseLock();
|
|
370108
370301
|
}
|
|
370109
370302
|
}
|
|
370303
|
+
/**
|
|
370304
|
+
* Kill every Specific-owned process (postgres, redis, electric, temporal,
|
|
370305
|
+
* drizzle-gateway) whose command line references this key's data
|
|
370306
|
+
* directory. This is the safety net for when state.json is missing or
|
|
370307
|
+
* incomplete — the port allocator can pick a different block on restart,
|
|
370308
|
+
* so port-based cleanup alone isn't enough. We identify orphans by their
|
|
370309
|
+
* data-dir/config-dir argument, which is stable across runs.
|
|
370310
|
+
*/
|
|
370311
|
+
async sweepKeyDirOrphans() {
|
|
370312
|
+
await killSpecificProcessesReferencing(this.stateDir);
|
|
370313
|
+
}
|
|
370110
370314
|
async cleanStaleState() {
|
|
370111
370315
|
if (!fs6.existsSync(this.statePath)) {
|
|
370316
|
+
await this.sweepKeyDirOrphans();
|
|
370112
370317
|
return false;
|
|
370113
370318
|
}
|
|
370114
370319
|
const releaseLock = await this.acquireLock();
|
|
@@ -370117,6 +370322,7 @@ var InstanceStateManager = class {
|
|
|
370117
370322
|
const state = JSON.parse(content);
|
|
370118
370323
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
370119
370324
|
await this.killOrphanedProcesses(state);
|
|
370325
|
+
await this.sweepKeyDirOrphans();
|
|
370120
370326
|
fs6.unlinkSync(this.statePath);
|
|
370121
370327
|
return true;
|
|
370122
370328
|
}
|
|
@@ -370146,18 +370352,22 @@ var InstanceStateManager = class {
|
|
|
370146
370352
|
}
|
|
370147
370353
|
}
|
|
370148
370354
|
for (const db of Object.values(state.databases)) {
|
|
370149
|
-
|
|
370150
|
-
|
|
370151
|
-
|
|
370152
|
-
|
|
370153
|
-
|
|
370154
|
-
|
|
370155
|
-
|
|
370156
|
-
|
|
370157
|
-
|
|
370158
|
-
|
|
370159
|
-
|
|
370160
|
-
|
|
370355
|
+
killTrackedProcess(db.pid, db.detached, this.isProcessRunning.bind(this));
|
|
370356
|
+
if (db.port) {
|
|
370357
|
+
await reclaimSpecificOrphanOnPort(db.port);
|
|
370358
|
+
}
|
|
370359
|
+
}
|
|
370360
|
+
for (const aux of Object.values(state.electric ?? {})) {
|
|
370361
|
+
killTrackedProcess(aux.pid, aux.detached, this.isProcessRunning.bind(this));
|
|
370362
|
+
if (aux.port) {
|
|
370363
|
+
await reclaimSpecificOrphanOnPort(aux.port);
|
|
370364
|
+
}
|
|
370365
|
+
}
|
|
370366
|
+
if (state.drizzleGateway) {
|
|
370367
|
+
const dg = state.drizzleGateway;
|
|
370368
|
+
killTrackedProcess(dg.pid, dg.detached, this.isProcessRunning.bind(this));
|
|
370369
|
+
if (dg.port) {
|
|
370370
|
+
await reclaimSpecificOrphanOnPort(dg.port);
|
|
370161
370371
|
}
|
|
370162
370372
|
}
|
|
370163
370373
|
}
|
|
@@ -370228,6 +370438,32 @@ var InstanceStateManager = class {
|
|
|
370228
370438
|
releaseLock();
|
|
370229
370439
|
}
|
|
370230
370440
|
}
|
|
370441
|
+
async registerElectric(databaseName, info) {
|
|
370442
|
+
if (!this.ownsInstances) {
|
|
370443
|
+
throw new Error("Cannot register Electric: not the owner");
|
|
370444
|
+
}
|
|
370445
|
+
const releaseLock = await this.acquireLock();
|
|
370446
|
+
try {
|
|
370447
|
+
const state = this.readState();
|
|
370448
|
+
state.electric = { ...state.electric ?? {}, [databaseName]: info };
|
|
370449
|
+
this.writeStateAtomic(state);
|
|
370450
|
+
} finally {
|
|
370451
|
+
releaseLock();
|
|
370452
|
+
}
|
|
370453
|
+
}
|
|
370454
|
+
async registerDrizzleGateway(info) {
|
|
370455
|
+
if (!this.ownsInstances) {
|
|
370456
|
+
throw new Error("Cannot register Drizzle Gateway: not the owner");
|
|
370457
|
+
}
|
|
370458
|
+
const releaseLock = await this.acquireLock();
|
|
370459
|
+
try {
|
|
370460
|
+
const state = this.readState();
|
|
370461
|
+
state.drizzleGateway = info;
|
|
370462
|
+
this.writeStateAtomic(state);
|
|
370463
|
+
} finally {
|
|
370464
|
+
releaseLock();
|
|
370465
|
+
}
|
|
370466
|
+
}
|
|
370231
370467
|
async setPublicUrls(publicUrls) {
|
|
370232
370468
|
if (!this.ownsInstances) {
|
|
370233
370469
|
throw new Error("Cannot set public URLs: not the owner");
|
|
@@ -370266,17 +370502,15 @@ var InstanceStateManager = class {
|
|
|
370266
370502
|
fs6.renameSync(tmpPath, this.statePath);
|
|
370267
370503
|
}
|
|
370268
370504
|
};
|
|
370269
|
-
|
|
370505
|
+
function killTrackedProcess(pid, detached, isProcessRunning) {
|
|
370506
|
+
if (!pid || !isProcessRunning(pid)) return;
|
|
370270
370507
|
try {
|
|
370271
|
-
|
|
370272
|
-
"
|
|
370273
|
-
|
|
370274
|
-
|
|
370275
|
-
|
|
370276
|
-
const pid = parseInt(stdout.trim().split("\n")[0], 10);
|
|
370277
|
-
return isNaN(pid) ? void 0 : pid;
|
|
370508
|
+
if (detached) {
|
|
370509
|
+
process.kill(-pid, "SIGKILL");
|
|
370510
|
+
} else {
|
|
370511
|
+
process.kill(pid, "SIGKILL");
|
|
370512
|
+
}
|
|
370278
370513
|
} catch {
|
|
370279
|
-
return void 0;
|
|
370280
370514
|
}
|
|
370281
370515
|
}
|
|
370282
370516
|
var __dirname = path7.dirname(fileURLToPath(import.meta.url));
|
|
@@ -370574,21 +370808,15 @@ async function startElectric(postgres, port, dataDir, options2) {
|
|
|
370574
370808
|
);
|
|
370575
370809
|
const secret = generateRandomString(32);
|
|
370576
370810
|
const host = "127.0.0.1";
|
|
370577
|
-
if (await
|
|
370578
|
-
|
|
370579
|
-
|
|
370580
|
-
await sleep2(100);
|
|
370581
|
-
if (!await checkTcpPort2(host, port)) {
|
|
370582
|
-
freed = true;
|
|
370583
|
-
break;
|
|
370584
|
-
}
|
|
370585
|
-
}
|
|
370811
|
+
if (await isPortInUse(host, port)) {
|
|
370812
|
+
await reclaimSpecificOrphanOnPort(port);
|
|
370813
|
+
const freed = await waitForPortFree(host, port, 3e3);
|
|
370586
370814
|
if (!freed) {
|
|
370587
370815
|
throw new Error(
|
|
370588
|
-
`Electric port ${port} is already in use
|
|
370816
|
+
`Electric port ${port} is already in use by a non-Specific process. Find it with \`lsof -i :${port}\` and kill it, then retry.`
|
|
370589
370817
|
);
|
|
370590
370818
|
}
|
|
370591
|
-
writeLog("electric", `Port ${port} was occupied but
|
|
370819
|
+
writeLog("electric", `Port ${port} was occupied but has been reclaimed`);
|
|
370592
370820
|
}
|
|
370593
370821
|
const storageDir = path9.join(process.cwd(), dataDir, `electric-${postgres.name}`);
|
|
370594
370822
|
fs8.rmSync(storageDir, { recursive: true, force: true });
|
|
@@ -370600,6 +370828,7 @@ async function startElectric(postgres, port, dataDir, options2) {
|
|
|
370600
370828
|
writeLog("electric", `Binary: ${binary.executables["electric"]}`);
|
|
370601
370829
|
const electric = spawn3(binary.executables["electric"], [], {
|
|
370602
370830
|
stdio: ["ignore", "pipe", "pipe"],
|
|
370831
|
+
detached: true,
|
|
370603
370832
|
env: {
|
|
370604
370833
|
...process.env,
|
|
370605
370834
|
DATABASE_URL: postgres.url,
|
|
@@ -370610,16 +370839,18 @@ async function startElectric(postgres, port, dataDir, options2) {
|
|
|
370610
370839
|
ELECTRIC_STORAGE: "MEMORY"
|
|
370611
370840
|
}
|
|
370612
370841
|
});
|
|
370842
|
+
electric.unref();
|
|
370613
370843
|
pipeProcess("electric", electric);
|
|
370614
370844
|
await waitForTcpPort2(host, port);
|
|
370615
370845
|
return {
|
|
370616
370846
|
databaseName: postgres.name,
|
|
370617
370847
|
pid: electric.pid,
|
|
370848
|
+
detached: true,
|
|
370618
370849
|
port,
|
|
370619
370850
|
url: `http://${host}:${port}`,
|
|
370620
370851
|
secret,
|
|
370621
370852
|
async stop() {
|
|
370622
|
-
return killProcess(electric);
|
|
370853
|
+
return killProcess(electric, { detached: true });
|
|
370623
370854
|
}
|
|
370624
370855
|
};
|
|
370625
370856
|
}
|
|
@@ -370636,7 +370867,7 @@ async function waitForTcpPort2(host, port, timeoutMs = 3e4) {
|
|
|
370636
370867
|
}
|
|
370637
370868
|
function checkTcpPort2(host, port) {
|
|
370638
370869
|
return new Promise((resolve52) => {
|
|
370639
|
-
const socket = new
|
|
370870
|
+
const socket = new net3.Socket();
|
|
370640
370871
|
socket.setTimeout(1e3);
|
|
370641
370872
|
socket.on("connect", () => {
|
|
370642
370873
|
socket.destroy();
|
|
@@ -370822,22 +371053,29 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
|
|
|
370822
371053
|
"drizzle-gateway",
|
|
370823
371054
|
`Binary: ${binary.executables["drizzle-gateway"]}`
|
|
370824
371055
|
);
|
|
371056
|
+
if (await isPortInUse(host, port)) {
|
|
371057
|
+
await reclaimSpecificOrphanOnPort(port);
|
|
371058
|
+
await waitForPortFree(host, port, 1e3);
|
|
371059
|
+
}
|
|
370825
371060
|
const drizzleGateway = spawn4(binary.executables["drizzle-gateway"], [], {
|
|
370826
371061
|
stdio: ["ignore", "pipe", "pipe"],
|
|
371062
|
+
detached: true,
|
|
370827
371063
|
env: {
|
|
370828
371064
|
...process.env,
|
|
370829
371065
|
STORE_PATH: drizzleConfigDir,
|
|
370830
371066
|
PORT: String(port)
|
|
370831
371067
|
}
|
|
370832
371068
|
});
|
|
371069
|
+
drizzleGateway.unref();
|
|
370833
371070
|
pipeProcess("drizzle-gateway", drizzleGateway);
|
|
370834
371071
|
await waitForTcpPort3(host, port);
|
|
370835
371072
|
return {
|
|
370836
371073
|
port,
|
|
370837
371074
|
url: `http://${host}:${port}`,
|
|
370838
371075
|
pid: drizzleGateway.pid,
|
|
371076
|
+
detached: true,
|
|
370839
371077
|
async stop() {
|
|
370840
|
-
return killProcess(drizzleGateway);
|
|
371078
|
+
return killProcess(drizzleGateway, { detached: true });
|
|
370841
371079
|
}
|
|
370842
371080
|
};
|
|
370843
371081
|
}
|
|
@@ -370856,7 +371094,7 @@ async function waitForTcpPort3(host, port, timeoutMs = 3e4) {
|
|
|
370856
371094
|
}
|
|
370857
371095
|
function checkTcpPort3(host, port) {
|
|
370858
371096
|
return new Promise((resolve52) => {
|
|
370859
|
-
const socket = new
|
|
371097
|
+
const socket = new net4.Socket();
|
|
370860
371098
|
socket.setTimeout(1e3);
|
|
370861
371099
|
socket.on("connect", () => {
|
|
370862
371100
|
socket.destroy();
|
|
@@ -371190,6 +371428,12 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
|
|
|
371190
371428
|
}
|
|
371191
371429
|
const host = "127.0.0.1";
|
|
371192
371430
|
const namespaceArgs = temporals.flatMap((t) => ["--namespace", t.name]);
|
|
371431
|
+
for (const p of [grpcPort, uiPort]) {
|
|
371432
|
+
if (await isPortInUse(host, p)) {
|
|
371433
|
+
await reclaimSpecificOrphanOnPort(p);
|
|
371434
|
+
await waitForPortFree(host, p, 1e3);
|
|
371435
|
+
}
|
|
371436
|
+
}
|
|
371193
371437
|
const proc = spawn5(
|
|
371194
371438
|
binary.executables["temporal"],
|
|
371195
371439
|
[
|
|
@@ -371208,12 +371452,14 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
|
|
|
371208
371452
|
"pretty"
|
|
371209
371453
|
],
|
|
371210
371454
|
{
|
|
371211
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
371455
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
371456
|
+
detached: true
|
|
371212
371457
|
}
|
|
371213
371458
|
);
|
|
371459
|
+
proc.unref();
|
|
371214
371460
|
pipeProcess("temporal", proc);
|
|
371215
371461
|
await waitForTcpPort4(host, grpcPort);
|
|
371216
|
-
const stopServer = () => killProcess(proc);
|
|
371462
|
+
const stopServer = () => killProcess(proc, { detached: true });
|
|
371217
371463
|
const instances = temporals.map((temporal, i) => ({
|
|
371218
371464
|
name: temporal.name,
|
|
371219
371465
|
type: "temporal",
|
|
@@ -371225,6 +371471,7 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
|
|
|
371225
371471
|
url: `${host}:${grpcPort}`,
|
|
371226
371472
|
uiPort,
|
|
371227
371473
|
pid: i === 0 ? proc.pid : void 0,
|
|
371474
|
+
detached: i === 0 ? true : void 0,
|
|
371228
371475
|
// Only the first instance owns the server lifecycle
|
|
371229
371476
|
stop: i === 0 ? stopServer : async () => {
|
|
371230
371477
|
}
|
|
@@ -371244,7 +371491,7 @@ async function waitForTcpPort4(host, port, timeoutMs = 3e4) {
|
|
|
371244
371491
|
}
|
|
371245
371492
|
function checkTcpPort4(host, port) {
|
|
371246
371493
|
return new Promise((resolve52) => {
|
|
371247
|
-
const socket = new
|
|
371494
|
+
const socket = new net5.Socket();
|
|
371248
371495
|
socket.setTimeout(1e3);
|
|
371249
371496
|
socket.on("connect", () => {
|
|
371250
371497
|
socket.destroy();
|
|
@@ -371346,6 +371593,8 @@ async function startResources(options2) {
|
|
|
371346
371593
|
dbName: instance.dbName,
|
|
371347
371594
|
url: instance.url
|
|
371348
371595
|
};
|
|
371596
|
+
if (instance.pid !== void 0) dbState.pid = instance.pid;
|
|
371597
|
+
if (instance.detached) dbState.detached = true;
|
|
371349
371598
|
if (instance.reshapeEnabled) {
|
|
371350
371599
|
dbState.reshapeEnabled = true;
|
|
371351
371600
|
if (instance.reshapeSearchPath) {
|
|
@@ -371368,7 +371617,7 @@ async function startResources(options2) {
|
|
|
371368
371617
|
startedResources.push(instance);
|
|
371369
371618
|
callbacks.onResourceReady?.(redis.name, instance);
|
|
371370
371619
|
log(`Redis "${redis.name}" ready`);
|
|
371371
|
-
|
|
371620
|
+
const redisState = {
|
|
371372
371621
|
engine: "redis",
|
|
371373
371622
|
port: instance.port,
|
|
371374
371623
|
host: instance.host,
|
|
@@ -371376,7 +371625,10 @@ async function startResources(options2) {
|
|
|
371376
371625
|
password: instance.password,
|
|
371377
371626
|
dbName: instance.dbName,
|
|
371378
371627
|
url: instance.url
|
|
371379
|
-
}
|
|
371628
|
+
};
|
|
371629
|
+
if (instance.pid !== void 0) redisState.pid = instance.pid;
|
|
371630
|
+
if (instance.detached) redisState.detached = true;
|
|
371631
|
+
await stateManager.registerDatabase(redis.name, redisState);
|
|
371380
371632
|
}
|
|
371381
371633
|
for (const storage of storageConfigs) {
|
|
371382
371634
|
if (signal?.cancelled) {
|
|
@@ -371430,6 +371682,8 @@ async function startResources(options2) {
|
|
|
371430
371682
|
dbName: "",
|
|
371431
371683
|
url: instance.url
|
|
371432
371684
|
};
|
|
371685
|
+
if (instance.pid !== void 0) dbState.pid = instance.pid;
|
|
371686
|
+
if (instance.detached) dbState.detached = true;
|
|
371433
371687
|
await stateManager.registerDatabase(instance.name, dbState);
|
|
371434
371688
|
}
|
|
371435
371689
|
}
|
|
@@ -371478,6 +371732,13 @@ async function startResources(options2) {
|
|
|
371478
371732
|
syncUrl: electricInstance.url,
|
|
371479
371733
|
syncSecret: electricInstance.secret
|
|
371480
371734
|
});
|
|
371735
|
+
if (electricInstance.pid !== void 0) {
|
|
371736
|
+
await stateManager.registerElectric(pgName, {
|
|
371737
|
+
port: electricInstance.port,
|
|
371738
|
+
pid: electricInstance.pid,
|
|
371739
|
+
detached: electricInstance.detached
|
|
371740
|
+
});
|
|
371741
|
+
}
|
|
371481
371742
|
callbacks.onElectricReady?.(pgName, electricInstance);
|
|
371482
371743
|
log(`Electric sync for "${pgName}" ready at ${electricInstance.url}`);
|
|
371483
371744
|
}
|
|
@@ -371563,7 +371824,7 @@ var BlockPortAllocator = class _BlockPortAllocator {
|
|
|
371563
371824
|
};
|
|
371564
371825
|
function isPortAvailable(port) {
|
|
371565
371826
|
return new Promise((resolve52) => {
|
|
371566
|
-
const server =
|
|
371827
|
+
const server = net6.createServer();
|
|
371567
371828
|
server.once("error", () => resolve52(false));
|
|
371568
371829
|
server.once("listening", () => {
|
|
371569
371830
|
server.close(() => resolve52(true));
|
|
@@ -371677,7 +371938,7 @@ var TunnelClientImpl = class extends EventEmitter2 {
|
|
|
371677
371938
|
}
|
|
371678
371939
|
}
|
|
371679
371940
|
addPoolConnection() {
|
|
371680
|
-
const remote =
|
|
371941
|
+
const remote = net7.connect({ host: this.tunnelHost, port: this.info.port });
|
|
371681
371942
|
remote.setKeepAlive(true, 3e4);
|
|
371682
371943
|
this.pool.add(remote);
|
|
371683
371944
|
remote.once("data", (firstChunk) => {
|
|
@@ -371692,7 +371953,7 @@ var TunnelClientImpl = class extends EventEmitter2 {
|
|
|
371692
371953
|
remote.on("close", () => this.onIdleClose(remote, errored));
|
|
371693
371954
|
}
|
|
371694
371955
|
pipeToLocal(remote, firstChunk) {
|
|
371695
|
-
const local =
|
|
371956
|
+
const local = net7.connect({ host: "127.0.0.1", port: this.localPort }, () => {
|
|
371696
371957
|
local.write(firstChunk);
|
|
371697
371958
|
remote.pipe(local);
|
|
371698
371959
|
local.pipe(remote);
|
|
@@ -371946,21 +372207,33 @@ var DevEnvironment = class extends TypedEventEmitter {
|
|
|
371946
372207
|
for (const electric of this.electricInstances) {
|
|
371947
372208
|
if (electric.pid) {
|
|
371948
372209
|
try {
|
|
371949
|
-
|
|
372210
|
+
if (electric.detached) {
|
|
372211
|
+
process.kill(-electric.pid, "SIGKILL");
|
|
372212
|
+
} else {
|
|
372213
|
+
process.kill(electric.pid, "SIGKILL");
|
|
372214
|
+
}
|
|
371950
372215
|
} catch {
|
|
371951
372216
|
}
|
|
371952
372217
|
}
|
|
371953
372218
|
}
|
|
371954
372219
|
if (this.drizzleGateway?.pid) {
|
|
371955
372220
|
try {
|
|
371956
|
-
|
|
372221
|
+
if (this.drizzleGateway.detached) {
|
|
372222
|
+
process.kill(-this.drizzleGateway.pid, "SIGKILL");
|
|
372223
|
+
} else {
|
|
372224
|
+
process.kill(this.drizzleGateway.pid, "SIGKILL");
|
|
372225
|
+
}
|
|
371957
372226
|
} catch {
|
|
371958
372227
|
}
|
|
371959
372228
|
}
|
|
371960
372229
|
for (const resource of this.resources.values()) {
|
|
371961
372230
|
if (resource.pid) {
|
|
371962
372231
|
try {
|
|
371963
|
-
|
|
372232
|
+
if (resource.detached) {
|
|
372233
|
+
process.kill(-resource.pid, "SIGKILL");
|
|
372234
|
+
} else {
|
|
372235
|
+
process.kill(resource.pid, "SIGKILL");
|
|
372236
|
+
}
|
|
371964
372237
|
} catch {
|
|
371965
372238
|
}
|
|
371966
372239
|
}
|
|
@@ -372114,21 +372387,33 @@ var DevEnvironment = class extends TypedEventEmitter {
|
|
|
372114
372387
|
for (const electric of this.electricInstances) {
|
|
372115
372388
|
if (electric.pid) {
|
|
372116
372389
|
try {
|
|
372117
|
-
|
|
372390
|
+
if (electric.detached) {
|
|
372391
|
+
process.kill(-electric.pid, "SIGKILL");
|
|
372392
|
+
} else {
|
|
372393
|
+
process.kill(electric.pid, "SIGKILL");
|
|
372394
|
+
}
|
|
372118
372395
|
} catch {
|
|
372119
372396
|
}
|
|
372120
372397
|
}
|
|
372121
372398
|
}
|
|
372122
372399
|
if (this.drizzleGateway?.pid) {
|
|
372123
372400
|
try {
|
|
372124
|
-
|
|
372401
|
+
if (this.drizzleGateway.detached) {
|
|
372402
|
+
process.kill(-this.drizzleGateway.pid, "SIGKILL");
|
|
372403
|
+
} else {
|
|
372404
|
+
process.kill(this.drizzleGateway.pid, "SIGKILL");
|
|
372405
|
+
}
|
|
372125
372406
|
} catch {
|
|
372126
372407
|
}
|
|
372127
372408
|
}
|
|
372128
372409
|
for (const resource of this.resources.values()) {
|
|
372129
372410
|
if (resource.pid) {
|
|
372130
372411
|
try {
|
|
372131
|
-
|
|
372412
|
+
if (resource.detached) {
|
|
372413
|
+
process.kill(-resource.pid, "SIGKILL");
|
|
372414
|
+
} else {
|
|
372415
|
+
process.kill(resource.pid, "SIGKILL");
|
|
372416
|
+
}
|
|
372132
372417
|
} catch {
|
|
372133
372418
|
}
|
|
372134
372419
|
}
|
|
@@ -372342,6 +372627,13 @@ var DevEnvironment = class extends TypedEventEmitter {
|
|
|
372342
372627
|
);
|
|
372343
372628
|
this.drizzleGateway = drizzleGateway;
|
|
372344
372629
|
this.systemLog(`Database viewer ready at ${drizzleGateway.url}`);
|
|
372630
|
+
if (drizzleGateway.pid !== void 0) {
|
|
372631
|
+
await stateManager.registerDrizzleGateway({
|
|
372632
|
+
port: drizzleGateway.port,
|
|
372633
|
+
pid: drizzleGateway.pid,
|
|
372634
|
+
detached: drizzleGateway.detached
|
|
372635
|
+
});
|
|
372636
|
+
}
|
|
372345
372637
|
} catch (err) {
|
|
372346
372638
|
this.systemLog(
|
|
372347
372639
|
`Failed to start database viewer: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -373383,7 +373675,7 @@ function trackEvent(event, properties) {
|
|
|
373383
373675
|
event,
|
|
373384
373676
|
properties: {
|
|
373385
373677
|
...properties,
|
|
373386
|
-
cli_version: "0.1.
|
|
373678
|
+
cli_version: "0.1.127",
|
|
373387
373679
|
platform: process.platform,
|
|
373388
373680
|
node_version: process.version,
|
|
373389
373681
|
project_id: getProjectId()
|
|
@@ -373701,7 +373993,7 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
|
|
|
373701
373993
|
}
|
|
373702
373994
|
|
|
373703
373995
|
// src/commands/docs.tsx
|
|
373704
|
-
import { readFileSync as
|
|
373996
|
+
import { readFileSync as readFileSync10, existsSync as existsSync17 } from "fs";
|
|
373705
373997
|
import { spawn as spawn6 } from "child_process";
|
|
373706
373998
|
import { join as join19, dirname as dirname8 } from "path";
|
|
373707
373999
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -373715,7 +374007,7 @@ var BETA_REGISTRY = [
|
|
|
373715
374007
|
];
|
|
373716
374008
|
|
|
373717
374009
|
// src/lib/beta/storage.ts
|
|
373718
|
-
import { readFileSync as
|
|
374010
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
|
|
373719
374011
|
import { join as join18 } from "path";
|
|
373720
374012
|
var BETAS_FILE = ".specific/betas.json";
|
|
373721
374013
|
function loadEnabledBetas(projectDir = process.cwd()) {
|
|
@@ -373724,7 +374016,7 @@ function loadEnabledBetas(projectDir = process.cwd()) {
|
|
|
373724
374016
|
return [];
|
|
373725
374017
|
}
|
|
373726
374018
|
try {
|
|
373727
|
-
const content =
|
|
374019
|
+
const content = readFileSync9(filePath, "utf-8");
|
|
373728
374020
|
const data = JSON.parse(content);
|
|
373729
374021
|
return data.enabled ?? [];
|
|
373730
374022
|
} catch {
|
|
@@ -373829,15 +374121,15 @@ function resolveEmbeddedDoc(path27) {
|
|
|
373829
374121
|
function resolveFilesystemDoc(path27) {
|
|
373830
374122
|
if (!path27) {
|
|
373831
374123
|
const indexPath2 = join19(docsDir, "index.md");
|
|
373832
|
-
return existsSync17(indexPath2) ?
|
|
374124
|
+
return existsSync17(indexPath2) ? readFileSync10(indexPath2, "utf-8") : null;
|
|
373833
374125
|
}
|
|
373834
374126
|
const directPath = join19(docsDir, `${path27}.md`);
|
|
373835
374127
|
if (existsSync17(directPath)) {
|
|
373836
|
-
return
|
|
374128
|
+
return readFileSync10(directPath, "utf-8");
|
|
373837
374129
|
}
|
|
373838
374130
|
const indexPath = join19(docsDir, path27, "index.md");
|
|
373839
374131
|
if (existsSync17(indexPath)) {
|
|
373840
|
-
return
|
|
374132
|
+
return readFileSync10(indexPath, "utf-8");
|
|
373841
374133
|
}
|
|
373842
374134
|
return null;
|
|
373843
374135
|
}
|
|
@@ -374921,11 +375213,13 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374921
375213
|
};
|
|
374922
375214
|
process.on("SIGINT", handleSignal);
|
|
374923
375215
|
process.on("SIGTERM", handleSignal);
|
|
375216
|
+
process.on("SIGHUP", handleSignal);
|
|
374924
375217
|
process.on("uncaughtException", handleCrash);
|
|
374925
375218
|
process.on("unhandledRejection", handleCrash);
|
|
374926
375219
|
return () => {
|
|
374927
375220
|
process.off("SIGINT", handleSignal);
|
|
374928
375221
|
process.off("SIGTERM", handleSignal);
|
|
375222
|
+
process.off("SIGHUP", handleSignal);
|
|
374929
375223
|
process.off("uncaughtException", handleCrash);
|
|
374930
375224
|
process.off("unhandledRejection", handleCrash);
|
|
374931
375225
|
};
|
|
@@ -377487,7 +377781,7 @@ function compareVersions(a, b) {
|
|
|
377487
377781
|
return 0;
|
|
377488
377782
|
}
|
|
377489
377783
|
async function checkForUpdate() {
|
|
377490
|
-
const currentVersion = "0.1.
|
|
377784
|
+
const currentVersion = "0.1.127";
|
|
377491
377785
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
377492
377786
|
if (!response.ok) {
|
|
377493
377787
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -377757,7 +378051,7 @@ async function projectListCommand() {
|
|
|
377757
378051
|
var program = new Command();
|
|
377758
378052
|
var env = "production";
|
|
377759
378053
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
377760
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
378054
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.127").enablePositionalOptions();
|
|
377761
378055
|
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
|
|
377762
378056
|
Examples:
|
|
377763
378057
|
$ specific init
|