@specific.dev/cli 0.1.61 → 0.1.62

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