@specific.dev/cli 0.1.60 → 0.1.62
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/cli.js +789 -652
- package/dist/postinstall.js +1 -1
- package/package.json +2 -1
- /package/dist/admin/_next/static/{tZ6oW5Gt46x7GjGGbdB6L → bSt01e539un5ZT_sTTRm7}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{tZ6oW5Gt46x7GjGGbdB6L → bSt01e539un5ZT_sTTRm7}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{tZ6oW5Gt46x7GjGGbdB6L → bSt01e539un5ZT_sTTRm7}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -39,10 +39,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
));
|
|
40
40
|
|
|
41
41
|
// node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
|
|
42
|
-
import
|
|
42
|
+
import fs5 from "node:fs";
|
|
43
43
|
function hasDockerEnv() {
|
|
44
44
|
try {
|
|
45
|
-
|
|
45
|
+
fs5.statSync("/.dockerenv");
|
|
46
46
|
return true;
|
|
47
47
|
} catch {
|
|
48
48
|
return false;
|
|
@@ -50,7 +50,7 @@ function hasDockerEnv() {
|
|
|
50
50
|
}
|
|
51
51
|
function hasDockerCGroup() {
|
|
52
52
|
try {
|
|
53
|
-
return
|
|
53
|
+
return fs5.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
54
54
|
} catch {
|
|
55
55
|
return false;
|
|
56
56
|
}
|
|
@@ -68,7 +68,7 @@ var init_is_docker = __esm({
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
// node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
|
|
71
|
-
import
|
|
71
|
+
import fs6 from "node:fs";
|
|
72
72
|
function isInsideContainer() {
|
|
73
73
|
if (cachedResult === void 0) {
|
|
74
74
|
cachedResult = hasContainerEnv() || isDocker();
|
|
@@ -81,7 +81,7 @@ var init_is_inside_container = __esm({
|
|
|
81
81
|
init_is_docker();
|
|
82
82
|
hasContainerEnv = () => {
|
|
83
83
|
try {
|
|
84
|
-
|
|
84
|
+
fs6.statSync("/run/.containerenv");
|
|
85
85
|
return true;
|
|
86
86
|
} catch {
|
|
87
87
|
return false;
|
|
@@ -92,8 +92,8 @@ var init_is_inside_container = __esm({
|
|
|
92
92
|
|
|
93
93
|
// node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
|
|
94
94
|
import process2 from "node:process";
|
|
95
|
-
import
|
|
96
|
-
import
|
|
95
|
+
import os4 from "node:os";
|
|
96
|
+
import fs7 from "node:fs";
|
|
97
97
|
var isWsl, is_wsl_default;
|
|
98
98
|
var init_is_wsl = __esm({
|
|
99
99
|
"node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js"() {
|
|
@@ -102,14 +102,14 @@ var init_is_wsl = __esm({
|
|
|
102
102
|
if (process2.platform !== "linux") {
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
105
|
-
if (
|
|
105
|
+
if (os4.release().toLowerCase().includes("microsoft")) {
|
|
106
106
|
if (isInsideContainer()) {
|
|
107
107
|
return false;
|
|
108
108
|
}
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
111
|
try {
|
|
112
|
-
return
|
|
112
|
+
return fs7.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
|
|
113
113
|
} catch {
|
|
114
114
|
return false;
|
|
115
115
|
}
|
|
@@ -179,7 +179,7 @@ var init_utilities = __esm({
|
|
|
179
179
|
// node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
|
|
180
180
|
import { promisify as promisify2 } from "node:util";
|
|
181
181
|
import childProcess2 from "node:child_process";
|
|
182
|
-
import
|
|
182
|
+
import fs8, { constants as fsConstants } from "node:fs/promises";
|
|
183
183
|
var execFile2, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
|
|
184
184
|
var init_wsl_utils = __esm({
|
|
185
185
|
"node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
|
|
@@ -198,14 +198,14 @@ var init_wsl_utils = __esm({
|
|
|
198
198
|
const configFilePath = "/etc/wsl.conf";
|
|
199
199
|
let isConfigFileExists = false;
|
|
200
200
|
try {
|
|
201
|
-
await
|
|
201
|
+
await fs8.access(configFilePath, fsConstants.F_OK);
|
|
202
202
|
isConfigFileExists = true;
|
|
203
203
|
} catch {
|
|
204
204
|
}
|
|
205
205
|
if (!isConfigFileExists) {
|
|
206
206
|
return defaultMountPoint;
|
|
207
207
|
}
|
|
208
|
-
const configContent = await
|
|
208
|
+
const configContent = await fs8.readFile(configFilePath, { encoding: "utf8" });
|
|
209
209
|
const parsedMountPoint = parseMountPointFromConfig(configContent);
|
|
210
210
|
if (parsedMountPoint === void 0) {
|
|
211
211
|
return defaultMountPoint;
|
|
@@ -224,7 +224,7 @@ var init_wsl_utils = __esm({
|
|
|
224
224
|
canAccessPowerShellPromise ??= (async () => {
|
|
225
225
|
try {
|
|
226
226
|
const psPath = await powerShellPath2();
|
|
227
|
-
await
|
|
227
|
+
await fs8.access(psPath, fsConstants.X_OK);
|
|
228
228
|
return true;
|
|
229
229
|
} catch {
|
|
230
230
|
return false;
|
|
@@ -238,15 +238,15 @@ var init_wsl_utils = __esm({
|
|
|
238
238
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
239
239
|
return stdout.trim();
|
|
240
240
|
};
|
|
241
|
-
convertWslPathToWindows = async (
|
|
242
|
-
if (/^[a-z]+:\/\//i.test(
|
|
243
|
-
return
|
|
241
|
+
convertWslPathToWindows = async (path27) => {
|
|
242
|
+
if (/^[a-z]+:\/\//i.test(path27)) {
|
|
243
|
+
return path27;
|
|
244
244
|
}
|
|
245
245
|
try {
|
|
246
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
246
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path27], { encoding: "utf8" });
|
|
247
247
|
return stdout.trim();
|
|
248
248
|
} catch {
|
|
249
|
-
return
|
|
249
|
+
return path27;
|
|
250
250
|
}
|
|
251
251
|
};
|
|
252
252
|
}
|
|
@@ -432,10 +432,10 @@ __export(open_exports, {
|
|
|
432
432
|
openApp: () => openApp
|
|
433
433
|
});
|
|
434
434
|
import process8 from "node:process";
|
|
435
|
-
import
|
|
435
|
+
import path5 from "node:path";
|
|
436
436
|
import { fileURLToPath } from "node:url";
|
|
437
437
|
import childProcess3 from "node:child_process";
|
|
438
|
-
import
|
|
438
|
+
import fs9, { constants as fsConstants2 } from "node:fs/promises";
|
|
439
439
|
function detectArchBinary(binary) {
|
|
440
440
|
if (typeof binary === "string" || Array.isArray(binary)) {
|
|
441
441
|
return binary;
|
|
@@ -446,16 +446,16 @@ function detectArchBinary(binary) {
|
|
|
446
446
|
}
|
|
447
447
|
return archBinary;
|
|
448
448
|
}
|
|
449
|
-
function detectPlatformBinary({ [
|
|
449
|
+
function detectPlatformBinary({ [platform3]: platformBinary }, { wsl } = {}) {
|
|
450
450
|
if (wsl && is_wsl_default) {
|
|
451
451
|
return detectArchBinary(wsl);
|
|
452
452
|
}
|
|
453
453
|
if (!platformBinary) {
|
|
454
|
-
throw new Error(`${
|
|
454
|
+
throw new Error(`${platform3} is not supported`);
|
|
455
455
|
}
|
|
456
456
|
return detectArchBinary(platformBinary);
|
|
457
457
|
}
|
|
458
|
-
var fallbackAttemptSymbol, __dirname, localXdgOpenPath,
|
|
458
|
+
var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform3, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
|
|
459
459
|
var init_open = __esm({
|
|
460
460
|
"node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
|
|
461
461
|
init_wsl_utils();
|
|
@@ -465,9 +465,9 @@ var init_open = __esm({
|
|
|
465
465
|
init_is_inside_container();
|
|
466
466
|
init_is_in_ssh();
|
|
467
467
|
fallbackAttemptSymbol = Symbol("fallbackAttempt");
|
|
468
|
-
__dirname = import.meta.url ?
|
|
469
|
-
localXdgOpenPath =
|
|
470
|
-
({ platform:
|
|
468
|
+
__dirname = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
|
|
469
|
+
localXdgOpenPath = path5.join(__dirname, "xdg-open");
|
|
470
|
+
({ platform: platform3, arch } = process8);
|
|
471
471
|
tryEachApp = async (apps2, opener) => {
|
|
472
472
|
if (apps2.length === 0) {
|
|
473
473
|
return;
|
|
@@ -564,7 +564,7 @@ var init_open = __esm({
|
|
|
564
564
|
if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
|
|
565
565
|
shouldUseWindowsInWsl = await canAccessPowerShell();
|
|
566
566
|
}
|
|
567
|
-
if (
|
|
567
|
+
if (platform3 === "darwin") {
|
|
568
568
|
command = "open";
|
|
569
569
|
if (options2.wait) {
|
|
570
570
|
cliArguments.push("--wait-apps");
|
|
@@ -578,7 +578,7 @@ var init_open = __esm({
|
|
|
578
578
|
if (app) {
|
|
579
579
|
cliArguments.push("-a", app);
|
|
580
580
|
}
|
|
581
|
-
} else if (
|
|
581
|
+
} else if (platform3 === "win32" || shouldUseWindowsInWsl) {
|
|
582
582
|
command = await powerShellPath2();
|
|
583
583
|
cliArguments.push(...executePowerShell.argumentsPrefix);
|
|
584
584
|
if (!is_wsl_default) {
|
|
@@ -614,11 +614,11 @@ var init_open = __esm({
|
|
|
614
614
|
const isBundled = !__dirname || __dirname === "/";
|
|
615
615
|
let exeLocalXdgOpen = false;
|
|
616
616
|
try {
|
|
617
|
-
await
|
|
617
|
+
await fs9.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
618
618
|
exeLocalXdgOpen = true;
|
|
619
619
|
} catch {
|
|
620
620
|
}
|
|
621
|
-
const useSystemXdgOpen = process8.versions.electron ?? (
|
|
621
|
+
const useSystemXdgOpen = process8.versions.electron ?? (platform3 === "android" || isBundled || !exeLocalXdgOpen);
|
|
622
622
|
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
623
623
|
}
|
|
624
624
|
if (appArguments.length > 0) {
|
|
@@ -629,7 +629,7 @@ var init_open = __esm({
|
|
|
629
629
|
childProcessOptions.detached = true;
|
|
630
630
|
}
|
|
631
631
|
}
|
|
632
|
-
if (
|
|
632
|
+
if (platform3 === "darwin" && appArguments.length > 0) {
|
|
633
633
|
cliArguments.push("--args", ...appArguments);
|
|
634
634
|
}
|
|
635
635
|
if (options2.target) {
|
|
@@ -754,8 +754,8 @@ var require_dist = __commonJS({
|
|
|
754
754
|
var $global, $module, $NaN = NaN;
|
|
755
755
|
if ("undefined" != typeof window ? $global = window : "undefined" != typeof self ? $global = self : "undefined" != typeof global ? ($global = global).require = __require : $global = this, void 0 === $global || void 0 === $global.Array) throw new Error("no global object found");
|
|
756
756
|
if ("undefined" != typeof module && ($module = module), !$global.fs && $global.require) try {
|
|
757
|
-
var
|
|
758
|
-
"object" == typeof
|
|
757
|
+
var fs29 = $global.require("fs");
|
|
758
|
+
"object" == typeof fs29 && null !== fs29 && 0 !== Object.keys(fs29).length && ($global.fs = fs29);
|
|
759
759
|
} catch (e) {
|
|
760
760
|
}
|
|
761
761
|
if (!$global.fs) {
|
|
@@ -182949,8 +182949,11 @@ import { Command } from "commander";
|
|
|
182949
182949
|
import React2, { useState, useEffect } from "react";
|
|
182950
182950
|
import { render as render2, Text as Text2, Box as Box2, useInput, useApp } from "ink";
|
|
182951
182951
|
import "ink-spinner";
|
|
182952
|
-
import * as
|
|
182953
|
-
import * as
|
|
182952
|
+
import * as fs11 from "fs";
|
|
182953
|
+
import * as path7 from "path";
|
|
182954
|
+
|
|
182955
|
+
// src/lib/dev/system-setup.ts
|
|
182956
|
+
import { execSync as execSync2 } from "child_process";
|
|
182954
182957
|
|
|
182955
182958
|
// src/lib/dev/local-ca.ts
|
|
182956
182959
|
import * as fs from "fs";
|
|
@@ -182965,6 +182968,38 @@ function caFilesExist() {
|
|
|
182965
182968
|
const caDir = getCADir();
|
|
182966
182969
|
return fs.existsSync(path.join(caDir, "ca.key")) && fs.existsSync(path.join(caDir, "ca.crt"));
|
|
182967
182970
|
}
|
|
182971
|
+
function caInstalledInTrustStore() {
|
|
182972
|
+
if (!caFilesExist()) {
|
|
182973
|
+
return false;
|
|
182974
|
+
}
|
|
182975
|
+
const platform5 = os.platform();
|
|
182976
|
+
const certPath = path.join(getCADir(), "ca.crt");
|
|
182977
|
+
const diskCert = fs.readFileSync(certPath, "utf-8").replace(/\r\n/g, "\n").trim();
|
|
182978
|
+
try {
|
|
182979
|
+
if (platform5 === "darwin") {
|
|
182980
|
+
const keychainCert = execSync(
|
|
182981
|
+
'security find-certificate -c "Specific Local Development CA" -p /Library/Keychains/System.keychain',
|
|
182982
|
+
{ encoding: "utf-8" }
|
|
182983
|
+
).replace(/\r\n/g, "\n").trim();
|
|
182984
|
+
return keychainCert === diskCert;
|
|
182985
|
+
} else if (platform5 === "linux") {
|
|
182986
|
+
const trustPaths = [
|
|
182987
|
+
"/usr/local/share/ca-certificates/specific-local-ca.crt",
|
|
182988
|
+
"/etc/pki/ca-trust/source/anchors/specific-local-ca.crt"
|
|
182989
|
+
];
|
|
182990
|
+
for (const trustPath of trustPaths) {
|
|
182991
|
+
if (fs.existsSync(trustPath)) {
|
|
182992
|
+
const trustedCert = fs.readFileSync(trustPath, "utf-8").replace(/\r\n/g, "\n").trim();
|
|
182993
|
+
return trustedCert === diskCert;
|
|
182994
|
+
}
|
|
182995
|
+
}
|
|
182996
|
+
return false;
|
|
182997
|
+
}
|
|
182998
|
+
} catch {
|
|
182999
|
+
return false;
|
|
183000
|
+
}
|
|
183001
|
+
return false;
|
|
183002
|
+
}
|
|
182968
183003
|
function createNameConstraintsExtension(permittedDNSNames) {
|
|
182969
183004
|
const nameConstraintsOID = "2.5.29.30";
|
|
182970
183005
|
const permittedSubtrees = permittedDNSNames.map((dnsName) => {
|
|
@@ -183054,32 +183089,30 @@ function removeCA() {
|
|
|
183054
183089
|
fs.unlinkSync(certPath);
|
|
183055
183090
|
}
|
|
183056
183091
|
}
|
|
183057
|
-
function
|
|
183058
|
-
const
|
|
183059
|
-
if (
|
|
183060
|
-
|
|
183061
|
-
|
|
183062
|
-
|
|
183063
|
-
|
|
183064
|
-
|
|
183092
|
+
function getCAInstallCommands(certPath) {
|
|
183093
|
+
const platform5 = os.platform();
|
|
183094
|
+
if (platform5 === "darwin") {
|
|
183095
|
+
return [
|
|
183096
|
+
// Remove any existing cert with the same CN first — add-trusted-cert
|
|
183097
|
+
// silently does nothing if a cert with the same subject already exists.
|
|
183098
|
+
'security delete-certificate -c "Specific Local Development CA" /Library/Keychains/System.keychain 2>/dev/null || true',
|
|
183099
|
+
`security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`
|
|
183100
|
+
];
|
|
183101
|
+
} else if (platform5 === "linux") {
|
|
183065
183102
|
if (fs.existsSync("/usr/local/share/ca-certificates")) {
|
|
183066
|
-
|
|
183067
|
-
`
|
|
183068
|
-
|
|
183069
|
-
|
|
183070
|
-
execSync("sudo update-ca-certificates", { stdio: "inherit" });
|
|
183103
|
+
return [
|
|
183104
|
+
`cp "${certPath}" /usr/local/share/ca-certificates/specific-local-ca.crt`,
|
|
183105
|
+
"update-ca-certificates"
|
|
183106
|
+
];
|
|
183071
183107
|
} else if (fs.existsSync("/etc/pki/ca-trust/source/anchors")) {
|
|
183072
|
-
|
|
183073
|
-
`
|
|
183074
|
-
|
|
183075
|
-
|
|
183076
|
-
execSync("sudo update-ca-trust extract", { stdio: "inherit" });
|
|
183077
|
-
} else {
|
|
183078
|
-
throw new Error("Could not detect Linux certificate trust mechanism");
|
|
183108
|
+
return [
|
|
183109
|
+
`cp "${certPath}" /etc/pki/ca-trust/source/anchors/specific-local-ca.crt`,
|
|
183110
|
+
"update-ca-trust extract"
|
|
183111
|
+
];
|
|
183079
183112
|
}
|
|
183080
|
-
|
|
183081
|
-
throw new Error(`Unsupported platform: ${platform4}`);
|
|
183113
|
+
throw new Error("Could not detect Linux certificate trust mechanism");
|
|
183082
183114
|
}
|
|
183115
|
+
throw new Error(`Unsupported platform: ${platform5}`);
|
|
183083
183116
|
}
|
|
183084
183117
|
function generateCertificate(domain, keys = []) {
|
|
183085
183118
|
const caDir = getCADir();
|
|
@@ -183118,14 +183151,164 @@ function generateCertificate(domain, keys = []) {
|
|
|
183118
183151
|
};
|
|
183119
183152
|
}
|
|
183120
183153
|
|
|
183154
|
+
// src/lib/dev/resolver-config.ts
|
|
183155
|
+
import * as fs2 from "fs";
|
|
183156
|
+
import * as os2 from "os";
|
|
183157
|
+
var RESOLVER_FILE_MACOS = "/etc/resolver/local.spcf.app";
|
|
183158
|
+
var RESOLVER_FILE_LINUX = "/etc/systemd/resolved.conf.d/specific-local.conf";
|
|
183159
|
+
function resolverConfigExists() {
|
|
183160
|
+
const platform5 = os2.platform();
|
|
183161
|
+
if (platform5 === "darwin") {
|
|
183162
|
+
return fs2.existsSync(RESOLVER_FILE_MACOS);
|
|
183163
|
+
} else if (platform5 === "linux") {
|
|
183164
|
+
return fs2.existsSync(RESOLVER_FILE_LINUX);
|
|
183165
|
+
}
|
|
183166
|
+
return false;
|
|
183167
|
+
}
|
|
183168
|
+
function getResolverInstallCommands(port) {
|
|
183169
|
+
const platform5 = os2.platform();
|
|
183170
|
+
if (platform5 === "darwin") {
|
|
183171
|
+
return [
|
|
183172
|
+
"mkdir -p /etc/resolver",
|
|
183173
|
+
`printf "nameserver 127.0.0.1\\nport ${port}\\n" > ${RESOLVER_FILE_MACOS}`
|
|
183174
|
+
];
|
|
183175
|
+
} else if (platform5 === "linux") {
|
|
183176
|
+
if (fs2.existsSync("/etc/systemd/resolved.conf.d") || fs2.existsSync("/etc/systemd")) {
|
|
183177
|
+
return [
|
|
183178
|
+
"mkdir -p /etc/systemd/resolved.conf.d",
|
|
183179
|
+
`printf "[Resolve]\\nDNS=127.0.0.1:${port}\\nDomains=~local.spcf.app\\n" > ${RESOLVER_FILE_LINUX}`,
|
|
183180
|
+
"systemctl restart systemd-resolved"
|
|
183181
|
+
];
|
|
183182
|
+
}
|
|
183183
|
+
return [];
|
|
183184
|
+
}
|
|
183185
|
+
return [];
|
|
183186
|
+
}
|
|
183187
|
+
|
|
183188
|
+
// src/lib/dev/dns-server.ts
|
|
183189
|
+
import DNS from "dns2";
|
|
183190
|
+
|
|
183191
|
+
// src/lib/dev/debug-logger.ts
|
|
183192
|
+
import * as fs3 from "fs";
|
|
183193
|
+
import * as os3 from "os";
|
|
183194
|
+
import * as path2 from "path";
|
|
183195
|
+
var DEBUG_LOG_PATH = ".specific/debug.log";
|
|
183196
|
+
var logStream = null;
|
|
183197
|
+
function writeLog(source, message) {
|
|
183198
|
+
const logPath = path2.join(os3.homedir(), DEBUG_LOG_PATH);
|
|
183199
|
+
fs3.mkdirSync(path2.dirname(logPath), { recursive: true });
|
|
183200
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
183201
|
+
const line = message.endsWith("\n") ? message : message + "\n";
|
|
183202
|
+
fs3.appendFileSync(logPath, `[${timestamp}] [${source}] ${line}`);
|
|
183203
|
+
}
|
|
183204
|
+
function pipeProcess(source, proc) {
|
|
183205
|
+
proc.stdout?.on("data", (data) => {
|
|
183206
|
+
const text = data.toString();
|
|
183207
|
+
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
183208
|
+
for (const line of lines) {
|
|
183209
|
+
writeLog(source, line);
|
|
183210
|
+
}
|
|
183211
|
+
});
|
|
183212
|
+
proc.stderr?.on("data", (data) => {
|
|
183213
|
+
const text = data.toString();
|
|
183214
|
+
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
183215
|
+
for (const line of lines) {
|
|
183216
|
+
writeLog(source, line);
|
|
183217
|
+
}
|
|
183218
|
+
});
|
|
183219
|
+
proc.on("error", (err) => {
|
|
183220
|
+
writeLog(`${source}:error`, err.message);
|
|
183221
|
+
});
|
|
183222
|
+
proc.on("exit", (code, signal) => {
|
|
183223
|
+
writeLog(source, `Process exited with code=${code} signal=${signal}`);
|
|
183224
|
+
});
|
|
183225
|
+
}
|
|
183226
|
+
function closeDebugLog() {
|
|
183227
|
+
if (logStream) {
|
|
183228
|
+
logStream.end();
|
|
183229
|
+
logStream = null;
|
|
183230
|
+
}
|
|
183231
|
+
}
|
|
183232
|
+
|
|
183233
|
+
// src/lib/dev/dns-server.ts
|
|
183234
|
+
var DNS_PORT = 15353;
|
|
183235
|
+
async function startDnsServer(port = DNS_PORT) {
|
|
183236
|
+
const server = DNS.createServer({
|
|
183237
|
+
udp: true,
|
|
183238
|
+
handle: (request, send) => {
|
|
183239
|
+
const response = DNS.Packet.createResponseFromRequest(request);
|
|
183240
|
+
for (const question of request.questions) {
|
|
183241
|
+
if (question.type === DNS.Packet.TYPE.A) {
|
|
183242
|
+
response.answers.push({
|
|
183243
|
+
name: question.name,
|
|
183244
|
+
type: DNS.Packet.TYPE.A,
|
|
183245
|
+
class: DNS.Packet.CLASS.IN,
|
|
183246
|
+
ttl: 300,
|
|
183247
|
+
address: "127.0.0.1"
|
|
183248
|
+
});
|
|
183249
|
+
}
|
|
183250
|
+
}
|
|
183251
|
+
send(response);
|
|
183252
|
+
}
|
|
183253
|
+
});
|
|
183254
|
+
await server.listen({
|
|
183255
|
+
udp: { port, address: "127.0.0.1" }
|
|
183256
|
+
});
|
|
183257
|
+
writeLog("dns", `DNS server started on 127.0.0.1:${port}`);
|
|
183258
|
+
return {
|
|
183259
|
+
port,
|
|
183260
|
+
async stop() {
|
|
183261
|
+
await server.close();
|
|
183262
|
+
writeLog("dns", "DNS server stopped");
|
|
183263
|
+
}
|
|
183264
|
+
};
|
|
183265
|
+
}
|
|
183266
|
+
|
|
183267
|
+
// src/lib/dev/system-setup.ts
|
|
183268
|
+
import * as path3 from "path";
|
|
183269
|
+
function systemSetupNeeded() {
|
|
183270
|
+
return !caInstalledInTrustStore() || !resolverConfigExists();
|
|
183271
|
+
}
|
|
183272
|
+
function performSystemSetup() {
|
|
183273
|
+
const needsGenerate = !caFilesExist();
|
|
183274
|
+
const needsInstallCA = !caInstalledInTrustStore();
|
|
183275
|
+
const needsResolver = !resolverConfigExists();
|
|
183276
|
+
if (!needsInstallCA && !needsResolver) {
|
|
183277
|
+
return;
|
|
183278
|
+
}
|
|
183279
|
+
if (needsGenerate) {
|
|
183280
|
+
const { key, cert } = generateRootCA();
|
|
183281
|
+
saveCA(key, cert);
|
|
183282
|
+
}
|
|
183283
|
+
const certPath = path3.join(getCADir(), "ca.crt");
|
|
183284
|
+
const commands = [];
|
|
183285
|
+
if (needsInstallCA) {
|
|
183286
|
+
commands.push(...getCAInstallCommands(certPath));
|
|
183287
|
+
}
|
|
183288
|
+
if (needsResolver) {
|
|
183289
|
+
commands.push(...getResolverInstallCommands(DNS_PORT));
|
|
183290
|
+
}
|
|
183291
|
+
if (commands.length === 0) {
|
|
183292
|
+
return;
|
|
183293
|
+
}
|
|
183294
|
+
try {
|
|
183295
|
+
execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
|
|
183296
|
+
} catch (err) {
|
|
183297
|
+
if (needsGenerate) {
|
|
183298
|
+
removeCA();
|
|
183299
|
+
}
|
|
183300
|
+
throw err;
|
|
183301
|
+
}
|
|
183302
|
+
}
|
|
183303
|
+
|
|
183121
183304
|
// src/lib/analytics/index.ts
|
|
183122
183305
|
import { PostHog } from "posthog-node";
|
|
183123
|
-
import * as
|
|
183306
|
+
import * as os6 from "os";
|
|
183124
183307
|
import * as crypto from "crypto";
|
|
183125
183308
|
|
|
183126
183309
|
// src/lib/project/config.ts
|
|
183127
|
-
import * as
|
|
183128
|
-
import * as
|
|
183310
|
+
import * as fs4 from "fs";
|
|
183311
|
+
import * as path4 from "path";
|
|
183129
183312
|
var PROJECT_ID_FILE = ".specific/project_id";
|
|
183130
183313
|
var ProjectNotLinkedError = class extends Error {
|
|
183131
183314
|
constructor() {
|
|
@@ -183140,32 +183323,32 @@ Run: specific deploy`
|
|
|
183140
183323
|
}
|
|
183141
183324
|
};
|
|
183142
183325
|
function readProjectId(projectDir = process.cwd()) {
|
|
183143
|
-
const projectIdPath =
|
|
183144
|
-
if (!
|
|
183326
|
+
const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
|
|
183327
|
+
if (!fs4.existsSync(projectIdPath)) {
|
|
183145
183328
|
throw new ProjectNotLinkedError();
|
|
183146
183329
|
}
|
|
183147
|
-
const projectId =
|
|
183330
|
+
const projectId = fs4.readFileSync(projectIdPath, "utf-8").trim();
|
|
183148
183331
|
if (!projectId) {
|
|
183149
183332
|
throw new Error(`${PROJECT_ID_FILE} is empty`);
|
|
183150
183333
|
}
|
|
183151
183334
|
return projectId;
|
|
183152
183335
|
}
|
|
183153
183336
|
function hasProjectId(projectDir = process.cwd()) {
|
|
183154
|
-
const projectIdPath =
|
|
183155
|
-
return
|
|
183337
|
+
const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
|
|
183338
|
+
return fs4.existsSync(projectIdPath);
|
|
183156
183339
|
}
|
|
183157
183340
|
function writeProjectId(projectId, projectDir = process.cwd()) {
|
|
183158
|
-
const specificDir =
|
|
183159
|
-
if (!
|
|
183160
|
-
|
|
183341
|
+
const specificDir = path4.join(projectDir, ".specific");
|
|
183342
|
+
if (!fs4.existsSync(specificDir)) {
|
|
183343
|
+
fs4.mkdirSync(specificDir, { recursive: true });
|
|
183161
183344
|
}
|
|
183162
|
-
|
|
183345
|
+
fs4.writeFileSync(path4.join(specificDir, "project_id"), projectId + "\n");
|
|
183163
183346
|
}
|
|
183164
183347
|
|
|
183165
183348
|
// src/lib/auth/credentials.ts
|
|
183166
|
-
import * as
|
|
183167
|
-
import * as
|
|
183168
|
-
import * as
|
|
183349
|
+
import * as fs10 from "fs";
|
|
183350
|
+
import * as path6 from "path";
|
|
183351
|
+
import * as os5 from "os";
|
|
183169
183352
|
|
|
183170
183353
|
// src/lib/auth/errors.ts
|
|
183171
183354
|
var RefreshTokenExpiredError = class extends Error {
|
|
@@ -183242,48 +183425,6 @@ import React from "react";
|
|
|
183242
183425
|
import { render, Box, Text } from "ink";
|
|
183243
183426
|
import Spinner from "ink-spinner";
|
|
183244
183427
|
|
|
183245
|
-
// src/lib/dev/debug-logger.ts
|
|
183246
|
-
import * as fs3 from "fs";
|
|
183247
|
-
import * as os2 from "os";
|
|
183248
|
-
import * as path3 from "path";
|
|
183249
|
-
var DEBUG_LOG_PATH = ".specific/debug.log";
|
|
183250
|
-
var logStream = null;
|
|
183251
|
-
function writeLog(source, message) {
|
|
183252
|
-
const logPath = path3.join(os2.homedir(), DEBUG_LOG_PATH);
|
|
183253
|
-
fs3.mkdirSync(path3.dirname(logPath), { recursive: true });
|
|
183254
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
183255
|
-
const line = message.endsWith("\n") ? message : message + "\n";
|
|
183256
|
-
fs3.appendFileSync(logPath, `[${timestamp}] [${source}] ${line}`);
|
|
183257
|
-
}
|
|
183258
|
-
function pipeProcess(source, proc) {
|
|
183259
|
-
proc.stdout?.on("data", (data) => {
|
|
183260
|
-
const text = data.toString();
|
|
183261
|
-
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
183262
|
-
for (const line of lines) {
|
|
183263
|
-
writeLog(source, line);
|
|
183264
|
-
}
|
|
183265
|
-
});
|
|
183266
|
-
proc.stderr?.on("data", (data) => {
|
|
183267
|
-
const text = data.toString();
|
|
183268
|
-
const lines = text.split("\n").filter((line) => line.length > 0);
|
|
183269
|
-
for (const line of lines) {
|
|
183270
|
-
writeLog(source, line);
|
|
183271
|
-
}
|
|
183272
|
-
});
|
|
183273
|
-
proc.on("error", (err) => {
|
|
183274
|
-
writeLog(`${source}:error`, err.message);
|
|
183275
|
-
});
|
|
183276
|
-
proc.on("exit", (code, signal) => {
|
|
183277
|
-
writeLog(source, `Process exited with code=${code} signal=${signal}`);
|
|
183278
|
-
});
|
|
183279
|
-
}
|
|
183280
|
-
function closeDebugLog() {
|
|
183281
|
-
if (logStream) {
|
|
183282
|
-
logStream.end();
|
|
183283
|
-
logStream = null;
|
|
183284
|
-
}
|
|
183285
|
-
}
|
|
183286
|
-
|
|
183287
183428
|
// src/lib/api/client.ts
|
|
183288
183429
|
var ApiClient = class {
|
|
183289
183430
|
baseUrl;
|
|
@@ -183756,18 +183897,18 @@ function performLogin(options2 = {}) {
|
|
|
183756
183897
|
|
|
183757
183898
|
// src/lib/auth/credentials.ts
|
|
183758
183899
|
function getUserCredentialsDir() {
|
|
183759
|
-
return
|
|
183900
|
+
return path6.join(os5.homedir(), ".specific");
|
|
183760
183901
|
}
|
|
183761
183902
|
function getCredentialsPath() {
|
|
183762
|
-
return
|
|
183903
|
+
return path6.join(getUserCredentialsDir(), "credentials.json");
|
|
183763
183904
|
}
|
|
183764
183905
|
function readUserCredentials() {
|
|
183765
183906
|
const credentialsPath = getCredentialsPath();
|
|
183766
|
-
if (!
|
|
183907
|
+
if (!fs10.existsSync(credentialsPath)) {
|
|
183767
183908
|
return null;
|
|
183768
183909
|
}
|
|
183769
183910
|
try {
|
|
183770
|
-
const content =
|
|
183911
|
+
const content = fs10.readFileSync(credentialsPath, "utf-8");
|
|
183771
183912
|
return JSON.parse(content);
|
|
183772
183913
|
} catch {
|
|
183773
183914
|
return null;
|
|
@@ -183775,18 +183916,18 @@ function readUserCredentials() {
|
|
|
183775
183916
|
}
|
|
183776
183917
|
function writeUserCredentials(credentials) {
|
|
183777
183918
|
const dir = getUserCredentialsDir();
|
|
183778
|
-
if (!
|
|
183779
|
-
|
|
183919
|
+
if (!fs10.existsSync(dir)) {
|
|
183920
|
+
fs10.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
183780
183921
|
}
|
|
183781
183922
|
const credentialsPath = getCredentialsPath();
|
|
183782
|
-
|
|
183923
|
+
fs10.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
|
|
183783
183924
|
mode: 384
|
|
183784
183925
|
});
|
|
183785
183926
|
}
|
|
183786
183927
|
function clearUserCredentials() {
|
|
183787
183928
|
const credentialsPath = getCredentialsPath();
|
|
183788
|
-
if (
|
|
183789
|
-
|
|
183929
|
+
if (fs10.existsSync(credentialsPath)) {
|
|
183930
|
+
fs10.unlinkSync(credentialsPath);
|
|
183790
183931
|
}
|
|
183791
183932
|
}
|
|
183792
183933
|
function isLoggedIn() {
|
|
@@ -183840,7 +183981,7 @@ function isEnabled() {
|
|
|
183840
183981
|
}
|
|
183841
183982
|
function getAnonymousId() {
|
|
183842
183983
|
if (anonymousId) return anonymousId;
|
|
183843
|
-
const machineId = `${
|
|
183984
|
+
const machineId = `${os6.hostname()}-${os6.userInfo().username}`;
|
|
183844
183985
|
anonymousId = crypto.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
|
|
183845
183986
|
return anonymousId;
|
|
183846
183987
|
}
|
|
@@ -183873,7 +184014,7 @@ function trackEvent(event, properties) {
|
|
|
183873
184014
|
event,
|
|
183874
184015
|
properties: {
|
|
183875
184016
|
...properties,
|
|
183876
|
-
cli_version: "0.1.
|
|
184017
|
+
cli_version: "0.1.62",
|
|
183877
184018
|
platform: process.platform,
|
|
183878
184019
|
node_version: process.version,
|
|
183879
184020
|
project_id: getProjectId(),
|
|
@@ -183910,67 +184051,67 @@ var options = [
|
|
|
183910
184051
|
{ id: "other", label: "Other / Manual" }
|
|
183911
184052
|
];
|
|
183912
184053
|
function isGitProject() {
|
|
183913
|
-
const gitPath =
|
|
183914
|
-
return
|
|
184054
|
+
const gitPath = path7.join(process.cwd(), ".git");
|
|
184055
|
+
return fs11.existsSync(gitPath);
|
|
183915
184056
|
}
|
|
183916
184057
|
function detectExistingAgents() {
|
|
183917
184058
|
const detected = {};
|
|
183918
|
-
const cursorDir =
|
|
183919
|
-
if (
|
|
184059
|
+
const cursorDir = path7.join(process.cwd(), ".cursor");
|
|
184060
|
+
if (fs11.existsSync(cursorDir)) {
|
|
183920
184061
|
detected["cursor"] = true;
|
|
183921
184062
|
}
|
|
183922
|
-
const claudeDir =
|
|
183923
|
-
const claudeMd =
|
|
183924
|
-
if (
|
|
184063
|
+
const claudeDir = path7.join(process.cwd(), ".claude");
|
|
184064
|
+
const claudeMd = path7.join(process.cwd(), "CLAUDE.md");
|
|
184065
|
+
if (fs11.existsSync(claudeDir) || fs11.existsSync(claudeMd)) {
|
|
183925
184066
|
detected["claude"] = true;
|
|
183926
184067
|
}
|
|
183927
|
-
const agentsMd =
|
|
183928
|
-
if (
|
|
184068
|
+
const agentsMd = path7.join(process.cwd(), "AGENTS.md");
|
|
184069
|
+
if (fs11.existsSync(agentsMd)) {
|
|
183929
184070
|
detected["codex"] = true;
|
|
183930
184071
|
}
|
|
183931
184072
|
return detected;
|
|
183932
184073
|
}
|
|
183933
184074
|
function appendOrCreateFile(filePath, content) {
|
|
183934
|
-
if (
|
|
183935
|
-
const existing =
|
|
184075
|
+
if (fs11.existsSync(filePath)) {
|
|
184076
|
+
const existing = fs11.readFileSync(filePath, "utf-8");
|
|
183936
184077
|
if (existing.includes("specific docs") || existing.includes("specific check")) {
|
|
183937
184078
|
return "unchanged";
|
|
183938
184079
|
}
|
|
183939
184080
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
183940
|
-
|
|
184081
|
+
fs11.writeFileSync(filePath, existing + separator + content + "\n");
|
|
183941
184082
|
return "modified";
|
|
183942
184083
|
} else {
|
|
183943
|
-
|
|
184084
|
+
fs11.writeFileSync(filePath, content + "\n");
|
|
183944
184085
|
return "created";
|
|
183945
184086
|
}
|
|
183946
184087
|
}
|
|
183947
184088
|
function addToGitignore() {
|
|
183948
|
-
const gitignorePath =
|
|
184089
|
+
const gitignorePath = path7.join(process.cwd(), ".gitignore");
|
|
183949
184090
|
const entries = [".specific", "specific.local"];
|
|
183950
|
-
if (
|
|
183951
|
-
const existing =
|
|
184091
|
+
if (fs11.existsSync(gitignorePath)) {
|
|
184092
|
+
const existing = fs11.readFileSync(gitignorePath, "utf-8");
|
|
183952
184093
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
183953
184094
|
const missingEntries = entries.filter((entry) => !lines.includes(entry));
|
|
183954
184095
|
if (missingEntries.length === 0) {
|
|
183955
184096
|
return "unchanged";
|
|
183956
184097
|
}
|
|
183957
184098
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
183958
|
-
|
|
184099
|
+
fs11.writeFileSync(
|
|
183959
184100
|
gitignorePath,
|
|
183960
184101
|
existing + separator + missingEntries.join("\n") + "\n"
|
|
183961
184102
|
);
|
|
183962
184103
|
return "modified";
|
|
183963
184104
|
} else {
|
|
183964
|
-
|
|
184105
|
+
fs11.writeFileSync(gitignorePath, entries.join("\n") + "\n");
|
|
183965
184106
|
return "created";
|
|
183966
184107
|
}
|
|
183967
184108
|
}
|
|
183968
184109
|
function configureClaudeCodePermissions() {
|
|
183969
|
-
const claudeDir =
|
|
183970
|
-
const settingsPath =
|
|
184110
|
+
const claudeDir = path7.join(process.cwd(), ".claude");
|
|
184111
|
+
const settingsPath = path7.join(claudeDir, "settings.local.json");
|
|
183971
184112
|
const permissions = ["Bash(specific docs:*)", "Bash(specific check:*)"];
|
|
183972
|
-
if (
|
|
183973
|
-
const existing = JSON.parse(
|
|
184113
|
+
if (fs11.existsSync(settingsPath)) {
|
|
184114
|
+
const existing = JSON.parse(fs11.readFileSync(settingsPath, "utf-8"));
|
|
183974
184115
|
const allowList = existing?.permissions?.allow || [];
|
|
183975
184116
|
const missingPermissions = permissions.filter(
|
|
183976
184117
|
(p) => !allowList.includes(p)
|
|
@@ -183985,39 +184126,39 @@ function configureClaudeCodePermissions() {
|
|
|
183985
184126
|
existing.permissions.allow = [];
|
|
183986
184127
|
}
|
|
183987
184128
|
existing.permissions.allow.push(...missingPermissions);
|
|
183988
|
-
|
|
184129
|
+
fs11.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
|
|
183989
184130
|
return "modified";
|
|
183990
184131
|
}
|
|
183991
|
-
if (!
|
|
183992
|
-
|
|
184132
|
+
if (!fs11.existsSync(claudeDir)) {
|
|
184133
|
+
fs11.mkdirSync(claudeDir);
|
|
183993
184134
|
}
|
|
183994
184135
|
const settings = {
|
|
183995
184136
|
permissions: {
|
|
183996
184137
|
allow: permissions
|
|
183997
184138
|
}
|
|
183998
184139
|
};
|
|
183999
|
-
|
|
184140
|
+
fs11.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
184000
184141
|
return "created";
|
|
184001
184142
|
}
|
|
184002
184143
|
function createCursorRule() {
|
|
184003
|
-
const cursorDir =
|
|
184004
|
-
const rulesDir =
|
|
184005
|
-
const mdcPath =
|
|
184006
|
-
if (
|
|
184007
|
-
const existing =
|
|
184144
|
+
const cursorDir = path7.join(process.cwd(), ".cursor");
|
|
184145
|
+
const rulesDir = path7.join(cursorDir, "rules");
|
|
184146
|
+
const mdcPath = path7.join(rulesDir, "specific.mdc");
|
|
184147
|
+
if (fs11.existsSync(mdcPath)) {
|
|
184148
|
+
const existing = fs11.readFileSync(mdcPath, "utf-8");
|
|
184008
184149
|
if (existing.includes("specific docs") || existing.includes("specific check")) {
|
|
184009
184150
|
return "unchanged";
|
|
184010
184151
|
}
|
|
184011
|
-
|
|
184152
|
+
fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
|
|
184012
184153
|
return "modified";
|
|
184013
184154
|
}
|
|
184014
|
-
if (!
|
|
184015
|
-
|
|
184155
|
+
if (!fs11.existsSync(cursorDir)) {
|
|
184156
|
+
fs11.mkdirSync(cursorDir);
|
|
184016
184157
|
}
|
|
184017
|
-
if (!
|
|
184018
|
-
|
|
184158
|
+
if (!fs11.existsSync(rulesDir)) {
|
|
184159
|
+
fs11.mkdirSync(rulesDir);
|
|
184019
184160
|
}
|
|
184020
|
-
|
|
184161
|
+
fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
|
|
184021
184162
|
return "created";
|
|
184022
184163
|
}
|
|
184023
184164
|
function configureAgents(checked) {
|
|
@@ -184033,7 +184174,7 @@ function configureAgents(checked) {
|
|
|
184033
184174
|
agents.filesModified.push(".cursor/rules/specific.mdc");
|
|
184034
184175
|
}
|
|
184035
184176
|
if (checked["claude"]) {
|
|
184036
|
-
const claudeMdPath =
|
|
184177
|
+
const claudeMdPath = path7.join(process.cwd(), "CLAUDE.md");
|
|
184037
184178
|
const status = appendOrCreateFile(claudeMdPath, SPECIFIC_INSTRUCTIONS);
|
|
184038
184179
|
if (status === "created") agents.filesCreated.push("CLAUDE.md");
|
|
184039
184180
|
else if (status === "modified") agents.filesModified.push("CLAUDE.md");
|
|
@@ -184044,7 +184185,7 @@ function configureAgents(checked) {
|
|
|
184044
184185
|
agents.filesModified.push(".claude/settings.local.json");
|
|
184045
184186
|
}
|
|
184046
184187
|
if (checked["codex"]) {
|
|
184047
|
-
const agentsMdPath =
|
|
184188
|
+
const agentsMdPath = path7.join(process.cwd(), "AGENTS.md");
|
|
184048
184189
|
const status = appendOrCreateFile(agentsMdPath, SPECIFIC_INSTRUCTIONS);
|
|
184049
184190
|
if (status === "created") agents.filesCreated.push("AGENTS.md");
|
|
184050
184191
|
else if (status === "modified") agents.filesModified.push("AGENTS.md");
|
|
@@ -184070,16 +184211,16 @@ function InitUI() {
|
|
|
184070
184211
|
};
|
|
184071
184212
|
});
|
|
184072
184213
|
const [phase, setPhase] = useState(
|
|
184073
|
-
() =>
|
|
184214
|
+
() => !systemSetupNeeded() ? "agents" : "installing-ca"
|
|
184074
184215
|
);
|
|
184075
|
-
const [caInstallPhase, setCaInstallPhase] = useState(() =>
|
|
184216
|
+
const [caInstallPhase, setCaInstallPhase] = useState(() => !systemSetupNeeded() ? "done" : "installing");
|
|
184076
184217
|
const [focusedIndex, setFocusedIndex] = useState(initialState.focusedIndex);
|
|
184077
184218
|
const [checked, setChecked] = useState(
|
|
184078
184219
|
initialState.detected
|
|
184079
184220
|
);
|
|
184080
184221
|
const [result, setResult] = useState(null);
|
|
184081
184222
|
const [tlsResult, setTlsResult] = useState(
|
|
184082
|
-
|
|
184223
|
+
!systemSetupNeeded() ? { status: "success" } : null
|
|
184083
184224
|
);
|
|
184084
184225
|
useEffect(() => {
|
|
184085
184226
|
if (phase === "installing-ca" && caInstallPhase === "installing") {
|
|
@@ -184088,14 +184229,11 @@ function InitUI() {
|
|
|
184088
184229
|
}, [phase, caInstallPhase]);
|
|
184089
184230
|
async function installCA() {
|
|
184090
184231
|
try {
|
|
184091
|
-
|
|
184092
|
-
const certPath = saveCA(key, cert);
|
|
184093
|
-
installCAToTrustStore(certPath);
|
|
184232
|
+
performSystemSetup();
|
|
184094
184233
|
setTlsResult({ status: "success" });
|
|
184095
184234
|
setCaInstallPhase("done");
|
|
184096
184235
|
setPhase("agents");
|
|
184097
184236
|
} catch (err) {
|
|
184098
|
-
removeCA();
|
|
184099
184237
|
setTlsResult({
|
|
184100
184238
|
status: "error",
|
|
184101
184239
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -184136,16 +184274,16 @@ function InitUI() {
|
|
|
184136
184274
|
}, [phase, exit]);
|
|
184137
184275
|
if (phase === "installing-ca") {
|
|
184138
184276
|
if (caInstallPhase === "installing") {
|
|
184139
|
-
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "
|
|
184277
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Local Development Setup"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Setting up TLS certificates and DNS resolution for local"), /* @__PURE__ */ React2.createElement(Text2, null, "development. This is a one-time setup for Specific projects."), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Your password is required to configure your system."), /* @__PURE__ */ React2.createElement(Text2, null, " "));
|
|
184140
184278
|
}
|
|
184141
184279
|
}
|
|
184142
184280
|
if (phase === "done") {
|
|
184143
184281
|
const selectedAgents = Object.entries(checked).filter(([, v]) => v).length;
|
|
184144
184282
|
const agentChanges = result && (result.agents.filesCreated.length > 0 || result.agents.filesModified.length > 0);
|
|
184145
184283
|
const gitChanges = result?.git && (result.git.filesCreated.length > 0 || result.git.filesModified.length > 0);
|
|
184146
|
-
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, tlsResult === null && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u25CF"), "
|
|
184284
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, tlsResult === null && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u25CF"), " Setting up TLS and DNS..."), tlsResult?.status === "success" && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS and DNS configured"), tlsResult?.status === "error" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u2717"), " Failed to set up TLS and DNS"), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", tlsResult.error)), result && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Coding agents configured"), result.agents.filesCreated.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Created: ", result.agents.filesCreated.join(", ")), result.agents.filesModified.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Modified: ", result.agents.filesModified.join(", ")), !agentChanges && selectedAgents > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "No changes needed (files already configured)"), selectedAgents === 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " No agents selected")), result?.git && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Git configured"), result.git.filesCreated.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Created: ", result.git.filesCreated.join(", ")), result.git.filesModified.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Modified: ", result.git.filesModified.join(", ")), !gitChanges && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "No changes needed (.gitignore already configured)")), result?.showManualInstructions && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Manual configuration selected"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, " Add this to your agent's system prompt:"), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React2.createElement(Text2, null, SPECIFIC_INSTRUCTIONS), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, " ", "We also recommend allowing your agent to run `specific docs *`"), /* @__PURE__ */ React2.createElement(Text2, null, " and `specific check *` without confirmation.")));
|
|
184147
184285
|
}
|
|
184148
|
-
const tlsLine = tlsResult?.status === "success" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS
|
|
184286
|
+
const tlsLine = tlsResult?.status === "success" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS and DNS configured") : tlsResult?.status === "error" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u2717"), " TLS and DNS setup failed", " ", /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "(", tlsResult.error, ")")) : null;
|
|
184149
184287
|
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, tlsLine, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u25CF"), " Configure coding agents", " ", /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "(space to select)")), /* @__PURE__ */ React2.createElement(Text2, null, " "), options.map((option, index) => {
|
|
184150
184288
|
const isFocused = focusedIndex === index;
|
|
184151
184289
|
const isChecked = checked[option.id];
|
|
@@ -184216,9 +184354,9 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
|
|
|
184216
184354
|
console.log(" No changes needed (.gitignore already configured)");
|
|
184217
184355
|
}
|
|
184218
184356
|
}
|
|
184219
|
-
if (
|
|
184357
|
+
if (systemSetupNeeded()) {
|
|
184220
184358
|
console.log(
|
|
184221
|
-
"\u26A0 TLS
|
|
184359
|
+
"\u26A0 TLS and DNS not configured (run `specific init` in a terminal to set up)"
|
|
184222
184360
|
);
|
|
184223
184361
|
}
|
|
184224
184362
|
if (result.showManualInstructions) {
|
|
@@ -184235,8 +184373,8 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
|
|
|
184235
184373
|
}
|
|
184236
184374
|
|
|
184237
184375
|
// src/commands/docs.tsx
|
|
184238
|
-
import { readFileSync as readFileSync6, existsSync as
|
|
184239
|
-
import { join as
|
|
184376
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
184377
|
+
import { join as join8, dirname as dirname2 } from "path";
|
|
184240
184378
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
184241
184379
|
|
|
184242
184380
|
// src/lib/beta/registry.ts
|
|
@@ -184248,12 +184386,12 @@ var BETA_REGISTRY = [
|
|
|
184248
184386
|
];
|
|
184249
184387
|
|
|
184250
184388
|
// src/lib/beta/storage.ts
|
|
184251
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as
|
|
184252
|
-
import { join as
|
|
184389
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
184390
|
+
import { join as join7 } from "path";
|
|
184253
184391
|
var BETAS_FILE = ".specific/betas.json";
|
|
184254
184392
|
function loadEnabledBetas(projectDir = process.cwd()) {
|
|
184255
|
-
const filePath =
|
|
184256
|
-
if (!
|
|
184393
|
+
const filePath = join7(projectDir, BETAS_FILE);
|
|
184394
|
+
if (!existsSync6(filePath)) {
|
|
184257
184395
|
return [];
|
|
184258
184396
|
}
|
|
184259
184397
|
try {
|
|
@@ -184276,25 +184414,25 @@ function disableBeta(name, projectDir = process.cwd()) {
|
|
|
184276
184414
|
saveBetas(enabled, projectDir);
|
|
184277
184415
|
}
|
|
184278
184416
|
function saveBetas(enabled, projectDir) {
|
|
184279
|
-
const specificDir =
|
|
184280
|
-
if (!
|
|
184417
|
+
const specificDir = join7(projectDir, ".specific");
|
|
184418
|
+
if (!existsSync6(specificDir)) {
|
|
184281
184419
|
mkdirSync6(specificDir, { recursive: true });
|
|
184282
184420
|
}
|
|
184283
184421
|
const data = { enabled };
|
|
184284
184422
|
writeFileSync5(
|
|
184285
|
-
|
|
184423
|
+
join7(projectDir, BETAS_FILE),
|
|
184286
184424
|
JSON.stringify(data, null, 2) + "\n"
|
|
184287
184425
|
);
|
|
184288
184426
|
}
|
|
184289
184427
|
|
|
184290
184428
|
// src/commands/docs.tsx
|
|
184291
184429
|
var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
184292
|
-
var docsDir =
|
|
184293
|
-
function docsCommand(
|
|
184294
|
-
const docPath = resolveDocPath(
|
|
184430
|
+
var docsDir = join8(__dirname2, "docs");
|
|
184431
|
+
function docsCommand(path27) {
|
|
184432
|
+
const docPath = resolveDocPath(path27);
|
|
184295
184433
|
if (!docPath) {
|
|
184296
184434
|
console.error(
|
|
184297
|
-
`Documentation not found: ${
|
|
184435
|
+
`Documentation not found: ${path27 || "index"}
|
|
184298
184436
|
|
|
184299
184437
|
Run 'specific docs' to see available topics.`
|
|
184300
184438
|
);
|
|
@@ -184313,17 +184451,17 @@ function filterBetaTags(content, enabledBetas) {
|
|
|
184313
184451
|
}
|
|
184314
184452
|
);
|
|
184315
184453
|
}
|
|
184316
|
-
function resolveDocPath(
|
|
184317
|
-
if (!
|
|
184318
|
-
const indexPath2 =
|
|
184319
|
-
return
|
|
184454
|
+
function resolveDocPath(path27) {
|
|
184455
|
+
if (!path27) {
|
|
184456
|
+
const indexPath2 = join8(docsDir, "index.md");
|
|
184457
|
+
return existsSync7(indexPath2) ? indexPath2 : null;
|
|
184320
184458
|
}
|
|
184321
|
-
const directPath =
|
|
184322
|
-
if (
|
|
184459
|
+
const directPath = join8(docsDir, `${path27}.md`);
|
|
184460
|
+
if (existsSync7(directPath)) {
|
|
184323
184461
|
return directPath;
|
|
184324
184462
|
}
|
|
184325
|
-
const indexPath =
|
|
184326
|
-
if (
|
|
184463
|
+
const indexPath = join8(docsDir, path27, "index.md");
|
|
184464
|
+
if (existsSync7(indexPath)) {
|
|
184327
184465
|
return indexPath;
|
|
184328
184466
|
}
|
|
184329
184467
|
return null;
|
|
@@ -184333,8 +184471,8 @@ function resolveDocPath(path26) {
|
|
|
184333
184471
|
import React3, { useState as useState2, useEffect as useEffect2 } from "react";
|
|
184334
184472
|
import { render as render3, Text as Text3, Box as Box3 } from "ink";
|
|
184335
184473
|
import Spinner3 from "ink-spinner";
|
|
184336
|
-
import * as
|
|
184337
|
-
import * as
|
|
184474
|
+
import * as fs13 from "fs";
|
|
184475
|
+
import * as path9 from "path";
|
|
184338
184476
|
import { execFile as execFile7 } from "child_process";
|
|
184339
184477
|
|
|
184340
184478
|
// node_modules/.pnpm/@specific+config@file+..+config/node_modules/@specific/config/dist/parser.js
|
|
@@ -185011,32 +185149,32 @@ var ExtractionError = class extends Error {
|
|
|
185011
185149
|
};
|
|
185012
185150
|
|
|
185013
185151
|
// src/lib/bin/manager.ts
|
|
185014
|
-
import * as
|
|
185015
|
-
import * as
|
|
185016
|
-
import * as
|
|
185152
|
+
import * as fs12 from "fs";
|
|
185153
|
+
import * as path8 from "path";
|
|
185154
|
+
import * as os7 from "os";
|
|
185017
185155
|
import { createReadStream } from "fs";
|
|
185018
185156
|
import { createTarExtractor, extractTo } from "tar-vern";
|
|
185019
185157
|
function getLibraryEnv(binary) {
|
|
185020
185158
|
if (!binary.libraryPath) {
|
|
185021
185159
|
return {};
|
|
185022
185160
|
}
|
|
185023
|
-
const
|
|
185024
|
-
if (
|
|
185161
|
+
const platform5 = os7.platform();
|
|
185162
|
+
if (platform5 === "darwin") {
|
|
185025
185163
|
return { DYLD_LIBRARY_PATH: binary.libraryPath };
|
|
185026
|
-
} else if (
|
|
185164
|
+
} else if (platform5 === "linux") {
|
|
185027
185165
|
return { LD_LIBRARY_PATH: binary.libraryPath };
|
|
185028
185166
|
}
|
|
185029
185167
|
return {};
|
|
185030
185168
|
}
|
|
185031
185169
|
function getBinBaseDir() {
|
|
185032
|
-
return
|
|
185170
|
+
return path8.join(os7.homedir(), ".specific", "bin");
|
|
185033
185171
|
}
|
|
185034
185172
|
function getPlatformInfo() {
|
|
185035
|
-
const
|
|
185036
|
-
const arch3 =
|
|
185037
|
-
if (
|
|
185173
|
+
const platform5 = os7.platform();
|
|
185174
|
+
const arch3 = os7.arch();
|
|
185175
|
+
if (platform5 !== "darwin" && platform5 !== "linux") {
|
|
185038
185176
|
throw new Error(
|
|
185039
|
-
`Unsupported platform: ${
|
|
185177
|
+
`Unsupported platform: ${platform5}. Only macOS and Linux are supported.`
|
|
185040
185178
|
);
|
|
185041
185179
|
}
|
|
185042
185180
|
const archStr = arch3;
|
|
@@ -185050,10 +185188,10 @@ function getPlatformInfo() {
|
|
|
185050
185188
|
`Unsupported architecture: ${arch3}. Only x64 and arm64 are supported.`
|
|
185051
185189
|
);
|
|
185052
185190
|
}
|
|
185053
|
-
return { platform:
|
|
185191
|
+
return { platform: platform5, arch: mappedArch };
|
|
185054
185192
|
}
|
|
185055
185193
|
function getBinaryDir(definition, version, platformInfo) {
|
|
185056
|
-
return
|
|
185194
|
+
return path8.join(
|
|
185057
185195
|
getBinBaseDir(),
|
|
185058
185196
|
definition.name,
|
|
185059
185197
|
version,
|
|
@@ -185063,8 +185201,8 @@ function getBinaryDir(definition, version, platformInfo) {
|
|
|
185063
185201
|
function isBinaryInstalled(definition, version, platformInfo) {
|
|
185064
185202
|
const binDir = getBinaryDir(definition, version, platformInfo);
|
|
185065
185203
|
for (const execPath of definition.executables) {
|
|
185066
|
-
const fullPath =
|
|
185067
|
-
if (!
|
|
185204
|
+
const fullPath = path8.join(binDir, execPath);
|
|
185205
|
+
if (!fs12.existsSync(fullPath)) {
|
|
185068
185206
|
return false;
|
|
185069
185207
|
}
|
|
185070
185208
|
}
|
|
@@ -185092,12 +185230,12 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
185092
185230
|
10
|
|
185093
185231
|
);
|
|
185094
185232
|
let bytesDownloaded = 0;
|
|
185095
|
-
const parentDir =
|
|
185096
|
-
if (!
|
|
185097
|
-
|
|
185233
|
+
const parentDir = path8.dirname(destPath);
|
|
185234
|
+
if (!fs12.existsSync(parentDir)) {
|
|
185235
|
+
fs12.mkdirSync(parentDir, { recursive: true });
|
|
185098
185236
|
}
|
|
185099
185237
|
const partPath = destPath + ".part";
|
|
185100
|
-
const fileStream =
|
|
185238
|
+
const fileStream = fs12.createWriteStream(partPath);
|
|
185101
185239
|
try {
|
|
185102
185240
|
const reader = response.body.getReader();
|
|
185103
185241
|
while (true) {
|
|
@@ -185120,12 +185258,12 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
185120
185258
|
else resolve10();
|
|
185121
185259
|
});
|
|
185122
185260
|
});
|
|
185123
|
-
|
|
185261
|
+
fs12.renameSync(partPath, destPath);
|
|
185124
185262
|
} catch (error) {
|
|
185125
185263
|
try {
|
|
185126
185264
|
fileStream.close();
|
|
185127
|
-
if (
|
|
185128
|
-
|
|
185265
|
+
if (fs12.existsSync(partPath)) {
|
|
185266
|
+
fs12.unlinkSync(partPath);
|
|
185129
185267
|
}
|
|
185130
185268
|
} catch {
|
|
185131
185269
|
}
|
|
@@ -185134,8 +185272,8 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
185134
185272
|
}
|
|
185135
185273
|
async function extractTarball(archivePath, destDir, definition, onProgress) {
|
|
185136
185274
|
onProgress?.({ phase: "extracting" });
|
|
185137
|
-
if (!
|
|
185138
|
-
|
|
185275
|
+
if (!fs12.existsSync(destDir)) {
|
|
185276
|
+
fs12.mkdirSync(destDir, { recursive: true });
|
|
185139
185277
|
}
|
|
185140
185278
|
try {
|
|
185141
185279
|
const fileStream = createReadStream(archivePath);
|
|
@@ -185143,9 +185281,9 @@ async function extractTarball(archivePath, destDir, definition, onProgress) {
|
|
|
185143
185281
|
await extractTo(entries, destDir);
|
|
185144
185282
|
onProgress?.({ phase: "finalizing" });
|
|
185145
185283
|
for (const execPath of definition.executables) {
|
|
185146
|
-
const fullPath =
|
|
185147
|
-
if (
|
|
185148
|
-
|
|
185284
|
+
const fullPath = path8.join(destDir, execPath);
|
|
185285
|
+
if (fs12.existsSync(fullPath)) {
|
|
185286
|
+
fs12.chmodSync(fullPath, 493);
|
|
185149
185287
|
}
|
|
185150
185288
|
}
|
|
185151
185289
|
} catch (error) {
|
|
@@ -185169,24 +185307,24 @@ async function ensureBinary(definition, version, onProgress) {
|
|
|
185169
185307
|
`Binary type definitions must have exactly one executable, got ${definition.executables.length}`
|
|
185170
185308
|
);
|
|
185171
185309
|
}
|
|
185172
|
-
if (!
|
|
185173
|
-
|
|
185310
|
+
if (!fs12.existsSync(binDir)) {
|
|
185311
|
+
fs12.mkdirSync(binDir, { recursive: true });
|
|
185174
185312
|
}
|
|
185175
|
-
const execPath =
|
|
185313
|
+
const execPath = path8.join(binDir, definition.executables[0]);
|
|
185176
185314
|
await downloadFile(url, execPath, onProgress);
|
|
185177
|
-
|
|
185315
|
+
fs12.chmodSync(execPath, 493);
|
|
185178
185316
|
onProgress?.({ phase: "finalizing" });
|
|
185179
185317
|
} else {
|
|
185180
|
-
const downloadDir =
|
|
185318
|
+
const downloadDir = path8.join(getBinBaseDir(), "downloads");
|
|
185181
185319
|
const archiveName = `${definition.name}-${resolvedVersion}-${platformInfo.platform}-${platformInfo.arch}.tar.gz`;
|
|
185182
|
-
const archivePath =
|
|
185320
|
+
const archivePath = path8.join(downloadDir, archiveName);
|
|
185183
185321
|
try {
|
|
185184
185322
|
await downloadFile(url, archivePath, onProgress);
|
|
185185
185323
|
await extractTarball(archivePath, binDir, definition, onProgress);
|
|
185186
185324
|
} finally {
|
|
185187
185325
|
try {
|
|
185188
|
-
if (
|
|
185189
|
-
|
|
185326
|
+
if (fs12.existsSync(archivePath)) {
|
|
185327
|
+
fs12.unlinkSync(archivePath);
|
|
185190
185328
|
}
|
|
185191
185329
|
} catch {
|
|
185192
185330
|
}
|
|
@@ -185195,10 +185333,10 @@ async function ensureBinary(definition, version, onProgress) {
|
|
|
185195
185333
|
}
|
|
185196
185334
|
const executables = {};
|
|
185197
185335
|
for (const execPath of definition.executables) {
|
|
185198
|
-
const name =
|
|
185199
|
-
executables[name] =
|
|
185336
|
+
const name = path8.basename(execPath);
|
|
185337
|
+
executables[name] = path8.join(binDir, execPath);
|
|
185200
185338
|
}
|
|
185201
|
-
const libraryPath = definition.libraryDir ?
|
|
185339
|
+
const libraryPath = definition.libraryDir ? path8.join(binDir, definition.libraryDir) : void 0;
|
|
185202
185340
|
return {
|
|
185203
185341
|
rootDir: binDir,
|
|
185204
185342
|
version: resolvedVersion,
|
|
@@ -185342,8 +185480,8 @@ function CheckUI() {
|
|
|
185342
185480
|
const [state, setState] = useState2({ status: "loading" });
|
|
185343
185481
|
useEffect2(() => {
|
|
185344
185482
|
async function load() {
|
|
185345
|
-
const configPath =
|
|
185346
|
-
if (!
|
|
185483
|
+
const configPath = path9.join(process.cwd(), "specific.hcl");
|
|
185484
|
+
if (!fs13.existsSync(configPath)) {
|
|
185347
185485
|
setState({
|
|
185348
185486
|
status: "error",
|
|
185349
185487
|
error: "No specific.hcl found in current directory"
|
|
@@ -185351,16 +185489,16 @@ function CheckUI() {
|
|
|
185351
185489
|
return;
|
|
185352
185490
|
}
|
|
185353
185491
|
try {
|
|
185354
|
-
const hcl =
|
|
185492
|
+
const hcl = fs13.readFileSync(configPath, "utf-8");
|
|
185355
185493
|
const config2 = await parseConfig(hcl);
|
|
185356
185494
|
const reshapeChecks2 = [];
|
|
185357
185495
|
for (const pg of config2.postgres) {
|
|
185358
185496
|
if (pg.reshape?.enabled) {
|
|
185359
|
-
const migrationsDir =
|
|
185497
|
+
const migrationsDir = path9.resolve(
|
|
185360
185498
|
process.cwd(),
|
|
185361
185499
|
pg.reshape.migrations_dir ?? "migrations"
|
|
185362
185500
|
);
|
|
185363
|
-
if (!
|
|
185501
|
+
if (!fs13.existsSync(migrationsDir)) {
|
|
185364
185502
|
reshapeChecks2.push({
|
|
185365
185503
|
databaseName: pg.name,
|
|
185366
185504
|
migrationsDir: pg.reshape.migrations_dir ?? "migrations",
|
|
@@ -185413,8 +185551,8 @@ function checkCommand() {
|
|
|
185413
185551
|
import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
|
|
185414
185552
|
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
|
|
185415
185553
|
import Spinner4 from "ink-spinner";
|
|
185416
|
-
import * as
|
|
185417
|
-
import * as
|
|
185554
|
+
import * as fs22 from "fs";
|
|
185555
|
+
import * as path19 from "path";
|
|
185418
185556
|
|
|
185419
185557
|
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
185420
185558
|
import { EventEmitter } from "node:events";
|
|
@@ -185506,7 +185644,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
185506
185644
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
185507
185645
|
const statMethod = opts.lstat ? lstat : stat;
|
|
185508
185646
|
if (wantBigintFsStats) {
|
|
185509
|
-
this._stat = (
|
|
185647
|
+
this._stat = (path27) => statMethod(path27, { bigint: true });
|
|
185510
185648
|
} else {
|
|
185511
185649
|
this._stat = statMethod;
|
|
185512
185650
|
}
|
|
@@ -185531,8 +185669,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
185531
185669
|
const par = this.parent;
|
|
185532
185670
|
const fil = par && par.files;
|
|
185533
185671
|
if (fil && fil.length > 0) {
|
|
185534
|
-
const { path:
|
|
185535
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
185672
|
+
const { path: path27, depth } = par;
|
|
185673
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path27));
|
|
185536
185674
|
const awaited = await Promise.all(slice);
|
|
185537
185675
|
for (const entry of awaited) {
|
|
185538
185676
|
if (!entry)
|
|
@@ -185572,20 +185710,20 @@ var ReaddirpStream = class extends Readable {
|
|
|
185572
185710
|
this.reading = false;
|
|
185573
185711
|
}
|
|
185574
185712
|
}
|
|
185575
|
-
async _exploreDir(
|
|
185713
|
+
async _exploreDir(path27, depth) {
|
|
185576
185714
|
let files;
|
|
185577
185715
|
try {
|
|
185578
|
-
files = await readdir(
|
|
185716
|
+
files = await readdir(path27, this._rdOptions);
|
|
185579
185717
|
} catch (error) {
|
|
185580
185718
|
this._onError(error);
|
|
185581
185719
|
}
|
|
185582
|
-
return { files, depth, path:
|
|
185720
|
+
return { files, depth, path: path27 };
|
|
185583
185721
|
}
|
|
185584
|
-
async _formatEntry(dirent,
|
|
185722
|
+
async _formatEntry(dirent, path27) {
|
|
185585
185723
|
let entry;
|
|
185586
185724
|
const basename6 = this._isDirent ? dirent.name : dirent;
|
|
185587
185725
|
try {
|
|
185588
|
-
const fullPath = presolve(pjoin(
|
|
185726
|
+
const fullPath = presolve(pjoin(path27, basename6));
|
|
185589
185727
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename6 };
|
|
185590
185728
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
185591
185729
|
} catch (err) {
|
|
@@ -185985,16 +186123,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
185985
186123
|
};
|
|
185986
186124
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
185987
186125
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
185988
|
-
function createFsWatchInstance(
|
|
186126
|
+
function createFsWatchInstance(path27, options2, listener, errHandler, emitRaw) {
|
|
185989
186127
|
const handleEvent = (rawEvent, evPath) => {
|
|
185990
|
-
listener(
|
|
185991
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
185992
|
-
if (evPath &&
|
|
185993
|
-
fsWatchBroadcast(sp.resolve(
|
|
186128
|
+
listener(path27);
|
|
186129
|
+
emitRaw(rawEvent, evPath, { watchedPath: path27 });
|
|
186130
|
+
if (evPath && path27 !== evPath) {
|
|
186131
|
+
fsWatchBroadcast(sp.resolve(path27, evPath), KEY_LISTENERS, sp.join(path27, evPath));
|
|
185994
186132
|
}
|
|
185995
186133
|
};
|
|
185996
186134
|
try {
|
|
185997
|
-
return fs_watch(
|
|
186135
|
+
return fs_watch(path27, {
|
|
185998
186136
|
persistent: options2.persistent
|
|
185999
186137
|
}, handleEvent);
|
|
186000
186138
|
} catch (error) {
|
|
@@ -186010,12 +186148,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
186010
186148
|
listener(val1, val2, val3);
|
|
186011
186149
|
});
|
|
186012
186150
|
};
|
|
186013
|
-
var setFsWatchListener = (
|
|
186151
|
+
var setFsWatchListener = (path27, fullPath, options2, handlers) => {
|
|
186014
186152
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
186015
186153
|
let cont = FsWatchInstances.get(fullPath);
|
|
186016
186154
|
let watcher;
|
|
186017
186155
|
if (!options2.persistent) {
|
|
186018
|
-
watcher = createFsWatchInstance(
|
|
186156
|
+
watcher = createFsWatchInstance(path27, options2, listener, errHandler, rawEmitter);
|
|
186019
186157
|
if (!watcher)
|
|
186020
186158
|
return;
|
|
186021
186159
|
return watcher.close.bind(watcher);
|
|
@@ -186026,7 +186164,7 @@ var setFsWatchListener = (path26, fullPath, options2, handlers) => {
|
|
|
186026
186164
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
186027
186165
|
} else {
|
|
186028
186166
|
watcher = createFsWatchInstance(
|
|
186029
|
-
|
|
186167
|
+
path27,
|
|
186030
186168
|
options2,
|
|
186031
186169
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
186032
186170
|
errHandler,
|
|
@@ -186041,7 +186179,7 @@ var setFsWatchListener = (path26, fullPath, options2, handlers) => {
|
|
|
186041
186179
|
cont.watcherUnusable = true;
|
|
186042
186180
|
if (isWindows && error.code === "EPERM") {
|
|
186043
186181
|
try {
|
|
186044
|
-
const fd = await open2(
|
|
186182
|
+
const fd = await open2(path27, "r");
|
|
186045
186183
|
await fd.close();
|
|
186046
186184
|
broadcastErr(error);
|
|
186047
186185
|
} catch (err) {
|
|
@@ -186072,7 +186210,7 @@ var setFsWatchListener = (path26, fullPath, options2, handlers) => {
|
|
|
186072
186210
|
};
|
|
186073
186211
|
};
|
|
186074
186212
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
186075
|
-
var setFsWatchFileListener = (
|
|
186213
|
+
var setFsWatchFileListener = (path27, fullPath, options2, handlers) => {
|
|
186076
186214
|
const { listener, rawEmitter } = handlers;
|
|
186077
186215
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
186078
186216
|
const copts = cont && cont.options;
|
|
@@ -186094,7 +186232,7 @@ var setFsWatchFileListener = (path26, fullPath, options2, handlers) => {
|
|
|
186094
186232
|
});
|
|
186095
186233
|
const currmtime = curr.mtimeMs;
|
|
186096
186234
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
186097
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
186235
|
+
foreach(cont.listeners, (listener2) => listener2(path27, curr));
|
|
186098
186236
|
}
|
|
186099
186237
|
})
|
|
186100
186238
|
};
|
|
@@ -186124,13 +186262,13 @@ var NodeFsHandler = class {
|
|
|
186124
186262
|
* @param listener on fs change
|
|
186125
186263
|
* @returns closer for the watcher instance
|
|
186126
186264
|
*/
|
|
186127
|
-
_watchWithNodeFs(
|
|
186265
|
+
_watchWithNodeFs(path27, listener) {
|
|
186128
186266
|
const opts = this.fsw.options;
|
|
186129
|
-
const directory = sp.dirname(
|
|
186130
|
-
const basename6 = sp.basename(
|
|
186267
|
+
const directory = sp.dirname(path27);
|
|
186268
|
+
const basename6 = sp.basename(path27);
|
|
186131
186269
|
const parent = this.fsw._getWatchedDir(directory);
|
|
186132
186270
|
parent.add(basename6);
|
|
186133
|
-
const absolutePath = sp.resolve(
|
|
186271
|
+
const absolutePath = sp.resolve(path27);
|
|
186134
186272
|
const options2 = {
|
|
186135
186273
|
persistent: opts.persistent
|
|
186136
186274
|
};
|
|
@@ -186140,12 +186278,12 @@ var NodeFsHandler = class {
|
|
|
186140
186278
|
if (opts.usePolling) {
|
|
186141
186279
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
186142
186280
|
options2.interval = enableBin && isBinaryPath(basename6) ? opts.binaryInterval : opts.interval;
|
|
186143
|
-
closer = setFsWatchFileListener(
|
|
186281
|
+
closer = setFsWatchFileListener(path27, absolutePath, options2, {
|
|
186144
186282
|
listener,
|
|
186145
186283
|
rawEmitter: this.fsw._emitRaw
|
|
186146
186284
|
});
|
|
186147
186285
|
} else {
|
|
186148
|
-
closer = setFsWatchListener(
|
|
186286
|
+
closer = setFsWatchListener(path27, absolutePath, options2, {
|
|
186149
186287
|
listener,
|
|
186150
186288
|
errHandler: this._boundHandleError,
|
|
186151
186289
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -186167,7 +186305,7 @@ var NodeFsHandler = class {
|
|
|
186167
186305
|
let prevStats = stats;
|
|
186168
186306
|
if (parent.has(basename6))
|
|
186169
186307
|
return;
|
|
186170
|
-
const listener = async (
|
|
186308
|
+
const listener = async (path27, newStats) => {
|
|
186171
186309
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
186172
186310
|
return;
|
|
186173
186311
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -186181,11 +186319,11 @@ var NodeFsHandler = class {
|
|
|
186181
186319
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
186182
186320
|
}
|
|
186183
186321
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
186184
|
-
this.fsw._closeFile(
|
|
186322
|
+
this.fsw._closeFile(path27);
|
|
186185
186323
|
prevStats = newStats2;
|
|
186186
186324
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
186187
186325
|
if (closer2)
|
|
186188
|
-
this.fsw._addPathCloser(
|
|
186326
|
+
this.fsw._addPathCloser(path27, closer2);
|
|
186189
186327
|
} else {
|
|
186190
186328
|
prevStats = newStats2;
|
|
186191
186329
|
}
|
|
@@ -186217,7 +186355,7 @@ var NodeFsHandler = class {
|
|
|
186217
186355
|
* @param item basename of this item
|
|
186218
186356
|
* @returns true if no more processing is needed for this entry.
|
|
186219
186357
|
*/
|
|
186220
|
-
async _handleSymlink(entry, directory,
|
|
186358
|
+
async _handleSymlink(entry, directory, path27, item) {
|
|
186221
186359
|
if (this.fsw.closed) {
|
|
186222
186360
|
return;
|
|
186223
186361
|
}
|
|
@@ -186227,7 +186365,7 @@ var NodeFsHandler = class {
|
|
|
186227
186365
|
this.fsw._incrReadyCount();
|
|
186228
186366
|
let linkPath;
|
|
186229
186367
|
try {
|
|
186230
|
-
linkPath = await fsrealpath(
|
|
186368
|
+
linkPath = await fsrealpath(path27);
|
|
186231
186369
|
} catch (e) {
|
|
186232
186370
|
this.fsw._emitReady();
|
|
186233
186371
|
return true;
|
|
@@ -186237,12 +186375,12 @@ var NodeFsHandler = class {
|
|
|
186237
186375
|
if (dir.has(item)) {
|
|
186238
186376
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
186239
186377
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
186240
|
-
this.fsw._emit(EV.CHANGE,
|
|
186378
|
+
this.fsw._emit(EV.CHANGE, path27, entry.stats);
|
|
186241
186379
|
}
|
|
186242
186380
|
} else {
|
|
186243
186381
|
dir.add(item);
|
|
186244
186382
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
186245
|
-
this.fsw._emit(EV.ADD,
|
|
186383
|
+
this.fsw._emit(EV.ADD, path27, entry.stats);
|
|
186246
186384
|
}
|
|
186247
186385
|
this.fsw._emitReady();
|
|
186248
186386
|
return true;
|
|
@@ -186272,9 +186410,9 @@ var NodeFsHandler = class {
|
|
|
186272
186410
|
return;
|
|
186273
186411
|
}
|
|
186274
186412
|
const item = entry.path;
|
|
186275
|
-
let
|
|
186413
|
+
let path27 = sp.join(directory, item);
|
|
186276
186414
|
current.add(item);
|
|
186277
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
186415
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path27, item)) {
|
|
186278
186416
|
return;
|
|
186279
186417
|
}
|
|
186280
186418
|
if (this.fsw.closed) {
|
|
@@ -186283,8 +186421,8 @@ var NodeFsHandler = class {
|
|
|
186283
186421
|
}
|
|
186284
186422
|
if (item === target || !target && !previous.has(item)) {
|
|
186285
186423
|
this.fsw._incrReadyCount();
|
|
186286
|
-
|
|
186287
|
-
this._addToNodeFs(
|
|
186424
|
+
path27 = sp.join(dir, sp.relative(dir, path27));
|
|
186425
|
+
this._addToNodeFs(path27, initialAdd, wh, depth + 1);
|
|
186288
186426
|
}
|
|
186289
186427
|
}).on(EV.ERROR, this._boundHandleError);
|
|
186290
186428
|
return new Promise((resolve10, reject) => {
|
|
@@ -186353,13 +186491,13 @@ var NodeFsHandler = class {
|
|
|
186353
186491
|
* @param depth Child path actually targeted for watch
|
|
186354
186492
|
* @param target Child path actually targeted for watch
|
|
186355
186493
|
*/
|
|
186356
|
-
async _addToNodeFs(
|
|
186494
|
+
async _addToNodeFs(path27, initialAdd, priorWh, depth, target) {
|
|
186357
186495
|
const ready = this.fsw._emitReady;
|
|
186358
|
-
if (this.fsw._isIgnored(
|
|
186496
|
+
if (this.fsw._isIgnored(path27) || this.fsw.closed) {
|
|
186359
186497
|
ready();
|
|
186360
186498
|
return false;
|
|
186361
186499
|
}
|
|
186362
|
-
const wh = this.fsw._getWatchHelpers(
|
|
186500
|
+
const wh = this.fsw._getWatchHelpers(path27);
|
|
186363
186501
|
if (priorWh) {
|
|
186364
186502
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
186365
186503
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -186375,8 +186513,8 @@ var NodeFsHandler = class {
|
|
|
186375
186513
|
const follow = this.fsw.options.followSymlinks;
|
|
186376
186514
|
let closer;
|
|
186377
186515
|
if (stats.isDirectory()) {
|
|
186378
|
-
const absPath = sp.resolve(
|
|
186379
|
-
const targetPath = follow ? await fsrealpath(
|
|
186516
|
+
const absPath = sp.resolve(path27);
|
|
186517
|
+
const targetPath = follow ? await fsrealpath(path27) : path27;
|
|
186380
186518
|
if (this.fsw.closed)
|
|
186381
186519
|
return;
|
|
186382
186520
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -186386,29 +186524,29 @@ var NodeFsHandler = class {
|
|
|
186386
186524
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
186387
186525
|
}
|
|
186388
186526
|
} else if (stats.isSymbolicLink()) {
|
|
186389
|
-
const targetPath = follow ? await fsrealpath(
|
|
186527
|
+
const targetPath = follow ? await fsrealpath(path27) : path27;
|
|
186390
186528
|
if (this.fsw.closed)
|
|
186391
186529
|
return;
|
|
186392
186530
|
const parent = sp.dirname(wh.watchPath);
|
|
186393
186531
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
186394
186532
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
186395
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
186533
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path27, wh, targetPath);
|
|
186396
186534
|
if (this.fsw.closed)
|
|
186397
186535
|
return;
|
|
186398
186536
|
if (targetPath !== void 0) {
|
|
186399
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
186537
|
+
this.fsw._symlinkPaths.set(sp.resolve(path27), targetPath);
|
|
186400
186538
|
}
|
|
186401
186539
|
} else {
|
|
186402
186540
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
186403
186541
|
}
|
|
186404
186542
|
ready();
|
|
186405
186543
|
if (closer)
|
|
186406
|
-
this.fsw._addPathCloser(
|
|
186544
|
+
this.fsw._addPathCloser(path27, closer);
|
|
186407
186545
|
return false;
|
|
186408
186546
|
} catch (error) {
|
|
186409
186547
|
if (this.fsw._handleError(error)) {
|
|
186410
186548
|
ready();
|
|
186411
|
-
return
|
|
186549
|
+
return path27;
|
|
186412
186550
|
}
|
|
186413
186551
|
}
|
|
186414
186552
|
}
|
|
@@ -186451,24 +186589,24 @@ function createPattern(matcher) {
|
|
|
186451
186589
|
}
|
|
186452
186590
|
return () => false;
|
|
186453
186591
|
}
|
|
186454
|
-
function normalizePath(
|
|
186455
|
-
if (typeof
|
|
186592
|
+
function normalizePath(path27) {
|
|
186593
|
+
if (typeof path27 !== "string")
|
|
186456
186594
|
throw new Error("string expected");
|
|
186457
|
-
|
|
186458
|
-
|
|
186595
|
+
path27 = sp2.normalize(path27);
|
|
186596
|
+
path27 = path27.replace(/\\/g, "/");
|
|
186459
186597
|
let prepend = false;
|
|
186460
|
-
if (
|
|
186598
|
+
if (path27.startsWith("//"))
|
|
186461
186599
|
prepend = true;
|
|
186462
|
-
|
|
186600
|
+
path27 = path27.replace(DOUBLE_SLASH_RE, "/");
|
|
186463
186601
|
if (prepend)
|
|
186464
|
-
|
|
186465
|
-
return
|
|
186602
|
+
path27 = "/" + path27;
|
|
186603
|
+
return path27;
|
|
186466
186604
|
}
|
|
186467
186605
|
function matchPatterns(patterns, testString, stats) {
|
|
186468
|
-
const
|
|
186606
|
+
const path27 = normalizePath(testString);
|
|
186469
186607
|
for (let index = 0; index < patterns.length; index++) {
|
|
186470
186608
|
const pattern = patterns[index];
|
|
186471
|
-
if (pattern(
|
|
186609
|
+
if (pattern(path27, stats)) {
|
|
186472
186610
|
return true;
|
|
186473
186611
|
}
|
|
186474
186612
|
}
|
|
@@ -186506,19 +186644,19 @@ var toUnix = (string) => {
|
|
|
186506
186644
|
}
|
|
186507
186645
|
return str;
|
|
186508
186646
|
};
|
|
186509
|
-
var normalizePathToUnix = (
|
|
186510
|
-
var normalizeIgnored = (cwd = "") => (
|
|
186511
|
-
if (typeof
|
|
186512
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
186647
|
+
var normalizePathToUnix = (path27) => toUnix(sp2.normalize(toUnix(path27)));
|
|
186648
|
+
var normalizeIgnored = (cwd = "") => (path27) => {
|
|
186649
|
+
if (typeof path27 === "string") {
|
|
186650
|
+
return normalizePathToUnix(sp2.isAbsolute(path27) ? path27 : sp2.join(cwd, path27));
|
|
186513
186651
|
} else {
|
|
186514
|
-
return
|
|
186652
|
+
return path27;
|
|
186515
186653
|
}
|
|
186516
186654
|
};
|
|
186517
|
-
var getAbsolutePath = (
|
|
186518
|
-
if (sp2.isAbsolute(
|
|
186519
|
-
return
|
|
186655
|
+
var getAbsolutePath = (path27, cwd) => {
|
|
186656
|
+
if (sp2.isAbsolute(path27)) {
|
|
186657
|
+
return path27;
|
|
186520
186658
|
}
|
|
186521
|
-
return sp2.join(cwd,
|
|
186659
|
+
return sp2.join(cwd, path27);
|
|
186522
186660
|
};
|
|
186523
186661
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
186524
186662
|
var DirEntry = class {
|
|
@@ -186583,10 +186721,10 @@ var WatchHelper = class {
|
|
|
186583
186721
|
dirParts;
|
|
186584
186722
|
followSymlinks;
|
|
186585
186723
|
statMethod;
|
|
186586
|
-
constructor(
|
|
186724
|
+
constructor(path27, follow, fsw) {
|
|
186587
186725
|
this.fsw = fsw;
|
|
186588
|
-
const watchPath =
|
|
186589
|
-
this.path =
|
|
186726
|
+
const watchPath = path27;
|
|
186727
|
+
this.path = path27 = path27.replace(REPLACER_RE, "");
|
|
186590
186728
|
this.watchPath = watchPath;
|
|
186591
186729
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
186592
186730
|
this.dirParts = [];
|
|
@@ -186726,20 +186864,20 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186726
186864
|
this._closePromise = void 0;
|
|
186727
186865
|
let paths = unifyPaths(paths_);
|
|
186728
186866
|
if (cwd) {
|
|
186729
|
-
paths = paths.map((
|
|
186730
|
-
const absPath = getAbsolutePath(
|
|
186867
|
+
paths = paths.map((path27) => {
|
|
186868
|
+
const absPath = getAbsolutePath(path27, cwd);
|
|
186731
186869
|
return absPath;
|
|
186732
186870
|
});
|
|
186733
186871
|
}
|
|
186734
|
-
paths.forEach((
|
|
186735
|
-
this._removeIgnoredPath(
|
|
186872
|
+
paths.forEach((path27) => {
|
|
186873
|
+
this._removeIgnoredPath(path27);
|
|
186736
186874
|
});
|
|
186737
186875
|
this._userIgnored = void 0;
|
|
186738
186876
|
if (!this._readyCount)
|
|
186739
186877
|
this._readyCount = 0;
|
|
186740
186878
|
this._readyCount += paths.length;
|
|
186741
|
-
Promise.all(paths.map(async (
|
|
186742
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
186879
|
+
Promise.all(paths.map(async (path27) => {
|
|
186880
|
+
const res = await this._nodeFsHandler._addToNodeFs(path27, !_internal, void 0, 0, _origAdd);
|
|
186743
186881
|
if (res)
|
|
186744
186882
|
this._emitReady();
|
|
186745
186883
|
return res;
|
|
@@ -186761,17 +186899,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186761
186899
|
return this;
|
|
186762
186900
|
const paths = unifyPaths(paths_);
|
|
186763
186901
|
const { cwd } = this.options;
|
|
186764
|
-
paths.forEach((
|
|
186765
|
-
if (!sp2.isAbsolute(
|
|
186902
|
+
paths.forEach((path27) => {
|
|
186903
|
+
if (!sp2.isAbsolute(path27) && !this._closers.has(path27)) {
|
|
186766
186904
|
if (cwd)
|
|
186767
|
-
|
|
186768
|
-
|
|
186905
|
+
path27 = sp2.join(cwd, path27);
|
|
186906
|
+
path27 = sp2.resolve(path27);
|
|
186769
186907
|
}
|
|
186770
|
-
this._closePath(
|
|
186771
|
-
this._addIgnoredPath(
|
|
186772
|
-
if (this._watched.has(
|
|
186908
|
+
this._closePath(path27);
|
|
186909
|
+
this._addIgnoredPath(path27);
|
|
186910
|
+
if (this._watched.has(path27)) {
|
|
186773
186911
|
this._addIgnoredPath({
|
|
186774
|
-
path:
|
|
186912
|
+
path: path27,
|
|
186775
186913
|
recursive: true
|
|
186776
186914
|
});
|
|
186777
186915
|
}
|
|
@@ -186835,38 +186973,38 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186835
186973
|
* @param stats arguments to be passed with event
|
|
186836
186974
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
186837
186975
|
*/
|
|
186838
|
-
async _emit(event,
|
|
186976
|
+
async _emit(event, path27, stats) {
|
|
186839
186977
|
if (this.closed)
|
|
186840
186978
|
return;
|
|
186841
186979
|
const opts = this.options;
|
|
186842
186980
|
if (isWindows)
|
|
186843
|
-
|
|
186981
|
+
path27 = sp2.normalize(path27);
|
|
186844
186982
|
if (opts.cwd)
|
|
186845
|
-
|
|
186846
|
-
const args = [
|
|
186983
|
+
path27 = sp2.relative(opts.cwd, path27);
|
|
186984
|
+
const args = [path27];
|
|
186847
186985
|
if (stats != null)
|
|
186848
186986
|
args.push(stats);
|
|
186849
186987
|
const awf = opts.awaitWriteFinish;
|
|
186850
186988
|
let pw;
|
|
186851
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
186989
|
+
if (awf && (pw = this._pendingWrites.get(path27))) {
|
|
186852
186990
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
186853
186991
|
return this;
|
|
186854
186992
|
}
|
|
186855
186993
|
if (opts.atomic) {
|
|
186856
186994
|
if (event === EVENTS.UNLINK) {
|
|
186857
|
-
this._pendingUnlinks.set(
|
|
186995
|
+
this._pendingUnlinks.set(path27, [event, ...args]);
|
|
186858
186996
|
setTimeout(() => {
|
|
186859
|
-
this._pendingUnlinks.forEach((entry,
|
|
186997
|
+
this._pendingUnlinks.forEach((entry, path28) => {
|
|
186860
186998
|
this.emit(...entry);
|
|
186861
186999
|
this.emit(EVENTS.ALL, ...entry);
|
|
186862
|
-
this._pendingUnlinks.delete(
|
|
187000
|
+
this._pendingUnlinks.delete(path28);
|
|
186863
187001
|
});
|
|
186864
187002
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
186865
187003
|
return this;
|
|
186866
187004
|
}
|
|
186867
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
187005
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path27)) {
|
|
186868
187006
|
event = EVENTS.CHANGE;
|
|
186869
|
-
this._pendingUnlinks.delete(
|
|
187007
|
+
this._pendingUnlinks.delete(path27);
|
|
186870
187008
|
}
|
|
186871
187009
|
}
|
|
186872
187010
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -186884,16 +187022,16 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186884
187022
|
this.emitWithAll(event, args);
|
|
186885
187023
|
}
|
|
186886
187024
|
};
|
|
186887
|
-
this._awaitWriteFinish(
|
|
187025
|
+
this._awaitWriteFinish(path27, awf.stabilityThreshold, event, awfEmit);
|
|
186888
187026
|
return this;
|
|
186889
187027
|
}
|
|
186890
187028
|
if (event === EVENTS.CHANGE) {
|
|
186891
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
187029
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path27, 50);
|
|
186892
187030
|
if (isThrottled)
|
|
186893
187031
|
return this;
|
|
186894
187032
|
}
|
|
186895
187033
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
186896
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
187034
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path27) : path27;
|
|
186897
187035
|
let stats2;
|
|
186898
187036
|
try {
|
|
186899
187037
|
stats2 = await stat3(fullPath);
|
|
@@ -186924,23 +187062,23 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186924
187062
|
* @param timeout duration of time to suppress duplicate actions
|
|
186925
187063
|
* @returns tracking object or false if action should be suppressed
|
|
186926
187064
|
*/
|
|
186927
|
-
_throttle(actionType,
|
|
187065
|
+
_throttle(actionType, path27, timeout) {
|
|
186928
187066
|
if (!this._throttled.has(actionType)) {
|
|
186929
187067
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
186930
187068
|
}
|
|
186931
187069
|
const action = this._throttled.get(actionType);
|
|
186932
187070
|
if (!action)
|
|
186933
187071
|
throw new Error("invalid throttle");
|
|
186934
|
-
const actionPath = action.get(
|
|
187072
|
+
const actionPath = action.get(path27);
|
|
186935
187073
|
if (actionPath) {
|
|
186936
187074
|
actionPath.count++;
|
|
186937
187075
|
return false;
|
|
186938
187076
|
}
|
|
186939
187077
|
let timeoutObject;
|
|
186940
187078
|
const clear = () => {
|
|
186941
|
-
const item = action.get(
|
|
187079
|
+
const item = action.get(path27);
|
|
186942
187080
|
const count = item ? item.count : 0;
|
|
186943
|
-
action.delete(
|
|
187081
|
+
action.delete(path27);
|
|
186944
187082
|
clearTimeout(timeoutObject);
|
|
186945
187083
|
if (item)
|
|
186946
187084
|
clearTimeout(item.timeoutObject);
|
|
@@ -186948,7 +187086,7 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186948
187086
|
};
|
|
186949
187087
|
timeoutObject = setTimeout(clear, timeout);
|
|
186950
187088
|
const thr = { timeoutObject, clear, count: 0 };
|
|
186951
|
-
action.set(
|
|
187089
|
+
action.set(path27, thr);
|
|
186952
187090
|
return thr;
|
|
186953
187091
|
}
|
|
186954
187092
|
_incrReadyCount() {
|
|
@@ -186962,44 +187100,44 @@ var FSWatcher = class extends EventEmitter {
|
|
|
186962
187100
|
* @param event
|
|
186963
187101
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
186964
187102
|
*/
|
|
186965
|
-
_awaitWriteFinish(
|
|
187103
|
+
_awaitWriteFinish(path27, threshold, event, awfEmit) {
|
|
186966
187104
|
const awf = this.options.awaitWriteFinish;
|
|
186967
187105
|
if (typeof awf !== "object")
|
|
186968
187106
|
return;
|
|
186969
187107
|
const pollInterval = awf.pollInterval;
|
|
186970
187108
|
let timeoutHandler;
|
|
186971
|
-
let fullPath =
|
|
186972
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
186973
|
-
fullPath = sp2.join(this.options.cwd,
|
|
187109
|
+
let fullPath = path27;
|
|
187110
|
+
if (this.options.cwd && !sp2.isAbsolute(path27)) {
|
|
187111
|
+
fullPath = sp2.join(this.options.cwd, path27);
|
|
186974
187112
|
}
|
|
186975
187113
|
const now = /* @__PURE__ */ new Date();
|
|
186976
187114
|
const writes = this._pendingWrites;
|
|
186977
187115
|
function awaitWriteFinishFn(prevStat) {
|
|
186978
187116
|
statcb(fullPath, (err, curStat) => {
|
|
186979
|
-
if (err || !writes.has(
|
|
187117
|
+
if (err || !writes.has(path27)) {
|
|
186980
187118
|
if (err && err.code !== "ENOENT")
|
|
186981
187119
|
awfEmit(err);
|
|
186982
187120
|
return;
|
|
186983
187121
|
}
|
|
186984
187122
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
186985
187123
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
186986
|
-
writes.get(
|
|
187124
|
+
writes.get(path27).lastChange = now2;
|
|
186987
187125
|
}
|
|
186988
|
-
const pw = writes.get(
|
|
187126
|
+
const pw = writes.get(path27);
|
|
186989
187127
|
const df = now2 - pw.lastChange;
|
|
186990
187128
|
if (df >= threshold) {
|
|
186991
|
-
writes.delete(
|
|
187129
|
+
writes.delete(path27);
|
|
186992
187130
|
awfEmit(void 0, curStat);
|
|
186993
187131
|
} else {
|
|
186994
187132
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
186995
187133
|
}
|
|
186996
187134
|
});
|
|
186997
187135
|
}
|
|
186998
|
-
if (!writes.has(
|
|
186999
|
-
writes.set(
|
|
187136
|
+
if (!writes.has(path27)) {
|
|
187137
|
+
writes.set(path27, {
|
|
187000
187138
|
lastChange: now,
|
|
187001
187139
|
cancelWait: () => {
|
|
187002
|
-
writes.delete(
|
|
187140
|
+
writes.delete(path27);
|
|
187003
187141
|
clearTimeout(timeoutHandler);
|
|
187004
187142
|
return event;
|
|
187005
187143
|
}
|
|
@@ -187010,8 +187148,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
187010
187148
|
/**
|
|
187011
187149
|
* Determines whether user has asked to ignore this path.
|
|
187012
187150
|
*/
|
|
187013
|
-
_isIgnored(
|
|
187014
|
-
if (this.options.atomic && DOT_RE.test(
|
|
187151
|
+
_isIgnored(path27, stats) {
|
|
187152
|
+
if (this.options.atomic && DOT_RE.test(path27))
|
|
187015
187153
|
return true;
|
|
187016
187154
|
if (!this._userIgnored) {
|
|
187017
187155
|
const { cwd } = this.options;
|
|
@@ -187021,17 +187159,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
187021
187159
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
187022
187160
|
this._userIgnored = anymatch(list, void 0);
|
|
187023
187161
|
}
|
|
187024
|
-
return this._userIgnored(
|
|
187162
|
+
return this._userIgnored(path27, stats);
|
|
187025
187163
|
}
|
|
187026
|
-
_isntIgnored(
|
|
187027
|
-
return !this._isIgnored(
|
|
187164
|
+
_isntIgnored(path27, stat4) {
|
|
187165
|
+
return !this._isIgnored(path27, stat4);
|
|
187028
187166
|
}
|
|
187029
187167
|
/**
|
|
187030
187168
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
187031
187169
|
* @param path file or directory pattern being watched
|
|
187032
187170
|
*/
|
|
187033
|
-
_getWatchHelpers(
|
|
187034
|
-
return new WatchHelper(
|
|
187171
|
+
_getWatchHelpers(path27) {
|
|
187172
|
+
return new WatchHelper(path27, this.options.followSymlinks, this);
|
|
187035
187173
|
}
|
|
187036
187174
|
// Directory helpers
|
|
187037
187175
|
// -----------------
|
|
@@ -187063,63 +187201,63 @@ var FSWatcher = class extends EventEmitter {
|
|
|
187063
187201
|
* @param item base path of item/directory
|
|
187064
187202
|
*/
|
|
187065
187203
|
_remove(directory, item, isDirectory) {
|
|
187066
|
-
const
|
|
187067
|
-
const fullPath = sp2.resolve(
|
|
187068
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
187069
|
-
if (!this._throttle("remove",
|
|
187204
|
+
const path27 = sp2.join(directory, item);
|
|
187205
|
+
const fullPath = sp2.resolve(path27);
|
|
187206
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path27) || this._watched.has(fullPath);
|
|
187207
|
+
if (!this._throttle("remove", path27, 100))
|
|
187070
187208
|
return;
|
|
187071
187209
|
if (!isDirectory && this._watched.size === 1) {
|
|
187072
187210
|
this.add(directory, item, true);
|
|
187073
187211
|
}
|
|
187074
|
-
const wp = this._getWatchedDir(
|
|
187212
|
+
const wp = this._getWatchedDir(path27);
|
|
187075
187213
|
const nestedDirectoryChildren = wp.getChildren();
|
|
187076
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
187214
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path27, nested));
|
|
187077
187215
|
const parent = this._getWatchedDir(directory);
|
|
187078
187216
|
const wasTracked = parent.has(item);
|
|
187079
187217
|
parent.remove(item);
|
|
187080
187218
|
if (this._symlinkPaths.has(fullPath)) {
|
|
187081
187219
|
this._symlinkPaths.delete(fullPath);
|
|
187082
187220
|
}
|
|
187083
|
-
let relPath =
|
|
187221
|
+
let relPath = path27;
|
|
187084
187222
|
if (this.options.cwd)
|
|
187085
|
-
relPath = sp2.relative(this.options.cwd,
|
|
187223
|
+
relPath = sp2.relative(this.options.cwd, path27);
|
|
187086
187224
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
187087
187225
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
187088
187226
|
if (event === EVENTS.ADD)
|
|
187089
187227
|
return;
|
|
187090
187228
|
}
|
|
187091
|
-
this._watched.delete(
|
|
187229
|
+
this._watched.delete(path27);
|
|
187092
187230
|
this._watched.delete(fullPath);
|
|
187093
187231
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
187094
|
-
if (wasTracked && !this._isIgnored(
|
|
187095
|
-
this._emit(eventName,
|
|
187096
|
-
this._closePath(
|
|
187232
|
+
if (wasTracked && !this._isIgnored(path27))
|
|
187233
|
+
this._emit(eventName, path27);
|
|
187234
|
+
this._closePath(path27);
|
|
187097
187235
|
}
|
|
187098
187236
|
/**
|
|
187099
187237
|
* Closes all watchers for a path
|
|
187100
187238
|
*/
|
|
187101
|
-
_closePath(
|
|
187102
|
-
this._closeFile(
|
|
187103
|
-
const dir = sp2.dirname(
|
|
187104
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
187239
|
+
_closePath(path27) {
|
|
187240
|
+
this._closeFile(path27);
|
|
187241
|
+
const dir = sp2.dirname(path27);
|
|
187242
|
+
this._getWatchedDir(dir).remove(sp2.basename(path27));
|
|
187105
187243
|
}
|
|
187106
187244
|
/**
|
|
187107
187245
|
* Closes only file-specific watchers
|
|
187108
187246
|
*/
|
|
187109
|
-
_closeFile(
|
|
187110
|
-
const closers = this._closers.get(
|
|
187247
|
+
_closeFile(path27) {
|
|
187248
|
+
const closers = this._closers.get(path27);
|
|
187111
187249
|
if (!closers)
|
|
187112
187250
|
return;
|
|
187113
187251
|
closers.forEach((closer) => closer());
|
|
187114
|
-
this._closers.delete(
|
|
187252
|
+
this._closers.delete(path27);
|
|
187115
187253
|
}
|
|
187116
|
-
_addPathCloser(
|
|
187254
|
+
_addPathCloser(path27, closer) {
|
|
187117
187255
|
if (!closer)
|
|
187118
187256
|
return;
|
|
187119
|
-
let list = this._closers.get(
|
|
187257
|
+
let list = this._closers.get(path27);
|
|
187120
187258
|
if (!list) {
|
|
187121
187259
|
list = [];
|
|
187122
|
-
this._closers.set(
|
|
187260
|
+
this._closers.set(path27, list);
|
|
187123
187261
|
}
|
|
187124
187262
|
list.push(closer);
|
|
187125
187263
|
}
|
|
@@ -187168,8 +187306,8 @@ var PortAllocator = class {
|
|
|
187168
187306
|
};
|
|
187169
187307
|
|
|
187170
187308
|
// src/lib/dev/stable-port-allocator.ts
|
|
187171
|
-
import * as
|
|
187172
|
-
import * as
|
|
187309
|
+
import * as fs14 from "fs";
|
|
187310
|
+
import * as path10 from "path";
|
|
187173
187311
|
var PORT_RANGE_START2 = 4e4;
|
|
187174
187312
|
var PORT_RANGE_END2 = 49999;
|
|
187175
187313
|
var StablePortAllocator = class {
|
|
@@ -187178,16 +187316,16 @@ var StablePortAllocator = class {
|
|
|
187178
187316
|
savedPorts = {};
|
|
187179
187317
|
usedPorts = /* @__PURE__ */ new Set();
|
|
187180
187318
|
constructor(projectRoot, key = "default") {
|
|
187181
|
-
this.portsDir =
|
|
187182
|
-
this.portsFilePath =
|
|
187319
|
+
this.portsDir = path10.join(projectRoot, ".specific", "keys", key);
|
|
187320
|
+
this.portsFilePath = path10.join(this.portsDir, "ports.json");
|
|
187183
187321
|
this.loadPorts();
|
|
187184
187322
|
}
|
|
187185
187323
|
loadPorts() {
|
|
187186
|
-
if (!
|
|
187324
|
+
if (!fs14.existsSync(this.portsFilePath)) {
|
|
187187
187325
|
return;
|
|
187188
187326
|
}
|
|
187189
187327
|
try {
|
|
187190
|
-
const content =
|
|
187328
|
+
const content = fs14.readFileSync(this.portsFilePath, "utf-8");
|
|
187191
187329
|
const data = JSON.parse(content);
|
|
187192
187330
|
if (data.version === 1 && data.ports) {
|
|
187193
187331
|
this.savedPorts = data.ports;
|
|
@@ -187200,14 +187338,14 @@ var StablePortAllocator = class {
|
|
|
187200
187338
|
}
|
|
187201
187339
|
}
|
|
187202
187340
|
savePorts() {
|
|
187203
|
-
if (!
|
|
187204
|
-
|
|
187341
|
+
if (!fs14.existsSync(this.portsDir)) {
|
|
187342
|
+
fs14.mkdirSync(this.portsDir, { recursive: true });
|
|
187205
187343
|
}
|
|
187206
187344
|
const data = {
|
|
187207
187345
|
version: 1,
|
|
187208
187346
|
ports: this.savedPorts
|
|
187209
187347
|
};
|
|
187210
|
-
|
|
187348
|
+
fs14.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
|
|
187211
187349
|
}
|
|
187212
187350
|
allocateRandom() {
|
|
187213
187351
|
const rangeSize = PORT_RANGE_END2 - PORT_RANGE_START2 + 1;
|
|
@@ -187234,21 +187372,21 @@ var StablePortAllocator = class {
|
|
|
187234
187372
|
};
|
|
187235
187373
|
|
|
187236
187374
|
// src/lib/dev/database-manager.ts
|
|
187237
|
-
import * as
|
|
187238
|
-
import * as
|
|
187375
|
+
import * as fs15 from "fs";
|
|
187376
|
+
import * as path11 from "path";
|
|
187239
187377
|
import * as net from "net";
|
|
187240
187378
|
import { spawn } from "child_process";
|
|
187241
187379
|
async function startPostgres(pg, port, dataDir, onProgress) {
|
|
187242
187380
|
const binary = await ensureBinary(postgresBinary, void 0, onProgress);
|
|
187243
|
-
const dbDataPath =
|
|
187381
|
+
const dbDataPath = path11.join(process.cwd(), dataDir, pg.name);
|
|
187244
187382
|
const host = "127.0.0.1";
|
|
187245
187383
|
const user = "postgres";
|
|
187246
187384
|
const password = "postgres";
|
|
187247
187385
|
const libraryEnv = getLibraryEnv(binary);
|
|
187248
187386
|
const env2 = { ...process.env, ...libraryEnv };
|
|
187249
|
-
const dataExists =
|
|
187387
|
+
const dataExists = fs15.existsSync(dbDataPath);
|
|
187250
187388
|
if (!dataExists) {
|
|
187251
|
-
|
|
187389
|
+
fs15.mkdirSync(dbDataPath, { recursive: true });
|
|
187252
187390
|
await runCommand(
|
|
187253
187391
|
binary.executables["initdb"],
|
|
187254
187392
|
["-D", dbDataPath, "-U", user, "--auth=trust", "--no-locale", "-E", "UTF8"],
|
|
@@ -187324,9 +187462,9 @@ async function startRedis(redis, port, onProgress) {
|
|
|
187324
187462
|
}
|
|
187325
187463
|
async function startStorage(storage, port, dataDir) {
|
|
187326
187464
|
const S3rver = (await import("s3rver")).default;
|
|
187327
|
-
const storageDataPath =
|
|
187328
|
-
if (!
|
|
187329
|
-
|
|
187465
|
+
const storageDataPath = path11.join(process.cwd(), dataDir, storage.name);
|
|
187466
|
+
if (!fs15.existsSync(storageDataPath)) {
|
|
187467
|
+
fs15.mkdirSync(storageDataPath, { recursive: true });
|
|
187330
187468
|
}
|
|
187331
187469
|
const host = "127.0.0.1";
|
|
187332
187470
|
const accessKey = "S3RVER";
|
|
@@ -187460,7 +187598,7 @@ import { spawn as spawn2 } from "child_process";
|
|
|
187460
187598
|
// src/lib/local/parser.ts
|
|
187461
187599
|
var import_hcl2_json_parser2 = __toESM(require_dist(), 1);
|
|
187462
187600
|
import { readFile, writeFile } from "fs/promises";
|
|
187463
|
-
import { existsSync as
|
|
187601
|
+
import { existsSync as existsSync12 } from "fs";
|
|
187464
187602
|
var { parseToObject: parseToObject2 } = import_hcl2_json_parser2.default;
|
|
187465
187603
|
var LOCAL_FILE = "specific.local";
|
|
187466
187604
|
var HEADER_COMMENT = `# Local secrets and configuration
|
|
@@ -187501,7 +187639,7 @@ async function parseLocalFile(content) {
|
|
|
187501
187639
|
return { secrets, configs };
|
|
187502
187640
|
}
|
|
187503
187641
|
async function loadLocal() {
|
|
187504
|
-
if (!
|
|
187642
|
+
if (!existsSync12(LOCAL_FILE)) {
|
|
187505
187643
|
return { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
|
|
187506
187644
|
}
|
|
187507
187645
|
const content = await readFile(LOCAL_FILE, "utf-8");
|
|
@@ -187541,7 +187679,7 @@ ${newLine}
|
|
|
187541
187679
|
}
|
|
187542
187680
|
async function saveLocalSecret(name, value) {
|
|
187543
187681
|
let content = "";
|
|
187544
|
-
if (
|
|
187682
|
+
if (existsSync12(LOCAL_FILE)) {
|
|
187545
187683
|
content = await readFile(LOCAL_FILE, "utf-8");
|
|
187546
187684
|
} else {
|
|
187547
187685
|
content = HEADER_COMMENT;
|
|
@@ -187551,7 +187689,7 @@ async function saveLocalSecret(name, value) {
|
|
|
187551
187689
|
}
|
|
187552
187690
|
async function saveLocalConfig(name, value) {
|
|
187553
187691
|
let content = "";
|
|
187554
|
-
if (
|
|
187692
|
+
if (existsSync12(LOCAL_FILE)) {
|
|
187555
187693
|
content = await readFile(LOCAL_FILE, "utf-8");
|
|
187556
187694
|
} else {
|
|
187557
187695
|
content = HEADER_COMMENT;
|
|
@@ -187915,8 +188053,8 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
|
|
|
187915
188053
|
}
|
|
187916
188054
|
|
|
187917
188055
|
// src/lib/dev/instance-state.ts
|
|
187918
|
-
import * as
|
|
187919
|
-
import * as
|
|
188056
|
+
import * as fs16 from "fs";
|
|
188057
|
+
import * as path12 from "path";
|
|
187920
188058
|
var InstanceStateManager = class {
|
|
187921
188059
|
stateDir;
|
|
187922
188060
|
statePath;
|
|
@@ -187925,16 +188063,16 @@ var InstanceStateManager = class {
|
|
|
187925
188063
|
key;
|
|
187926
188064
|
constructor(projectRoot, key = "default") {
|
|
187927
188065
|
this.key = key;
|
|
187928
|
-
this.stateDir =
|
|
187929
|
-
this.statePath =
|
|
187930
|
-
this.lockPath =
|
|
188066
|
+
this.stateDir = path12.join(projectRoot, ".specific", "keys", key);
|
|
188067
|
+
this.statePath = path12.join(this.stateDir, "state.json");
|
|
188068
|
+
this.lockPath = path12.join(this.stateDir, "state.lock");
|
|
187931
188069
|
}
|
|
187932
188070
|
getKey() {
|
|
187933
188071
|
return this.key;
|
|
187934
188072
|
}
|
|
187935
188073
|
ensureStateDir() {
|
|
187936
|
-
if (!
|
|
187937
|
-
|
|
188074
|
+
if (!fs16.existsSync(this.stateDir)) {
|
|
188075
|
+
fs16.mkdirSync(this.stateDir, { recursive: true });
|
|
187938
188076
|
}
|
|
187939
188077
|
}
|
|
187940
188078
|
isProcessRunning(pid) {
|
|
@@ -187951,15 +188089,15 @@ var InstanceStateManager = class {
|
|
|
187951
188089
|
const startTime = Date.now();
|
|
187952
188090
|
while (Date.now() - startTime < timeoutMs) {
|
|
187953
188091
|
try {
|
|
187954
|
-
const fd =
|
|
188092
|
+
const fd = fs16.openSync(
|
|
187955
188093
|
this.lockPath,
|
|
187956
|
-
|
|
188094
|
+
fs16.constants.O_CREAT | fs16.constants.O_EXCL | fs16.constants.O_WRONLY
|
|
187957
188095
|
);
|
|
187958
|
-
|
|
187959
|
-
|
|
188096
|
+
fs16.writeSync(fd, String(process.pid));
|
|
188097
|
+
fs16.closeSync(fd);
|
|
187960
188098
|
return () => {
|
|
187961
188099
|
try {
|
|
187962
|
-
|
|
188100
|
+
fs16.unlinkSync(this.lockPath);
|
|
187963
188101
|
} catch {
|
|
187964
188102
|
}
|
|
187965
188103
|
};
|
|
@@ -187968,16 +188106,16 @@ var InstanceStateManager = class {
|
|
|
187968
188106
|
if (err.code === "EEXIST") {
|
|
187969
188107
|
try {
|
|
187970
188108
|
const lockPid = parseInt(
|
|
187971
|
-
|
|
188109
|
+
fs16.readFileSync(this.lockPath, "utf-8").trim(),
|
|
187972
188110
|
10
|
|
187973
188111
|
);
|
|
187974
188112
|
if (!this.isProcessRunning(lockPid)) {
|
|
187975
|
-
|
|
188113
|
+
fs16.unlinkSync(this.lockPath);
|
|
187976
188114
|
continue;
|
|
187977
188115
|
}
|
|
187978
188116
|
} catch {
|
|
187979
188117
|
try {
|
|
187980
|
-
|
|
188118
|
+
fs16.unlinkSync(this.lockPath);
|
|
187981
188119
|
} catch {
|
|
187982
188120
|
}
|
|
187983
188121
|
continue;
|
|
@@ -187991,12 +188129,12 @@ var InstanceStateManager = class {
|
|
|
187991
188129
|
throw new Error("Failed to acquire state lock (timeout)");
|
|
187992
188130
|
}
|
|
187993
188131
|
async getExistingInstances() {
|
|
187994
|
-
if (!
|
|
188132
|
+
if (!fs16.existsSync(this.statePath)) {
|
|
187995
188133
|
return null;
|
|
187996
188134
|
}
|
|
187997
188135
|
const releaseLock = await this.acquireLock();
|
|
187998
188136
|
try {
|
|
187999
|
-
const content =
|
|
188137
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
188000
188138
|
const state = JSON.parse(content);
|
|
188001
188139
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
188002
188140
|
return null;
|
|
@@ -188009,21 +188147,21 @@ var InstanceStateManager = class {
|
|
|
188009
188147
|
}
|
|
188010
188148
|
}
|
|
188011
188149
|
async cleanStaleState() {
|
|
188012
|
-
if (!
|
|
188150
|
+
if (!fs16.existsSync(this.statePath)) {
|
|
188013
188151
|
return false;
|
|
188014
188152
|
}
|
|
188015
188153
|
const releaseLock = await this.acquireLock();
|
|
188016
188154
|
try {
|
|
188017
|
-
const content =
|
|
188155
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
188018
188156
|
const state = JSON.parse(content);
|
|
188019
188157
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
188020
|
-
|
|
188158
|
+
fs16.unlinkSync(this.statePath);
|
|
188021
188159
|
return true;
|
|
188022
188160
|
}
|
|
188023
188161
|
return false;
|
|
188024
188162
|
} catch {
|
|
188025
188163
|
try {
|
|
188026
|
-
|
|
188164
|
+
fs16.unlinkSync(this.statePath);
|
|
188027
188165
|
return true;
|
|
188028
188166
|
} catch {
|
|
188029
188167
|
}
|
|
@@ -188035,8 +188173,8 @@ var InstanceStateManager = class {
|
|
|
188035
188173
|
async claimOwnership(command) {
|
|
188036
188174
|
const releaseLock = await this.acquireLock();
|
|
188037
188175
|
try {
|
|
188038
|
-
if (
|
|
188039
|
-
const content =
|
|
188176
|
+
if (fs16.existsSync(this.statePath)) {
|
|
188177
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
188040
188178
|
const state2 = JSON.parse(content);
|
|
188041
188179
|
if (this.isProcessRunning(state2.owner.pid)) {
|
|
188042
188180
|
throw new Error(`Instances already owned by PID ${state2.owner.pid}`);
|
|
@@ -188105,8 +188243,8 @@ var InstanceStateManager = class {
|
|
|
188105
188243
|
}
|
|
188106
188244
|
const releaseLock = await this.acquireLock();
|
|
188107
188245
|
try {
|
|
188108
|
-
if (
|
|
188109
|
-
|
|
188246
|
+
if (fs16.existsSync(this.statePath)) {
|
|
188247
|
+
fs16.unlinkSync(this.statePath);
|
|
188110
188248
|
}
|
|
188111
188249
|
this.ownsInstances = false;
|
|
188112
188250
|
} finally {
|
|
@@ -188114,26 +188252,26 @@ var InstanceStateManager = class {
|
|
|
188114
188252
|
}
|
|
188115
188253
|
}
|
|
188116
188254
|
readState() {
|
|
188117
|
-
const content =
|
|
188255
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
188118
188256
|
return JSON.parse(content);
|
|
188119
188257
|
}
|
|
188120
188258
|
writeStateAtomic(state) {
|
|
188121
188259
|
this.ensureStateDir();
|
|
188122
188260
|
const tmpPath = this.statePath + ".tmp";
|
|
188123
|
-
|
|
188124
|
-
|
|
188261
|
+
fs16.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
|
|
188262
|
+
fs16.renameSync(tmpPath, this.statePath);
|
|
188125
188263
|
}
|
|
188126
188264
|
};
|
|
188127
188265
|
|
|
188128
188266
|
// src/lib/dev/http-proxy.ts
|
|
188129
188267
|
import * as http from "http";
|
|
188130
188268
|
import * as https from "https";
|
|
188131
|
-
import * as
|
|
188132
|
-
import * as
|
|
188269
|
+
import * as fs17 from "fs";
|
|
188270
|
+
import * as path13 from "path";
|
|
188133
188271
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
188134
188272
|
import httpProxy from "http-proxy";
|
|
188135
|
-
var __dirname3 =
|
|
188136
|
-
var adminDir =
|
|
188273
|
+
var __dirname3 = path13.dirname(fileURLToPath3(import.meta.url));
|
|
188274
|
+
var adminDir = path13.join(__dirname3, "admin");
|
|
188137
188275
|
var HTTP_PORT = 80;
|
|
188138
188276
|
var HTTPS_PORT = 443;
|
|
188139
188277
|
var DOMAIN_SUFFIX = ".local.spcf.app";
|
|
@@ -188419,18 +188557,18 @@ function serveStaticFile(res, pathname) {
|
|
|
188419
188557
|
filePath = filePath + "index.html";
|
|
188420
188558
|
}
|
|
188421
188559
|
const relativePath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
188422
|
-
const fullPath =
|
|
188423
|
-
const resolvedPath =
|
|
188424
|
-
const resolvedAdminDir =
|
|
188560
|
+
const fullPath = path13.join(adminDir, relativePath);
|
|
188561
|
+
const resolvedPath = path13.resolve(fullPath);
|
|
188562
|
+
const resolvedAdminDir = path13.resolve(adminDir);
|
|
188425
188563
|
if (!resolvedPath.startsWith(resolvedAdminDir)) {
|
|
188426
188564
|
res.writeHead(403, { "Content-Type": "text/html" });
|
|
188427
188565
|
res.end("<h1>Forbidden</h1>");
|
|
188428
188566
|
return;
|
|
188429
188567
|
}
|
|
188430
|
-
if (
|
|
188431
|
-
if (
|
|
188432
|
-
const indexPath2 =
|
|
188433
|
-
if (
|
|
188568
|
+
if (fs17.existsSync(resolvedPath)) {
|
|
188569
|
+
if (fs17.statSync(resolvedPath).isDirectory()) {
|
|
188570
|
+
const indexPath2 = path13.join(resolvedPath, "index.html");
|
|
188571
|
+
if (fs17.existsSync(indexPath2)) {
|
|
188434
188572
|
return serveFile(res, indexPath2);
|
|
188435
188573
|
}
|
|
188436
188574
|
} else {
|
|
@@ -188438,28 +188576,28 @@ function serveStaticFile(res, pathname) {
|
|
|
188438
188576
|
}
|
|
188439
188577
|
}
|
|
188440
188578
|
const htmlPath = resolvedPath + ".html";
|
|
188441
|
-
if (
|
|
188579
|
+
if (fs17.existsSync(htmlPath)) {
|
|
188442
188580
|
return serveFile(res, htmlPath);
|
|
188443
188581
|
}
|
|
188444
|
-
const indexPath =
|
|
188445
|
-
if (
|
|
188582
|
+
const indexPath = path13.join(resolvedPath, "index.html");
|
|
188583
|
+
if (fs17.existsSync(indexPath)) {
|
|
188446
188584
|
return serveFile(res, indexPath);
|
|
188447
188585
|
}
|
|
188448
|
-
const notFoundPath =
|
|
188449
|
-
if (
|
|
188586
|
+
const notFoundPath = path13.join(adminDir, "404.html");
|
|
188587
|
+
if (fs17.existsSync(notFoundPath)) {
|
|
188450
188588
|
return serveFileContent(res, notFoundPath, "text/html", 404);
|
|
188451
188589
|
}
|
|
188452
188590
|
res.writeHead(404, { "Content-Type": "text/html" });
|
|
188453
188591
|
res.end("<h1>Not Found</h1>");
|
|
188454
188592
|
}
|
|
188455
188593
|
function serveFile(res, filePath) {
|
|
188456
|
-
const ext =
|
|
188594
|
+
const ext = path13.extname(filePath).toLowerCase();
|
|
188457
188595
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
188458
188596
|
serveFileContent(res, filePath, contentType, 200);
|
|
188459
188597
|
}
|
|
188460
188598
|
function serveFileContent(res, filePath, contentType, statusCode = 200) {
|
|
188461
188599
|
try {
|
|
188462
|
-
const content =
|
|
188600
|
+
const content = fs17.readFileSync(filePath);
|
|
188463
188601
|
res.writeHead(statusCode, { "Content-Type": contentType });
|
|
188464
188602
|
res.end(content);
|
|
188465
188603
|
} catch (err) {
|
|
@@ -188519,8 +188657,8 @@ import { spawn as spawn3 } from "child_process";
|
|
|
188519
188657
|
|
|
188520
188658
|
// src/lib/secrets/parser.ts
|
|
188521
188659
|
import { readFile as readFile2, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
188522
|
-
import { existsSync as
|
|
188523
|
-
import * as
|
|
188660
|
+
import { existsSync as existsSync15 } from "fs";
|
|
188661
|
+
import * as path14 from "path";
|
|
188524
188662
|
import * as crypto2 from "crypto";
|
|
188525
188663
|
var GENERATED_SECRETS_FILE = ".specific/generated-secrets.json";
|
|
188526
188664
|
async function loadSecrets() {
|
|
@@ -188537,7 +188675,7 @@ function generateRandomString(length = 64) {
|
|
|
188537
188675
|
return result;
|
|
188538
188676
|
}
|
|
188539
188677
|
async function loadGeneratedSecrets() {
|
|
188540
|
-
if (!
|
|
188678
|
+
if (!existsSync15(GENERATED_SECRETS_FILE)) {
|
|
188541
188679
|
return /* @__PURE__ */ new Map();
|
|
188542
188680
|
}
|
|
188543
188681
|
const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
|
|
@@ -188546,13 +188684,13 @@ async function loadGeneratedSecrets() {
|
|
|
188546
188684
|
}
|
|
188547
188685
|
async function saveGeneratedSecret(name, value) {
|
|
188548
188686
|
let secrets = {};
|
|
188549
|
-
if (
|
|
188687
|
+
if (existsSync15(GENERATED_SECRETS_FILE)) {
|
|
188550
188688
|
const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
|
|
188551
188689
|
secrets = JSON.parse(content);
|
|
188552
188690
|
}
|
|
188553
188691
|
secrets[name] = value;
|
|
188554
|
-
const dir =
|
|
188555
|
-
if (!
|
|
188692
|
+
const dir = path14.dirname(GENERATED_SECRETS_FILE);
|
|
188693
|
+
if (!existsSync15(dir)) {
|
|
188556
188694
|
await mkdir(dir, { recursive: true });
|
|
188557
188695
|
}
|
|
188558
188696
|
await writeFile2(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
|
|
@@ -188706,8 +188844,8 @@ function sleep3(ms) {
|
|
|
188706
188844
|
|
|
188707
188845
|
// src/lib/dev/drizzle-gateway-manager.ts
|
|
188708
188846
|
import * as net3 from "net";
|
|
188709
|
-
import * as
|
|
188710
|
-
import * as
|
|
188847
|
+
import * as fs18 from "fs";
|
|
188848
|
+
import * as path15 from "path";
|
|
188711
188849
|
import { spawn as spawn4 } from "child_process";
|
|
188712
188850
|
import { randomUUID } from "crypto";
|
|
188713
188851
|
function generateStoreJson(postgresInstances) {
|
|
@@ -188739,13 +188877,13 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
|
|
|
188739
188877
|
options2?.onProgress
|
|
188740
188878
|
);
|
|
188741
188879
|
const host = "127.0.0.1";
|
|
188742
|
-
const drizzleConfigDir =
|
|
188743
|
-
if (!
|
|
188744
|
-
|
|
188880
|
+
const drizzleConfigDir = path15.join(configDir, "drizzle-gateway");
|
|
188881
|
+
if (!fs18.existsSync(drizzleConfigDir)) {
|
|
188882
|
+
fs18.mkdirSync(drizzleConfigDir, { recursive: true });
|
|
188745
188883
|
}
|
|
188746
188884
|
const storeJson = generateStoreJson(postgresInstances);
|
|
188747
|
-
const storeJsonPath =
|
|
188748
|
-
|
|
188885
|
+
const storeJsonPath = path15.join(drizzleConfigDir, "store.json");
|
|
188886
|
+
fs18.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
|
|
188749
188887
|
writeLog("drizzle-gateway", `Starting Drizzle Gateway`);
|
|
188750
188888
|
writeLog("drizzle-gateway", `STORE_PATH: ${drizzleConfigDir}`);
|
|
188751
188889
|
writeLog("drizzle-gateway", `PORT: ${port}`);
|
|
@@ -188847,16 +188985,16 @@ function detectSyncDatabases(config) {
|
|
|
188847
188985
|
}
|
|
188848
188986
|
|
|
188849
188987
|
// src/lib/dev/reshape-watcher.ts
|
|
188850
|
-
import * as
|
|
188851
|
-
import * as
|
|
188988
|
+
import * as fs19 from "fs";
|
|
188989
|
+
import * as path16 from "path";
|
|
188852
188990
|
import { spawnSync } from "child_process";
|
|
188853
188991
|
function getMigrationFiles(dir, log) {
|
|
188854
188992
|
log(`Scanning migrations directory: ${dir}`);
|
|
188855
|
-
if (!
|
|
188993
|
+
if (!fs19.existsSync(dir)) {
|
|
188856
188994
|
log(`Migrations directory does not exist: ${dir}`);
|
|
188857
188995
|
return [];
|
|
188858
188996
|
}
|
|
188859
|
-
const files =
|
|
188997
|
+
const files = fs19.readdirSync(dir);
|
|
188860
188998
|
log(`Found ${files.length} files in directory`);
|
|
188861
188999
|
const tomlFiles = files.filter((f) => f.endsWith(".toml")).sort((a, b) => a.localeCompare(b));
|
|
188862
189000
|
log(`Found ${tomlFiles.length} .toml migration files: ${tomlFiles.join(", ") || "(none)"}`);
|
|
@@ -188906,7 +189044,7 @@ function runReshape(args, databaseUrl, migrationsDir, reshapeBinaryPath, log) {
|
|
|
188906
189044
|
}
|
|
188907
189045
|
function makeReadOnly(filePath, log) {
|
|
188908
189046
|
try {
|
|
188909
|
-
|
|
189047
|
+
fs19.chmodSync(filePath, 292);
|
|
188910
189048
|
log(`Set file permissions to read-only (444): ${filePath}`);
|
|
188911
189049
|
} catch (err) {
|
|
188912
189050
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -188967,7 +189105,7 @@ function createReshapeWatcher(options2) {
|
|
|
188967
189105
|
log(`Successfully completed ${currentMigrationFiles.length - 1} migration(s)`);
|
|
188968
189106
|
log(`Making completed migration files read-only...`);
|
|
188969
189107
|
for (let i = 0; i < currentMigrationFiles.length - 1; i++) {
|
|
188970
|
-
const filePath =
|
|
189108
|
+
const filePath = path16.join(migrationsDir, currentMigrationFiles[i]);
|
|
188971
189109
|
makeReadOnly(filePath, log);
|
|
188972
189110
|
}
|
|
188973
189111
|
log(`Starting latest migration "${lastMigrationName}" (will not be completed, allowing iteration)`);
|
|
@@ -188992,9 +189130,9 @@ function createReshapeWatcher(options2) {
|
|
|
188992
189130
|
};
|
|
188993
189131
|
const startWatching = () => {
|
|
188994
189132
|
log(`Starting file watcher for migrations directory...`);
|
|
188995
|
-
if (!
|
|
189133
|
+
if (!fs19.existsSync(migrationsDir)) {
|
|
188996
189134
|
log(`Migrations directory does not exist, creating: ${migrationsDir}`);
|
|
188997
|
-
|
|
189135
|
+
fs19.mkdirSync(migrationsDir, { recursive: true });
|
|
188998
189136
|
}
|
|
188999
189137
|
log(`Watching directory: ${migrationsDir}`);
|
|
189000
189138
|
watcher = chokidar_default.watch(migrationsDir, {
|
|
@@ -189007,7 +189145,7 @@ function createReshapeWatcher(options2) {
|
|
|
189007
189145
|
}
|
|
189008
189146
|
});
|
|
189009
189147
|
watcher.on("change", (filePath) => {
|
|
189010
|
-
const filename =
|
|
189148
|
+
const filename = path16.basename(filePath);
|
|
189011
189149
|
if (!filename.endsWith(".toml")) return;
|
|
189012
189150
|
log(`File change detected: ${filename}`);
|
|
189013
189151
|
log(` Full path: ${filePath}`);
|
|
@@ -189038,7 +189176,7 @@ function createReshapeWatcher(options2) {
|
|
|
189038
189176
|
}
|
|
189039
189177
|
});
|
|
189040
189178
|
watcher.on("add", (filePath) => {
|
|
189041
|
-
const filename =
|
|
189179
|
+
const filename = path16.basename(filePath);
|
|
189042
189180
|
if (!filename.endsWith(".toml")) return;
|
|
189043
189181
|
log(`New file detected: ${filename}`);
|
|
189044
189182
|
log(` Full path: ${filePath}`);
|
|
@@ -189062,7 +189200,7 @@ function createReshapeWatcher(options2) {
|
|
|
189062
189200
|
return;
|
|
189063
189201
|
}
|
|
189064
189202
|
log(`Previous migration completed successfully`);
|
|
189065
|
-
const completedPath =
|
|
189203
|
+
const completedPath = path16.join(migrationsDir, startedMigration);
|
|
189066
189204
|
makeReadOnly(completedPath, log);
|
|
189067
189205
|
} else {
|
|
189068
189206
|
log(`No previous migration was started`);
|
|
@@ -189087,7 +189225,7 @@ function createReshapeWatcher(options2) {
|
|
|
189087
189225
|
onSearchPathChanged(newSearchPath);
|
|
189088
189226
|
});
|
|
189089
189227
|
watcher.on("unlink", (filePath) => {
|
|
189090
|
-
const filename =
|
|
189228
|
+
const filename = path16.basename(filePath);
|
|
189091
189229
|
if (!filename.endsWith(".toml")) return;
|
|
189092
189230
|
log(`File deleted: ${filename}`);
|
|
189093
189231
|
log(` Full path: ${filePath}`);
|
|
@@ -189311,24 +189449,24 @@ function watchConfigFile(configPath, debounceMs, onChange) {
|
|
|
189311
189449
|
}
|
|
189312
189450
|
|
|
189313
189451
|
// src/lib/dev/subdomain-generator.ts
|
|
189314
|
-
import * as
|
|
189315
|
-
import * as
|
|
189452
|
+
import * as fs20 from "fs";
|
|
189453
|
+
import * as path17 from "path";
|
|
189316
189454
|
import { generateSlug } from "random-word-slugs";
|
|
189317
189455
|
var StableSubdomainAllocator = class {
|
|
189318
189456
|
tunnelsDir;
|
|
189319
189457
|
tunnelsFilePath;
|
|
189320
189458
|
baseSlug = null;
|
|
189321
189459
|
constructor(projectRoot, key = "default") {
|
|
189322
|
-
this.tunnelsDir =
|
|
189323
|
-
this.tunnelsFilePath =
|
|
189460
|
+
this.tunnelsDir = path17.join(projectRoot, ".specific", "keys", key);
|
|
189461
|
+
this.tunnelsFilePath = path17.join(this.tunnelsDir, "tunnels.json");
|
|
189324
189462
|
this.loadTunnels();
|
|
189325
189463
|
}
|
|
189326
189464
|
loadTunnels() {
|
|
189327
|
-
if (!
|
|
189465
|
+
if (!fs20.existsSync(this.tunnelsFilePath)) {
|
|
189328
189466
|
return;
|
|
189329
189467
|
}
|
|
189330
189468
|
try {
|
|
189331
|
-
const content =
|
|
189469
|
+
const content = fs20.readFileSync(this.tunnelsFilePath, "utf-8");
|
|
189332
189470
|
const data = JSON.parse(content);
|
|
189333
189471
|
if (data.version === 1 && data.baseSlug) {
|
|
189334
189472
|
this.baseSlug = data.baseSlug;
|
|
@@ -189338,14 +189476,14 @@ var StableSubdomainAllocator = class {
|
|
|
189338
189476
|
}
|
|
189339
189477
|
}
|
|
189340
189478
|
saveTunnels() {
|
|
189341
|
-
if (!
|
|
189342
|
-
|
|
189479
|
+
if (!fs20.existsSync(this.tunnelsDir)) {
|
|
189480
|
+
fs20.mkdirSync(this.tunnelsDir, { recursive: true });
|
|
189343
189481
|
}
|
|
189344
189482
|
const data = {
|
|
189345
189483
|
version: 1,
|
|
189346
189484
|
baseSlug: this.baseSlug
|
|
189347
189485
|
};
|
|
189348
|
-
|
|
189486
|
+
fs20.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
|
|
189349
189487
|
}
|
|
189350
189488
|
generateBaseSlug() {
|
|
189351
189489
|
return generateSlug(2, {
|
|
@@ -189384,6 +189522,7 @@ var StableSubdomainAllocator = class {
|
|
|
189384
189522
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
189385
189523
|
import * as net4 from "node:net";
|
|
189386
189524
|
var DEFAULT_HOST = "https://tunnel.spcf.app";
|
|
189525
|
+
var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 15e3];
|
|
189387
189526
|
async function register(baseUrl, subdomain) {
|
|
189388
189527
|
const res = await fetch(`${baseUrl}/${subdomain}`);
|
|
189389
189528
|
if (!res.ok) {
|
|
@@ -189396,15 +189535,17 @@ var TunnelClientImpl = class extends EventEmitter2 {
|
|
|
189396
189535
|
info;
|
|
189397
189536
|
localPort;
|
|
189398
189537
|
tunnelHost;
|
|
189538
|
+
baseUrl;
|
|
189399
189539
|
url;
|
|
189400
189540
|
subdomain;
|
|
189401
189541
|
pool = /* @__PURE__ */ new Set();
|
|
189402
189542
|
closed = false;
|
|
189403
|
-
constructor(info, localPort, tunnelHost) {
|
|
189543
|
+
constructor(info, localPort, tunnelHost, baseUrl) {
|
|
189404
189544
|
super();
|
|
189405
189545
|
this.info = info;
|
|
189406
189546
|
this.localPort = localPort;
|
|
189407
189547
|
this.tunnelHost = tunnelHost;
|
|
189548
|
+
this.baseUrl = baseUrl;
|
|
189408
189549
|
this.url = info.url;
|
|
189409
189550
|
this.subdomain = info.id;
|
|
189410
189551
|
this.fillPool();
|
|
@@ -189452,69 +189593,55 @@ var TunnelClientImpl = class extends EventEmitter2 {
|
|
|
189452
189593
|
return;
|
|
189453
189594
|
if (errored) {
|
|
189454
189595
|
if (this.pool.size === 0)
|
|
189455
|
-
this.
|
|
189596
|
+
this.reconnect();
|
|
189456
189597
|
} else {
|
|
189457
189598
|
this.fillPool();
|
|
189458
189599
|
}
|
|
189459
189600
|
}
|
|
189601
|
+
async reconnect() {
|
|
189602
|
+
this.emit("close");
|
|
189603
|
+
for (let attempt = 0; !this.closed; attempt++) {
|
|
189604
|
+
const delay = RECONNECT_DELAYS[Math.min(attempt, RECONNECT_DELAYS.length - 1)];
|
|
189605
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
189606
|
+
if (this.closed)
|
|
189607
|
+
return;
|
|
189608
|
+
try {
|
|
189609
|
+
this.info = await register(this.baseUrl, this.subdomain);
|
|
189610
|
+
this.fillPool();
|
|
189611
|
+
this.emit("reconnect");
|
|
189612
|
+
return;
|
|
189613
|
+
} catch {
|
|
189614
|
+
}
|
|
189615
|
+
}
|
|
189616
|
+
}
|
|
189460
189617
|
};
|
|
189461
189618
|
async function connect2(options2) {
|
|
189462
189619
|
const host = options2.host ?? DEFAULT_HOST;
|
|
189463
189620
|
const tunnelHost = new URL(host).hostname;
|
|
189464
189621
|
const info = await register(host, options2.subdomain);
|
|
189465
|
-
return new TunnelClientImpl(info, options2.port, tunnelHost);
|
|
189622
|
+
return new TunnelClientImpl(info, options2.port, tunnelHost, host);
|
|
189466
189623
|
}
|
|
189467
189624
|
|
|
189468
189625
|
// src/lib/dev/tunnel-manager.ts
|
|
189469
|
-
var TUNNEL_HOST = "https://tunnel.spcf.app";
|
|
189470
189626
|
async function startTunnel(serviceName, endpointName, port, subdomain, callbacks) {
|
|
189471
|
-
|
|
189472
|
-
|
|
189473
|
-
|
|
189474
|
-
|
|
189475
|
-
callbacks?.onError?.(serviceName, endpointName, err);
|
|
189476
|
-
});
|
|
189477
|
-
tunnel.on("close", () => {
|
|
189478
|
-
if (!stopped) {
|
|
189479
|
-
callbacks?.onClose?.(serviceName, endpointName);
|
|
189480
|
-
reconnect();
|
|
189481
|
-
}
|
|
189482
|
-
});
|
|
189483
|
-
}
|
|
189484
|
-
async function reconnect() {
|
|
189485
|
-
const delays = [1e3, 2e3, 4e3, 8e3, 15e3];
|
|
189486
|
-
for (let attempt = 0; !stopped; attempt++) {
|
|
189487
|
-
const delay = delays[Math.min(attempt, delays.length - 1)];
|
|
189488
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
189489
|
-
if (stopped) return;
|
|
189490
|
-
try {
|
|
189491
|
-
currentTunnel = await connect2({ port, subdomain, host: TUNNEL_HOST });
|
|
189492
|
-
setupTunnel(currentTunnel);
|
|
189493
|
-
callbacks?.onReconnect?.(serviceName, endpointName);
|
|
189494
|
-
return;
|
|
189495
|
-
} catch {
|
|
189496
|
-
}
|
|
189497
|
-
}
|
|
189498
|
-
}
|
|
189499
|
-
currentTunnel = await connect2({ port, subdomain, host: TUNNEL_HOST });
|
|
189500
|
-
setupTunnel(currentTunnel);
|
|
189627
|
+
const tunnel = await connect2({ port, subdomain });
|
|
189628
|
+
tunnel.on("error", (err) => callbacks?.onError?.(serviceName, endpointName, err));
|
|
189629
|
+
tunnel.on("close", () => callbacks?.onClose?.(serviceName, endpointName));
|
|
189630
|
+
tunnel.on("reconnect", () => callbacks?.onReconnect?.(serviceName, endpointName));
|
|
189501
189631
|
return {
|
|
189502
189632
|
serviceName,
|
|
189503
189633
|
endpointName,
|
|
189504
189634
|
localPort: port,
|
|
189505
|
-
url:
|
|
189635
|
+
url: tunnel.url,
|
|
189506
189636
|
subdomain,
|
|
189507
|
-
stop: async () =>
|
|
189508
|
-
stopped = true;
|
|
189509
|
-
currentTunnel?.close();
|
|
189510
|
-
}
|
|
189637
|
+
stop: async () => tunnel.close()
|
|
189511
189638
|
};
|
|
189512
189639
|
}
|
|
189513
189640
|
|
|
189514
189641
|
// src/lib/dev/proxy-registry.ts
|
|
189515
|
-
import * as
|
|
189516
|
-
import * as
|
|
189517
|
-
import * as
|
|
189642
|
+
import * as fs21 from "fs";
|
|
189643
|
+
import * as path18 from "path";
|
|
189644
|
+
import * as os8 from "os";
|
|
189518
189645
|
import * as net5 from "net";
|
|
189519
189646
|
var ProxyRegistryManager = class {
|
|
189520
189647
|
proxyDir;
|
|
@@ -189524,14 +189651,14 @@ var ProxyRegistryManager = class {
|
|
|
189524
189651
|
isOwner = false;
|
|
189525
189652
|
registryWatcher = null;
|
|
189526
189653
|
constructor() {
|
|
189527
|
-
this.proxyDir =
|
|
189528
|
-
this.ownerPath =
|
|
189529
|
-
this.registryPath =
|
|
189530
|
-
this.lockPath =
|
|
189654
|
+
this.proxyDir = path18.join(os8.homedir(), ".specific", "proxy");
|
|
189655
|
+
this.ownerPath = path18.join(this.proxyDir, "owner.json");
|
|
189656
|
+
this.registryPath = path18.join(this.proxyDir, "registry.json");
|
|
189657
|
+
this.lockPath = path18.join(this.proxyDir, "registry.lock");
|
|
189531
189658
|
}
|
|
189532
189659
|
ensureProxyDir() {
|
|
189533
|
-
if (!
|
|
189534
|
-
|
|
189660
|
+
if (!fs21.existsSync(this.proxyDir)) {
|
|
189661
|
+
fs21.mkdirSync(this.proxyDir, { recursive: true });
|
|
189535
189662
|
}
|
|
189536
189663
|
}
|
|
189537
189664
|
isProcessRunning(pid) {
|
|
@@ -189588,15 +189715,15 @@ var ProxyRegistryManager = class {
|
|
|
189588
189715
|
const startTime = Date.now();
|
|
189589
189716
|
while (Date.now() - startTime < timeoutMs) {
|
|
189590
189717
|
try {
|
|
189591
|
-
const fd =
|
|
189718
|
+
const fd = fs21.openSync(
|
|
189592
189719
|
this.lockPath,
|
|
189593
|
-
|
|
189720
|
+
fs21.constants.O_CREAT | fs21.constants.O_EXCL | fs21.constants.O_WRONLY
|
|
189594
189721
|
);
|
|
189595
|
-
|
|
189596
|
-
|
|
189722
|
+
fs21.writeSync(fd, String(process.pid));
|
|
189723
|
+
fs21.closeSync(fd);
|
|
189597
189724
|
return () => {
|
|
189598
189725
|
try {
|
|
189599
|
-
|
|
189726
|
+
fs21.unlinkSync(this.lockPath);
|
|
189600
189727
|
} catch {
|
|
189601
189728
|
}
|
|
189602
189729
|
};
|
|
@@ -189605,16 +189732,16 @@ var ProxyRegistryManager = class {
|
|
|
189605
189732
|
if (err.code === "EEXIST") {
|
|
189606
189733
|
try {
|
|
189607
189734
|
const lockPid = parseInt(
|
|
189608
|
-
|
|
189735
|
+
fs21.readFileSync(this.lockPath, "utf-8").trim(),
|
|
189609
189736
|
10
|
|
189610
189737
|
);
|
|
189611
189738
|
if (!this.isProcessRunning(lockPid)) {
|
|
189612
|
-
|
|
189739
|
+
fs21.unlinkSync(this.lockPath);
|
|
189613
189740
|
continue;
|
|
189614
189741
|
}
|
|
189615
189742
|
} catch {
|
|
189616
189743
|
try {
|
|
189617
|
-
|
|
189744
|
+
fs21.unlinkSync(this.lockPath);
|
|
189618
189745
|
} catch {
|
|
189619
189746
|
}
|
|
189620
189747
|
continue;
|
|
@@ -189634,8 +189761,8 @@ var ProxyRegistryManager = class {
|
|
|
189634
189761
|
async claimProxyOwnership(key) {
|
|
189635
189762
|
const releaseLock = await this.acquireLock();
|
|
189636
189763
|
try {
|
|
189637
|
-
if (
|
|
189638
|
-
const content =
|
|
189764
|
+
if (fs21.existsSync(this.ownerPath)) {
|
|
189765
|
+
const content = fs21.readFileSync(this.ownerPath, "utf-8");
|
|
189639
189766
|
const ownerFile2 = JSON.parse(content);
|
|
189640
189767
|
if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
|
|
189641
189768
|
return false;
|
|
@@ -189665,11 +189792,11 @@ var ProxyRegistryManager = class {
|
|
|
189665
189792
|
}
|
|
189666
189793
|
const releaseLock = await this.acquireLock();
|
|
189667
189794
|
try {
|
|
189668
|
-
if (
|
|
189669
|
-
const content =
|
|
189795
|
+
if (fs21.existsSync(this.ownerPath)) {
|
|
189796
|
+
const content = fs21.readFileSync(this.ownerPath, "utf-8");
|
|
189670
189797
|
const ownerFile = JSON.parse(content);
|
|
189671
189798
|
if (ownerFile.owner.pid === process.pid) {
|
|
189672
|
-
|
|
189799
|
+
fs21.unlinkSync(this.ownerPath);
|
|
189673
189800
|
}
|
|
189674
189801
|
}
|
|
189675
189802
|
this.isOwner = false;
|
|
@@ -189681,12 +189808,12 @@ var ProxyRegistryManager = class {
|
|
|
189681
189808
|
* Get the current proxy owner.
|
|
189682
189809
|
*/
|
|
189683
189810
|
async getProxyOwner() {
|
|
189684
|
-
if (!
|
|
189811
|
+
if (!fs21.existsSync(this.ownerPath)) {
|
|
189685
189812
|
return null;
|
|
189686
189813
|
}
|
|
189687
189814
|
const releaseLock = await this.acquireLock();
|
|
189688
189815
|
try {
|
|
189689
|
-
const content =
|
|
189816
|
+
const content = fs21.readFileSync(this.ownerPath, "utf-8");
|
|
189690
189817
|
const ownerFile = JSON.parse(content);
|
|
189691
189818
|
if (!await this.isProxyOwnerHealthy(ownerFile.owner.pid)) {
|
|
189692
189819
|
return null;
|
|
@@ -189780,7 +189907,7 @@ var ProxyRegistryManager = class {
|
|
|
189780
189907
|
*/
|
|
189781
189908
|
watchRegistry(onChange) {
|
|
189782
189909
|
this.ensureProxyDir();
|
|
189783
|
-
if (!
|
|
189910
|
+
if (!fs21.existsSync(this.registryPath)) {
|
|
189784
189911
|
const emptyRegistry = {
|
|
189785
189912
|
version: 1,
|
|
189786
189913
|
keys: {},
|
|
@@ -189823,13 +189950,13 @@ var ProxyRegistryManager = class {
|
|
|
189823
189950
|
async attemptElection(key) {
|
|
189824
189951
|
const releaseLock = await this.acquireLock();
|
|
189825
189952
|
try {
|
|
189826
|
-
if (
|
|
189827
|
-
const content =
|
|
189953
|
+
if (fs21.existsSync(this.ownerPath)) {
|
|
189954
|
+
const content = fs21.readFileSync(this.ownerPath, "utf-8");
|
|
189828
189955
|
const ownerFile2 = JSON.parse(content);
|
|
189829
189956
|
if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
|
|
189830
189957
|
return false;
|
|
189831
189958
|
}
|
|
189832
|
-
|
|
189959
|
+
fs21.unlinkSync(this.ownerPath);
|
|
189833
189960
|
}
|
|
189834
189961
|
const ownerFile = {
|
|
189835
189962
|
version: 1,
|
|
@@ -189847,7 +189974,7 @@ var ProxyRegistryManager = class {
|
|
|
189847
189974
|
}
|
|
189848
189975
|
}
|
|
189849
189976
|
readRegistry() {
|
|
189850
|
-
if (!
|
|
189977
|
+
if (!fs21.existsSync(this.registryPath)) {
|
|
189851
189978
|
return {
|
|
189852
189979
|
version: 1,
|
|
189853
189980
|
keys: {},
|
|
@@ -189855,7 +189982,7 @@ var ProxyRegistryManager = class {
|
|
|
189855
189982
|
};
|
|
189856
189983
|
}
|
|
189857
189984
|
try {
|
|
189858
|
-
const content =
|
|
189985
|
+
const content = fs21.readFileSync(this.registryPath, "utf-8");
|
|
189859
189986
|
return JSON.parse(content);
|
|
189860
189987
|
} catch {
|
|
189861
189988
|
return {
|
|
@@ -189868,8 +189995,8 @@ var ProxyRegistryManager = class {
|
|
|
189868
189995
|
writeFileAtomic(filePath, data) {
|
|
189869
189996
|
this.ensureProxyDir();
|
|
189870
189997
|
const tmpPath = filePath + ".tmp";
|
|
189871
|
-
|
|
189872
|
-
|
|
189998
|
+
fs21.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
189999
|
+
fs21.renameSync(tmpPath, filePath);
|
|
189873
190000
|
}
|
|
189874
190001
|
};
|
|
189875
190002
|
|
|
@@ -189973,10 +190100,10 @@ var COLORS = ["cyan", "yellow", "green", "magenta", "blue"];
|
|
|
189973
190100
|
function DevUI({ instanceKey, tunnelEnabled }) {
|
|
189974
190101
|
const { exit } = useApp2();
|
|
189975
190102
|
const [state, setState] = useState5(() => {
|
|
189976
|
-
const
|
|
190103
|
+
const setupDone = tunnelEnabled || !systemSetupNeeded();
|
|
189977
190104
|
return {
|
|
189978
|
-
status:
|
|
189979
|
-
...
|
|
190105
|
+
status: setupDone ? "loading" : "installing-ca",
|
|
190106
|
+
...setupDone ? {} : { caInstallPhase: "installing" },
|
|
189980
190107
|
resources: /* @__PURE__ */ new Map(),
|
|
189981
190108
|
resourceStatus: /* @__PURE__ */ new Map(),
|
|
189982
190109
|
services: [],
|
|
@@ -189989,18 +190116,15 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
189989
190116
|
});
|
|
189990
190117
|
useEffect3(() => {
|
|
189991
190118
|
if (state.status === "installing-ca" && state.caInstallPhase === "installing") {
|
|
189992
|
-
|
|
190119
|
+
installSystemConfig();
|
|
189993
190120
|
}
|
|
189994
190121
|
}, [state.status, state.caInstallPhase]);
|
|
189995
|
-
async function
|
|
190122
|
+
async function installSystemConfig() {
|
|
189996
190123
|
try {
|
|
189997
|
-
|
|
189998
|
-
const certPath = saveCA(key, cert);
|
|
189999
|
-
installCAToTrustStore(certPath);
|
|
190124
|
+
performSystemSetup();
|
|
190000
190125
|
setState((s) => ({ ...s, status: "loading", caInstallPhase: "done" }));
|
|
190001
190126
|
setReadyToStart(true);
|
|
190002
190127
|
} catch (err) {
|
|
190003
|
-
removeCA();
|
|
190004
190128
|
setState((s) => ({
|
|
190005
190129
|
...s,
|
|
190006
190130
|
caInstallPhase: "error",
|
|
@@ -190018,13 +190142,14 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190018
190142
|
const registryWatcherCleanupRef = useRef(null);
|
|
190019
190143
|
const electionIntervalRef = useRef(null);
|
|
190020
190144
|
const tunnelsRef = useRef([]);
|
|
190145
|
+
const dnsServerRef = useRef(null);
|
|
190021
190146
|
const proxyRef = useRef(null);
|
|
190022
190147
|
const adminServerRef = useRef(null);
|
|
190023
190148
|
const servicesRef = useRef([]);
|
|
190024
190149
|
const resourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
190025
190150
|
const restartServicesRef = useRef(null);
|
|
190026
190151
|
const [reloadTrigger, setReloadTrigger] = useState5(0);
|
|
190027
|
-
const [readyToStart, setReadyToStart] = useState5(() => tunnelEnabled ||
|
|
190152
|
+
const [readyToStart, setReadyToStart] = useState5(() => tunnelEnabled || !systemSetupNeeded());
|
|
190028
190153
|
const shutdown2 = async () => {
|
|
190029
190154
|
if (shuttingDown.current) return;
|
|
190030
190155
|
shuttingDown.current = true;
|
|
@@ -190043,6 +190168,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190043
190168
|
await Promise.all([
|
|
190044
190169
|
// Stop proxy
|
|
190045
190170
|
proxyRef.current?.stop(),
|
|
190171
|
+
// Stop DNS server
|
|
190172
|
+
dnsServerRef.current?.stop(),
|
|
190046
190173
|
// Stop admin server
|
|
190047
190174
|
adminServerRef.current?.stop(),
|
|
190048
190175
|
// Stop all services
|
|
@@ -190086,6 +190213,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190086
190213
|
await Promise.all([
|
|
190087
190214
|
// Stop proxy
|
|
190088
190215
|
proxyRef.current?.stop(),
|
|
190216
|
+
// Stop DNS server
|
|
190217
|
+
dnsServerRef.current?.stop(),
|
|
190089
190218
|
// Stop admin server
|
|
190090
190219
|
adminServerRef.current?.stop(),
|
|
190091
190220
|
// Stop all services
|
|
@@ -190106,6 +190235,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190106
190235
|
restartServicesRef.current = null;
|
|
190107
190236
|
drizzleGatewayRef.current = null;
|
|
190108
190237
|
proxyRef.current = null;
|
|
190238
|
+
dnsServerRef.current = null;
|
|
190109
190239
|
adminServerRef.current = null;
|
|
190110
190240
|
servicesRef.current = [];
|
|
190111
190241
|
resourcesRef.current = /* @__PURE__ */ new Map();
|
|
@@ -190137,6 +190267,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190137
190267
|
writeLog("system", "Force shutting down");
|
|
190138
190268
|
const allProcesses = [
|
|
190139
190269
|
proxyRef.current,
|
|
190270
|
+
dnsServerRef.current,
|
|
190140
190271
|
...servicesRef.current,
|
|
190141
190272
|
...electricInstancesRef.current,
|
|
190142
190273
|
drizzleGatewayRef.current,
|
|
@@ -190178,10 +190309,10 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190178
190309
|
}, [state.status]);
|
|
190179
190310
|
useEffect3(() => {
|
|
190180
190311
|
if (state.status !== "running") return;
|
|
190181
|
-
const configPath =
|
|
190312
|
+
const configPath = path19.join(process.cwd(), "specific.hcl");
|
|
190182
190313
|
const watcher = watchConfigFile(configPath, 1e3, () => {
|
|
190183
190314
|
try {
|
|
190184
|
-
const hcl =
|
|
190315
|
+
const hcl = fs22.readFileSync(configPath, "utf-8");
|
|
190185
190316
|
parseConfig(hcl).then(() => {
|
|
190186
190317
|
triggerReload();
|
|
190187
190318
|
}).catch((err) => {
|
|
@@ -190306,8 +190437,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190306
190437
|
}));
|
|
190307
190438
|
return;
|
|
190308
190439
|
}
|
|
190309
|
-
const configPath =
|
|
190310
|
-
if (!
|
|
190440
|
+
const configPath = path19.join(process.cwd(), "specific.hcl");
|
|
190441
|
+
if (!fs22.existsSync(configPath)) {
|
|
190311
190442
|
writeLog("system", "Waiting for specific.hcl to appear");
|
|
190312
190443
|
setState((s) => ({
|
|
190313
190444
|
...s,
|
|
@@ -190326,7 +190457,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190326
190457
|
}
|
|
190327
190458
|
let config2;
|
|
190328
190459
|
try {
|
|
190329
|
-
const hcl =
|
|
190460
|
+
const hcl = fs22.readFileSync(configPath, "utf-8");
|
|
190330
190461
|
config2 = await parseConfig(hcl);
|
|
190331
190462
|
} catch (err) {
|
|
190332
190463
|
setState((s) => ({
|
|
@@ -190432,7 +190563,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190432
190563
|
const drizzleGateway = await startDrizzleGateway(
|
|
190433
190564
|
postgresResources,
|
|
190434
190565
|
drizzlePort,
|
|
190435
|
-
|
|
190566
|
+
path19.join(process.cwd(), ".specific", "keys", instanceKey)
|
|
190436
190567
|
);
|
|
190437
190568
|
startedDrizzleGateway = drizzleGateway;
|
|
190438
190569
|
drizzleGatewayRef.current = drizzleGateway;
|
|
@@ -190452,7 +190583,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
190452
190583
|
if (pg.reshape?.enabled) {
|
|
190453
190584
|
const resource = resources2.get(pg.name);
|
|
190454
190585
|
if (!resource) continue;
|
|
190455
|
-
const migrationsDir =
|
|
190586
|
+
const migrationsDir = path19.resolve(
|
|
190456
190587
|
process.cwd(),
|
|
190457
190588
|
pg.reshape.migrations_dir ?? "migrations"
|
|
190458
190589
|
);
|
|
@@ -190620,10 +190751,10 @@ Add them to the config block in specific.local`);
|
|
|
190620
190751
|
}
|
|
190621
190752
|
const services2 = [];
|
|
190622
190753
|
function resolveServiceCwd(service) {
|
|
190623
|
-
if (service.root) return
|
|
190754
|
+
if (service.root) return path19.resolve(process.cwd(), service.root);
|
|
190624
190755
|
if (service.build) {
|
|
190625
190756
|
const build = config2.builds.find((b) => b.name === service.build.name);
|
|
190626
|
-
if (build?.root) return
|
|
190757
|
+
if (build?.root) return path19.resolve(process.cwd(), build.root);
|
|
190627
190758
|
}
|
|
190628
190759
|
return process.cwd();
|
|
190629
190760
|
}
|
|
@@ -190814,8 +190945,10 @@ Add them to the config block in specific.local`);
|
|
|
190814
190945
|
writeLog("system", `Registered ${serviceInfos.length} services with proxy registry`);
|
|
190815
190946
|
const becameProxyOwner = await proxyRegistry.claimProxyOwnership(instanceKey);
|
|
190816
190947
|
if (becameProxyOwner) {
|
|
190817
|
-
writeLog("system", "Claimed proxy ownership, starting HTTP proxy");
|
|
190948
|
+
writeLog("system", "Claimed proxy ownership, starting HTTP proxy and DNS server");
|
|
190818
190949
|
try {
|
|
190950
|
+
const dnsServer = await startDnsServer();
|
|
190951
|
+
dnsServerRef.current = dnsServer;
|
|
190819
190952
|
const currentServices = await proxyRegistry.getAllServices();
|
|
190820
190953
|
const registeredKeys = [...new Set(currentServices.map((s) => s.key))];
|
|
190821
190954
|
const certificate = generateCertificate("local.spcf.app", registeredKeys);
|
|
@@ -190880,12 +191013,14 @@ Add them to the config block in specific.local`);
|
|
|
190880
191013
|
writeLog("system", "Proxy owner died, attempting election");
|
|
190881
191014
|
const won = await proxyRegistry.attemptElection(instanceKey);
|
|
190882
191015
|
if (won) {
|
|
190883
|
-
writeLog("system", "Won election, starting HTTP proxy");
|
|
191016
|
+
writeLog("system", "Won election, starting HTTP proxy and DNS server");
|
|
190884
191017
|
if (electionIntervalRef.current) {
|
|
190885
191018
|
clearInterval(electionIntervalRef.current);
|
|
190886
191019
|
electionIntervalRef.current = null;
|
|
190887
191020
|
}
|
|
190888
191021
|
try {
|
|
191022
|
+
const dnsServer = await startDnsServer();
|
|
191023
|
+
dnsServerRef.current = dnsServer;
|
|
190889
191024
|
const electionServices = await proxyRegistry.getAllServices();
|
|
190890
191025
|
const electionKeyRegistrations = await proxyRegistry.getAllKeyRegistrations();
|
|
190891
191026
|
const electionKeyNames = Object.keys(electionKeyRegistrations);
|
|
@@ -190931,6 +191066,8 @@ Add them to the config block in specific.local`);
|
|
|
190931
191066
|
startedProxy.stop().catch(() => {
|
|
190932
191067
|
});
|
|
190933
191068
|
}
|
|
191069
|
+
dnsServerRef.current?.stop().catch(() => {
|
|
191070
|
+
});
|
|
190934
191071
|
for (const service of startedServices) {
|
|
190935
191072
|
service.stop().catch(() => {
|
|
190936
191073
|
});
|
|
@@ -190963,10 +191100,10 @@ Add them to the config block in specific.local`);
|
|
|
190963
191100
|
}, [reloadTrigger, readyToStart, instanceKey]);
|
|
190964
191101
|
if (state.status === "installing-ca") {
|
|
190965
191102
|
if (state.caInstallPhase === "installing") {
|
|
190966
|
-
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "
|
|
191103
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Local Development Setup"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Setting up TLS certificates and DNS resolution for local"), /* @__PURE__ */ React6.createElement(Text6, null, "development. This is a one-time setup for Specific projects."), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Your password is required to configure your system."), /* @__PURE__ */ React6.createElement(Text6, null, " "));
|
|
190967
191104
|
}
|
|
190968
191105
|
if (state.caInstallPhase === "error") {
|
|
190969
|
-
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "
|
|
191106
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Setup failed: ", state.caError));
|
|
190970
191107
|
}
|
|
190971
191108
|
}
|
|
190972
191109
|
if (state.status === "loading") {
|
|
@@ -191166,20 +191303,20 @@ function devCommand(instanceKey, tunnelEnabled = false) {
|
|
|
191166
191303
|
}
|
|
191167
191304
|
|
|
191168
191305
|
// src/lib/dev/git-worktree.ts
|
|
191169
|
-
import { execSync as
|
|
191170
|
-
import * as
|
|
191306
|
+
import { execSync as execSync3 } from "child_process";
|
|
191307
|
+
import * as path20 from "path";
|
|
191171
191308
|
function isInWorktree() {
|
|
191172
191309
|
try {
|
|
191173
|
-
const commonDir =
|
|
191310
|
+
const commonDir = execSync3("git rev-parse --git-common-dir", {
|
|
191174
191311
|
encoding: "utf-8",
|
|
191175
191312
|
stdio: ["pipe", "pipe", "pipe"]
|
|
191176
191313
|
}).trim();
|
|
191177
|
-
const gitDir =
|
|
191314
|
+
const gitDir = execSync3("git rev-parse --git-dir", {
|
|
191178
191315
|
encoding: "utf-8",
|
|
191179
191316
|
stdio: ["pipe", "pipe", "pipe"]
|
|
191180
191317
|
}).trim();
|
|
191181
|
-
const resolvedCommonDir =
|
|
191182
|
-
const resolvedGitDir =
|
|
191318
|
+
const resolvedCommonDir = path20.resolve(commonDir);
|
|
191319
|
+
const resolvedGitDir = path20.resolve(gitDir);
|
|
191183
191320
|
return resolvedCommonDir !== resolvedGitDir;
|
|
191184
191321
|
} catch {
|
|
191185
191322
|
return false;
|
|
@@ -191190,11 +191327,11 @@ function getWorktreeName() {
|
|
|
191190
191327
|
return null;
|
|
191191
191328
|
}
|
|
191192
191329
|
try {
|
|
191193
|
-
const gitDir =
|
|
191330
|
+
const gitDir = execSync3("git rev-parse --git-dir", {
|
|
191194
191331
|
encoding: "utf-8",
|
|
191195
191332
|
stdio: ["pipe", "pipe", "pipe"]
|
|
191196
191333
|
}).trim();
|
|
191197
|
-
return
|
|
191334
|
+
return path20.basename(gitDir);
|
|
191198
191335
|
} catch {
|
|
191199
191336
|
return null;
|
|
191200
191337
|
}
|
|
@@ -191209,36 +191346,36 @@ init_open();
|
|
|
191209
191346
|
import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
|
|
191210
191347
|
import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
191211
191348
|
import Spinner5 from "ink-spinner";
|
|
191212
|
-
import * as
|
|
191213
|
-
import * as
|
|
191349
|
+
import * as fs24 from "fs";
|
|
191350
|
+
import * as path22 from "path";
|
|
191214
191351
|
|
|
191215
191352
|
// src/lib/deploy/build-tester.ts
|
|
191216
191353
|
import { spawn as spawn5 } from "child_process";
|
|
191217
|
-
import { existsSync as
|
|
191218
|
-
import { join as
|
|
191354
|
+
import { existsSync as existsSync21 } from "fs";
|
|
191355
|
+
import { join as join22, resolve as resolve7 } from "path";
|
|
191219
191356
|
function getDependencyInstallCommand(build, projectDir) {
|
|
191220
191357
|
switch (build.base) {
|
|
191221
191358
|
case "node":
|
|
191222
|
-
if (
|
|
191359
|
+
if (existsSync21(join22(projectDir, "pnpm-lock.yaml"))) {
|
|
191223
191360
|
return "pnpm install --frozen-lockfile";
|
|
191224
|
-
} else if (
|
|
191361
|
+
} else if (existsSync21(join22(projectDir, "yarn.lock"))) {
|
|
191225
191362
|
return "yarn install --frozen-lockfile";
|
|
191226
|
-
} else if (
|
|
191363
|
+
} else if (existsSync21(join22(projectDir, "package-lock.json"))) {
|
|
191227
191364
|
return "npm ci";
|
|
191228
|
-
} else if (
|
|
191365
|
+
} else if (existsSync21(join22(projectDir, "package.json"))) {
|
|
191229
191366
|
return "npm install";
|
|
191230
191367
|
}
|
|
191231
191368
|
return null;
|
|
191232
191369
|
case "python":
|
|
191233
|
-
if (
|
|
191370
|
+
if (existsSync21(join22(projectDir, "poetry.lock"))) {
|
|
191234
191371
|
return "poetry install --no-interaction";
|
|
191235
|
-
} else if (
|
|
191372
|
+
} else if (existsSync21(join22(projectDir, "Pipfile.lock"))) {
|
|
191236
191373
|
return "pipenv install --deploy";
|
|
191237
|
-
} else if (
|
|
191374
|
+
} else if (existsSync21(join22(projectDir, "Pipfile"))) {
|
|
191238
191375
|
return "pipenv install";
|
|
191239
|
-
} else if (
|
|
191376
|
+
} else if (existsSync21(join22(projectDir, "pyproject.toml"))) {
|
|
191240
191377
|
return "pip install .";
|
|
191241
|
-
} else if (
|
|
191378
|
+
} else if (existsSync21(join22(projectDir, "requirements.txt"))) {
|
|
191242
191379
|
return "pip install -r requirements.txt";
|
|
191243
191380
|
}
|
|
191244
191381
|
return null;
|
|
@@ -191383,13 +191520,13 @@ async function testAllBuilds(builds, projectDir) {
|
|
|
191383
191520
|
}
|
|
191384
191521
|
|
|
191385
191522
|
// src/lib/tarball/create.ts
|
|
191386
|
-
import { execSync as
|
|
191387
|
-
import * as
|
|
191388
|
-
import * as
|
|
191523
|
+
import { execSync as execSync4 } from "child_process";
|
|
191524
|
+
import * as fs23 from "fs";
|
|
191525
|
+
import * as path21 from "path";
|
|
191389
191526
|
import { createTarPacker, createEntryItemGenerator } from "tar-vern";
|
|
191390
191527
|
function isInsideGitRepository(dir) {
|
|
191391
191528
|
try {
|
|
191392
|
-
const result =
|
|
191529
|
+
const result = execSync4("git rev-parse --is-inside-work-tree", {
|
|
191393
191530
|
cwd: dir,
|
|
191394
191531
|
encoding: "utf-8",
|
|
191395
191532
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -191401,7 +191538,7 @@ function isInsideGitRepository(dir) {
|
|
|
191401
191538
|
}
|
|
191402
191539
|
async function createGitArchive(projectDir) {
|
|
191403
191540
|
writeLog("tarball", "Creating tarball using git ls-files");
|
|
191404
|
-
const filesOutput =
|
|
191541
|
+
const filesOutput = execSync4(
|
|
191405
191542
|
"git ls-files --cached --others --exclude-standard",
|
|
191406
191543
|
{
|
|
191407
191544
|
cwd: projectDir,
|
|
@@ -191442,10 +191579,10 @@ var EXCLUDED_DIRS = [
|
|
|
191442
191579
|
];
|
|
191443
191580
|
async function collectPaths(baseDir, currentDir, exclude) {
|
|
191444
191581
|
const results = [];
|
|
191445
|
-
const entries = await
|
|
191582
|
+
const entries = await fs23.promises.readdir(currentDir, { withFileTypes: true });
|
|
191446
191583
|
for (const entry of entries) {
|
|
191447
|
-
const fullPath =
|
|
191448
|
-
const relativePath =
|
|
191584
|
+
const fullPath = path21.join(currentDir, entry.name);
|
|
191585
|
+
const relativePath = path21.relative(baseDir, fullPath);
|
|
191449
191586
|
if (entry.isDirectory()) {
|
|
191450
191587
|
if (!exclude.includes(entry.name)) {
|
|
191451
191588
|
results.push(relativePath);
|
|
@@ -191460,8 +191597,8 @@ async function collectPaths(baseDir, currentDir, exclude) {
|
|
|
191460
191597
|
}
|
|
191461
191598
|
async function createTarArchive(projectDir) {
|
|
191462
191599
|
writeLog("tarball", "Creating tarball using tar-vern (non-git project)");
|
|
191463
|
-
const configPath =
|
|
191464
|
-
if (!
|
|
191600
|
+
const configPath = path21.join(projectDir, "specific.hcl");
|
|
191601
|
+
if (!fs23.existsSync(configPath)) {
|
|
191465
191602
|
throw new Error("specific.hcl not found in project directory");
|
|
191466
191603
|
}
|
|
191467
191604
|
const relativePaths = await collectPaths(projectDir, projectDir, EXCLUDED_DIRS);
|
|
@@ -191478,8 +191615,8 @@ async function createTarArchive(projectDir) {
|
|
|
191478
191615
|
}
|
|
191479
191616
|
function findWidestContext(projectDir, contexts) {
|
|
191480
191617
|
if (contexts.length === 0) return ".";
|
|
191481
|
-
const absolute = contexts.map((c) =>
|
|
191482
|
-
const segments = absolute.map((p) => p.split(
|
|
191618
|
+
const absolute = contexts.map((c) => path21.resolve(projectDir, c));
|
|
191619
|
+
const segments = absolute.map((p) => p.split(path21.sep).filter(Boolean));
|
|
191483
191620
|
const firstSegments = segments[0];
|
|
191484
191621
|
if (!firstSegments) return ".";
|
|
191485
191622
|
const minLen = Math.min(...segments.map((s) => s.length));
|
|
@@ -191493,12 +191630,12 @@ function findWidestContext(projectDir, contexts) {
|
|
|
191493
191630
|
}
|
|
191494
191631
|
}
|
|
191495
191632
|
const ancestorSegments = firstSegments.slice(0, commonLength);
|
|
191496
|
-
const ancestor =
|
|
191497
|
-
return
|
|
191633
|
+
const ancestor = path21.sep + ancestorSegments.join(path21.sep);
|
|
191634
|
+
return path21.relative(projectDir, ancestor) || ".";
|
|
191498
191635
|
}
|
|
191499
191636
|
async function createProjectTarball(projectDir, context = ".") {
|
|
191500
|
-
const contextDir =
|
|
191501
|
-
const appPath =
|
|
191637
|
+
const contextDir = path21.resolve(projectDir, context);
|
|
191638
|
+
const appPath = path21.relative(contextDir, projectDir) || ".";
|
|
191502
191639
|
writeLog("tarball", `Context: ${contextDir}, appPath: ${appPath}`);
|
|
191503
191640
|
let tarball;
|
|
191504
191641
|
if (isInsideGitRepository(contextDir)) {
|
|
@@ -192385,14 +192522,14 @@ ${errorMsg}`
|
|
|
192385
192522
|
), phase === "error" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, "Error: ", error)), phase === "success" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Deployment successful!"), deployment?.publicUrls && Object.keys(deployment.publicUrls).length > 0 && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Public URLs:"), Object.entries(deployment.publicUrls).map(([name, url]) => /* @__PURE__ */ React7.createElement(Text7, { key: name }, " ", name, ": ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, url))))));
|
|
192386
192523
|
}
|
|
192387
192524
|
async function deployCommand(environment, options2) {
|
|
192388
|
-
const configPath =
|
|
192389
|
-
if (!
|
|
192525
|
+
const configPath = path22.join(process.cwd(), "specific.hcl");
|
|
192526
|
+
if (!fs24.existsSync(configPath)) {
|
|
192390
192527
|
console.error("Error: No specific.hcl found in current directory");
|
|
192391
192528
|
process.exit(1);
|
|
192392
192529
|
}
|
|
192393
192530
|
let config;
|
|
192394
192531
|
try {
|
|
192395
|
-
const hcl =
|
|
192532
|
+
const hcl = fs24.readFileSync(configPath, "utf-8");
|
|
192396
192533
|
config = await parseConfig(hcl);
|
|
192397
192534
|
} catch (err) {
|
|
192398
192535
|
console.error(
|
|
@@ -192416,8 +192553,8 @@ async function deployCommand(environment, options2) {
|
|
|
192416
192553
|
|
|
192417
192554
|
// src/commands/exec.tsx
|
|
192418
192555
|
import { spawn as spawn6 } from "child_process";
|
|
192419
|
-
import * as
|
|
192420
|
-
import * as
|
|
192556
|
+
import * as fs25 from "fs";
|
|
192557
|
+
import * as path23 from "path";
|
|
192421
192558
|
async function execCommand(serviceName, command, instanceKey = "default") {
|
|
192422
192559
|
if (command.length === 0) {
|
|
192423
192560
|
console.error(
|
|
@@ -192445,14 +192582,14 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
192445
192582
|
}
|
|
192446
192583
|
}
|
|
192447
192584
|
};
|
|
192448
|
-
const configPath =
|
|
192449
|
-
if (!
|
|
192585
|
+
const configPath = path23.join(process.cwd(), "specific.hcl");
|
|
192586
|
+
if (!fs25.existsSync(configPath)) {
|
|
192450
192587
|
console.error("Error: No specific.hcl found in current directory");
|
|
192451
192588
|
process.exit(1);
|
|
192452
192589
|
}
|
|
192453
192590
|
let config;
|
|
192454
192591
|
try {
|
|
192455
|
-
const hcl =
|
|
192592
|
+
const hcl = fs25.readFileSync(configPath, "utf-8");
|
|
192456
192593
|
config = await parseConfig(hcl);
|
|
192457
192594
|
} catch (err) {
|
|
192458
192595
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -192568,11 +192705,11 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
192568
192705
|
process.on("SIGTERM", () => handleSignal("SIGTERM"));
|
|
192569
192706
|
let effectiveCwd = process.cwd();
|
|
192570
192707
|
if (service.root) {
|
|
192571
|
-
effectiveCwd =
|
|
192708
|
+
effectiveCwd = path23.resolve(process.cwd(), service.root);
|
|
192572
192709
|
} else if (service.build) {
|
|
192573
192710
|
const build = config.builds.find((b) => b.name === service.build.name);
|
|
192574
192711
|
if (build?.root) {
|
|
192575
|
-
effectiveCwd =
|
|
192712
|
+
effectiveCwd = path23.resolve(process.cwd(), build.root);
|
|
192576
192713
|
}
|
|
192577
192714
|
}
|
|
192578
192715
|
child = spawn6(command[0], command.slice(1), {
|
|
@@ -192600,8 +192737,8 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
192600
192737
|
|
|
192601
192738
|
// src/commands/psql.tsx
|
|
192602
192739
|
import { spawn as spawn7 } from "child_process";
|
|
192603
|
-
import * as
|
|
192604
|
-
import * as
|
|
192740
|
+
import * as fs26 from "fs";
|
|
192741
|
+
import * as path24 from "path";
|
|
192605
192742
|
async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []) {
|
|
192606
192743
|
let startedResources = [];
|
|
192607
192744
|
let ownsInstances = false;
|
|
@@ -192618,14 +192755,14 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
|
|
|
192618
192755
|
}
|
|
192619
192756
|
}
|
|
192620
192757
|
};
|
|
192621
|
-
const configPath =
|
|
192622
|
-
if (!
|
|
192758
|
+
const configPath = path24.join(process.cwd(), "specific.hcl");
|
|
192759
|
+
if (!fs26.existsSync(configPath)) {
|
|
192623
192760
|
console.error("Error: No specific.hcl found in current directory");
|
|
192624
192761
|
process.exit(1);
|
|
192625
192762
|
}
|
|
192626
192763
|
let config;
|
|
192627
192764
|
try {
|
|
192628
|
-
const hcl =
|
|
192765
|
+
const hcl = fs26.readFileSync(configPath, "utf-8");
|
|
192629
192766
|
config = await parseConfig(hcl);
|
|
192630
192767
|
} catch (err) {
|
|
192631
192768
|
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -192747,8 +192884,8 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
|
|
|
192747
192884
|
|
|
192748
192885
|
// src/commands/reshape.tsx
|
|
192749
192886
|
import { spawn as spawn8 } from "child_process";
|
|
192750
|
-
import * as
|
|
192751
|
-
import * as
|
|
192887
|
+
import * as fs27 from "fs";
|
|
192888
|
+
import * as path25 from "path";
|
|
192752
192889
|
var VALID_ACTIONS = ["start", "complete", "status", "abort", "check"];
|
|
192753
192890
|
var MIGRATION_SUBCOMMANDS = ["start", "complete", "abort"];
|
|
192754
192891
|
var OFFLINE_ACTIONS = ["check"];
|
|
@@ -192760,13 +192897,13 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
192760
192897
|
process.exit(1);
|
|
192761
192898
|
}
|
|
192762
192899
|
const isOfflineAction = OFFLINE_ACTIONS.includes(action);
|
|
192763
|
-
const configPath =
|
|
192900
|
+
const configPath = path25.join(process.cwd(), "specific.hcl");
|
|
192764
192901
|
let config;
|
|
192765
192902
|
let migrationsDir = "migrations";
|
|
192766
192903
|
let targetDb;
|
|
192767
192904
|
try {
|
|
192768
|
-
if (
|
|
192769
|
-
const configContent =
|
|
192905
|
+
if (fs27.existsSync(configPath)) {
|
|
192906
|
+
const configContent = fs27.readFileSync(configPath, "utf-8");
|
|
192770
192907
|
config = await parseConfig(configContent);
|
|
192771
192908
|
if (databaseName) {
|
|
192772
192909
|
const postgresConfig = config.postgres.find((p) => p.name === databaseName);
|
|
@@ -192899,9 +193036,9 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
192899
193036
|
}
|
|
192900
193037
|
const isMigrationSubcommand = MIGRATION_SUBCOMMANDS.includes(action);
|
|
192901
193038
|
const reshapeArgs = isMigrationSubcommand ? ["migration", action] : [action];
|
|
192902
|
-
const fullMigrationsPath =
|
|
193039
|
+
const fullMigrationsPath = path25.join(process.cwd(), migrationsDir);
|
|
192903
193040
|
if (action === "check" || action === "start") {
|
|
192904
|
-
if (
|
|
193041
|
+
if (fs27.existsSync(fullMigrationsPath)) {
|
|
192905
193042
|
reshapeArgs.push("--dirs", fullMigrationsPath);
|
|
192906
193043
|
} else if (action === "check") {
|
|
192907
193044
|
console.error(`Error: Migrations directory not found: ${fullMigrationsPath}`);
|
|
@@ -192951,21 +193088,21 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
192951
193088
|
import React8, { useState as useState7, useEffect as useEffect5 } from "react";
|
|
192952
193089
|
import { render as render6, Text as Text8, Box as Box8 } from "ink";
|
|
192953
193090
|
import Spinner6 from "ink-spinner";
|
|
192954
|
-
import * as
|
|
192955
|
-
import * as
|
|
193091
|
+
import * as fs28 from "fs";
|
|
193092
|
+
import * as path26 from "path";
|
|
192956
193093
|
function CleanUI({ instanceKey }) {
|
|
192957
193094
|
const [state, setState] = useState7({ status: "checking" });
|
|
192958
193095
|
useEffect5(() => {
|
|
192959
193096
|
async function clean() {
|
|
192960
193097
|
const projectRoot = process.cwd();
|
|
192961
|
-
const specificDir =
|
|
192962
|
-
if (!
|
|
193098
|
+
const specificDir = path26.join(projectRoot, ".specific");
|
|
193099
|
+
if (!fs28.existsSync(specificDir)) {
|
|
192963
193100
|
setState({ status: "nothing" });
|
|
192964
193101
|
return;
|
|
192965
193102
|
}
|
|
192966
193103
|
if (instanceKey) {
|
|
192967
|
-
const keyDir =
|
|
192968
|
-
if (!
|
|
193104
|
+
const keyDir = path26.join(specificDir, "keys", instanceKey);
|
|
193105
|
+
if (!fs28.existsSync(keyDir)) {
|
|
192969
193106
|
setState({ status: "nothing" });
|
|
192970
193107
|
return;
|
|
192971
193108
|
}
|
|
@@ -192981,7 +193118,7 @@ function CleanUI({ instanceKey }) {
|
|
|
192981
193118
|
await stateManager.cleanStaleState();
|
|
192982
193119
|
setState({ status: "cleaning" });
|
|
192983
193120
|
try {
|
|
192984
|
-
|
|
193121
|
+
fs28.rmSync(keyDir, { recursive: true, force: true });
|
|
192985
193122
|
setState({ status: "success" });
|
|
192986
193123
|
} catch (err) {
|
|
192987
193124
|
setState({
|
|
@@ -192990,13 +193127,13 @@ function CleanUI({ instanceKey }) {
|
|
|
192990
193127
|
});
|
|
192991
193128
|
}
|
|
192992
193129
|
} else {
|
|
192993
|
-
const keysDir =
|
|
192994
|
-
if (!
|
|
193130
|
+
const keysDir = path26.join(specificDir, "keys");
|
|
193131
|
+
if (!fs28.existsSync(keysDir)) {
|
|
192995
193132
|
setState({ status: "nothing" });
|
|
192996
193133
|
return;
|
|
192997
193134
|
}
|
|
192998
|
-
const keys =
|
|
192999
|
-
(f) =>
|
|
193135
|
+
const keys = fs28.readdirSync(keysDir).filter(
|
|
193136
|
+
(f) => fs28.statSync(path26.join(keysDir, f)).isDirectory()
|
|
193000
193137
|
);
|
|
193001
193138
|
for (const key of keys) {
|
|
193002
193139
|
const stateManager2 = new InstanceStateManager(projectRoot, key);
|
|
@@ -193020,7 +193157,7 @@ function CleanUI({ instanceKey }) {
|
|
|
193020
193157
|
}
|
|
193021
193158
|
setState({ status: "cleaning" });
|
|
193022
193159
|
try {
|
|
193023
|
-
|
|
193160
|
+
fs28.rmSync(keysDir, { recursive: true, force: true });
|
|
193024
193161
|
setState({ status: "success" });
|
|
193025
193162
|
} catch (err) {
|
|
193026
193163
|
setState({
|
|
@@ -193183,7 +193320,7 @@ function betaCommand() {
|
|
|
193183
193320
|
var program = new Command();
|
|
193184
193321
|
var env = "production";
|
|
193185
193322
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
193186
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
193323
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.62").enablePositionalOptions();
|
|
193187
193324
|
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").action((options2) => initCommand(options2));
|
|
193188
193325
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
193189
193326
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|