@specific.dev/cli 0.1.126 → 0.1.128
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 +424 -91
- package/package.json +4 -4
- /package/dist/admin/_next/static/{xkQQHpz09QHzHXw5WkFYT → RI2b-FbUxlHXeowkJKNZM}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{xkQQHpz09QHzHXw5WkFYT → RI2b-FbUxlHXeowkJKNZM}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{xkQQHpz09QHzHXw5WkFYT → RI2b-FbUxlHXeowkJKNZM}/_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,41 +371938,80 @@ 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);
|
|
371944
|
+
let active = false;
|
|
371945
|
+
let errored = false;
|
|
371683
371946
|
remote.once("data", (firstChunk) => {
|
|
371684
371947
|
this.pool.delete(remote);
|
|
371948
|
+
active = true;
|
|
371685
371949
|
this.pipeToLocal(remote, firstChunk);
|
|
371686
371950
|
});
|
|
371687
|
-
let errored = false;
|
|
371688
371951
|
remote.on("error", (err) => {
|
|
371689
371952
|
errored = true;
|
|
371690
371953
|
this.emit("error", err);
|
|
371691
371954
|
});
|
|
371692
|
-
remote.on("close", () =>
|
|
371955
|
+
remote.on("close", () => {
|
|
371956
|
+
if (this.closed)
|
|
371957
|
+
return;
|
|
371958
|
+
if (active) {
|
|
371959
|
+
this.fillPool();
|
|
371960
|
+
return;
|
|
371961
|
+
}
|
|
371962
|
+
this.pool.delete(remote);
|
|
371963
|
+
if (errored && this.pool.size === 0) {
|
|
371964
|
+
this.reconnect();
|
|
371965
|
+
} else {
|
|
371966
|
+
this.fillPool();
|
|
371967
|
+
}
|
|
371968
|
+
});
|
|
371693
371969
|
}
|
|
371694
371970
|
pipeToLocal(remote, firstChunk) {
|
|
371695
|
-
|
|
371696
|
-
|
|
371971
|
+
let buffered = firstChunk;
|
|
371972
|
+
const HEADER_END = Buffer.from("\r\n\r\n");
|
|
371973
|
+
const MAX_HEADER_BYTES = 64 * 1024;
|
|
371974
|
+
const flush = (end) => {
|
|
371975
|
+
const headers = buffered.subarray(0, end + HEADER_END.length);
|
|
371976
|
+
const body = buffered.subarray(end + HEADER_END.length);
|
|
371977
|
+
const rewritten = this.rewriteDevOriginHeaders(headers);
|
|
371978
|
+
const request2 = body.length > 0 ? Buffer.concat([rewritten, body]) : rewritten;
|
|
371979
|
+
this.openLocal(remote, request2);
|
|
371980
|
+
};
|
|
371981
|
+
const initial = buffered.indexOf(HEADER_END);
|
|
371982
|
+
if (initial !== -1) {
|
|
371983
|
+
flush(initial);
|
|
371984
|
+
return;
|
|
371985
|
+
}
|
|
371986
|
+
const onData = (chunk) => {
|
|
371987
|
+
buffered = Buffer.concat([buffered, chunk]);
|
|
371988
|
+
const end = buffered.indexOf(HEADER_END);
|
|
371989
|
+
if (end !== -1) {
|
|
371990
|
+
remote.off("data", onData);
|
|
371991
|
+
flush(end);
|
|
371992
|
+
} else if (buffered.length > MAX_HEADER_BYTES) {
|
|
371993
|
+
remote.off("data", onData);
|
|
371994
|
+
remote.destroy();
|
|
371995
|
+
}
|
|
371996
|
+
};
|
|
371997
|
+
remote.on("data", onData);
|
|
371998
|
+
}
|
|
371999
|
+
openLocal(remote, request2) {
|
|
372000
|
+
const local = net7.connect({ host: "127.0.0.1", port: this.localPort }, () => {
|
|
372001
|
+
local.write(request2);
|
|
371697
372002
|
remote.pipe(local);
|
|
371698
372003
|
local.pipe(remote);
|
|
371699
372004
|
});
|
|
371700
372005
|
local.on("error", () => remote.destroy());
|
|
371701
|
-
remote.on("close", () => {
|
|
371702
|
-
if (!this.closed)
|
|
371703
|
-
this.fillPool();
|
|
371704
|
-
});
|
|
371705
372006
|
}
|
|
371706
|
-
|
|
371707
|
-
|
|
371708
|
-
|
|
371709
|
-
|
|
371710
|
-
|
|
371711
|
-
|
|
371712
|
-
|
|
371713
|
-
|
|
371714
|
-
}
|
|
372007
|
+
rewriteDevOriginHeaders(headers) {
|
|
372008
|
+
const target = `localhost:${this.localPort}`;
|
|
372009
|
+
const text = headers.toString("latin1");
|
|
372010
|
+
let out = text.replace(/^Host:[^\r\n]*\r\n/im, `Host: ${target}\r
|
|
372011
|
+
`);
|
|
372012
|
+
out = out.replace(/^Origin:[^\r\n]*\r\n/im, `Origin: http://${target}\r
|
|
372013
|
+
`);
|
|
372014
|
+
return Buffer.from(out, "latin1");
|
|
371715
372015
|
}
|
|
371716
372016
|
async reconnect() {
|
|
371717
372017
|
this.emit("close");
|
|
@@ -371946,21 +372246,33 @@ var DevEnvironment = class extends TypedEventEmitter {
|
|
|
371946
372246
|
for (const electric of this.electricInstances) {
|
|
371947
372247
|
if (electric.pid) {
|
|
371948
372248
|
try {
|
|
371949
|
-
|
|
372249
|
+
if (electric.detached) {
|
|
372250
|
+
process.kill(-electric.pid, "SIGKILL");
|
|
372251
|
+
} else {
|
|
372252
|
+
process.kill(electric.pid, "SIGKILL");
|
|
372253
|
+
}
|
|
371950
372254
|
} catch {
|
|
371951
372255
|
}
|
|
371952
372256
|
}
|
|
371953
372257
|
}
|
|
371954
372258
|
if (this.drizzleGateway?.pid) {
|
|
371955
372259
|
try {
|
|
371956
|
-
|
|
372260
|
+
if (this.drizzleGateway.detached) {
|
|
372261
|
+
process.kill(-this.drizzleGateway.pid, "SIGKILL");
|
|
372262
|
+
} else {
|
|
372263
|
+
process.kill(this.drizzleGateway.pid, "SIGKILL");
|
|
372264
|
+
}
|
|
371957
372265
|
} catch {
|
|
371958
372266
|
}
|
|
371959
372267
|
}
|
|
371960
372268
|
for (const resource of this.resources.values()) {
|
|
371961
372269
|
if (resource.pid) {
|
|
371962
372270
|
try {
|
|
371963
|
-
|
|
372271
|
+
if (resource.detached) {
|
|
372272
|
+
process.kill(-resource.pid, "SIGKILL");
|
|
372273
|
+
} else {
|
|
372274
|
+
process.kill(resource.pid, "SIGKILL");
|
|
372275
|
+
}
|
|
371964
372276
|
} catch {
|
|
371965
372277
|
}
|
|
371966
372278
|
}
|
|
@@ -372114,21 +372426,33 @@ var DevEnvironment = class extends TypedEventEmitter {
|
|
|
372114
372426
|
for (const electric of this.electricInstances) {
|
|
372115
372427
|
if (electric.pid) {
|
|
372116
372428
|
try {
|
|
372117
|
-
|
|
372429
|
+
if (electric.detached) {
|
|
372430
|
+
process.kill(-electric.pid, "SIGKILL");
|
|
372431
|
+
} else {
|
|
372432
|
+
process.kill(electric.pid, "SIGKILL");
|
|
372433
|
+
}
|
|
372118
372434
|
} catch {
|
|
372119
372435
|
}
|
|
372120
372436
|
}
|
|
372121
372437
|
}
|
|
372122
372438
|
if (this.drizzleGateway?.pid) {
|
|
372123
372439
|
try {
|
|
372124
|
-
|
|
372440
|
+
if (this.drizzleGateway.detached) {
|
|
372441
|
+
process.kill(-this.drizzleGateway.pid, "SIGKILL");
|
|
372442
|
+
} else {
|
|
372443
|
+
process.kill(this.drizzleGateway.pid, "SIGKILL");
|
|
372444
|
+
}
|
|
372125
372445
|
} catch {
|
|
372126
372446
|
}
|
|
372127
372447
|
}
|
|
372128
372448
|
for (const resource of this.resources.values()) {
|
|
372129
372449
|
if (resource.pid) {
|
|
372130
372450
|
try {
|
|
372131
|
-
|
|
372451
|
+
if (resource.detached) {
|
|
372452
|
+
process.kill(-resource.pid, "SIGKILL");
|
|
372453
|
+
} else {
|
|
372454
|
+
process.kill(resource.pid, "SIGKILL");
|
|
372455
|
+
}
|
|
372132
372456
|
} catch {
|
|
372133
372457
|
}
|
|
372134
372458
|
}
|
|
@@ -372342,6 +372666,13 @@ var DevEnvironment = class extends TypedEventEmitter {
|
|
|
372342
372666
|
);
|
|
372343
372667
|
this.drizzleGateway = drizzleGateway;
|
|
372344
372668
|
this.systemLog(`Database viewer ready at ${drizzleGateway.url}`);
|
|
372669
|
+
if (drizzleGateway.pid !== void 0) {
|
|
372670
|
+
await stateManager.registerDrizzleGateway({
|
|
372671
|
+
port: drizzleGateway.port,
|
|
372672
|
+
pid: drizzleGateway.pid,
|
|
372673
|
+
detached: drizzleGateway.detached
|
|
372674
|
+
});
|
|
372675
|
+
}
|
|
372345
372676
|
} catch (err) {
|
|
372346
372677
|
this.systemLog(
|
|
372347
372678
|
`Failed to start database viewer: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -373383,7 +373714,7 @@ function trackEvent(event, properties) {
|
|
|
373383
373714
|
event,
|
|
373384
373715
|
properties: {
|
|
373385
373716
|
...properties,
|
|
373386
|
-
cli_version: "0.1.
|
|
373717
|
+
cli_version: "0.1.128",
|
|
373387
373718
|
platform: process.platform,
|
|
373388
373719
|
node_version: process.version,
|
|
373389
373720
|
project_id: getProjectId()
|
|
@@ -373701,7 +374032,7 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
|
|
|
373701
374032
|
}
|
|
373702
374033
|
|
|
373703
374034
|
// src/commands/docs.tsx
|
|
373704
|
-
import { readFileSync as
|
|
374035
|
+
import { readFileSync as readFileSync10, existsSync as existsSync17 } from "fs";
|
|
373705
374036
|
import { spawn as spawn6 } from "child_process";
|
|
373706
374037
|
import { join as join19, dirname as dirname8 } from "path";
|
|
373707
374038
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -373715,7 +374046,7 @@ var BETA_REGISTRY = [
|
|
|
373715
374046
|
];
|
|
373716
374047
|
|
|
373717
374048
|
// src/lib/beta/storage.ts
|
|
373718
|
-
import { readFileSync as
|
|
374049
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
|
|
373719
374050
|
import { join as join18 } from "path";
|
|
373720
374051
|
var BETAS_FILE = ".specific/betas.json";
|
|
373721
374052
|
function loadEnabledBetas(projectDir = process.cwd()) {
|
|
@@ -373724,7 +374055,7 @@ function loadEnabledBetas(projectDir = process.cwd()) {
|
|
|
373724
374055
|
return [];
|
|
373725
374056
|
}
|
|
373726
374057
|
try {
|
|
373727
|
-
const content =
|
|
374058
|
+
const content = readFileSync9(filePath, "utf-8");
|
|
373728
374059
|
const data = JSON.parse(content);
|
|
373729
374060
|
return data.enabled ?? [];
|
|
373730
374061
|
} catch {
|
|
@@ -373829,15 +374160,15 @@ function resolveEmbeddedDoc(path27) {
|
|
|
373829
374160
|
function resolveFilesystemDoc(path27) {
|
|
373830
374161
|
if (!path27) {
|
|
373831
374162
|
const indexPath2 = join19(docsDir, "index.md");
|
|
373832
|
-
return existsSync17(indexPath2) ?
|
|
374163
|
+
return existsSync17(indexPath2) ? readFileSync10(indexPath2, "utf-8") : null;
|
|
373833
374164
|
}
|
|
373834
374165
|
const directPath = join19(docsDir, `${path27}.md`);
|
|
373835
374166
|
if (existsSync17(directPath)) {
|
|
373836
|
-
return
|
|
374167
|
+
return readFileSync10(directPath, "utf-8");
|
|
373837
374168
|
}
|
|
373838
374169
|
const indexPath = join19(docsDir, path27, "index.md");
|
|
373839
374170
|
if (existsSync17(indexPath)) {
|
|
373840
|
-
return
|
|
374171
|
+
return readFileSync10(indexPath, "utf-8");
|
|
373841
374172
|
}
|
|
373842
374173
|
return null;
|
|
373843
374174
|
}
|
|
@@ -374921,11 +375252,13 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374921
375252
|
};
|
|
374922
375253
|
process.on("SIGINT", handleSignal);
|
|
374923
375254
|
process.on("SIGTERM", handleSignal);
|
|
375255
|
+
process.on("SIGHUP", handleSignal);
|
|
374924
375256
|
process.on("uncaughtException", handleCrash);
|
|
374925
375257
|
process.on("unhandledRejection", handleCrash);
|
|
374926
375258
|
return () => {
|
|
374927
375259
|
process.off("SIGINT", handleSignal);
|
|
374928
375260
|
process.off("SIGTERM", handleSignal);
|
|
375261
|
+
process.off("SIGHUP", handleSignal);
|
|
374929
375262
|
process.off("uncaughtException", handleCrash);
|
|
374930
375263
|
process.off("unhandledRejection", handleCrash);
|
|
374931
375264
|
};
|
|
@@ -377487,7 +377820,7 @@ function compareVersions(a, b) {
|
|
|
377487
377820
|
return 0;
|
|
377488
377821
|
}
|
|
377489
377822
|
async function checkForUpdate() {
|
|
377490
|
-
const currentVersion = "0.1.
|
|
377823
|
+
const currentVersion = "0.1.128";
|
|
377491
377824
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
377492
377825
|
if (!response.ok) {
|
|
377493
377826
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -377757,7 +378090,7 @@ async function projectListCommand() {
|
|
|
377757
378090
|
var program = new Command();
|
|
377758
378091
|
var env = "production";
|
|
377759
378092
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
377760
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
378093
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.128").enablePositionalOptions();
|
|
377761
378094
|
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
378095
|
Examples:
|
|
377763
378096
|
$ specific init
|