@specific.dev/cli 0.1.71 → 0.1.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +1 -1
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +1 -1
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_not-found/__next._full.txt +1 -1
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/databases/__next._full.txt +1 -1
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +1 -1
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +1 -1
- package/dist/admin/fullscreen/__next._full.txt +1 -1
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +1 -1
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +1 -1
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/mail/__next._full.txt +1 -1
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +1 -1
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +1 -1
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +1 -1
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +1 -1
- package/dist/cli.js +310 -264
- package/dist/postinstall.js +1 -1
- package/package.json +1 -1
- /package/dist/admin/_next/static/{3nqvPNOX7a-_9HydleH6d → EdA1eXzy3MBFAW53uuebn}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{3nqvPNOX7a-_9HydleH6d → EdA1eXzy3MBFAW53uuebn}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{3nqvPNOX7a-_9HydleH6d → EdA1eXzy3MBFAW53uuebn}/_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 fs6 from "node:fs";
|
|
43
43
|
function hasDockerEnv() {
|
|
44
44
|
try {
|
|
45
|
-
|
|
45
|
+
fs6.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 fs6.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 fs7 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
|
+
fs7.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 os5 from "node:os";
|
|
96
|
+
import fs8 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 (os5.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 fs8.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 fs9, { 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 fs9.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 fs9.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 fs9.access(psPath, fsConstants.X_OK);
|
|
228
228
|
return true;
|
|
229
229
|
} catch {
|
|
230
230
|
return false;
|
|
@@ -435,7 +435,7 @@ import process8 from "node:process";
|
|
|
435
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 fs10, { 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({ [platform4]: 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(`${platform4} is not supported`);
|
|
455
455
|
}
|
|
456
456
|
return detectArchBinary(platformBinary);
|
|
457
457
|
}
|
|
458
|
-
var fallbackAttemptSymbol, __dirname, localXdgOpenPath,
|
|
458
|
+
var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform4, 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();
|
|
@@ -467,7 +467,7 @@ var init_open = __esm({
|
|
|
467
467
|
fallbackAttemptSymbol = Symbol("fallbackAttempt");
|
|
468
468
|
__dirname = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
|
|
469
469
|
localXdgOpenPath = path5.join(__dirname, "xdg-open");
|
|
470
|
-
({ platform:
|
|
470
|
+
({ platform: platform4, 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 (platform4 === "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 (platform4 === "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 fs10.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 ?? (platform4 === "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 (platform4 === "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 fs33 = $global.require("fs");
|
|
758
|
+
"object" == typeof fs33 && null !== fs33 && 0 !== Object.keys(fs33).length && ($global.fs = fs33);
|
|
759
759
|
} catch (e) {
|
|
760
760
|
}
|
|
761
761
|
if (!$global.fs) {
|
|
@@ -183430,11 +183430,14 @@ import { Command } from "commander";
|
|
|
183430
183430
|
import React2, { useState, useEffect } from "react";
|
|
183431
183431
|
import { render as render2, Text as Text2, Box as Box2, useInput, useApp } from "ink";
|
|
183432
183432
|
import "ink-spinner";
|
|
183433
|
-
import * as
|
|
183433
|
+
import * as fs12 from "fs";
|
|
183434
183434
|
import * as path7 from "path";
|
|
183435
183435
|
|
|
183436
183436
|
// src/lib/dev/system-setup.ts
|
|
183437
183437
|
import { execSync as execSync2 } from "child_process";
|
|
183438
|
+
import * as fs4 from "fs";
|
|
183439
|
+
import * as os4 from "os";
|
|
183440
|
+
import * as path3 from "path";
|
|
183438
183441
|
|
|
183439
183442
|
// src/lib/dev/local-ca.ts
|
|
183440
183443
|
import * as fs from "fs";
|
|
@@ -183453,17 +183456,17 @@ function caInstalledInTrustStore() {
|
|
|
183453
183456
|
if (!caFilesExist()) {
|
|
183454
183457
|
return false;
|
|
183455
183458
|
}
|
|
183456
|
-
const
|
|
183459
|
+
const platform6 = os.platform();
|
|
183457
183460
|
const certPath = path.join(getCADir(), "ca.crt");
|
|
183458
183461
|
const diskCert = fs.readFileSync(certPath, "utf-8").replace(/\r\n/g, "\n").trim();
|
|
183459
183462
|
try {
|
|
183460
|
-
if (
|
|
183463
|
+
if (platform6 === "darwin") {
|
|
183461
183464
|
const keychainCert = execSync(
|
|
183462
183465
|
'security find-certificate -c "Specific Local Development CA" -p /Library/Keychains/System.keychain',
|
|
183463
183466
|
{ encoding: "utf-8" }
|
|
183464
183467
|
).replace(/\r\n/g, "\n").trim();
|
|
183465
183468
|
return keychainCert === diskCert;
|
|
183466
|
-
} else if (
|
|
183469
|
+
} else if (platform6 === "linux") {
|
|
183467
183470
|
const trustPaths = [
|
|
183468
183471
|
"/usr/local/share/ca-certificates/specific-local-ca.crt",
|
|
183469
183472
|
"/etc/pki/ca-trust/source/anchors/specific-local-ca.crt"
|
|
@@ -183571,15 +183574,15 @@ function removeCA() {
|
|
|
183571
183574
|
}
|
|
183572
183575
|
}
|
|
183573
183576
|
function getCAInstallCommands(certPath) {
|
|
183574
|
-
const
|
|
183575
|
-
if (
|
|
183577
|
+
const platform6 = os.platform();
|
|
183578
|
+
if (platform6 === "darwin") {
|
|
183576
183579
|
return [
|
|
183577
183580
|
// Remove any existing cert with the same CN first — add-trusted-cert
|
|
183578
183581
|
// silently does nothing if a cert with the same subject already exists.
|
|
183579
183582
|
'security delete-certificate -c "Specific Local Development CA" /Library/Keychains/System.keychain 2>/dev/null || true',
|
|
183580
183583
|
`security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`
|
|
183581
183584
|
];
|
|
183582
|
-
} else if (
|
|
183585
|
+
} else if (platform6 === "linux") {
|
|
183583
183586
|
if (fs.existsSync("/usr/local/share/ca-certificates")) {
|
|
183584
183587
|
return [
|
|
183585
183588
|
`cp "${certPath}" /usr/local/share/ca-certificates/specific-local-ca.crt`,
|
|
@@ -183593,7 +183596,7 @@ function getCAInstallCommands(certPath) {
|
|
|
183593
183596
|
}
|
|
183594
183597
|
throw new Error("Could not detect Linux certificate trust mechanism");
|
|
183595
183598
|
}
|
|
183596
|
-
throw new Error(`Unsupported platform: ${
|
|
183599
|
+
throw new Error(`Unsupported platform: ${platform6}`);
|
|
183597
183600
|
}
|
|
183598
183601
|
function generateCertificate(domain, keys = []) {
|
|
183599
183602
|
const caDir = getCADir();
|
|
@@ -183638,22 +183641,22 @@ import * as os2 from "os";
|
|
|
183638
183641
|
var RESOLVER_FILE_MACOS = "/etc/resolver/local.spcf.app";
|
|
183639
183642
|
var RESOLVER_FILE_LINUX = "/etc/systemd/resolved.conf.d/specific-local.conf";
|
|
183640
183643
|
function resolverConfigExists() {
|
|
183641
|
-
const
|
|
183642
|
-
if (
|
|
183644
|
+
const platform6 = os2.platform();
|
|
183645
|
+
if (platform6 === "darwin") {
|
|
183643
183646
|
return fs2.existsSync(RESOLVER_FILE_MACOS);
|
|
183644
|
-
} else if (
|
|
183647
|
+
} else if (platform6 === "linux") {
|
|
183645
183648
|
return fs2.existsSync(RESOLVER_FILE_LINUX);
|
|
183646
183649
|
}
|
|
183647
183650
|
return false;
|
|
183648
183651
|
}
|
|
183649
183652
|
function getResolverInstallCommands(port) {
|
|
183650
|
-
const
|
|
183651
|
-
if (
|
|
183653
|
+
const platform6 = os2.platform();
|
|
183654
|
+
if (platform6 === "darwin") {
|
|
183652
183655
|
return [
|
|
183653
183656
|
"mkdir -p /etc/resolver",
|
|
183654
183657
|
`printf "nameserver 127.0.0.1\\nport ${port}\\n" > ${RESOLVER_FILE_MACOS}`
|
|
183655
183658
|
];
|
|
183656
|
-
} else if (
|
|
183659
|
+
} else if (platform6 === "linux") {
|
|
183657
183660
|
if (fs2.existsSync("/etc/systemd/resolved.conf.d") || fs2.existsSync("/etc/systemd")) {
|
|
183658
183661
|
return [
|
|
183659
183662
|
"mkdir -p /etc/systemd/resolved.conf.d",
|
|
@@ -183746,7 +183749,6 @@ async function startDnsServer(port = DNS_PORT) {
|
|
|
183746
183749
|
}
|
|
183747
183750
|
|
|
183748
183751
|
// src/lib/dev/system-setup.ts
|
|
183749
|
-
import * as path3 from "path";
|
|
183750
183752
|
function systemSetupNeeded() {
|
|
183751
183753
|
return !caInstalledInTrustStore() || !resolverConfigExists();
|
|
183752
183754
|
}
|
|
@@ -183773,7 +183775,7 @@ function performSystemSetup() {
|
|
|
183773
183775
|
return;
|
|
183774
183776
|
}
|
|
183775
183777
|
try {
|
|
183776
|
-
|
|
183778
|
+
execPrivileged(commands);
|
|
183777
183779
|
} catch (err) {
|
|
183778
183780
|
if (needsGenerate) {
|
|
183779
183781
|
removeCA();
|
|
@@ -183781,14 +183783,43 @@ function performSystemSetup() {
|
|
|
183781
183783
|
throw err;
|
|
183782
183784
|
}
|
|
183783
183785
|
}
|
|
183786
|
+
function execPrivileged(commands) {
|
|
183787
|
+
if (commands.length === 0) return;
|
|
183788
|
+
if (os4.platform() === "darwin") {
|
|
183789
|
+
const scriptPath = path3.join(os4.tmpdir(), "specific-setup.sh");
|
|
183790
|
+
const appPath = path3.join(os4.tmpdir(), "Specific.app");
|
|
183791
|
+
try {
|
|
183792
|
+
fs4.writeFileSync(
|
|
183793
|
+
scriptPath,
|
|
183794
|
+
"#!/bin/sh\nset -e\n" + commands.join("\n") + "\n",
|
|
183795
|
+
{ mode: 448 }
|
|
183796
|
+
);
|
|
183797
|
+
execSync2(
|
|
183798
|
+
`osacompile -o '${appPath}' -e 'do shell script "sh ${scriptPath}" with administrator privileges'`
|
|
183799
|
+
);
|
|
183800
|
+
execSync2(`'${appPath}/Contents/MacOS/applet'`, { stdio: "pipe" });
|
|
183801
|
+
} finally {
|
|
183802
|
+
try {
|
|
183803
|
+
fs4.unlinkSync(scriptPath);
|
|
183804
|
+
} catch {
|
|
183805
|
+
}
|
|
183806
|
+
try {
|
|
183807
|
+
fs4.rmSync(appPath, { recursive: true });
|
|
183808
|
+
} catch {
|
|
183809
|
+
}
|
|
183810
|
+
}
|
|
183811
|
+
} else {
|
|
183812
|
+
execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
|
|
183813
|
+
}
|
|
183814
|
+
}
|
|
183784
183815
|
|
|
183785
183816
|
// src/lib/analytics/index.ts
|
|
183786
183817
|
import { PostHog } from "posthog-node";
|
|
183787
|
-
import * as
|
|
183818
|
+
import * as os7 from "os";
|
|
183788
183819
|
import * as crypto from "crypto";
|
|
183789
183820
|
|
|
183790
183821
|
// src/lib/project/config.ts
|
|
183791
|
-
import * as
|
|
183822
|
+
import * as fs5 from "fs";
|
|
183792
183823
|
import * as path4 from "path";
|
|
183793
183824
|
var PROJECT_ID_FILE = ".specific/project_id";
|
|
183794
183825
|
var ProjectNotLinkedError = class extends Error {
|
|
@@ -183805,10 +183836,10 @@ Run: specific deploy`
|
|
|
183805
183836
|
};
|
|
183806
183837
|
function readProjectId(projectDir = process.cwd()) {
|
|
183807
183838
|
const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
|
|
183808
|
-
if (!
|
|
183839
|
+
if (!fs5.existsSync(projectIdPath)) {
|
|
183809
183840
|
throw new ProjectNotLinkedError();
|
|
183810
183841
|
}
|
|
183811
|
-
const projectId =
|
|
183842
|
+
const projectId = fs5.readFileSync(projectIdPath, "utf-8").trim();
|
|
183812
183843
|
if (!projectId) {
|
|
183813
183844
|
throw new Error(`${PROJECT_ID_FILE} is empty`);
|
|
183814
183845
|
}
|
|
@@ -183816,20 +183847,20 @@ function readProjectId(projectDir = process.cwd()) {
|
|
|
183816
183847
|
}
|
|
183817
183848
|
function hasProjectId(projectDir = process.cwd()) {
|
|
183818
183849
|
const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
|
|
183819
|
-
return
|
|
183850
|
+
return fs5.existsSync(projectIdPath);
|
|
183820
183851
|
}
|
|
183821
183852
|
function writeProjectId(projectId, projectDir = process.cwd()) {
|
|
183822
183853
|
const specificDir = path4.join(projectDir, ".specific");
|
|
183823
|
-
if (!
|
|
183824
|
-
|
|
183854
|
+
if (!fs5.existsSync(specificDir)) {
|
|
183855
|
+
fs5.mkdirSync(specificDir, { recursive: true });
|
|
183825
183856
|
}
|
|
183826
|
-
|
|
183857
|
+
fs5.writeFileSync(path4.join(specificDir, "project_id"), projectId + "\n");
|
|
183827
183858
|
}
|
|
183828
183859
|
|
|
183829
183860
|
// src/lib/auth/credentials.ts
|
|
183830
|
-
import * as
|
|
183861
|
+
import * as fs11 from "fs";
|
|
183831
183862
|
import * as path6 from "path";
|
|
183832
|
-
import * as
|
|
183863
|
+
import * as os6 from "os";
|
|
183833
183864
|
|
|
183834
183865
|
// src/lib/auth/errors.ts
|
|
183835
183866
|
var RefreshTokenExpiredError = class extends Error {
|
|
@@ -184382,18 +184413,18 @@ var ApiClient = class {
|
|
|
184382
184413
|
|
|
184383
184414
|
// src/lib/auth/credentials.ts
|
|
184384
184415
|
function getUserCredentialsDir() {
|
|
184385
|
-
return path6.join(
|
|
184416
|
+
return path6.join(os6.homedir(), ".specific");
|
|
184386
184417
|
}
|
|
184387
184418
|
function getCredentialsPath() {
|
|
184388
184419
|
return path6.join(getUserCredentialsDir(), "credentials.json");
|
|
184389
184420
|
}
|
|
184390
184421
|
function readUserCredentials() {
|
|
184391
184422
|
const credentialsPath = getCredentialsPath();
|
|
184392
|
-
if (!
|
|
184423
|
+
if (!fs11.existsSync(credentialsPath)) {
|
|
184393
184424
|
return null;
|
|
184394
184425
|
}
|
|
184395
184426
|
try {
|
|
184396
|
-
const content =
|
|
184427
|
+
const content = fs11.readFileSync(credentialsPath, "utf-8");
|
|
184397
184428
|
return JSON.parse(content);
|
|
184398
184429
|
} catch {
|
|
184399
184430
|
return null;
|
|
@@ -184401,18 +184432,18 @@ function readUserCredentials() {
|
|
|
184401
184432
|
}
|
|
184402
184433
|
function writeUserCredentials(credentials) {
|
|
184403
184434
|
const dir = getUserCredentialsDir();
|
|
184404
|
-
if (!
|
|
184405
|
-
|
|
184435
|
+
if (!fs11.existsSync(dir)) {
|
|
184436
|
+
fs11.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
184406
184437
|
}
|
|
184407
184438
|
const credentialsPath = getCredentialsPath();
|
|
184408
|
-
|
|
184439
|
+
fs11.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
|
|
184409
184440
|
mode: 384
|
|
184410
184441
|
});
|
|
184411
184442
|
}
|
|
184412
184443
|
function clearUserCredentials() {
|
|
184413
184444
|
const credentialsPath = getCredentialsPath();
|
|
184414
|
-
if (
|
|
184415
|
-
|
|
184445
|
+
if (fs11.existsSync(credentialsPath)) {
|
|
184446
|
+
fs11.unlinkSync(credentialsPath);
|
|
184416
184447
|
}
|
|
184417
184448
|
}
|
|
184418
184449
|
function isLoggedIn() {
|
|
@@ -184491,7 +184522,7 @@ function isEnabled() {
|
|
|
184491
184522
|
}
|
|
184492
184523
|
function getAnonymousId() {
|
|
184493
184524
|
if (anonymousId) return anonymousId;
|
|
184494
|
-
const machineId = `${
|
|
184525
|
+
const machineId = `${os7.hostname()}-${os7.userInfo().username}`;
|
|
184495
184526
|
anonymousId = crypto.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
|
|
184496
184527
|
return anonymousId;
|
|
184497
184528
|
}
|
|
@@ -184538,7 +184569,7 @@ function trackEvent(event, properties) {
|
|
|
184538
184569
|
event,
|
|
184539
184570
|
properties: {
|
|
184540
184571
|
...properties,
|
|
184541
|
-
cli_version: "0.1.
|
|
184572
|
+
cli_version: "0.1.72",
|
|
184542
184573
|
platform: process.platform,
|
|
184543
184574
|
node_version: process.version,
|
|
184544
184575
|
project_id: getProjectId()
|
|
@@ -184575,57 +184606,57 @@ var options = [
|
|
|
184575
184606
|
];
|
|
184576
184607
|
function isGitProject() {
|
|
184577
184608
|
const gitPath = path7.join(process.cwd(), ".git");
|
|
184578
|
-
return
|
|
184609
|
+
return fs12.existsSync(gitPath);
|
|
184579
184610
|
}
|
|
184580
184611
|
function detectExistingAgents() {
|
|
184581
184612
|
const detected = {};
|
|
184582
184613
|
const cursorDir = path7.join(process.cwd(), ".cursor");
|
|
184583
|
-
if (
|
|
184614
|
+
if (fs12.existsSync(cursorDir)) {
|
|
184584
184615
|
detected["cursor"] = true;
|
|
184585
184616
|
}
|
|
184586
184617
|
const claudeDir = path7.join(process.cwd(), ".claude");
|
|
184587
184618
|
const claudeMd = path7.join(process.cwd(), "CLAUDE.md");
|
|
184588
|
-
if (
|
|
184619
|
+
if (fs12.existsSync(claudeDir) || fs12.existsSync(claudeMd)) {
|
|
184589
184620
|
detected["claude"] = true;
|
|
184590
184621
|
}
|
|
184591
184622
|
const agentsMd = path7.join(process.cwd(), "AGENTS.md");
|
|
184592
|
-
if (
|
|
184623
|
+
if (fs12.existsSync(agentsMd)) {
|
|
184593
184624
|
detected["codex"] = true;
|
|
184594
184625
|
}
|
|
184595
184626
|
return detected;
|
|
184596
184627
|
}
|
|
184597
184628
|
function appendOrCreateFile(filePath, content) {
|
|
184598
|
-
if (
|
|
184599
|
-
const existing =
|
|
184629
|
+
if (fs12.existsSync(filePath)) {
|
|
184630
|
+
const existing = fs12.readFileSync(filePath, "utf-8");
|
|
184600
184631
|
if (existing.includes("specific docs") || existing.includes("specific check")) {
|
|
184601
184632
|
return "unchanged";
|
|
184602
184633
|
}
|
|
184603
184634
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
184604
|
-
|
|
184635
|
+
fs12.writeFileSync(filePath, existing + separator + content + "\n");
|
|
184605
184636
|
return "modified";
|
|
184606
184637
|
} else {
|
|
184607
|
-
|
|
184638
|
+
fs12.writeFileSync(filePath, content + "\n");
|
|
184608
184639
|
return "created";
|
|
184609
184640
|
}
|
|
184610
184641
|
}
|
|
184611
184642
|
function addToGitignore() {
|
|
184612
184643
|
const gitignorePath = path7.join(process.cwd(), ".gitignore");
|
|
184613
184644
|
const entries = [".specific", "specific.local"];
|
|
184614
|
-
if (
|
|
184615
|
-
const existing =
|
|
184645
|
+
if (fs12.existsSync(gitignorePath)) {
|
|
184646
|
+
const existing = fs12.readFileSync(gitignorePath, "utf-8");
|
|
184616
184647
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
184617
184648
|
const missingEntries = entries.filter((entry) => !lines.includes(entry));
|
|
184618
184649
|
if (missingEntries.length === 0) {
|
|
184619
184650
|
return "unchanged";
|
|
184620
184651
|
}
|
|
184621
184652
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
184622
|
-
|
|
184653
|
+
fs12.writeFileSync(
|
|
184623
184654
|
gitignorePath,
|
|
184624
184655
|
existing + separator + missingEntries.join("\n") + "\n"
|
|
184625
184656
|
);
|
|
184626
184657
|
return "modified";
|
|
184627
184658
|
} else {
|
|
184628
|
-
|
|
184659
|
+
fs12.writeFileSync(gitignorePath, entries.join("\n") + "\n");
|
|
184629
184660
|
return "created";
|
|
184630
184661
|
}
|
|
184631
184662
|
}
|
|
@@ -184633,8 +184664,8 @@ function configureClaudeCodePermissions() {
|
|
|
184633
184664
|
const claudeDir = path7.join(process.cwd(), ".claude");
|
|
184634
184665
|
const settingsPath = path7.join(claudeDir, "settings.local.json");
|
|
184635
184666
|
const permissions = ["Bash(specific docs:*)", "Bash(specific check:*)"];
|
|
184636
|
-
if (
|
|
184637
|
-
const existing = JSON.parse(
|
|
184667
|
+
if (fs12.existsSync(settingsPath)) {
|
|
184668
|
+
const existing = JSON.parse(fs12.readFileSync(settingsPath, "utf-8"));
|
|
184638
184669
|
const allowList = existing?.permissions?.allow || [];
|
|
184639
184670
|
const missingPermissions = permissions.filter(
|
|
184640
184671
|
(p) => !allowList.includes(p)
|
|
@@ -184649,39 +184680,39 @@ function configureClaudeCodePermissions() {
|
|
|
184649
184680
|
existing.permissions.allow = [];
|
|
184650
184681
|
}
|
|
184651
184682
|
existing.permissions.allow.push(...missingPermissions);
|
|
184652
|
-
|
|
184683
|
+
fs12.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
|
|
184653
184684
|
return "modified";
|
|
184654
184685
|
}
|
|
184655
|
-
if (!
|
|
184656
|
-
|
|
184686
|
+
if (!fs12.existsSync(claudeDir)) {
|
|
184687
|
+
fs12.mkdirSync(claudeDir);
|
|
184657
184688
|
}
|
|
184658
184689
|
const settings = {
|
|
184659
184690
|
permissions: {
|
|
184660
184691
|
allow: permissions
|
|
184661
184692
|
}
|
|
184662
184693
|
};
|
|
184663
|
-
|
|
184694
|
+
fs12.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
184664
184695
|
return "created";
|
|
184665
184696
|
}
|
|
184666
184697
|
function createCursorRule() {
|
|
184667
184698
|
const cursorDir = path7.join(process.cwd(), ".cursor");
|
|
184668
184699
|
const rulesDir = path7.join(cursorDir, "rules");
|
|
184669
184700
|
const mdcPath = path7.join(rulesDir, "specific.mdc");
|
|
184670
|
-
if (
|
|
184671
|
-
const existing =
|
|
184701
|
+
if (fs12.existsSync(mdcPath)) {
|
|
184702
|
+
const existing = fs12.readFileSync(mdcPath, "utf-8");
|
|
184672
184703
|
if (existing.includes("specific docs") || existing.includes("specific check")) {
|
|
184673
184704
|
return "unchanged";
|
|
184674
184705
|
}
|
|
184675
|
-
|
|
184706
|
+
fs12.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
|
|
184676
184707
|
return "modified";
|
|
184677
184708
|
}
|
|
184678
|
-
if (!
|
|
184679
|
-
|
|
184709
|
+
if (!fs12.existsSync(cursorDir)) {
|
|
184710
|
+
fs12.mkdirSync(cursorDir);
|
|
184680
184711
|
}
|
|
184681
|
-
if (!
|
|
184682
|
-
|
|
184712
|
+
if (!fs12.existsSync(rulesDir)) {
|
|
184713
|
+
fs12.mkdirSync(rulesDir);
|
|
184683
184714
|
}
|
|
184684
|
-
|
|
184715
|
+
fs12.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
|
|
184685
184716
|
return "created";
|
|
184686
184717
|
}
|
|
184687
184718
|
function configureAgents(checked) {
|
|
@@ -184736,7 +184767,7 @@ function InitUI() {
|
|
|
184736
184767
|
const [phase, setPhase] = useState(
|
|
184737
184768
|
() => !systemSetupNeeded() ? "agents" : "installing-ca"
|
|
184738
184769
|
);
|
|
184739
|
-
const [caInstallPhase, setCaInstallPhase] = useState(() => !systemSetupNeeded() ? "done" : "
|
|
184770
|
+
const [caInstallPhase, setCaInstallPhase] = useState(() => !systemSetupNeeded() ? "done" : "prompt");
|
|
184740
184771
|
const [focusedIndex, setFocusedIndex] = useState(initialState.focusedIndex);
|
|
184741
184772
|
const [checked, setChecked] = useState(
|
|
184742
184773
|
initialState.detected
|
|
@@ -184767,6 +184798,10 @@ function InitUI() {
|
|
|
184767
184798
|
}
|
|
184768
184799
|
const isSubmitFocused = focusedIndex === options.length;
|
|
184769
184800
|
useInput((input, key) => {
|
|
184801
|
+
if (phase === "installing-ca" && caInstallPhase === "prompt" && key.return) {
|
|
184802
|
+
setCaInstallPhase("installing");
|
|
184803
|
+
return;
|
|
184804
|
+
}
|
|
184770
184805
|
if (phase !== "agents") return;
|
|
184771
184806
|
if (key.upArrow || input === "k") {
|
|
184772
184807
|
setFocusedIndex((prev) => Math.max(0, prev - 1));
|
|
@@ -184796,8 +184831,11 @@ function InitUI() {
|
|
|
184796
184831
|
}
|
|
184797
184832
|
}, [phase, exit]);
|
|
184798
184833
|
if (phase === "installing-ca") {
|
|
184834
|
+
if (caInstallPhase === "prompt") {
|
|
184835
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "We need to do a one-time setup for all your Specific projects."), /* @__PURE__ */ React2.createElement(Text2, null, "This is so we can run your apps locally with secure URLs:"), /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "green" }, "https://your-app.local.spcf.app"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "You will be prompted to authorize with your password."), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Press ", /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Enter"), " to authorize."));
|
|
184836
|
+
}
|
|
184799
184837
|
if (caInstallPhase === "installing") {
|
|
184800
|
-
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "
|
|
184838
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Awaiting authorization\u2026"));
|
|
184801
184839
|
}
|
|
184802
184840
|
}
|
|
184803
184841
|
if (phase === "done") {
|
|
@@ -184917,7 +184955,7 @@ var BETA_REGISTRY = [
|
|
|
184917
184955
|
];
|
|
184918
184956
|
|
|
184919
184957
|
// src/lib/beta/storage.ts
|
|
184920
|
-
import { readFileSync as readFileSync5, writeFileSync as
|
|
184958
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync6, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
184921
184959
|
import { join as join7 } from "path";
|
|
184922
184960
|
var BETAS_FILE = ".specific/betas.json";
|
|
184923
184961
|
function loadEnabledBetas(projectDir = process.cwd()) {
|
|
@@ -184950,7 +184988,7 @@ function saveBetas(enabled, projectDir) {
|
|
|
184950
184988
|
mkdirSync6(specificDir, { recursive: true });
|
|
184951
184989
|
}
|
|
184952
184990
|
const data = { enabled };
|
|
184953
|
-
|
|
184991
|
+
writeFileSync6(
|
|
184954
184992
|
join7(projectDir, BETAS_FILE),
|
|
184955
184993
|
JSON.stringify(data, null, 2) + "\n"
|
|
184956
184994
|
);
|
|
@@ -185017,7 +185055,7 @@ function resolveFilesystemDoc(path30) {
|
|
|
185017
185055
|
import React3, { useState as useState2, useEffect as useEffect2 } from "react";
|
|
185018
185056
|
import { render as render3, Text as Text3, Box as Box3 } from "ink";
|
|
185019
185057
|
import Spinner3 from "ink-spinner";
|
|
185020
|
-
import * as
|
|
185058
|
+
import * as fs14 from "fs";
|
|
185021
185059
|
import * as path9 from "path";
|
|
185022
185060
|
import { execFile as execFile7 } from "child_process";
|
|
185023
185061
|
|
|
@@ -185889,32 +185927,32 @@ var ExtractionError = class extends Error {
|
|
|
185889
185927
|
};
|
|
185890
185928
|
|
|
185891
185929
|
// src/lib/bin/manager.ts
|
|
185892
|
-
import * as
|
|
185930
|
+
import * as fs13 from "fs";
|
|
185893
185931
|
import * as path8 from "path";
|
|
185894
|
-
import * as
|
|
185932
|
+
import * as os8 from "os";
|
|
185895
185933
|
import { createReadStream } from "fs";
|
|
185896
185934
|
import { createTarExtractor, extractTo } from "tar-vern";
|
|
185897
185935
|
function getLibraryEnv(binary) {
|
|
185898
185936
|
if (!binary.libraryPath) {
|
|
185899
185937
|
return {};
|
|
185900
185938
|
}
|
|
185901
|
-
const
|
|
185902
|
-
if (
|
|
185939
|
+
const platform6 = os8.platform();
|
|
185940
|
+
if (platform6 === "darwin") {
|
|
185903
185941
|
return { DYLD_LIBRARY_PATH: binary.libraryPath };
|
|
185904
|
-
} else if (
|
|
185942
|
+
} else if (platform6 === "linux") {
|
|
185905
185943
|
return { LD_LIBRARY_PATH: binary.libraryPath };
|
|
185906
185944
|
}
|
|
185907
185945
|
return {};
|
|
185908
185946
|
}
|
|
185909
185947
|
function getBinBaseDir() {
|
|
185910
|
-
return path8.join(
|
|
185948
|
+
return path8.join(os8.homedir(), ".specific", "bin");
|
|
185911
185949
|
}
|
|
185912
185950
|
function getPlatformInfo() {
|
|
185913
|
-
const
|
|
185914
|
-
const arch3 =
|
|
185915
|
-
if (
|
|
185951
|
+
const platform6 = os8.platform();
|
|
185952
|
+
const arch3 = os8.arch();
|
|
185953
|
+
if (platform6 !== "darwin" && platform6 !== "linux") {
|
|
185916
185954
|
throw new Error(
|
|
185917
|
-
`Unsupported platform: ${
|
|
185955
|
+
`Unsupported platform: ${platform6}. Only macOS and Linux are supported.`
|
|
185918
185956
|
);
|
|
185919
185957
|
}
|
|
185920
185958
|
const archStr = arch3;
|
|
@@ -185928,7 +185966,7 @@ function getPlatformInfo() {
|
|
|
185928
185966
|
`Unsupported architecture: ${arch3}. Only x64 and arm64 are supported.`
|
|
185929
185967
|
);
|
|
185930
185968
|
}
|
|
185931
|
-
return { platform:
|
|
185969
|
+
return { platform: platform6, arch: mappedArch };
|
|
185932
185970
|
}
|
|
185933
185971
|
function getBinaryDir(definition, version, platformInfo) {
|
|
185934
185972
|
return path8.join(
|
|
@@ -185942,7 +185980,7 @@ function isBinaryInstalled(definition, version, platformInfo) {
|
|
|
185942
185980
|
const binDir = getBinaryDir(definition, version, platformInfo);
|
|
185943
185981
|
for (const execPath of definition.executables) {
|
|
185944
185982
|
const fullPath = path8.join(binDir, execPath);
|
|
185945
|
-
if (!
|
|
185983
|
+
if (!fs13.existsSync(fullPath)) {
|
|
185946
185984
|
return false;
|
|
185947
185985
|
}
|
|
185948
185986
|
}
|
|
@@ -185971,11 +186009,11 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
185971
186009
|
);
|
|
185972
186010
|
let bytesDownloaded = 0;
|
|
185973
186011
|
const parentDir = path8.dirname(destPath);
|
|
185974
|
-
if (!
|
|
185975
|
-
|
|
186012
|
+
if (!fs13.existsSync(parentDir)) {
|
|
186013
|
+
fs13.mkdirSync(parentDir, { recursive: true });
|
|
185976
186014
|
}
|
|
185977
186015
|
const partPath = destPath + ".part";
|
|
185978
|
-
const fileStream =
|
|
186016
|
+
const fileStream = fs13.createWriteStream(partPath);
|
|
185979
186017
|
try {
|
|
185980
186018
|
const reader = response.body.getReader();
|
|
185981
186019
|
while (true) {
|
|
@@ -185998,12 +186036,12 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
185998
186036
|
else resolve10();
|
|
185999
186037
|
});
|
|
186000
186038
|
});
|
|
186001
|
-
|
|
186039
|
+
fs13.renameSync(partPath, destPath);
|
|
186002
186040
|
} catch (error) {
|
|
186003
186041
|
try {
|
|
186004
186042
|
fileStream.close();
|
|
186005
|
-
if (
|
|
186006
|
-
|
|
186043
|
+
if (fs13.existsSync(partPath)) {
|
|
186044
|
+
fs13.unlinkSync(partPath);
|
|
186007
186045
|
}
|
|
186008
186046
|
} catch {
|
|
186009
186047
|
}
|
|
@@ -186012,8 +186050,8 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
186012
186050
|
}
|
|
186013
186051
|
async function extractTarball(archivePath, destDir, definition, onProgress) {
|
|
186014
186052
|
onProgress?.({ phase: "extracting" });
|
|
186015
|
-
if (!
|
|
186016
|
-
|
|
186053
|
+
if (!fs13.existsSync(destDir)) {
|
|
186054
|
+
fs13.mkdirSync(destDir, { recursive: true });
|
|
186017
186055
|
}
|
|
186018
186056
|
try {
|
|
186019
186057
|
const fileStream = createReadStream(archivePath);
|
|
@@ -186022,8 +186060,8 @@ async function extractTarball(archivePath, destDir, definition, onProgress) {
|
|
|
186022
186060
|
onProgress?.({ phase: "finalizing" });
|
|
186023
186061
|
for (const execPath of definition.executables) {
|
|
186024
186062
|
const fullPath = path8.join(destDir, execPath);
|
|
186025
|
-
if (
|
|
186026
|
-
|
|
186063
|
+
if (fs13.existsSync(fullPath)) {
|
|
186064
|
+
fs13.chmodSync(fullPath, 493);
|
|
186027
186065
|
}
|
|
186028
186066
|
}
|
|
186029
186067
|
} catch (error) {
|
|
@@ -186047,12 +186085,12 @@ async function ensureBinary(definition, version, onProgress) {
|
|
|
186047
186085
|
`Binary type definitions must have exactly one executable, got ${definition.executables.length}`
|
|
186048
186086
|
);
|
|
186049
186087
|
}
|
|
186050
|
-
if (!
|
|
186051
|
-
|
|
186088
|
+
if (!fs13.existsSync(binDir)) {
|
|
186089
|
+
fs13.mkdirSync(binDir, { recursive: true });
|
|
186052
186090
|
}
|
|
186053
186091
|
const execPath = path8.join(binDir, definition.executables[0]);
|
|
186054
186092
|
await downloadFile(url, execPath, onProgress);
|
|
186055
|
-
|
|
186093
|
+
fs13.chmodSync(execPath, 493);
|
|
186056
186094
|
onProgress?.({ phase: "finalizing" });
|
|
186057
186095
|
} else {
|
|
186058
186096
|
const downloadDir = path8.join(getBinBaseDir(), "downloads");
|
|
@@ -186063,8 +186101,8 @@ async function ensureBinary(definition, version, onProgress) {
|
|
|
186063
186101
|
await extractTarball(archivePath, binDir, definition, onProgress);
|
|
186064
186102
|
} finally {
|
|
186065
186103
|
try {
|
|
186066
|
-
if (
|
|
186067
|
-
|
|
186104
|
+
if (fs13.existsSync(archivePath)) {
|
|
186105
|
+
fs13.unlinkSync(archivePath);
|
|
186068
186106
|
}
|
|
186069
186107
|
} catch {
|
|
186070
186108
|
}
|
|
@@ -186240,20 +186278,20 @@ function CheckUI() {
|
|
|
186240
186278
|
useEffect2(() => {
|
|
186241
186279
|
async function load() {
|
|
186242
186280
|
const configPath = path9.join(process.cwd(), "specific.hcl");
|
|
186243
|
-
if (!
|
|
186281
|
+
if (!fs14.existsSync(configPath)) {
|
|
186244
186282
|
setState({
|
|
186245
186283
|
status: "error",
|
|
186246
186284
|
error: "No specific.hcl found in current directory"
|
|
186247
186285
|
});
|
|
186248
186286
|
return;
|
|
186249
186287
|
}
|
|
186250
|
-
const hcl =
|
|
186288
|
+
const hcl = fs14.readFileSync(configPath, "utf-8");
|
|
186251
186289
|
try {
|
|
186252
186290
|
const config2 = await parseConfig(hcl);
|
|
186253
186291
|
for (const build of config2.builds) {
|
|
186254
186292
|
if (build.dockerfile) {
|
|
186255
186293
|
const dockerfilePath = path9.resolve(process.cwd(), build.dockerfile);
|
|
186256
|
-
if (!
|
|
186294
|
+
if (!fs14.existsSync(dockerfilePath)) {
|
|
186257
186295
|
setState({
|
|
186258
186296
|
status: "error",
|
|
186259
186297
|
error: `Build "${build.name}": Dockerfile not found at "${build.dockerfile}" (resolved to ${dockerfilePath})`
|
|
@@ -186269,7 +186307,7 @@ function CheckUI() {
|
|
|
186269
186307
|
process.cwd(),
|
|
186270
186308
|
pg.reshape.migrations_dir ?? "migrations"
|
|
186271
186309
|
);
|
|
186272
|
-
if (!
|
|
186310
|
+
if (!fs14.existsSync(migrationsDir)) {
|
|
186273
186311
|
reshapeChecks2.push({
|
|
186274
186312
|
databaseName: pg.name,
|
|
186275
186313
|
migrationsDir: pg.reshape.migrations_dir ?? "migrations",
|
|
@@ -186320,9 +186358,9 @@ function checkCommand() {
|
|
|
186320
186358
|
|
|
186321
186359
|
// src/commands/dev.tsx
|
|
186322
186360
|
import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
|
|
186323
|
-
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
|
|
186361
|
+
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static, useInput as useInput4 } from "ink";
|
|
186324
186362
|
import Spinner4 from "ink-spinner";
|
|
186325
|
-
import * as
|
|
186363
|
+
import * as fs24 from "fs";
|
|
186326
186364
|
import * as path20 from "path";
|
|
186327
186365
|
|
|
186328
186366
|
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
@@ -188077,7 +188115,7 @@ var PortAllocator = class {
|
|
|
188077
188115
|
};
|
|
188078
188116
|
|
|
188079
188117
|
// src/lib/dev/stable-port-allocator.ts
|
|
188080
|
-
import * as
|
|
188118
|
+
import * as fs15 from "fs";
|
|
188081
188119
|
import * as path10 from "path";
|
|
188082
188120
|
var PORT_RANGE_START2 = 4e4;
|
|
188083
188121
|
var PORT_RANGE_END2 = 49999;
|
|
@@ -188092,11 +188130,11 @@ var StablePortAllocator = class {
|
|
|
188092
188130
|
this.loadPorts();
|
|
188093
188131
|
}
|
|
188094
188132
|
loadPorts() {
|
|
188095
|
-
if (!
|
|
188133
|
+
if (!fs15.existsSync(this.portsFilePath)) {
|
|
188096
188134
|
return;
|
|
188097
188135
|
}
|
|
188098
188136
|
try {
|
|
188099
|
-
const content =
|
|
188137
|
+
const content = fs15.readFileSync(this.portsFilePath, "utf-8");
|
|
188100
188138
|
const data = JSON.parse(content);
|
|
188101
188139
|
if (data.version === 1 && data.ports) {
|
|
188102
188140
|
this.savedPorts = data.ports;
|
|
@@ -188109,14 +188147,14 @@ var StablePortAllocator = class {
|
|
|
188109
188147
|
}
|
|
188110
188148
|
}
|
|
188111
188149
|
savePorts() {
|
|
188112
|
-
if (!
|
|
188113
|
-
|
|
188150
|
+
if (!fs15.existsSync(this.portsDir)) {
|
|
188151
|
+
fs15.mkdirSync(this.portsDir, { recursive: true });
|
|
188114
188152
|
}
|
|
188115
188153
|
const data = {
|
|
188116
188154
|
version: 1,
|
|
188117
188155
|
ports: this.savedPorts
|
|
188118
188156
|
};
|
|
188119
|
-
|
|
188157
|
+
fs15.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
|
|
188120
188158
|
}
|
|
188121
188159
|
allocateRandom() {
|
|
188122
188160
|
const rangeSize = PORT_RANGE_END2 - PORT_RANGE_START2 + 1;
|
|
@@ -188143,7 +188181,7 @@ var StablePortAllocator = class {
|
|
|
188143
188181
|
};
|
|
188144
188182
|
|
|
188145
188183
|
// src/lib/dev/database-manager.ts
|
|
188146
|
-
import * as
|
|
188184
|
+
import * as fs16 from "fs";
|
|
188147
188185
|
import * as path11 from "path";
|
|
188148
188186
|
import * as net from "net";
|
|
188149
188187
|
import { spawn } from "child_process";
|
|
@@ -188155,9 +188193,9 @@ async function startPostgres(pg, port, dataDir, onProgress) {
|
|
|
188155
188193
|
const password = "postgres";
|
|
188156
188194
|
const libraryEnv = getLibraryEnv(binary);
|
|
188157
188195
|
const env2 = { ...process.env, ...libraryEnv };
|
|
188158
|
-
const dataExists =
|
|
188196
|
+
const dataExists = fs16.existsSync(dbDataPath);
|
|
188159
188197
|
if (!dataExists) {
|
|
188160
|
-
|
|
188198
|
+
fs16.mkdirSync(dbDataPath, { recursive: true });
|
|
188161
188199
|
await runCommand(
|
|
188162
188200
|
binary.executables["initdb"],
|
|
188163
188201
|
["-D", dbDataPath, "-U", user, "--auth=trust", "--no-locale", "-E", "UTF8"],
|
|
@@ -188234,8 +188272,8 @@ async function startRedis(redis, port, onProgress) {
|
|
|
188234
188272
|
async function startStorage(storage, port, dataDir) {
|
|
188235
188273
|
const S3rver = (await import("s3rver")).default;
|
|
188236
188274
|
const storageDataPath = path11.join(process.cwd(), dataDir, storage.name);
|
|
188237
|
-
if (!
|
|
188238
|
-
|
|
188275
|
+
if (!fs16.existsSync(storageDataPath)) {
|
|
188276
|
+
fs16.mkdirSync(storageDataPath, { recursive: true });
|
|
188239
188277
|
}
|
|
188240
188278
|
const host = "127.0.0.1";
|
|
188241
188279
|
const accessKey = "S3RVER";
|
|
@@ -188878,7 +188916,7 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
|
|
|
188878
188916
|
}
|
|
188879
188917
|
|
|
188880
188918
|
// src/lib/dev/instance-state.ts
|
|
188881
|
-
import * as
|
|
188919
|
+
import * as fs17 from "fs";
|
|
188882
188920
|
import * as path12 from "path";
|
|
188883
188921
|
var InstanceStateManager = class {
|
|
188884
188922
|
stateDir;
|
|
@@ -188896,8 +188934,8 @@ var InstanceStateManager = class {
|
|
|
188896
188934
|
return this.key;
|
|
188897
188935
|
}
|
|
188898
188936
|
ensureStateDir() {
|
|
188899
|
-
if (!
|
|
188900
|
-
|
|
188937
|
+
if (!fs17.existsSync(this.stateDir)) {
|
|
188938
|
+
fs17.mkdirSync(this.stateDir, { recursive: true });
|
|
188901
188939
|
}
|
|
188902
188940
|
}
|
|
188903
188941
|
isProcessRunning(pid) {
|
|
@@ -188914,15 +188952,15 @@ var InstanceStateManager = class {
|
|
|
188914
188952
|
const startTime = Date.now();
|
|
188915
188953
|
while (Date.now() - startTime < timeoutMs) {
|
|
188916
188954
|
try {
|
|
188917
|
-
const fd =
|
|
188955
|
+
const fd = fs17.openSync(
|
|
188918
188956
|
this.lockPath,
|
|
188919
|
-
|
|
188957
|
+
fs17.constants.O_CREAT | fs17.constants.O_EXCL | fs17.constants.O_WRONLY
|
|
188920
188958
|
);
|
|
188921
|
-
|
|
188922
|
-
|
|
188959
|
+
fs17.writeSync(fd, String(process.pid));
|
|
188960
|
+
fs17.closeSync(fd);
|
|
188923
188961
|
return () => {
|
|
188924
188962
|
try {
|
|
188925
|
-
|
|
188963
|
+
fs17.unlinkSync(this.lockPath);
|
|
188926
188964
|
} catch {
|
|
188927
188965
|
}
|
|
188928
188966
|
};
|
|
@@ -188931,16 +188969,16 @@ var InstanceStateManager = class {
|
|
|
188931
188969
|
if (err.code === "EEXIST") {
|
|
188932
188970
|
try {
|
|
188933
188971
|
const lockPid = parseInt(
|
|
188934
|
-
|
|
188972
|
+
fs17.readFileSync(this.lockPath, "utf-8").trim(),
|
|
188935
188973
|
10
|
|
188936
188974
|
);
|
|
188937
188975
|
if (!this.isProcessRunning(lockPid)) {
|
|
188938
|
-
|
|
188976
|
+
fs17.unlinkSync(this.lockPath);
|
|
188939
188977
|
continue;
|
|
188940
188978
|
}
|
|
188941
188979
|
} catch {
|
|
188942
188980
|
try {
|
|
188943
|
-
|
|
188981
|
+
fs17.unlinkSync(this.lockPath);
|
|
188944
188982
|
} catch {
|
|
188945
188983
|
}
|
|
188946
188984
|
continue;
|
|
@@ -188954,12 +188992,12 @@ var InstanceStateManager = class {
|
|
|
188954
188992
|
throw new Error("Failed to acquire state lock (timeout)");
|
|
188955
188993
|
}
|
|
188956
188994
|
async getExistingInstances() {
|
|
188957
|
-
if (!
|
|
188995
|
+
if (!fs17.existsSync(this.statePath)) {
|
|
188958
188996
|
return null;
|
|
188959
188997
|
}
|
|
188960
188998
|
const releaseLock = await this.acquireLock();
|
|
188961
188999
|
try {
|
|
188962
|
-
const content =
|
|
189000
|
+
const content = fs17.readFileSync(this.statePath, "utf-8");
|
|
188963
189001
|
const state = JSON.parse(content);
|
|
188964
189002
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
188965
189003
|
return null;
|
|
@@ -188972,21 +189010,21 @@ var InstanceStateManager = class {
|
|
|
188972
189010
|
}
|
|
188973
189011
|
}
|
|
188974
189012
|
async cleanStaleState() {
|
|
188975
|
-
if (!
|
|
189013
|
+
if (!fs17.existsSync(this.statePath)) {
|
|
188976
189014
|
return false;
|
|
188977
189015
|
}
|
|
188978
189016
|
const releaseLock = await this.acquireLock();
|
|
188979
189017
|
try {
|
|
188980
|
-
const content =
|
|
189018
|
+
const content = fs17.readFileSync(this.statePath, "utf-8");
|
|
188981
189019
|
const state = JSON.parse(content);
|
|
188982
189020
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
188983
|
-
|
|
189021
|
+
fs17.unlinkSync(this.statePath);
|
|
188984
189022
|
return true;
|
|
188985
189023
|
}
|
|
188986
189024
|
return false;
|
|
188987
189025
|
} catch {
|
|
188988
189026
|
try {
|
|
188989
|
-
|
|
189027
|
+
fs17.unlinkSync(this.statePath);
|
|
188990
189028
|
return true;
|
|
188991
189029
|
} catch {
|
|
188992
189030
|
}
|
|
@@ -188998,8 +189036,8 @@ var InstanceStateManager = class {
|
|
|
188998
189036
|
async claimOwnership(command) {
|
|
188999
189037
|
const releaseLock = await this.acquireLock();
|
|
189000
189038
|
try {
|
|
189001
|
-
if (
|
|
189002
|
-
const content =
|
|
189039
|
+
if (fs17.existsSync(this.statePath)) {
|
|
189040
|
+
const content = fs17.readFileSync(this.statePath, "utf-8");
|
|
189003
189041
|
const state2 = JSON.parse(content);
|
|
189004
189042
|
if (this.isProcessRunning(state2.owner.pid)) {
|
|
189005
189043
|
throw new Error(`Instances already owned by PID ${state2.owner.pid}`);
|
|
@@ -189068,8 +189106,8 @@ var InstanceStateManager = class {
|
|
|
189068
189106
|
}
|
|
189069
189107
|
const releaseLock = await this.acquireLock();
|
|
189070
189108
|
try {
|
|
189071
|
-
if (
|
|
189072
|
-
|
|
189109
|
+
if (fs17.existsSync(this.statePath)) {
|
|
189110
|
+
fs17.unlinkSync(this.statePath);
|
|
189073
189111
|
}
|
|
189074
189112
|
this.ownsInstances = false;
|
|
189075
189113
|
} finally {
|
|
@@ -189077,21 +189115,21 @@ var InstanceStateManager = class {
|
|
|
189077
189115
|
}
|
|
189078
189116
|
}
|
|
189079
189117
|
readState() {
|
|
189080
|
-
const content =
|
|
189118
|
+
const content = fs17.readFileSync(this.statePath, "utf-8");
|
|
189081
189119
|
return JSON.parse(content);
|
|
189082
189120
|
}
|
|
189083
189121
|
writeStateAtomic(state) {
|
|
189084
189122
|
this.ensureStateDir();
|
|
189085
189123
|
const tmpPath = this.statePath + ".tmp";
|
|
189086
|
-
|
|
189087
|
-
|
|
189124
|
+
fs17.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
|
|
189125
|
+
fs17.renameSync(tmpPath, this.statePath);
|
|
189088
189126
|
}
|
|
189089
189127
|
};
|
|
189090
189128
|
|
|
189091
189129
|
// src/lib/dev/http-proxy.ts
|
|
189092
189130
|
import * as http from "http";
|
|
189093
189131
|
import * as https from "https";
|
|
189094
|
-
import * as
|
|
189132
|
+
import * as fs18 from "fs";
|
|
189095
189133
|
import * as path13 from "path";
|
|
189096
189134
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
189097
189135
|
import httpProxy from "http-proxy";
|
|
@@ -189499,10 +189537,10 @@ function serveFilesystemFile(res, pathname) {
|
|
|
189499
189537
|
res.end("<h1>Forbidden</h1>");
|
|
189500
189538
|
return;
|
|
189501
189539
|
}
|
|
189502
|
-
if (
|
|
189503
|
-
if (
|
|
189540
|
+
if (fs18.existsSync(resolvedPath)) {
|
|
189541
|
+
if (fs18.statSync(resolvedPath).isDirectory()) {
|
|
189504
189542
|
const indexPath2 = path13.join(resolvedPath, "index.html");
|
|
189505
|
-
if (
|
|
189543
|
+
if (fs18.existsSync(indexPath2)) {
|
|
189506
189544
|
return serveFile(res, indexPath2);
|
|
189507
189545
|
}
|
|
189508
189546
|
} else {
|
|
@@ -189510,15 +189548,15 @@ function serveFilesystemFile(res, pathname) {
|
|
|
189510
189548
|
}
|
|
189511
189549
|
}
|
|
189512
189550
|
const htmlPath = resolvedPath + ".html";
|
|
189513
|
-
if (
|
|
189551
|
+
if (fs18.existsSync(htmlPath)) {
|
|
189514
189552
|
return serveFile(res, htmlPath);
|
|
189515
189553
|
}
|
|
189516
189554
|
const indexPath = path13.join(resolvedPath, "index.html");
|
|
189517
|
-
if (
|
|
189555
|
+
if (fs18.existsSync(indexPath)) {
|
|
189518
189556
|
return serveFile(res, indexPath);
|
|
189519
189557
|
}
|
|
189520
189558
|
const notFoundPath = path13.join(adminDir, "404.html");
|
|
189521
|
-
if (
|
|
189559
|
+
if (fs18.existsSync(notFoundPath)) {
|
|
189522
189560
|
return serveFileContent(res, notFoundPath, "text/html", 404);
|
|
189523
189561
|
}
|
|
189524
189562
|
res.writeHead(404, { "Content-Type": "text/html" });
|
|
@@ -189531,7 +189569,7 @@ function serveFile(res, filePath) {
|
|
|
189531
189569
|
}
|
|
189532
189570
|
function serveFileContent(res, filePath, contentType, statusCode = 200) {
|
|
189533
189571
|
try {
|
|
189534
|
-
const content =
|
|
189572
|
+
const content = fs18.readFileSync(filePath);
|
|
189535
189573
|
res.writeHead(statusCode, { "Content-Type": contentType });
|
|
189536
189574
|
res.end(content);
|
|
189537
189575
|
} catch (err) {
|
|
@@ -189906,7 +189944,7 @@ async function startMailServer(mail, smtpPort, apiPort) {
|
|
|
189906
189944
|
|
|
189907
189945
|
// src/lib/dev/drizzle-gateway-manager.ts
|
|
189908
189946
|
import * as net3 from "net";
|
|
189909
|
-
import * as
|
|
189947
|
+
import * as fs19 from "fs";
|
|
189910
189948
|
import * as path15 from "path";
|
|
189911
189949
|
import { spawn as spawn4 } from "child_process";
|
|
189912
189950
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -189940,12 +189978,12 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
|
|
|
189940
189978
|
);
|
|
189941
189979
|
const host = "127.0.0.1";
|
|
189942
189980
|
const drizzleConfigDir = path15.join(configDir, "drizzle-gateway");
|
|
189943
|
-
if (!
|
|
189944
|
-
|
|
189981
|
+
if (!fs19.existsSync(drizzleConfigDir)) {
|
|
189982
|
+
fs19.mkdirSync(drizzleConfigDir, { recursive: true });
|
|
189945
189983
|
}
|
|
189946
189984
|
const storeJson = generateStoreJson(postgresInstances);
|
|
189947
189985
|
const storeJsonPath = path15.join(drizzleConfigDir, "store.json");
|
|
189948
|
-
|
|
189986
|
+
fs19.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
|
|
189949
189987
|
writeLog("drizzle-gateway", `Starting Drizzle Gateway`);
|
|
189950
189988
|
writeLog("drizzle-gateway", `STORE_PATH: ${drizzleConfigDir}`);
|
|
189951
189989
|
writeLog("drizzle-gateway", `PORT: ${port}`);
|
|
@@ -190047,16 +190085,16 @@ function detectSyncDatabases(config) {
|
|
|
190047
190085
|
}
|
|
190048
190086
|
|
|
190049
190087
|
// src/lib/dev/reshape-watcher.ts
|
|
190050
|
-
import * as
|
|
190088
|
+
import * as fs20 from "fs";
|
|
190051
190089
|
import * as path16 from "path";
|
|
190052
190090
|
import { spawnSync } from "child_process";
|
|
190053
190091
|
function getMigrationFiles(dir, log) {
|
|
190054
190092
|
log(`Scanning migrations directory: ${dir}`);
|
|
190055
|
-
if (!
|
|
190093
|
+
if (!fs20.existsSync(dir)) {
|
|
190056
190094
|
log(`Migrations directory does not exist: ${dir}`);
|
|
190057
190095
|
return [];
|
|
190058
190096
|
}
|
|
190059
|
-
const files =
|
|
190097
|
+
const files = fs20.readdirSync(dir);
|
|
190060
190098
|
log(`Found ${files.length} files in directory`);
|
|
190061
190099
|
const tomlFiles = files.filter((f) => f.endsWith(".toml")).sort((a, b) => a.localeCompare(b));
|
|
190062
190100
|
log(`Found ${tomlFiles.length} .toml migration files: ${tomlFiles.join(", ") || "(none)"}`);
|
|
@@ -190106,7 +190144,7 @@ function runReshape(args, databaseUrl, migrationsDir, reshapeBinaryPath, log) {
|
|
|
190106
190144
|
}
|
|
190107
190145
|
function makeReadOnly(filePath, log) {
|
|
190108
190146
|
try {
|
|
190109
|
-
|
|
190147
|
+
fs20.chmodSync(filePath, 292);
|
|
190110
190148
|
log(`Set file permissions to read-only (444): ${filePath}`);
|
|
190111
190149
|
} catch (err) {
|
|
190112
190150
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -190192,9 +190230,9 @@ function createReshapeWatcher(options2) {
|
|
|
190192
190230
|
};
|
|
190193
190231
|
const startWatching = () => {
|
|
190194
190232
|
log(`Starting file watcher for migrations directory...`);
|
|
190195
|
-
if (!
|
|
190233
|
+
if (!fs20.existsSync(migrationsDir)) {
|
|
190196
190234
|
log(`Migrations directory does not exist, creating: ${migrationsDir}`);
|
|
190197
|
-
|
|
190235
|
+
fs20.mkdirSync(migrationsDir, { recursive: true });
|
|
190198
190236
|
}
|
|
190199
190237
|
log(`Watching directory: ${migrationsDir}`);
|
|
190200
190238
|
watcher = chokidar_default.watch(migrationsDir, {
|
|
@@ -190329,7 +190367,7 @@ function createReshapeWatcher(options2) {
|
|
|
190329
190367
|
}
|
|
190330
190368
|
|
|
190331
190369
|
// src/lib/dev/temporal-manager.ts
|
|
190332
|
-
import * as
|
|
190370
|
+
import * as fs21 from "fs";
|
|
190333
190371
|
import * as path17 from "path";
|
|
190334
190372
|
import * as net4 from "net";
|
|
190335
190373
|
import { spawn as spawn5 } from "child_process";
|
|
@@ -190337,8 +190375,8 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
|
|
|
190337
190375
|
const binary = await ensureBinary(temporalBinary, void 0, onProgress);
|
|
190338
190376
|
const dbPath = path17.join(process.cwd(), dataDir, "temporal.db");
|
|
190339
190377
|
const dbDir = path17.dirname(dbPath);
|
|
190340
|
-
if (!
|
|
190341
|
-
|
|
190378
|
+
if (!fs21.existsSync(dbDir)) {
|
|
190379
|
+
fs21.mkdirSync(dbDir, { recursive: true });
|
|
190342
190380
|
}
|
|
190343
190381
|
const host = "127.0.0.1";
|
|
190344
190382
|
const namespaceArgs = temporals.flatMap((t) => ["--namespace", t.name]);
|
|
@@ -190667,7 +190705,7 @@ function watchConfigFile(configPath, debounceMs, onChange) {
|
|
|
190667
190705
|
}
|
|
190668
190706
|
|
|
190669
190707
|
// src/lib/dev/subdomain-generator.ts
|
|
190670
|
-
import * as
|
|
190708
|
+
import * as fs22 from "fs";
|
|
190671
190709
|
import * as path18 from "path";
|
|
190672
190710
|
import { generateSlug } from "random-word-slugs";
|
|
190673
190711
|
var StableSubdomainAllocator = class {
|
|
@@ -190680,11 +190718,11 @@ var StableSubdomainAllocator = class {
|
|
|
190680
190718
|
this.loadTunnels();
|
|
190681
190719
|
}
|
|
190682
190720
|
loadTunnels() {
|
|
190683
|
-
if (!
|
|
190721
|
+
if (!fs22.existsSync(this.tunnelsFilePath)) {
|
|
190684
190722
|
return;
|
|
190685
190723
|
}
|
|
190686
190724
|
try {
|
|
190687
|
-
const content =
|
|
190725
|
+
const content = fs22.readFileSync(this.tunnelsFilePath, "utf-8");
|
|
190688
190726
|
const data = JSON.parse(content);
|
|
190689
190727
|
if (data.version === 1 && data.baseSlug) {
|
|
190690
190728
|
this.baseSlug = data.baseSlug;
|
|
@@ -190694,14 +190732,14 @@ var StableSubdomainAllocator = class {
|
|
|
190694
190732
|
}
|
|
190695
190733
|
}
|
|
190696
190734
|
saveTunnels() {
|
|
190697
|
-
if (!
|
|
190698
|
-
|
|
190735
|
+
if (!fs22.existsSync(this.tunnelsDir)) {
|
|
190736
|
+
fs22.mkdirSync(this.tunnelsDir, { recursive: true });
|
|
190699
190737
|
}
|
|
190700
190738
|
const data = {
|
|
190701
190739
|
version: 1,
|
|
190702
190740
|
baseSlug: this.baseSlug
|
|
190703
190741
|
};
|
|
190704
|
-
|
|
190742
|
+
fs22.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
|
|
190705
190743
|
}
|
|
190706
190744
|
generateBaseSlug() {
|
|
190707
190745
|
return generateSlug(2, {
|
|
@@ -190857,9 +190895,9 @@ async function startTunnel(serviceName, endpointName, port, subdomain, callbacks
|
|
|
190857
190895
|
}
|
|
190858
190896
|
|
|
190859
190897
|
// src/lib/dev/proxy-registry.ts
|
|
190860
|
-
import * as
|
|
190898
|
+
import * as fs23 from "fs";
|
|
190861
190899
|
import * as path19 from "path";
|
|
190862
|
-
import * as
|
|
190900
|
+
import * as os9 from "os";
|
|
190863
190901
|
import * as net6 from "net";
|
|
190864
190902
|
var ProxyRegistryManager = class {
|
|
190865
190903
|
proxyDir;
|
|
@@ -190869,14 +190907,14 @@ var ProxyRegistryManager = class {
|
|
|
190869
190907
|
isOwner = false;
|
|
190870
190908
|
registryWatcher = null;
|
|
190871
190909
|
constructor() {
|
|
190872
|
-
this.proxyDir = path19.join(
|
|
190910
|
+
this.proxyDir = path19.join(os9.homedir(), ".specific", "proxy");
|
|
190873
190911
|
this.ownerPath = path19.join(this.proxyDir, "owner.json");
|
|
190874
190912
|
this.registryPath = path19.join(this.proxyDir, "registry.json");
|
|
190875
190913
|
this.lockPath = path19.join(this.proxyDir, "registry.lock");
|
|
190876
190914
|
}
|
|
190877
190915
|
ensureProxyDir() {
|
|
190878
|
-
if (!
|
|
190879
|
-
|
|
190916
|
+
if (!fs23.existsSync(this.proxyDir)) {
|
|
190917
|
+
fs23.mkdirSync(this.proxyDir, { recursive: true });
|
|
190880
190918
|
}
|
|
190881
190919
|
}
|
|
190882
190920
|
isProcessRunning(pid) {
|
|
@@ -190933,15 +190971,15 @@ var ProxyRegistryManager = class {
|
|
|
190933
190971
|
const startTime = Date.now();
|
|
190934
190972
|
while (Date.now() - startTime < timeoutMs) {
|
|
190935
190973
|
try {
|
|
190936
|
-
const fd =
|
|
190974
|
+
const fd = fs23.openSync(
|
|
190937
190975
|
this.lockPath,
|
|
190938
|
-
|
|
190976
|
+
fs23.constants.O_CREAT | fs23.constants.O_EXCL | fs23.constants.O_WRONLY
|
|
190939
190977
|
);
|
|
190940
|
-
|
|
190941
|
-
|
|
190978
|
+
fs23.writeSync(fd, String(process.pid));
|
|
190979
|
+
fs23.closeSync(fd);
|
|
190942
190980
|
return () => {
|
|
190943
190981
|
try {
|
|
190944
|
-
|
|
190982
|
+
fs23.unlinkSync(this.lockPath);
|
|
190945
190983
|
} catch {
|
|
190946
190984
|
}
|
|
190947
190985
|
};
|
|
@@ -190950,16 +190988,16 @@ var ProxyRegistryManager = class {
|
|
|
190950
190988
|
if (err.code === "EEXIST") {
|
|
190951
190989
|
try {
|
|
190952
190990
|
const lockPid = parseInt(
|
|
190953
|
-
|
|
190991
|
+
fs23.readFileSync(this.lockPath, "utf-8").trim(),
|
|
190954
190992
|
10
|
|
190955
190993
|
);
|
|
190956
190994
|
if (!this.isProcessRunning(lockPid)) {
|
|
190957
|
-
|
|
190995
|
+
fs23.unlinkSync(this.lockPath);
|
|
190958
190996
|
continue;
|
|
190959
190997
|
}
|
|
190960
190998
|
} catch {
|
|
190961
190999
|
try {
|
|
190962
|
-
|
|
191000
|
+
fs23.unlinkSync(this.lockPath);
|
|
190963
191001
|
} catch {
|
|
190964
191002
|
}
|
|
190965
191003
|
continue;
|
|
@@ -190979,8 +191017,8 @@ var ProxyRegistryManager = class {
|
|
|
190979
191017
|
async claimProxyOwnership(key) {
|
|
190980
191018
|
const releaseLock = await this.acquireLock();
|
|
190981
191019
|
try {
|
|
190982
|
-
if (
|
|
190983
|
-
const content =
|
|
191020
|
+
if (fs23.existsSync(this.ownerPath)) {
|
|
191021
|
+
const content = fs23.readFileSync(this.ownerPath, "utf-8");
|
|
190984
191022
|
const ownerFile2 = JSON.parse(content);
|
|
190985
191023
|
if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
|
|
190986
191024
|
return false;
|
|
@@ -191010,11 +191048,11 @@ var ProxyRegistryManager = class {
|
|
|
191010
191048
|
}
|
|
191011
191049
|
const releaseLock = await this.acquireLock();
|
|
191012
191050
|
try {
|
|
191013
|
-
if (
|
|
191014
|
-
const content =
|
|
191051
|
+
if (fs23.existsSync(this.ownerPath)) {
|
|
191052
|
+
const content = fs23.readFileSync(this.ownerPath, "utf-8");
|
|
191015
191053
|
const ownerFile = JSON.parse(content);
|
|
191016
191054
|
if (ownerFile.owner.pid === process.pid) {
|
|
191017
|
-
|
|
191055
|
+
fs23.unlinkSync(this.ownerPath);
|
|
191018
191056
|
}
|
|
191019
191057
|
}
|
|
191020
191058
|
this.isOwner = false;
|
|
@@ -191026,12 +191064,12 @@ var ProxyRegistryManager = class {
|
|
|
191026
191064
|
* Get the current proxy owner.
|
|
191027
191065
|
*/
|
|
191028
191066
|
async getProxyOwner() {
|
|
191029
|
-
if (!
|
|
191067
|
+
if (!fs23.existsSync(this.ownerPath)) {
|
|
191030
191068
|
return null;
|
|
191031
191069
|
}
|
|
191032
191070
|
const releaseLock = await this.acquireLock();
|
|
191033
191071
|
try {
|
|
191034
|
-
const content =
|
|
191072
|
+
const content = fs23.readFileSync(this.ownerPath, "utf-8");
|
|
191035
191073
|
const ownerFile = JSON.parse(content);
|
|
191036
191074
|
if (!await this.isProxyOwnerHealthy(ownerFile.owner.pid)) {
|
|
191037
191075
|
return null;
|
|
@@ -191128,7 +191166,7 @@ var ProxyRegistryManager = class {
|
|
|
191128
191166
|
*/
|
|
191129
191167
|
watchRegistry(onChange) {
|
|
191130
191168
|
this.ensureProxyDir();
|
|
191131
|
-
if (!
|
|
191169
|
+
if (!fs23.existsSync(this.registryPath)) {
|
|
191132
191170
|
const emptyRegistry = {
|
|
191133
191171
|
version: 1,
|
|
191134
191172
|
keys: {},
|
|
@@ -191171,13 +191209,13 @@ var ProxyRegistryManager = class {
|
|
|
191171
191209
|
async attemptElection(key) {
|
|
191172
191210
|
const releaseLock = await this.acquireLock();
|
|
191173
191211
|
try {
|
|
191174
|
-
if (
|
|
191175
|
-
const content =
|
|
191212
|
+
if (fs23.existsSync(this.ownerPath)) {
|
|
191213
|
+
const content = fs23.readFileSync(this.ownerPath, "utf-8");
|
|
191176
191214
|
const ownerFile2 = JSON.parse(content);
|
|
191177
191215
|
if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
|
|
191178
191216
|
return false;
|
|
191179
191217
|
}
|
|
191180
|
-
|
|
191218
|
+
fs23.unlinkSync(this.ownerPath);
|
|
191181
191219
|
}
|
|
191182
191220
|
const ownerFile = {
|
|
191183
191221
|
version: 1,
|
|
@@ -191195,7 +191233,7 @@ var ProxyRegistryManager = class {
|
|
|
191195
191233
|
}
|
|
191196
191234
|
}
|
|
191197
191235
|
readRegistry() {
|
|
191198
|
-
if (!
|
|
191236
|
+
if (!fs23.existsSync(this.registryPath)) {
|
|
191199
191237
|
return {
|
|
191200
191238
|
version: 1,
|
|
191201
191239
|
keys: {},
|
|
@@ -191203,7 +191241,7 @@ var ProxyRegistryManager = class {
|
|
|
191203
191241
|
};
|
|
191204
191242
|
}
|
|
191205
191243
|
try {
|
|
191206
|
-
const content =
|
|
191244
|
+
const content = fs23.readFileSync(this.registryPath, "utf-8");
|
|
191207
191245
|
return JSON.parse(content);
|
|
191208
191246
|
} catch {
|
|
191209
191247
|
return {
|
|
@@ -191216,8 +191254,8 @@ var ProxyRegistryManager = class {
|
|
|
191216
191254
|
writeFileAtomic(filePath, data) {
|
|
191217
191255
|
this.ensureProxyDir();
|
|
191218
191256
|
const tmpPath = filePath + ".tmp";
|
|
191219
|
-
|
|
191220
|
-
|
|
191257
|
+
fs23.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
191258
|
+
fs23.renameSync(tmpPath, filePath);
|
|
191221
191259
|
}
|
|
191222
191260
|
};
|
|
191223
191261
|
|
|
@@ -191326,7 +191364,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191326
191364
|
const setupDone = tunnelEnabled || !systemSetupNeeded();
|
|
191327
191365
|
return {
|
|
191328
191366
|
status: setupDone ? "loading" : "installing-ca",
|
|
191329
|
-
...setupDone ? {} : { caInstallPhase: "
|
|
191367
|
+
...setupDone ? {} : { caInstallPhase: "prompt" },
|
|
191330
191368
|
resources: /* @__PURE__ */ new Map(),
|
|
191331
191369
|
resourceStatus: /* @__PURE__ */ new Map(),
|
|
191332
191370
|
services: [],
|
|
@@ -191342,6 +191380,11 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191342
191380
|
installSystemConfig();
|
|
191343
191381
|
}
|
|
191344
191382
|
}, [state.status, state.caInstallPhase]);
|
|
191383
|
+
useInput4((_input, key) => {
|
|
191384
|
+
if (state.status === "installing-ca" && state.caInstallPhase === "prompt" && key.return) {
|
|
191385
|
+
setState((s) => ({ ...s, caInstallPhase: "installing" }));
|
|
191386
|
+
}
|
|
191387
|
+
});
|
|
191345
191388
|
async function installSystemConfig() {
|
|
191346
191389
|
try {
|
|
191347
191390
|
performSystemSetup();
|
|
@@ -191535,7 +191578,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191535
191578
|
const configPath = path20.join(process.cwd(), "specific.hcl");
|
|
191536
191579
|
const watcher = watchConfigFile(configPath, 1e3, () => {
|
|
191537
191580
|
try {
|
|
191538
|
-
const hcl =
|
|
191581
|
+
const hcl = fs24.readFileSync(configPath, "utf-8");
|
|
191539
191582
|
parseConfig(hcl).then(() => {
|
|
191540
191583
|
triggerReload();
|
|
191541
191584
|
}).catch((err) => {
|
|
@@ -191661,7 +191704,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191661
191704
|
return;
|
|
191662
191705
|
}
|
|
191663
191706
|
const configPath = path20.join(process.cwd(), "specific.hcl");
|
|
191664
|
-
if (!
|
|
191707
|
+
if (!fs24.existsSync(configPath)) {
|
|
191665
191708
|
writeLog("system", "Waiting for specific.hcl to appear");
|
|
191666
191709
|
setState((s) => ({
|
|
191667
191710
|
...s,
|
|
@@ -191679,7 +191722,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191679
191722
|
return;
|
|
191680
191723
|
}
|
|
191681
191724
|
let config2;
|
|
191682
|
-
const hcl =
|
|
191725
|
+
const hcl = fs24.readFileSync(configPath, "utf-8");
|
|
191683
191726
|
try {
|
|
191684
191727
|
config2 = await parseConfig(hcl);
|
|
191685
191728
|
} catch (err) {
|
|
@@ -192006,7 +192049,7 @@ Add them to the config block in specific.local`);
|
|
|
192006
192049
|
if (service.volumes) {
|
|
192007
192050
|
for (const vol of service.volumes) {
|
|
192008
192051
|
const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
|
|
192009
|
-
|
|
192052
|
+
fs24.mkdirSync(volumeDir, { recursive: true });
|
|
192010
192053
|
volumePaths.set(vol.name, volumeDir);
|
|
192011
192054
|
}
|
|
192012
192055
|
}
|
|
@@ -192062,7 +192105,7 @@ Add them to the config block in specific.local`);
|
|
|
192062
192105
|
if (service.volumes) {
|
|
192063
192106
|
for (const vol of service.volumes) {
|
|
192064
192107
|
const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
|
|
192065
|
-
|
|
192108
|
+
fs24.mkdirSync(volumeDir, { recursive: true });
|
|
192066
192109
|
volumePaths.set(vol.name, volumeDir);
|
|
192067
192110
|
}
|
|
192068
192111
|
}
|
|
@@ -192356,8 +192399,11 @@ Add them to the config block in specific.local`);
|
|
|
192356
192399
|
};
|
|
192357
192400
|
}, [reloadTrigger, readyToStart, instanceKey]);
|
|
192358
192401
|
if (state.status === "installing-ca") {
|
|
192402
|
+
if (state.caInstallPhase === "prompt") {
|
|
192403
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "We need to do a one-time setup for all your Specific projects."), /* @__PURE__ */ React6.createElement(Text6, null, "This is so we can run your apps locally with secure URLs:"), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "green" }, "https://your-app.local.spcf.app"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "You will be prompted to authorize with your password."), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Press ", /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Enter"), " to authorize."));
|
|
192404
|
+
}
|
|
192359
192405
|
if (state.caInstallPhase === "installing") {
|
|
192360
|
-
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "
|
|
192406
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Awaiting authorization\u2026"));
|
|
192361
192407
|
}
|
|
192362
192408
|
if (state.caInstallPhase === "error") {
|
|
192363
192409
|
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Setup failed: ", state.caError));
|
|
@@ -192630,7 +192676,7 @@ init_open();
|
|
|
192630
192676
|
import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
|
|
192631
192677
|
import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
192632
192678
|
import Spinner5 from "ink-spinner";
|
|
192633
|
-
import * as
|
|
192679
|
+
import * as fs26 from "fs";
|
|
192634
192680
|
import * as path23 from "path";
|
|
192635
192681
|
|
|
192636
192682
|
// src/lib/deploy/build-tester.ts
|
|
@@ -192815,7 +192861,7 @@ async function testAllBuilds(builds, projectDir) {
|
|
|
192815
192861
|
|
|
192816
192862
|
// src/lib/tarball/create.ts
|
|
192817
192863
|
import { execSync as execSync4 } from "child_process";
|
|
192818
|
-
import * as
|
|
192864
|
+
import * as fs25 from "fs";
|
|
192819
192865
|
import * as path22 from "path";
|
|
192820
192866
|
import { createTarPacker, createEntryItemGenerator } from "tar-vern";
|
|
192821
192867
|
function isInsideGitRepository(dir) {
|
|
@@ -192873,7 +192919,7 @@ var EXCLUDED_DIRS = [
|
|
|
192873
192919
|
];
|
|
192874
192920
|
async function collectPaths(baseDir, currentDir, exclude) {
|
|
192875
192921
|
const results = [];
|
|
192876
|
-
const entries = await
|
|
192922
|
+
const entries = await fs25.promises.readdir(currentDir, { withFileTypes: true });
|
|
192877
192923
|
for (const entry of entries) {
|
|
192878
192924
|
const fullPath = path22.join(currentDir, entry.name);
|
|
192879
192925
|
const relativePath = path22.relative(baseDir, fullPath);
|
|
@@ -192892,7 +192938,7 @@ async function collectPaths(baseDir, currentDir, exclude) {
|
|
|
192892
192938
|
async function createTarArchive(projectDir) {
|
|
192893
192939
|
writeLog("tarball", "Creating tarball using tar-vern (non-git project)");
|
|
192894
192940
|
const configPath = path22.join(projectDir, "specific.hcl");
|
|
192895
|
-
if (!
|
|
192941
|
+
if (!fs25.existsSync(configPath)) {
|
|
192896
192942
|
throw new Error("specific.hcl not found in project directory");
|
|
192897
192943
|
}
|
|
192898
192944
|
const relativePaths = await collectPaths(projectDir, projectDir, EXCLUDED_DIRS);
|
|
@@ -193825,12 +193871,12 @@ ${errorMsg}`
|
|
|
193825
193871
|
}
|
|
193826
193872
|
async function deployCommand(environment, options2) {
|
|
193827
193873
|
const configPath = path23.join(process.cwd(), "specific.hcl");
|
|
193828
|
-
if (!
|
|
193874
|
+
if (!fs26.existsSync(configPath)) {
|
|
193829
193875
|
console.error("Error: No specific.hcl found in current directory");
|
|
193830
193876
|
process.exit(1);
|
|
193831
193877
|
}
|
|
193832
193878
|
let config;
|
|
193833
|
-
const hcl =
|
|
193879
|
+
const hcl = fs26.readFileSync(configPath, "utf-8");
|
|
193834
193880
|
try {
|
|
193835
193881
|
config = await parseConfig(hcl);
|
|
193836
193882
|
} catch (err) {
|
|
@@ -193853,7 +193899,7 @@ async function deployCommand(environment, options2) {
|
|
|
193853
193899
|
|
|
193854
193900
|
// src/commands/exec.tsx
|
|
193855
193901
|
import { spawn as spawn7 } from "child_process";
|
|
193856
|
-
import * as
|
|
193902
|
+
import * as fs27 from "fs";
|
|
193857
193903
|
import * as path24 from "path";
|
|
193858
193904
|
async function execCommand(serviceName, command, instanceKey = "default") {
|
|
193859
193905
|
if (command.length === 0) {
|
|
@@ -193883,12 +193929,12 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
193883
193929
|
}
|
|
193884
193930
|
};
|
|
193885
193931
|
const configPath = path24.join(process.cwd(), "specific.hcl");
|
|
193886
|
-
if (!
|
|
193932
|
+
if (!fs27.existsSync(configPath)) {
|
|
193887
193933
|
console.error("Error: No specific.hcl found in current directory");
|
|
193888
193934
|
process.exit(1);
|
|
193889
193935
|
}
|
|
193890
193936
|
let config;
|
|
193891
|
-
const hcl =
|
|
193937
|
+
const hcl = fs27.readFileSync(configPath, "utf-8");
|
|
193892
193938
|
try {
|
|
193893
193939
|
config = await parseConfig(hcl);
|
|
193894
193940
|
} catch (err) {
|
|
@@ -194038,7 +194084,7 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
194038
194084
|
|
|
194039
194085
|
// src/commands/psql.tsx
|
|
194040
194086
|
import { spawn as spawn8 } from "child_process";
|
|
194041
|
-
import * as
|
|
194087
|
+
import * as fs28 from "fs";
|
|
194042
194088
|
import * as path25 from "path";
|
|
194043
194089
|
async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []) {
|
|
194044
194090
|
let startedResources = [];
|
|
@@ -194057,12 +194103,12 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
|
|
|
194057
194103
|
}
|
|
194058
194104
|
};
|
|
194059
194105
|
const configPath = path25.join(process.cwd(), "specific.hcl");
|
|
194060
|
-
if (!
|
|
194106
|
+
if (!fs28.existsSync(configPath)) {
|
|
194061
194107
|
console.error("Error: No specific.hcl found in current directory");
|
|
194062
194108
|
process.exit(1);
|
|
194063
194109
|
}
|
|
194064
194110
|
let config;
|
|
194065
|
-
const hcl =
|
|
194111
|
+
const hcl = fs28.readFileSync(configPath, "utf-8");
|
|
194066
194112
|
try {
|
|
194067
194113
|
config = await parseConfig(hcl);
|
|
194068
194114
|
} catch (err) {
|
|
@@ -194186,7 +194232,7 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
|
|
|
194186
194232
|
|
|
194187
194233
|
// src/commands/reshape.tsx
|
|
194188
194234
|
import { spawn as spawn9 } from "child_process";
|
|
194189
|
-
import * as
|
|
194235
|
+
import * as fs29 from "fs";
|
|
194190
194236
|
import * as path26 from "path";
|
|
194191
194237
|
var VALID_ACTIONS = ["start", "complete", "status", "abort", "check"];
|
|
194192
194238
|
var MIGRATION_SUBCOMMANDS = ["start", "complete", "abort"];
|
|
@@ -194204,8 +194250,8 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
194204
194250
|
let migrationsDir = "migrations";
|
|
194205
194251
|
let targetDb;
|
|
194206
194252
|
try {
|
|
194207
|
-
if (
|
|
194208
|
-
const configContent =
|
|
194253
|
+
if (fs29.existsSync(configPath)) {
|
|
194254
|
+
const configContent = fs29.readFileSync(configPath, "utf-8");
|
|
194209
194255
|
config = await parseConfig(configContent);
|
|
194210
194256
|
if (databaseName) {
|
|
194211
194257
|
const postgresConfig = config.postgres.find((p) => p.name === databaseName);
|
|
@@ -194341,7 +194387,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
194341
194387
|
const reshapeArgs = isMigrationSubcommand ? ["migration", action] : [action];
|
|
194342
194388
|
const fullMigrationsPath = path26.join(process.cwd(), migrationsDir);
|
|
194343
194389
|
if (action === "check" || action === "start") {
|
|
194344
|
-
if (
|
|
194390
|
+
if (fs29.existsSync(fullMigrationsPath)) {
|
|
194345
194391
|
reshapeArgs.push("--dirs", fullMigrationsPath);
|
|
194346
194392
|
} else if (action === "check") {
|
|
194347
194393
|
console.error(`Error: Migrations directory not found: ${fullMigrationsPath}`);
|
|
@@ -194391,7 +194437,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
194391
194437
|
import React8, { useState as useState7, useEffect as useEffect5 } from "react";
|
|
194392
194438
|
import { render as render6, Text as Text8, Box as Box8 } from "ink";
|
|
194393
194439
|
import Spinner6 from "ink-spinner";
|
|
194394
|
-
import * as
|
|
194440
|
+
import * as fs30 from "fs";
|
|
194395
194441
|
import * as path27 from "path";
|
|
194396
194442
|
function CleanUI({ instanceKey }) {
|
|
194397
194443
|
const [state, setState] = useState7({ status: "checking" });
|
|
@@ -194399,13 +194445,13 @@ function CleanUI({ instanceKey }) {
|
|
|
194399
194445
|
async function clean() {
|
|
194400
194446
|
const projectRoot = process.cwd();
|
|
194401
194447
|
const specificDir = path27.join(projectRoot, ".specific");
|
|
194402
|
-
if (!
|
|
194448
|
+
if (!fs30.existsSync(specificDir)) {
|
|
194403
194449
|
setState({ status: "nothing" });
|
|
194404
194450
|
return;
|
|
194405
194451
|
}
|
|
194406
194452
|
if (instanceKey) {
|
|
194407
194453
|
const keyDir = path27.join(specificDir, "keys", instanceKey);
|
|
194408
|
-
if (!
|
|
194454
|
+
if (!fs30.existsSync(keyDir)) {
|
|
194409
194455
|
setState({ status: "nothing" });
|
|
194410
194456
|
return;
|
|
194411
194457
|
}
|
|
@@ -194421,7 +194467,7 @@ function CleanUI({ instanceKey }) {
|
|
|
194421
194467
|
await stateManager.cleanStaleState();
|
|
194422
194468
|
setState({ status: "cleaning" });
|
|
194423
194469
|
try {
|
|
194424
|
-
|
|
194470
|
+
fs30.rmSync(keyDir, { recursive: true, force: true });
|
|
194425
194471
|
setState({ status: "success" });
|
|
194426
194472
|
} catch (err) {
|
|
194427
194473
|
setState({
|
|
@@ -194431,12 +194477,12 @@ function CleanUI({ instanceKey }) {
|
|
|
194431
194477
|
}
|
|
194432
194478
|
} else {
|
|
194433
194479
|
const keysDir = path27.join(specificDir, "keys");
|
|
194434
|
-
if (!
|
|
194480
|
+
if (!fs30.existsSync(keysDir)) {
|
|
194435
194481
|
setState({ status: "nothing" });
|
|
194436
194482
|
return;
|
|
194437
194483
|
}
|
|
194438
|
-
const keys =
|
|
194439
|
-
(f) =>
|
|
194484
|
+
const keys = fs30.readdirSync(keysDir).filter(
|
|
194485
|
+
(f) => fs30.statSync(path27.join(keysDir, f)).isDirectory()
|
|
194440
194486
|
);
|
|
194441
194487
|
for (const key of keys) {
|
|
194442
194488
|
const stateManager2 = new InstanceStateManager(projectRoot, key);
|
|
@@ -194460,7 +194506,7 @@ function CleanUI({ instanceKey }) {
|
|
|
194460
194506
|
}
|
|
194461
194507
|
setState({ status: "cleaning" });
|
|
194462
194508
|
try {
|
|
194463
|
-
|
|
194509
|
+
fs30.rmSync(keysDir, { recursive: true, force: true });
|
|
194464
194510
|
setState({ status: "success" });
|
|
194465
194511
|
} catch (err) {
|
|
194466
194512
|
setState({
|
|
@@ -194625,7 +194671,7 @@ import { render as render9, Text as Text11, Box as Box10, useApp as useApp6 } fr
|
|
|
194625
194671
|
import Spinner7 from "ink-spinner";
|
|
194626
194672
|
|
|
194627
194673
|
// src/lib/update.ts
|
|
194628
|
-
import * as
|
|
194674
|
+
import * as fs31 from "fs";
|
|
194629
194675
|
import * as path28 from "path";
|
|
194630
194676
|
var BINARIES_BASE_URL = "https://binaries.specific.dev/cli";
|
|
194631
194677
|
function compareVersions(a, b) {
|
|
@@ -194640,7 +194686,7 @@ function compareVersions(a, b) {
|
|
|
194640
194686
|
return 0;
|
|
194641
194687
|
}
|
|
194642
194688
|
async function checkForUpdate() {
|
|
194643
|
-
const currentVersion = "0.1.
|
|
194689
|
+
const currentVersion = "0.1.72";
|
|
194644
194690
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
194645
194691
|
if (!response.ok) {
|
|
194646
194692
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -194656,7 +194702,7 @@ function isBinaryWritable() {
|
|
|
194656
194702
|
const binaryPath = getCurrentBinaryPath();
|
|
194657
194703
|
const dir = path28.dirname(binaryPath);
|
|
194658
194704
|
try {
|
|
194659
|
-
|
|
194705
|
+
fs31.accessSync(dir, fs31.constants.W_OK);
|
|
194660
194706
|
return true;
|
|
194661
194707
|
} catch {
|
|
194662
194708
|
return false;
|
|
@@ -194667,21 +194713,21 @@ async function performUpdate(version, onProgress) {
|
|
|
194667
194713
|
const binaryDir = path28.dirname(binaryPath);
|
|
194668
194714
|
const tempPath = path28.join(binaryDir, `.specific-update-${process.pid}`);
|
|
194669
194715
|
try {
|
|
194670
|
-
const { platform:
|
|
194671
|
-
const url = `${BINARIES_BASE_URL}/${version}/specific-${
|
|
194716
|
+
const { platform: platform6, arch: arch3 } = getPlatformInfo();
|
|
194717
|
+
const url = `${BINARIES_BASE_URL}/${version}/specific-${platform6}-${arch3}`;
|
|
194672
194718
|
await downloadFile(url, tempPath, onProgress);
|
|
194673
|
-
const stat4 =
|
|
194719
|
+
const stat4 = fs31.statSync(tempPath);
|
|
194674
194720
|
if (stat4.size === 0) {
|
|
194675
194721
|
throw new Error("Downloaded binary is empty");
|
|
194676
194722
|
}
|
|
194677
|
-
|
|
194723
|
+
fs31.chmodSync(tempPath, 493);
|
|
194678
194724
|
onProgress?.({ phase: "finalizing" });
|
|
194679
|
-
|
|
194680
|
-
|
|
194725
|
+
fs31.unlinkSync(binaryPath);
|
|
194726
|
+
fs31.renameSync(tempPath, binaryPath);
|
|
194681
194727
|
} catch (error) {
|
|
194682
194728
|
try {
|
|
194683
|
-
if (
|
|
194684
|
-
|
|
194729
|
+
if (fs31.existsSync(tempPath)) {
|
|
194730
|
+
fs31.unlinkSync(tempPath);
|
|
194685
194731
|
}
|
|
194686
194732
|
} catch {
|
|
194687
194733
|
}
|
|
@@ -194691,21 +194737,21 @@ async function performUpdate(version, onProgress) {
|
|
|
194691
194737
|
|
|
194692
194738
|
// src/lib/background-update.ts
|
|
194693
194739
|
import { spawn as spawn10 } from "child_process";
|
|
194694
|
-
import * as
|
|
194740
|
+
import * as fs32 from "fs";
|
|
194695
194741
|
import * as path29 from "path";
|
|
194696
|
-
import * as
|
|
194697
|
-
var SPECIFIC_DIR = path29.join(
|
|
194742
|
+
import * as os10 from "os";
|
|
194743
|
+
var SPECIFIC_DIR = path29.join(os10.homedir(), ".specific");
|
|
194698
194744
|
var RATE_LIMIT_FILE = path29.join(SPECIFIC_DIR, "last-update-check");
|
|
194699
194745
|
var LOCK_FILE = path29.join(SPECIFIC_DIR, "update.lock");
|
|
194700
194746
|
var RATE_LIMIT_MS = 60 * 60 * 1e3;
|
|
194701
194747
|
var STALE_LOCK_MS = 10 * 60 * 1e3;
|
|
194702
194748
|
function writeCheckTimestamp() {
|
|
194703
|
-
|
|
194704
|
-
|
|
194749
|
+
fs32.mkdirSync(SPECIFIC_DIR, { recursive: true });
|
|
194750
|
+
fs32.writeFileSync(RATE_LIMIT_FILE, String(Date.now()), "utf-8");
|
|
194705
194751
|
}
|
|
194706
194752
|
function isRateLimited() {
|
|
194707
194753
|
try {
|
|
194708
|
-
const content =
|
|
194754
|
+
const content = fs32.readFileSync(RATE_LIMIT_FILE, "utf-8").trim();
|
|
194709
194755
|
const lastCheck = parseInt(content, 10);
|
|
194710
194756
|
if (isNaN(lastCheck)) return false;
|
|
194711
194757
|
return Date.now() - lastCheck < RATE_LIMIT_MS;
|
|
@@ -194839,7 +194885,7 @@ function updateCommand() {
|
|
|
194839
194885
|
var program = new Command();
|
|
194840
194886
|
var env = "production";
|
|
194841
194887
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
194842
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
194888
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.72").enablePositionalOptions();
|
|
194843
194889
|
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));
|
|
194844
194890
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
194845
194891
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|