@specific.dev/cli 0.1.71 → 0.1.73

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 (70) 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 +2 -2
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +5 -5
  5. package/dist/admin/__next._full.txt +8 -8
  6. package/dist/admin/__next._head.txt +1 -1
  7. package/dist/admin/__next._index.txt +3 -3
  8. package/dist/admin/__next._tree.txt +1 -1
  9. package/dist/admin/_next/static/chunks/4bd160f783f6ccf1.js +1 -0
  10. package/dist/admin/_not-found/__next._full.txt +3 -3
  11. package/dist/admin/_not-found/__next._head.txt +1 -1
  12. package/dist/admin/_not-found/__next._index.txt +3 -3
  13. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  14. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  15. package/dist/admin/_not-found/__next._tree.txt +1 -1
  16. package/dist/admin/_not-found/index.html +1 -1
  17. package/dist/admin/_not-found/index.txt +3 -3
  18. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +2 -2
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  20. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +5 -5
  21. package/dist/admin/databases/__next._full.txt +8 -8
  22. package/dist/admin/databases/__next._head.txt +1 -1
  23. package/dist/admin/databases/__next._index.txt +3 -3
  24. package/dist/admin/databases/__next._tree.txt +1 -1
  25. package/dist/admin/databases/index.html +1 -1
  26. package/dist/admin/databases/index.txt +8 -8
  27. package/dist/admin/fullscreen/__next._full.txt +4 -4
  28. package/dist/admin/fullscreen/__next._head.txt +1 -1
  29. package/dist/admin/fullscreen/__next._index.txt +3 -3
  30. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  31. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
  32. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  33. package/dist/admin/fullscreen/databases/__next._full.txt +4 -4
  34. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._index.txt +3 -3
  36. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +2 -2
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  39. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  40. package/dist/admin/fullscreen/databases/index.html +1 -1
  41. package/dist/admin/fullscreen/databases/index.txt +4 -4
  42. package/dist/admin/fullscreen/index.html +1 -1
  43. package/dist/admin/fullscreen/index.txt +4 -4
  44. package/dist/admin/index.html +1 -1
  45. package/dist/admin/index.txt +8 -8
  46. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +2 -2
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  48. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +5 -5
  49. package/dist/admin/mail/__next._full.txt +8 -8
  50. package/dist/admin/mail/__next._head.txt +1 -1
  51. package/dist/admin/mail/__next._index.txt +3 -3
  52. package/dist/admin/mail/__next._tree.txt +1 -1
  53. package/dist/admin/mail/index.html +1 -1
  54. package/dist/admin/mail/index.txt +8 -8
  55. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +5 -5
  56. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +2 -2
  57. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  58. package/dist/admin/workflows/__next._full.txt +8 -8
  59. package/dist/admin/workflows/__next._head.txt +1 -1
  60. package/dist/admin/workflows/__next._index.txt +3 -3
  61. package/dist/admin/workflows/__next._tree.txt +1 -1
  62. package/dist/admin/workflows/index.html +1 -1
  63. package/dist/admin/workflows/index.txt +8 -8
  64. package/dist/cli.js +343 -279
  65. package/dist/postinstall.js +1 -1
  66. package/package.json +1 -1
  67. package/dist/admin/_next/static/chunks/47a5dab862795de7.js +0 -1
  68. /package/dist/admin/_next/static/{3nqvPNOX7a-_9HydleH6d → 2GhRJUspcGN_TKmFF6ihm}/_buildManifest.js +0 -0
  69. /package/dist/admin/_next/static/{3nqvPNOX7a-_9HydleH6d → 2GhRJUspcGN_TKmFF6ihm}/_clientMiddlewareManifest.json +0 -0
  70. /package/dist/admin/_next/static/{3nqvPNOX7a-_9HydleH6d → 2GhRJUspcGN_TKmFF6ihm}/_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 fs5 from "node:fs";
