@specific.dev/cli 0.1.74 → 0.1.76
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 +357 -322
- package/dist/postinstall.js +1 -1
- package/package.json +1 -1
- /package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → j9zz6vmZhKrtrUzT5h_gg}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → j9zz6vmZhKrtrUzT5h_gg}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → j9zz6vmZhKrtrUzT5h_gg}/_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;
|
|
@@ -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 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();
|
|
@@ -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: 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 fs32 = $global.require("fs");
|
|
758
|
+
"object" == typeof fs32 && null !== fs32 && 0 !== Object.keys(fs32).length && ($global.fs = fs32);
|
|
759
759
|
} catch (e) {
|
|
760
760
|
}
|
|
761
761
|
if (!$global.fs) {
|
|
@@ -183430,13 +183430,11 @@ 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 fs11 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
183438
|
import * as path3 from "path";
|
|
183441
183439
|
|
|
183442
183440
|
// src/lib/dev/local-ca.ts
|
|
@@ -183472,20 +183470,24 @@ function caInstalledInTrustStore() {
|
|
|
183472
183470
|
if (!caFilesExist()) {
|
|
183473
183471
|
return false;
|
|
183474
183472
|
}
|
|
183475
|
-
const
|
|
183473
|
+
const platform5 = os.platform();
|
|
183476
183474
|
const certPath = path.join(getCADir(), "ca.crt");
|
|
183477
183475
|
const diskCert = fs.readFileSync(certPath, "utf-8").replace(/\r\n/g, "\n").trim();
|
|
183478
183476
|
try {
|
|
183479
|
-
if (
|
|
183477
|
+
if (platform5 === "darwin") {
|
|
183480
183478
|
const keychainCert = execSync(
|
|
183481
183479
|
'security find-certificate -c "Specific Local Development CA" -p /Library/Keychains/System.keychain',
|
|
183482
183480
|
{ encoding: "utf-8" }
|
|
183483
183481
|
).replace(/\r\n/g, "\n").trim();
|
|
183484
183482
|
return keychainCert === diskCert;
|
|
183485
|
-
} else if (
|
|
183483
|
+
} else if (platform5 === "linux") {
|
|
183486
183484
|
const trustPaths = [
|
|
183487
183485
|
"/usr/local/share/ca-certificates/specific-local-ca.crt",
|
|
183488
|
-
|
|
183486
|
+
// Debian/Ubuntu
|
|
183487
|
+
"/etc/pki/ca-trust/source/anchors/specific-local-ca.crt",
|
|
183488
|
+
// RHEL/Fedora
|
|
183489
|
+
"/etc/ca-certificates/trust-source/anchors/specific-local-ca.crt"
|
|
183490
|
+
// Arch
|
|
183489
183491
|
];
|
|
183490
183492
|
for (const trustPath of trustPaths) {
|
|
183491
183493
|
if (fs.existsSync(trustPath)) {
|
|
@@ -183590,15 +183592,15 @@ function removeCA() {
|
|
|
183590
183592
|
}
|
|
183591
183593
|
}
|
|
183592
183594
|
function getCAInstallCommands(certPath) {
|
|
183593
|
-
const
|
|
183594
|
-
if (
|
|
183595
|
+
const platform5 = os.platform();
|
|
183596
|
+
if (platform5 === "darwin") {
|
|
183595
183597
|
return [
|
|
183596
183598
|
// Remove any existing cert with the same CN first — add-trusted-cert
|
|
183597
183599
|
// silently does nothing if a cert with the same subject already exists.
|
|
183598
183600
|
'security delete-certificate -c "Specific Local Development CA" /Library/Keychains/System.keychain 2>/dev/null || true',
|
|
183599
183601
|
`security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`
|
|
183600
183602
|
];
|
|
183601
|
-
} else if (
|
|
183603
|
+
} else if (platform5 === "linux") {
|
|
183602
183604
|
if (fs.existsSync("/usr/local/share/ca-certificates")) {
|
|
183603
183605
|
return [
|
|
183604
183606
|
`cp "${certPath}" /usr/local/share/ca-certificates/specific-local-ca.crt`,
|
|
@@ -183609,10 +183611,15 @@ function getCAInstallCommands(certPath) {
|
|
|
183609
183611
|
`cp "${certPath}" /etc/pki/ca-trust/source/anchors/specific-local-ca.crt`,
|
|
183610
183612
|
"update-ca-trust extract"
|
|
183611
183613
|
];
|
|
183614
|
+
} else if (fs.existsSync("/etc/ca-certificates/trust-source/anchors")) {
|
|
183615
|
+
return [
|
|
183616
|
+
`cp "${certPath}" /etc/ca-certificates/trust-source/anchors/specific-local-ca.crt`,
|
|
183617
|
+
"trust extract-compat"
|
|
183618
|
+
];
|
|
183612
183619
|
}
|
|
183613
183620
|
throw new Error("Could not detect Linux certificate trust mechanism");
|
|
183614
183621
|
}
|
|
183615
|
-
throw new Error(`Unsupported platform: ${
|
|
183622
|
+
throw new Error(`Unsupported platform: ${platform5}`);
|
|
183616
183623
|
}
|
|
183617
183624
|
function generateCertificate(domain, keys = []) {
|
|
183618
183625
|
const caDir = getCADir();
|
|
@@ -183658,23 +183665,23 @@ var RESOLVER_FILE_MACOS = "/etc/resolver/spcf.localhost";
|
|
|
183658
183665
|
var OLD_RESOLVER_FILE_MACOS = "/etc/resolver/local.spcf.app";
|
|
183659
183666
|
var RESOLVER_FILE_LINUX = "/etc/systemd/resolved.conf.d/specific-local.conf";
|
|
183660
183667
|
function resolverConfigExists() {
|
|
183661
|
-
const
|
|
183662
|
-
if (
|
|
183668
|
+
const platform5 = os2.platform();
|
|
183669
|
+
if (platform5 === "darwin") {
|
|
183663
183670
|
return fs2.existsSync(RESOLVER_FILE_MACOS);
|
|
183664
|
-
} else if (
|
|
183671
|
+
} else if (platform5 === "linux") {
|
|
183665
183672
|
return fs2.existsSync(RESOLVER_FILE_LINUX);
|
|
183666
183673
|
}
|
|
183667
183674
|
return false;
|
|
183668
183675
|
}
|
|
183669
183676
|
function getResolverInstallCommands(port) {
|
|
183670
|
-
const
|
|
183671
|
-
if (
|
|
183677
|
+
const platform5 = os2.platform();
|
|
183678
|
+
if (platform5 === "darwin") {
|
|
183672
183679
|
return [
|
|
183673
183680
|
"mkdir -p /etc/resolver",
|
|
183674
183681
|
`rm -f ${OLD_RESOLVER_FILE_MACOS}`,
|
|
183675
183682
|
`printf "nameserver 127.0.0.1\\nport ${port}\\n" > ${RESOLVER_FILE_MACOS}`
|
|
183676
183683
|
];
|
|
183677
|
-
} else if (
|
|
183684
|
+
} else if (platform5 === "linux") {
|
|
183678
183685
|
if (fs2.existsSync("/etc/systemd/resolved.conf.d") || fs2.existsSync("/etc/systemd")) {
|
|
183679
183686
|
return [
|
|
183680
183687
|
"mkdir -p /etc/systemd/resolved.conf.d",
|
|
@@ -183793,7 +183800,7 @@ function performSystemSetup() {
|
|
|
183793
183800
|
return;
|
|
183794
183801
|
}
|
|
183795
183802
|
try {
|
|
183796
|
-
|
|
183803
|
+
execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
|
|
183797
183804
|
} catch (err) {
|
|
183798
183805
|
if (needsGenerate) {
|
|
183799
183806
|
removeCA();
|
|
@@ -183801,43 +183808,14 @@ function performSystemSetup() {
|
|
|
183801
183808
|
throw err;
|
|
183802
183809
|
}
|
|
183803
183810
|
}
|
|
183804
|
-
function execPrivileged(commands) {
|
|
183805
|
-
if (commands.length === 0) return;
|
|
183806
|
-
if (os4.platform() === "darwin") {
|
|
183807
|
-
const scriptPath = path3.join(os4.tmpdir(), "specific-setup.sh");
|
|
183808
|
-
const appPath = path3.join(os4.tmpdir(), "Specific.app");
|
|
183809
|
-
try {
|
|
183810
|
-
fs4.writeFileSync(
|
|
183811
|
-
scriptPath,
|
|
183812
|
-
"#!/bin/sh\nset -e\n" + commands.join("\n") + "\n",
|
|
183813
|
-
{ mode: 448 }
|
|
183814
|
-
);
|
|
183815
|
-
execSync2(
|
|
183816
|
-
`osacompile -o '${appPath}' -e 'do shell script "sh ${scriptPath}" with administrator privileges'`
|
|
183817
|
-
);
|
|
183818
|
-
execSync2(`'${appPath}/Contents/MacOS/applet'`, { stdio: "pipe" });
|
|
183819
|
-
} finally {
|
|
183820
|
-
try {
|
|
183821
|
-
fs4.unlinkSync(scriptPath);
|
|
183822
|
-
} catch {
|
|
183823
|
-
}
|
|
183824
|
-
try {
|
|
183825
|
-
fs4.rmSync(appPath, { recursive: true });
|
|
183826
|
-
} catch {
|
|
183827
|
-
}
|
|
183828
|
-
}
|
|
183829
|
-
} else {
|
|
183830
|
-
execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
|
|
183831
|
-
}
|
|
183832
|
-
}
|
|
183833
183811
|
|
|
183834
183812
|
// src/lib/analytics/index.ts
|
|
183835
183813
|
import { PostHog } from "posthog-node";
|
|
183836
|
-
import * as
|
|
183814
|
+
import * as os6 from "os";
|
|
183837
183815
|
import * as crypto from "crypto";
|
|
183838
183816
|
|
|
183839
183817
|
// src/lib/project/config.ts
|
|
183840
|
-
import * as
|
|
183818
|
+
import * as fs4 from "fs";
|
|
183841
183819
|
import * as path4 from "path";
|
|
183842
183820
|
var PROJECT_ID_FILE = ".specific/project_id";
|
|
183843
183821
|
var ProjectNotLinkedError = class extends Error {
|
|
@@ -183854,10 +183832,10 @@ Run: specific deploy`
|
|
|
183854
183832
|
};
|
|
183855
183833
|
function readProjectId(projectDir = process.cwd()) {
|
|
183856
183834
|
const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
|
|
183857
|
-
if (!
|
|
183835
|
+
if (!fs4.existsSync(projectIdPath)) {
|
|
183858
183836
|
throw new ProjectNotLinkedError();
|
|
183859
183837
|
}
|
|
183860
|
-
const projectId =
|
|
183838
|
+
const projectId = fs4.readFileSync(projectIdPath, "utf-8").trim();
|
|
183861
183839
|
if (!projectId) {
|
|
183862
183840
|
throw new Error(`${PROJECT_ID_FILE} is empty`);
|
|
183863
183841
|
}
|
|
@@ -183865,20 +183843,20 @@ function readProjectId(projectDir = process.cwd()) {
|
|
|
183865
183843
|
}
|
|
183866
183844
|
function hasProjectId(projectDir = process.cwd()) {
|
|
183867
183845
|
const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
|
|
183868
|
-
return
|
|
183846
|
+
return fs4.existsSync(projectIdPath);
|
|
183869
183847
|
}
|
|
183870
183848
|
function writeProjectId(projectId, projectDir = process.cwd()) {
|
|
183871
183849
|
const specificDir = path4.join(projectDir, ".specific");
|
|
183872
|
-
if (!
|
|
183873
|
-
|
|
183850
|
+
if (!fs4.existsSync(specificDir)) {
|
|
183851
|
+
fs4.mkdirSync(specificDir, { recursive: true });
|
|
183874
183852
|
}
|
|
183875
|
-
|
|
183853
|
+
fs4.writeFileSync(path4.join(specificDir, "project_id"), projectId + "\n");
|
|
183876
183854
|
}
|
|
183877
183855
|
|
|
183878
183856
|
// src/lib/auth/credentials.ts
|
|
183879
|
-
import * as
|
|
183857
|
+
import * as fs10 from "fs";
|
|
183880
183858
|
import * as path6 from "path";
|
|
183881
|
-
import * as
|
|
183859
|
+
import * as os5 from "os";
|
|
183882
183860
|
|
|
183883
183861
|
// src/lib/auth/errors.ts
|
|
183884
183862
|
var RefreshTokenExpiredError = class extends Error {
|
|
@@ -184362,9 +184340,12 @@ var ApiClient = class {
|
|
|
184362
184340
|
}
|
|
184363
184341
|
return response.json();
|
|
184364
184342
|
}
|
|
184365
|
-
async createProject(name) {
|
|
184343
|
+
async createProject(name, organizationId) {
|
|
184366
184344
|
const url = `${this.baseUrl}/projects`;
|
|
184367
184345
|
const requestBody = { name };
|
|
184346
|
+
if (organizationId) {
|
|
184347
|
+
requestBody.organizationId = organizationId;
|
|
184348
|
+
}
|
|
184368
184349
|
writeLog("api", `POST ${url}`);
|
|
184369
184350
|
writeLog("api", `Request body: ${JSON.stringify(requestBody)}`);
|
|
184370
184351
|
const response = await fetch(url, {
|
|
@@ -184399,6 +184380,31 @@ var ApiClient = class {
|
|
|
184399
184380
|
}
|
|
184400
184381
|
return response.json();
|
|
184401
184382
|
}
|
|
184383
|
+
async listOrganizations() {
|
|
184384
|
+
const url = `${this.baseUrl}/user/organizations`;
|
|
184385
|
+
writeLog("api", `GET ${url}`);
|
|
184386
|
+
const response = await fetch(url, {
|
|
184387
|
+
headers: await this.authHeaders()
|
|
184388
|
+
});
|
|
184389
|
+
writeLog("api", `Response: ${response.status} ${response.statusText}`);
|
|
184390
|
+
if (!response.ok) {
|
|
184391
|
+
let errorBody;
|
|
184392
|
+
try {
|
|
184393
|
+
const error = await response.json();
|
|
184394
|
+
errorBody = JSON.stringify(error);
|
|
184395
|
+
writeLog("api:error", `API error: ${error.error} (${error.code})`);
|
|
184396
|
+
throw new Error(`Failed to list organizations: ${error.error} (${error.code})`);
|
|
184397
|
+
} catch (e) {
|
|
184398
|
+
if (e instanceof Error && e.message.startsWith("Failed to list organizations")) {
|
|
184399
|
+
throw e;
|
|
184400
|
+
}
|
|
184401
|
+
errorBody = await response.text();
|
|
184402
|
+
writeLog("api:error", `Failed to parse error response: ${errorBody}`);
|
|
184403
|
+
throw new Error(`Failed to list organizations: ${response.statusText}`);
|
|
184404
|
+
}
|
|
184405
|
+
}
|
|
184406
|
+
return response.json();
|
|
184407
|
+
}
|
|
184402
184408
|
async getMe(signal) {
|
|
184403
184409
|
const url = `${this.baseUrl}/users/me`;
|
|
184404
184410
|
writeLog("api", `GET ${url}`);
|
|
@@ -184431,18 +184437,18 @@ var ApiClient = class {
|
|
|
184431
184437
|
|
|
184432
184438
|
// src/lib/auth/credentials.ts
|
|
184433
184439
|
function getUserCredentialsDir() {
|
|
184434
|
-
return path6.join(
|
|
184440
|
+
return path6.join(os5.homedir(), ".specific");
|
|
184435
184441
|
}
|
|
184436
184442
|
function getCredentialsPath() {
|
|
184437
184443
|
return path6.join(getUserCredentialsDir(), "credentials.json");
|
|
184438
184444
|
}
|
|
184439
184445
|
function readUserCredentials() {
|
|
184440
184446
|
const credentialsPath = getCredentialsPath();
|
|
184441
|
-
if (!
|
|
184447
|
+
if (!fs10.existsSync(credentialsPath)) {
|
|
184442
184448
|
return null;
|
|
184443
184449
|
}
|
|
184444
184450
|
try {
|
|
184445
|
-
const content =
|
|
184451
|
+
const content = fs10.readFileSync(credentialsPath, "utf-8");
|
|
184446
184452
|
return JSON.parse(content);
|
|
184447
184453
|
} catch {
|
|
184448
184454
|
return null;
|
|
@@ -184450,18 +184456,18 @@ function readUserCredentials() {
|
|
|
184450
184456
|
}
|
|
184451
184457
|
function writeUserCredentials(credentials) {
|
|
184452
184458
|
const dir = getUserCredentialsDir();
|
|
184453
|
-
if (!
|
|
184454
|
-
|
|
184459
|
+
if (!fs10.existsSync(dir)) {
|
|
184460
|
+
fs10.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
184455
184461
|
}
|
|
184456
184462
|
const credentialsPath = getCredentialsPath();
|
|
184457
|
-
|
|
184463
|
+
fs10.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
|
|
184458
184464
|
mode: 384
|
|
184459
184465
|
});
|
|
184460
184466
|
}
|
|
184461
184467
|
function clearUserCredentials() {
|
|
184462
184468
|
const credentialsPath = getCredentialsPath();
|
|
184463
|
-
if (
|
|
184464
|
-
|
|
184469
|
+
if (fs10.existsSync(credentialsPath)) {
|
|
184470
|
+
fs10.unlinkSync(credentialsPath);
|
|
184465
184471
|
}
|
|
184466
184472
|
}
|
|
184467
184473
|
function isLoggedIn() {
|
|
@@ -184540,7 +184546,7 @@ function isEnabled() {
|
|
|
184540
184546
|
}
|
|
184541
184547
|
function getAnonymousId() {
|
|
184542
184548
|
if (anonymousId) return anonymousId;
|
|
184543
|
-
const machineId = `${
|
|
184549
|
+
const machineId = `${os6.hostname()}-${os6.userInfo().username}`;
|
|
184544
184550
|
anonymousId = crypto.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
|
|
184545
184551
|
return anonymousId;
|
|
184546
184552
|
}
|
|
@@ -184587,7 +184593,7 @@ function trackEvent(event, properties) {
|
|
|
184587
184593
|
event,
|
|
184588
184594
|
properties: {
|
|
184589
184595
|
...properties,
|
|
184590
|
-
cli_version: "0.1.
|
|
184596
|
+
cli_version: "0.1.76",
|
|
184591
184597
|
platform: process.platform,
|
|
184592
184598
|
node_version: process.version,
|
|
184593
184599
|
project_id: getProjectId()
|
|
@@ -184624,57 +184630,57 @@ var options = [
|
|
|
184624
184630
|
];
|
|
184625
184631
|
function isGitProject() {
|
|
184626
184632
|
const gitPath = path7.join(process.cwd(), ".git");
|
|
184627
|
-
return
|
|
184633
|
+
return fs11.existsSync(gitPath);
|
|
184628
184634
|
}
|
|
184629
184635
|
function detectExistingAgents() {
|
|
184630
184636
|
const detected = {};
|
|
184631
184637
|
const cursorDir = path7.join(process.cwd(), ".cursor");
|
|
184632
|
-
if (
|
|
184638
|
+
if (fs11.existsSync(cursorDir)) {
|
|
184633
184639
|
detected["cursor"] = true;
|
|
184634
184640
|
}
|
|
184635
184641
|
const claudeDir = path7.join(process.cwd(), ".claude");
|
|
184636
184642
|
const claudeMd = path7.join(process.cwd(), "CLAUDE.md");
|
|
184637
|
-
if (
|
|
184643
|
+
if (fs11.existsSync(claudeDir) || fs11.existsSync(claudeMd)) {
|
|
184638
184644
|
detected["claude"] = true;
|
|
184639
184645
|
}
|
|
184640
184646
|
const agentsMd = path7.join(process.cwd(), "AGENTS.md");
|
|
184641
|
-
if (
|
|
184647
|
+
if (fs11.existsSync(agentsMd)) {
|
|
184642
184648
|
detected["codex"] = true;
|
|
184643
184649
|
}
|
|
184644
184650
|
return detected;
|
|
184645
184651
|
}
|
|
184646
184652
|
function appendOrCreateFile(filePath, content) {
|
|
184647
|
-
if (
|
|
184648
|
-
const existing =
|
|
184653
|
+
if (fs11.existsSync(filePath)) {
|
|
184654
|
+
const existing = fs11.readFileSync(filePath, "utf-8");
|
|
184649
184655
|
if (existing.includes("specific docs") || existing.includes("specific check")) {
|
|
184650
184656
|
return "unchanged";
|
|
184651
184657
|
}
|
|
184652
184658
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
184653
|
-
|
|
184659
|
+
fs11.writeFileSync(filePath, existing + separator + content + "\n");
|
|
184654
184660
|
return "modified";
|
|
184655
184661
|
} else {
|
|
184656
|
-
|
|
184662
|
+
fs11.writeFileSync(filePath, content + "\n");
|
|
184657
184663
|
return "created";
|
|
184658
184664
|
}
|
|
184659
184665
|
}
|
|
184660
184666
|
function addToGitignore() {
|
|
184661
184667
|
const gitignorePath = path7.join(process.cwd(), ".gitignore");
|
|
184662
184668
|
const entries = [".specific", "specific.local"];
|
|
184663
|
-
if (
|
|
184664
|
-
const existing =
|
|
184669
|
+
if (fs11.existsSync(gitignorePath)) {
|
|
184670
|
+
const existing = fs11.readFileSync(gitignorePath, "utf-8");
|
|
184665
184671
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
184666
184672
|
const missingEntries = entries.filter((entry) => !lines.includes(entry));
|
|
184667
184673
|
if (missingEntries.length === 0) {
|
|
184668
184674
|
return "unchanged";
|
|
184669
184675
|
}
|
|
184670
184676
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
184671
|
-
|
|
184677
|
+
fs11.writeFileSync(
|
|
184672
184678
|
gitignorePath,
|
|
184673
184679
|
existing + separator + missingEntries.join("\n") + "\n"
|
|
184674
184680
|
);
|
|
184675
184681
|
return "modified";
|
|
184676
184682
|
} else {
|
|
184677
|
-
|
|
184683
|
+
fs11.writeFileSync(gitignorePath, entries.join("\n") + "\n");
|
|
184678
184684
|
return "created";
|
|
184679
184685
|
}
|
|
184680
184686
|
}
|
|
@@ -184682,8 +184688,8 @@ function configureClaudeCodePermissions() {
|
|
|
184682
184688
|
const claudeDir = path7.join(process.cwd(), ".claude");
|
|
184683
184689
|
const settingsPath = path7.join(claudeDir, "settings.local.json");
|
|
184684
184690
|
const permissions = ["Bash(specific docs:*)", "Bash(specific check:*)"];
|
|
184685
|
-
if (
|
|
184686
|
-
const existing = JSON.parse(
|
|
184691
|
+
if (fs11.existsSync(settingsPath)) {
|
|
184692
|
+
const existing = JSON.parse(fs11.readFileSync(settingsPath, "utf-8"));
|
|
184687
184693
|
const allowList = existing?.permissions?.allow || [];
|
|
184688
184694
|
const missingPermissions = permissions.filter(
|
|
184689
184695
|
(p) => !allowList.includes(p)
|
|
@@ -184698,39 +184704,39 @@ function configureClaudeCodePermissions() {
|
|
|
184698
184704
|
existing.permissions.allow = [];
|
|
184699
184705
|
}
|
|
184700
184706
|
existing.permissions.allow.push(...missingPermissions);
|
|
184701
|
-
|
|
184707
|
+
fs11.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
|
|
184702
184708
|
return "modified";
|
|
184703
184709
|
}
|
|
184704
|
-
if (!
|
|
184705
|
-
|
|
184710
|
+
if (!fs11.existsSync(claudeDir)) {
|
|
184711
|
+
fs11.mkdirSync(claudeDir);
|
|
184706
184712
|
}
|
|
184707
184713
|
const settings = {
|
|
184708
184714
|
permissions: {
|
|
184709
184715
|
allow: permissions
|
|
184710
184716
|
}
|
|
184711
184717
|
};
|
|
184712
|
-
|
|
184718
|
+
fs11.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
184713
184719
|
return "created";
|
|
184714
184720
|
}
|
|
184715
184721
|
function createCursorRule() {
|
|
184716
184722
|
const cursorDir = path7.join(process.cwd(), ".cursor");
|
|
184717
184723
|
const rulesDir = path7.join(cursorDir, "rules");
|
|
184718
184724
|
const mdcPath = path7.join(rulesDir, "specific.mdc");
|
|
184719
|
-
if (
|
|
184720
|
-
const existing =
|
|
184725
|
+
if (fs11.existsSync(mdcPath)) {
|
|
184726
|
+
const existing = fs11.readFileSync(mdcPath, "utf-8");
|
|
184721
184727
|
if (existing.includes("specific docs") || existing.includes("specific check")) {
|
|
184722
184728
|
return "unchanged";
|
|
184723
184729
|
}
|
|
184724
|
-
|
|
184730
|
+
fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
|
|
184725
184731
|
return "modified";
|
|
184726
184732
|
}
|
|
184727
|
-
if (!
|
|
184728
|
-
|
|
184733
|
+
if (!fs11.existsSync(cursorDir)) {
|
|
184734
|
+
fs11.mkdirSync(cursorDir);
|
|
184729
184735
|
}
|
|
184730
|
-
if (!
|
|
184731
|
-
|
|
184736
|
+
if (!fs11.existsSync(rulesDir)) {
|
|
184737
|
+
fs11.mkdirSync(rulesDir);
|
|
184732
184738
|
}
|
|
184733
|
-
|
|
184739
|
+
fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
|
|
184734
184740
|
return "created";
|
|
184735
184741
|
}
|
|
184736
184742
|
function configureAgents(checked) {
|
|
@@ -184973,7 +184979,7 @@ var BETA_REGISTRY = [
|
|
|
184973
184979
|
];
|
|
184974
184980
|
|
|
184975
184981
|
// src/lib/beta/storage.ts
|
|
184976
|
-
import { readFileSync as readFileSync5, writeFileSync as
|
|
184982
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
184977
184983
|
import { join as join7 } from "path";
|
|
184978
184984
|
var BETAS_FILE = ".specific/betas.json";
|
|
184979
184985
|
function loadEnabledBetas(projectDir = process.cwd()) {
|
|
@@ -185006,7 +185012,7 @@ function saveBetas(enabled, projectDir) {
|
|
|
185006
185012
|
mkdirSync6(specificDir, { recursive: true });
|
|
185007
185013
|
}
|
|
185008
185014
|
const data = { enabled };
|
|
185009
|
-
|
|
185015
|
+
writeFileSync5(
|
|
185010
185016
|
join7(projectDir, BETAS_FILE),
|
|
185011
185017
|
JSON.stringify(data, null, 2) + "\n"
|
|
185012
185018
|
);
|
|
@@ -185073,7 +185079,7 @@ function resolveFilesystemDoc(path30) {
|
|
|
185073
185079
|
import React3, { useState as useState2, useEffect as useEffect2 } from "react";
|
|
185074
185080
|
import { render as render3, Text as Text3, Box as Box3 } from "ink";
|
|
185075
185081
|
import Spinner3 from "ink-spinner";
|
|
185076
|
-
import * as
|
|
185082
|
+
import * as fs13 from "fs";
|
|
185077
185083
|
import * as path9 from "path";
|
|
185078
185084
|
import { execFile as execFile7 } from "child_process";
|
|
185079
185085
|
|
|
@@ -185945,32 +185951,32 @@ var ExtractionError = class extends Error {
|
|
|
185945
185951
|
};
|
|
185946
185952
|
|
|
185947
185953
|
// src/lib/bin/manager.ts
|
|
185948
|
-
import * as
|
|
185954
|
+
import * as fs12 from "fs";
|
|
185949
185955
|
import * as path8 from "path";
|
|
185950
|
-
import * as
|
|
185956
|
+
import * as os7 from "os";
|
|
185951
185957
|
import { createReadStream } from "fs";
|
|
185952
185958
|
import { createTarExtractor, extractTo } from "tar-vern";
|
|
185953
185959
|
function getLibraryEnv(binary) {
|
|
185954
185960
|
if (!binary.libraryPath) {
|
|
185955
185961
|
return {};
|
|
185956
185962
|
}
|
|
185957
|
-
const
|
|
185958
|
-
if (
|
|
185963
|
+
const platform5 = os7.platform();
|
|
185964
|
+
if (platform5 === "darwin") {
|
|
185959
185965
|
return { DYLD_LIBRARY_PATH: binary.libraryPath };
|
|
185960
|
-
} else if (
|
|
185966
|
+
} else if (platform5 === "linux") {
|
|
185961
185967
|
return { LD_LIBRARY_PATH: binary.libraryPath };
|
|
185962
185968
|
}
|
|
185963
185969
|
return {};
|
|
185964
185970
|
}
|
|
185965
185971
|
function getBinBaseDir() {
|
|
185966
|
-
return path8.join(
|
|
185972
|
+
return path8.join(os7.homedir(), ".specific", "bin");
|
|
185967
185973
|
}
|
|
185968
185974
|
function getPlatformInfo() {
|
|
185969
|
-
const
|
|
185970
|
-
const arch3 =
|
|
185971
|
-
if (
|
|
185975
|
+
const platform5 = os7.platform();
|
|
185976
|
+
const arch3 = os7.arch();
|
|
185977
|
+
if (platform5 !== "darwin" && platform5 !== "linux") {
|
|
185972
185978
|
throw new Error(
|
|
185973
|
-
`Unsupported platform: ${
|
|
185979
|
+
`Unsupported platform: ${platform5}. Only macOS and Linux are supported.`
|
|
185974
185980
|
);
|
|
185975
185981
|
}
|
|
185976
185982
|
const archStr = arch3;
|
|
@@ -185984,7 +185990,7 @@ function getPlatformInfo() {
|
|
|
185984
185990
|
`Unsupported architecture: ${arch3}. Only x64 and arm64 are supported.`
|
|
185985
185991
|
);
|
|
185986
185992
|
}
|
|
185987
|
-
return { platform:
|
|
185993
|
+
return { platform: platform5, arch: mappedArch };
|
|
185988
185994
|
}
|
|
185989
185995
|
function getBinaryDir(definition, version, platformInfo) {
|
|
185990
185996
|
return path8.join(
|
|
@@ -185998,7 +186004,7 @@ function isBinaryInstalled(definition, version, platformInfo) {
|
|
|
185998
186004
|
const binDir = getBinaryDir(definition, version, platformInfo);
|
|
185999
186005
|
for (const execPath of definition.executables) {
|
|
186000
186006
|
const fullPath = path8.join(binDir, execPath);
|
|
186001
|
-
if (!
|
|
186007
|
+
if (!fs12.existsSync(fullPath)) {
|
|
186002
186008
|
return false;
|
|
186003
186009
|
}
|
|
186004
186010
|
}
|
|
@@ -186027,11 +186033,11 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
186027
186033
|
);
|
|
186028
186034
|
let bytesDownloaded = 0;
|
|
186029
186035
|
const parentDir = path8.dirname(destPath);
|
|
186030
|
-
if (!
|
|
186031
|
-
|
|
186036
|
+
if (!fs12.existsSync(parentDir)) {
|
|
186037
|
+
fs12.mkdirSync(parentDir, { recursive: true });
|
|
186032
186038
|
}
|
|
186033
186039
|
const partPath = destPath + ".part";
|
|
186034
|
-
const fileStream =
|
|
186040
|
+
const fileStream = fs12.createWriteStream(partPath);
|
|
186035
186041
|
try {
|
|
186036
186042
|
const reader = response.body.getReader();
|
|
186037
186043
|
while (true) {
|
|
@@ -186054,12 +186060,12 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
186054
186060
|
else resolve9();
|
|
186055
186061
|
});
|
|
186056
186062
|
});
|
|
186057
|
-
|
|
186063
|
+
fs12.renameSync(partPath, destPath);
|
|
186058
186064
|
} catch (error) {
|
|
186059
186065
|
try {
|
|
186060
186066
|
fileStream.close();
|
|
186061
|
-
if (
|
|
186062
|
-
|
|
186067
|
+
if (fs12.existsSync(partPath)) {
|
|
186068
|
+
fs12.unlinkSync(partPath);
|
|
186063
186069
|
}
|
|
186064
186070
|
} catch {
|
|
186065
186071
|
}
|
|
@@ -186068,8 +186074,8 @@ async function downloadFile(url, destPath, onProgress) {
|
|
|
186068
186074
|
}
|
|
186069
186075
|
async function extractTarball(archivePath, destDir, definition, onProgress) {
|
|
186070
186076
|
onProgress?.({ phase: "extracting" });
|
|
186071
|
-
if (!
|
|
186072
|
-
|
|
186077
|
+
if (!fs12.existsSync(destDir)) {
|
|
186078
|
+
fs12.mkdirSync(destDir, { recursive: true });
|
|
186073
186079
|
}
|
|
186074
186080
|
try {
|
|
186075
186081
|
const fileStream = createReadStream(archivePath);
|
|
@@ -186078,8 +186084,8 @@ async function extractTarball(archivePath, destDir, definition, onProgress) {
|
|
|
186078
186084
|
onProgress?.({ phase: "finalizing" });
|
|
186079
186085
|
for (const execPath of definition.executables) {
|
|
186080
186086
|
const fullPath = path8.join(destDir, execPath);
|
|
186081
|
-
if (
|
|
186082
|
-
|
|
186087
|
+
if (fs12.existsSync(fullPath)) {
|
|
186088
|
+
fs12.chmodSync(fullPath, 493);
|
|
186083
186089
|
}
|
|
186084
186090
|
}
|
|
186085
186091
|
} catch (error) {
|
|
@@ -186103,12 +186109,12 @@ async function ensureBinary(definition, version, onProgress) {
|
|
|
186103
186109
|
`Binary type definitions must have exactly one executable, got ${definition.executables.length}`
|
|
186104
186110
|
);
|
|
186105
186111
|
}
|
|
186106
|
-
if (!
|
|
186107
|
-
|
|
186112
|
+
if (!fs12.existsSync(binDir)) {
|
|
186113
|
+
fs12.mkdirSync(binDir, { recursive: true });
|
|
186108
186114
|
}
|
|
186109
186115
|
const execPath = path8.join(binDir, definition.executables[0]);
|
|
186110
186116
|
await downloadFile(url, execPath, onProgress);
|
|
186111
|
-
|
|
186117
|
+
fs12.chmodSync(execPath, 493);
|
|
186112
186118
|
onProgress?.({ phase: "finalizing" });
|
|
186113
186119
|
} else {
|
|
186114
186120
|
const downloadDir = path8.join(getBinBaseDir(), "downloads");
|
|
@@ -186119,8 +186125,8 @@ async function ensureBinary(definition, version, onProgress) {
|
|
|
186119
186125
|
await extractTarball(archivePath, binDir, definition, onProgress);
|
|
186120
186126
|
} finally {
|
|
186121
186127
|
try {
|
|
186122
|
-
if (
|
|
186123
|
-
|
|
186128
|
+
if (fs12.existsSync(archivePath)) {
|
|
186129
|
+
fs12.unlinkSync(archivePath);
|
|
186124
186130
|
}
|
|
186125
186131
|
} catch {
|
|
186126
186132
|
}
|
|
@@ -186296,20 +186302,20 @@ function CheckUI() {
|
|
|
186296
186302
|
useEffect2(() => {
|
|
186297
186303
|
async function load() {
|
|
186298
186304
|
const configPath = path9.join(process.cwd(), "specific.hcl");
|
|
186299
|
-
if (!
|
|
186305
|
+
if (!fs13.existsSync(configPath)) {
|
|
186300
186306
|
setState({
|
|
186301
186307
|
status: "error",
|
|
186302
186308
|
error: "No specific.hcl found in current directory"
|
|
186303
186309
|
});
|
|
186304
186310
|
return;
|
|
186305
186311
|
}
|
|
186306
|
-
const hcl =
|
|
186312
|
+
const hcl = fs13.readFileSync(configPath, "utf-8");
|
|
186307
186313
|
try {
|
|
186308
186314
|
const config2 = await parseConfig(hcl);
|
|
186309
186315
|
for (const build of config2.builds) {
|
|
186310
186316
|
if (build.dockerfile) {
|
|
186311
186317
|
const dockerfilePath = path9.resolve(process.cwd(), build.dockerfile);
|
|
186312
|
-
if (!
|
|
186318
|
+
if (!fs13.existsSync(dockerfilePath)) {
|
|
186313
186319
|
setState({
|
|
186314
186320
|
status: "error",
|
|
186315
186321
|
error: `Build "${build.name}": Dockerfile not found at "${build.dockerfile}" (resolved to ${dockerfilePath})`
|
|
@@ -186325,7 +186331,7 @@ function CheckUI() {
|
|
|
186325
186331
|
process.cwd(),
|
|
186326
186332
|
pg.reshape.migrations_dir ?? "migrations"
|
|
186327
186333
|
);
|
|
186328
|
-
if (!
|
|
186334
|
+
if (!fs13.existsSync(migrationsDir)) {
|
|
186329
186335
|
reshapeChecks2.push({
|
|
186330
186336
|
databaseName: pg.name,
|
|
186331
186337
|
migrationsDir: pg.reshape.migrations_dir ?? "migrations",
|
|
@@ -186378,7 +186384,7 @@ function checkCommand() {
|
|
|
186378
186384
|
import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
|
|
186379
186385
|
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static, useInput as useInput4 } from "ink";
|
|
186380
186386
|
import Spinner4 from "ink-spinner";
|
|
186381
|
-
import * as
|
|
186387
|
+
import * as fs23 from "fs";
|
|
186382
186388
|
import * as path20 from "path";
|
|
186383
186389
|
|
|
186384
186390
|
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
@@ -188133,7 +188139,7 @@ var PortAllocator = class {
|
|
|
188133
188139
|
};
|
|
188134
188140
|
|
|
188135
188141
|
// src/lib/dev/stable-port-allocator.ts
|
|
188136
|
-
import * as
|
|
188142
|
+
import * as fs14 from "fs";
|
|
188137
188143
|
import * as path10 from "path";
|
|
188138
188144
|
var PORT_RANGE_START2 = 4e4;
|
|
188139
188145
|
var PORT_RANGE_END2 = 49999;
|
|
@@ -188148,11 +188154,11 @@ var StablePortAllocator = class {
|
|
|
188148
188154
|
this.loadPorts();
|
|
188149
188155
|
}
|
|
188150
188156
|
loadPorts() {
|
|
188151
|
-
if (!
|
|
188157
|
+
if (!fs14.existsSync(this.portsFilePath)) {
|
|
188152
188158
|
return;
|
|
188153
188159
|
}
|
|
188154
188160
|
try {
|
|
188155
|
-
const content =
|
|
188161
|
+
const content = fs14.readFileSync(this.portsFilePath, "utf-8");
|
|
188156
188162
|
const data = JSON.parse(content);
|
|
188157
188163
|
if (data.version === 1 && data.ports) {
|
|
188158
188164
|
this.savedPorts = data.ports;
|
|
@@ -188165,14 +188171,14 @@ var StablePortAllocator = class {
|
|
|
188165
188171
|
}
|
|
188166
188172
|
}
|
|
188167
188173
|
savePorts() {
|
|
188168
|
-
if (!
|
|
188169
|
-
|
|
188174
|
+
if (!fs14.existsSync(this.portsDir)) {
|
|
188175
|
+
fs14.mkdirSync(this.portsDir, { recursive: true });
|
|
188170
188176
|
}
|
|
188171
188177
|
const data = {
|
|
188172
188178
|
version: 1,
|
|
188173
188179
|
ports: this.savedPorts
|
|
188174
188180
|
};
|
|
188175
|
-
|
|
188181
|
+
fs14.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
|
|
188176
188182
|
}
|
|
188177
188183
|
allocateRandom() {
|
|
188178
188184
|
const rangeSize = PORT_RANGE_END2 - PORT_RANGE_START2 + 1;
|
|
@@ -188199,7 +188205,7 @@ var StablePortAllocator = class {
|
|
|
188199
188205
|
};
|
|
188200
188206
|
|
|
188201
188207
|
// src/lib/dev/database-manager.ts
|
|
188202
|
-
import * as
|
|
188208
|
+
import * as fs15 from "fs";
|
|
188203
188209
|
import * as path11 from "path";
|
|
188204
188210
|
import * as net from "net";
|
|
188205
188211
|
import { spawn } from "child_process";
|
|
@@ -188211,9 +188217,9 @@ async function startPostgres(pg, port, dataDir, onProgress) {
|
|
|
188211
188217
|
const password = "postgres";
|
|
188212
188218
|
const libraryEnv = getLibraryEnv(binary);
|
|
188213
188219
|
const env2 = { ...process.env, ...libraryEnv };
|
|
188214
|
-
const dataExists =
|
|
188220
|
+
const dataExists = fs15.existsSync(dbDataPath);
|
|
188215
188221
|
if (!dataExists) {
|
|
188216
|
-
|
|
188222
|
+
fs15.mkdirSync(dbDataPath, { recursive: true });
|
|
188217
188223
|
await runCommand(
|
|
188218
188224
|
binary.executables["initdb"],
|
|
188219
188225
|
["-D", dbDataPath, "-U", user, "--auth=trust", "--no-locale", "-E", "UTF8"],
|
|
@@ -188290,8 +188296,8 @@ async function startRedis(redis, port, onProgress) {
|
|
|
188290
188296
|
async function startStorage(storage, port, dataDir) {
|
|
188291
188297
|
const S3rver = (await import("s3rver")).default;
|
|
188292
188298
|
const storageDataPath = path11.join(process.cwd(), dataDir, storage.name);
|
|
188293
|
-
if (!
|
|
188294
|
-
|
|
188299
|
+
if (!fs15.existsSync(storageDataPath)) {
|
|
188300
|
+
fs15.mkdirSync(storageDataPath, { recursive: true });
|
|
188295
188301
|
}
|
|
188296
188302
|
const host = "127.0.0.1";
|
|
188297
188303
|
const accessKey = "S3RVER";
|
|
@@ -188934,7 +188940,7 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
|
|
|
188934
188940
|
}
|
|
188935
188941
|
|
|
188936
188942
|
// src/lib/dev/instance-state.ts
|
|
188937
|
-
import * as
|
|
188943
|
+
import * as fs16 from "fs";
|
|
188938
188944
|
import * as path12 from "path";
|
|
188939
188945
|
var InstanceStateManager = class {
|
|
188940
188946
|
stateDir;
|
|
@@ -188952,8 +188958,8 @@ var InstanceStateManager = class {
|
|
|
188952
188958
|
return this.key;
|
|
188953
188959
|
}
|
|
188954
188960
|
ensureStateDir() {
|
|
188955
|
-
if (!
|
|
188956
|
-
|
|
188961
|
+
if (!fs16.existsSync(this.stateDir)) {
|
|
188962
|
+
fs16.mkdirSync(this.stateDir, { recursive: true });
|
|
188957
188963
|
}
|
|
188958
188964
|
}
|
|
188959
188965
|
isProcessRunning(pid) {
|
|
@@ -188970,15 +188976,15 @@ var InstanceStateManager = class {
|
|
|
188970
188976
|
const startTime = Date.now();
|
|
188971
188977
|
while (Date.now() - startTime < timeoutMs) {
|
|
188972
188978
|
try {
|
|
188973
|
-
const fd =
|
|
188979
|
+
const fd = fs16.openSync(
|
|
188974
188980
|
this.lockPath,
|
|
188975
|
-
|
|
188981
|
+
fs16.constants.O_CREAT | fs16.constants.O_EXCL | fs16.constants.O_WRONLY
|
|
188976
188982
|
);
|
|
188977
|
-
|
|
188978
|
-
|
|
188983
|
+
fs16.writeSync(fd, String(process.pid));
|
|
188984
|
+
fs16.closeSync(fd);
|
|
188979
188985
|
return () => {
|
|
188980
188986
|
try {
|
|
188981
|
-
|
|
188987
|
+
fs16.unlinkSync(this.lockPath);
|
|
188982
188988
|
} catch {
|
|
188983
188989
|
}
|
|
188984
188990
|
};
|
|
@@ -188987,16 +188993,16 @@ var InstanceStateManager = class {
|
|
|
188987
188993
|
if (err.code === "EEXIST") {
|
|
188988
188994
|
try {
|
|
188989
188995
|
const lockPid = parseInt(
|
|
188990
|
-
|
|
188996
|
+
fs16.readFileSync(this.lockPath, "utf-8").trim(),
|
|
188991
188997
|
10
|
|
188992
188998
|
);
|
|
188993
188999
|
if (!this.isProcessRunning(lockPid)) {
|
|
188994
|
-
|
|
189000
|
+
fs16.unlinkSync(this.lockPath);
|
|
188995
189001
|
continue;
|
|
188996
189002
|
}
|
|
188997
189003
|
} catch {
|
|
188998
189004
|
try {
|
|
188999
|
-
|
|
189005
|
+
fs16.unlinkSync(this.lockPath);
|
|
189000
189006
|
} catch {
|
|
189001
189007
|
}
|
|
189002
189008
|
continue;
|
|
@@ -189010,12 +189016,12 @@ var InstanceStateManager = class {
|
|
|
189010
189016
|
throw new Error("Failed to acquire state lock (timeout)");
|
|
189011
189017
|
}
|
|
189012
189018
|
async getExistingInstances() {
|
|
189013
|
-
if (!
|
|
189019
|
+
if (!fs16.existsSync(this.statePath)) {
|
|
189014
189020
|
return null;
|
|
189015
189021
|
}
|
|
189016
189022
|
const releaseLock = await this.acquireLock();
|
|
189017
189023
|
try {
|
|
189018
|
-
const content =
|
|
189024
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
189019
189025
|
const state = JSON.parse(content);
|
|
189020
189026
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
189021
189027
|
return null;
|
|
@@ -189028,21 +189034,21 @@ var InstanceStateManager = class {
|
|
|
189028
189034
|
}
|
|
189029
189035
|
}
|
|
189030
189036
|
async cleanStaleState() {
|
|
189031
|
-
if (!
|
|
189037
|
+
if (!fs16.existsSync(this.statePath)) {
|
|
189032
189038
|
return false;
|
|
189033
189039
|
}
|
|
189034
189040
|
const releaseLock = await this.acquireLock();
|
|
189035
189041
|
try {
|
|
189036
|
-
const content =
|
|
189042
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
189037
189043
|
const state = JSON.parse(content);
|
|
189038
189044
|
if (!this.isProcessRunning(state.owner.pid)) {
|
|
189039
|
-
|
|
189045
|
+
fs16.unlinkSync(this.statePath);
|
|
189040
189046
|
return true;
|
|
189041
189047
|
}
|
|
189042
189048
|
return false;
|
|
189043
189049
|
} catch {
|
|
189044
189050
|
try {
|
|
189045
|
-
|
|
189051
|
+
fs16.unlinkSync(this.statePath);
|
|
189046
189052
|
return true;
|
|
189047
189053
|
} catch {
|
|
189048
189054
|
}
|
|
@@ -189054,8 +189060,8 @@ var InstanceStateManager = class {
|
|
|
189054
189060
|
async claimOwnership(command) {
|
|
189055
189061
|
const releaseLock = await this.acquireLock();
|
|
189056
189062
|
try {
|
|
189057
|
-
if (
|
|
189058
|
-
const content =
|
|
189063
|
+
if (fs16.existsSync(this.statePath)) {
|
|
189064
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
189059
189065
|
const state2 = JSON.parse(content);
|
|
189060
189066
|
if (this.isProcessRunning(state2.owner.pid)) {
|
|
189061
189067
|
throw new Error(`Instances already owned by PID ${state2.owner.pid}`);
|
|
@@ -189124,8 +189130,8 @@ var InstanceStateManager = class {
|
|
|
189124
189130
|
}
|
|
189125
189131
|
const releaseLock = await this.acquireLock();
|
|
189126
189132
|
try {
|
|
189127
|
-
if (
|
|
189128
|
-
|
|
189133
|
+
if (fs16.existsSync(this.statePath)) {
|
|
189134
|
+
fs16.unlinkSync(this.statePath);
|
|
189129
189135
|
}
|
|
189130
189136
|
this.ownsInstances = false;
|
|
189131
189137
|
} finally {
|
|
@@ -189133,21 +189139,21 @@ var InstanceStateManager = class {
|
|
|
189133
189139
|
}
|
|
189134
189140
|
}
|
|
189135
189141
|
readState() {
|
|
189136
|
-
const content =
|
|
189142
|
+
const content = fs16.readFileSync(this.statePath, "utf-8");
|
|
189137
189143
|
return JSON.parse(content);
|
|
189138
189144
|
}
|
|
189139
189145
|
writeStateAtomic(state) {
|
|
189140
189146
|
this.ensureStateDir();
|
|
189141
189147
|
const tmpPath = this.statePath + ".tmp";
|
|
189142
|
-
|
|
189143
|
-
|
|
189148
|
+
fs16.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
|
|
189149
|
+
fs16.renameSync(tmpPath, this.statePath);
|
|
189144
189150
|
}
|
|
189145
189151
|
};
|
|
189146
189152
|
|
|
189147
189153
|
// src/lib/dev/http-proxy.ts
|
|
189148
189154
|
import * as http from "http";
|
|
189149
189155
|
import * as https from "https";
|
|
189150
|
-
import * as
|
|
189156
|
+
import * as fs17 from "fs";
|
|
189151
189157
|
import * as path13 from "path";
|
|
189152
189158
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
189153
189159
|
import httpProxy from "http-proxy";
|
|
@@ -189555,10 +189561,10 @@ function serveFilesystemFile(res, pathname) {
|
|
|
189555
189561
|
res.end("<h1>Forbidden</h1>");
|
|
189556
189562
|
return;
|
|
189557
189563
|
}
|
|
189558
|
-
if (
|
|
189559
|
-
if (
|
|
189564
|
+
if (fs17.existsSync(resolvedPath)) {
|
|
189565
|
+
if (fs17.statSync(resolvedPath).isDirectory()) {
|
|
189560
189566
|
const indexPath2 = path13.join(resolvedPath, "index.html");
|
|
189561
|
-
if (
|
|
189567
|
+
if (fs17.existsSync(indexPath2)) {
|
|
189562
189568
|
return serveFile(res, indexPath2);
|
|
189563
189569
|
}
|
|
189564
189570
|
} else {
|
|
@@ -189566,15 +189572,15 @@ function serveFilesystemFile(res, pathname) {
|
|
|
189566
189572
|
}
|
|
189567
189573
|
}
|
|
189568
189574
|
const htmlPath = resolvedPath + ".html";
|
|
189569
|
-
if (
|
|
189575
|
+
if (fs17.existsSync(htmlPath)) {
|
|
189570
189576
|
return serveFile(res, htmlPath);
|
|
189571
189577
|
}
|
|
189572
189578
|
const indexPath = path13.join(resolvedPath, "index.html");
|
|
189573
|
-
if (
|
|
189579
|
+
if (fs17.existsSync(indexPath)) {
|
|
189574
189580
|
return serveFile(res, indexPath);
|
|
189575
189581
|
}
|
|
189576
189582
|
const notFoundPath = path13.join(adminDir, "404.html");
|
|
189577
|
-
if (
|
|
189583
|
+
if (fs17.existsSync(notFoundPath)) {
|
|
189578
189584
|
return serveFileContent(res, notFoundPath, "text/html", 404);
|
|
189579
189585
|
}
|
|
189580
189586
|
res.writeHead(404, { "Content-Type": "text/html" });
|
|
@@ -189587,7 +189593,7 @@ function serveFile(res, filePath) {
|
|
|
189587
189593
|
}
|
|
189588
189594
|
function serveFileContent(res, filePath, contentType, statusCode = 200) {
|
|
189589
189595
|
try {
|
|
189590
|
-
const content =
|
|
189596
|
+
const content = fs17.readFileSync(filePath);
|
|
189591
189597
|
res.writeHead(statusCode, { "Content-Type": contentType });
|
|
189592
189598
|
res.end(content);
|
|
189593
189599
|
} catch (err) {
|
|
@@ -189962,7 +189968,7 @@ async function startMailServer(mail, smtpPort, apiPort) {
|
|
|
189962
189968
|
|
|
189963
189969
|
// src/lib/dev/drizzle-gateway-manager.ts
|
|
189964
189970
|
import * as net3 from "net";
|
|
189965
|
-
import * as
|
|
189971
|
+
import * as fs18 from "fs";
|
|
189966
189972
|
import * as path15 from "path";
|
|
189967
189973
|
import { spawn as spawn4 } from "child_process";
|
|
189968
189974
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -189996,12 +190002,12 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
|
|
|
189996
190002
|
);
|
|
189997
190003
|
const host = "127.0.0.1";
|
|
189998
190004
|
const drizzleConfigDir = path15.join(configDir, "drizzle-gateway");
|
|
189999
|
-
if (!
|
|
190000
|
-
|
|
190005
|
+
if (!fs18.existsSync(drizzleConfigDir)) {
|
|
190006
|
+
fs18.mkdirSync(drizzleConfigDir, { recursive: true });
|
|
190001
190007
|
}
|
|
190002
190008
|
const storeJson = generateStoreJson(postgresInstances);
|
|
190003
190009
|
const storeJsonPath = path15.join(drizzleConfigDir, "store.json");
|
|
190004
|
-
|
|
190010
|
+
fs18.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
|
|
190005
190011
|
writeLog("drizzle-gateway", `Starting Drizzle Gateway`);
|
|
190006
190012
|
writeLog("drizzle-gateway", `STORE_PATH: ${drizzleConfigDir}`);
|
|
190007
190013
|
writeLog("drizzle-gateway", `PORT: ${port}`);
|
|
@@ -190103,16 +190109,16 @@ function detectSyncDatabases(config) {
|
|
|
190103
190109
|
}
|
|
190104
190110
|
|
|
190105
190111
|
// src/lib/dev/reshape-watcher.ts
|
|
190106
|
-
import * as
|
|
190112
|
+
import * as fs19 from "fs";
|
|
190107
190113
|
import * as path16 from "path";
|
|
190108
190114
|
import { spawnSync } from "child_process";
|
|
190109
190115
|
function getMigrationFiles(dir, log) {
|
|
190110
190116
|
log(`Scanning migrations directory: ${dir}`);
|
|
190111
|
-
if (!
|
|
190117
|
+
if (!fs19.existsSync(dir)) {
|
|
190112
190118
|
log(`Migrations directory does not exist: ${dir}`);
|
|
190113
190119
|
return [];
|
|
190114
190120
|
}
|
|
190115
|
-
const files =
|
|
190121
|
+
const files = fs19.readdirSync(dir);
|
|
190116
190122
|
log(`Found ${files.length} files in directory`);
|
|
190117
190123
|
const tomlFiles = files.filter((f) => f.endsWith(".toml")).sort((a, b) => a.localeCompare(b));
|
|
190118
190124
|
log(`Found ${tomlFiles.length} .toml migration files: ${tomlFiles.join(", ") || "(none)"}`);
|
|
@@ -190162,7 +190168,7 @@ function runReshape(args, databaseUrl, migrationsDir, reshapeBinaryPath, log) {
|
|
|
190162
190168
|
}
|
|
190163
190169
|
function makeReadOnly(filePath, log) {
|
|
190164
190170
|
try {
|
|
190165
|
-
|
|
190171
|
+
fs19.chmodSync(filePath, 292);
|
|
190166
190172
|
log(`Set file permissions to read-only (444): ${filePath}`);
|
|
190167
190173
|
} catch (err) {
|
|
190168
190174
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -190248,9 +190254,9 @@ function createReshapeWatcher(options2) {
|
|
|
190248
190254
|
};
|
|
190249
190255
|
const startWatching = () => {
|
|
190250
190256
|
log(`Starting file watcher for migrations directory...`);
|
|
190251
|
-
if (!
|
|
190257
|
+
if (!fs19.existsSync(migrationsDir)) {
|
|
190252
190258
|
log(`Migrations directory does not exist, creating: ${migrationsDir}`);
|
|
190253
|
-
|
|
190259
|
+
fs19.mkdirSync(migrationsDir, { recursive: true });
|
|
190254
190260
|
}
|
|
190255
190261
|
log(`Watching directory: ${migrationsDir}`);
|
|
190256
190262
|
watcher = chokidar_default.watch(migrationsDir, {
|
|
@@ -190385,7 +190391,7 @@ function createReshapeWatcher(options2) {
|
|
|
190385
190391
|
}
|
|
190386
190392
|
|
|
190387
190393
|
// src/lib/dev/temporal-manager.ts
|
|
190388
|
-
import * as
|
|
190394
|
+
import * as fs20 from "fs";
|
|
190389
190395
|
import * as path17 from "path";
|
|
190390
190396
|
import * as net4 from "net";
|
|
190391
190397
|
import { spawn as spawn5 } from "child_process";
|
|
@@ -190393,8 +190399,8 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
|
|
|
190393
190399
|
const binary = await ensureBinary(temporalBinary, void 0, onProgress);
|
|
190394
190400
|
const dbPath = path17.join(process.cwd(), dataDir, "temporal.db");
|
|
190395
190401
|
const dbDir = path17.dirname(dbPath);
|
|
190396
|
-
if (!
|
|
190397
|
-
|
|
190402
|
+
if (!fs20.existsSync(dbDir)) {
|
|
190403
|
+
fs20.mkdirSync(dbDir, { recursive: true });
|
|
190398
190404
|
}
|
|
190399
190405
|
const host = "127.0.0.1";
|
|
190400
190406
|
const namespaceArgs = temporals.flatMap((t) => ["--namespace", t.name]);
|
|
@@ -190723,7 +190729,7 @@ function watchConfigFile(configPath, debounceMs, onChange) {
|
|
|
190723
190729
|
}
|
|
190724
190730
|
|
|
190725
190731
|
// src/lib/dev/subdomain-generator.ts
|
|
190726
|
-
import * as
|
|
190732
|
+
import * as fs21 from "fs";
|
|
190727
190733
|
import * as path18 from "path";
|
|
190728
190734
|
import { generateSlug } from "random-word-slugs";
|
|
190729
190735
|
var StableSubdomainAllocator = class {
|
|
@@ -190736,11 +190742,11 @@ var StableSubdomainAllocator = class {
|
|
|
190736
190742
|
this.loadTunnels();
|
|
190737
190743
|
}
|
|
190738
190744
|
loadTunnels() {
|
|
190739
|
-
if (!
|
|
190745
|
+
if (!fs21.existsSync(this.tunnelsFilePath)) {
|
|
190740
190746
|
return;
|
|
190741
190747
|
}
|
|
190742
190748
|
try {
|
|
190743
|
-
const content =
|
|
190749
|
+
const content = fs21.readFileSync(this.tunnelsFilePath, "utf-8");
|
|
190744
190750
|
const data = JSON.parse(content);
|
|
190745
190751
|
if (data.version === 1 && data.baseSlug) {
|
|
190746
190752
|
this.baseSlug = data.baseSlug;
|
|
@@ -190750,14 +190756,14 @@ var StableSubdomainAllocator = class {
|
|
|
190750
190756
|
}
|
|
190751
190757
|
}
|
|
190752
190758
|
saveTunnels() {
|
|
190753
|
-
if (!
|
|
190754
|
-
|
|
190759
|
+
if (!fs21.existsSync(this.tunnelsDir)) {
|
|
190760
|
+
fs21.mkdirSync(this.tunnelsDir, { recursive: true });
|
|
190755
190761
|
}
|
|
190756
190762
|
const data = {
|
|
190757
190763
|
version: 1,
|
|
190758
190764
|
baseSlug: this.baseSlug
|
|
190759
190765
|
};
|
|
190760
|
-
|
|
190766
|
+
fs21.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
|
|
190761
190767
|
}
|
|
190762
190768
|
generateBaseSlug() {
|
|
190763
190769
|
return generateSlug(2, {
|
|
@@ -190913,9 +190919,9 @@ async function startTunnel(serviceName, endpointName, port, subdomain, callbacks
|
|
|
190913
190919
|
}
|
|
190914
190920
|
|
|
190915
190921
|
// src/lib/dev/proxy-registry.ts
|
|
190916
|
-
import * as
|
|
190922
|
+
import * as fs22 from "fs";
|
|
190917
190923
|
import * as path19 from "path";
|
|
190918
|
-
import * as
|
|
190924
|
+
import * as os8 from "os";
|
|
190919
190925
|
import * as net6 from "net";
|
|
190920
190926
|
var ProxyRegistryManager = class {
|
|
190921
190927
|
proxyDir;
|
|
@@ -190925,14 +190931,14 @@ var ProxyRegistryManager = class {
|
|
|
190925
190931
|
isOwner = false;
|
|
190926
190932
|
registryWatcher = null;
|
|
190927
190933
|
constructor() {
|
|
190928
|
-
this.proxyDir = path19.join(
|
|
190934
|
+
this.proxyDir = path19.join(os8.homedir(), ".specific", "proxy");
|
|
190929
190935
|
this.ownerPath = path19.join(this.proxyDir, "owner.json");
|
|
190930
190936
|
this.registryPath = path19.join(this.proxyDir, "registry.json");
|
|
190931
190937
|
this.lockPath = path19.join(this.proxyDir, "registry.lock");
|
|
190932
190938
|
}
|
|
190933
190939
|
ensureProxyDir() {
|
|
190934
|
-
if (!
|
|
190935
|
-
|
|
190940
|
+
if (!fs22.existsSync(this.proxyDir)) {
|
|
190941
|
+
fs22.mkdirSync(this.proxyDir, { recursive: true });
|
|
190936
190942
|
}
|
|
190937
190943
|
}
|
|
190938
190944
|
isProcessRunning(pid) {
|
|
@@ -190989,15 +190995,15 @@ var ProxyRegistryManager = class {
|
|
|
190989
190995
|
const startTime = Date.now();
|
|
190990
190996
|
while (Date.now() - startTime < timeoutMs) {
|
|
190991
190997
|
try {
|
|
190992
|
-
const fd =
|
|
190998
|
+
const fd = fs22.openSync(
|
|
190993
190999
|
this.lockPath,
|
|
190994
|
-
|
|
191000
|
+
fs22.constants.O_CREAT | fs22.constants.O_EXCL | fs22.constants.O_WRONLY
|
|
190995
191001
|
);
|
|
190996
|
-
|
|
190997
|
-
|
|
191002
|
+
fs22.writeSync(fd, String(process.pid));
|
|
191003
|
+
fs22.closeSync(fd);
|
|
190998
191004
|
return () => {
|
|
190999
191005
|
try {
|
|
191000
|
-
|
|
191006
|
+
fs22.unlinkSync(this.lockPath);
|
|
191001
191007
|
} catch {
|
|
191002
191008
|
}
|
|
191003
191009
|
};
|
|
@@ -191006,16 +191012,16 @@ var ProxyRegistryManager = class {
|
|
|
191006
191012
|
if (err.code === "EEXIST") {
|
|
191007
191013
|
try {
|
|
191008
191014
|
const lockPid = parseInt(
|
|
191009
|
-
|
|
191015
|
+
fs22.readFileSync(this.lockPath, "utf-8").trim(),
|
|
191010
191016
|
10
|
|
191011
191017
|
);
|
|
191012
191018
|
if (!this.isProcessRunning(lockPid)) {
|
|
191013
|
-
|
|
191019
|
+
fs22.unlinkSync(this.lockPath);
|
|
191014
191020
|
continue;
|
|
191015
191021
|
}
|
|
191016
191022
|
} catch {
|
|
191017
191023
|
try {
|
|
191018
|
-
|
|
191024
|
+
fs22.unlinkSync(this.lockPath);
|
|
191019
191025
|
} catch {
|
|
191020
191026
|
}
|
|
191021
191027
|
continue;
|
|
@@ -191035,8 +191041,8 @@ var ProxyRegistryManager = class {
|
|
|
191035
191041
|
async claimProxyOwnership(key) {
|
|
191036
191042
|
const releaseLock = await this.acquireLock();
|
|
191037
191043
|
try {
|
|
191038
|
-
if (
|
|
191039
|
-
const content =
|
|
191044
|
+
if (fs22.existsSync(this.ownerPath)) {
|
|
191045
|
+
const content = fs22.readFileSync(this.ownerPath, "utf-8");
|
|
191040
191046
|
const ownerFile2 = JSON.parse(content);
|
|
191041
191047
|
if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
|
|
191042
191048
|
return false;
|
|
@@ -191066,11 +191072,11 @@ var ProxyRegistryManager = class {
|
|
|
191066
191072
|
}
|
|
191067
191073
|
const releaseLock = await this.acquireLock();
|
|
191068
191074
|
try {
|
|
191069
|
-
if (
|
|
191070
|
-
const content =
|
|
191075
|
+
if (fs22.existsSync(this.ownerPath)) {
|
|
191076
|
+
const content = fs22.readFileSync(this.ownerPath, "utf-8");
|
|
191071
191077
|
const ownerFile = JSON.parse(content);
|
|
191072
191078
|
if (ownerFile.owner.pid === process.pid) {
|
|
191073
|
-
|
|
191079
|
+
fs22.unlinkSync(this.ownerPath);
|
|
191074
191080
|
}
|
|
191075
191081
|
}
|
|
191076
191082
|
this.isOwner = false;
|
|
@@ -191082,12 +191088,12 @@ var ProxyRegistryManager = class {
|
|
|
191082
191088
|
* Get the current proxy owner.
|
|
191083
191089
|
*/
|
|
191084
191090
|
async getProxyOwner() {
|
|
191085
|
-
if (!
|
|
191091
|
+
if (!fs22.existsSync(this.ownerPath)) {
|
|
191086
191092
|
return null;
|
|
191087
191093
|
}
|
|
191088
191094
|
const releaseLock = await this.acquireLock();
|
|
191089
191095
|
try {
|
|
191090
|
-
const content =
|
|
191096
|
+
const content = fs22.readFileSync(this.ownerPath, "utf-8");
|
|
191091
191097
|
const ownerFile = JSON.parse(content);
|
|
191092
191098
|
if (!await this.isProxyOwnerHealthy(ownerFile.owner.pid)) {
|
|
191093
191099
|
return null;
|
|
@@ -191184,7 +191190,7 @@ var ProxyRegistryManager = class {
|
|
|
191184
191190
|
*/
|
|
191185
191191
|
watchRegistry(onChange) {
|
|
191186
191192
|
this.ensureProxyDir();
|
|
191187
|
-
if (!
|
|
191193
|
+
if (!fs22.existsSync(this.registryPath)) {
|
|
191188
191194
|
const emptyRegistry = {
|
|
191189
191195
|
version: 1,
|
|
191190
191196
|
keys: {},
|
|
@@ -191227,13 +191233,13 @@ var ProxyRegistryManager = class {
|
|
|
191227
191233
|
async attemptElection(key) {
|
|
191228
191234
|
const releaseLock = await this.acquireLock();
|
|
191229
191235
|
try {
|
|
191230
|
-
if (
|
|
191231
|
-
const content =
|
|
191236
|
+
if (fs22.existsSync(this.ownerPath)) {
|
|
191237
|
+
const content = fs22.readFileSync(this.ownerPath, "utf-8");
|
|
191232
191238
|
const ownerFile2 = JSON.parse(content);
|
|
191233
191239
|
if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
|
|
191234
191240
|
return false;
|
|
191235
191241
|
}
|
|
191236
|
-
|
|
191242
|
+
fs22.unlinkSync(this.ownerPath);
|
|
191237
191243
|
}
|
|
191238
191244
|
const ownerFile = {
|
|
191239
191245
|
version: 1,
|
|
@@ -191251,7 +191257,7 @@ var ProxyRegistryManager = class {
|
|
|
191251
191257
|
}
|
|
191252
191258
|
}
|
|
191253
191259
|
readRegistry() {
|
|
191254
|
-
if (!
|
|
191260
|
+
if (!fs22.existsSync(this.registryPath)) {
|
|
191255
191261
|
return {
|
|
191256
191262
|
version: 1,
|
|
191257
191263
|
keys: {},
|
|
@@ -191259,7 +191265,7 @@ var ProxyRegistryManager = class {
|
|
|
191259
191265
|
};
|
|
191260
191266
|
}
|
|
191261
191267
|
try {
|
|
191262
|
-
const content =
|
|
191268
|
+
const content = fs22.readFileSync(this.registryPath, "utf-8");
|
|
191263
191269
|
return JSON.parse(content);
|
|
191264
191270
|
} catch {
|
|
191265
191271
|
return {
|
|
@@ -191272,8 +191278,8 @@ var ProxyRegistryManager = class {
|
|
|
191272
191278
|
writeFileAtomic(filePath, data) {
|
|
191273
191279
|
this.ensureProxyDir();
|
|
191274
191280
|
const tmpPath = filePath + ".tmp";
|
|
191275
|
-
|
|
191276
|
-
|
|
191281
|
+
fs22.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
191282
|
+
fs22.renameSync(tmpPath, filePath);
|
|
191277
191283
|
}
|
|
191278
191284
|
};
|
|
191279
191285
|
|
|
@@ -191596,7 +191602,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191596
191602
|
const configPath = path20.join(process.cwd(), "specific.hcl");
|
|
191597
191603
|
const watcher = watchConfigFile(configPath, 1e3, () => {
|
|
191598
191604
|
try {
|
|
191599
|
-
const hcl =
|
|
191605
|
+
const hcl = fs23.readFileSync(configPath, "utf-8");
|
|
191600
191606
|
parseConfig(hcl).then(() => {
|
|
191601
191607
|
triggerReload();
|
|
191602
191608
|
}).catch((err) => {
|
|
@@ -191722,7 +191728,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191722
191728
|
return;
|
|
191723
191729
|
}
|
|
191724
191730
|
const configPath = path20.join(process.cwd(), "specific.hcl");
|
|
191725
|
-
if (!
|
|
191731
|
+
if (!fs23.existsSync(configPath)) {
|
|
191726
191732
|
writeLog("system", "Waiting for specific.hcl to appear");
|
|
191727
191733
|
setState((s) => ({
|
|
191728
191734
|
...s,
|
|
@@ -191740,7 +191746,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
191740
191746
|
return;
|
|
191741
191747
|
}
|
|
191742
191748
|
let config2;
|
|
191743
|
-
const hcl =
|
|
191749
|
+
const hcl = fs23.readFileSync(configPath, "utf-8");
|
|
191744
191750
|
try {
|
|
191745
191751
|
config2 = await parseConfig(hcl);
|
|
191746
191752
|
} catch (err) {
|
|
@@ -192067,7 +192073,7 @@ Add them to the config block in specific.local`);
|
|
|
192067
192073
|
if (service.volumes) {
|
|
192068
192074
|
for (const vol of service.volumes) {
|
|
192069
192075
|
const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
|
|
192070
|
-
|
|
192076
|
+
fs23.mkdirSync(volumeDir, { recursive: true });
|
|
192071
192077
|
volumePaths.set(vol.name, volumeDir);
|
|
192072
192078
|
}
|
|
192073
192079
|
}
|
|
@@ -192123,7 +192129,7 @@ Add them to the config block in specific.local`);
|
|
|
192123
192129
|
if (service.volumes) {
|
|
192124
192130
|
for (const vol of service.volumes) {
|
|
192125
192131
|
const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
|
|
192126
|
-
|
|
192132
|
+
fs23.mkdirSync(volumeDir, { recursive: true });
|
|
192127
192133
|
volumePaths.set(vol.name, volumeDir);
|
|
192128
192134
|
}
|
|
192129
192135
|
}
|
|
@@ -192694,12 +192700,12 @@ init_open();
|
|
|
192694
192700
|
import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
|
|
192695
192701
|
import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
192696
192702
|
import Spinner5 from "ink-spinner";
|
|
192697
|
-
import * as
|
|
192703
|
+
import * as fs25 from "fs";
|
|
192698
192704
|
import * as path23 from "path";
|
|
192699
192705
|
|
|
192700
192706
|
// src/lib/tarball/create.ts
|
|
192701
192707
|
import { execSync as execSync4 } from "child_process";
|
|
192702
|
-
import * as
|
|
192708
|
+
import * as fs24 from "fs";
|
|
192703
192709
|
import * as path22 from "path";
|
|
192704
192710
|
import { createTarPacker, createEntryItemGenerator } from "tar-vern";
|
|
192705
192711
|
function isInsideGitRepository(dir) {
|
|
@@ -192757,7 +192763,7 @@ var EXCLUDED_DIRS = [
|
|
|
192757
192763
|
];
|
|
192758
192764
|
async function collectPaths(baseDir, currentDir, exclude) {
|
|
192759
192765
|
const results = [];
|
|
192760
|
-
const entries = await
|
|
192766
|
+
const entries = await fs24.promises.readdir(currentDir, { withFileTypes: true });
|
|
192761
192767
|
for (const entry of entries) {
|
|
192762
192768
|
const fullPath = path22.join(currentDir, entry.name);
|
|
192763
192769
|
const relativePath = path22.relative(baseDir, fullPath);
|
|
@@ -192776,7 +192782,7 @@ async function collectPaths(baseDir, currentDir, exclude) {
|
|
|
192776
192782
|
async function createTarArchive(projectDir) {
|
|
192777
192783
|
writeLog("tarball", "Creating tarball using tar-vern (non-git project)");
|
|
192778
192784
|
const configPath = path22.join(projectDir, "specific.hcl");
|
|
192779
|
-
if (!
|
|
192785
|
+
if (!fs24.existsSync(configPath)) {
|
|
192780
192786
|
throw new Error("specific.hcl not found in project directory");
|
|
192781
192787
|
}
|
|
192782
192788
|
const relativePaths = await collectPaths(projectDir, projectDir, EXCLUDED_DIRS);
|
|
@@ -192866,22 +192872,35 @@ function PhaseIndicator({
|
|
|
192866
192872
|
}
|
|
192867
192873
|
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " ", "\u25CB"), " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, label));
|
|
192868
192874
|
}
|
|
192875
|
+
function buildSelectorItems(projects, organizations) {
|
|
192876
|
+
const items = [];
|
|
192877
|
+
for (const org of organizations) {
|
|
192878
|
+
items.push({ type: "header", orgName: org.name });
|
|
192879
|
+
items.push({ type: "new", orgId: org.id });
|
|
192880
|
+
const orgProjects = projects.filter((p) => p.organizationId === org.id);
|
|
192881
|
+
for (const project of orgProjects) {
|
|
192882
|
+
items.push({ type: "project", project });
|
|
192883
|
+
}
|
|
192884
|
+
}
|
|
192885
|
+
return items;
|
|
192886
|
+
}
|
|
192869
192887
|
function ProjectSelector({
|
|
192870
192888
|
projects,
|
|
192889
|
+
organizations,
|
|
192871
192890
|
selectedIndex,
|
|
192872
192891
|
onSelect,
|
|
192873
192892
|
onUp,
|
|
192874
192893
|
onDown
|
|
192875
192894
|
}) {
|
|
192895
|
+
const items = buildSelectorItems(projects, organizations);
|
|
192896
|
+
const selectableIndices = items.map((item, index) => item.type !== "header" ? index : -1).filter((i) => i >= 0);
|
|
192876
192897
|
useInput5((input, key) => {
|
|
192877
192898
|
if (key.return) {
|
|
192878
|
-
|
|
192879
|
-
|
|
192880
|
-
|
|
192881
|
-
|
|
192882
|
-
|
|
192883
|
-
onSelect(project);
|
|
192884
|
-
}
|
|
192899
|
+
const item = items[selectedIndex];
|
|
192900
|
+
if (item?.type === "new") {
|
|
192901
|
+
onSelect({ type: "new", orgId: item.orgId });
|
|
192902
|
+
} else if (item?.type === "project") {
|
|
192903
|
+
onSelect(item.project);
|
|
192885
192904
|
}
|
|
192886
192905
|
} else if (key.upArrow) {
|
|
192887
192906
|
onUp();
|
|
@@ -192889,11 +192908,16 @@ function ProjectSelector({
|
|
|
192889
192908
|
onDown();
|
|
192890
192909
|
}
|
|
192891
192910
|
});
|
|
192892
|
-
|
|
192893
|
-
|
|
192894
|
-
|
|
192895
|
-
|
|
192896
|
-
|
|
192911
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Select a project to deploy:"), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, items.map((item, index) => {
|
|
192912
|
+
if (item.type === "header") {
|
|
192913
|
+
return /* @__PURE__ */ React7.createElement(Text7, { key: `header-${item.orgName}` }, index > 0 ? "\n" : "", /* @__PURE__ */ React7.createElement(Text7, { bold: true }, item.orgName));
|
|
192914
|
+
}
|
|
192915
|
+
const isSelected = index === selectedIndex;
|
|
192916
|
+
if (item.type === "new") {
|
|
192917
|
+
return /* @__PURE__ */ React7.createElement(Text7, { key: `new-${item.orgId}` }, isSelected ? /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, " ", "> ") : /* @__PURE__ */ React7.createElement(Text7, null, " "), /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Create new project"));
|
|
192918
|
+
}
|
|
192919
|
+
return /* @__PURE__ */ React7.createElement(Text7, { key: item.project.id }, isSelected ? /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, " ", "> ") : /* @__PURE__ */ React7.createElement(Text7, null, " "), /* @__PURE__ */ React7.createElement(Text7, null, item.project.name, " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "(", item.project.id, ")")));
|
|
192920
|
+
})), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Use arrow keys to navigate, Enter to select"));
|
|
192897
192921
|
}
|
|
192898
192922
|
function NameInput({ onSubmit, onCancel }) {
|
|
192899
192923
|
const [value, setValue] = useState6("");
|
|
@@ -193040,12 +193064,18 @@ function DeployUI({ environment, config }) {
|
|
|
193040
193064
|
async function loadProjects() {
|
|
193041
193065
|
try {
|
|
193042
193066
|
const client2 = new ApiClient();
|
|
193043
|
-
const { projects: projects2 } = await
|
|
193067
|
+
const [{ projects: projects2 }, { organizations }] = await Promise.all([
|
|
193068
|
+
client2.listProjects(),
|
|
193069
|
+
client2.listOrganizations()
|
|
193070
|
+
]);
|
|
193044
193071
|
if (cancelled) return;
|
|
193072
|
+
const items = buildSelectorItems(projects2, organizations);
|
|
193073
|
+
const firstSelectable = items.findIndex((item) => item.type !== "header");
|
|
193045
193074
|
setState({
|
|
193046
193075
|
phase: "selecting-project",
|
|
193047
193076
|
projects: projects2,
|
|
193048
|
-
|
|
193077
|
+
organizations,
|
|
193078
|
+
selectedIndex: firstSelectable >= 0 ? firstSelectable : 0
|
|
193049
193079
|
});
|
|
193050
193080
|
} catch (err) {
|
|
193051
193081
|
if (cancelled) return;
|
|
@@ -193062,13 +193092,14 @@ function DeployUI({ environment, config }) {
|
|
|
193062
193092
|
}, [state.phase]);
|
|
193063
193093
|
const handleProjectSelect = useCallback(
|
|
193064
193094
|
(project) => {
|
|
193065
|
-
if (project === "new") {
|
|
193066
|
-
setState((s) => ({ ...s, phase: "entering-name" }));
|
|
193095
|
+
if ("type" in project && project.type === "new") {
|
|
193096
|
+
setState((s) => ({ ...s, phase: "entering-name", selectedOrganizationId: project.orgId }));
|
|
193067
193097
|
} else {
|
|
193068
|
-
|
|
193098
|
+
const proj = project;
|
|
193099
|
+
writeProjectId(proj.id);
|
|
193069
193100
|
setState({
|
|
193070
193101
|
phase: "creating-tarball",
|
|
193071
|
-
projectId:
|
|
193102
|
+
projectId: proj.id
|
|
193072
193103
|
});
|
|
193073
193104
|
}
|
|
193074
193105
|
},
|
|
@@ -193086,7 +193117,7 @@ function DeployUI({ environment, config }) {
|
|
|
193086
193117
|
async function createProject() {
|
|
193087
193118
|
try {
|
|
193088
193119
|
const client2 = new ApiClient();
|
|
193089
|
-
const project = await client2.createProject(state.newProjectName);
|
|
193120
|
+
const project = await client2.createProject(state.newProjectName, state.selectedOrganizationId);
|
|
193090
193121
|
if (cancelled) return;
|
|
193091
193122
|
writeProjectId(project.id);
|
|
193092
193123
|
setState({
|
|
@@ -193562,24 +193593,28 @@ function DeployUI({ environment, config }) {
|
|
|
193562
193593
|
if (phase === "loading-projects") {
|
|
193563
193594
|
return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Loading projects..."));
|
|
193564
193595
|
}
|
|
193565
|
-
if (phase === "selecting-project" && projects && selectedIndex !== void 0) {
|
|
193596
|
+
if (phase === "selecting-project" && projects && state.organizations && selectedIndex !== void 0) {
|
|
193597
|
+
const selectorItems = buildSelectorItems(projects, state.organizations);
|
|
193598
|
+
const selectableIndices = selectorItems.map((item, index) => item.type !== "header" ? index : -1).filter((i) => i >= 0);
|
|
193566
193599
|
return /* @__PURE__ */ React7.createElement(
|
|
193567
193600
|
ProjectSelector,
|
|
193568
193601
|
{
|
|
193569
193602
|
projects,
|
|
193603
|
+
organizations: state.organizations,
|
|
193570
193604
|
selectedIndex,
|
|
193571
193605
|
onSelect: handleProjectSelect,
|
|
193572
|
-
onUp: () => setState((s) =>
|
|
193573
|
-
|
|
193574
|
-
|
|
193575
|
-
|
|
193576
|
-
|
|
193577
|
-
|
|
193578
|
-
|
|
193579
|
-
|
|
193580
|
-
|
|
193581
|
-
)
|
|
193582
|
-
|
|
193606
|
+
onUp: () => setState((s) => {
|
|
193607
|
+
const idx = s.selectedIndex ?? 0;
|
|
193608
|
+
const currentPos = selectableIndices.indexOf(idx);
|
|
193609
|
+
const prevPos = Math.max(0, currentPos - 1);
|
|
193610
|
+
return { ...s, selectedIndex: selectableIndices[prevPos] ?? idx };
|
|
193611
|
+
}),
|
|
193612
|
+
onDown: () => setState((s) => {
|
|
193613
|
+
const idx = s.selectedIndex ?? 0;
|
|
193614
|
+
const currentPos = selectableIndices.indexOf(idx);
|
|
193615
|
+
const nextPos = Math.min(selectableIndices.length - 1, currentPos + 1);
|
|
193616
|
+
return { ...s, selectedIndex: selectableIndices[nextPos] ?? idx };
|
|
193617
|
+
})
|
|
193583
193618
|
}
|
|
193584
193619
|
);
|
|
193585
193620
|
}
|
|
@@ -193669,12 +193704,12 @@ function DeployUI({ environment, config }) {
|
|
|
193669
193704
|
}
|
|
193670
193705
|
async function deployCommand(environment) {
|
|
193671
193706
|
const configPath = path23.join(process.cwd(), "specific.hcl");
|
|
193672
|
-
if (!
|
|
193707
|
+
if (!fs25.existsSync(configPath)) {
|
|
193673
193708
|
console.error("Error: No specific.hcl found in current directory");
|
|
193674
193709
|
process.exit(1);
|
|
193675
193710
|
}
|
|
193676
193711
|
let config;
|
|
193677
|
-
const hcl =
|
|
193712
|
+
const hcl = fs25.readFileSync(configPath, "utf-8");
|
|
193678
193713
|
try {
|
|
193679
193714
|
config = await parseConfig(hcl);
|
|
193680
193715
|
} catch (err) {
|
|
@@ -193695,7 +193730,7 @@ async function deployCommand(environment) {
|
|
|
193695
193730
|
|
|
193696
193731
|
// src/commands/exec.tsx
|
|
193697
193732
|
import { spawn as spawn6 } from "child_process";
|
|
193698
|
-
import * as
|
|
193733
|
+
import * as fs26 from "fs";
|
|
193699
193734
|
import * as path24 from "path";
|
|
193700
193735
|
async function execCommand(serviceName, command, instanceKey = "default") {
|
|
193701
193736
|
if (command.length === 0) {
|
|
@@ -193725,12 +193760,12 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
193725
193760
|
}
|
|
193726
193761
|
};
|
|
193727
193762
|
const configPath = path24.join(process.cwd(), "specific.hcl");
|
|
193728
|
-
if (!
|
|
193763
|
+
if (!fs26.existsSync(configPath)) {
|
|
193729
193764
|
console.error("Error: No specific.hcl found in current directory");
|
|
193730
193765
|
process.exit(1);
|
|
193731
193766
|
}
|
|
193732
193767
|
let config;
|
|
193733
|
-
const hcl =
|
|
193768
|
+
const hcl = fs26.readFileSync(configPath, "utf-8");
|
|
193734
193769
|
try {
|
|
193735
193770
|
config = await parseConfig(hcl);
|
|
193736
193771
|
} catch (err) {
|
|
@@ -193880,7 +193915,7 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
193880
193915
|
|
|
193881
193916
|
// src/commands/psql.tsx
|
|
193882
193917
|
import { spawn as spawn7 } from "child_process";
|
|
193883
|
-
import * as
|
|
193918
|
+
import * as fs27 from "fs";
|
|
193884
193919
|
import * as path25 from "path";
|
|
193885
193920
|
async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []) {
|
|
193886
193921
|
let startedResources = [];
|
|
@@ -193899,12 +193934,12 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
|
|
|
193899
193934
|
}
|
|
193900
193935
|
};
|
|
193901
193936
|
const configPath = path25.join(process.cwd(), "specific.hcl");
|
|
193902
|
-
if (!
|
|
193937
|
+
if (!fs27.existsSync(configPath)) {
|
|
193903
193938
|
console.error("Error: No specific.hcl found in current directory");
|
|
193904
193939
|
process.exit(1);
|
|
193905
193940
|
}
|
|
193906
193941
|
let config;
|
|
193907
|
-
const hcl =
|
|
193942
|
+
const hcl = fs27.readFileSync(configPath, "utf-8");
|
|
193908
193943
|
try {
|
|
193909
193944
|
config = await parseConfig(hcl);
|
|
193910
193945
|
} catch (err) {
|
|
@@ -194028,7 +194063,7 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
|
|
|
194028
194063
|
|
|
194029
194064
|
// src/commands/reshape.tsx
|
|
194030
194065
|
import { spawn as spawn8 } from "child_process";
|
|
194031
|
-
import * as
|
|
194066
|
+
import * as fs28 from "fs";
|
|
194032
194067
|
import * as path26 from "path";
|
|
194033
194068
|
var VALID_ACTIONS = ["start", "complete", "status", "abort", "check"];
|
|
194034
194069
|
var MIGRATION_SUBCOMMANDS = ["start", "complete", "abort"];
|
|
@@ -194046,8 +194081,8 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
194046
194081
|
let migrationsDir = "migrations";
|
|
194047
194082
|
let targetDb;
|
|
194048
194083
|
try {
|
|
194049
|
-
if (
|
|
194050
|
-
const configContent =
|
|
194084
|
+
if (fs28.existsSync(configPath)) {
|
|
194085
|
+
const configContent = fs28.readFileSync(configPath, "utf-8");
|
|
194051
194086
|
config = await parseConfig(configContent);
|
|
194052
194087
|
if (databaseName) {
|
|
194053
194088
|
const postgresConfig = config.postgres.find((p) => p.name === databaseName);
|
|
@@ -194183,7 +194218,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
194183
194218
|
const reshapeArgs = isMigrationSubcommand ? ["migration", action] : [action];
|
|
194184
194219
|
const fullMigrationsPath = path26.join(process.cwd(), migrationsDir);
|
|
194185
194220
|
if (action === "check" || action === "start") {
|
|
194186
|
-
if (
|
|
194221
|
+
if (fs28.existsSync(fullMigrationsPath)) {
|
|
194187
194222
|
reshapeArgs.push("--dirs", fullMigrationsPath);
|
|
194188
194223
|
} else if (action === "check") {
|
|
194189
194224
|
console.error(`Error: Migrations directory not found: ${fullMigrationsPath}`);
|
|
@@ -194233,7 +194268,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
194233
194268
|
import React8, { useState as useState7, useEffect as useEffect5 } from "react";
|
|
194234
194269
|
import { render as render6, Text as Text8, Box as Box8 } from "ink";
|
|
194235
194270
|
import Spinner6 from "ink-spinner";
|
|
194236
|
-
import * as
|
|
194271
|
+
import * as fs29 from "fs";
|
|
194237
194272
|
import * as path27 from "path";
|
|
194238
194273
|
function CleanUI({ instanceKey }) {
|
|
194239
194274
|
const [state, setState] = useState7({ status: "checking" });
|
|
@@ -194241,13 +194276,13 @@ function CleanUI({ instanceKey }) {
|
|
|
194241
194276
|
async function clean() {
|
|
194242
194277
|
const projectRoot = process.cwd();
|
|
194243
194278
|
const specificDir = path27.join(projectRoot, ".specific");
|
|
194244
|
-
if (!
|
|
194279
|
+
if (!fs29.existsSync(specificDir)) {
|
|
194245
194280
|
setState({ status: "nothing" });
|
|
194246
194281
|
return;
|
|
194247
194282
|
}
|
|
194248
194283
|
if (instanceKey) {
|
|
194249
194284
|
const keyDir = path27.join(specificDir, "keys", instanceKey);
|
|
194250
|
-
if (!
|
|
194285
|
+
if (!fs29.existsSync(keyDir)) {
|
|
194251
194286
|
setState({ status: "nothing" });
|
|
194252
194287
|
return;
|
|
194253
194288
|
}
|
|
@@ -194263,7 +194298,7 @@ function CleanUI({ instanceKey }) {
|
|
|
194263
194298
|
await stateManager.cleanStaleState();
|
|
194264
194299
|
setState({ status: "cleaning" });
|
|
194265
194300
|
try {
|
|
194266
|
-
|
|
194301
|
+
fs29.rmSync(keyDir, { recursive: true, force: true });
|
|
194267
194302
|
setState({ status: "success" });
|
|
194268
194303
|
} catch (err) {
|
|
194269
194304
|
setState({
|
|
@@ -194273,12 +194308,12 @@ function CleanUI({ instanceKey }) {
|
|
|
194273
194308
|
}
|
|
194274
194309
|
} else {
|
|
194275
194310
|
const keysDir = path27.join(specificDir, "keys");
|
|
194276
|
-
if (!
|
|
194311
|
+
if (!fs29.existsSync(keysDir)) {
|
|
194277
194312
|
setState({ status: "nothing" });
|
|
194278
194313
|
return;
|
|
194279
194314
|
}
|
|
194280
|
-
const keys =
|
|
194281
|
-
(f) =>
|
|
194315
|
+
const keys = fs29.readdirSync(keysDir).filter(
|
|
194316
|
+
(f) => fs29.statSync(path27.join(keysDir, f)).isDirectory()
|
|
194282
194317
|
);
|
|
194283
194318
|
for (const key of keys) {
|
|
194284
194319
|
const stateManager2 = new InstanceStateManager(projectRoot, key);
|
|
@@ -194302,7 +194337,7 @@ function CleanUI({ instanceKey }) {
|
|
|
194302
194337
|
}
|
|
194303
194338
|
setState({ status: "cleaning" });
|
|
194304
194339
|
try {
|
|
194305
|
-
|
|
194340
|
+
fs29.rmSync(keysDir, { recursive: true, force: true });
|
|
194306
194341
|
setState({ status: "success" });
|
|
194307
194342
|
} catch (err) {
|
|
194308
194343
|
setState({
|
|
@@ -194467,7 +194502,7 @@ import { render as render9, Text as Text11, Box as Box10, useApp as useApp6 } fr
|
|
|
194467
194502
|
import Spinner7 from "ink-spinner";
|
|
194468
194503
|
|
|
194469
194504
|
// src/lib/update.ts
|
|
194470
|
-
import * as
|
|
194505
|
+
import * as fs30 from "fs";
|
|
194471
194506
|
import * as path28 from "path";
|
|
194472
194507
|
var BINARIES_BASE_URL = "https://binaries.specific.dev/cli";
|
|
194473
194508
|
function compareVersions(a, b) {
|
|
@@ -194482,7 +194517,7 @@ function compareVersions(a, b) {
|
|
|
194482
194517
|
return 0;
|
|
194483
194518
|
}
|
|
194484
194519
|
async function checkForUpdate() {
|
|
194485
|
-
const currentVersion = "0.1.
|
|
194520
|
+
const currentVersion = "0.1.76";
|
|
194486
194521
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
194487
194522
|
if (!response.ok) {
|
|
194488
194523
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -194498,7 +194533,7 @@ function isBinaryWritable() {
|
|
|
194498
194533
|
const binaryPath = getCurrentBinaryPath();
|
|
194499
194534
|
const dir = path28.dirname(binaryPath);
|
|
194500
194535
|
try {
|
|
194501
|
-
|
|
194536
|
+
fs30.accessSync(dir, fs30.constants.W_OK);
|
|
194502
194537
|
return true;
|
|
194503
194538
|
} catch {
|
|
194504
194539
|
return false;
|
|
@@ -194509,21 +194544,21 @@ async function performUpdate(version, onProgress) {
|
|
|
194509
194544
|
const binaryDir = path28.dirname(binaryPath);
|
|
194510
194545
|
const tempPath = path28.join(binaryDir, `.specific-update-${process.pid}`);
|
|
194511
194546
|
try {
|
|
194512
|
-
const { platform:
|
|
194513
|
-
const url = `${BINARIES_BASE_URL}/${version}/specific-${
|
|
194547
|
+
const { platform: platform5, arch: arch3 } = getPlatformInfo();
|
|
194548
|
+
const url = `${BINARIES_BASE_URL}/${version}/specific-${platform5}-${arch3}`;
|
|
194514
194549
|
await downloadFile(url, tempPath, onProgress);
|
|
194515
|
-
const stat4 =
|
|
194550
|
+
const stat4 = fs30.statSync(tempPath);
|
|
194516
194551
|
if (stat4.size === 0) {
|
|
194517
194552
|
throw new Error("Downloaded binary is empty");
|
|
194518
194553
|
}
|
|
194519
|
-
|
|
194554
|
+
fs30.chmodSync(tempPath, 493);
|
|
194520
194555
|
onProgress?.({ phase: "finalizing" });
|
|
194521
|
-
|
|
194522
|
-
|
|
194556
|
+
fs30.unlinkSync(binaryPath);
|
|
194557
|
+
fs30.renameSync(tempPath, binaryPath);
|
|
194523
194558
|
} catch (error) {
|
|
194524
194559
|
try {
|
|
194525
|
-
if (
|
|
194526
|
-
|
|
194560
|
+
if (fs30.existsSync(tempPath)) {
|
|
194561
|
+
fs30.unlinkSync(tempPath);
|
|
194527
194562
|
}
|
|
194528
194563
|
} catch {
|
|
194529
194564
|
}
|
|
@@ -194533,21 +194568,21 @@ async function performUpdate(version, onProgress) {
|
|
|
194533
194568
|
|
|
194534
194569
|
// src/lib/background-update.ts
|
|
194535
194570
|
import { spawn as spawn9 } from "child_process";
|
|
194536
|
-
import * as
|
|
194571
|
+
import * as fs31 from "fs";
|
|
194537
194572
|
import * as path29 from "path";
|
|
194538
|
-
import * as
|
|
194539
|
-
var SPECIFIC_DIR = path29.join(
|
|
194573
|
+
import * as os9 from "os";
|
|
194574
|
+
var SPECIFIC_DIR = path29.join(os9.homedir(), ".specific");
|
|
194540
194575
|
var RATE_LIMIT_FILE = path29.join(SPECIFIC_DIR, "last-update-check");
|
|
194541
194576
|
var LOCK_FILE = path29.join(SPECIFIC_DIR, "update.lock");
|
|
194542
194577
|
var RATE_LIMIT_MS = 60 * 60 * 1e3;
|
|
194543
194578
|
var STALE_LOCK_MS = 10 * 60 * 1e3;
|
|
194544
194579
|
function writeCheckTimestamp() {
|
|
194545
|
-
|
|
194546
|
-
|
|
194580
|
+
fs31.mkdirSync(SPECIFIC_DIR, { recursive: true });
|
|
194581
|
+
fs31.writeFileSync(RATE_LIMIT_FILE, String(Date.now()), "utf-8");
|
|
194547
194582
|
}
|
|
194548
194583
|
function isRateLimited() {
|
|
194549
194584
|
try {
|
|
194550
|
-
const content =
|
|
194585
|
+
const content = fs31.readFileSync(RATE_LIMIT_FILE, "utf-8").trim();
|
|
194551
194586
|
const lastCheck = parseInt(content, 10);
|
|
194552
194587
|
if (isNaN(lastCheck)) return false;
|
|
194553
194588
|
return Date.now() - lastCheck < RATE_LIMIT_MS;
|
|
@@ -194681,7 +194716,7 @@ function updateCommand() {
|
|
|
194681
194716
|
var program = new Command();
|
|
194682
194717
|
var env = "production";
|
|
194683
194718
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
194684
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
194719
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.76").enablePositionalOptions();
|
|
194685
194720
|
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));
|
|
194686
194721
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
194687
194722
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|