42
+ import fs6 from "node:fs";
43
43
  function hasDockerEnv() {
44
44
  try {
45
- fs5.statSync("/.dockerenv");
45
+ fs6.statSync("/.dockerenv");
46
46
  return true;
47
47
  } catch {
48
48
  return false;
@@ -50,7 +50,7 @@ function hasDockerEnv() {
50
50
  }
51
51
  function hasDockerCGroup() {
52
52
  try {
53
- return fs5.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
53
+ return fs6.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
54
54
  } catch {
55
55
  return false;
56
56
  }
@@ -68,7 +68,7 @@ var init_is_docker = __esm({
68
68
  });
69
69
 
70
70
  // node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
71
- import fs6 from "node:fs";
71
+ import fs7 from "node:fs";
72
72
  function isInsideContainer() {
73
73
  if (cachedResult === void 0) {
74
74
  cachedResult = hasContainerEnv() || isDocker();
@@ -81,7 +81,7 @@ var init_is_inside_container = __esm({
81
81
  init_is_docker();
82
82
  hasContainerEnv = () => {
83
83
  try {
84
- fs6.statSync("/run/.containerenv");
84
+ fs7.statSync("/run/.containerenv");
85
85
  return true;
86
86
  } catch {
87
87
  return false;
@@ -92,8 +92,8 @@ var init_is_inside_container = __esm({
92
92
 
93
93
  // node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
94
94
  import process2 from "node:process";
95
- import os4 from "node:os";
96
- import fs7 from "node:fs";
95
+ import os5 from "node:os";
96
+ import fs8 from "node:fs";
97
97
  var isWsl, is_wsl_default;
98
98
  var init_is_wsl = __esm({
99
99
  "node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js"() {
@@ -102,14 +102,14 @@ var init_is_wsl = __esm({
102
102
  if (process2.platform !== "linux") {
103
103
  return false;
104
104
  }
105
- if (os4.release().toLowerCase().includes("microsoft")) {
105
+ if (os5.release().toLowerCase().includes("microsoft")) {
106
106
  if (isInsideContainer()) {
107
107
  return false;
108
108
  }
109
109
  return true;
110
110
  }
111
111
  try {
112
- return fs7.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
112
+ return fs8.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
113
113
  } catch {
114
114
  return false;
115
115
  }
@@ -179,7 +179,7 @@ var init_utilities = __esm({
179
179
  // node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
180
180
  import { promisify as promisify2 } from "node:util";
181
181
  import childProcess2 from "node:child_process";
182
- import fs8, { constants as fsConstants } from "node:fs/promises";
182
+ import fs9, { constants as fsConstants } from "node:fs/promises";
183
183
  var execFile2, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
184
184
  var init_wsl_utils = __esm({
185
185
  "node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
@@ -198,14 +198,14 @@ var init_wsl_utils = __esm({
198
198
  const configFilePath = "/etc/wsl.conf";
199
199
  let isConfigFileExists = false;
200
200
  try {
201
- await fs8.access(configFilePath, fsConstants.F_OK);
201
+ await fs9.access(configFilePath, fsConstants.F_OK);
202
202
  isConfigFileExists = true;
203
203
  } catch {
204
204
  }
205
205
  if (!isConfigFileExists) {
206
206
  return defaultMountPoint;
207
207
  }
208
- const configContent = await fs8.readFile(configFilePath, { encoding: "utf8" });
208
+ const configContent = await fs9.readFile(configFilePath, { encoding: "utf8" });
209
209
  const parsedMountPoint = parseMountPointFromConfig(configContent);
210
210
  if (parsedMountPoint === void 0) {
211
211
  return defaultMountPoint;
@@ -224,7 +224,7 @@ var init_wsl_utils = __esm({
224
224
  canAccessPowerShellPromise ??= (async () => {
225
225
  try {
226
226
  const psPath = await powerShellPath2();
227
- await fs8.access(psPath, fsConstants.X_OK);
227
+ await fs9.access(psPath, fsConstants.X_OK);
228
228
  return true;
229
229
  } catch {
230
230
  return false;
@@ -435,7 +435,7 @@ import process8 from "node:process";
435
435
  import path5 from "node:path";
436
436
  import { fileURLToPath } from "node:url";
437
437
  import childProcess3 from "node:child_process";
438
- import fs9, { constants as fsConstants2 } from "node:fs/promises";
438
+ import fs10, { constants as fsConstants2 } from "node:fs/promises";
439
439
  function detectArchBinary(binary) {
440
440
  if (typeof binary === "string" || Array.isArray(binary)) {
441
441
  return binary;
@@ -446,16 +446,16 @@ function detectArchBinary(binary) {
446
446
  }
447
447
  return archBinary;
448
448
  }
449
- function detectPlatformBinary({ [platform3]: platformBinary }, { wsl } = {}) {
449
+ function detectPlatformBinary({ [platform4]: platformBinary }, { wsl } = {}) {
450
450
  if (wsl && is_wsl_default) {
451
451
  return detectArchBinary(wsl);
452
452
  }
453
453
  if (!platformBinary) {
454
- throw new Error(`${platform3} is not supported`);
454
+ throw new Error(`${platform4} is not supported`);
455
455
  }
456
456
  return detectArchBinary(platformBinary);
457
457
  }
458
- var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform3, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
458
+ var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform4, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
459
459
  var init_open = __esm({
460
460
  "node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
461
461
  init_wsl_utils();
@@ -467,7 +467,7 @@ var init_open = __esm({
467
467
  fallbackAttemptSymbol = Symbol("fallbackAttempt");
468
468
  __dirname = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
469
469
  localXdgOpenPath = path5.join(__dirname, "xdg-open");
470
- ({ platform: platform3, arch } = process8);
470
+ ({ platform: platform4, arch } = process8);
471
471
  tryEachApp = async (apps2, opener) => {
472
472
  if (apps2.length === 0) {
473
473
  return;
@@ -564,7 +564,7 @@ var init_open = __esm({
564
564
  if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
565
565
  shouldUseWindowsInWsl = await canAccessPowerShell();
566
566
  }
567
- if (platform3 === "darwin") {
567
+ if (platform4 === "darwin") {
568
568
  command = "open";
569
569
  if (options2.wait) {
570
570
  cliArguments.push("--wait-apps");
@@ -578,7 +578,7 @@ var init_open = __esm({
578
578
  if (app) {
579
579
  cliArguments.push("-a", app);
580
580
  }
581
- } else if (platform3 === "win32" || shouldUseWindowsInWsl) {
581
+ } else if (platform4 === "win32" || shouldUseWindowsInWsl) {
582
582
  command = await powerShellPath2();
583
583
  cliArguments.push(...executePowerShell.argumentsPrefix);
584
584
  if (!is_wsl_default) {
@@ -614,11 +614,11 @@ var init_open = __esm({
614
614
  const isBundled = !__dirname || __dirname === "/";
615
615
  let exeLocalXdgOpen = false;
616
616
  try {
617
- await fs9.access(localXdgOpenPath, fsConstants2.X_OK);
617
+ await fs10.access(localXdgOpenPath, fsConstants2.X_OK);
618
618
  exeLocalXdgOpen = true;
619
619
  } catch {
620
620
  }
621
- const useSystemXdgOpen = process8.versions.electron ?? (platform3 === "android" || isBundled || !exeLocalXdgOpen);
621
+ const useSystemXdgOpen = process8.versions.electron ?? (platform4 === "android" || isBundled || !exeLocalXdgOpen);
622
622
  command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
623
623
  }
624
624
  if (appArguments.length > 0) {
@@ -629,7 +629,7 @@ var init_open = __esm({
629
629
  childProcessOptions.detached = true;
630
630
  }
631
631
  }
632
- if (platform3 === "darwin" && appArguments.length > 0) {
632
+ if (platform4 === "darwin" && appArguments.length > 0) {
633
633
  cliArguments.push("--args", ...appArguments);
634
634
  }
635
635
  if (options2.target) {
@@ -754,8 +754,8 @@ var require_dist = __commonJS({
754
754
  var $global, $module, $NaN = NaN;
755
755
  if ("undefined" != typeof window ? $global = window : "undefined" != typeof self ? $global = self : "undefined" != typeof global ? ($global = global).require = __require : $global = this, void 0 === $global || void 0 === $global.Array) throw new Error("no global object found");
756
756
  if ("undefined" != typeof module && ($module = module), !$global.fs && $global.require) try {
757
- var fs32 = $global.require("fs");
758
- "object" == typeof fs32 && null !== fs32 && 0 !== Object.keys(fs32).length && ($global.fs = fs32);
757
+ var fs33 = $global.require("fs");
758
+ "object" == typeof fs33 && null !== fs33 && 0 !== Object.keys(fs33).length && ($global.fs = fs33);
759
759
  } catch (e) {
760
760
  }
761
761
  if (!$global.fs) {
@@ -183430,11 +183430,14 @@ import { Command } from "commander";
183430
183430
  import React2, { useState, useEffect } from "react";
183431
183431
  import { render as render2, Text as Text2, Box as Box2, useInput, useApp } from "ink";
183432
183432
  import "ink-spinner";
183433
- import * as fs11 from "fs";
183433
+ import * as fs12 from "fs";
183434
183434
  import * as path7 from "path";
183435
183435
 
183436
183436
  // src/lib/dev/system-setup.ts
183437
183437
  import { execSync as execSync2 } from "child_process";
183438
+ import * as fs4 from "fs";
183439
+ import * as os4 from "os";
183440
+ import * as path3 from "path";
183438
183441
 
183439
183442
  // src/lib/dev/local-ca.ts
183440
183443
  import * as fs from "fs";
@@ -183445,25 +183448,41 @@ import { execSync } from "child_process";
183445
183448
  function getCADir() {
183446
183449
  return path.join(os.homedir(), ".specific", "root_ca");
183447
183450
  }
183451
+ var EXPECTED_DOMAIN = "spcf.localhost";
183448
183452
  function caFilesExist() {
183449
183453
  const caDir = getCADir();
183450
- return fs.existsSync(path.join(caDir, "ca.key")) && fs.existsSync(path.join(caDir, "ca.crt"));
183454
+ const keyPath = path.join(caDir, "ca.key");
183455
+ const certPath = path.join(caDir, "ca.crt");
183456
+ if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
183457
+ return false;
183458
+ }
183459
+ try {
183460
+ const certPem = fs.readFileSync(certPath, "utf-8");
183461
+ const cert = forge.pki.certificateFromPem(certPem);
183462
+ const nameConstraints = cert.getExtension("nameConstraints");
183463
+ if (!nameConstraints) {
183464
+ return false;
183465
+ }
183466
+ return nameConstraints.value.includes(EXPECTED_DOMAIN);
183467
+ } catch {
183468
+ return false;
183469
+ }
183451
183470
  }
183452
183471
  function caInstalledInTrustStore() {
183453
183472
  if (!caFilesExist()) {
183454
183473
  return false;
183455
183474
  }
183456
- const platform5 = os.platform();
183475
+ const platform6 = os.platform();
183457
183476
  const certPath = path.join(getCADir(), "ca.crt");
183458
183477
  const diskCert = fs.readFileSync(certPath, "utf-8").replace(/\r\n/g, "\n").trim();
183459
183478
  try {
183460
- if (platform5 === "darwin") {
183479
+ if (platform6 === "darwin") {
183461
183480
  const keychainCert = execSync(
183462
183481
  'security find-certificate -c "Specific Local Development CA" -p /Library/Keychains/System.keychain',
183463
183482
  { encoding: "utf-8" }
183464
183483
  ).replace(/\r\n/g, "\n").trim();
183465
183484
  return keychainCert === diskCert;
183466
- } else if (platform5 === "linux") {
183485
+ } else if (platform6 === "linux") {
183467
183486
  const trustPaths = [
183468
183487
  "/usr/local/share/ca-certificates/specific-local-ca.crt",
183469
183488
  "/etc/pki/ca-trust/source/anchors/specific-local-ca.crt"
@@ -183536,8 +183555,8 @@ function generateRootCA() {
183536
183555
  cert.setSubject(attrs);
183537
183556
  cert.setIssuer(attrs);
183538
183557
  const nameConstraintsExt = createNameConstraintsExtension([
183539
- ".local.spcf.app",
183540
- "local.spcf.app"
183558
+ ".spcf.localhost",
183559
+ "spcf.localhost"
183541
183560
  ]);
183542
183561
  cert.setExtensions([
183543
183562
  { name: "basicConstraints", cA: true, critical: true },
@@ -183571,15 +183590,15 @@ function removeCA() {
183571
183590
  }
183572
183591
  }
183573
183592
  function getCAInstallCommands(certPath) {
183574
- const platform5 = os.platform();
183575
- if (platform5 === "darwin") {
183593
+ const platform6 = os.platform();
183594
+ if (platform6 === "darwin") {
183576
183595
  return [
183577
183596
  // Remove any existing cert with the same CN first — add-trusted-cert
183578
183597
  // silently does nothing if a cert with the same subject already exists.
183579
183598
  'security delete-certificate -c "Specific Local Development CA" /Library/Keychains/System.keychain 2>/dev/null || true',
183580
183599
  `security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`
183581
183600
  ];
183582
- } else if (platform5 === "linux") {
183601
+ } else if (platform6 === "linux") {
183583
183602
  if (fs.existsSync("/usr/local/share/ca-certificates")) {
183584
183603
  return [
183585
183604
  `cp "${certPath}" /usr/local/share/ca-certificates/specific-local-ca.crt`,
@@ -183593,7 +183612,7 @@ function getCAInstallCommands(certPath) {
183593
183612
  }
183594
183613
  throw new Error("Could not detect Linux certificate trust mechanism");
183595
183614
  }
183596
- throw new Error(`Unsupported platform: ${platform5}`);
183615
+ throw new Error(`Unsupported platform: ${platform6}`);
183597
183616
  }
183598
183617
  function generateCertificate(domain, keys = []) {
183599
183618
  const caDir = getCADir();
@@ -183635,29 +183654,31 @@ function generateCertificate(domain, keys = []) {
183635
183654
  // src/lib/dev/resolver-config.ts
183636
183655
  import * as fs2 from "fs";
183637
183656
  import * as os2 from "os";
183638
- var RESOLVER_FILE_MACOS = "/etc/resolver/local.spcf.app";
183657
+ var RESOLVER_FILE_MACOS = "/etc/resolver/spcf.localhost";
183658
+ var OLD_RESOLVER_FILE_MACOS = "/etc/resolver/local.spcf.app";
183639
183659
  var RESOLVER_FILE_LINUX = "/etc/systemd/resolved.conf.d/specific-local.conf";
183640
183660
  function resolverConfigExists() {
183641
- const platform5 = os2.platform();
183642
- if (platform5 === "darwin") {
183661
+ const platform6 = os2.platform();
183662
+ if (platform6 === "darwin") {
183643
183663
  return fs2.existsSync(RESOLVER_FILE_MACOS);
183644
- } else if (platform5 === "linux") {
183664
+ } else if (platform6 === "linux") {
183645
183665
  return fs2.existsSync(RESOLVER_FILE_LINUX);
183646
183666
  }
183647
183667
  return false;
183648
183668
  }
183649
183669
  function getResolverInstallCommands(port) {
183650
- const platform5 = os2.platform();
183651
- if (platform5 === "darwin") {
183670
+ const platform6 = os2.platform();
183671
+ if (platform6 === "darwin") {
183652
183672
  return [
183653
183673
  "mkdir -p /etc/resolver",
183674
+ `rm -f ${OLD_RESOLVER_FILE_MACOS}`,
183654
183675
  `printf "nameserver 127.0.0.1\\nport ${port}\\n" > ${RESOLVER_FILE_MACOS}`
183655
183676
  ];
183656
- } else if (platform5 === "linux") {
183677
+ } else if (platform6 === "linux") {
183657
183678
  if (fs2.existsSync("/etc/systemd/resolved.conf.d") || fs2.existsSync("/etc/systemd")) {
183658
183679
  return [
183659
183680
  "mkdir -p /etc/systemd/resolved.conf.d",
183660
- `printf "[Resolve]\\nDNS=127.0.0.1:${port}\\nDomains=~local.spcf.app\\n" > ${RESOLVER_FILE_LINUX}`,
183681
+ `printf "[Resolve]\\nDNS=127.0.0.1:${port}\\nDomains=~spcf.localhost\\n" > ${RESOLVER_FILE_LINUX}`,
183661
183682
  "systemctl restart systemd-resolved"
183662
183683
  ];
183663
183684
  }
@@ -183746,7 +183767,6 @@ async function startDnsServer(port = DNS_PORT) {
183746
183767
  }
183747
183768
 
183748
183769
  // src/lib/dev/system-setup.ts
183749
- import * as path3 from "path";
183750
183770
  function systemSetupNeeded() {
183751
183771
  return !caInstalledInTrustStore() || !resolverConfigExists();
183752
183772
  }
@@ -183773,7 +183793,7 @@ function performSystemSetup() {
183773
183793
  return;
183774
183794
  }
183775
183795
  try {
183776
- execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
183796
+ execPrivileged(commands);
183777
183797
  } catch (err) {
183778
183798
  if (needsGenerate) {
183779
183799
  removeCA();
@@ -183781,14 +183801,43 @@ function performSystemSetup() {
183781
183801
  throw err;
183782
183802
  }
183783
183803
  }
183804
+ function execPrivileged(commands) {
183805
+ if (commands.length === 0) return;
183806
+ if (os4.platform() === "darwin") {
183807
+ const scriptPath = path3.join(os4.tmpdir(), "specific-setup.sh");
183808
+ const appPath = path3.join(os4.tmpdir(), "Specific.app");
183809
+ try {
183810
+ fs4.writeFileSync(
183811
+ scriptPath,
183812
+ "#!/bin/sh\nset -e\n" + commands.join("\n") + "\n",
183813
+ { mode: 448 }
183814
+ );
183815
+ execSync2(
183816
+ `osacompile -o '${appPath}' -e 'do shell script "sh ${scriptPath}" with administrator privileges'`
183817
+ );
183818
+ execSync2(`'${appPath}/Contents/MacOS/applet'`, { stdio: "pipe" });
183819
+ } finally {
183820
+ try {
183821
+ fs4.unlinkSync(scriptPath);
183822
+ } catch {
183823
+ }
183824
+ try {
183825
+ fs4.rmSync(appPath, { recursive: true });
183826
+ } catch {
183827
+ }
183828
+ }
183829
+ } else {
183830
+ execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
183831
+ }
183832
+ }
183784
183833
 
183785
183834
  // src/lib/analytics/index.ts
183786
183835
  import { PostHog } from "posthog-node";
183787
- import * as os6 from "os";
183836
+ import * as os7 from "os";
183788
183837
  import * as crypto from "crypto";
183789
183838
 
183790
183839
  // src/lib/project/config.ts
183791
- import * as fs4 from "fs";
183840
+ import * as fs5 from "fs";
183792
183841
  import * as path4 from "path";
183793
183842
  var PROJECT_ID_FILE = ".specific/project_id";
183794
183843
  var ProjectNotLinkedError = class extends Error {
@@ -183805,10 +183854,10 @@ Run: specific deploy`
183805
183854
  };
183806
183855
  function readProjectId(projectDir = process.cwd()) {
183807
183856
  const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
183808
- if (!fs4.existsSync(projectIdPath)) {
183857
+ if (!fs5.existsSync(projectIdPath)) {
183809
183858
  throw new ProjectNotLinkedError();
183810
183859
  }
183811
- const projectId = fs4.readFileSync(projectIdPath, "utf-8").trim();
183860
+ const projectId = fs5.readFileSync(projectIdPath, "utf-8").trim();
183812
183861
  if (!projectId) {
183813
183862
  throw new Error(`${PROJECT_ID_FILE} is empty`);
183814
183863
  }
@@ -183816,20 +183865,20 @@ function readProjectId(projectDir = process.cwd()) {
183816
183865
  }
183817
183866
  function hasProjectId(projectDir = process.cwd()) {
183818
183867
  const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
183819
- return fs4.existsSync(projectIdPath);
183868
+ return fs5.existsSync(projectIdPath);
183820
183869
  }
183821
183870
  function writeProjectId(projectId, projectDir = process.cwd()) {
183822
183871
  const specificDir = path4.join(projectDir, ".specific");
183823
- if (!fs4.existsSync(specificDir)) {
183824
- fs4.mkdirSync(specificDir, { recursive: true });
183872
+ if (!fs5.existsSync(specificDir)) {
183873
+ fs5.mkdirSync(specificDir, { recursive: true });
183825
183874
  }
183826
- fs4.writeFileSync(path4.join(specificDir, "project_id"), projectId + "\n");
183875
+ fs5.writeFileSync(path4.join(specificDir, "project_id"), projectId + "\n");
183827
183876
  }
183828
183877
 
183829
183878
  // src/lib/auth/credentials.ts
183830
- import * as fs10 from "fs";
183879
+ import * as fs11 from "fs";
183831
183880
  import * as path6 from "path";
183832
- import * as os5 from "os";
183881
+ import * as os6 from "os";
183833
183882
 
183834
183883
  // src/lib/auth/errors.ts
183835
183884
  var RefreshTokenExpiredError = class extends Error {
@@ -184382,18 +184431,18 @@ var ApiClient = class {
184382
184431
 
184383
184432
  // src/lib/auth/credentials.ts
184384
184433
  function getUserCredentialsDir() {
184385
- return path6.join(os5.homedir(), ".specific");
184434
+ return path6.join(os6.homedir(), ".specific");
184386
184435
  }
184387
184436
  function getCredentialsPath() {
184388
184437
  return path6.join(getUserCredentialsDir(), "credentials.json");
184389
184438
  }
184390
184439
  function readUserCredentials() {
184391
184440
  const credentialsPath = getCredentialsPath();
184392
- if (!fs10.existsSync(credentialsPath)) {
184441
+ if (!fs11.existsSync(credentialsPath)) {
184393
184442
  return null;
184394
184443
  }
184395
184444
  try {
184396
- const content = fs10.readFileSync(credentialsPath, "utf-8");
184445
+ const content = fs11.readFileSync(credentialsPath, "utf-8");
184397
184446
  return JSON.parse(content);
184398
184447
  } catch {
184399
184448
  return null;
@@ -184401,18 +184450,18 @@ function readUserCredentials() {
184401
184450
  }
184402
184451
  function writeUserCredentials(credentials) {
184403
184452
  const dir = getUserCredentialsDir();
184404
- if (!fs10.existsSync(dir)) {
184405
- fs10.mkdirSync(dir, { recursive: true, mode: 448 });
184453
+ if (!fs11.existsSync(dir)) {
184454
+ fs11.mkdirSync(dir, { recursive: true, mode: 448 });
184406
184455
  }
184407
184456
  const credentialsPath = getCredentialsPath();
184408
- fs10.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
184457
+ fs11.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
184409
184458
  mode: 384
184410
184459
  });
184411
184460
  }
184412
184461
  function clearUserCredentials() {
184413
184462
  const credentialsPath = getCredentialsPath();
184414
- if (fs10.existsSync(credentialsPath)) {
184415
- fs10.unlinkSync(credentialsPath);
184463
+ if (fs11.existsSync(credentialsPath)) {
184464
+ fs11.unlinkSync(credentialsPath);
184416
184465
  }
184417
184466
  }
184418
184467
  function isLoggedIn() {
@@ -184491,7 +184540,7 @@ function isEnabled() {
184491
184540
  }
184492
184541
  function getAnonymousId() {
184493
184542
  if (anonymousId) return anonymousId;
184494
- const machineId = `${os6.hostname()}-${os6.userInfo().username}`;
184543
+ const machineId = `${os7.hostname()}-${os7.userInfo().username}`;
184495
184544
  anonymousId = crypto.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
184496
184545
  return anonymousId;
184497
184546
  }
@@ -184538,7 +184587,7 @@ function trackEvent(event, properties) {
184538
184587
  event,
184539
184588
  properties: {
184540
184589
  ...properties,
184541
- cli_version: "0.1.71",
184590
+ cli_version: "0.1.73",
184542
184591
  platform: process.platform,
184543
184592
  node_version: process.version,
184544
184593
  project_id: getProjectId()
@@ -184575,57 +184624,57 @@ var options = [
184575
184624
  ];
184576
184625
  function isGitProject() {
184577
184626
  const gitPath = path7.join(process.cwd(), ".git");
184578
- return fs11.existsSync(gitPath);
184627
+ return fs12.existsSync(gitPath);
184579
184628
  }
184580
184629
  function detectExistingAgents() {
184581
184630
  const detected = {};
184582
184631
  const cursorDir = path7.join(process.cwd(), ".cursor");
184583
- if (fs11.existsSync(cursorDir)) {
184632
+ if (fs12.existsSync(cursorDir)) {
184584
184633
  detected["cursor"] = true;
184585
184634
  }
184586
184635
  const claudeDir = path7.join(process.cwd(), ".claude");
184587
184636
  const claudeMd = path7.join(process.cwd(), "CLAUDE.md");
184588
- if (fs11.existsSync(claudeDir) || fs11.existsSync(claudeMd)) {
184637
+ if (fs12.existsSync(claudeDir) || fs12.existsSync(claudeMd)) {
184589
184638
  detected["claude"] = true;
184590
184639
  }
184591
184640
  const agentsMd = path7.join(process.cwd(), "AGENTS.md");
184592
- if (fs11.existsSync(agentsMd)) {
184641
+ if (fs12.existsSync(agentsMd)) {
184593
184642
  detected["codex"] = true;
184594
184643
  }
184595
184644
  return detected;
184596
184645
  }
184597
184646
  function appendOrCreateFile(filePath, content) {
184598
- if (fs11.existsSync(filePath)) {
184599
- const existing = fs11.readFileSync(filePath, "utf-8");
184647
+ if (fs12.existsSync(filePath)) {
184648
+ const existing = fs12.readFileSync(filePath, "utf-8");
184600
184649
  if (existing.includes("specific docs") || existing.includes("specific check")) {
184601
184650
  return "unchanged";
184602
184651
  }
184603
184652
  const separator = existing.endsWith("\n") ? "\n" : "\n\n";
184604
- fs11.writeFileSync(filePath, existing + separator + content + "\n");
184653
+ fs12.writeFileSync(filePath, existing + separator + content + "\n");
184605
184654
  return "modified";
184606
184655
  } else {
184607
- fs11.writeFileSync(filePath, content + "\n");
184656
+ fs12.writeFileSync(filePath, content + "\n");
184608
184657
  return "created";
184609
184658
  }
184610
184659
  }
184611
184660
  function addToGitignore() {
184612
184661
  const gitignorePath = path7.join(process.cwd(), ".gitignore");
184613
184662
  const entries = [".specific", "specific.local"];
184614
- if (fs11.existsSync(gitignorePath)) {
184615
- const existing = fs11.readFileSync(gitignorePath, "utf-8");
184663
+ if (fs12.existsSync(gitignorePath)) {
184664
+ const existing = fs12.readFileSync(gitignorePath, "utf-8");
184616
184665
  const lines = existing.split("\n").map((l) => l.trim());
184617
184666
  const missingEntries = entries.filter((entry) => !lines.includes(entry));
184618
184667
  if (missingEntries.length === 0) {
184619
184668
  return "unchanged";
184620
184669
  }
184621
184670
  const separator = existing.endsWith("\n") ? "" : "\n";
184622
- fs11.writeFileSync(
184671
+ fs12.writeFileSync(
184623
184672
  gitignorePath,
184624
184673
  existing + separator + missingEntries.join("\n") + "\n"
184625
184674
  );
184626
184675
  return "modified";
184627
184676
  } else {
184628
- fs11.writeFileSync(gitignorePath, entries.join("\n") + "\n");
184677
+ fs12.writeFileSync(gitignorePath, entries.join("\n") + "\n");
184629
184678
  return "created";
184630
184679
  }
184631
184680
  }
@@ -184633,8 +184682,8 @@ function configureClaudeCodePermissions() {
184633
184682
  const claudeDir = path7.join(process.cwd(), ".claude");
184634
184683
  const settingsPath = path7.join(claudeDir, "settings.local.json");
184635
184684
  const permissions = ["Bash(specific docs:*)", "Bash(specific check:*)"];
184636
- if (fs11.existsSync(settingsPath)) {
184637
- const existing = JSON.parse(fs11.readFileSync(settingsPath, "utf-8"));
184685
+ if (fs12.existsSync(settingsPath)) {
184686
+ const existing = JSON.parse(fs12.readFileSync(settingsPath, "utf-8"));
184638
184687
  const allowList = existing?.permissions?.allow || [];
184639
184688
  const missingPermissions = permissions.filter(
184640
184689
  (p) => !allowList.includes(p)
@@ -184649,39 +184698,39 @@ function configureClaudeCodePermissions() {
184649
184698
  existing.permissions.allow = [];
184650
184699
  }
184651
184700
  existing.permissions.allow.push(...missingPermissions);
184652
- fs11.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
184701
+ fs12.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
184653
184702
  return "modified";
184654
184703
  }
184655
- if (!fs11.existsSync(claudeDir)) {
184656
- fs11.mkdirSync(claudeDir);
184704
+ if (!fs12.existsSync(claudeDir)) {
184705
+ fs12.mkdirSync(claudeDir);
184657
184706
  }
184658
184707
  const settings = {
184659
184708
  permissions: {
184660
184709
  allow: permissions
184661
184710
  }
184662
184711
  };
184663
- fs11.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
184712
+ fs12.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
184664
184713
  return "created";
184665
184714
  }
184666
184715
  function createCursorRule() {
184667
184716
  const cursorDir = path7.join(process.cwd(), ".cursor");
184668
184717
  const rulesDir = path7.join(cursorDir, "rules");
184669
184718
  const mdcPath = path7.join(rulesDir, "specific.mdc");
184670
- if (fs11.existsSync(mdcPath)) {
184671
- const existing = fs11.readFileSync(mdcPath, "utf-8");
184719
+ if (fs12.existsSync(mdcPath)) {
184720
+ const existing = fs12.readFileSync(mdcPath, "utf-8");
184672
184721
  if (existing.includes("specific docs") || existing.includes("specific check")) {
184673
184722
  return "unchanged";
184674
184723
  }
184675
- fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184724
+ fs12.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184676
184725
  return "modified";
184677
184726
  }
184678
- if (!fs11.existsSync(cursorDir)) {
184679
- fs11.mkdirSync(cursorDir);
184727
+ if (!fs12.existsSync(cursorDir)) {
184728
+ fs12.mkdirSync(cursorDir);
184680
184729
  }
184681
- if (!fs11.existsSync(rulesDir)) {
184682
- fs11.mkdirSync(rulesDir);
184730
+ if (!fs12.existsSync(rulesDir)) {
184731
+ fs12.mkdirSync(rulesDir);
184683
184732
  }
184684
- fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184733
+ fs12.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184685
184734
  return "created";
184686
184735
  }
184687
184736
  function configureAgents(checked) {
@@ -184736,7 +184785,7 @@ function InitUI() {
184736
184785
  const [phase, setPhase] = useState(
184737
184786
  () => !systemSetupNeeded() ? "agents" : "installing-ca"
184738
184787
  );
184739
- const [caInstallPhase, setCaInstallPhase] = useState(() => !systemSetupNeeded() ? "done" : "installing");
184788
+ const [caInstallPhase, setCaInstallPhase] = useState(() => !systemSetupNeeded() ? "done" : "prompt");
184740
184789
  const [focusedIndex, setFocusedIndex] = useState(initialState.focusedIndex);
184741
184790
  const [checked, setChecked] = useState(
184742
184791
  initialState.detected
@@ -184767,6 +184816,10 @@ function InitUI() {
184767
184816
  }
184768
184817
  const isSubmitFocused = focusedIndex === options.length;
184769
184818
  useInput((input, key) => {
184819
+ if (phase === "installing-ca" && caInstallPhase === "prompt" && key.return) {
184820
+ setCaInstallPhase("installing");
184821
+ return;
184822
+ }
184770
184823
  if (phase !== "agents") return;
184771
184824
  if (key.upArrow || input === "k") {
184772
184825
  setFocusedIndex((prev) => Math.max(0, prev - 1));
@@ -184796,8 +184849,11 @@ function InitUI() {
184796
184849
  }
184797
184850
  }, [phase, exit]);
184798
184851
  if (phase === "installing-ca") {
184852
+ if (caInstallPhase === "prompt") {
184853
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "We need to do a one-time setup for all your Specific projects."), /* @__PURE__ */ React2.createElement(Text2, null, "This is so we can run your apps locally with secure URLs:"), /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "green" }, "https://your-app.spcf.localhost"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "You will be prompted to authorize with your password."), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Press ", /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Enter"), " to authorize."));
184854
+ }
184799
184855
  if (caInstallPhase === "installing") {
184800
- 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, " "));
184856
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Awaiting authorization\u2026"));
184801
184857
  }
184802
184858
  }
184803
184859
  if (phase === "done") {
@@ -184917,7 +184973,7 @@ var BETA_REGISTRY = [
184917
184973
  ];
184918
184974
 
184919
184975
  // src/lib/beta/storage.ts
184920
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
184976
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync6, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
184921
184977
  import { join as join7 } from "path";
184922
184978
  var BETAS_FILE = ".specific/betas.json";
184923
184979
  function loadEnabledBetas(projectDir = process.cwd()) {
@@ -184950,7 +185006,7 @@ function saveBetas(enabled, projectDir) {
184950
185006
  mkdirSync6(specificDir, { recursive: true });
184951
185007
  }
184952
185008
  const data = { enabled };
184953
- writeFileSync5(
185009
+ writeFileSync6(
184954
185010
  join7(projectDir, BETAS_FILE),
184955
185011
  JSON.stringify(data, null, 2) + "\n"
184956
185012
  );
@@ -185017,7 +185073,7 @@ function resolveFilesystemDoc(path30) {
185017
185073
  import React3, { useState as useState2, useEffect as useEffect2 } from "react";
185018
185074
  import { render as render3, Text as Text3, Box as Box3 } from "ink";
185019
185075
  import Spinner3 from "ink-spinner";
185020
- import * as fs13 from "fs";
185076
+ import * as fs14 from "fs";
185021
185077
  import * as path9 from "path";
185022
185078
  import { execFile as execFile7 } from "child_process";
185023
185079
 
@@ -185889,32 +185945,32 @@ var ExtractionError = class extends Error {
185889
185945
  };
185890
185946
 
185891
185947
  // src/lib/bin/manager.ts
185892
- import * as fs12 from "fs";
185948
+ import * as fs13 from "fs";
185893
185949
  import * as path8 from "path";
185894
- import * as os7 from "os";
185950
+ import * as os8 from "os";
185895
185951
  import { createReadStream } from "fs";
185896
185952
  import { createTarExtractor, extractTo } from "tar-vern";
185897
185953
  function getLibraryEnv(binary) {
185898
185954
  if (!binary.libraryPath) {
185899
185955
  return {};
185900
185956
  }
185901
- const platform5 = os7.platform();
185902
- if (platform5 === "darwin") {
185957
+ const platform6 = os8.platform();
185958
+ if (platform6 === "darwin") {
185903
185959
  return { DYLD_LIBRARY_PATH: binary.libraryPath };
185904
- } else if (platform5 === "linux") {
185960
+ } else if (platform6 === "linux") {
185905
185961
  return { LD_LIBRARY_PATH: binary.libraryPath };
185906
185962
  }
185907
185963
  return {};
185908
185964
  }
185909
185965
  function getBinBaseDir() {
185910
- return path8.join(os7.homedir(), ".specific", "bin");
185966
+ return path8.join(os8.homedir(), ".specific", "bin");
185911
185967
  }
185912
185968
  function getPlatformInfo() {
185913
- const platform5 = os7.platform();
185914
- const arch3 = os7.arch();
185915
- if (platform5 !== "darwin" && platform5 !== "linux") {
185969
+ const platform6 = os8.platform();
185970
+ const arch3 = os8.arch();
185971
+ if (platform6 !== "darwin" && platform6 !== "linux") {
185916
185972
  throw new Error(
185917
- `Unsupported platform: ${platform5}. Only macOS and Linux are supported.`
185973
+ `Unsupported platform: ${platform6}. Only macOS and Linux are supported.`
185918
185974
  );
185919
185975
  }
185920
185976
  const archStr = arch3;
@@ -185928,7 +185984,7 @@ function getPlatformInfo() {
185928
185984
  `Unsupported architecture: ${arch3}. Only x64 and arm64 are supported.`
185929
185985
  );
185930
185986
  }
185931
- return { platform: platform5, arch: mappedArch };
185987
+ return { platform: platform6, arch: mappedArch };
185932
185988
  }
185933
185989
  function getBinaryDir(definition, version, platformInfo) {
185934
185990
  return path8.join(
@@ -185942,7 +185998,7 @@ function isBinaryInstalled(definition, version, platformInfo) {
185942
185998
  const binDir = getBinaryDir(definition, version, platformInfo);
185943
185999
  for (const execPath of definition.executables) {
185944
186000
  const fullPath = path8.join(binDir, execPath);
185945
- if (!fs12.existsSync(fullPath)) {
186001
+ if (!fs13.existsSync(fullPath)) {
185946
186002
  return false;
185947
186003
  }
185948
186004
  }
@@ -185971,11 +186027,11 @@ async function downloadFile(url, destPath, onProgress) {
185971
186027
  );
185972
186028
  let bytesDownloaded = 0;
185973
186029
  const parentDir = path8.dirname(destPath);
185974
- if (!fs12.existsSync(parentDir)) {
185975
- fs12.mkdirSync(parentDir, { recursive: true });
186030
+ if (!fs13.existsSync(parentDir)) {
186031
+ fs13.mkdirSync(parentDir, { recursive: true });
185976
186032
  }
185977
186033
  const partPath = destPath + ".part";
185978
- const fileStream = fs12.createWriteStream(partPath);
186034
+ const fileStream = fs13.createWriteStream(partPath);
185979
186035
  try {
185980
186036
  const reader = response.body.getReader();
185981
186037
  while (true) {
@@ -185998,12 +186054,12 @@ async function downloadFile(url, destPath, onProgress) {
185998
186054
  else resolve10();
185999
186055
  });
186000
186056
  });
186001
- fs12.renameSync(partPath, destPath);
186057
+ fs13.renameSync(partPath, destPath);
186002
186058
  } catch (error) {
186003
186059
  try {
186004
186060
  fileStream.close();
186005
- if (fs12.existsSync(partPath)) {
186006
- fs12.unlinkSync(partPath);
186061
+ if (fs13.existsSync(partPath)) {
186062
+ fs13.unlinkSync(partPath);
186007
186063
  }
186008
186064
  } catch {
186009
186065
  }
@@ -186012,8 +186068,8 @@ async function downloadFile(url, destPath, onProgress) {
186012
186068
  }
186013
186069
  async function extractTarball(archivePath, destDir, definition, onProgress) {
186014
186070
  onProgress?.({ phase: "extracting" });
186015
- if (!fs12.existsSync(destDir)) {
186016
- fs12.mkdirSync(destDir, { recursive: true });
186071
+ if (!fs13.existsSync(destDir)) {
186072
+ fs13.mkdirSync(destDir, { recursive: true });
186017
186073
  }
186018
186074
  try {
186019
186075
  const fileStream = createReadStream(archivePath);
@@ -186022,8 +186078,8 @@ async function extractTarball(archivePath, destDir, definition, onProgress) {
186022
186078
  onProgress?.({ phase: "finalizing" });
186023
186079
  for (const execPath of definition.executables) {
186024
186080
  const fullPath = path8.join(destDir, execPath);
186025
- if (fs12.existsSync(fullPath)) {
186026
- fs12.chmodSync(fullPath, 493);
186081
+ if (fs13.existsSync(fullPath)) {
186082
+ fs13.chmodSync(fullPath, 493);
186027
186083
  }
186028
186084
  }
186029
186085
  } catch (error) {
@@ -186047,12 +186103,12 @@ async function ensureBinary(definition, version, onProgress) {
186047
186103
  `Binary type definitions must have exactly one executable, got ${definition.executables.length}`
186048
186104
  );
186049
186105
  }
186050
- if (!fs12.existsSync(binDir)) {
186051
- fs12.mkdirSync(binDir, { recursive: true });
186106
+ if (!fs13.existsSync(binDir)) {
186107
+ fs13.mkdirSync(binDir, { recursive: true });
186052
186108
  }
186053
186109
  const execPath = path8.join(binDir, definition.executables[0]);
186054
186110
  await downloadFile(url, execPath, onProgress);
186055
- fs12.chmodSync(execPath, 493);
186111
+ fs13.chmodSync(execPath, 493);
186056
186112
  onProgress?.({ phase: "finalizing" });
186057
186113
  } else {
186058
186114
  const downloadDir = path8.join(getBinBaseDir(), "downloads");
@@ -186063,8 +186119,8 @@ async function ensureBinary(definition, version, onProgress) {
186063
186119
  await extractTarball(archivePath, binDir, definition, onProgress);
186064
186120
  } finally {
186065
186121
  try {
186066
- if (fs12.existsSync(archivePath)) {
186067
- fs12.unlinkSync(archivePath);
186122
+ if (fs13.existsSync(archivePath)) {
186123
+ fs13.unlinkSync(archivePath);
186068
186124
  }
186069
186125
  } catch {
186070
186126
  }
@@ -186240,20 +186296,20 @@ function CheckUI() {
186240
186296
  useEffect2(() => {
186241
186297
  async function load() {
186242
186298
  const configPath = path9.join(process.cwd(), "specific.hcl");
186243
- if (!fs13.existsSync(configPath)) {
186299
+ if (!fs14.existsSync(configPath)) {
186244
186300
  setState({
186245
186301
  status: "error",
186246
186302
  error: "No specific.hcl found in current directory"
186247
186303
  });
186248
186304
  return;
186249
186305
  }
186250
- const hcl = fs13.readFileSync(configPath, "utf-8");
186306
+ const hcl = fs14.readFileSync(configPath, "utf-8");
186251
186307
  try {
186252
186308
  const config2 = await parseConfig(hcl);
186253
186309
  for (const build of config2.builds) {
186254
186310
  if (build.dockerfile) {
186255
186311
  const dockerfilePath = path9.resolve(process.cwd(), build.dockerfile);
186256
- if (!fs13.existsSync(dockerfilePath)) {
186312
+ if (!fs14.existsSync(dockerfilePath)) {
186257
186313
  setState({
186258
186314
  status: "error",
186259
186315
  error: `Build "${build.name}": Dockerfile not found at "${build.dockerfile}" (resolved to ${dockerfilePath})`
@@ -186269,7 +186325,7 @@ function CheckUI() {
186269
186325
  process.cwd(),
186270
186326
  pg.reshape.migrations_dir ?? "migrations"
186271
186327
  );
186272
- if (!fs13.existsSync(migrationsDir)) {
186328
+ if (!fs14.existsSync(migrationsDir)) {
186273
186329
  reshapeChecks2.push({
186274
186330
  databaseName: pg.name,
186275
186331
  migrationsDir: pg.reshape.migrations_dir ?? "migrations",
@@ -186320,9 +186376,9 @@ function checkCommand() {
186320
186376
 
186321
186377
  // src/commands/dev.tsx
186322
186378
  import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
186323
- import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
186379
+ import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static, useInput as useInput4 } from "ink";
186324
186380
  import Spinner4 from "ink-spinner";
186325
- import * as fs23 from "fs";
186381
+ import * as fs24 from "fs";
186326
186382
  import * as path20 from "path";
186327
186383
 
186328
186384
  // node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
@@ -188077,7 +188133,7 @@ var PortAllocator = class {
188077
188133
  };
188078
188134
 
188079
188135
  // src/lib/dev/stable-port-allocator.ts
188080
- import * as fs14 from "fs";
188136
+ import * as fs15 from "fs";
188081
188137
  import * as path10 from "path";
188082
188138
  var PORT_RANGE_START2 = 4e4;
188083
188139
  var PORT_RANGE_END2 = 49999;
@@ -188092,11 +188148,11 @@ var StablePortAllocator = class {
188092
188148
  this.loadPorts();
188093
188149
  }
188094
188150
  loadPorts() {
188095
- if (!fs14.existsSync(this.portsFilePath)) {
188151
+ if (!fs15.existsSync(this.portsFilePath)) {
188096
188152
  return;
188097
188153
  }
188098
188154
  try {
188099
- const content = fs14.readFileSync(this.portsFilePath, "utf-8");
188155
+ const content = fs15.readFileSync(this.portsFilePath, "utf-8");
188100
188156
  const data = JSON.parse(content);
188101
188157
  if (data.version === 1 && data.ports) {
188102
188158
  this.savedPorts = data.ports;
@@ -188109,14 +188165,14 @@ var StablePortAllocator = class {
188109
188165
  }
188110
188166
  }
188111
188167
  savePorts() {
188112
- if (!fs14.existsSync(this.portsDir)) {
188113
- fs14.mkdirSync(this.portsDir, { recursive: true });
188168
+ if (!fs15.existsSync(this.portsDir)) {
188169
+ fs15.mkdirSync(this.portsDir, { recursive: true });
188114
188170
  }
188115
188171
  const data = {
188116
188172
  version: 1,
188117
188173
  ports: this.savedPorts
188118
188174
  };
188119
- fs14.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
188175
+ fs15.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
188120
188176
  }
188121
188177
  allocateRandom() {
188122
188178
  const rangeSize = PORT_RANGE_END2 - PORT_RANGE_START2 + 1;
@@ -188143,7 +188199,7 @@ var StablePortAllocator = class {
188143
188199
  };
188144
188200
 
188145
188201
  // src/lib/dev/database-manager.ts
188146
- import * as fs15 from "fs";
188202
+ import * as fs16 from "fs";
188147
188203
  import * as path11 from "path";
188148
188204
  import * as net from "net";
188149
188205
  import { spawn } from "child_process";
@@ -188155,9 +188211,9 @@ async function startPostgres(pg, port, dataDir, onProgress) {
188155
188211
  const password = "postgres";
188156
188212
  const libraryEnv = getLibraryEnv(binary);
188157
188213
  const env2 = { ...process.env, ...libraryEnv };
188158
- const dataExists = fs15.existsSync(dbDataPath);
188214
+ const dataExists = fs16.existsSync(dbDataPath);
188159
188215
  if (!dataExists) {
188160
- fs15.mkdirSync(dbDataPath, { recursive: true });
188216
+ fs16.mkdirSync(dbDataPath, { recursive: true });
188161
188217
  await runCommand(
188162
188218
  binary.executables["initdb"],
188163
188219
  ["-D", dbDataPath, "-U", user, "--auth=trust", "--no-locale", "-E", "UTF8"],
@@ -188234,8 +188290,8 @@ async function startRedis(redis, port, onProgress) {
188234
188290
  async function startStorage(storage, port, dataDir) {
188235
188291
  const S3rver = (await import("s3rver")).default;
188236
188292
  const storageDataPath = path11.join(process.cwd(), dataDir, storage.name);
188237
- if (!fs15.existsSync(storageDataPath)) {
188238
- fs15.mkdirSync(storageDataPath, { recursive: true });
188293
+ if (!fs16.existsSync(storageDataPath)) {
188294
+ fs16.mkdirSync(storageDataPath, { recursive: true });
188239
188295
  }
188240
188296
  const host = "127.0.0.1";
188241
188297
  const accessKey = "S3RVER";
@@ -188878,7 +188934,7 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
188878
188934
  }
188879
188935
 
188880
188936
  // src/lib/dev/instance-state.ts
188881
- import * as fs16 from "fs";
188937
+ import * as fs17 from "fs";
188882
188938
  import * as path12 from "path";
188883
188939
  var InstanceStateManager = class {
188884
188940
  stateDir;
@@ -188896,8 +188952,8 @@ var InstanceStateManager = class {
188896
188952
  return this.key;
188897
188953
  }
188898
188954
  ensureStateDir() {
188899
- if (!fs16.existsSync(this.stateDir)) {
188900
- fs16.mkdirSync(this.stateDir, { recursive: true });
188955
+ if (!fs17.existsSync(this.stateDir)) {
188956
+ fs17.mkdirSync(this.stateDir, { recursive: true });
188901
188957
  }
188902
188958
  }
188903
188959
  isProcessRunning(pid) {
@@ -188914,15 +188970,15 @@ var InstanceStateManager = class {
188914
188970
  const startTime = Date.now();
188915
188971
  while (Date.now() - startTime < timeoutMs) {
188916
188972
  try {
188917
- const fd = fs16.openSync(
188973
+ const fd = fs17.openSync(
188918
188974
  this.lockPath,
188919
- fs16.constants.O_CREAT | fs16.constants.O_EXCL | fs16.constants.O_WRONLY
188975
+ fs17.constants.O_CREAT | fs17.constants.O_EXCL | fs17.constants.O_WRONLY
188920
188976
  );
188921
- fs16.writeSync(fd, String(process.pid));
188922
- fs16.closeSync(fd);
188977
+ fs17.writeSync(fd, String(process.pid));
188978
+ fs17.closeSync(fd);
188923
188979
  return () => {
188924
188980
  try {
188925
- fs16.unlinkSync(this.lockPath);
188981
+ fs17.unlinkSync(this.lockPath);
188926
188982
  } catch {
188927
188983
  }
188928
188984
  };
@@ -188931,16 +188987,16 @@ var InstanceStateManager = class {
188931
188987
  if (err.code === "EEXIST") {
188932
188988
  try {
188933
188989
  const lockPid = parseInt(
188934
- fs16.readFileSync(this.lockPath, "utf-8").trim(),
188990
+ fs17.readFileSync(this.lockPath, "utf-8").trim(),
188935
188991
  10
188936
188992
  );
188937
188993
  if (!this.isProcessRunning(lockPid)) {
188938
- fs16.unlinkSync(this.lockPath);
188994
+ fs17.unlinkSync(this.lockPath);
188939
188995
  continue;
188940
188996
  }
188941
188997
  } catch {
188942
188998
  try {
188943
- fs16.unlinkSync(this.lockPath);
188999
+ fs17.unlinkSync(this.lockPath);
188944
189000
  } catch {
188945
189001
  }
188946
189002
  continue;
@@ -188954,12 +189010,12 @@ var InstanceStateManager = class {
188954
189010
  throw new Error("Failed to acquire state lock (timeout)");
188955
189011
  }
188956
189012
  async getExistingInstances() {
188957
- if (!fs16.existsSync(this.statePath)) {
189013
+ if (!fs17.existsSync(this.statePath)) {
188958
189014
  return null;
188959
189015
  }
188960
189016
  const releaseLock = await this.acquireLock();
188961
189017
  try {
188962
- const content = fs16.readFileSync(this.statePath, "utf-8");
189018
+ const content = fs17.readFileSync(this.statePath, "utf-8");
188963
189019
  const state = JSON.parse(content);
188964
189020
  if (!this.isProcessRunning(state.owner.pid)) {
188965
189021
  return null;
@@ -188972,21 +189028,21 @@ var InstanceStateManager = class {
188972
189028
  }
188973
189029
  }
188974
189030
  async cleanStaleState() {
188975
- if (!fs16.existsSync(this.statePath)) {
189031
+ if (!fs17.existsSync(this.statePath)) {
188976
189032
  return false;
188977
189033
  }
188978
189034
  const releaseLock = await this.acquireLock();
188979
189035
  try {
188980
- const content = fs16.readFileSync(this.statePath, "utf-8");
189036
+ const content = fs17.readFileSync(this.statePath, "utf-8");
188981
189037
  const state = JSON.parse(content);
188982
189038
  if (!this.isProcessRunning(state.owner.pid)) {
188983
- fs16.unlinkSync(this.statePath);
189039
+ fs17.unlinkSync(this.statePath);
188984
189040
  return true;
188985
189041
  }
188986
189042
  return false;
188987
189043
  } catch {
188988
189044
  try {
188989
- fs16.unlinkSync(this.statePath);
189045
+ fs17.unlinkSync(this.statePath);
188990
189046
  return true;
188991
189047
  } catch {
188992
189048
  }
@@ -188998,8 +189054,8 @@ var InstanceStateManager = class {
188998
189054
  async claimOwnership(command) {
188999
189055
  const releaseLock = await this.acquireLock();
189000
189056
  try {
189001
- if (fs16.existsSync(this.statePath)) {
189002
- const content = fs16.readFileSync(this.statePath, "utf-8");
189057
+ if (fs17.existsSync(this.statePath)) {
189058
+ const content = fs17.readFileSync(this.statePath, "utf-8");
189003
189059
  const state2 = JSON.parse(content);
189004
189060
  if (this.isProcessRunning(state2.owner.pid)) {
189005
189061
  throw new Error(`Instances already owned by PID ${state2.owner.pid}`);
@@ -189068,8 +189124,8 @@ var InstanceStateManager = class {
189068
189124
  }
189069
189125
  const releaseLock = await this.acquireLock();
189070
189126
  try {
189071
- if (fs16.existsSync(this.statePath)) {
189072
- fs16.unlinkSync(this.statePath);
189127
+ if (fs17.existsSync(this.statePath)) {
189128
+ fs17.unlinkSync(this.statePath);
189073
189129
  }
189074
189130
  this.ownsInstances = false;
189075
189131
  } finally {
@@ -189077,21 +189133,21 @@ var InstanceStateManager = class {
189077
189133
  }
189078
189134
  }
189079
189135
  readState() {
189080
- const content = fs16.readFileSync(this.statePath, "utf-8");
189136
+ const content = fs17.readFileSync(this.statePath, "utf-8");
189081
189137
  return JSON.parse(content);
189082
189138
  }
189083
189139
  writeStateAtomic(state) {
189084
189140
  this.ensureStateDir();
189085
189141
  const tmpPath = this.statePath + ".tmp";
189086
- fs16.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
189087
- fs16.renameSync(tmpPath, this.statePath);
189142
+ fs17.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
189143
+ fs17.renameSync(tmpPath, this.statePath);
189088
189144
  }
189089
189145
  };
189090
189146
 
189091
189147
  // src/lib/dev/http-proxy.ts
189092
189148
  import * as http from "http";
189093
189149
  import * as https from "https";
189094
- import * as fs17 from "fs";
189150
+ import * as fs18 from "fs";
189095
189151
  import * as path13 from "path";
189096
189152
  import { fileURLToPath as fileURLToPath3 } from "url";
189097
189153
  import httpProxy from "http-proxy";
@@ -189100,8 +189156,8 @@ var adminDir = path13.join(__dirname3, "admin");
189100
189156
  var _embeddedAdmin = null;
189101
189157
  var HTTP_PORT = 80;
189102
189158
  var HTTPS_PORT = 443;
189103
- var DOMAIN_SUFFIX = ".local.spcf.app";
189104
- var ADMIN_DOMAIN = "local.spcf.app";
189159
+ var DOMAIN_SUFFIX = ".spcf.localhost";
189160
+ var ADMIN_DOMAIN = "spcf.localhost";
189105
189161
  var DRIZZLE_GATEWAY_PREFIX = "__drizzle_gateway";
189106
189162
  var TEMPORAL_UI_PREFIX = "__temporal";
189107
189163
  var MIME_TYPES = {
@@ -189425,9 +189481,9 @@ function sendNotFound(res, requestedService, serviceMap) {
189425
189481
  const serviceList = Array.from(serviceMap.keys()).map((key) => {
189426
189482
  const parts = key.split(".");
189427
189483
  if (parts.length === 1) {
189428
- return `<li>${parts[0]}.local.spcf.app</li>`;
189484
+ return `<li>${parts[0]}.spcf.localhost</li>`;
189429
189485
  } else {
189430
- return `<li>${key}.local.spcf.app</li>`;
189486
+ return `<li>${key}.spcf.localhost</li>`;
189431
189487
  }
189432
189488
  }).join("\n");
189433
189489
  const message = requestedService ? `No service named "${requestedService}" is running.` : "Invalid host header.";
@@ -189499,10 +189555,10 @@ function serveFilesystemFile(res, pathname) {
189499
189555
  res.end("<h1>Forbidden</h1>");
189500
189556
  return;
189501
189557
  }
189502
- if (fs17.existsSync(resolvedPath)) {
189503
- if (fs17.statSync(resolvedPath).isDirectory()) {
189558
+ if (fs18.existsSync(resolvedPath)) {
189559
+ if (fs18.statSync(resolvedPath).isDirectory()) {
189504
189560
  const indexPath2 = path13.join(resolvedPath, "index.html");
189505
- if (fs17.existsSync(indexPath2)) {
189561
+ if (fs18.existsSync(indexPath2)) {
189506
189562
  return serveFile(res, indexPath2);
189507
189563
  }
189508
189564
  } else {
@@ -189510,15 +189566,15 @@ function serveFilesystemFile(res, pathname) {
189510
189566
  }
189511
189567
  }
189512
189568
  const htmlPath = resolvedPath + ".html";
189513
- if (fs17.existsSync(htmlPath)) {
189569
+ if (fs18.existsSync(htmlPath)) {
189514
189570
  return serveFile(res, htmlPath);
189515
189571
  }
189516
189572
  const indexPath = path13.join(resolvedPath, "index.html");
189517
- if (fs17.existsSync(indexPath)) {
189573
+ if (fs18.existsSync(indexPath)) {
189518
189574
  return serveFile(res, indexPath);
189519
189575
  }
189520
189576
  const notFoundPath = path13.join(adminDir, "404.html");
189521
- if (fs17.existsSync(notFoundPath)) {
189577
+ if (fs18.existsSync(notFoundPath)) {
189522
189578
  return serveFileContent(res, notFoundPath, "text/html", 404);
189523
189579
  }
189524
189580
  res.writeHead(404, { "Content-Type": "text/html" });
@@ -189531,7 +189587,7 @@ function serveFile(res, filePath) {
189531
189587
  }
189532
189588
  function serveFileContent(res, filePath, contentType, statusCode = 200) {
189533
189589
  try {
189534
- const content = fs17.readFileSync(filePath);
189590
+ const content = fs18.readFileSync(filePath);
189535
189591
  res.writeHead(statusCode, { "Content-Type": contentType });
189536
189592
  res.end(content);
189537
189593
  } catch (err) {
@@ -189906,7 +189962,7 @@ async function startMailServer(mail, smtpPort, apiPort) {
189906
189962
 
189907
189963
  // src/lib/dev/drizzle-gateway-manager.ts
189908
189964
  import * as net3 from "net";
189909
- import * as fs18 from "fs";
189965
+ import * as fs19 from "fs";
189910
189966
  import * as path15 from "path";
189911
189967
  import { spawn as spawn4 } from "child_process";
189912
189968
  import { randomUUID as randomUUID2 } from "crypto";
@@ -189940,12 +189996,12 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
189940
189996
  );
189941
189997
  const host = "127.0.0.1";
189942
189998
  const drizzleConfigDir = path15.join(configDir, "drizzle-gateway");
189943
- if (!fs18.existsSync(drizzleConfigDir)) {
189944
- fs18.mkdirSync(drizzleConfigDir, { recursive: true });
189999
+ if (!fs19.existsSync(drizzleConfigDir)) {
190000
+ fs19.mkdirSync(drizzleConfigDir, { recursive: true });
189945
190001
  }
189946
190002
  const storeJson = generateStoreJson(postgresInstances);
189947
190003
  const storeJsonPath = path15.join(drizzleConfigDir, "store.json");
189948
- fs18.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
190004
+ fs19.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
189949
190005
  writeLog("drizzle-gateway", `Starting Drizzle Gateway`);
189950
190006
  writeLog("drizzle-gateway", `STORE_PATH: ${drizzleConfigDir}`);
189951
190007
  writeLog("drizzle-gateway", `PORT: ${port}`);
@@ -190047,16 +190103,16 @@ function detectSyncDatabases(config) {
190047
190103
  }
190048
190104
 
190049
190105
  // src/lib/dev/reshape-watcher.ts
190050
- import * as fs19 from "fs";
190106
+ import * as fs20 from "fs";
190051
190107
  import * as path16 from "path";
190052
190108
  import { spawnSync } from "child_process";
190053
190109
  function getMigrationFiles(dir, log) {
190054
190110
  log(`Scanning migrations directory: ${dir}`);
190055
- if (!fs19.existsSync(dir)) {
190111
+ if (!fs20.existsSync(dir)) {
190056
190112
  log(`Migrations directory does not exist: ${dir}`);
190057
190113
  return [];
190058
190114
  }
190059
- const files = fs19.readdirSync(dir);
190115
+ const files = fs20.readdirSync(dir);
190060
190116
  log(`Found ${files.length} files in directory`);
190061
190117
  const tomlFiles = files.filter((f) => f.endsWith(".toml")).sort((a, b) => a.localeCompare(b));
190062
190118
  log(`Found ${tomlFiles.length} .toml migration files: ${tomlFiles.join(", ") || "(none)"}`);
@@ -190106,7 +190162,7 @@ function runReshape(args, databaseUrl, migrationsDir, reshapeBinaryPath, log) {
190106
190162
  }
190107
190163
  function makeReadOnly(filePath, log) {
190108
190164
  try {
190109
- fs19.chmodSync(filePath, 292);
190165
+ fs20.chmodSync(filePath, 292);
190110
190166
  log(`Set file permissions to read-only (444): ${filePath}`);
190111
190167
  } catch (err) {
190112
190168
  const message = err instanceof Error ? err.message : String(err);
@@ -190192,9 +190248,9 @@ function createReshapeWatcher(options2) {
190192
190248
  };
190193
190249
  const startWatching = () => {
190194
190250
  log(`Starting file watcher for migrations directory...`);
190195
- if (!fs19.existsSync(migrationsDir)) {
190251
+ if (!fs20.existsSync(migrationsDir)) {
190196
190252
  log(`Migrations directory does not exist, creating: ${migrationsDir}`);
190197
- fs19.mkdirSync(migrationsDir, { recursive: true });
190253
+ fs20.mkdirSync(migrationsDir, { recursive: true });
190198
190254
  }
190199
190255
  log(`Watching directory: ${migrationsDir}`);
190200
190256
  watcher = chokidar_default.watch(migrationsDir, {
@@ -190329,7 +190385,7 @@ function createReshapeWatcher(options2) {
190329
190385
  }
190330
190386
 
190331
190387
  // src/lib/dev/temporal-manager.ts
190332
- import * as fs20 from "fs";
190388
+ import * as fs21 from "fs";
190333
190389
  import * as path17 from "path";
190334
190390
  import * as net4 from "net";
190335
190391
  import { spawn as spawn5 } from "child_process";
@@ -190337,8 +190393,8 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
190337
190393
  const binary = await ensureBinary(temporalBinary, void 0, onProgress);
190338
190394
  const dbPath = path17.join(process.cwd(), dataDir, "temporal.db");
190339
190395
  const dbDir = path17.dirname(dbPath);
190340
- if (!fs20.existsSync(dbDir)) {
190341
- fs20.mkdirSync(dbDir, { recursive: true });
190396
+ if (!fs21.existsSync(dbDir)) {
190397
+ fs21.mkdirSync(dbDir, { recursive: true });
190342
190398
  }
190343
190399
  const host = "127.0.0.1";
190344
190400
  const namespaceArgs = temporals.flatMap((t) => ["--namespace", t.name]);
@@ -190667,7 +190723,7 @@ function watchConfigFile(configPath, debounceMs, onChange) {
190667
190723
  }
190668
190724
 
190669
190725
  // src/lib/dev/subdomain-generator.ts
190670
- import * as fs21 from "fs";
190726
+ import * as fs22 from "fs";
190671
190727
  import * as path18 from "path";
190672
190728
  import { generateSlug } from "random-word-slugs";
190673
190729
  var StableSubdomainAllocator = class {
@@ -190680,11 +190736,11 @@ var StableSubdomainAllocator = class {
190680
190736
  this.loadTunnels();
190681
190737
  }
190682
190738
  loadTunnels() {
190683
- if (!fs21.existsSync(this.tunnelsFilePath)) {
190739
+ if (!fs22.existsSync(this.tunnelsFilePath)) {
190684
190740
  return;
190685
190741
  }
190686
190742
  try {
190687
- const content = fs21.readFileSync(this.tunnelsFilePath, "utf-8");
190743
+ const content = fs22.readFileSync(this.tunnelsFilePath, "utf-8");
190688
190744
  const data = JSON.parse(content);
190689
190745
  if (data.version === 1 && data.baseSlug) {
190690
190746
  this.baseSlug = data.baseSlug;
@@ -190694,14 +190750,14 @@ var StableSubdomainAllocator = class {
190694
190750
  }
190695
190751
  }
190696
190752
  saveTunnels() {
190697
- if (!fs21.existsSync(this.tunnelsDir)) {
190698
- fs21.mkdirSync(this.tunnelsDir, { recursive: true });
190753
+ if (!fs22.existsSync(this.tunnelsDir)) {
190754
+ fs22.mkdirSync(this.tunnelsDir, { recursive: true });
190699
190755
  }
190700
190756
  const data = {
190701
190757
  version: 1,
190702
190758
  baseSlug: this.baseSlug
190703
190759
  };
190704
- fs21.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
190760
+ fs22.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
190705
190761
  }
190706
190762
  generateBaseSlug() {
190707
190763
  return generateSlug(2, {
@@ -190857,9 +190913,9 @@ async function startTunnel(serviceName, endpointName, port, subdomain, callbacks
190857
190913
  }
190858
190914
 
190859
190915
  // src/lib/dev/proxy-registry.ts
190860
- import * as fs22 from "fs";
190916
+ import * as fs23 from "fs";
190861
190917
  import * as path19 from "path";
190862
- import * as os8 from "os";
190918
+ import * as os9 from "os";
190863
190919
  import * as net6 from "net";
190864
190920
  var ProxyRegistryManager = class {
190865
190921
  proxyDir;
@@ -190869,14 +190925,14 @@ var ProxyRegistryManager = class {
190869
190925
  isOwner = false;
190870
190926
  registryWatcher = null;
190871
190927
  constructor() {
190872
- this.proxyDir = path19.join(os8.homedir(), ".specific", "proxy");
190928
+ this.proxyDir = path19.join(os9.homedir(), ".specific", "proxy");
190873
190929
  this.ownerPath = path19.join(this.proxyDir, "owner.json");
190874
190930
  this.registryPath = path19.join(this.proxyDir, "registry.json");
190875
190931
  this.lockPath = path19.join(this.proxyDir, "registry.lock");
190876
190932
  }
190877
190933
  ensureProxyDir() {
190878
- if (!fs22.existsSync(this.proxyDir)) {
190879
- fs22.mkdirSync(this.proxyDir, { recursive: true });
190934
+ if (!fs23.existsSync(this.proxyDir)) {
190935
+ fs23.mkdirSync(this.proxyDir, { recursive: true });
190880
190936
  }
190881
190937
  }
190882
190938
  isProcessRunning(pid) {
@@ -190933,15 +190989,15 @@ var ProxyRegistryManager = class {
190933
190989
  const startTime = Date.now();
190934
190990
  while (Date.now() - startTime < timeoutMs) {
190935
190991
  try {
190936
- const fd = fs22.openSync(
190992
+ const fd = fs23.openSync(
190937
190993
  this.lockPath,
190938
- fs22.constants.O_CREAT | fs22.constants.O_EXCL | fs22.constants.O_WRONLY
190994
+ fs23.constants.O_CREAT | fs23.constants.O_EXCL | fs23.constants.O_WRONLY
190939
190995
  );
190940
- fs22.writeSync(fd, String(process.pid));
190941
- fs22.closeSync(fd);
190996
+ fs23.writeSync(fd, String(process.pid));
190997
+ fs23.closeSync(fd);
190942
190998
  return () => {
190943
190999
  try {
190944
- fs22.unlinkSync(this.lockPath);
191000
+ fs23.unlinkSync(this.lockPath);
190945
191001
  } catch {
190946
191002
  }
190947
191003
  };
@@ -190950,16 +191006,16 @@ var ProxyRegistryManager = class {
190950
191006
  if (err.code === "EEXIST") {
190951
191007
  try {
190952
191008
  const lockPid = parseInt(
190953
- fs22.readFileSync(this.lockPath, "utf-8").trim(),
191009
+ fs23.readFileSync(this.lockPath, "utf-8").trim(),
190954
191010
  10
190955
191011
  );
190956
191012
  if (!this.isProcessRunning(lockPid)) {
190957
- fs22.unlinkSync(this.lockPath);
191013
+ fs23.unlinkSync(this.lockPath);
190958
191014
  continue;
190959
191015
  }
190960
191016
  } catch {
190961
191017
  try {
190962
- fs22.unlinkSync(this.lockPath);
191018
+ fs23.unlinkSync(this.lockPath);
190963
191019
  } catch {
190964
191020
  }
190965
191021
  continue;
@@ -190979,8 +191035,8 @@ var ProxyRegistryManager = class {
190979
191035
  async claimProxyOwnership(key) {
190980
191036
  const releaseLock = await this.acquireLock();
190981
191037
  try {
190982
- if (fs22.existsSync(this.ownerPath)) {
190983
- const content = fs22.readFileSync(this.ownerPath, "utf-8");
191038
+ if (fs23.existsSync(this.ownerPath)) {
191039
+ const content = fs23.readFileSync(this.ownerPath, "utf-8");
190984
191040
  const ownerFile2 = JSON.parse(content);
190985
191041
  if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
190986
191042
  return false;
@@ -191010,11 +191066,11 @@ var ProxyRegistryManager = class {
191010
191066
  }
191011
191067
  const releaseLock = await this.acquireLock();
191012
191068
  try {
191013
- if (fs22.existsSync(this.ownerPath)) {
191014
- const content = fs22.readFileSync(this.ownerPath, "utf-8");
191069
+ if (fs23.existsSync(this.ownerPath)) {
191070
+ const content = fs23.readFileSync(this.ownerPath, "utf-8");
191015
191071
  const ownerFile = JSON.parse(content);
191016
191072
  if (ownerFile.owner.pid === process.pid) {
191017
- fs22.unlinkSync(this.ownerPath);
191073
+ fs23.unlinkSync(this.ownerPath);
191018
191074
  }
191019
191075
  }
191020
191076
  this.isOwner = false;
@@ -191026,12 +191082,12 @@ var ProxyRegistryManager = class {
191026
191082
  * Get the current proxy owner.
191027
191083
  */
191028
191084
  async getProxyOwner() {
191029
- if (!fs22.existsSync(this.ownerPath)) {
191085
+ if (!fs23.existsSync(this.ownerPath)) {
191030
191086
  return null;
191031
191087
  }
191032
191088
  const releaseLock = await this.acquireLock();
191033
191089
  try {
191034
- const content = fs22.readFileSync(this.ownerPath, "utf-8");
191090
+ const content = fs23.readFileSync(this.ownerPath, "utf-8");
191035
191091
  const ownerFile = JSON.parse(content);
191036
191092
  if (!await this.isProxyOwnerHealthy(ownerFile.owner.pid)) {
191037
191093
  return null;
@@ -191128,7 +191184,7 @@ var ProxyRegistryManager = class {
191128
191184
  */
191129
191185
  watchRegistry(onChange) {
191130
191186
  this.ensureProxyDir();
191131
- if (!fs22.existsSync(this.registryPath)) {
191187
+ if (!fs23.existsSync(this.registryPath)) {
191132
191188
  const emptyRegistry = {
191133
191189
  version: 1,
191134
191190
  keys: {},
@@ -191171,13 +191227,13 @@ var ProxyRegistryManager = class {
191171
191227
  async attemptElection(key) {
191172
191228
  const releaseLock = await this.acquireLock();
191173
191229
  try {
191174
- if (fs22.existsSync(this.ownerPath)) {
191175
- const content = fs22.readFileSync(this.ownerPath, "utf-8");
191230
+ if (fs23.existsSync(this.ownerPath)) {
191231
+ const content = fs23.readFileSync(this.ownerPath, "utf-8");
191176
191232
  const ownerFile2 = JSON.parse(content);
191177
191233
  if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
191178
191234
  return false;
191179
191235
  }
191180
- fs22.unlinkSync(this.ownerPath);
191236
+ fs23.unlinkSync(this.ownerPath);
191181
191237
  }
191182
191238
  const ownerFile = {
191183
191239
  version: 1,
@@ -191195,7 +191251,7 @@ var ProxyRegistryManager = class {
191195
191251
  }
191196
191252
  }
191197
191253
  readRegistry() {
191198
- if (!fs22.existsSync(this.registryPath)) {
191254
+ if (!fs23.existsSync(this.registryPath)) {
191199
191255
  return {
191200
191256
  version: 1,
191201
191257
  keys: {},
@@ -191203,7 +191259,7 @@ var ProxyRegistryManager = class {
191203
191259
  };
191204
191260
  }
191205
191261
  try {
191206
- const content = fs22.readFileSync(this.registryPath, "utf-8");
191262
+ const content = fs23.readFileSync(this.registryPath, "utf-8");
191207
191263
  return JSON.parse(content);
191208
191264
  } catch {
191209
191265
  return {
@@ -191216,8 +191272,8 @@ var ProxyRegistryManager = class {
191216
191272
  writeFileAtomic(filePath, data) {
191217
191273
  this.ensureProxyDir();
191218
191274
  const tmpPath = filePath + ".tmp";
191219
- fs22.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
191220
- fs22.renameSync(tmpPath, filePath);
191275
+ fs23.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
191276
+ fs23.renameSync(tmpPath, filePath);
191221
191277
  }
191222
191278
  };
191223
191279
 
@@ -191326,7 +191382,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
191326
191382
  const setupDone = tunnelEnabled || !systemSetupNeeded();
191327
191383
  return {
191328
191384
  status: setupDone ? "loading" : "installing-ca",
191329
- ...setupDone ? {} : { caInstallPhase: "installing" },
191385
+ ...setupDone ? {} : { caInstallPhase: "prompt" },
191330
191386
  resources: /* @__PURE__ */ new Map(),
191331
191387
  resourceStatus: /* @__PURE__ */ new Map(),
191332
191388
  services: [],
@@ -191342,6 +191398,11 @@ function DevUI({ instanceKey, tunnelEnabled }) {
191342
191398
  installSystemConfig();
191343
191399
  }
191344
191400
  }, [state.status, state.caInstallPhase]);
191401
+ useInput4((_input, key) => {
191402
+ if (state.status === "installing-ca" && state.caInstallPhase === "prompt" && key.return) {
191403
+ setState((s) => ({ ...s, caInstallPhase: "installing" }));
191404
+ }
191405
+ });
191345
191406
  async function installSystemConfig() {
191346
191407
  try {
191347
191408
  performSystemSetup();
@@ -191535,7 +191596,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
191535
191596
  const configPath = path20.join(process.cwd(), "specific.hcl");
191536
191597
  const watcher = watchConfigFile(configPath, 1e3, () => {
191537
191598
  try {
191538
- const hcl = fs23.readFileSync(configPath, "utf-8");
191599
+ const hcl = fs24.readFileSync(configPath, "utf-8");
191539
191600
  parseConfig(hcl).then(() => {
191540
191601
  triggerReload();
191541
191602
  }).catch((err) => {
@@ -191661,7 +191722,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
191661
191722
  return;
191662
191723
  }
191663
191724
  const configPath = path20.join(process.cwd(), "specific.hcl");
191664
- if (!fs23.existsSync(configPath)) {
191725
+ if (!fs24.existsSync(configPath)) {
191665
191726
  writeLog("system", "Waiting for specific.hcl to appear");
191666
191727
  setState((s) => ({
191667
191728
  ...s,
@@ -191679,7 +191740,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
191679
191740
  return;
191680
191741
  }
191681
191742
  let config2;
191682
- const hcl = fs23.readFileSync(configPath, "utf-8");
191743
+ const hcl = fs24.readFileSync(configPath, "utf-8");
191683
191744
  try {
191684
191745
  config2 = await parseConfig(hcl);
191685
191746
  } catch (err) {
@@ -191975,7 +192036,7 @@ Add them to the config block in specific.local`);
191975
192036
  } else {
191976
192037
  const keySuffix = instanceKey === "default" ? "" : `.${instanceKey}`;
191977
192038
  for (const svc of exposedServices) {
191978
- publicUrls.set(svc.name, `${svc.name}${keySuffix}.local.spcf.app`);
192039
+ publicUrls.set(svc.name, `${svc.name}${keySuffix}.spcf.localhost`);
191979
192040
  }
191980
192041
  }
191981
192042
  const services2 = [];
@@ -192006,7 +192067,7 @@ Add them to the config block in specific.local`);
192006
192067
  if (service.volumes) {
192007
192068
  for (const vol of service.volumes) {
192008
192069
  const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
192009
- fs23.mkdirSync(volumeDir, { recursive: true });
192070
+ fs24.mkdirSync(volumeDir, { recursive: true });
192010
192071
  volumePaths.set(vol.name, volumeDir);
192011
192072
  }
192012
192073
  }
@@ -192062,7 +192123,7 @@ Add them to the config block in specific.local`);
192062
192123
  if (service.volumes) {
192063
192124
  for (const vol of service.volumes) {
192064
192125
  const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
192065
- fs23.mkdirSync(volumeDir, { recursive: true });
192126
+ fs24.mkdirSync(volumeDir, { recursive: true });
192066
192127
  volumePaths.set(vol.name, volumeDir);
192067
192128
  }
192068
192129
  }
@@ -192208,7 +192269,7 @@ Add them to the config block in specific.local`);
192208
192269
  dnsServerRef.current = dnsServer;
192209
192270
  const currentServices = await proxyRegistry.getAllServices();
192210
192271
  const registeredKeys = [...new Set(currentServices.map((s) => s.key))];
192211
- const certificate = generateCertificate("local.spcf.app", registeredKeys);
192272
+ const certificate = generateCertificate("spcf.localhost", registeredKeys);
192212
192273
  const proxy2 = await startHttpProxy(
192213
192274
  exposedServices,
192214
192275
  certificate,
@@ -192229,7 +192290,7 @@ Add them to the config block in specific.local`);
192229
192290
  knownKeys.add(key);
192230
192291
  }
192231
192292
  const allKeys = [...knownKeys];
192232
- const newCertificate = generateCertificate("local.spcf.app", allKeys);
192293
+ const newCertificate = generateCertificate("spcf.localhost", allKeys);
192233
192294
  proxy2.updateCertificate(newCertificate);
192234
192295
  }
192235
192296
  });
@@ -192281,7 +192342,7 @@ Add them to the config block in specific.local`);
192281
192342
  const electionServices = await proxyRegistry.getAllServices();
192282
192343
  const electionKeyRegistrations = await proxyRegistry.getAllKeyRegistrations();
192283
192344
  const electionKeyNames = Object.keys(electionKeyRegistrations);
192284
- const certificate = generateCertificate("local.spcf.app", electionKeyNames);
192345
+ const certificate = generateCertificate("spcf.localhost", electionKeyNames);
192285
192346
  const proxy2 = await startHttpProxy(
192286
192347
  exposedServices,
192287
192348
  certificate,
@@ -192356,8 +192417,11 @@ Add them to the config block in specific.local`);
192356
192417
  };
192357
192418
  }, [reloadTrigger, readyToStart, instanceKey]);
192358
192419
  if (state.status === "installing-ca") {
192420
+ if (state.caInstallPhase === "prompt") {
192421
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "We need to do a one-time setup for all your Specific projects."), /* @__PURE__ */ React6.createElement(Text6, null, "This is so we can run your apps locally with secure URLs:"), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "green" }, "https://your-app.spcf.localhost"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "You will be prompted to authorize with your password."), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Press ", /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Enter"), " to authorize."));
192422
+ }
192359
192423
  if (state.caInstallPhase === "installing") {
192360
- 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, " "));
192424
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Configure development environment"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Awaiting authorization\u2026"));
192361
192425
  }
192362
192426
  if (state.caInstallPhase === "error") {
192363
192427
  return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Setup failed: ", state.caError));
@@ -192479,7 +192543,7 @@ Add them to the config block in specific.local`);
192479
192543
  ...!tunnelEnabled ? [
192480
192544
  {
192481
192545
  key: "admin",
192482
- content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Admin:"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", instanceKey === "default" ? "" : `${instanceKey}.`, "local.spcf.app"))
192546
+ content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Admin:"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", instanceKey === "default" ? "" : `${instanceKey}.`, "spcf.localhost"))
192483
192547
  },
192484
192548
  { key: "admin-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
192485
192549
  ] : [],
@@ -192517,7 +192581,7 @@ Add them to the config block in specific.local`);
192517
192581
  const proxyName = endpoint.name === "default" ? svc.name : `${svc.name}-${endpoint.name}`;
192518
192582
  return {
192519
192583
  key: `svc-${svc.name}-${endpoint.name}`,
192520
- content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, displayName), port ? endpoint.public ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", proxyName, instanceKey === "default" ? "" : `.${instanceKey}`, ".local.spcf.app"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")")) : /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")") : null)
192584
+ content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, displayName), port ? endpoint.public ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", proxyName, instanceKey === "default" ? "" : `.${instanceKey}`, ".spcf.localhost"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")")) : /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")") : null)
192521
192585
  };
192522
192586
  });
192523
192587
  }),
@@ -192630,7 +192694,7 @@ init_open();
192630
192694
  import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
192631
192695
  import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput5 } from "ink";
192632
192696
  import Spinner5 from "ink-spinner";
192633
- import * as fs25 from "fs";
192697
+ import * as fs26 from "fs";
192634
192698
  import * as path23 from "path";
192635
192699
 
192636
192700
  // src/lib/deploy/build-tester.ts
@@ -192815,7 +192879,7 @@ async function testAllBuilds(builds, projectDir) {
192815
192879
 
192816
192880
  // src/lib/tarball/create.ts
192817
192881
  import { execSync as execSync4 } from "child_process";
192818
- import * as fs24 from "fs";
192882
+ import * as fs25 from "fs";
192819
192883
  import * as path22 from "path";
192820
192884
  import { createTarPacker, createEntryItemGenerator } from "tar-vern";
192821
192885
  function isInsideGitRepository(dir) {
@@ -192873,7 +192937,7 @@ var EXCLUDED_DIRS = [
192873
192937
  ];
192874
192938
  async function collectPaths(baseDir, currentDir, exclude) {
192875
192939
  const results = [];
192876
- const entries = await fs24.promises.readdir(currentDir, { withFileTypes: true });
192940
+ const entries = await fs25.promises.readdir(currentDir, { withFileTypes: true });
192877
192941
  for (const entry of entries) {
192878
192942
  const fullPath = path22.join(currentDir, entry.name);
192879
192943
  const relativePath = path22.relative(baseDir, fullPath);
@@ -192892,7 +192956,7 @@ async function collectPaths(baseDir, currentDir, exclude) {
192892
192956
  async function createTarArchive(projectDir) {
192893
192957
  writeLog("tarball", "Creating tarball using tar-vern (non-git project)");
192894
192958
  const configPath = path22.join(projectDir, "specific.hcl");
192895
- if (!fs24.existsSync(configPath)) {
192959
+ if (!fs25.existsSync(configPath)) {
192896
192960
  throw new Error("specific.hcl not found in project directory");
192897
192961
  }
192898
192962
  const relativePaths = await collectPaths(projectDir, projectDir, EXCLUDED_DIRS);
@@ -193825,12 +193889,12 @@ ${errorMsg}`
193825
193889
  }
193826
193890
  async function deployCommand(environment, options2) {
193827
193891
  const configPath = path23.join(process.cwd(), "specific.hcl");
193828
- if (!fs25.existsSync(configPath)) {
193892
+ if (!fs26.existsSync(configPath)) {
193829
193893
  console.error("Error: No specific.hcl found in current directory");
193830
193894
  process.exit(1);
193831
193895
  }
193832
193896
  let config;
193833
- const hcl = fs25.readFileSync(configPath, "utf-8");
193897
+ const hcl = fs26.readFileSync(configPath, "utf-8");
193834
193898
  try {
193835
193899
  config = await parseConfig(hcl);
193836
193900
  } catch (err) {
@@ -193853,7 +193917,7 @@ async function deployCommand(environment, options2) {
193853
193917
 
193854
193918
  // src/commands/exec.tsx
193855
193919
  import { spawn as spawn7 } from "child_process";
193856
- import * as fs26 from "fs";
193920
+ import * as fs27 from "fs";
193857
193921
  import * as path24 from "path";
193858
193922
  async function execCommand(serviceName, command, instanceKey = "default") {
193859
193923
  if (command.length === 0) {
@@ -193883,12 +193947,12 @@ async function execCommand(serviceName, command, instanceKey = "default") {
193883
193947
  }
193884
193948
  };
193885
193949
  const configPath = path24.join(process.cwd(), "specific.hcl");
193886
- if (!fs26.existsSync(configPath)) {
193950
+ if (!fs27.existsSync(configPath)) {
193887
193951
  console.error("Error: No specific.hcl found in current directory");
193888
193952
  process.exit(1);
193889
193953
  }
193890
193954
  let config;
193891
- const hcl = fs26.readFileSync(configPath, "utf-8");
193955
+ const hcl = fs27.readFileSync(configPath, "utf-8");
193892
193956
  try {
193893
193957
  config = await parseConfig(hcl);
193894
193958
  } catch (err) {
@@ -194038,7 +194102,7 @@ async function execCommand(serviceName, command, instanceKey = "default") {
194038
194102
 
194039
194103
  // src/commands/psql.tsx
194040
194104
  import { spawn as spawn8 } from "child_process";
194041
- import * as fs27 from "fs";
194105
+ import * as fs28 from "fs";
194042
194106
  import * as path25 from "path";
194043
194107
  async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []) {
194044
194108
  let startedResources = [];
@@ -194057,12 +194121,12 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
194057
194121
  }
194058
194122
  };
194059
194123
  const configPath = path25.join(process.cwd(), "specific.hcl");
194060
- if (!fs27.existsSync(configPath)) {
194124
+ if (!fs28.existsSync(configPath)) {
194061
194125
  console.error("Error: No specific.hcl found in current directory");
194062
194126
  process.exit(1);
194063
194127
  }
194064
194128
  let config;
194065
- const hcl = fs27.readFileSync(configPath, "utf-8");
194129
+ const hcl = fs28.readFileSync(configPath, "utf-8");
194066
194130
  try {
194067
194131
  config = await parseConfig(hcl);
194068
194132
  } catch (err) {
@@ -194186,7 +194250,7 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
194186
194250
 
194187
194251
  // src/commands/reshape.tsx
194188
194252
  import { spawn as spawn9 } from "child_process";
194189
- import * as fs28 from "fs";
194253
+ import * as fs29 from "fs";
194190
194254
  import * as path26 from "path";
194191
194255
  var VALID_ACTIONS = ["start", "complete", "status", "abort", "check"];
194192
194256
  var MIGRATION_SUBCOMMANDS = ["start", "complete", "abort"];
@@ -194204,8 +194268,8 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
194204
194268
  let migrationsDir = "migrations";
194205
194269
  let targetDb;
194206
194270
  try {
194207
- if (fs28.existsSync(configPath)) {
194208
- const configContent = fs28.readFileSync(configPath, "utf-8");
194271
+ if (fs29.existsSync(configPath)) {
194272
+ const configContent = fs29.readFileSync(configPath, "utf-8");
194209
194273
  config = await parseConfig(configContent);
194210
194274
  if (databaseName) {
194211
194275
  const postgresConfig = config.postgres.find((p) => p.name === databaseName);
@@ -194341,7 +194405,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
194341
194405
  const reshapeArgs = isMigrationSubcommand ? ["migration", action] : [action];
194342
194406
  const fullMigrationsPath = path26.join(process.cwd(), migrationsDir);
194343
194407
  if (action === "check" || action === "start") {
194344
- if (fs28.existsSync(fullMigrationsPath)) {
194408
+ if (fs29.existsSync(fullMigrationsPath)) {
194345
194409
  reshapeArgs.push("--dirs", fullMigrationsPath);
194346
194410
  } else if (action === "check") {
194347
194411
  console.error(`Error: Migrations directory not found: ${fullMigrationsPath}`);
@@ -194391,7 +194455,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
194391
194455
  import React8, { useState as useState7, useEffect as useEffect5 } from "react";
194392
194456
  import { render as render6, Text as Text8, Box as Box8 } from "ink";
194393
194457
  import Spinner6 from "ink-spinner";
194394
- import * as fs29 from "fs";
194458
+ import * as fs30 from "fs";
194395
194459
  import * as path27 from "path";
194396
194460
  function CleanUI({ instanceKey }) {
194397
194461
  const [state, setState] = useState7({ status: "checking" });
@@ -194399,13 +194463,13 @@ function CleanUI({ instanceKey }) {
194399
194463
  async function clean() {
194400
194464
  const projectRoot = process.cwd();
194401
194465
  const specificDir = path27.join(projectRoot, ".specific");
194402
- if (!fs29.existsSync(specificDir)) {
194466
+ if (!fs30.existsSync(specificDir)) {
194403
194467
  setState({ status: "nothing" });
194404
194468
  return;
194405
194469
  }
194406
194470
  if (instanceKey) {
194407
194471
  const keyDir = path27.join(specificDir, "keys", instanceKey);
194408
- if (!fs29.existsSync(keyDir)) {
194472
+ if (!fs30.existsSync(keyDir)) {
194409
194473
  setState({ status: "nothing" });
194410
194474
  return;
194411
194475
  }
@@ -194421,7 +194485,7 @@ function CleanUI({ instanceKey }) {
194421
194485
  await stateManager.cleanStaleState();
194422
194486
  setState({ status: "cleaning" });
194423
194487
  try {
194424
- fs29.rmSync(keyDir, { recursive: true, force: true });
194488
+ fs30.rmSync(keyDir, { recursive: true, force: true });
194425
194489
  setState({ status: "success" });
194426
194490
  } catch (err) {
194427
194491
  setState({
@@ -194431,12 +194495,12 @@ function CleanUI({ instanceKey }) {
194431
194495
  }
194432
194496
  } else {
194433
194497
  const keysDir = path27.join(specificDir, "keys");
194434
- if (!fs29.existsSync(keysDir)) {
194498
+ if (!fs30.existsSync(keysDir)) {
194435
194499
  setState({ status: "nothing" });
194436
194500
  return;
194437
194501
  }
194438
- const keys = fs29.readdirSync(keysDir).filter(
194439
- (f) => fs29.statSync(path27.join(keysDir, f)).isDirectory()
194502
+ const keys = fs30.readdirSync(keysDir).filter(
194503
+ (f) => fs30.statSync(path27.join(keysDir, f)).isDirectory()
194440
194504
  );
194441
194505
  for (const key of keys) {
194442
194506
  const stateManager2 = new InstanceStateManager(projectRoot, key);
@@ -194460,7 +194524,7 @@ function CleanUI({ instanceKey }) {
194460
194524
  }
194461
194525
  setState({ status: "cleaning" });
194462
194526
  try {
194463
- fs29.rmSync(keysDir, { recursive: true, force: true });
194527
+ fs30.rmSync(keysDir, { recursive: true, force: true });
194464
194528
  setState({ status: "success" });
194465
194529
  } catch (err) {
194466
194530
  setState({
@@ -194625,7 +194689,7 @@ import { render as render9, Text as Text11, Box as Box10, useApp as useApp6 } fr
194625
194689
  import Spinner7 from "ink-spinner";
194626
194690
 
194627
194691
  // src/lib/update.ts
194628
- import * as fs30 from "fs";
194692
+ import * as fs31 from "fs";
194629
194693
  import * as path28 from "path";
194630
194694
  var BINARIES_BASE_URL = "https://binaries.specific.dev/cli";
194631
194695
  function compareVersions(a, b) {
@@ -194640,7 +194704,7 @@ function compareVersions(a, b) {
194640
194704
  return 0;
194641
194705
  }
194642
194706
  async function checkForUpdate() {
194643
- const currentVersion = "0.1.71";
194707
+ const currentVersion = "0.1.73";
194644
194708
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
194645
194709
  if (!response.ok) {
194646
194710
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -194656,7 +194720,7 @@ function isBinaryWritable() {
194656
194720
  const binaryPath = getCurrentBinaryPath();
194657
194721
  const dir = path28.dirname(binaryPath);
194658
194722
  try {
194659
- fs30.accessSync(dir, fs30.constants.W_OK);
194723
+ fs31.accessSync(dir, fs31.constants.W_OK);
194660
194724
  return true;
194661
194725
  } catch {
194662
194726
  return false;
@@ -194667,21 +194731,21 @@ async function performUpdate(version, onProgress) {
194667
194731
  const binaryDir = path28.dirname(binaryPath);
194668
194732
  const tempPath = path28.join(binaryDir, `.specific-update-${process.pid}`);
194669
194733
  try {
194670
- const { platform: platform5, arch: arch3 } = getPlatformInfo();
194671
- const url = `${BINARIES_BASE_URL}/${version}/specific-${platform5}-${arch3}`;
194734
+ const { platform: platform6, arch: arch3 } = getPlatformInfo();
194735
+ const url = `${BINARIES_BASE_URL}/${version}/specific-${platform6}-${arch3}`;
194672
194736
  await downloadFile(url, tempPath, onProgress);
194673
- const stat4 = fs30.statSync(tempPath);
194737
+ const stat4 = fs31.statSync(tempPath);
194674
194738
  if (stat4.size === 0) {
194675
194739
  throw new Error("Downloaded binary is empty");
194676
194740
  }
194677
- fs30.chmodSync(tempPath, 493);
194741
+ fs31.chmodSync(tempPath, 493);
194678
194742
  onProgress?.({ phase: "finalizing" });
194679
- fs30.unlinkSync(binaryPath);
194680
- fs30.renameSync(tempPath, binaryPath);
194743
+ fs31.unlinkSync(binaryPath);
194744
+ fs31.renameSync(tempPath, binaryPath);
194681
194745
  } catch (error) {
194682
194746
  try {
194683
- if (fs30.existsSync(tempPath)) {
194684
- fs30.unlinkSync(tempPath);
194747
+ if (fs31.existsSync(tempPath)) {
194748
+ fs31.unlinkSync(tempPath);
194685
194749
  }
194686
194750
  } catch {
194687
194751
  }
@@ -194691,21 +194755,21 @@ async function performUpdate(version, onProgress) {
194691
194755
 
194692
194756
  // src/lib/background-update.ts
194693
194757
  import { spawn as spawn10 } from "child_process";
194694
- import * as fs31 from "fs";
194758
+ import * as fs32 from "fs";
194695
194759
  import * as path29 from "path";
194696
- import * as os9 from "os";
194697
- var SPECIFIC_DIR = path29.join(os9.homedir(), ".specific");
194760
+ import * as os10 from "os";
194761
+ var SPECIFIC_DIR = path29.join(os10.homedir(), ".specific");
194698
194762
  var RATE_LIMIT_FILE = path29.join(SPECIFIC_DIR, "last-update-check");
194699
194763
  var LOCK_FILE = path29.join(SPECIFIC_DIR, "update.lock");
194700
194764
  var RATE_LIMIT_MS = 60 * 60 * 1e3;
194701
194765
  var STALE_LOCK_MS = 10 * 60 * 1e3;
194702
194766
  function writeCheckTimestamp() {
194703
- fs31.mkdirSync(SPECIFIC_DIR, { recursive: true });
194704
- fs31.writeFileSync(RATE_LIMIT_FILE, String(Date.now()), "utf-8");
194767
+ fs32.mkdirSync(SPECIFIC_DIR, { recursive: true });
194768
+ fs32.writeFileSync(RATE_LIMIT_FILE, String(Date.now()), "utf-8");
194705
194769
  }
194706
194770
  function isRateLimited() {
194707
194771
  try {
194708
- const content = fs31.readFileSync(RATE_LIMIT_FILE, "utf-8").trim();
194772
+ const content = fs32.readFileSync(RATE_LIMIT_FILE, "utf-8").trim();
194709
194773
  const lastCheck = parseInt(content, 10);
194710
194774
  if (isNaN(lastCheck)) return false;
194711
194775
  return Date.now() - lastCheck < RATE_LIMIT_MS;
@@ -194839,7 +194903,7 @@ function updateCommand() {
194839
194903
  var program = new Command();
194840
194904
  var env = "production";
194841
194905
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
194842
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.71").enablePositionalOptions();
194906
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.73").enablePositionalOptions();
194843
194907
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").action((options2) => initCommand(options2));
194844
194908
  program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
194845
194909
  program.command("check").description("Validate specific.hcl configuration").action(checkCommand);