@specific.dev/cli 0.1.61 → 0.1.63

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 (69) 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/{59b95f8f36877231.js → 369cccd775763aa2.js} +2 -2
  10. package/dist/admin/_next/static/chunks/497f00630c8a5681.js +1 -0
  11. package/dist/admin/_next/static/chunks/{422a5aac8222197b.js → c7954d71061f1f9b.js} +2 -2
  12. package/dist/admin/_next/static/chunks/e3baf0c708c5b9ae.js +1 -0
  13. package/dist/admin/_not-found/__next._full.txt +3 -3
  14. package/dist/admin/_not-found/__next._head.txt +1 -1
  15. package/dist/admin/_not-found/__next._index.txt +3 -3
  16. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  17. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  18. package/dist/admin/_not-found/__next._tree.txt +1 -1
  19. package/dist/admin/_not-found/index.html +1 -1
  20. package/dist/admin/_not-found/index.txt +3 -3
  21. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +2 -2
  22. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  23. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +5 -5
  24. package/dist/admin/databases/__next._full.txt +8 -8
  25. package/dist/admin/databases/__next._head.txt +1 -1
  26. package/dist/admin/databases/__next._index.txt +3 -3
  27. package/dist/admin/databases/__next._tree.txt +1 -1
  28. package/dist/admin/databases/index.html +1 -1
  29. package/dist/admin/databases/index.txt +8 -8
  30. package/dist/admin/fullscreen/__next._full.txt +4 -4
  31. package/dist/admin/fullscreen/__next._head.txt +1 -1
  32. package/dist/admin/fullscreen/__next._index.txt +3 -3
  33. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  34. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
  35. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next._full.txt +4 -4
  37. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next._index.txt +3 -3
  39. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  40. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +2 -2
  41. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  42. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  43. package/dist/admin/fullscreen/databases/index.html +1 -1
  44. package/dist/admin/fullscreen/databases/index.txt +4 -4
  45. package/dist/admin/fullscreen/index.html +1 -1
  46. package/dist/admin/fullscreen/index.txt +4 -4
  47. package/dist/admin/index.html +1 -1
  48. package/dist/admin/index.txt +8 -8
  49. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +8 -0
  50. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +9 -0
  51. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +4 -0
  52. package/dist/admin/workflows/__next._full.txt +27 -0
  53. package/dist/admin/workflows/__next._head.txt +6 -0
  54. package/dist/admin/workflows/__next._index.txt +7 -0
  55. package/dist/admin/workflows/__next._tree.txt +5 -0
  56. package/dist/admin/workflows/index.html +1 -0
  57. package/dist/admin/workflows/index.txt +27 -0
  58. package/dist/cli.js +1837 -727
  59. package/dist/docs/builds.md +59 -13
  60. package/dist/docs/index.md +4 -0
  61. package/dist/docs/integrations/temporal.md +4 -0
  62. package/dist/docs/temporal.md +98 -0
  63. package/dist/docs/volumes.md +63 -0
  64. package/dist/postinstall.js +1 -1
  65. package/package.json +5 -2
  66. package/dist/admin/_next/static/chunks/144304e5f91b7ae5.js +0 -1
  67. /package/dist/admin/_next/static/{ko53a3ptYl472sHJWxbir → 3gQ1McserxEZ29fmlvSRS}/_buildManifest.js +0 -0
  68. /package/dist/admin/_next/static/{ko53a3ptYl472sHJWxbir → 3gQ1McserxEZ29fmlvSRS}/_clientMiddlewareManifest.json +0 -0
  69. /package/dist/admin/_next/static/{ko53a3ptYl472sHJWxbir → 3gQ1McserxEZ29fmlvSRS}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -39,10 +39,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  ));
40
40
 
41
41
  // node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
42
- import fs4 from "node:fs";
42
+ import fs5 from "node:fs";
43
43
  function hasDockerEnv() {
44
44
  try {
45
- fs4.statSync("/.dockerenv");
45
+ fs5.statSync("/.dockerenv");
46
46
  return true;
47
47
  } catch {
48
48
  return false;
@@ -50,7 +50,7 @@ function hasDockerEnv() {
50
50
  }
51
51
  function hasDockerCGroup() {
52
52
  try {
53
- return fs4.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
53
+ return fs5.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
54
54
  } catch {
55
55
  return false;
56
56
  }
@@ -68,7 +68,7 @@ var init_is_docker = __esm({
68
68
  });
69
69
 
70
70
  // node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
71
- import fs5 from "node:fs";
71
+ import fs6 from "node:fs";
72
72
  function isInsideContainer() {
73
73
  if (cachedResult === void 0) {
74
74
  cachedResult = hasContainerEnv() || isDocker();
@@ -81,7 +81,7 @@ var init_is_inside_container = __esm({
81
81
  init_is_docker();
82
82
  hasContainerEnv = () => {
83
83
  try {
84
- fs5.statSync("/run/.containerenv");
84
+ fs6.statSync("/run/.containerenv");
85
85
  return true;
86
86
  } catch {
87
87
  return false;
@@ -92,8 +92,8 @@ var init_is_inside_container = __esm({
92
92
 
93
93
  // node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
94
94
  import process2 from "node:process";
95
- import os3 from "node:os";
96
- import fs6 from "node:fs";
95
+ import os4 from "node:os";
96
+ import fs7 from "node:fs";
97
97
  var isWsl, is_wsl_default;
98
98
  var init_is_wsl = __esm({
99
99
  "node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js"() {
@@ -102,14 +102,14 @@ var init_is_wsl = __esm({
102
102
  if (process2.platform !== "linux") {
103
103
  return false;
104
104
  }
105
- if (os3.release().toLowerCase().includes("microsoft")) {
105
+ if (os4.release().toLowerCase().includes("microsoft")) {
106
106
  if (isInsideContainer()) {
107
107
  return false;
108
108
  }
109
109
  return true;
110
110
  }
111
111
  try {
112
- return fs6.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
112
+ return fs7.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
113
113
  } catch {
114
114
  return false;
115
115
  }
@@ -179,7 +179,7 @@ var init_utilities = __esm({
179
179
  // node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
180
180
  import { promisify as promisify2 } from "node:util";
181
181
  import childProcess2 from "node:child_process";
182
- import fs7, { constants as fsConstants } from "node:fs/promises";
182
+ import fs8, { constants as fsConstants } from "node:fs/promises";
183
183
  var execFile2, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
184
184
  var init_wsl_utils = __esm({
185
185
  "node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
@@ -198,14 +198,14 @@ var init_wsl_utils = __esm({
198
198
  const configFilePath = "/etc/wsl.conf";
199
199
  let isConfigFileExists = false;
200
200
  try {
201
- await fs7.access(configFilePath, fsConstants.F_OK);
201
+ await fs8.access(configFilePath, fsConstants.F_OK);
202
202
  isConfigFileExists = true;
203
203
  } catch {
204
204
  }
205
205
  if (!isConfigFileExists) {
206
206
  return defaultMountPoint;
207
207
  }
208
- const configContent = await fs7.readFile(configFilePath, { encoding: "utf8" });
208
+ const configContent = await fs8.readFile(configFilePath, { encoding: "utf8" });
209
209
  const parsedMountPoint = parseMountPointFromConfig(configContent);
210
210
  if (parsedMountPoint === void 0) {
211
211
  return defaultMountPoint;
@@ -224,7 +224,7 @@ var init_wsl_utils = __esm({
224
224
  canAccessPowerShellPromise ??= (async () => {
225
225
  try {
226
226
  const psPath = await powerShellPath2();
227
- await fs7.access(psPath, fsConstants.X_OK);
227
+ await fs8.access(psPath, fsConstants.X_OK);
228
228
  return true;
229
229
  } catch {
230
230
  return false;
@@ -238,15 +238,15 @@ var init_wsl_utils = __esm({
238
238
  const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
239
239
  return stdout.trim();
240
240
  };
241
- convertWslPathToWindows = async (path26) => {
242
- if (/^[a-z]+:\/\//i.test(path26)) {
243
- return path26;
241
+ convertWslPathToWindows = async (path28) => {
242
+ if (/^[a-z]+:\/\//i.test(path28)) {
243
+ return path28;
244
244
  }
245
245
  try {
246
- const { stdout } = await execFile2("wslpath", ["-aw", path26], { encoding: "utf8" });
246
+ const { stdout } = await execFile2("wslpath", ["-aw", path28], { encoding: "utf8" });
247
247
  return stdout.trim();
248
248
  } catch {
249
- return path26;
249
+ return path28;
250
250
  }
251
251
  };
252
252
  }
@@ -432,10 +432,10 @@ __export(open_exports, {
432
432
  openApp: () => openApp
433
433
  });
434
434
  import process8 from "node:process";
435
- import path4 from "node:path";
435
+ import path5 from "node:path";
436
436
  import { fileURLToPath } from "node:url";
437
437
  import childProcess3 from "node:child_process";
438
- import fs8, { constants as fsConstants2 } from "node:fs/promises";
438
+ import fs9, { constants as fsConstants2 } from "node:fs/promises";
439
439
  function detectArchBinary(binary) {
440
440
  if (typeof binary === "string" || Array.isArray(binary)) {
441
441
  return binary;
@@ -446,16 +446,16 @@ function detectArchBinary(binary) {
446
446
  }
447
447
  return archBinary;
448
448
  }
449
- function detectPlatformBinary({ [platform2]: platformBinary }, { wsl } = {}) {
449
+ function detectPlatformBinary({ [platform3]: platformBinary }, { wsl } = {}) {
450
450
  if (wsl && is_wsl_default) {
451
451
  return detectArchBinary(wsl);
452
452
  }
453
453
  if (!platformBinary) {
454
- throw new Error(`${platform2} is not supported`);
454
+ throw new Error(`${platform3} is not supported`);
455
455
  }
456
456
  return detectArchBinary(platformBinary);
457
457
  }
458
- var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform2, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
458
+ var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform3, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
459
459
  var init_open = __esm({
460
460
  "node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
461
461
  init_wsl_utils();
@@ -465,9 +465,9 @@ var init_open = __esm({
465
465
  init_is_inside_container();
466
466
  init_is_in_ssh();
467
467
  fallbackAttemptSymbol = Symbol("fallbackAttempt");
468
- __dirname = import.meta.url ? path4.dirname(fileURLToPath(import.meta.url)) : "";
469
- localXdgOpenPath = path4.join(__dirname, "xdg-open");
470
- ({ platform: platform2, arch } = process8);
468
+ __dirname = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
469
+ localXdgOpenPath = path5.join(__dirname, "xdg-open");
470
+ ({ platform: platform3, arch } = process8);
471
471
  tryEachApp = async (apps2, opener) => {
472
472
  if (apps2.length === 0) {
473
473
  return;
@@ -564,7 +564,7 @@ var init_open = __esm({
564
564
  if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
565
565
  shouldUseWindowsInWsl = await canAccessPowerShell();
566
566
  }
567
- if (platform2 === "darwin") {
567
+ if (platform3 === "darwin") {
568
568
  command = "open";
569
569
  if (options2.wait) {
570
570
  cliArguments.push("--wait-apps");
@@ -578,7 +578,7 @@ var init_open = __esm({
578
578
  if (app) {
579
579
  cliArguments.push("-a", app);
580
580
  }
581
- } else if (platform2 === "win32" || shouldUseWindowsInWsl) {
581
+ } else if (platform3 === "win32" || shouldUseWindowsInWsl) {
582
582
  command = await powerShellPath2();
583
583
  cliArguments.push(...executePowerShell.argumentsPrefix);
584
584
  if (!is_wsl_default) {
@@ -614,11 +614,11 @@ var init_open = __esm({
614
614
  const isBundled = !__dirname || __dirname === "/";
615
615
  let exeLocalXdgOpen = false;
616
616
  try {
617
- await fs8.access(localXdgOpenPath, fsConstants2.X_OK);
617
+ await fs9.access(localXdgOpenPath, fsConstants2.X_OK);
618
618
  exeLocalXdgOpen = true;
619
619
  } catch {
620
620
  }
621
- const useSystemXdgOpen = process8.versions.electron ?? (platform2 === "android" || isBundled || !exeLocalXdgOpen);
621
+ const useSystemXdgOpen = process8.versions.electron ?? (platform3 === "android" || isBundled || !exeLocalXdgOpen);
622
622
  command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
623
623
  }
624
624
  if (appArguments.length > 0) {
@@ -629,7 +629,7 @@ var init_open = __esm({
629
629
  childProcessOptions.detached = true;
630
630
  }
631
631
  }
632
- if (platform2 === "darwin" && appArguments.length > 0) {
632
+ if (platform3 === "darwin" && appArguments.length > 0) {
633
633
  cliArguments.push("--args", ...appArguments);
634
634
  }
635
635
  if (options2.target) {
@@ -754,8 +754,8 @@ var require_dist = __commonJS({
754
754
  var $global, $module, $NaN = NaN;
755
755
  if ("undefined" != typeof window ? $global = window : "undefined" != typeof self ? $global = self : "undefined" != typeof global ? ($global = global).require = __require : $global = this, void 0 === $global || void 0 === $global.Array) throw new Error("no global object found");
756
756
  if ("undefined" != typeof module && ($module = module), !$global.fs && $global.require) try {
757
- var fs28 = $global.require("fs");
758
- "object" == typeof fs28 && null !== fs28 && 0 !== Object.keys(fs28).length && ($global.fs = fs28);
757
+ var fs30 = $global.require("fs");
758
+ "object" == typeof fs30 && null !== fs30 && 0 !== Object.keys(fs30).length && ($global.fs = fs30);
759
759
  } catch (e) {
760
760
  }
761
761
  if (!$global.fs) {
@@ -182942,6 +182942,487 @@ var require_dist = __commonJS({
182942
182942
  }
182943
182943
  });
182944
182944
 
182945
+ // node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
182946
+ var require_picocolors = __commonJS({
182947
+ "node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js"(exports, module) {
182948
+ var p = process || {};
182949
+ var argv = p.argv || [];
182950
+ var env2 = p.env || {};
182951
+ var isColorSupported = !(!!env2.NO_COLOR || argv.includes("--no-color")) && (!!env2.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env2.TERM !== "dumb" || !!env2.CI);
182952
+ var formatter = (open3, close, replace = open3) => (input) => {
182953
+ let string = "" + input, index = string.indexOf(close, open3.length);
182954
+ return ~index ? open3 + replaceClose(string, close, replace, index) + close : open3 + string + close;
182955
+ };
182956
+ var replaceClose = (string, close, replace, index) => {
182957
+ let result = "", cursor = 0;
182958
+ do {
182959
+ result += string.substring(cursor, index) + replace;
182960
+ cursor = index + close.length;
182961
+ index = string.indexOf(close, cursor);
182962
+ } while (~index);
182963
+ return result + string.substring(cursor);
182964
+ };
182965
+ var createColors = (enabled = isColorSupported) => {
182966
+ let f = enabled ? formatter : () => String;
182967
+ return {
182968
+ isColorSupported: enabled,
182969
+ reset: f("\x1B[0m", "\x1B[0m"),
182970
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
182971
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
182972
+ italic: f("\x1B[3m", "\x1B[23m"),
182973
+ underline: f("\x1B[4m", "\x1B[24m"),
182974
+ inverse: f("\x1B[7m", "\x1B[27m"),
182975
+ hidden: f("\x1B[8m", "\x1B[28m"),
182976
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
182977
+ black: f("\x1B[30m", "\x1B[39m"),
182978
+ red: f("\x1B[31m", "\x1B[39m"),
182979
+ green: f("\x1B[32m", "\x1B[39m"),
182980
+ yellow: f("\x1B[33m", "\x1B[39m"),
182981
+ blue: f("\x1B[34m", "\x1B[39m"),
182982
+ magenta: f("\x1B[35m", "\x1B[39m"),
182983
+ cyan: f("\x1B[36m", "\x1B[39m"),
182984
+ white: f("\x1B[37m", "\x1B[39m"),
182985
+ gray: f("\x1B[90m", "\x1B[39m"),
182986
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
182987
+ bgRed: f("\x1B[41m", "\x1B[49m"),
182988
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
182989
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
182990
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
182991
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
182992
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
182993
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
182994
+ blackBright: f("\x1B[90m", "\x1B[39m"),
182995
+ redBright: f("\x1B[91m", "\x1B[39m"),
182996
+ greenBright: f("\x1B[92m", "\x1B[39m"),
182997
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
182998
+ blueBright: f("\x1B[94m", "\x1B[39m"),
182999
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
183000
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
183001
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
183002
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
183003
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
183004
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
183005
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
183006
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
183007
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
183008
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
183009
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
183010
+ };
183011
+ };
183012
+ module.exports = createColors();
183013
+ module.exports.createColors = createColors;
183014
+ }
183015
+ });
183016
+
183017
+ // node_modules/.pnpm/js-tokens@4.0.0/node_modules/js-tokens/index.js
183018
+ var require_js_tokens = __commonJS({
183019
+ "node_modules/.pnpm/js-tokens@4.0.0/node_modules/js-tokens/index.js"(exports) {
183020
+ Object.defineProperty(exports, "__esModule", {
183021
+ value: true
183022
+ });
183023
+ exports.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyus]{1,6}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g;
183024
+ exports.matchToToken = function(match) {
183025
+ var token = { type: "invalid", value: match[0], closed: void 0 };
183026
+ if (match[1]) token.type = "string", token.closed = !!(match[3] || match[4]);
183027
+ else if (match[5]) token.type = "comment";
183028
+ else if (match[6]) token.type = "comment", token.closed = !!match[7];
183029
+ else if (match[8]) token.type = "regex";
183030
+ else if (match[9]) token.type = "number";
183031
+ else if (match[10]) token.type = "name";
183032
+ else if (match[11]) token.type = "punctuator";
183033
+ else if (match[12]) token.type = "whitespace";
183034
+ return token;
183035
+ };
183036
+ }
183037
+ });
183038
+
183039
+ // node_modules/.pnpm/@babel+helper-validator-identifier@7.28.5/node_modules/@babel/helper-validator-identifier/lib/identifier.js
183040
+ var require_identifier = __commonJS({
183041
+ "node_modules/.pnpm/@babel+helper-validator-identifier@7.28.5/node_modules/@babel/helper-validator-identifier/lib/identifier.js"(exports) {
183042
+ "use strict";
183043
+ Object.defineProperty(exports, "__esModule", {
183044
+ value: true
183045
+ });
183046
+ exports.isIdentifierChar = isIdentifierChar;
183047
+ exports.isIdentifierName = isIdentifierName;
183048
+ exports.isIdentifierStart = isIdentifierStart;
183049
+ var nonASCIIidentifierStartChars = "\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088F\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5C\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDC-\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7DC\uA7F1-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC";
183050
+ var nonASCIIidentifierChars = "\xB7\u0300-\u036F\u0387\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u0669\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u06F0-\u06F9\u0711\u0730-\u074A\u07A6-\u07B0\u07C0-\u07C9\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0966-\u096F\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09E6-\u09EF\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A66-\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AE6-\u0AEF\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B55-\u0B57\u0B62\u0B63\u0B66-\u0B6F\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0BE6-\u0BEF\u0C00-\u0C04\u0C3C\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0CE6-\u0CEF\u0CF3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D66-\u0D6F\u0D81-\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0E50-\u0E59\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0ED0-\u0ED9\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1040-\u1049\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F-\u109D\u135D-\u135F\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u17E0-\u17E9\u180B-\u180D\u180F-\u1819\u18A9\u1920-\u192B\u1930-\u193B\u1946-\u194F\u19D0-\u19DA\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AB0-\u1ABD\u1ABF-\u1ADD\u1AE0-\u1AEB\u1B00-\u1B04\u1B34-\u1B44\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BB0-\u1BB9\u1BE6-\u1BF3\u1C24-\u1C37\u1C40-\u1C49\u1C50-\u1C59\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DFF\u200C\u200D\u203F\u2040\u2054\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\u30FB\uA620-\uA629\uA66F\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA82C\uA880\uA881\uA8B4-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F1\uA8FF-\uA909\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9D0-\uA9D9\uA9E5\uA9F0-\uA9F9\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA50-\uAA59\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uABF0-\uABF9\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFF10-\uFF19\uFF3F\uFF65";
183051
+ var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
183052
+ var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
183053
+ nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
183054
+ var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 7, 25, 39, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 5, 57, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 24, 43, 261, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 33, 24, 3, 24, 45, 74, 6, 0, 67, 12, 65, 1, 2, 0, 15, 4, 10, 7381, 42, 31, 98, 114, 8702, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 208, 30, 2, 2, 2, 1, 2, 6, 3, 4, 10, 1, 225, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4381, 3, 5773, 3, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 8489];
183055
+ var astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 78, 5, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 199, 7, 137, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 55, 9, 266, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 233, 0, 3, 0, 8, 1, 6, 0, 475, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
183056
+ function isInAstralSet(code, set) {
183057
+ let pos = 65536;
183058
+ for (let i = 0, length = set.length; i < length; i += 2) {
183059
+ pos += set[i];
183060
+ if (pos > code) return false;
183061
+ pos += set[i + 1];
183062
+ if (pos >= code) return true;
183063
+ }
183064
+ return false;
183065
+ }
183066
+ function isIdentifierStart(code) {
183067
+ if (code < 65) return code === 36;
183068
+ if (code <= 90) return true;
183069
+ if (code < 97) return code === 95;
183070
+ if (code <= 122) return true;
183071
+ if (code <= 65535) {
183072
+ return code >= 170 && nonASCIIidentifierStart.test(String.fromCharCode(code));
183073
+ }
183074
+ return isInAstralSet(code, astralIdentifierStartCodes);
183075
+ }
183076
+ function isIdentifierChar(code) {
183077
+ if (code < 48) return code === 36;
183078
+ if (code < 58) return true;
183079
+ if (code < 65) return false;
183080
+ if (code <= 90) return true;
183081
+ if (code < 97) return code === 95;
183082
+ if (code <= 122) return true;
183083
+ if (code <= 65535) {
183084
+ return code >= 170 && nonASCIIidentifier.test(String.fromCharCode(code));
183085
+ }
183086
+ return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
183087
+ }
183088
+ function isIdentifierName(name) {
183089
+ let isFirst = true;
183090
+ for (let i = 0; i < name.length; i++) {
183091
+ let cp = name.charCodeAt(i);
183092
+ if ((cp & 64512) === 55296 && i + 1 < name.length) {
183093
+ const trail = name.charCodeAt(++i);
183094
+ if ((trail & 64512) === 56320) {
183095
+ cp = 65536 + ((cp & 1023) << 10) + (trail & 1023);
183096
+ }
183097
+ }
183098
+ if (isFirst) {
183099
+ isFirst = false;
183100
+ if (!isIdentifierStart(cp)) {
183101
+ return false;
183102
+ }
183103
+ } else if (!isIdentifierChar(cp)) {
183104
+ return false;
183105
+ }
183106
+ }
183107
+ return !isFirst;
183108
+ }
183109
+ }
183110
+ });
183111
+
183112
+ // node_modules/.pnpm/@babel+helper-validator-identifier@7.28.5/node_modules/@babel/helper-validator-identifier/lib/keyword.js
183113
+ var require_keyword = __commonJS({
183114
+ "node_modules/.pnpm/@babel+helper-validator-identifier@7.28.5/node_modules/@babel/helper-validator-identifier/lib/keyword.js"(exports) {
183115
+ "use strict";
183116
+ Object.defineProperty(exports, "__esModule", {
183117
+ value: true
183118
+ });
183119
+ exports.isKeyword = isKeyword;
183120
+ exports.isReservedWord = isReservedWord;
183121
+ exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
183122
+ exports.isStrictBindReservedWord = isStrictBindReservedWord;
183123
+ exports.isStrictReservedWord = isStrictReservedWord;
183124
+ var reservedWords = {
183125
+ keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
183126
+ strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
183127
+ strictBind: ["eval", "arguments"]
183128
+ };
183129
+ var keywords = new Set(reservedWords.keyword);
183130
+ var reservedWordsStrictSet = new Set(reservedWords.strict);
183131
+ var reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
183132
+ function isReservedWord(word, inModule) {
183133
+ return inModule && word === "await" || word === "enum";
183134
+ }
183135
+ function isStrictReservedWord(word, inModule) {
183136
+ return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
183137
+ }
183138
+ function isStrictBindOnlyReservedWord(word) {
183139
+ return reservedWordsStrictBindSet.has(word);
183140
+ }
183141
+ function isStrictBindReservedWord(word, inModule) {
183142
+ return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
183143
+ }
183144
+ function isKeyword(word) {
183145
+ return keywords.has(word);
183146
+ }
183147
+ }
183148
+ });
183149
+
183150
+ // node_modules/.pnpm/@babel+helper-validator-identifier@7.28.5/node_modules/@babel/helper-validator-identifier/lib/index.js
183151
+ var require_lib = __commonJS({
183152
+ "node_modules/.pnpm/@babel+helper-validator-identifier@7.28.5/node_modules/@babel/helper-validator-identifier/lib/index.js"(exports) {
183153
+ "use strict";
183154
+ Object.defineProperty(exports, "__esModule", {
183155
+ value: true
183156
+ });
183157
+ Object.defineProperty(exports, "isIdentifierChar", {
183158
+ enumerable: true,
183159
+ get: function() {
183160
+ return _identifier.isIdentifierChar;
183161
+ }
183162
+ });
183163
+ Object.defineProperty(exports, "isIdentifierName", {
183164
+ enumerable: true,
183165
+ get: function() {
183166
+ return _identifier.isIdentifierName;
183167
+ }
183168
+ });
183169
+ Object.defineProperty(exports, "isIdentifierStart", {
183170
+ enumerable: true,
183171
+ get: function() {
183172
+ return _identifier.isIdentifierStart;
183173
+ }
183174
+ });
183175
+ Object.defineProperty(exports, "isKeyword", {
183176
+ enumerable: true,
183177
+ get: function() {
183178
+ return _keyword.isKeyword;
183179
+ }
183180
+ });
183181
+ Object.defineProperty(exports, "isReservedWord", {
183182
+ enumerable: true,
183183
+ get: function() {
183184
+ return _keyword.isReservedWord;
183185
+ }
183186
+ });
183187
+ Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
183188
+ enumerable: true,
183189
+ get: function() {
183190
+ return _keyword.isStrictBindOnlyReservedWord;
183191
+ }
183192
+ });
183193
+ Object.defineProperty(exports, "isStrictBindReservedWord", {
183194
+ enumerable: true,
183195
+ get: function() {
183196
+ return _keyword.isStrictBindReservedWord;
183197
+ }
183198
+ });
183199
+ Object.defineProperty(exports, "isStrictReservedWord", {
183200
+ enumerable: true,
183201
+ get: function() {
183202
+ return _keyword.isStrictReservedWord;
183203
+ }
183204
+ });
183205
+ var _identifier = require_identifier();
183206
+ var _keyword = require_keyword();
183207
+ }
183208
+ });
183209
+
183210
+ // node_modules/.pnpm/@babel+code-frame@7.29.0/node_modules/@babel/code-frame/lib/index.js
183211
+ var require_lib2 = __commonJS({
183212
+ "node_modules/.pnpm/@babel+code-frame@7.29.0/node_modules/@babel/code-frame/lib/index.js"(exports) {
183213
+ "use strict";
183214
+ Object.defineProperty(exports, "__esModule", { value: true });
183215
+ var picocolors = require_picocolors();
183216
+ var jsTokens = require_js_tokens();
183217
+ var helperValidatorIdentifier = require_lib();
183218
+ function isColorSupported() {
183219
+ return typeof process === "object" && (process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false") ? false : picocolors.isColorSupported;
183220
+ }
183221
+ var compose = (f, g) => (v) => f(g(v));
183222
+ function buildDefs(colors) {
183223
+ return {
183224
+ keyword: colors.cyan,
183225
+ capitalized: colors.yellow,
183226
+ jsxIdentifier: colors.yellow,
183227
+ punctuator: colors.yellow,
183228
+ number: colors.magenta,
183229
+ string: colors.green,
183230
+ regex: colors.magenta,
183231
+ comment: colors.gray,
183232
+ invalid: compose(compose(colors.white, colors.bgRed), colors.bold),
183233
+ gutter: colors.gray,
183234
+ marker: compose(colors.red, colors.bold),
183235
+ message: compose(colors.red, colors.bold),
183236
+ reset: colors.reset
183237
+ };
183238
+ }
183239
+ var defsOn = buildDefs(picocolors.createColors(true));
183240
+ var defsOff = buildDefs(picocolors.createColors(false));
183241
+ function getDefs(enabled) {
183242
+ return enabled ? defsOn : defsOff;
183243
+ }
183244
+ var sometimesKeywords = /* @__PURE__ */ new Set(["as", "async", "from", "get", "of", "set"]);
183245
+ var NEWLINE$1 = /\r\n|[\n\r\u2028\u2029]/;
183246
+ var BRACKET = /^[()[\]{}]$/;
183247
+ var tokenize;
183248
+ var JSX_TAG = /^[a-z][\w-]*$/i;
183249
+ var getTokenType = function(token, offset, text) {
183250
+ if (token.type === "name") {
183251
+ const tokenValue = token.value;
183252
+ if (helperValidatorIdentifier.isKeyword(tokenValue) || helperValidatorIdentifier.isStrictReservedWord(tokenValue, true) || sometimesKeywords.has(tokenValue)) {
183253
+ return "keyword";
183254
+ }
183255
+ if (JSX_TAG.test(tokenValue) && (text[offset - 1] === "<" || text.slice(offset - 2, offset) === "</")) {
183256
+ return "jsxIdentifier";
183257
+ }
183258
+ const firstChar = String.fromCodePoint(tokenValue.codePointAt(0));
183259
+ if (firstChar !== firstChar.toLowerCase()) {
183260
+ return "capitalized";
183261
+ }
183262
+ }
183263
+ if (token.type === "punctuator" && BRACKET.test(token.value)) {
183264
+ return "bracket";
183265
+ }
183266
+ if (token.type === "invalid" && (token.value === "@" || token.value === "#")) {
183267
+ return "punctuator";
183268
+ }
183269
+ return token.type;
183270
+ };
183271
+ tokenize = function* (text) {
183272
+ let match;
183273
+ while (match = jsTokens.default.exec(text)) {
183274
+ const token = jsTokens.matchToToken(match);
183275
+ yield {
183276
+ type: getTokenType(token, match.index, text),
183277
+ value: token.value
183278
+ };
183279
+ }
183280
+ };
183281
+ function highlight(text) {
183282
+ if (text === "") return "";
183283
+ const defs = getDefs(true);
183284
+ let highlighted = "";
183285
+ for (const {
183286
+ type,
183287
+ value
183288
+ } of tokenize(text)) {
183289
+ if (type in defs) {
183290
+ highlighted += value.split(NEWLINE$1).map((str) => defs[type](str)).join("\n");
183291
+ } else {
183292
+ highlighted += value;
183293
+ }
183294
+ }
183295
+ return highlighted;
183296
+ }
183297
+ var deprecationWarningShown = false;
183298
+ var NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
183299
+ function getMarkerLines(loc, source, opts, startLineBaseZero) {
183300
+ const startLoc = Object.assign({
183301
+ column: 0,
183302
+ line: -1
183303
+ }, loc.start);
183304
+ const endLoc = Object.assign({}, startLoc, loc.end);
183305
+ const {
183306
+ linesAbove = 2,
183307
+ linesBelow = 3
183308
+ } = opts || {};
183309
+ const startLine = startLoc.line - startLineBaseZero;
183310
+ const startColumn = startLoc.column;
183311
+ const endLine = endLoc.line - startLineBaseZero;
183312
+ const endColumn = endLoc.column;
183313
+ let start = Math.max(startLine - (linesAbove + 1), 0);
183314
+ let end = Math.min(source.length, endLine + linesBelow);
183315
+ if (startLine === -1) {
183316
+ start = 0;
183317
+ }
183318
+ if (endLine === -1) {
183319
+ end = source.length;
183320
+ }
183321
+ const lineDiff = endLine - startLine;
183322
+ const markerLines = {};
183323
+ if (lineDiff) {
183324
+ for (let i = 0; i <= lineDiff; i++) {
183325
+ const lineNumber = i + startLine;
183326
+ if (!startColumn) {
183327
+ markerLines[lineNumber] = true;
183328
+ } else if (i === 0) {
183329
+ const sourceLength = source[lineNumber - 1].length;
183330
+ markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
183331
+ } else if (i === lineDiff) {
183332
+ markerLines[lineNumber] = [0, endColumn];
183333
+ } else {
183334
+ const sourceLength = source[lineNumber - i].length;
183335
+ markerLines[lineNumber] = [0, sourceLength];
183336
+ }
183337
+ }
183338
+ } else {
183339
+ if (startColumn === endColumn) {
183340
+ if (startColumn) {
183341
+ markerLines[startLine] = [startColumn, 0];
183342
+ } else {
183343
+ markerLines[startLine] = true;
183344
+ }
183345
+ } else {
183346
+ markerLines[startLine] = [startColumn, endColumn - startColumn];
183347
+ }
183348
+ }
183349
+ return {
183350
+ start,
183351
+ end,
183352
+ markerLines
183353
+ };
183354
+ }
183355
+ function codeFrameColumns2(rawLines, loc, opts = {}) {
183356
+ const shouldHighlight = opts.forceColor || isColorSupported() && opts.highlightCode;
183357
+ const startLineBaseZero = (opts.startLine || 1) - 1;
183358
+ const defs = getDefs(shouldHighlight);
183359
+ const lines = rawLines.split(NEWLINE);
183360
+ const {
183361
+ start,
183362
+ end,
183363
+ markerLines
183364
+ } = getMarkerLines(loc, lines, opts, startLineBaseZero);
183365
+ const hasColumns = loc.start && typeof loc.start.column === "number";
183366
+ const numberMaxWidth = String(end + startLineBaseZero).length;
183367
+ const highlightedLines = shouldHighlight ? highlight(rawLines) : rawLines;
183368
+ let frame = highlightedLines.split(NEWLINE, end).slice(start, end).map((line, index2) => {
183369
+ const number = start + 1 + index2;
183370
+ const paddedNumber = ` ${number + startLineBaseZero}`.slice(-numberMaxWidth);
183371
+ const gutter = ` ${paddedNumber} |`;
183372
+ const hasMarker = markerLines[number];
183373
+ const lastMarkerLine = !markerLines[number + 1];
183374
+ if (hasMarker) {
183375
+ let markerLine = "";
183376
+ if (Array.isArray(hasMarker)) {
183377
+ const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
183378
+ const numberOfMarkers = hasMarker[1] || 1;
183379
+ markerLine = ["\n ", defs.gutter(gutter.replace(/\d/g, " ")), " ", markerSpacing, defs.marker("^").repeat(numberOfMarkers)].join("");
183380
+ if (lastMarkerLine && opts.message) {
183381
+ markerLine += " " + defs.message(opts.message);
183382
+ }
183383
+ }
183384
+ return [defs.marker(">"), defs.gutter(gutter), line.length > 0 ? ` ${line}` : "", markerLine].join("");
183385
+ } else {
183386
+ return ` ${defs.gutter(gutter)}${line.length > 0 ? ` ${line}` : ""}`;
183387
+ }
183388
+ }).join("\n");
183389
+ if (opts.message && !hasColumns) {
183390
+ frame = `${" ".repeat(numberMaxWidth + 1)}${opts.message}
183391
+ ${frame}`;
183392
+ }
183393
+ if (shouldHighlight) {
183394
+ return defs.reset(frame);
183395
+ } else {
183396
+ return frame;
183397
+ }
183398
+ }
183399
+ function index(rawLines, lineNumber, colNumber, opts = {}) {
183400
+ if (!deprecationWarningShown) {
183401
+ deprecationWarningShown = true;
183402
+ const message = "Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";
183403
+ if (process.emitWarning) {
183404
+ process.emitWarning(message, "DeprecationWarning");
183405
+ } else {
183406
+ const deprecationError = new Error(message);
183407
+ deprecationError.name = "DeprecationWarning";
183408
+ console.warn(new Error(message));
183409
+ }
183410
+ }
183411
+ colNumber = Math.max(colNumber, 0);
183412
+ const location = {
183413
+ start: {
183414
+ column: colNumber,
183415
+ line: lineNumber
183416
+ }
183417
+ };
183418
+ return codeFrameColumns2(rawLines, location, opts);
183419
+ }
183420
+ exports.codeFrameColumns = codeFrameColumns2;
183421
+ exports.default = index;
183422
+ exports.highlight = highlight;
183423
+ }
183424
+ });
183425
+
182945
183426
  // src/cli.tsx
182946
183427
  import { Command } from "commander";
182947
183428
 
@@ -182949,8 +183430,11 @@ import { Command } from "commander";
182949
183430
  import React2, { useState, useEffect } from "react";
182950
183431
  import { render as render2, Text as Text2, Box as Box2, useInput, useApp } from "ink";
182951
183432
  import "ink-spinner";
182952
- import * as fs10 from "fs";
182953
- import * as path6 from "path";
183433
+ import * as fs11 from "fs";
183434
+ import * as path7 from "path";
183435
+
183436
+ // src/lib/dev/system-setup.ts
183437
+ import { execSync as execSync2 } from "child_process";
182954
183438
 
182955
183439
  // src/lib/dev/local-ca.ts
182956
183440
  import * as fs from "fs";
@@ -182965,6 +183449,38 @@ function caFilesExist() {
182965
183449
  const caDir = getCADir();
182966
183450
  return fs.existsSync(path.join(caDir, "ca.key")) && fs.existsSync(path.join(caDir, "ca.crt"));
182967
183451
  }
183452
+ function caInstalledInTrustStore() {
183453
+ if (!caFilesExist()) {
183454
+ return false;
183455
+ }
183456
+ const platform5 = os.platform();
183457
+ const certPath = path.join(getCADir(), "ca.crt");
183458
+ const diskCert = fs.readFileSync(certPath, "utf-8").replace(/\r\n/g, "\n").trim();
183459
+ try {
183460
+ if (platform5 === "darwin") {
183461
+ const keychainCert = execSync(
183462
+ 'security find-certificate -c "Specific Local Development CA" -p /Library/Keychains/System.keychain',
183463
+ { encoding: "utf-8" }
183464
+ ).replace(/\r\n/g, "\n").trim();
183465
+ return keychainCert === diskCert;
183466
+ } else if (platform5 === "linux") {
183467
+ const trustPaths = [
183468
+ "/usr/local/share/ca-certificates/specific-local-ca.crt",
183469
+ "/etc/pki/ca-trust/source/anchors/specific-local-ca.crt"
183470
+ ];
183471
+ for (const trustPath of trustPaths) {
183472
+ if (fs.existsSync(trustPath)) {
183473
+ const trustedCert = fs.readFileSync(trustPath, "utf-8").replace(/\r\n/g, "\n").trim();
183474
+ return trustedCert === diskCert;
183475
+ }
183476
+ }
183477
+ return false;
183478
+ }
183479
+ } catch {
183480
+ return false;
183481
+ }
183482
+ return false;
183483
+ }
182968
183484
  function createNameConstraintsExtension(permittedDNSNames) {
182969
183485
  const nameConstraintsOID = "2.5.29.30";
182970
183486
  const permittedSubtrees = permittedDNSNames.map((dnsName) => {
@@ -183054,32 +183570,30 @@ function removeCA() {
183054
183570
  fs.unlinkSync(certPath);
183055
183571
  }
183056
183572
  }
183057
- function installCAToTrustStore(certPath) {
183058
- const platform4 = os.platform();
183059
- if (platform4 === "darwin") {
183060
- execSync(
183061
- `sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`,
183062
- { stdio: "inherit" }
183063
- );
183064
- } else if (platform4 === "linux") {
183573
+ function getCAInstallCommands(certPath) {
183574
+ const platform5 = os.platform();
183575
+ if (platform5 === "darwin") {
183576
+ return [
183577
+ // Remove any existing cert with the same CN first — add-trusted-cert
183578
+ // silently does nothing if a cert with the same subject already exists.
183579
+ 'security delete-certificate -c "Specific Local Development CA" /Library/Keychains/System.keychain 2>/dev/null || true',
183580
+ `security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${certPath}"`
183581
+ ];
183582
+ } else if (platform5 === "linux") {
183065
183583
  if (fs.existsSync("/usr/local/share/ca-certificates")) {
183066
- execSync(
183067
- `sudo cp "${certPath}" /usr/local/share/ca-certificates/specific-local-ca.crt`,
183068
- { stdio: "inherit" }
183069
- );
183070
- execSync("sudo update-ca-certificates", { stdio: "inherit" });
183584
+ return [
183585
+ `cp "${certPath}" /usr/local/share/ca-certificates/specific-local-ca.crt`,
183586
+ "update-ca-certificates"
183587
+ ];
183071
183588
  } else if (fs.existsSync("/etc/pki/ca-trust/source/anchors")) {
183072
- execSync(
183073
- `sudo cp "${certPath}" /etc/pki/ca-trust/source/anchors/specific-local-ca.crt`,
183074
- { stdio: "inherit" }
183075
- );
183076
- execSync("sudo update-ca-trust extract", { stdio: "inherit" });
183077
- } else {
183078
- throw new Error("Could not detect Linux certificate trust mechanism");
183589
+ return [
183590
+ `cp "${certPath}" /etc/pki/ca-trust/source/anchors/specific-local-ca.crt`,
183591
+ "update-ca-trust extract"
183592
+ ];
183079
183593
  }
183080
- } else {
183081
- throw new Error(`Unsupported platform: ${platform4}`);
183594
+ throw new Error("Could not detect Linux certificate trust mechanism");
183082
183595
  }
183596
+ throw new Error(`Unsupported platform: ${platform5}`);
183083
183597
  }
183084
183598
  function generateCertificate(domain, keys = []) {
183085
183599
  const caDir = getCADir();
@@ -183118,139 +183632,52 @@ function generateCertificate(domain, keys = []) {
183118
183632
  };
183119
183633
  }
183120
183634
 
183121
- // src/lib/analytics/index.ts
183122
- import { PostHog } from "posthog-node";
183123
- import * as os5 from "os";
183124
- import * as crypto from "crypto";
183125
-
183126
- // src/lib/project/config.ts
183635
+ // src/lib/dev/resolver-config.ts
183127
183636
  import * as fs2 from "fs";
183128
- import * as path2 from "path";
183129
- var PROJECT_ID_FILE = ".specific/project_id";
183130
- var ProjectNotLinkedError = class extends Error {
183131
- constructor() {
183132
- super(
183133
- `Project not linked to Specific.
183134
-
183135
- The file ${PROJECT_ID_FILE} does not exist.
183136
-
183137
- Run: specific deploy`
183138
- );
183139
- this.name = "ProjectNotLinkedError";
183140
- }
183141
- };
183142
- function readProjectId(projectDir = process.cwd()) {
183143
- const projectIdPath = path2.join(projectDir, PROJECT_ID_FILE);
183144
- if (!fs2.existsSync(projectIdPath)) {
183145
- throw new ProjectNotLinkedError();
183146
- }
183147
- const projectId = fs2.readFileSync(projectIdPath, "utf-8").trim();
183148
- if (!projectId) {
183149
- throw new Error(`${PROJECT_ID_FILE} is empty`);
183150
- }
183151
- return projectId;
183152
- }
183153
- function hasProjectId(projectDir = process.cwd()) {
183154
- const projectIdPath = path2.join(projectDir, PROJECT_ID_FILE);
183155
- return fs2.existsSync(projectIdPath);
183156
- }
183157
- function writeProjectId(projectId, projectDir = process.cwd()) {
183158
- const specificDir = path2.join(projectDir, ".specific");
183159
- if (!fs2.existsSync(specificDir)) {
183160
- fs2.mkdirSync(specificDir, { recursive: true });
183161
- }
183162
- fs2.writeFileSync(path2.join(specificDir, "project_id"), projectId + "\n");
183163
- }
183164
-
183165
- // src/lib/auth/credentials.ts
183166
- import * as fs9 from "fs";
183167
- import * as path5 from "path";
183168
- import * as os4 from "os";
183169
-
183170
- // src/lib/auth/errors.ts
183171
- var RefreshTokenExpiredError = class extends Error {
183172
- constructor(originalError) {
183173
- super("Session expired due to inactivity. Please log in again.");
183174
- this.originalError = originalError;
183175
- this.name = "RefreshTokenExpiredError";
183176
- }
183177
- };
183178
-
183179
- // src/lib/auth/workos.ts
183180
- var WORKOS_CLIENT_ID = "client_01K4HSP8CE0R73V7Z67WE9CC86";
183181
- async function initiateDeviceAuthorization() {
183182
- const response = await fetch(
183183
- "https://api.workos.com/user_management/authorize/device",
183184
- {
183185
- method: "POST",
183186
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
183187
- body: new URLSearchParams({ client_id: WORKOS_CLIENT_ID })
183188
- }
183189
- );
183190
- if (!response.ok) {
183191
- const error = await response.text();
183192
- throw new Error(`Failed to initiate device authorization: ${error}`);
183637
+ import * as os2 from "os";
183638
+ var RESOLVER_FILE_MACOS = "/etc/resolver/local.spcf.app";
183639
+ var RESOLVER_FILE_LINUX = "/etc/systemd/resolved.conf.d/specific-local.conf";
183640
+ function resolverConfigExists() {
183641
+ const platform5 = os2.platform();
183642
+ if (platform5 === "darwin") {
183643
+ return fs2.existsSync(RESOLVER_FILE_MACOS);
183644
+ } else if (platform5 === "linux") {
183645
+ return fs2.existsSync(RESOLVER_FILE_LINUX);
183193
183646
  }
183194
- return response.json();
183195
- }
183196
- async function pollForToken(deviceCode) {
183197
- const response = await fetch(
183198
- "https://api.workos.com/user_management/authenticate",
183199
- {
183200
- method: "POST",
183201
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
183202
- body: new URLSearchParams({
183203
- client_id: WORKOS_CLIENT_ID,
183204
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
183205
- device_code: deviceCode
183206
- })
183207
- }
183208
- );
183209
- const data = await response.json();
183210
- return data;
183647
+ return false;
183211
183648
  }
183212
- async function refreshAccessToken(refreshToken) {
183213
- const response = await fetch(
183214
- "https://api.workos.com/user_management/authenticate",
183215
- {
183216
- method: "POST",
183217
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
183218
- body: new URLSearchParams({
183219
- client_id: WORKOS_CLIENT_ID,
183220
- grant_type: "refresh_token",
183221
- refresh_token: refreshToken
183222
- })
183223
- }
183224
- );
183225
- if (!response.ok) {
183226
- const errorText = await response.text();
183227
- try {
183228
- const errorJson = JSON.parse(errorText);
183229
- if (errorJson.error === "invalid_grant") {
183230
- throw new RefreshTokenExpiredError(errorJson.error_description);
183231
- }
183232
- } catch (e) {
183233
- if (e instanceof RefreshTokenExpiredError) throw e;
183649
+ function getResolverInstallCommands(port) {
183650
+ const platform5 = os2.platform();
183651
+ if (platform5 === "darwin") {
183652
+ return [
183653
+ "mkdir -p /etc/resolver",
183654
+ `printf "nameserver 127.0.0.1\\nport ${port}\\n" > ${RESOLVER_FILE_MACOS}`
183655
+ ];
183656
+ } else if (platform5 === "linux") {
183657
+ if (fs2.existsSync("/etc/systemd/resolved.conf.d") || fs2.existsSync("/etc/systemd")) {
183658
+ return [
183659
+ "mkdir -p /etc/systemd/resolved.conf.d",
183660
+ `printf "[Resolve]\\nDNS=127.0.0.1:${port}\\nDomains=~local.spcf.app\\n" > ${RESOLVER_FILE_LINUX}`,
183661
+ "systemctl restart systemd-resolved"
183662
+ ];
183234
183663
  }
183235
- throw new Error(`Failed to refresh token: ${errorText}`);
183664
+ return [];
183236
183665
  }
183237
- return response.json();
183666
+ return [];
183238
183667
  }
183239
183668
 
183240
- // src/lib/auth/login.tsx
183241
- import React from "react";
183242
- import { render, Box, Text } from "ink";
183243
- import Spinner from "ink-spinner";
183669
+ // src/lib/dev/dns-server.ts
183670
+ import DNS from "dns2";
183244
183671
 
183245
183672
  // src/lib/dev/debug-logger.ts
183246
183673
  import * as fs3 from "fs";
183247
- import * as os2 from "os";
183248
- import * as path3 from "path";
183674
+ import * as os3 from "os";
183675
+ import * as path2 from "path";
183249
183676
  var DEBUG_LOG_PATH = ".specific/debug.log";
183250
183677
  var logStream = null;
183251
183678
  function writeLog(source, message) {
183252
- const logPath = path3.join(os2.homedir(), DEBUG_LOG_PATH);
183253
- fs3.mkdirSync(path3.dirname(logPath), { recursive: true });
183679
+ const logPath = path2.join(os3.homedir(), DEBUG_LOG_PATH);
183680
+ fs3.mkdirSync(path2.dirname(logPath), { recursive: true });
183254
183681
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
183255
183682
  const line = message.endsWith("\n") ? message : message + "\n";
183256
183683
  fs3.appendFileSync(logPath, `[${timestamp}] [${source}] ${line}`);
@@ -183284,6 +183711,201 @@ function closeDebugLog() {
183284
183711
  }
183285
183712
  }
183286
183713
 
183714
+ // src/lib/dev/dns-server.ts
183715
+ var DNS_PORT = 15353;
183716
+ async function startDnsServer(port = DNS_PORT) {
183717
+ const server = DNS.createServer({
183718
+ udp: true,
183719
+ handle: (request, send) => {
183720
+ const response = DNS.Packet.createResponseFromRequest(request);
183721
+ for (const question of request.questions) {
183722
+ if (question.type === DNS.Packet.TYPE.A) {
183723
+ response.answers.push({
183724
+ name: question.name,
183725
+ type: DNS.Packet.TYPE.A,
183726
+ class: DNS.Packet.CLASS.IN,
183727
+ ttl: 300,
183728
+ address: "127.0.0.1"
183729
+ });
183730
+ }
183731
+ }
183732
+ send(response);
183733
+ }
183734
+ });
183735
+ await server.listen({
183736
+ udp: { port, address: "127.0.0.1" }
183737
+ });
183738
+ writeLog("dns", `DNS server started on 127.0.0.1:${port}`);
183739
+ return {
183740
+ port,
183741
+ async stop() {
183742
+ await server.close();
183743
+ writeLog("dns", "DNS server stopped");
183744
+ }
183745
+ };
183746
+ }
183747
+
183748
+ // src/lib/dev/system-setup.ts
183749
+ import * as path3 from "path";
183750
+ function systemSetupNeeded() {
183751
+ return !caInstalledInTrustStore() || !resolverConfigExists();
183752
+ }
183753
+ function performSystemSetup() {
183754
+ const needsGenerate = !caFilesExist();
183755
+ const needsInstallCA = !caInstalledInTrustStore();
183756
+ const needsResolver = !resolverConfigExists();
183757
+ if (!needsInstallCA && !needsResolver) {
183758
+ return;
183759
+ }
183760
+ if (needsGenerate) {
183761
+ const { key, cert } = generateRootCA();
183762
+ saveCA(key, cert);
183763
+ }
183764
+ const certPath = path3.join(getCADir(), "ca.crt");
183765
+ const commands = [];
183766
+ if (needsInstallCA) {
183767
+ commands.push(...getCAInstallCommands(certPath));
183768
+ }
183769
+ if (needsResolver) {
183770
+ commands.push(...getResolverInstallCommands(DNS_PORT));
183771
+ }
183772
+ if (commands.length === 0) {
183773
+ return;
183774
+ }
183775
+ try {
183776
+ execSync2(`sudo sh -c '${commands.join(" && ")}'`, { stdio: "inherit" });
183777
+ } catch (err) {
183778
+ if (needsGenerate) {
183779
+ removeCA();
183780
+ }
183781
+ throw err;
183782
+ }
183783
+ }
183784
+
183785
+ // src/lib/analytics/index.ts
183786
+ import { PostHog } from "posthog-node";
183787
+ import * as os6 from "os";
183788
+ import * as crypto from "crypto";
183789
+
183790
+ // src/lib/project/config.ts
183791
+ import * as fs4 from "fs";
183792
+ import * as path4 from "path";
183793
+ var PROJECT_ID_FILE = ".specific/project_id";
183794
+ var ProjectNotLinkedError = class extends Error {
183795
+ constructor() {
183796
+ super(
183797
+ `Project not linked to Specific.
183798
+
183799
+ The file ${PROJECT_ID_FILE} does not exist.
183800
+
183801
+ Run: specific deploy`
183802
+ );
183803
+ this.name = "ProjectNotLinkedError";
183804
+ }
183805
+ };
183806
+ function readProjectId(projectDir = process.cwd()) {
183807
+ const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
183808
+ if (!fs4.existsSync(projectIdPath)) {
183809
+ throw new ProjectNotLinkedError();
183810
+ }
183811
+ const projectId = fs4.readFileSync(projectIdPath, "utf-8").trim();
183812
+ if (!projectId) {
183813
+ throw new Error(`${PROJECT_ID_FILE} is empty`);
183814
+ }
183815
+ return projectId;
183816
+ }
183817
+ function hasProjectId(projectDir = process.cwd()) {
183818
+ const projectIdPath = path4.join(projectDir, PROJECT_ID_FILE);
183819
+ return fs4.existsSync(projectIdPath);
183820
+ }
183821
+ function writeProjectId(projectId, projectDir = process.cwd()) {
183822
+ const specificDir = path4.join(projectDir, ".specific");
183823
+ if (!fs4.existsSync(specificDir)) {
183824
+ fs4.mkdirSync(specificDir, { recursive: true });
183825
+ }
183826
+ fs4.writeFileSync(path4.join(specificDir, "project_id"), projectId + "\n");
183827
+ }
183828
+
183829
+ // src/lib/auth/credentials.ts
183830
+ import * as fs10 from "fs";
183831
+ import * as path6 from "path";
183832
+ import * as os5 from "os";
183833
+
183834
+ // src/lib/auth/errors.ts
183835
+ var RefreshTokenExpiredError = class extends Error {
183836
+ constructor(originalError) {
183837
+ super("Session expired due to inactivity. Please log in again.");
183838
+ this.originalError = originalError;
183839
+ this.name = "RefreshTokenExpiredError";
183840
+ }
183841
+ };
183842
+
183843
+ // src/lib/auth/workos.ts
183844
+ var WORKOS_CLIENT_ID = "client_01K4HSP8CE0R73V7Z67WE9CC86";
183845
+ async function initiateDeviceAuthorization() {
183846
+ const response = await fetch(
183847
+ "https://api.workos.com/user_management/authorize/device",
183848
+ {
183849
+ method: "POST",
183850
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
183851
+ body: new URLSearchParams({ client_id: WORKOS_CLIENT_ID })
183852
+ }
183853
+ );
183854
+ if (!response.ok) {
183855
+ const error = await response.text();
183856
+ throw new Error(`Failed to initiate device authorization: ${error}`);
183857
+ }
183858
+ return response.json();
183859
+ }
183860
+ async function pollForToken(deviceCode) {
183861
+ const response = await fetch(
183862
+ "https://api.workos.com/user_management/authenticate",
183863
+ {
183864
+ method: "POST",
183865
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
183866
+ body: new URLSearchParams({
183867
+ client_id: WORKOS_CLIENT_ID,
183868
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
183869
+ device_code: deviceCode
183870
+ })
183871
+ }
183872
+ );
183873
+ const data = await response.json();
183874
+ return data;
183875
+ }
183876
+ async function refreshAccessToken(refreshToken) {
183877
+ const response = await fetch(
183878
+ "https://api.workos.com/user_management/authenticate",
183879
+ {
183880
+ method: "POST",
183881
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
183882
+ body: new URLSearchParams({
183883
+ client_id: WORKOS_CLIENT_ID,
183884
+ grant_type: "refresh_token",
183885
+ refresh_token: refreshToken
183886
+ })
183887
+ }
183888
+ );
183889
+ if (!response.ok) {
183890
+ const errorText = await response.text();
183891
+ try {
183892
+ const errorJson = JSON.parse(errorText);
183893
+ if (errorJson.error === "invalid_grant") {
183894
+ throw new RefreshTokenExpiredError(errorJson.error_description);
183895
+ }
183896
+ } catch (e) {
183897
+ if (e instanceof RefreshTokenExpiredError) throw e;
183898
+ }
183899
+ throw new Error(`Failed to refresh token: ${errorText}`);
183900
+ }
183901
+ return response.json();
183902
+ }
183903
+
183904
+ // src/lib/auth/login.tsx
183905
+ import React from "react";
183906
+ import { render, Box, Text } from "ink";
183907
+ import Spinner from "ink-spinner";
183908
+
183287
183909
  // src/lib/api/client.ts
183288
183910
  var ApiClient = class {
183289
183911
  baseUrl;
@@ -183756,18 +184378,18 @@ function performLogin(options2 = {}) {
183756
184378
 
183757
184379
  // src/lib/auth/credentials.ts
183758
184380
  function getUserCredentialsDir() {
183759
- return path5.join(os4.homedir(), ".specific");
184381
+ return path6.join(os5.homedir(), ".specific");
183760
184382
  }
183761
184383
  function getCredentialsPath() {
183762
- return path5.join(getUserCredentialsDir(), "credentials.json");
184384
+ return path6.join(getUserCredentialsDir(), "credentials.json");
183763
184385
  }
183764
184386
  function readUserCredentials() {
183765
184387
  const credentialsPath = getCredentialsPath();
183766
- if (!fs9.existsSync(credentialsPath)) {
184388
+ if (!fs10.existsSync(credentialsPath)) {
183767
184389
  return null;
183768
184390
  }
183769
184391
  try {
183770
- const content = fs9.readFileSync(credentialsPath, "utf-8");
184392
+ const content = fs10.readFileSync(credentialsPath, "utf-8");
183771
184393
  return JSON.parse(content);
183772
184394
  } catch {
183773
184395
  return null;
@@ -183775,18 +184397,18 @@ function readUserCredentials() {
183775
184397
  }
183776
184398
  function writeUserCredentials(credentials) {
183777
184399
  const dir = getUserCredentialsDir();
183778
- if (!fs9.existsSync(dir)) {
183779
- fs9.mkdirSync(dir, { recursive: true, mode: 448 });
184400
+ if (!fs10.existsSync(dir)) {
184401
+ fs10.mkdirSync(dir, { recursive: true, mode: 448 });
183780
184402
  }
183781
184403
  const credentialsPath = getCredentialsPath();
183782
- fs9.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
184404
+ fs10.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
183783
184405
  mode: 384
183784
184406
  });
183785
184407
  }
183786
184408
  function clearUserCredentials() {
183787
184409
  const credentialsPath = getCredentialsPath();
183788
- if (fs9.existsSync(credentialsPath)) {
183789
- fs9.unlinkSync(credentialsPath);
184410
+ if (fs10.existsSync(credentialsPath)) {
184411
+ fs10.unlinkSync(credentialsPath);
183790
184412
  }
183791
184413
  }
183792
184414
  function isLoggedIn() {
@@ -183840,7 +184462,7 @@ function isEnabled() {
183840
184462
  }
183841
184463
  function getAnonymousId() {
183842
184464
  if (anonymousId) return anonymousId;
183843
- const machineId = `${os5.hostname()}-${os5.userInfo().username}`;
184465
+ const machineId = `${os6.hostname()}-${os6.userInfo().username}`;
183844
184466
  anonymousId = crypto.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
183845
184467
  return anonymousId;
183846
184468
  }
@@ -183873,7 +184495,7 @@ function trackEvent(event, properties) {
183873
184495
  event,
183874
184496
  properties: {
183875
184497
  ...properties,
183876
- cli_version: "0.1.61",
184498
+ cli_version: "0.1.63",
183877
184499
  platform: process.platform,
183878
184500
  node_version: process.version,
183879
184501
  project_id: getProjectId(),
@@ -183910,67 +184532,67 @@ var options = [
183910
184532
  { id: "other", label: "Other / Manual" }
183911
184533
  ];
183912
184534
  function isGitProject() {
183913
- const gitPath = path6.join(process.cwd(), ".git");
183914
- return fs10.existsSync(gitPath);
184535
+ const gitPath = path7.join(process.cwd(), ".git");
184536
+ return fs11.existsSync(gitPath);
183915
184537
  }
183916
184538
  function detectExistingAgents() {
183917
184539
  const detected = {};
183918
- const cursorDir = path6.join(process.cwd(), ".cursor");
183919
- if (fs10.existsSync(cursorDir)) {
184540
+ const cursorDir = path7.join(process.cwd(), ".cursor");
184541
+ if (fs11.existsSync(cursorDir)) {
183920
184542
  detected["cursor"] = true;
183921
184543
  }
183922
- const claudeDir = path6.join(process.cwd(), ".claude");
183923
- const claudeMd = path6.join(process.cwd(), "CLAUDE.md");
183924
- if (fs10.existsSync(claudeDir) || fs10.existsSync(claudeMd)) {
184544
+ const claudeDir = path7.join(process.cwd(), ".claude");
184545
+ const claudeMd = path7.join(process.cwd(), "CLAUDE.md");
184546
+ if (fs11.existsSync(claudeDir) || fs11.existsSync(claudeMd)) {
183925
184547
  detected["claude"] = true;
183926
184548
  }
183927
- const agentsMd = path6.join(process.cwd(), "AGENTS.md");
183928
- if (fs10.existsSync(agentsMd)) {
184549
+ const agentsMd = path7.join(process.cwd(), "AGENTS.md");
184550
+ if (fs11.existsSync(agentsMd)) {
183929
184551
  detected["codex"] = true;
183930
184552
  }
183931
184553
  return detected;
183932
184554
  }
183933
184555
  function appendOrCreateFile(filePath, content) {
183934
- if (fs10.existsSync(filePath)) {
183935
- const existing = fs10.readFileSync(filePath, "utf-8");
184556
+ if (fs11.existsSync(filePath)) {
184557
+ const existing = fs11.readFileSync(filePath, "utf-8");
183936
184558
  if (existing.includes("specific docs") || existing.includes("specific check")) {
183937
184559
  return "unchanged";
183938
184560
  }
183939
184561
  const separator = existing.endsWith("\n") ? "\n" : "\n\n";
183940
- fs10.writeFileSync(filePath, existing + separator + content + "\n");
184562
+ fs11.writeFileSync(filePath, existing + separator + content + "\n");
183941
184563
  return "modified";
183942
184564
  } else {
183943
- fs10.writeFileSync(filePath, content + "\n");
184565
+ fs11.writeFileSync(filePath, content + "\n");
183944
184566
  return "created";
183945
184567
  }
183946
184568
  }
183947
184569
  function addToGitignore() {
183948
- const gitignorePath = path6.join(process.cwd(), ".gitignore");
184570
+ const gitignorePath = path7.join(process.cwd(), ".gitignore");
183949
184571
  const entries = [".specific", "specific.local"];
183950
- if (fs10.existsSync(gitignorePath)) {
183951
- const existing = fs10.readFileSync(gitignorePath, "utf-8");
184572
+ if (fs11.existsSync(gitignorePath)) {
184573
+ const existing = fs11.readFileSync(gitignorePath, "utf-8");
183952
184574
  const lines = existing.split("\n").map((l) => l.trim());
183953
184575
  const missingEntries = entries.filter((entry) => !lines.includes(entry));
183954
184576
  if (missingEntries.length === 0) {
183955
184577
  return "unchanged";
183956
184578
  }
183957
184579
  const separator = existing.endsWith("\n") ? "" : "\n";
183958
- fs10.writeFileSync(
184580
+ fs11.writeFileSync(
183959
184581
  gitignorePath,
183960
184582
  existing + separator + missingEntries.join("\n") + "\n"
183961
184583
  );
183962
184584
  return "modified";
183963
184585
  } else {
183964
- fs10.writeFileSync(gitignorePath, entries.join("\n") + "\n");
184586
+ fs11.writeFileSync(gitignorePath, entries.join("\n") + "\n");
183965
184587
  return "created";
183966
184588
  }
183967
184589
  }
183968
184590
  function configureClaudeCodePermissions() {
183969
- const claudeDir = path6.join(process.cwd(), ".claude");
183970
- const settingsPath = path6.join(claudeDir, "settings.local.json");
184591
+ const claudeDir = path7.join(process.cwd(), ".claude");
184592
+ const settingsPath = path7.join(claudeDir, "settings.local.json");
183971
184593
  const permissions = ["Bash(specific docs:*)", "Bash(specific check:*)"];
183972
- if (fs10.existsSync(settingsPath)) {
183973
- const existing = JSON.parse(fs10.readFileSync(settingsPath, "utf-8"));
184594
+ if (fs11.existsSync(settingsPath)) {
184595
+ const existing = JSON.parse(fs11.readFileSync(settingsPath, "utf-8"));
183974
184596
  const allowList = existing?.permissions?.allow || [];
183975
184597
  const missingPermissions = permissions.filter(
183976
184598
  (p) => !allowList.includes(p)
@@ -183985,39 +184607,39 @@ function configureClaudeCodePermissions() {
183985
184607
  existing.permissions.allow = [];
183986
184608
  }
183987
184609
  existing.permissions.allow.push(...missingPermissions);
183988
- fs10.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
184610
+ fs11.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n");
183989
184611
  return "modified";
183990
184612
  }
183991
- if (!fs10.existsSync(claudeDir)) {
183992
- fs10.mkdirSync(claudeDir);
184613
+ if (!fs11.existsSync(claudeDir)) {
184614
+ fs11.mkdirSync(claudeDir);
183993
184615
  }
183994
184616
  const settings = {
183995
184617
  permissions: {
183996
184618
  allow: permissions
183997
184619
  }
183998
184620
  };
183999
- fs10.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
184621
+ fs11.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
184000
184622
  return "created";
184001
184623
  }
184002
184624
  function createCursorRule() {
184003
- const cursorDir = path6.join(process.cwd(), ".cursor");
184004
- const rulesDir = path6.join(cursorDir, "rules");
184005
- const mdcPath = path6.join(rulesDir, "specific.mdc");
184006
- if (fs10.existsSync(mdcPath)) {
184007
- const existing = fs10.readFileSync(mdcPath, "utf-8");
184625
+ const cursorDir = path7.join(process.cwd(), ".cursor");
184626
+ const rulesDir = path7.join(cursorDir, "rules");
184627
+ const mdcPath = path7.join(rulesDir, "specific.mdc");
184628
+ if (fs11.existsSync(mdcPath)) {
184629
+ const existing = fs11.readFileSync(mdcPath, "utf-8");
184008
184630
  if (existing.includes("specific docs") || existing.includes("specific check")) {
184009
184631
  return "unchanged";
184010
184632
  }
184011
- fs10.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184633
+ fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184012
184634
  return "modified";
184013
184635
  }
184014
- if (!fs10.existsSync(cursorDir)) {
184015
- fs10.mkdirSync(cursorDir);
184636
+ if (!fs11.existsSync(cursorDir)) {
184637
+ fs11.mkdirSync(cursorDir);
184016
184638
  }
184017
- if (!fs10.existsSync(rulesDir)) {
184018
- fs10.mkdirSync(rulesDir);
184639
+ if (!fs11.existsSync(rulesDir)) {
184640
+ fs11.mkdirSync(rulesDir);
184019
184641
  }
184020
- fs10.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184642
+ fs11.writeFileSync(mdcPath, CURSOR_MDC_CONTENT);
184021
184643
  return "created";
184022
184644
  }
184023
184645
  function configureAgents(checked) {
@@ -184033,7 +184655,7 @@ function configureAgents(checked) {
184033
184655
  agents.filesModified.push(".cursor/rules/specific.mdc");
184034
184656
  }
184035
184657
  if (checked["claude"]) {
184036
- const claudeMdPath = path6.join(process.cwd(), "CLAUDE.md");
184658
+ const claudeMdPath = path7.join(process.cwd(), "CLAUDE.md");
184037
184659
  const status = appendOrCreateFile(claudeMdPath, SPECIFIC_INSTRUCTIONS);
184038
184660
  if (status === "created") agents.filesCreated.push("CLAUDE.md");
184039
184661
  else if (status === "modified") agents.filesModified.push("CLAUDE.md");
@@ -184044,7 +184666,7 @@ function configureAgents(checked) {
184044
184666
  agents.filesModified.push(".claude/settings.local.json");
184045
184667
  }
184046
184668
  if (checked["codex"]) {
184047
- const agentsMdPath = path6.join(process.cwd(), "AGENTS.md");
184669
+ const agentsMdPath = path7.join(process.cwd(), "AGENTS.md");
184048
184670
  const status = appendOrCreateFile(agentsMdPath, SPECIFIC_INSTRUCTIONS);
184049
184671
  if (status === "created") agents.filesCreated.push("AGENTS.md");
184050
184672
  else if (status === "modified") agents.filesModified.push("AGENTS.md");
@@ -184070,16 +184692,16 @@ function InitUI() {
184070
184692
  };
184071
184693
  });
184072
184694
  const [phase, setPhase] = useState(
184073
- () => caFilesExist() ? "agents" : "installing-ca"
184695
+ () => !systemSetupNeeded() ? "agents" : "installing-ca"
184074
184696
  );
184075
- const [caInstallPhase, setCaInstallPhase] = useState(() => caFilesExist() ? "done" : "installing");
184697
+ const [caInstallPhase, setCaInstallPhase] = useState(() => !systemSetupNeeded() ? "done" : "installing");
184076
184698
  const [focusedIndex, setFocusedIndex] = useState(initialState.focusedIndex);
184077
184699
  const [checked, setChecked] = useState(
184078
184700
  initialState.detected
184079
184701
  );
184080
184702
  const [result, setResult] = useState(null);
184081
184703
  const [tlsResult, setTlsResult] = useState(
184082
- caFilesExist() ? { status: "success" } : null
184704
+ !systemSetupNeeded() ? { status: "success" } : null
184083
184705
  );
184084
184706
  useEffect(() => {
184085
184707
  if (phase === "installing-ca" && caInstallPhase === "installing") {
@@ -184088,14 +184710,11 @@ function InitUI() {
184088
184710
  }, [phase, caInstallPhase]);
184089
184711
  async function installCA() {
184090
184712
  try {
184091
- const { key, cert } = generateRootCA();
184092
- const certPath = saveCA(key, cert);
184093
- installCAToTrustStore(certPath);
184713
+ performSystemSetup();
184094
184714
  setTlsResult({ status: "success" });
184095
184715
  setCaInstallPhase("done");
184096
184716
  setPhase("agents");
184097
184717
  } catch (err) {
184098
- removeCA();
184099
184718
  setTlsResult({
184100
184719
  status: "error",
184101
184720
  error: err instanceof Error ? err.message : String(err)
@@ -184136,16 +184755,16 @@ function InitUI() {
184136
184755
  }, [phase, exit]);
184137
184756
  if (phase === "installing-ca") {
184138
184757
  if (caInstallPhase === "installing") {
184139
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "TLS Certificate Setup"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Installing a local certificate authority (CA) to enable HTTPS"), /* @__PURE__ */ React2.createElement(Text2, null, "for local development. The CA is limited to Specific projects."), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Your password is required to add the CA to your system's trust store."), /* @__PURE__ */ React2.createElement(Text2, null, " "));
184758
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, "Local Development Setup"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Setting up TLS certificates and DNS resolution for local"), /* @__PURE__ */ React2.createElement(Text2, null, "development. This is a one-time setup for Specific projects."), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, "Your password is required to configure your system."), /* @__PURE__ */ React2.createElement(Text2, null, " "));
184140
184759
  }
184141
184760
  }
184142
184761
  if (phase === "done") {
184143
184762
  const selectedAgents = Object.entries(checked).filter(([, v]) => v).length;
184144
184763
  const agentChanges = result && (result.agents.filesCreated.length > 0 || result.agents.filesModified.length > 0);
184145
184764
  const gitChanges = result?.git && (result.git.filesCreated.length > 0 || result.git.filesModified.length > 0);
184146
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, tlsResult === null && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u25CF"), " Installing TLS certificates..."), tlsResult?.status === "success" && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS certificates installed"), tlsResult?.status === "error" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u2717"), " Failed to install TLS certificates"), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", tlsResult.error)), result && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Coding agents configured"), result.agents.filesCreated.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Created: ", result.agents.filesCreated.join(", ")), result.agents.filesModified.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Modified: ", result.agents.filesModified.join(", ")), !agentChanges && selectedAgents > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "No changes needed (files already configured)"), selectedAgents === 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " No agents selected")), result?.git && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Git configured"), result.git.filesCreated.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Created: ", result.git.filesCreated.join(", ")), result.git.filesModified.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Modified: ", result.git.filesModified.join(", ")), !gitChanges && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "No changes needed (.gitignore already configured)")), result?.showManualInstructions && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Manual configuration selected"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, " Add this to your agent's system prompt:"), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React2.createElement(Text2, null, SPECIFIC_INSTRUCTIONS), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, " ", "We also recommend allowing your agent to run `specific docs *`"), /* @__PURE__ */ React2.createElement(Text2, null, " and `specific check *` without confirmation.")));
184765
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, tlsResult === null && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u25CF"), " Setting up TLS and DNS..."), tlsResult?.status === "success" && /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS and DNS configured"), tlsResult?.status === "error" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u2717"), " Failed to set up TLS and DNS"), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", tlsResult.error)), result && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Coding agents configured"), result.agents.filesCreated.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Created: ", result.agents.filesCreated.join(", ")), result.agents.filesModified.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Modified: ", result.agents.filesModified.join(", ")), !agentChanges && selectedAgents > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "No changes needed (files already configured)"), selectedAgents === 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " No agents selected")), result?.git && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Git configured"), result.git.filesCreated.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Created: ", result.git.filesCreated.join(", ")), result.git.filesModified.length > 0 && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "Modified: ", result.git.filesModified.join(", ")), !gitChanges && /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " ", "No changes needed (.gitignore already configured)")), result?.showManualInstructions && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " Manual configuration selected"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, " Add this to your agent's system prompt:"), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React2.createElement(Text2, null, SPECIFIC_INSTRUCTIONS), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), /* @__PURE__ */ React2.createElement(Text2, null, " "), /* @__PURE__ */ React2.createElement(Text2, null, " ", "We also recommend allowing your agent to run `specific docs *`"), /* @__PURE__ */ React2.createElement(Text2, null, " and `specific check *` without confirmation.")));
184147
184766
  }
184148
- const tlsLine = tlsResult?.status === "success" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS certificates installed") : tlsResult?.status === "error" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u2717"), " TLS certificates failed", " ", /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "(", tlsResult.error, ")")) : null;
184767
+ const tlsLine = tlsResult?.status === "success" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "green" }, "\u2713"), " TLS and DNS configured") : tlsResult?.status === "error" ? /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u2717"), " TLS and DNS setup failed", " ", /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "(", tlsResult.error, ")")) : null;
184149
184768
  return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, tlsLine, /* @__PURE__ */ React2.createElement(Text2, null, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u25CF"), " Configure coding agents", " ", /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "(space to select)")), /* @__PURE__ */ React2.createElement(Text2, null, " "), options.map((option, index) => {
184150
184769
  const isFocused = focusedIndex === index;
184151
184770
  const isChecked = checked[option.id];
@@ -184216,9 +184835,9 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
184216
184835
  console.log(" No changes needed (.gitignore already configured)");
184217
184836
  }
184218
184837
  }
184219
- if (!caFilesExist()) {
184838
+ if (systemSetupNeeded()) {
184220
184839
  console.log(
184221
- "\u26A0 TLS certificates not installed (run `specific init` in a terminal to set up)"
184840
+ "\u26A0 TLS and DNS not configured (run `specific init` in a terminal to set up)"
184222
184841
  );
184223
184842
  }
184224
184843
  if (result.showManualInstructions) {
@@ -184235,8 +184854,8 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
184235
184854
  }
184236
184855
 
184237
184856
  // src/commands/docs.tsx
184238
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
184239
- import { join as join7, dirname as dirname2 } from "path";
184857
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
184858
+ import { join as join8, dirname as dirname2 } from "path";
184240
184859
  import { fileURLToPath as fileURLToPath2 } from "url";
184241
184860
 
184242
184861
  // src/lib/beta/registry.ts
@@ -184244,16 +184863,20 @@ var BETA_REGISTRY = [
184244
184863
  {
184245
184864
  name: "reshape",
184246
184865
  description: "Zero-downtime database schema migrations using Reshape"
184866
+ },
184867
+ {
184868
+ name: "temporal",
184869
+ description: "Managed Temporal workflow engine for durable workflows and background tasks"
184247
184870
  }
184248
184871
  ];
184249
184872
 
184250
184873
  // src/lib/beta/storage.ts
184251
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync5, mkdirSync as mkdirSync6 } from "fs";
184252
- import { join as join6 } from "path";
184874
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
184875
+ import { join as join7 } from "path";
184253
184876
  var BETAS_FILE = ".specific/betas.json";
184254
184877
  function loadEnabledBetas(projectDir = process.cwd()) {
184255
- const filePath = join6(projectDir, BETAS_FILE);
184256
- if (!existsSync5(filePath)) {
184878
+ const filePath = join7(projectDir, BETAS_FILE);
184879
+ if (!existsSync6(filePath)) {
184257
184880
  return [];
184258
184881
  }
184259
184882
  try {
@@ -184276,25 +184899,25 @@ function disableBeta(name, projectDir = process.cwd()) {
184276
184899
  saveBetas(enabled, projectDir);
184277
184900
  }
184278
184901
  function saveBetas(enabled, projectDir) {
184279
- const specificDir = join6(projectDir, ".specific");
184280
- if (!existsSync5(specificDir)) {
184902
+ const specificDir = join7(projectDir, ".specific");
184903
+ if (!existsSync6(specificDir)) {
184281
184904
  mkdirSync6(specificDir, { recursive: true });
184282
184905
  }
184283
184906
  const data = { enabled };
184284
184907
  writeFileSync5(
184285
- join6(projectDir, BETAS_FILE),
184908
+ join7(projectDir, BETAS_FILE),
184286
184909
  JSON.stringify(data, null, 2) + "\n"
184287
184910
  );
184288
184911
  }
184289
184912
 
184290
184913
  // src/commands/docs.tsx
184291
184914
  var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
184292
- var docsDir = join7(__dirname2, "docs");
184293
- function docsCommand(path26) {
184294
- const docPath = resolveDocPath(path26);
184915
+ var docsDir = join8(__dirname2, "docs");
184916
+ function docsCommand(path28) {
184917
+ const docPath = resolveDocPath(path28);
184295
184918
  if (!docPath) {
184296
184919
  console.error(
184297
- `Documentation not found: ${path26 || "index"}
184920
+ `Documentation not found: ${path28 || "index"}
184298
184921
 
184299
184922
  Run 'specific docs' to see available topics.`
184300
184923
  );
@@ -184313,17 +184936,17 @@ function filterBetaTags(content, enabledBetas) {
184313
184936
  }
184314
184937
  );
184315
184938
  }
184316
- function resolveDocPath(path26) {
184317
- if (!path26) {
184318
- const indexPath2 = join7(docsDir, "index.md");
184319
- return existsSync6(indexPath2) ? indexPath2 : null;
184939
+ function resolveDocPath(path28) {
184940
+ if (!path28) {
184941
+ const indexPath2 = join8(docsDir, "index.md");
184942
+ return existsSync7(indexPath2) ? indexPath2 : null;
184320
184943
  }
184321
- const directPath = join7(docsDir, `${path26}.md`);
184322
- if (existsSync6(directPath)) {
184944
+ const directPath = join8(docsDir, `${path28}.md`);
184945
+ if (existsSync7(directPath)) {
184323
184946
  return directPath;
184324
184947
  }
184325
- const indexPath = join7(docsDir, path26, "index.md");
184326
- if (existsSync6(indexPath)) {
184948
+ const indexPath = join8(docsDir, path28, "index.md");
184949
+ if (existsSync7(indexPath)) {
184327
184950
  return indexPath;
184328
184951
  }
184329
184952
  return null;
@@ -184333,8 +184956,8 @@ function resolveDocPath(path26) {
184333
184956
  import React3, { useState as useState2, useEffect as useEffect2 } from "react";
184334
184957
  import { render as render3, Text as Text3, Box as Box3 } from "ink";
184335
184958
  import Spinner3 from "ink-spinner";
184336
- import * as fs12 from "fs";
184337
- import * as path8 from "path";
184959
+ import * as fs13 from "fs";
184960
+ import * as path9 from "path";
184338
184961
  import { execFile as execFile7 } from "child_process";
184339
184962
 
184340
184963
  // node_modules/.pnpm/@specific+config@file+..+config/node_modules/@specific/config/dist/parser.js
@@ -184437,6 +185060,28 @@ function parseReferenceString(str) {
184437
185060
  };
184438
185061
  }
184439
185062
  }
185063
+ const temporalMatch = str.match(/^temporal\.(\w+)\.(\w+)$/);
185064
+ if (temporalMatch && temporalMatch[1] && temporalMatch[2]) {
185065
+ const attr = temporalMatch[2];
185066
+ if (["url", "namespace", "api_key"].includes(attr)) {
185067
+ return {
185068
+ type: "temporal",
185069
+ name: temporalMatch[1],
185070
+ attribute: attr
185071
+ };
185072
+ }
185073
+ }
185074
+ const volumeMatch = str.match(/^volume\.(\w+)\.(\w+)$/);
185075
+ if (volumeMatch && volumeMatch[1] && volumeMatch[2]) {
185076
+ const attr = volumeMatch[2];
185077
+ if (["path"].includes(attr)) {
185078
+ return {
185079
+ type: "volume",
185080
+ volumeName: volumeMatch[1],
185081
+ attribute: attr
185082
+ };
185083
+ }
185084
+ }
184440
185085
  const configMatch = str.match(/^config\.(\w+)$/);
184441
185086
  if (configMatch && configMatch[1]) {
184442
185087
  return { type: "config", name: configMatch[1] };
@@ -184547,16 +185192,31 @@ function parseBuilds(buildData) {
184547
185192
  }
184548
185193
  const fieldObj = fields;
184549
185194
  const base = fieldObj.base;
184550
- if (!base) {
184551
- throw new Error(`Build "${name}" is missing required field "base". Supported values: ${VALID_BASES.join(", ")}`);
185195
+ const dockerfile = fieldObj.dockerfile;
185196
+ if (base && dockerfile) {
185197
+ throw new Error(`Build "${name}" cannot have both "base" and "dockerfile". Use one or the other.`);
185198
+ }
185199
+ if (!base && !dockerfile) {
185200
+ throw new Error(`Build "${name}" must have either "base" (supported: ${VALID_BASES.join(", ")}) or "dockerfile" (path to a custom Dockerfile).`);
184552
185201
  }
184553
- if (typeof base !== "string" || !VALID_BASES.includes(base)) {
184554
- throw new Error(`Build "${name}" has invalid base "${base}". Supported values: ${VALID_BASES.join(", ")}`);
185202
+ if (base) {
185203
+ if (typeof base !== "string" || !VALID_BASES.includes(base)) {
185204
+ throw new Error(`Build "${name}" has invalid base "${base}". Supported values: ${VALID_BASES.join(", ")}`);
185205
+ }
185206
+ }
185207
+ if (dockerfile) {
185208
+ if (typeof dockerfile !== "string" || dockerfile.trim() === "") {
185209
+ throw new Error(`Build "${name}" has invalid "dockerfile" value. Must be a non-empty path string.`);
185210
+ }
185211
+ if (fieldObj.command) {
185212
+ throw new Error(`Build "${name}" cannot have both "dockerfile" and "command". When using a custom Dockerfile, the build steps are defined in the Dockerfile itself.`);
185213
+ }
184555
185214
  }
184556
185215
  const dev = parseDevBlock(fieldObj.dev);
184557
185216
  const build = {
184558
185217
  name,
184559
- base
185218
+ ...base ? { base } : {},
185219
+ ...dockerfile ? { dockerfile: String(dockerfile) } : {}
184560
185220
  };
184561
185221
  if (fieldObj.command) {
184562
185222
  build.command = String(fieldObj.command);
@@ -184645,6 +185305,22 @@ function parseEndpoints(fieldObj) {
184645
185305
  }
184646
185306
  return endpoints;
184647
185307
  }
185308
+ function parseVolumes(fieldObj) {
185309
+ const volumes = [];
185310
+ const volumeData = fieldObj.volume;
185311
+ if (!volumeData) {
185312
+ return volumes;
185313
+ }
185314
+ if (typeof volumeData !== "object") {
185315
+ return volumes;
185316
+ }
185317
+ if (!Array.isArray(volumeData)) {
185318
+ for (const [name] of Object.entries(volumeData)) {
185319
+ volumes.push({ name });
185320
+ }
185321
+ }
185322
+ return volumes;
185323
+ }
184648
185324
  function parseServices(serviceData) {
184649
185325
  if (!serviceData || typeof serviceData !== "object" || Array.isArray(serviceData)) {
184650
185326
  return [];
@@ -184668,6 +185344,10 @@ function parseServices(serviceData) {
184668
185344
  service.root = String(fieldObj.root);
184669
185345
  }
184670
185346
  const endpoints = parseEndpoints(fieldObj);
185347
+ const volumes = parseVolumes(fieldObj);
185348
+ if (volumes.length > 0) {
185349
+ service.volumes = volumes;
185350
+ }
184671
185351
  if (fieldObj.expose !== void 0) {
184672
185352
  service.expose = {};
184673
185353
  if (endpoints.length === 0) {
@@ -184761,6 +185441,16 @@ function parseStorage(data) {
184761
185441
  }
184762
185442
  return result;
184763
185443
  }
185444
+ function parseTemporal(data) {
185445
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
185446
+ return [];
185447
+ }
185448
+ const result = [];
185449
+ for (const [name] of Object.entries(data)) {
185450
+ result.push({ name });
185451
+ }
185452
+ return result;
185453
+ }
184764
185454
  function parseConfigDevBlock(dev) {
184765
185455
  if (!dev) {
184766
185456
  return void 0;
@@ -184872,6 +185562,7 @@ async function parseConfig(hcl) {
184872
185562
  postgres: parsePostgres(json.postgres),
184873
185563
  redis: parseRedis(json.redis),
184874
185564
  storage: parseStorage(json.storage),
185565
+ temporal: parseTemporal(json.temporal),
184875
185566
  configs: parseConfigs(json.config),
184876
185567
  secrets: parseSecrets(json.secret),
184877
185568
  environments: parseEnvironments(json.environment)
@@ -184970,12 +185661,101 @@ function validateEndpointReferences(config) {
184970
185661
  });
184971
185662
  }
184972
185663
  }
185664
+ if (ref.type === "volume") {
185665
+ const volumeRef = ref;
185666
+ const volumeExists = service.volumes?.some((v) => v.name === volumeRef.volumeName);
185667
+ if (!volumeExists) {
185668
+ errors.push({
185669
+ service: service.name,
185670
+ message: `Service "${service.name}" references volume "${volumeRef.volumeName}" in env var "${key}", but that volume is not defined on this service.`
185671
+ });
185672
+ }
185673
+ }
184973
185674
  }
184974
185675
  }
184975
185676
  }
184976
185677
  return errors;
184977
185678
  }
184978
185679
 
185680
+ // node_modules/.pnpm/@specific+config@file+..+config/node_modules/@specific/config/dist/errors.js
185681
+ function parseHclErrors(rawError) {
185682
+ const raw = rawError.trim();
185683
+ if (!raw.startsWith("parse config: [")) {
185684
+ return [];
185685
+ }
185686
+ const inner = raw.slice("parse config: [".length, -1);
185687
+ const errors = [];
185688
+ const locationPattern = /:(\d+),(\d+)-(?:(\d+),)?(\d+):\s*/g;
185689
+ const locations = [];
185690
+ let match;
185691
+ while ((match = locationPattern.exec(inner)) !== null) {
185692
+ const line = parseInt(match[1], 10);
185693
+ const colStart = parseInt(match[2], 10);
185694
+ const endLine = match[3] ? parseInt(match[3], 10) : line;
185695
+ const colEnd = parseInt(match[4], 10);
185696
+ locations.push({
185697
+ index: match.index,
185698
+ line,
185699
+ colStart,
185700
+ endLine,
185701
+ colEnd,
185702
+ matchEnd: match.index + match[0].length
185703
+ });
185704
+ }
185705
+ for (let i = 0; i < locations.length; i++) {
185706
+ const loc = locations[i];
185707
+ const nextStart = locations[i + 1]?.index ?? inner.length;
185708
+ const messageText = inner.slice(loc.matchEnd, nextStart).trim();
185709
+ const semicolonIdx = messageText.indexOf(";");
185710
+ let title;
185711
+ let description;
185712
+ if (semicolonIdx !== -1) {
185713
+ title = messageText.slice(0, semicolonIdx).trim();
185714
+ description = messageText.slice(semicolonIdx + 1).trim();
185715
+ } else {
185716
+ title = messageText;
185717
+ description = "";
185718
+ }
185719
+ errors.push({
185720
+ line: loc.line,
185721
+ colStart: loc.colStart,
185722
+ endLine: loc.endLine,
185723
+ colEnd: loc.colEnd,
185724
+ title,
185725
+ description
185726
+ });
185727
+ }
185728
+ return errors;
185729
+ }
185730
+
185731
+ // src/lib/format-config-error.ts
185732
+ var import_code_frame = __toESM(require_lib2(), 1);
185733
+ function formatConfigError(err, fileContents, filePath) {
185734
+ const raw = err instanceof Error ? err.message : String(err);
185735
+ const errors = parseHclErrors(raw);
185736
+ if (errors.length === 0) {
185737
+ return `Error: Invalid configuration: ${raw}`;
185738
+ }
185739
+ const name = filePath ?? "specific.hcl";
185740
+ const header = errors.length === 1 ? `Error in ${name}:` : `${errors.length} errors in ${name}:`;
185741
+ const blocks = errors.map((e) => {
185742
+ const frame = (0, import_code_frame.codeFrameColumns)(
185743
+ fileContents,
185744
+ {
185745
+ start: { line: e.line, column: e.colStart },
185746
+ end: { line: e.endLine, column: e.colEnd }
185747
+ },
185748
+ { highlightCode: false, message: e.description }
185749
+ );
185750
+ return ` ${e.title}
185751
+
185752
+ ${frame}`;
185753
+ });
185754
+ return `${header}
185755
+
185756
+ ${blocks.join("\n\n")}`;
185757
+ }
185758
+
184979
185759
  // src/lib/bin/types.ts
184980
185760
  var BinaryNotFoundError = class extends Error {
184981
185761
  constructor(binaryName, version, platformInfo) {
@@ -185011,32 +185791,32 @@ var ExtractionError = class extends Error {
185011
185791
  };
185012
185792
 
185013
185793
  // src/lib/bin/manager.ts
185014
- import * as fs11 from "fs";
185015
- import * as path7 from "path";
185016
- import * as os6 from "os";
185794
+ import * as fs12 from "fs";
185795
+ import * as path8 from "path";
185796
+ import * as os7 from "os";
185017
185797
  import { createReadStream } from "fs";
185018
185798
  import { createTarExtractor, extractTo } from "tar-vern";
185019
185799
  function getLibraryEnv(binary) {
185020
185800
  if (!binary.libraryPath) {
185021
185801
  return {};
185022
185802
  }
185023
- const platform4 = os6.platform();
185024
- if (platform4 === "darwin") {
185803
+ const platform5 = os7.platform();
185804
+ if (platform5 === "darwin") {
185025
185805
  return { DYLD_LIBRARY_PATH: binary.libraryPath };
185026
- } else if (platform4 === "linux") {
185806
+ } else if (platform5 === "linux") {
185027
185807
  return { LD_LIBRARY_PATH: binary.libraryPath };
185028
185808
  }
185029
185809
  return {};
185030
185810
  }
185031
185811
  function getBinBaseDir() {
185032
- return path7.join(os6.homedir(), ".specific", "bin");
185812
+ return path8.join(os7.homedir(), ".specific", "bin");
185033
185813
  }
185034
185814
  function getPlatformInfo() {
185035
- const platform4 = os6.platform();
185036
- const arch3 = os6.arch();
185037
- if (platform4 !== "darwin" && platform4 !== "linux") {
185815
+ const platform5 = os7.platform();
185816
+ const arch3 = os7.arch();
185817
+ if (platform5 !== "darwin" && platform5 !== "linux") {
185038
185818
  throw new Error(
185039
- `Unsupported platform: ${platform4}. Only macOS and Linux are supported.`
185819
+ `Unsupported platform: ${platform5}. Only macOS and Linux are supported.`
185040
185820
  );
185041
185821
  }
185042
185822
  const archStr = arch3;
@@ -185050,10 +185830,10 @@ function getPlatformInfo() {
185050
185830
  `Unsupported architecture: ${arch3}. Only x64 and arm64 are supported.`
185051
185831
  );
185052
185832
  }
185053
- return { platform: platform4, arch: mappedArch };
185833
+ return { platform: platform5, arch: mappedArch };
185054
185834
  }
185055
185835
  function getBinaryDir(definition, version, platformInfo) {
185056
- return path7.join(
185836
+ return path8.join(
185057
185837
  getBinBaseDir(),
185058
185838
  definition.name,
185059
185839
  version,
@@ -185063,8 +185843,8 @@ function getBinaryDir(definition, version, platformInfo) {
185063
185843
  function isBinaryInstalled(definition, version, platformInfo) {
185064
185844
  const binDir = getBinaryDir(definition, version, platformInfo);
185065
185845
  for (const execPath of definition.executables) {
185066
- const fullPath = path7.join(binDir, execPath);
185067
- if (!fs11.existsSync(fullPath)) {
185846
+ const fullPath = path8.join(binDir, execPath);
185847
+ if (!fs12.existsSync(fullPath)) {
185068
185848
  return false;
185069
185849
  }
185070
185850
  }
@@ -185092,12 +185872,12 @@ async function downloadFile(url, destPath, onProgress) {
185092
185872
  10
185093
185873
  );
185094
185874
  let bytesDownloaded = 0;
185095
- const parentDir = path7.dirname(destPath);
185096
- if (!fs11.existsSync(parentDir)) {
185097
- fs11.mkdirSync(parentDir, { recursive: true });
185875
+ const parentDir = path8.dirname(destPath);
185876
+ if (!fs12.existsSync(parentDir)) {
185877
+ fs12.mkdirSync(parentDir, { recursive: true });
185098
185878
  }
185099
185879
  const partPath = destPath + ".part";
185100
- const fileStream = fs11.createWriteStream(partPath);
185880
+ const fileStream = fs12.createWriteStream(partPath);
185101
185881
  try {
185102
185882
  const reader = response.body.getReader();
185103
185883
  while (true) {
@@ -185120,12 +185900,12 @@ async function downloadFile(url, destPath, onProgress) {
185120
185900
  else resolve10();
185121
185901
  });
185122
185902
  });
185123
- fs11.renameSync(partPath, destPath);
185903
+ fs12.renameSync(partPath, destPath);
185124
185904
  } catch (error) {
185125
185905
  try {
185126
185906
  fileStream.close();
185127
- if (fs11.existsSync(partPath)) {
185128
- fs11.unlinkSync(partPath);
185907
+ if (fs12.existsSync(partPath)) {
185908
+ fs12.unlinkSync(partPath);
185129
185909
  }
185130
185910
  } catch {
185131
185911
  }
@@ -185134,8 +185914,8 @@ async function downloadFile(url, destPath, onProgress) {
185134
185914
  }
185135
185915
  async function extractTarball(archivePath, destDir, definition, onProgress) {
185136
185916
  onProgress?.({ phase: "extracting" });
185137
- if (!fs11.existsSync(destDir)) {
185138
- fs11.mkdirSync(destDir, { recursive: true });
185917
+ if (!fs12.existsSync(destDir)) {
185918
+ fs12.mkdirSync(destDir, { recursive: true });
185139
185919
  }
185140
185920
  try {
185141
185921
  const fileStream = createReadStream(archivePath);
@@ -185143,9 +185923,9 @@ async function extractTarball(archivePath, destDir, definition, onProgress) {
185143
185923
  await extractTo(entries, destDir);
185144
185924
  onProgress?.({ phase: "finalizing" });
185145
185925
  for (const execPath of definition.executables) {
185146
- const fullPath = path7.join(destDir, execPath);
185147
- if (fs11.existsSync(fullPath)) {
185148
- fs11.chmodSync(fullPath, 493);
185926
+ const fullPath = path8.join(destDir, execPath);
185927
+ if (fs12.existsSync(fullPath)) {
185928
+ fs12.chmodSync(fullPath, 493);
185149
185929
  }
185150
185930
  }
185151
185931
  } catch (error) {
@@ -185169,24 +185949,24 @@ async function ensureBinary(definition, version, onProgress) {
185169
185949
  `Binary type definitions must have exactly one executable, got ${definition.executables.length}`
185170
185950
  );
185171
185951
  }
185172
- if (!fs11.existsSync(binDir)) {
185173
- fs11.mkdirSync(binDir, { recursive: true });
185952
+ if (!fs12.existsSync(binDir)) {
185953
+ fs12.mkdirSync(binDir, { recursive: true });
185174
185954
  }
185175
- const execPath = path7.join(binDir, definition.executables[0]);
185955
+ const execPath = path8.join(binDir, definition.executables[0]);
185176
185956
  await downloadFile(url, execPath, onProgress);
185177
- fs11.chmodSync(execPath, 493);
185957
+ fs12.chmodSync(execPath, 493);
185178
185958
  onProgress?.({ phase: "finalizing" });
185179
185959
  } else {
185180
- const downloadDir = path7.join(getBinBaseDir(), "downloads");
185960
+ const downloadDir = path8.join(getBinBaseDir(), "downloads");
185181
185961
  const archiveName = `${definition.name}-${resolvedVersion}-${platformInfo.platform}-${platformInfo.arch}.tar.gz`;
185182
- const archivePath = path7.join(downloadDir, archiveName);
185962
+ const archivePath = path8.join(downloadDir, archiveName);
185183
185963
  try {
185184
185964
  await downloadFile(url, archivePath, onProgress);
185185
185965
  await extractTarball(archivePath, binDir, definition, onProgress);
185186
185966
  } finally {
185187
185967
  try {
185188
- if (fs11.existsSync(archivePath)) {
185189
- fs11.unlinkSync(archivePath);
185968
+ if (fs12.existsSync(archivePath)) {
185969
+ fs12.unlinkSync(archivePath);
185190
185970
  }
185191
185971
  } catch {
185192
185972
  }
@@ -185195,10 +185975,10 @@ async function ensureBinary(definition, version, onProgress) {
185195
185975
  }
185196
185976
  const executables = {};
185197
185977
  for (const execPath of definition.executables) {
185198
- const name = path7.basename(execPath);
185199
- executables[name] = path7.join(binDir, execPath);
185978
+ const name = path8.basename(execPath);
185979
+ executables[name] = path8.join(binDir, execPath);
185200
185980
  }
185201
- const libraryPath = definition.libraryDir ? path7.join(binDir, definition.libraryDir) : void 0;
185981
+ const libraryPath = definition.libraryDir ? path8.join(binDir, definition.libraryDir) : void 0;
185202
185982
  return {
185203
185983
  rootDir: binDir,
185204
185984
  version: resolvedVersion,
@@ -185319,6 +186099,25 @@ var reshapeBinary = {
185319
186099
  executables: ["reshape"]
185320
186100
  };
185321
186101
 
186102
+ // src/lib/bin/definitions/temporal.ts
186103
+ var temporalBinary = {
186104
+ name: "temporal",
186105
+ versions: ["1.3.0"],
186106
+ urlTemplate: "https://temporal.download/cli/archive/v{version}?platform={platform}&arch={arch}",
186107
+ platformMapping: {
186108
+ darwin: {
186109
+ arm64: { platform: "darwin", arch: "arm64" },
186110
+ x64: { platform: "darwin", arch: "amd64" }
186111
+ },
186112
+ linux: {
186113
+ arm64: { platform: "linux", arch: "arm64" },
186114
+ x64: { platform: "linux", arch: "amd64" }
186115
+ }
186116
+ },
186117
+ stripComponents: 0,
186118
+ executables: ["temporal"]
186119
+ };
186120
+
185322
186121
  // src/commands/check.tsx
185323
186122
  async function runReshapeCheck(migrationsDir) {
185324
186123
  try {
@@ -185342,25 +186141,37 @@ function CheckUI() {
185342
186141
  const [state, setState] = useState2({ status: "loading" });
185343
186142
  useEffect2(() => {
185344
186143
  async function load() {
185345
- const configPath = path8.join(process.cwd(), "specific.hcl");
185346
- if (!fs12.existsSync(configPath)) {
186144
+ const configPath = path9.join(process.cwd(), "specific.hcl");
186145
+ if (!fs13.existsSync(configPath)) {
185347
186146
  setState({
185348
186147
  status: "error",
185349
186148
  error: "No specific.hcl found in current directory"
185350
186149
  });
185351
186150
  return;
185352
186151
  }
186152
+ const hcl = fs13.readFileSync(configPath, "utf-8");
185353
186153
  try {
185354
- const hcl = fs12.readFileSync(configPath, "utf-8");
185355
186154
  const config2 = await parseConfig(hcl);
186155
+ for (const build of config2.builds) {
186156
+ if (build.dockerfile) {
186157
+ const dockerfilePath = path9.resolve(process.cwd(), build.dockerfile);
186158
+ if (!fs13.existsSync(dockerfilePath)) {
186159
+ setState({
186160
+ status: "error",
186161
+ error: `Build "${build.name}": Dockerfile not found at "${build.dockerfile}" (resolved to ${dockerfilePath})`
186162
+ });
186163
+ return;
186164
+ }
186165
+ }
186166
+ }
185356
186167
  const reshapeChecks2 = [];
185357
186168
  for (const pg of config2.postgres) {
185358
186169
  if (pg.reshape?.enabled) {
185359
- const migrationsDir = path8.resolve(
186170
+ const migrationsDir = path9.resolve(
185360
186171
  process.cwd(),
185361
186172
  pg.reshape.migrations_dir ?? "migrations"
185362
186173
  );
185363
- if (!fs12.existsSync(migrationsDir)) {
186174
+ if (!fs13.existsSync(migrationsDir)) {
185364
186175
  reshapeChecks2.push({
185365
186176
  databaseName: pg.name,
185366
186177
  migrationsDir: pg.reshape.migrations_dir ?? "migrations",
@@ -185384,7 +186195,7 @@ function CheckUI() {
185384
186195
  } catch (err) {
185385
186196
  setState({
185386
186197
  status: "error",
185387
- error: err instanceof Error ? err.message : String(err)
186198
+ error: formatConfigError(err, hcl, configPath)
185388
186199
  });
185389
186200
  }
185390
186201
  }
@@ -185394,7 +186205,7 @@ function CheckUI() {
185394
186205
  return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, /* @__PURE__ */ React3.createElement(Spinner3, { type: "dots" })), /* @__PURE__ */ React3.createElement(Text3, null, " Checking configuration..."));
185395
186206
  }
185396
186207
  if (state.status === "error") {
185397
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, "Error: ", state.error));
186208
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, state.error));
185398
186209
  }
185399
186210
  const { config } = state;
185400
186211
  if (!config) {
@@ -185403,7 +186214,7 @@ function CheckUI() {
185403
186214
  const reshapeChecks = state.reshapeChecks ?? [];
185404
186215
  const reshapeErrors = reshapeChecks.filter((r) => !r.success);
185405
186216
  const hasReshapeErrors = reshapeErrors.length > 0;
185406
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: hasReshapeErrors ? "yellow" : "green" }, hasReshapeErrors ? "Configuration is valid but reshape migrations have errors" : "Configuration is valid"), config.builds.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Builds (", config.builds.length, "):"), config.builds.map((b) => /* @__PURE__ */ React3.createElement(Text3, { key: b.name }, " ", "- ", b.name))), config.services.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Services (", config.services.length, "):"), config.services.map((s) => /* @__PURE__ */ React3.createElement(Text3, { key: s.name }, " ", "- ", s.name))), config.postgres.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Postgres (", config.postgres.length, "):"), config.postgres.map((p) => /* @__PURE__ */ React3.createElement(Text3, { key: p.name }, " ", "- ", p.name, p.reshape?.enabled ? " (reshape enabled)" : ""))), reshapeChecks.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Reshape Migrations:"), reshapeChecks.map((r) => /* @__PURE__ */ React3.createElement(Box3, { key: r.databaseName, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, null, " ", /* @__PURE__ */ React3.createElement(Text3, { color: r.success ? "green" : "red" }, r.success ? "pass" : "fail"), " ", r.databaseName, " (", r.migrationsDir, ")"), r.error && /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, " ", r.error)))), config.redis.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Redis (", config.redis.length, "):"), config.redis.map((r) => /* @__PURE__ */ React3.createElement(Text3, { key: r.name }, " ", "- ", r.name))), config.storage.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Storage (", config.storage.length, "):"), config.storage.map((s) => /* @__PURE__ */ React3.createElement(Text3, { key: s.name }, " ", "- ", s.name))), config.configs.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Config (", config.configs.length, "):"), config.configs.map((c) => /* @__PURE__ */ React3.createElement(Text3, { key: c.name }, " ", "- ", c.name, c.default ? ` (default: ${c.default})` : ""))), config.environments.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Environments (", config.environments.length, "):"), config.environments.map((e) => /* @__PURE__ */ React3.createElement(Text3, { key: e.name }, " ", "- ", e.name))));
186217
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: hasReshapeErrors ? "yellow" : "green" }, hasReshapeErrors ? "Configuration is valid but reshape migrations have errors" : "Configuration is valid"), config.builds.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Builds (", config.builds.length, "):"), config.builds.map((b) => /* @__PURE__ */ React3.createElement(Text3, { key: b.name }, " ", "- ", b.name, b.base ? ` (${b.base})` : "", b.dockerfile ? ` (dockerfile: ${b.dockerfile})` : ""))), config.services.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Services (", config.services.length, "):"), config.services.map((s) => /* @__PURE__ */ React3.createElement(Text3, { key: s.name }, " ", "- ", s.name))), config.postgres.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Postgres (", config.postgres.length, "):"), config.postgres.map((p) => /* @__PURE__ */ React3.createElement(Text3, { key: p.name }, " ", "- ", p.name, p.reshape?.enabled ? " (reshape enabled)" : ""))), reshapeChecks.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Reshape Migrations:"), reshapeChecks.map((r) => /* @__PURE__ */ React3.createElement(Box3, { key: r.databaseName, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, null, " ", /* @__PURE__ */ React3.createElement(Text3, { color: r.success ? "green" : "red" }, r.success ? "pass" : "fail"), " ", r.databaseName, " (", r.migrationsDir, ")"), r.error && /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, " ", r.error)))), config.redis.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Redis (", config.redis.length, "):"), config.redis.map((r) => /* @__PURE__ */ React3.createElement(Text3, { key: r.name }, " ", "- ", r.name))), config.storage.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Storage (", config.storage.length, "):"), config.storage.map((s) => /* @__PURE__ */ React3.createElement(Text3, { key: s.name }, " ", "- ", s.name))), config.configs.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Config (", config.configs.length, "):"), config.configs.map((c) => /* @__PURE__ */ React3.createElement(Text3, { key: c.name }, " ", "- ", c.name, c.default ? ` (default: ${c.default})` : ""))), config.environments.length > 0 && /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Environments (", config.environments.length, "):"), config.environments.map((e) => /* @__PURE__ */ React3.createElement(Text3, { key: e.name }, " ", "- ", e.name))));
185407
186218
  }
185408
186219
  function checkCommand() {
185409
186220
  render3(/* @__PURE__ */ React3.createElement(CheckUI, null));
@@ -185413,8 +186224,8 @@ function checkCommand() {
185413
186224
  import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
185414
186225
  import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
185415
186226
  import Spinner4 from "ink-spinner";
185416
- import * as fs21 from "fs";
185417
- import * as path18 from "path";
186227
+ import * as fs23 from "fs";
186228
+ import * as path20 from "path";
185418
186229
 
185419
186230
  // node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
185420
186231
  import { EventEmitter } from "node:events";
@@ -185506,7 +186317,7 @@ var ReaddirpStream = class extends Readable {
185506
186317
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
185507
186318
  const statMethod = opts.lstat ? lstat : stat;
185508
186319
  if (wantBigintFsStats) {
185509
- this._stat = (path26) => statMethod(path26, { bigint: true });
186320
+ this._stat = (path28) => statMethod(path28, { bigint: true });
185510
186321
  } else {
185511
186322
  this._stat = statMethod;
185512
186323
  }
@@ -185531,8 +186342,8 @@ var ReaddirpStream = class extends Readable {
185531
186342
  const par = this.parent;
185532
186343
  const fil = par && par.files;
185533
186344
  if (fil && fil.length > 0) {
185534
- const { path: path26, depth } = par;
185535
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path26));
186345
+ const { path: path28, depth } = par;
186346
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path28));
185536
186347
  const awaited = await Promise.all(slice);
185537
186348
  for (const entry of awaited) {
185538
186349
  if (!entry)
@@ -185572,20 +186383,20 @@ var ReaddirpStream = class extends Readable {
185572
186383
  this.reading = false;
185573
186384
  }
185574
186385
  }
185575
- async _exploreDir(path26, depth) {
186386
+ async _exploreDir(path28, depth) {
185576
186387
  let files;
185577
186388
  try {
185578
- files = await readdir(path26, this._rdOptions);
186389
+ files = await readdir(path28, this._rdOptions);
185579
186390
  } catch (error) {
185580
186391
  this._onError(error);
185581
186392
  }
185582
- return { files, depth, path: path26 };
186393
+ return { files, depth, path: path28 };
185583
186394
  }
185584
- async _formatEntry(dirent, path26) {
186395
+ async _formatEntry(dirent, path28) {
185585
186396
  let entry;
185586
186397
  const basename6 = this._isDirent ? dirent.name : dirent;
185587
186398
  try {
185588
- const fullPath = presolve(pjoin(path26, basename6));
186399
+ const fullPath = presolve(pjoin(path28, basename6));
185589
186400
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename6 };
185590
186401
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
185591
186402
  } catch (err) {
@@ -185985,16 +186796,16 @@ var delFromSet = (main, prop, item) => {
185985
186796
  };
185986
186797
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
185987
186798
  var FsWatchInstances = /* @__PURE__ */ new Map();
185988
- function createFsWatchInstance(path26, options2, listener, errHandler, emitRaw) {
186799
+ function createFsWatchInstance(path28, options2, listener, errHandler, emitRaw) {
185989
186800
  const handleEvent = (rawEvent, evPath) => {
185990
- listener(path26);
185991
- emitRaw(rawEvent, evPath, { watchedPath: path26 });
185992
- if (evPath && path26 !== evPath) {
185993
- fsWatchBroadcast(sp.resolve(path26, evPath), KEY_LISTENERS, sp.join(path26, evPath));
186801
+ listener(path28);
186802
+ emitRaw(rawEvent, evPath, { watchedPath: path28 });
186803
+ if (evPath && path28 !== evPath) {
186804
+ fsWatchBroadcast(sp.resolve(path28, evPath), KEY_LISTENERS, sp.join(path28, evPath));
185994
186805
  }
185995
186806
  };
185996
186807
  try {
185997
- return fs_watch(path26, {
186808
+ return fs_watch(path28, {
185998
186809
  persistent: options2.persistent
185999
186810
  }, handleEvent);
186000
186811
  } catch (error) {
@@ -186010,12 +186821,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
186010
186821
  listener(val1, val2, val3);
186011
186822
  });
186012
186823
  };
186013
- var setFsWatchListener = (path26, fullPath, options2, handlers) => {
186824
+ var setFsWatchListener = (path28, fullPath, options2, handlers) => {
186014
186825
  const { listener, errHandler, rawEmitter } = handlers;
186015
186826
  let cont = FsWatchInstances.get(fullPath);
186016
186827
  let watcher;
186017
186828
  if (!options2.persistent) {
186018
- watcher = createFsWatchInstance(path26, options2, listener, errHandler, rawEmitter);
186829
+ watcher = createFsWatchInstance(path28, options2, listener, errHandler, rawEmitter);
186019
186830
  if (!watcher)
186020
186831
  return;
186021
186832
  return watcher.close.bind(watcher);
@@ -186026,7 +186837,7 @@ var setFsWatchListener = (path26, fullPath, options2, handlers) => {
186026
186837
  addAndConvert(cont, KEY_RAW, rawEmitter);
186027
186838
  } else {
186028
186839
  watcher = createFsWatchInstance(
186029
- path26,
186840
+ path28,
186030
186841
  options2,
186031
186842
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
186032
186843
  errHandler,
@@ -186041,7 +186852,7 @@ var setFsWatchListener = (path26, fullPath, options2, handlers) => {
186041
186852
  cont.watcherUnusable = true;
186042
186853
  if (isWindows && error.code === "EPERM") {
186043
186854
  try {
186044
- const fd = await open2(path26, "r");
186855
+ const fd = await open2(path28, "r");
186045
186856
  await fd.close();
186046
186857
  broadcastErr(error);
186047
186858
  } catch (err) {
@@ -186072,7 +186883,7 @@ var setFsWatchListener = (path26, fullPath, options2, handlers) => {
186072
186883
  };
186073
186884
  };
186074
186885
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
186075
- var setFsWatchFileListener = (path26, fullPath, options2, handlers) => {
186886
+ var setFsWatchFileListener = (path28, fullPath, options2, handlers) => {
186076
186887
  const { listener, rawEmitter } = handlers;
186077
186888
  let cont = FsWatchFileInstances.get(fullPath);
186078
186889
  const copts = cont && cont.options;
@@ -186094,7 +186905,7 @@ var setFsWatchFileListener = (path26, fullPath, options2, handlers) => {
186094
186905
  });
186095
186906
  const currmtime = curr.mtimeMs;
186096
186907
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
186097
- foreach(cont.listeners, (listener2) => listener2(path26, curr));
186908
+ foreach(cont.listeners, (listener2) => listener2(path28, curr));
186098
186909
  }
186099
186910
  })
186100
186911
  };
@@ -186124,13 +186935,13 @@ var NodeFsHandler = class {
186124
186935
  * @param listener on fs change
186125
186936
  * @returns closer for the watcher instance
186126
186937
  */
186127
- _watchWithNodeFs(path26, listener) {
186938
+ _watchWithNodeFs(path28, listener) {
186128
186939
  const opts = this.fsw.options;
186129
- const directory = sp.dirname(path26);
186130
- const basename6 = sp.basename(path26);
186940
+ const directory = sp.dirname(path28);
186941
+ const basename6 = sp.basename(path28);
186131
186942
  const parent = this.fsw._getWatchedDir(directory);
186132
186943
  parent.add(basename6);
186133
- const absolutePath = sp.resolve(path26);
186944
+ const absolutePath = sp.resolve(path28);
186134
186945
  const options2 = {
186135
186946
  persistent: opts.persistent
186136
186947
  };
@@ -186140,12 +186951,12 @@ var NodeFsHandler = class {
186140
186951
  if (opts.usePolling) {
186141
186952
  const enableBin = opts.interval !== opts.binaryInterval;
186142
186953
  options2.interval = enableBin && isBinaryPath(basename6) ? opts.binaryInterval : opts.interval;
186143
- closer = setFsWatchFileListener(path26, absolutePath, options2, {
186954
+ closer = setFsWatchFileListener(path28, absolutePath, options2, {
186144
186955
  listener,
186145
186956
  rawEmitter: this.fsw._emitRaw
186146
186957
  });
186147
186958
  } else {
186148
- closer = setFsWatchListener(path26, absolutePath, options2, {
186959
+ closer = setFsWatchListener(path28, absolutePath, options2, {
186149
186960
  listener,
186150
186961
  errHandler: this._boundHandleError,
186151
186962
  rawEmitter: this.fsw._emitRaw
@@ -186161,13 +186972,13 @@ var NodeFsHandler = class {
186161
186972
  if (this.fsw.closed) {
186162
186973
  return;
186163
186974
  }
186164
- const dirname8 = sp.dirname(file);
186975
+ const dirname9 = sp.dirname(file);
186165
186976
  const basename6 = sp.basename(file);
186166
- const parent = this.fsw._getWatchedDir(dirname8);
186977
+ const parent = this.fsw._getWatchedDir(dirname9);
186167
186978
  let prevStats = stats;
186168
186979
  if (parent.has(basename6))
186169
186980
  return;
186170
- const listener = async (path26, newStats) => {
186981
+ const listener = async (path28, newStats) => {
186171
186982
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
186172
186983
  return;
186173
186984
  if (!newStats || newStats.mtimeMs === 0) {
@@ -186181,16 +186992,16 @@ var NodeFsHandler = class {
186181
186992
  this.fsw._emit(EV.CHANGE, file, newStats2);
186182
186993
  }
186183
186994
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
186184
- this.fsw._closeFile(path26);
186995
+ this.fsw._closeFile(path28);
186185
186996
  prevStats = newStats2;
186186
186997
  const closer2 = this._watchWithNodeFs(file, listener);
186187
186998
  if (closer2)
186188
- this.fsw._addPathCloser(path26, closer2);
186999
+ this.fsw._addPathCloser(path28, closer2);
186189
187000
  } else {
186190
187001
  prevStats = newStats2;
186191
187002
  }
186192
187003
  } catch (error) {
186193
- this.fsw._remove(dirname8, basename6);
187004
+ this.fsw._remove(dirname9, basename6);
186194
187005
  }
186195
187006
  } else if (parent.has(basename6)) {
186196
187007
  const at = newStats.atimeMs;
@@ -186217,7 +187028,7 @@ var NodeFsHandler = class {
186217
187028
  * @param item basename of this item
186218
187029
  * @returns true if no more processing is needed for this entry.
186219
187030
  */
186220
- async _handleSymlink(entry, directory, path26, item) {
187031
+ async _handleSymlink(entry, directory, path28, item) {
186221
187032
  if (this.fsw.closed) {
186222
187033
  return;
186223
187034
  }
@@ -186227,7 +187038,7 @@ var NodeFsHandler = class {
186227
187038
  this.fsw._incrReadyCount();
186228
187039
  let linkPath;
186229
187040
  try {
186230
- linkPath = await fsrealpath(path26);
187041
+ linkPath = await fsrealpath(path28);
186231
187042
  } catch (e) {
186232
187043
  this.fsw._emitReady();
186233
187044
  return true;
@@ -186237,12 +187048,12 @@ var NodeFsHandler = class {
186237
187048
  if (dir.has(item)) {
186238
187049
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
186239
187050
  this.fsw._symlinkPaths.set(full, linkPath);
186240
- this.fsw._emit(EV.CHANGE, path26, entry.stats);
187051
+ this.fsw._emit(EV.CHANGE, path28, entry.stats);
186241
187052
  }
186242
187053
  } else {
186243
187054
  dir.add(item);
186244
187055
  this.fsw._symlinkPaths.set(full, linkPath);
186245
- this.fsw._emit(EV.ADD, path26, entry.stats);
187056
+ this.fsw._emit(EV.ADD, path28, entry.stats);
186246
187057
  }
186247
187058
  this.fsw._emitReady();
186248
187059
  return true;
@@ -186272,9 +187083,9 @@ var NodeFsHandler = class {
186272
187083
  return;
186273
187084
  }
186274
187085
  const item = entry.path;
186275
- let path26 = sp.join(directory, item);
187086
+ let path28 = sp.join(directory, item);
186276
187087
  current.add(item);
186277
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path26, item)) {
187088
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path28, item)) {
186278
187089
  return;
186279
187090
  }
186280
187091
  if (this.fsw.closed) {
@@ -186283,8 +187094,8 @@ var NodeFsHandler = class {
186283
187094
  }
186284
187095
  if (item === target || !target && !previous.has(item)) {
186285
187096
  this.fsw._incrReadyCount();
186286
- path26 = sp.join(dir, sp.relative(dir, path26));
186287
- this._addToNodeFs(path26, initialAdd, wh, depth + 1);
187097
+ path28 = sp.join(dir, sp.relative(dir, path28));
187098
+ this._addToNodeFs(path28, initialAdd, wh, depth + 1);
186288
187099
  }
186289
187100
  }).on(EV.ERROR, this._boundHandleError);
186290
187101
  return new Promise((resolve10, reject) => {
@@ -186353,13 +187164,13 @@ var NodeFsHandler = class {
186353
187164
  * @param depth Child path actually targeted for watch
186354
187165
  * @param target Child path actually targeted for watch
186355
187166
  */
186356
- async _addToNodeFs(path26, initialAdd, priorWh, depth, target) {
187167
+ async _addToNodeFs(path28, initialAdd, priorWh, depth, target) {
186357
187168
  const ready = this.fsw._emitReady;
186358
- if (this.fsw._isIgnored(path26) || this.fsw.closed) {
187169
+ if (this.fsw._isIgnored(path28) || this.fsw.closed) {
186359
187170
  ready();
186360
187171
  return false;
186361
187172
  }
186362
- const wh = this.fsw._getWatchHelpers(path26);
187173
+ const wh = this.fsw._getWatchHelpers(path28);
186363
187174
  if (priorWh) {
186364
187175
  wh.filterPath = (entry) => priorWh.filterPath(entry);
186365
187176
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -186375,8 +187186,8 @@ var NodeFsHandler = class {
186375
187186
  const follow = this.fsw.options.followSymlinks;
186376
187187
  let closer;
186377
187188
  if (stats.isDirectory()) {
186378
- const absPath = sp.resolve(path26);
186379
- const targetPath = follow ? await fsrealpath(path26) : path26;
187189
+ const absPath = sp.resolve(path28);
187190
+ const targetPath = follow ? await fsrealpath(path28) : path28;
186380
187191
  if (this.fsw.closed)
186381
187192
  return;
186382
187193
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -186386,29 +187197,29 @@ var NodeFsHandler = class {
186386
187197
  this.fsw._symlinkPaths.set(absPath, targetPath);
186387
187198
  }
186388
187199
  } else if (stats.isSymbolicLink()) {
186389
- const targetPath = follow ? await fsrealpath(path26) : path26;
187200
+ const targetPath = follow ? await fsrealpath(path28) : path28;
186390
187201
  if (this.fsw.closed)
186391
187202
  return;
186392
187203
  const parent = sp.dirname(wh.watchPath);
186393
187204
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
186394
187205
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
186395
- closer = await this._handleDir(parent, stats, initialAdd, depth, path26, wh, targetPath);
187206
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path28, wh, targetPath);
186396
187207
  if (this.fsw.closed)
186397
187208
  return;
186398
187209
  if (targetPath !== void 0) {
186399
- this.fsw._symlinkPaths.set(sp.resolve(path26), targetPath);
187210
+ this.fsw._symlinkPaths.set(sp.resolve(path28), targetPath);
186400
187211
  }
186401
187212
  } else {
186402
187213
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
186403
187214
  }
186404
187215
  ready();
186405
187216
  if (closer)
186406
- this.fsw._addPathCloser(path26, closer);
187217
+ this.fsw._addPathCloser(path28, closer);
186407
187218
  return false;
186408
187219
  } catch (error) {
186409
187220
  if (this.fsw._handleError(error)) {
186410
187221
  ready();
186411
- return path26;
187222
+ return path28;
186412
187223
  }
186413
187224
  }
186414
187225
  }
@@ -186451,24 +187262,24 @@ function createPattern(matcher) {
186451
187262
  }
186452
187263
  return () => false;
186453
187264
  }
186454
- function normalizePath(path26) {
186455
- if (typeof path26 !== "string")
187265
+ function normalizePath(path28) {
187266
+ if (typeof path28 !== "string")
186456
187267
  throw new Error("string expected");
186457
- path26 = sp2.normalize(path26);
186458
- path26 = path26.replace(/\\/g, "/");
187268
+ path28 = sp2.normalize(path28);
187269
+ path28 = path28.replace(/\\/g, "/");
186459
187270
  let prepend = false;
186460
- if (path26.startsWith("//"))
187271
+ if (path28.startsWith("//"))
186461
187272
  prepend = true;
186462
- path26 = path26.replace(DOUBLE_SLASH_RE, "/");
187273
+ path28 = path28.replace(DOUBLE_SLASH_RE, "/");
186463
187274
  if (prepend)
186464
- path26 = "/" + path26;
186465
- return path26;
187275
+ path28 = "/" + path28;
187276
+ return path28;
186466
187277
  }
186467
187278
  function matchPatterns(patterns, testString, stats) {
186468
- const path26 = normalizePath(testString);
187279
+ const path28 = normalizePath(testString);
186469
187280
  for (let index = 0; index < patterns.length; index++) {
186470
187281
  const pattern = patterns[index];
186471
- if (pattern(path26, stats)) {
187282
+ if (pattern(path28, stats)) {
186472
187283
  return true;
186473
187284
  }
186474
187285
  }
@@ -186506,19 +187317,19 @@ var toUnix = (string) => {
186506
187317
  }
186507
187318
  return str;
186508
187319
  };
186509
- var normalizePathToUnix = (path26) => toUnix(sp2.normalize(toUnix(path26)));
186510
- var normalizeIgnored = (cwd = "") => (path26) => {
186511
- if (typeof path26 === "string") {
186512
- return normalizePathToUnix(sp2.isAbsolute(path26) ? path26 : sp2.join(cwd, path26));
187320
+ var normalizePathToUnix = (path28) => toUnix(sp2.normalize(toUnix(path28)));
187321
+ var normalizeIgnored = (cwd = "") => (path28) => {
187322
+ if (typeof path28 === "string") {
187323
+ return normalizePathToUnix(sp2.isAbsolute(path28) ? path28 : sp2.join(cwd, path28));
186513
187324
  } else {
186514
- return path26;
187325
+ return path28;
186515
187326
  }
186516
187327
  };
186517
- var getAbsolutePath = (path26, cwd) => {
186518
- if (sp2.isAbsolute(path26)) {
186519
- return path26;
187328
+ var getAbsolutePath = (path28, cwd) => {
187329
+ if (sp2.isAbsolute(path28)) {
187330
+ return path28;
186520
187331
  }
186521
- return sp2.join(cwd, path26);
187332
+ return sp2.join(cwd, path28);
186522
187333
  };
186523
187334
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
186524
187335
  var DirEntry = class {
@@ -186583,10 +187394,10 @@ var WatchHelper = class {
186583
187394
  dirParts;
186584
187395
  followSymlinks;
186585
187396
  statMethod;
186586
- constructor(path26, follow, fsw) {
187397
+ constructor(path28, follow, fsw) {
186587
187398
  this.fsw = fsw;
186588
- const watchPath = path26;
186589
- this.path = path26 = path26.replace(REPLACER_RE, "");
187399
+ const watchPath = path28;
187400
+ this.path = path28 = path28.replace(REPLACER_RE, "");
186590
187401
  this.watchPath = watchPath;
186591
187402
  this.fullWatchPath = sp2.resolve(watchPath);
186592
187403
  this.dirParts = [];
@@ -186726,20 +187537,20 @@ var FSWatcher = class extends EventEmitter {
186726
187537
  this._closePromise = void 0;
186727
187538
  let paths = unifyPaths(paths_);
186728
187539
  if (cwd) {
186729
- paths = paths.map((path26) => {
186730
- const absPath = getAbsolutePath(path26, cwd);
187540
+ paths = paths.map((path28) => {
187541
+ const absPath = getAbsolutePath(path28, cwd);
186731
187542
  return absPath;
186732
187543
  });
186733
187544
  }
186734
- paths.forEach((path26) => {
186735
- this._removeIgnoredPath(path26);
187545
+ paths.forEach((path28) => {
187546
+ this._removeIgnoredPath(path28);
186736
187547
  });
186737
187548
  this._userIgnored = void 0;
186738
187549
  if (!this._readyCount)
186739
187550
  this._readyCount = 0;
186740
187551
  this._readyCount += paths.length;
186741
- Promise.all(paths.map(async (path26) => {
186742
- const res = await this._nodeFsHandler._addToNodeFs(path26, !_internal, void 0, 0, _origAdd);
187552
+ Promise.all(paths.map(async (path28) => {
187553
+ const res = await this._nodeFsHandler._addToNodeFs(path28, !_internal, void 0, 0, _origAdd);
186743
187554
  if (res)
186744
187555
  this._emitReady();
186745
187556
  return res;
@@ -186761,17 +187572,17 @@ var FSWatcher = class extends EventEmitter {
186761
187572
  return this;
186762
187573
  const paths = unifyPaths(paths_);
186763
187574
  const { cwd } = this.options;
186764
- paths.forEach((path26) => {
186765
- if (!sp2.isAbsolute(path26) && !this._closers.has(path26)) {
187575
+ paths.forEach((path28) => {
187576
+ if (!sp2.isAbsolute(path28) && !this._closers.has(path28)) {
186766
187577
  if (cwd)
186767
- path26 = sp2.join(cwd, path26);
186768
- path26 = sp2.resolve(path26);
187578
+ path28 = sp2.join(cwd, path28);
187579
+ path28 = sp2.resolve(path28);
186769
187580
  }
186770
- this._closePath(path26);
186771
- this._addIgnoredPath(path26);
186772
- if (this._watched.has(path26)) {
187581
+ this._closePath(path28);
187582
+ this._addIgnoredPath(path28);
187583
+ if (this._watched.has(path28)) {
186773
187584
  this._addIgnoredPath({
186774
- path: path26,
187585
+ path: path28,
186775
187586
  recursive: true
186776
187587
  });
186777
187588
  }
@@ -186835,38 +187646,38 @@ var FSWatcher = class extends EventEmitter {
186835
187646
  * @param stats arguments to be passed with event
186836
187647
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
186837
187648
  */
186838
- async _emit(event, path26, stats) {
187649
+ async _emit(event, path28, stats) {
186839
187650
  if (this.closed)
186840
187651
  return;
186841
187652
  const opts = this.options;
186842
187653
  if (isWindows)
186843
- path26 = sp2.normalize(path26);
187654
+ path28 = sp2.normalize(path28);
186844
187655
  if (opts.cwd)
186845
- path26 = sp2.relative(opts.cwd, path26);
186846
- const args = [path26];
187656
+ path28 = sp2.relative(opts.cwd, path28);
187657
+ const args = [path28];
186847
187658
  if (stats != null)
186848
187659
  args.push(stats);
186849
187660
  const awf = opts.awaitWriteFinish;
186850
187661
  let pw;
186851
- if (awf && (pw = this._pendingWrites.get(path26))) {
187662
+ if (awf && (pw = this._pendingWrites.get(path28))) {
186852
187663
  pw.lastChange = /* @__PURE__ */ new Date();
186853
187664
  return this;
186854
187665
  }
186855
187666
  if (opts.atomic) {
186856
187667
  if (event === EVENTS.UNLINK) {
186857
- this._pendingUnlinks.set(path26, [event, ...args]);
187668
+ this._pendingUnlinks.set(path28, [event, ...args]);
186858
187669
  setTimeout(() => {
186859
- this._pendingUnlinks.forEach((entry, path27) => {
187670
+ this._pendingUnlinks.forEach((entry, path29) => {
186860
187671
  this.emit(...entry);
186861
187672
  this.emit(EVENTS.ALL, ...entry);
186862
- this._pendingUnlinks.delete(path27);
187673
+ this._pendingUnlinks.delete(path29);
186863
187674
  });
186864
187675
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
186865
187676
  return this;
186866
187677
  }
186867
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path26)) {
187678
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path28)) {
186868
187679
  event = EVENTS.CHANGE;
186869
- this._pendingUnlinks.delete(path26);
187680
+ this._pendingUnlinks.delete(path28);
186870
187681
  }
186871
187682
  }
186872
187683
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -186884,16 +187695,16 @@ var FSWatcher = class extends EventEmitter {
186884
187695
  this.emitWithAll(event, args);
186885
187696
  }
186886
187697
  };
186887
- this._awaitWriteFinish(path26, awf.stabilityThreshold, event, awfEmit);
187698
+ this._awaitWriteFinish(path28, awf.stabilityThreshold, event, awfEmit);
186888
187699
  return this;
186889
187700
  }
186890
187701
  if (event === EVENTS.CHANGE) {
186891
- const isThrottled = !this._throttle(EVENTS.CHANGE, path26, 50);
187702
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path28, 50);
186892
187703
  if (isThrottled)
186893
187704
  return this;
186894
187705
  }
186895
187706
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
186896
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path26) : path26;
187707
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path28) : path28;
186897
187708
  let stats2;
186898
187709
  try {
186899
187710
  stats2 = await stat3(fullPath);
@@ -186924,23 +187735,23 @@ var FSWatcher = class extends EventEmitter {
186924
187735
  * @param timeout duration of time to suppress duplicate actions
186925
187736
  * @returns tracking object or false if action should be suppressed
186926
187737
  */
186927
- _throttle(actionType, path26, timeout) {
187738
+ _throttle(actionType, path28, timeout) {
186928
187739
  if (!this._throttled.has(actionType)) {
186929
187740
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
186930
187741
  }
186931
187742
  const action = this._throttled.get(actionType);
186932
187743
  if (!action)
186933
187744
  throw new Error("invalid throttle");
186934
- const actionPath = action.get(path26);
187745
+ const actionPath = action.get(path28);
186935
187746
  if (actionPath) {
186936
187747
  actionPath.count++;
186937
187748
  return false;
186938
187749
  }
186939
187750
  let timeoutObject;
186940
187751
  const clear = () => {
186941
- const item = action.get(path26);
187752
+ const item = action.get(path28);
186942
187753
  const count = item ? item.count : 0;
186943
- action.delete(path26);
187754
+ action.delete(path28);
186944
187755
  clearTimeout(timeoutObject);
186945
187756
  if (item)
186946
187757
  clearTimeout(item.timeoutObject);
@@ -186948,7 +187759,7 @@ var FSWatcher = class extends EventEmitter {
186948
187759
  };
186949
187760
  timeoutObject = setTimeout(clear, timeout);
186950
187761
  const thr = { timeoutObject, clear, count: 0 };
186951
- action.set(path26, thr);
187762
+ action.set(path28, thr);
186952
187763
  return thr;
186953
187764
  }
186954
187765
  _incrReadyCount() {
@@ -186962,44 +187773,44 @@ var FSWatcher = class extends EventEmitter {
186962
187773
  * @param event
186963
187774
  * @param awfEmit Callback to be called when ready for event to be emitted.
186964
187775
  */
186965
- _awaitWriteFinish(path26, threshold, event, awfEmit) {
187776
+ _awaitWriteFinish(path28, threshold, event, awfEmit) {
186966
187777
  const awf = this.options.awaitWriteFinish;
186967
187778
  if (typeof awf !== "object")
186968
187779
  return;
186969
187780
  const pollInterval = awf.pollInterval;
186970
187781
  let timeoutHandler;
186971
- let fullPath = path26;
186972
- if (this.options.cwd && !sp2.isAbsolute(path26)) {
186973
- fullPath = sp2.join(this.options.cwd, path26);
187782
+ let fullPath = path28;
187783
+ if (this.options.cwd && !sp2.isAbsolute(path28)) {
187784
+ fullPath = sp2.join(this.options.cwd, path28);
186974
187785
  }
186975
187786
  const now = /* @__PURE__ */ new Date();
186976
187787
  const writes = this._pendingWrites;
186977
187788
  function awaitWriteFinishFn(prevStat) {
186978
187789
  statcb(fullPath, (err, curStat) => {
186979
- if (err || !writes.has(path26)) {
187790
+ if (err || !writes.has(path28)) {
186980
187791
  if (err && err.code !== "ENOENT")
186981
187792
  awfEmit(err);
186982
187793
  return;
186983
187794
  }
186984
187795
  const now2 = Number(/* @__PURE__ */ new Date());
186985
187796
  if (prevStat && curStat.size !== prevStat.size) {
186986
- writes.get(path26).lastChange = now2;
187797
+ writes.get(path28).lastChange = now2;
186987
187798
  }
186988
- const pw = writes.get(path26);
187799
+ const pw = writes.get(path28);
186989
187800
  const df = now2 - pw.lastChange;
186990
187801
  if (df >= threshold) {
186991
- writes.delete(path26);
187802
+ writes.delete(path28);
186992
187803
  awfEmit(void 0, curStat);
186993
187804
  } else {
186994
187805
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
186995
187806
  }
186996
187807
  });
186997
187808
  }
186998
- if (!writes.has(path26)) {
186999
- writes.set(path26, {
187809
+ if (!writes.has(path28)) {
187810
+ writes.set(path28, {
187000
187811
  lastChange: now,
187001
187812
  cancelWait: () => {
187002
- writes.delete(path26);
187813
+ writes.delete(path28);
187003
187814
  clearTimeout(timeoutHandler);
187004
187815
  return event;
187005
187816
  }
@@ -187010,8 +187821,8 @@ var FSWatcher = class extends EventEmitter {
187010
187821
  /**
187011
187822
  * Determines whether user has asked to ignore this path.
187012
187823
  */
187013
- _isIgnored(path26, stats) {
187014
- if (this.options.atomic && DOT_RE.test(path26))
187824
+ _isIgnored(path28, stats) {
187825
+ if (this.options.atomic && DOT_RE.test(path28))
187015
187826
  return true;
187016
187827
  if (!this._userIgnored) {
187017
187828
  const { cwd } = this.options;
@@ -187021,17 +187832,17 @@ var FSWatcher = class extends EventEmitter {
187021
187832
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
187022
187833
  this._userIgnored = anymatch(list, void 0);
187023
187834
  }
187024
- return this._userIgnored(path26, stats);
187835
+ return this._userIgnored(path28, stats);
187025
187836
  }
187026
- _isntIgnored(path26, stat4) {
187027
- return !this._isIgnored(path26, stat4);
187837
+ _isntIgnored(path28, stat4) {
187838
+ return !this._isIgnored(path28, stat4);
187028
187839
  }
187029
187840
  /**
187030
187841
  * Provides a set of common helpers and properties relating to symlink handling.
187031
187842
  * @param path file or directory pattern being watched
187032
187843
  */
187033
- _getWatchHelpers(path26) {
187034
- return new WatchHelper(path26, this.options.followSymlinks, this);
187844
+ _getWatchHelpers(path28) {
187845
+ return new WatchHelper(path28, this.options.followSymlinks, this);
187035
187846
  }
187036
187847
  // Directory helpers
187037
187848
  // -----------------
@@ -187063,63 +187874,63 @@ var FSWatcher = class extends EventEmitter {
187063
187874
  * @param item base path of item/directory
187064
187875
  */
187065
187876
  _remove(directory, item, isDirectory) {
187066
- const path26 = sp2.join(directory, item);
187067
- const fullPath = sp2.resolve(path26);
187068
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path26) || this._watched.has(fullPath);
187069
- if (!this._throttle("remove", path26, 100))
187877
+ const path28 = sp2.join(directory, item);
187878
+ const fullPath = sp2.resolve(path28);
187879
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path28) || this._watched.has(fullPath);
187880
+ if (!this._throttle("remove", path28, 100))
187070
187881
  return;
187071
187882
  if (!isDirectory && this._watched.size === 1) {
187072
187883
  this.add(directory, item, true);
187073
187884
  }
187074
- const wp = this._getWatchedDir(path26);
187885
+ const wp = this._getWatchedDir(path28);
187075
187886
  const nestedDirectoryChildren = wp.getChildren();
187076
- nestedDirectoryChildren.forEach((nested) => this._remove(path26, nested));
187887
+ nestedDirectoryChildren.forEach((nested) => this._remove(path28, nested));
187077
187888
  const parent = this._getWatchedDir(directory);
187078
187889
  const wasTracked = parent.has(item);
187079
187890
  parent.remove(item);
187080
187891
  if (this._symlinkPaths.has(fullPath)) {
187081
187892
  this._symlinkPaths.delete(fullPath);
187082
187893
  }
187083
- let relPath = path26;
187894
+ let relPath = path28;
187084
187895
  if (this.options.cwd)
187085
- relPath = sp2.relative(this.options.cwd, path26);
187896
+ relPath = sp2.relative(this.options.cwd, path28);
187086
187897
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
187087
187898
  const event = this._pendingWrites.get(relPath).cancelWait();
187088
187899
  if (event === EVENTS.ADD)
187089
187900
  return;
187090
187901
  }
187091
- this._watched.delete(path26);
187902
+ this._watched.delete(path28);
187092
187903
  this._watched.delete(fullPath);
187093
187904
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
187094
- if (wasTracked && !this._isIgnored(path26))
187095
- this._emit(eventName, path26);
187096
- this._closePath(path26);
187905
+ if (wasTracked && !this._isIgnored(path28))
187906
+ this._emit(eventName, path28);
187907
+ this._closePath(path28);
187097
187908
  }
187098
187909
  /**
187099
187910
  * Closes all watchers for a path
187100
187911
  */
187101
- _closePath(path26) {
187102
- this._closeFile(path26);
187103
- const dir = sp2.dirname(path26);
187104
- this._getWatchedDir(dir).remove(sp2.basename(path26));
187912
+ _closePath(path28) {
187913
+ this._closeFile(path28);
187914
+ const dir = sp2.dirname(path28);
187915
+ this._getWatchedDir(dir).remove(sp2.basename(path28));
187105
187916
  }
187106
187917
  /**
187107
187918
  * Closes only file-specific watchers
187108
187919
  */
187109
- _closeFile(path26) {
187110
- const closers = this._closers.get(path26);
187920
+ _closeFile(path28) {
187921
+ const closers = this._closers.get(path28);
187111
187922
  if (!closers)
187112
187923
  return;
187113
187924
  closers.forEach((closer) => closer());
187114
- this._closers.delete(path26);
187925
+ this._closers.delete(path28);
187115
187926
  }
187116
- _addPathCloser(path26, closer) {
187927
+ _addPathCloser(path28, closer) {
187117
187928
  if (!closer)
187118
187929
  return;
187119
- let list = this._closers.get(path26);
187930
+ let list = this._closers.get(path28);
187120
187931
  if (!list) {
187121
187932
  list = [];
187122
- this._closers.set(path26, list);
187933
+ this._closers.set(path28, list);
187123
187934
  }
187124
187935
  list.push(closer);
187125
187936
  }
@@ -187168,8 +187979,8 @@ var PortAllocator = class {
187168
187979
  };
187169
187980
 
187170
187981
  // src/lib/dev/stable-port-allocator.ts
187171
- import * as fs13 from "fs";
187172
- import * as path9 from "path";
187982
+ import * as fs14 from "fs";
187983
+ import * as path10 from "path";
187173
187984
  var PORT_RANGE_START2 = 4e4;
187174
187985
  var PORT_RANGE_END2 = 49999;
187175
187986
  var StablePortAllocator = class {
@@ -187178,16 +187989,16 @@ var StablePortAllocator = class {
187178
187989
  savedPorts = {};
187179
187990
  usedPorts = /* @__PURE__ */ new Set();
187180
187991
  constructor(projectRoot, key = "default") {
187181
- this.portsDir = path9.join(projectRoot, ".specific", "keys", key);
187182
- this.portsFilePath = path9.join(this.portsDir, "ports.json");
187992
+ this.portsDir = path10.join(projectRoot, ".specific", "keys", key);
187993
+ this.portsFilePath = path10.join(this.portsDir, "ports.json");
187183
187994
  this.loadPorts();
187184
187995
  }
187185
187996
  loadPorts() {
187186
- if (!fs13.existsSync(this.portsFilePath)) {
187997
+ if (!fs14.existsSync(this.portsFilePath)) {
187187
187998
  return;
187188
187999
  }
187189
188000
  try {
187190
- const content = fs13.readFileSync(this.portsFilePath, "utf-8");
188001
+ const content = fs14.readFileSync(this.portsFilePath, "utf-8");
187191
188002
  const data = JSON.parse(content);
187192
188003
  if (data.version === 1 && data.ports) {
187193
188004
  this.savedPorts = data.ports;
@@ -187200,14 +188011,14 @@ var StablePortAllocator = class {
187200
188011
  }
187201
188012
  }
187202
188013
  savePorts() {
187203
- if (!fs13.existsSync(this.portsDir)) {
187204
- fs13.mkdirSync(this.portsDir, { recursive: true });
188014
+ if (!fs14.existsSync(this.portsDir)) {
188015
+ fs14.mkdirSync(this.portsDir, { recursive: true });
187205
188016
  }
187206
188017
  const data = {
187207
188018
  version: 1,
187208
188019
  ports: this.savedPorts
187209
188020
  };
187210
- fs13.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
188021
+ fs14.writeFileSync(this.portsFilePath, JSON.stringify(data, null, 2));
187211
188022
  }
187212
188023
  allocateRandom() {
187213
188024
  const rangeSize = PORT_RANGE_END2 - PORT_RANGE_START2 + 1;
@@ -187234,21 +188045,21 @@ var StablePortAllocator = class {
187234
188045
  };
187235
188046
 
187236
188047
  // src/lib/dev/database-manager.ts
187237
- import * as fs14 from "fs";
187238
- import * as path10 from "path";
188048
+ import * as fs15 from "fs";
188049
+ import * as path11 from "path";
187239
188050
  import * as net from "net";
187240
188051
  import { spawn } from "child_process";
187241
188052
  async function startPostgres(pg, port, dataDir, onProgress) {
187242
188053
  const binary = await ensureBinary(postgresBinary, void 0, onProgress);
187243
- const dbDataPath = path10.join(process.cwd(), dataDir, pg.name);
188054
+ const dbDataPath = path11.join(process.cwd(), dataDir, pg.name);
187244
188055
  const host = "127.0.0.1";
187245
188056
  const user = "postgres";
187246
188057
  const password = "postgres";
187247
188058
  const libraryEnv = getLibraryEnv(binary);
187248
188059
  const env2 = { ...process.env, ...libraryEnv };
187249
- const dataExists = fs14.existsSync(dbDataPath);
188060
+ const dataExists = fs15.existsSync(dbDataPath);
187250
188061
  if (!dataExists) {
187251
- fs14.mkdirSync(dbDataPath, { recursive: true });
188062
+ fs15.mkdirSync(dbDataPath, { recursive: true });
187252
188063
  await runCommand(
187253
188064
  binary.executables["initdb"],
187254
188065
  ["-D", dbDataPath, "-U", user, "--auth=trust", "--no-locale", "-E", "UTF8"],
@@ -187324,9 +188135,9 @@ async function startRedis(redis, port, onProgress) {
187324
188135
  }
187325
188136
  async function startStorage(storage, port, dataDir) {
187326
188137
  const S3rver = (await import("s3rver")).default;
187327
- const storageDataPath = path10.join(process.cwd(), dataDir, storage.name);
187328
- if (!fs14.existsSync(storageDataPath)) {
187329
- fs14.mkdirSync(storageDataPath, { recursive: true });
188138
+ const storageDataPath = path11.join(process.cwd(), dataDir, storage.name);
188139
+ if (!fs15.existsSync(storageDataPath)) {
188140
+ fs15.mkdirSync(storageDataPath, { recursive: true });
187330
188141
  }
187331
188142
  const host = "127.0.0.1";
187332
188143
  const accessKey = "S3RVER";
@@ -187460,7 +188271,7 @@ import { spawn as spawn2 } from "child_process";
187460
188271
  // src/lib/local/parser.ts
187461
188272
  var import_hcl2_json_parser2 = __toESM(require_dist(), 1);
187462
188273
  import { readFile, writeFile } from "fs/promises";
187463
- import { existsSync as existsSync11 } from "fs";
188274
+ import { existsSync as existsSync12 } from "fs";
187464
188275
  var { parseToObject: parseToObject2 } = import_hcl2_json_parser2.default;
187465
188276
  var LOCAL_FILE = "specific.local";
187466
188277
  var HEADER_COMMENT = `# Local secrets and configuration
@@ -187501,7 +188312,7 @@ async function parseLocalFile(content) {
187501
188312
  return { secrets, configs };
187502
188313
  }
187503
188314
  async function loadLocal() {
187504
- if (!existsSync11(LOCAL_FILE)) {
188315
+ if (!existsSync12(LOCAL_FILE)) {
187505
188316
  return { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
187506
188317
  }
187507
188318
  const content = await readFile(LOCAL_FILE, "utf-8");
@@ -187541,7 +188352,7 @@ ${newLine}
187541
188352
  }
187542
188353
  async function saveLocalSecret(name, value) {
187543
188354
  let content = "";
187544
- if (existsSync11(LOCAL_FILE)) {
188355
+ if (existsSync12(LOCAL_FILE)) {
187545
188356
  content = await readFile(LOCAL_FILE, "utf-8");
187546
188357
  } else {
187547
188358
  content = HEADER_COMMENT;
@@ -187551,7 +188362,7 @@ async function saveLocalSecret(name, value) {
187551
188362
  }
187552
188363
  async function saveLocalConfig(name, value) {
187553
188364
  let content = "";
187554
- if (existsSync11(LOCAL_FILE)) {
188365
+ if (existsSync12(LOCAL_FILE)) {
187555
188366
  content = await readFile(LOCAL_FILE, "utf-8");
187556
188367
  } else {
187557
188368
  content = HEADER_COMMENT;
@@ -187600,7 +188411,7 @@ config {
187600
188411
  this.name = "MissingConfigError";
187601
188412
  }
187602
188413
  };
187603
- function resolveEnvValue(value, resources, secrets, configs, servicePort, serviceEndpoints, currentServicePorts, publicUrls) {
188414
+ function resolveEnvValue(value, resources, secrets, configs, servicePort, serviceEndpoints, currentServicePorts, publicUrls, volumePaths) {
187604
188415
  if (typeof value === "string") {
187605
188416
  return value;
187606
188417
  }
@@ -187615,7 +188426,8 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
187615
188426
  servicePort,
187616
188427
  serviceEndpoints,
187617
188428
  currentServicePorts,
187618
- publicUrls
188429
+ publicUrls,
188430
+ volumePaths
187619
188431
  );
187620
188432
  }).join("");
187621
188433
  }
@@ -187762,6 +188574,22 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
187762
188574
  throw new Error(`Unknown storage attribute: ${String(value.attribute)}`);
187763
188575
  }
187764
188576
  }
188577
+ case "temporal": {
188578
+ const temporal = resources.get(value.name);
188579
+ if (!temporal || temporal.type !== "temporal") {
188580
+ throw new Error(`Temporal "${value.name}" not found`);
188581
+ }
188582
+ switch (value.attribute) {
188583
+ case "url":
188584
+ return temporal.url;
188585
+ case "namespace":
188586
+ return value.name;
188587
+ case "api_key":
188588
+ return "";
188589
+ default:
188590
+ throw new Error(`Unknown temporal attribute: ${String(value.attribute)}`);
188591
+ }
188592
+ }
187765
188593
  case "config": {
187766
188594
  const configValue = configs.get(value.name);
187767
188595
  if (configValue === void 0) {
@@ -187776,13 +188604,24 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
187776
188604
  }
187777
188605
  return secretValue;
187778
188606
  }
188607
+ case "volume": {
188608
+ const volumeRef = value;
188609
+ if (!volumePaths) {
188610
+ throw new Error("Volume reference used but no volume paths provided");
188611
+ }
188612
+ const volumePath = volumePaths.get(volumeRef.volumeName);
188613
+ if (volumePath === void 0) {
188614
+ throw new Error(`Volume "${volumeRef.volumeName}" not found`);
188615
+ }
188616
+ return volumePath;
188617
+ }
187779
188618
  case "build":
187780
188619
  throw new Error(`Build references cannot be used as env values`);
187781
188620
  default:
187782
188621
  throw new Error(`Unknown reference type`);
187783
188622
  }
187784
188623
  }
187785
- function resolveEnv(env2, resources, secrets, configs, servicePort, serviceEndpoints, currentServicePorts, publicUrls) {
188624
+ function resolveEnv(env2, resources, secrets, configs, servicePort, serviceEndpoints, currentServicePorts, publicUrls, volumePaths) {
187786
188625
  if (!env2) {
187787
188626
  return {};
187788
188627
  }
@@ -187796,7 +188635,8 @@ function resolveEnv(env2, resources, secrets, configs, servicePort, serviceEndpo
187796
188635
  servicePort,
187797
188636
  serviceEndpoints,
187798
188637
  currentServicePorts,
187799
- publicUrls
188638
+ publicUrls,
188639
+ volumePaths
187800
188640
  );
187801
188641
  }
187802
188642
  return resolved;
@@ -187811,12 +188651,12 @@ function resolveEnvForExec(env2, resources, secrets, configs) {
187811
188651
  resolved[key] = value;
187812
188652
  continue;
187813
188653
  }
187814
- if (value.type === "port" || value.type === "endpoint" || value.type === "service") {
188654
+ if (value.type === "port" || value.type === "endpoint" || value.type === "service" || value.type === "volume") {
187815
188655
  continue;
187816
188656
  }
187817
188657
  if (value.type === "interpolated") {
187818
188658
  const hasSkippableRef = value.parts.some(
187819
- (part) => part.type === "ref" && (part.ref.type === "port" || part.ref.type === "endpoint" || part.ref.type === "service")
188659
+ (part) => part.type === "ref" && (part.ref.type === "port" || part.ref.type === "endpoint" || part.ref.type === "service" || part.ref.type === "volume")
187820
188660
  );
187821
188661
  if (hasSkippableRef) {
187822
188662
  continue;
@@ -187830,7 +188670,7 @@ function resolveEnvForExec(env2, resources, secrets, configs) {
187830
188670
  }
187831
188671
 
187832
188672
  // src/lib/dev/service-runner.ts
187833
- function startService(service, resources, secrets, configs, endpointPorts, serviceEndpoints, onLog, publicUrls, cwd) {
188673
+ function startService(service, resources, secrets, configs, endpointPorts, serviceEndpoints, onLog, publicUrls, cwd, volumePaths) {
187834
188674
  const command = service.dev?.command ?? service.command;
187835
188675
  if (!command) {
187836
188676
  throw new Error(`Service "${service.name}" has no command`);
@@ -187848,7 +188688,8 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
187848
188688
  defaultPort,
187849
188689
  serviceEndpoints,
187850
188690
  endpointPorts,
187851
- publicUrls
188691
+ publicUrls,
188692
+ volumePaths
187852
188693
  );
187853
188694
  const child = spawn2(command, {
187854
188695
  shell: true,
@@ -187915,8 +188756,8 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
187915
188756
  }
187916
188757
 
187917
188758
  // src/lib/dev/instance-state.ts
187918
- import * as fs15 from "fs";
187919
- import * as path11 from "path";
188759
+ import * as fs16 from "fs";
188760
+ import * as path12 from "path";
187920
188761
  var InstanceStateManager = class {
187921
188762
  stateDir;
187922
188763
  statePath;
@@ -187925,16 +188766,16 @@ var InstanceStateManager = class {
187925
188766
  key;
187926
188767
  constructor(projectRoot, key = "default") {
187927
188768
  this.key = key;
187928
- this.stateDir = path11.join(projectRoot, ".specific", "keys", key);
187929
- this.statePath = path11.join(this.stateDir, "state.json");
187930
- this.lockPath = path11.join(this.stateDir, "state.lock");
188769
+ this.stateDir = path12.join(projectRoot, ".specific", "keys", key);
188770
+ this.statePath = path12.join(this.stateDir, "state.json");
188771
+ this.lockPath = path12.join(this.stateDir, "state.lock");
187931
188772
  }
187932
188773
  getKey() {
187933
188774
  return this.key;
187934
188775
  }
187935
188776
  ensureStateDir() {
187936
- if (!fs15.existsSync(this.stateDir)) {
187937
- fs15.mkdirSync(this.stateDir, { recursive: true });
188777
+ if (!fs16.existsSync(this.stateDir)) {
188778
+ fs16.mkdirSync(this.stateDir, { recursive: true });
187938
188779
  }
187939
188780
  }
187940
188781
  isProcessRunning(pid) {
@@ -187951,15 +188792,15 @@ var InstanceStateManager = class {
187951
188792
  const startTime = Date.now();
187952
188793
  while (Date.now() - startTime < timeoutMs) {
187953
188794
  try {
187954
- const fd = fs15.openSync(
188795
+ const fd = fs16.openSync(
187955
188796
  this.lockPath,
187956
- fs15.constants.O_CREAT | fs15.constants.O_EXCL | fs15.constants.O_WRONLY
188797
+ fs16.constants.O_CREAT | fs16.constants.O_EXCL | fs16.constants.O_WRONLY
187957
188798
  );
187958
- fs15.writeSync(fd, String(process.pid));
187959
- fs15.closeSync(fd);
188799
+ fs16.writeSync(fd, String(process.pid));
188800
+ fs16.closeSync(fd);
187960
188801
  return () => {
187961
188802
  try {
187962
- fs15.unlinkSync(this.lockPath);
188803
+ fs16.unlinkSync(this.lockPath);
187963
188804
  } catch {
187964
188805
  }
187965
188806
  };
@@ -187968,16 +188809,16 @@ var InstanceStateManager = class {
187968
188809
  if (err.code === "EEXIST") {
187969
188810
  try {
187970
188811
  const lockPid = parseInt(
187971
- fs15.readFileSync(this.lockPath, "utf-8").trim(),
188812
+ fs16.readFileSync(this.lockPath, "utf-8").trim(),
187972
188813
  10
187973
188814
  );
187974
188815
  if (!this.isProcessRunning(lockPid)) {
187975
- fs15.unlinkSync(this.lockPath);
188816
+ fs16.unlinkSync(this.lockPath);
187976
188817
  continue;
187977
188818
  }
187978
188819
  } catch {
187979
188820
  try {
187980
- fs15.unlinkSync(this.lockPath);
188821
+ fs16.unlinkSync(this.lockPath);
187981
188822
  } catch {
187982
188823
  }
187983
188824
  continue;
@@ -187991,12 +188832,12 @@ var InstanceStateManager = class {
187991
188832
  throw new Error("Failed to acquire state lock (timeout)");
187992
188833
  }
187993
188834
  async getExistingInstances() {
187994
- if (!fs15.existsSync(this.statePath)) {
188835
+ if (!fs16.existsSync(this.statePath)) {
187995
188836
  return null;
187996
188837
  }
187997
188838
  const releaseLock = await this.acquireLock();
187998
188839
  try {
187999
- const content = fs15.readFileSync(this.statePath, "utf-8");
188840
+ const content = fs16.readFileSync(this.statePath, "utf-8");
188000
188841
  const state = JSON.parse(content);
188001
188842
  if (!this.isProcessRunning(state.owner.pid)) {
188002
188843
  return null;
@@ -188009,21 +188850,21 @@ var InstanceStateManager = class {
188009
188850
  }
188010
188851
  }
188011
188852
  async cleanStaleState() {
188012
- if (!fs15.existsSync(this.statePath)) {
188853
+ if (!fs16.existsSync(this.statePath)) {
188013
188854
  return false;
188014
188855
  }
188015
188856
  const releaseLock = await this.acquireLock();
188016
188857
  try {
188017
- const content = fs15.readFileSync(this.statePath, "utf-8");
188858
+ const content = fs16.readFileSync(this.statePath, "utf-8");
188018
188859
  const state = JSON.parse(content);
188019
188860
  if (!this.isProcessRunning(state.owner.pid)) {
188020
- fs15.unlinkSync(this.statePath);
188861
+ fs16.unlinkSync(this.statePath);
188021
188862
  return true;
188022
188863
  }
188023
188864
  return false;
188024
188865
  } catch {
188025
188866
  try {
188026
- fs15.unlinkSync(this.statePath);
188867
+ fs16.unlinkSync(this.statePath);
188027
188868
  return true;
188028
188869
  } catch {
188029
188870
  }
@@ -188035,8 +188876,8 @@ var InstanceStateManager = class {
188035
188876
  async claimOwnership(command) {
188036
188877
  const releaseLock = await this.acquireLock();
188037
188878
  try {
188038
- if (fs15.existsSync(this.statePath)) {
188039
- const content = fs15.readFileSync(this.statePath, "utf-8");
188879
+ if (fs16.existsSync(this.statePath)) {
188880
+ const content = fs16.readFileSync(this.statePath, "utf-8");
188040
188881
  const state2 = JSON.parse(content);
188041
188882
  if (this.isProcessRunning(state2.owner.pid)) {
188042
188883
  throw new Error(`Instances already owned by PID ${state2.owner.pid}`);
@@ -188105,8 +188946,8 @@ var InstanceStateManager = class {
188105
188946
  }
188106
188947
  const releaseLock = await this.acquireLock();
188107
188948
  try {
188108
- if (fs15.existsSync(this.statePath)) {
188109
- fs15.unlinkSync(this.statePath);
188949
+ if (fs16.existsSync(this.statePath)) {
188950
+ fs16.unlinkSync(this.statePath);
188110
188951
  }
188111
188952
  this.ownsInstances = false;
188112
188953
  } finally {
@@ -188114,31 +188955,32 @@ var InstanceStateManager = class {
188114
188955
  }
188115
188956
  }
188116
188957
  readState() {
188117
- const content = fs15.readFileSync(this.statePath, "utf-8");
188958
+ const content = fs16.readFileSync(this.statePath, "utf-8");
188118
188959
  return JSON.parse(content);
188119
188960
  }
188120
188961
  writeStateAtomic(state) {
188121
188962
  this.ensureStateDir();
188122
188963
  const tmpPath = this.statePath + ".tmp";
188123
- fs15.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
188124
- fs15.renameSync(tmpPath, this.statePath);
188964
+ fs16.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
188965
+ fs16.renameSync(tmpPath, this.statePath);
188125
188966
  }
188126
188967
  };
188127
188968
 
188128
188969
  // src/lib/dev/http-proxy.ts
188129
188970
  import * as http from "http";
188130
188971
  import * as https from "https";
188131
- import * as fs16 from "fs";
188132
- import * as path12 from "path";
188972
+ import * as fs17 from "fs";
188973
+ import * as path13 from "path";
188133
188974
  import { fileURLToPath as fileURLToPath3 } from "url";
188134
188975
  import httpProxy from "http-proxy";
188135
- var __dirname3 = path12.dirname(fileURLToPath3(import.meta.url));
188136
- var adminDir = path12.join(__dirname3, "admin");
188976
+ var __dirname3 = path13.dirname(fileURLToPath3(import.meta.url));
188977
+ var adminDir = path13.join(__dirname3, "admin");
188137
188978
  var HTTP_PORT = 80;
188138
188979
  var HTTPS_PORT = 443;
188139
188980
  var DOMAIN_SUFFIX = ".local.spcf.app";
188140
188981
  var ADMIN_DOMAIN = "local.spcf.app";
188141
188982
  var DRIZZLE_GATEWAY_PREFIX = "__drizzle_gateway";
188983
+ var TEMPORAL_UI_PREFIX = "__temporal";
188142
188984
  var MIME_TYPES = {
188143
188985
  ".html": "text/html",
188144
188986
  ".css": "text/css",
@@ -188157,6 +188999,7 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188157
188999
  const serviceMap = /* @__PURE__ */ new Map();
188158
189000
  const adminPortMap = /* @__PURE__ */ new Map();
188159
189001
  const drizzleGatewayPortMap = /* @__PURE__ */ new Map();
189002
+ const temporalUiPortMap = /* @__PURE__ */ new Map();
188160
189003
  const buildMapKey = (serviceName, key) => {
188161
189004
  return key === "default" ? serviceName : `${serviceName}.${key}`;
188162
189005
  };
@@ -188167,6 +189010,7 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188167
189010
  serviceMap.clear();
188168
189011
  adminPortMap.clear();
188169
189012
  drizzleGatewayPortMap.clear();
189013
+ temporalUiPortMap.clear();
188170
189014
  for (const svc of registryServices) {
188171
189015
  serviceMap.set(buildMapKey(svc.serviceName, svc.key), svc.port);
188172
189016
  }
@@ -188175,6 +189019,9 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188175
189019
  if (registration.drizzleGatewayPort !== void 0) {
188176
189020
  drizzleGatewayPortMap.set(key, registration.drizzleGatewayPort);
188177
189021
  }
189022
+ if (registration.temporalUiPort !== void 0) {
189023
+ temporalUiPortMap.set(key, registration.temporalUiPort);
189024
+ }
188178
189025
  }
188179
189026
  writeLog("proxy", `Updated service map: ${serviceMap.size} services, ${adminPortMap.size} admin instances, ${drizzleGatewayPortMap.size} drizzle gateways`);
188180
189027
  };
@@ -188188,9 +189035,32 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188188
189035
  res.end(`<h1>Bad Gateway</h1><p>Service unavailable: ${err.message}</p>`);
188189
189036
  }
188190
189037
  });
189038
+ proxy.on("proxyRes", (proxyRes, req) => {
189039
+ const host = req.headers?.host || "";
189040
+ if (extractTemporalUiKey(host) !== null || extractDrizzleGatewayKey(host) !== null) {
189041
+ delete proxyRes.headers["x-frame-options"];
189042
+ const csp = proxyRes.headers["content-security-policy"];
189043
+ if (typeof csp === "string" && csp.includes("frame-ancestors")) {
189044
+ proxyRes.headers["content-security-policy"] = csp.split(";").filter((d) => !d.trim().startsWith("frame-ancestors")).join(";");
189045
+ }
189046
+ }
189047
+ });
188191
189048
  const handleRequest = (req, res) => {
188192
189049
  const host = req.headers.host || "";
188193
189050
  const hostname2 = host.split(":")[0];
189051
+ const temporalKey = extractTemporalUiKey(host);
189052
+ if (temporalKey !== null) {
189053
+ const temporalPort = temporalUiPortMap.get(temporalKey);
189054
+ if (temporalPort) {
189055
+ proxy.web(req, res, {
189056
+ target: `http://127.0.0.1:${temporalPort}`
189057
+ });
189058
+ return;
189059
+ }
189060
+ res.writeHead(503, { "Content-Type": "text/html" });
189061
+ res.end("<h1>Workflow Engine</h1><p>No workflow engine running for this instance.</p>");
189062
+ return;
189063
+ }
188194
189064
  const drizzleKey = extractDrizzleGatewayKey(host);
188195
189065
  if (drizzleKey !== null) {
188196
189066
  const drizzlePort = drizzleGatewayPortMap.get(drizzleKey);
@@ -188235,6 +189105,26 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188235
189105
  };
188236
189106
  const handleUpgrade = (req, socket, head) => {
188237
189107
  const host = req.headers.host || "";
189108
+ const temporalKey = extractTemporalUiKey(host);
189109
+ if (temporalKey !== null) {
189110
+ const temporalPort = temporalUiPortMap.get(temporalKey);
189111
+ if (temporalPort) {
189112
+ proxy.ws(req, socket, head, { target: `http://127.0.0.1:${temporalPort}` });
189113
+ return;
189114
+ }
189115
+ socket.end("HTTP/1.1 404 Not Found\r\n\r\n");
189116
+ return;
189117
+ }
189118
+ const drizzleKey = extractDrizzleGatewayKey(host);
189119
+ if (drizzleKey !== null) {
189120
+ const drizzlePort = drizzleGatewayPortMap.get(drizzleKey);
189121
+ if (drizzlePort) {
189122
+ proxy.ws(req, socket, head, { target: `http://127.0.0.1:${drizzlePort}` });
189123
+ return;
189124
+ }
189125
+ socket.end("HTTP/1.1 404 Not Found\r\n\r\n");
189126
+ return;
189127
+ }
188238
189128
  const adminKey = extractAdminKey(host);
188239
189129
  if (adminKey !== null) {
188240
189130
  if (adminPortMap.has(adminKey)) {
@@ -188370,6 +189260,23 @@ function extractDrizzleGatewayKey(host) {
188370
189260
  }
188371
189261
  return null;
188372
189262
  }
189263
+ function extractTemporalUiKey(host) {
189264
+ const hostname2 = host.split(":")[0];
189265
+ if (!hostname2 || !hostname2.endsWith(DOMAIN_SUFFIX)) {
189266
+ return null;
189267
+ }
189268
+ const prefix = hostname2.slice(0, -DOMAIN_SUFFIX.length);
189269
+ if (!prefix) {
189270
+ return null;
189271
+ }
189272
+ const parts = prefix.split(".");
189273
+ if (parts.length === 1 && parts[0] === TEMPORAL_UI_PREFIX) {
189274
+ return "default";
189275
+ } else if (parts.length === 2 && parts[0] === TEMPORAL_UI_PREFIX && parts[1]) {
189276
+ return parts[1];
189277
+ }
189278
+ return null;
189279
+ }
188373
189280
  function extractAdminKey(host) {
188374
189281
  const hostname2 = host.split(":")[0];
188375
189282
  if (!hostname2) {
@@ -188419,18 +189326,18 @@ function serveStaticFile(res, pathname) {
188419
189326
  filePath = filePath + "index.html";
188420
189327
  }
188421
189328
  const relativePath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
188422
- const fullPath = path12.join(adminDir, relativePath);
188423
- const resolvedPath = path12.resolve(fullPath);
188424
- const resolvedAdminDir = path12.resolve(adminDir);
189329
+ const fullPath = path13.join(adminDir, relativePath);
189330
+ const resolvedPath = path13.resolve(fullPath);
189331
+ const resolvedAdminDir = path13.resolve(adminDir);
188425
189332
  if (!resolvedPath.startsWith(resolvedAdminDir)) {
188426
189333
  res.writeHead(403, { "Content-Type": "text/html" });
188427
189334
  res.end("<h1>Forbidden</h1>");
188428
189335
  return;
188429
189336
  }
188430
- if (fs16.existsSync(resolvedPath)) {
188431
- if (fs16.statSync(resolvedPath).isDirectory()) {
188432
- const indexPath2 = path12.join(resolvedPath, "index.html");
188433
- if (fs16.existsSync(indexPath2)) {
189337
+ if (fs17.existsSync(resolvedPath)) {
189338
+ if (fs17.statSync(resolvedPath).isDirectory()) {
189339
+ const indexPath2 = path13.join(resolvedPath, "index.html");
189340
+ if (fs17.existsSync(indexPath2)) {
188434
189341
  return serveFile(res, indexPath2);
188435
189342
  }
188436
189343
  } else {
@@ -188438,28 +189345,28 @@ function serveStaticFile(res, pathname) {
188438
189345
  }
188439
189346
  }
188440
189347
  const htmlPath = resolvedPath + ".html";
188441
- if (fs16.existsSync(htmlPath)) {
189348
+ if (fs17.existsSync(htmlPath)) {
188442
189349
  return serveFile(res, htmlPath);
188443
189350
  }
188444
- const indexPath = path12.join(resolvedPath, "index.html");
188445
- if (fs16.existsSync(indexPath)) {
189351
+ const indexPath = path13.join(resolvedPath, "index.html");
189352
+ if (fs17.existsSync(indexPath)) {
188446
189353
  return serveFile(res, indexPath);
188447
189354
  }
188448
- const notFoundPath = path12.join(adminDir, "404.html");
188449
- if (fs16.existsSync(notFoundPath)) {
189355
+ const notFoundPath = path13.join(adminDir, "404.html");
189356
+ if (fs17.existsSync(notFoundPath)) {
188450
189357
  return serveFileContent(res, notFoundPath, "text/html", 404);
188451
189358
  }
188452
189359
  res.writeHead(404, { "Content-Type": "text/html" });
188453
189360
  res.end("<h1>Not Found</h1>");
188454
189361
  }
188455
189362
  function serveFile(res, filePath) {
188456
- const ext = path12.extname(filePath).toLowerCase();
189363
+ const ext = path13.extname(filePath).toLowerCase();
188457
189364
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
188458
189365
  serveFileContent(res, filePath, contentType, 200);
188459
189366
  }
188460
189367
  function serveFileContent(res, filePath, contentType, statusCode = 200) {
188461
189368
  try {
188462
- const content = fs16.readFileSync(filePath);
189369
+ const content = fs17.readFileSync(filePath);
188463
189370
  res.writeHead(statusCode, { "Content-Type": contentType });
188464
189371
  res.end(content);
188465
189372
  } catch (err) {
@@ -188519,8 +189426,8 @@ import { spawn as spawn3 } from "child_process";
188519
189426
 
188520
189427
  // src/lib/secrets/parser.ts
188521
189428
  import { readFile as readFile2, writeFile as writeFile2, mkdir } from "fs/promises";
188522
- import { existsSync as existsSync14 } from "fs";
188523
- import * as path13 from "path";
189429
+ import { existsSync as existsSync15 } from "fs";
189430
+ import * as path14 from "path";
188524
189431
  import * as crypto2 from "crypto";
188525
189432
  var GENERATED_SECRETS_FILE = ".specific/generated-secrets.json";
188526
189433
  async function loadSecrets() {
@@ -188537,7 +189444,7 @@ function generateRandomString(length = 64) {
188537
189444
  return result;
188538
189445
  }
188539
189446
  async function loadGeneratedSecrets() {
188540
- if (!existsSync14(GENERATED_SECRETS_FILE)) {
189447
+ if (!existsSync15(GENERATED_SECRETS_FILE)) {
188541
189448
  return /* @__PURE__ */ new Map();
188542
189449
  }
188543
189450
  const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
@@ -188546,13 +189453,13 @@ async function loadGeneratedSecrets() {
188546
189453
  }
188547
189454
  async function saveGeneratedSecret(name, value) {
188548
189455
  let secrets = {};
188549
- if (existsSync14(GENERATED_SECRETS_FILE)) {
189456
+ if (existsSync15(GENERATED_SECRETS_FILE)) {
188550
189457
  const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
188551
189458
  secrets = JSON.parse(content);
188552
189459
  }
188553
189460
  secrets[name] = value;
188554
- const dir = path13.dirname(GENERATED_SECRETS_FILE);
188555
- if (!existsSync14(dir)) {
189461
+ const dir = path14.dirname(GENERATED_SECRETS_FILE);
189462
+ if (!existsSync15(dir)) {
188556
189463
  await mkdir(dir, { recursive: true });
188557
189464
  }
188558
189465
  await writeFile2(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
@@ -188706,8 +189613,8 @@ function sleep3(ms) {
188706
189613
 
188707
189614
  // src/lib/dev/drizzle-gateway-manager.ts
188708
189615
  import * as net3 from "net";
188709
- import * as fs17 from "fs";
188710
- import * as path14 from "path";
189616
+ import * as fs18 from "fs";
189617
+ import * as path15 from "path";
188711
189618
  import { spawn as spawn4 } from "child_process";
188712
189619
  import { randomUUID } from "crypto";
188713
189620
  function generateStoreJson(postgresInstances) {
@@ -188739,13 +189646,13 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
188739
189646
  options2?.onProgress
188740
189647
  );
188741
189648
  const host = "127.0.0.1";
188742
- const drizzleConfigDir = path14.join(configDir, "drizzle-gateway");
188743
- if (!fs17.existsSync(drizzleConfigDir)) {
188744
- fs17.mkdirSync(drizzleConfigDir, { recursive: true });
189649
+ const drizzleConfigDir = path15.join(configDir, "drizzle-gateway");
189650
+ if (!fs18.existsSync(drizzleConfigDir)) {
189651
+ fs18.mkdirSync(drizzleConfigDir, { recursive: true });
188745
189652
  }
188746
189653
  const storeJson = generateStoreJson(postgresInstances);
188747
- const storeJsonPath = path14.join(drizzleConfigDir, "store.json");
188748
- fs17.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
189654
+ const storeJsonPath = path15.join(drizzleConfigDir, "store.json");
189655
+ fs18.writeFileSync(storeJsonPath, JSON.stringify(storeJson, null, 2));
188749
189656
  writeLog("drizzle-gateway", `Starting Drizzle Gateway`);
188750
189657
  writeLog("drizzle-gateway", `STORE_PATH: ${drizzleConfigDir}`);
188751
189658
  writeLog("drizzle-gateway", `PORT: ${port}`);
@@ -188847,16 +189754,16 @@ function detectSyncDatabases(config) {
188847
189754
  }
188848
189755
 
188849
189756
  // src/lib/dev/reshape-watcher.ts
188850
- import * as fs18 from "fs";
188851
- import * as path15 from "path";
189757
+ import * as fs19 from "fs";
189758
+ import * as path16 from "path";
188852
189759
  import { spawnSync } from "child_process";
188853
189760
  function getMigrationFiles(dir, log) {
188854
189761
  log(`Scanning migrations directory: ${dir}`);
188855
- if (!fs18.existsSync(dir)) {
189762
+ if (!fs19.existsSync(dir)) {
188856
189763
  log(`Migrations directory does not exist: ${dir}`);
188857
189764
  return [];
188858
189765
  }
188859
- const files = fs18.readdirSync(dir);
189766
+ const files = fs19.readdirSync(dir);
188860
189767
  log(`Found ${files.length} files in directory`);
188861
189768
  const tomlFiles = files.filter((f) => f.endsWith(".toml")).sort((a, b) => a.localeCompare(b));
188862
189769
  log(`Found ${tomlFiles.length} .toml migration files: ${tomlFiles.join(", ") || "(none)"}`);
@@ -188906,7 +189813,7 @@ function runReshape(args, databaseUrl, migrationsDir, reshapeBinaryPath, log) {
188906
189813
  }
188907
189814
  function makeReadOnly(filePath, log) {
188908
189815
  try {
188909
- fs18.chmodSync(filePath, 292);
189816
+ fs19.chmodSync(filePath, 292);
188910
189817
  log(`Set file permissions to read-only (444): ${filePath}`);
188911
189818
  } catch (err) {
188912
189819
  const message = err instanceof Error ? err.message : String(err);
@@ -188967,7 +189874,7 @@ function createReshapeWatcher(options2) {
188967
189874
  log(`Successfully completed ${currentMigrationFiles.length - 1} migration(s)`);
188968
189875
  log(`Making completed migration files read-only...`);
188969
189876
  for (let i = 0; i < currentMigrationFiles.length - 1; i++) {
188970
- const filePath = path15.join(migrationsDir, currentMigrationFiles[i]);
189877
+ const filePath = path16.join(migrationsDir, currentMigrationFiles[i]);
188971
189878
  makeReadOnly(filePath, log);
188972
189879
  }
188973
189880
  log(`Starting latest migration "${lastMigrationName}" (will not be completed, allowing iteration)`);
@@ -188992,9 +189899,9 @@ function createReshapeWatcher(options2) {
188992
189899
  };
188993
189900
  const startWatching = () => {
188994
189901
  log(`Starting file watcher for migrations directory...`);
188995
- if (!fs18.existsSync(migrationsDir)) {
189902
+ if (!fs19.existsSync(migrationsDir)) {
188996
189903
  log(`Migrations directory does not exist, creating: ${migrationsDir}`);
188997
- fs18.mkdirSync(migrationsDir, { recursive: true });
189904
+ fs19.mkdirSync(migrationsDir, { recursive: true });
188998
189905
  }
188999
189906
  log(`Watching directory: ${migrationsDir}`);
189000
189907
  watcher = chokidar_default.watch(migrationsDir, {
@@ -189007,7 +189914,7 @@ function createReshapeWatcher(options2) {
189007
189914
  }
189008
189915
  });
189009
189916
  watcher.on("change", (filePath) => {
189010
- const filename = path15.basename(filePath);
189917
+ const filename = path16.basename(filePath);
189011
189918
  if (!filename.endsWith(".toml")) return;
189012
189919
  log(`File change detected: ${filename}`);
189013
189920
  log(` Full path: ${filePath}`);
@@ -189038,7 +189945,7 @@ function createReshapeWatcher(options2) {
189038
189945
  }
189039
189946
  });
189040
189947
  watcher.on("add", (filePath) => {
189041
- const filename = path15.basename(filePath);
189948
+ const filename = path16.basename(filePath);
189042
189949
  if (!filename.endsWith(".toml")) return;
189043
189950
  log(`New file detected: ${filename}`);
189044
189951
  log(` Full path: ${filePath}`);
@@ -189062,7 +189969,7 @@ function createReshapeWatcher(options2) {
189062
189969
  return;
189063
189970
  }
189064
189971
  log(`Previous migration completed successfully`);
189065
- const completedPath = path15.join(migrationsDir, startedMigration);
189972
+ const completedPath = path16.join(migrationsDir, startedMigration);
189066
189973
  makeReadOnly(completedPath, log);
189067
189974
  } else {
189068
189975
  log(`No previous migration was started`);
@@ -189087,7 +189994,7 @@ function createReshapeWatcher(options2) {
189087
189994
  onSearchPathChanged(newSearchPath);
189088
189995
  });
189089
189996
  watcher.on("unlink", (filePath) => {
189090
- const filename = path15.basename(filePath);
189997
+ const filename = path16.basename(filePath);
189091
189998
  if (!filename.endsWith(".toml")) return;
189092
189999
  log(`File deleted: ${filename}`);
189093
190000
  log(` Full path: ${filePath}`);
@@ -189128,9 +190035,110 @@ function createReshapeWatcher(options2) {
189128
190035
  };
189129
190036
  }
189130
190037
 
190038
+ // src/lib/dev/temporal-manager.ts
190039
+ import * as fs20 from "fs";
190040
+ import * as path17 from "path";
190041
+ import * as net4 from "net";
190042
+ import { spawn as spawn5 } from "child_process";
190043
+ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onProgress) {
190044
+ const binary = await ensureBinary(temporalBinary, void 0, onProgress);
190045
+ const dbPath = path17.join(process.cwd(), dataDir, "temporal.db");
190046
+ const dbDir = path17.dirname(dbPath);
190047
+ if (!fs20.existsSync(dbDir)) {
190048
+ fs20.mkdirSync(dbDir, { recursive: true });
190049
+ }
190050
+ const host = "127.0.0.1";
190051
+ const namespaceArgs = temporals.flatMap((t) => ["--namespace", t.name]);
190052
+ const proc = spawn5(
190053
+ binary.executables["temporal"],
190054
+ [
190055
+ "server",
190056
+ "start-dev",
190057
+ "--port",
190058
+ String(grpcPort),
190059
+ "--ui-port",
190060
+ String(uiPort),
190061
+ "--db-filename",
190062
+ dbPath,
190063
+ ...namespaceArgs,
190064
+ "--log-format",
190065
+ "pretty"
190066
+ ],
190067
+ {
190068
+ stdio: ["ignore", "pipe", "pipe"]
190069
+ }
190070
+ );
190071
+ pipeProcess("temporal", proc);
190072
+ await waitForTcpPort4(host, grpcPort);
190073
+ const stopServer = () => stopProcess4(proc);
190074
+ const instances = temporals.map((temporal, i) => ({
190075
+ name: temporal.name,
190076
+ type: "temporal",
190077
+ port: grpcPort,
190078
+ host,
190079
+ user: "",
190080
+ password: "",
190081
+ dbName: temporal.name,
190082
+ url: `${host}:${grpcPort}`,
190083
+ uiPort,
190084
+ // Only the first instance owns the server lifecycle
190085
+ stop: i === 0 ? stopServer : async () => {
190086
+ }
190087
+ }));
190088
+ return instances;
190089
+ }
190090
+ async function waitForTcpPort4(host, port, timeoutMs = 3e4) {
190091
+ const startTime = Date.now();
190092
+ while (Date.now() - startTime < timeoutMs) {
190093
+ const isOpen = await checkTcpPort4(host, port);
190094
+ if (isOpen) {
190095
+ return;
190096
+ }
190097
+ await new Promise((resolve10) => setTimeout(resolve10, 100));
190098
+ }
190099
+ throw new Error(`Temporal port ${port} did not become available within timeout`);
190100
+ }
190101
+ function checkTcpPort4(host, port) {
190102
+ return new Promise((resolve10) => {
190103
+ const socket = new net4.Socket();
190104
+ socket.setTimeout(1e3);
190105
+ socket.on("connect", () => {
190106
+ socket.destroy();
190107
+ resolve10(true);
190108
+ });
190109
+ socket.on("timeout", () => {
190110
+ socket.destroy();
190111
+ resolve10(false);
190112
+ });
190113
+ socket.on("error", () => {
190114
+ socket.destroy();
190115
+ resolve10(false);
190116
+ });
190117
+ socket.connect(port, host);
190118
+ });
190119
+ }
190120
+ async function stopProcess4(proc) {
190121
+ return new Promise((resolve10) => {
190122
+ if (proc.killed || proc.exitCode !== null) {
190123
+ resolve10();
190124
+ return;
190125
+ }
190126
+ proc.once("exit", () => {
190127
+ clearTimeout(forceKillTimeout);
190128
+ resolve10();
190129
+ });
190130
+ proc.kill("SIGTERM");
190131
+ const forceKillTimeout = setTimeout(() => {
190132
+ if (!proc.killed && proc.exitCode === null) {
190133
+ proc.kill("SIGKILL");
190134
+ }
190135
+ }, 2e3);
190136
+ });
190137
+ }
190138
+
189131
190139
  // src/lib/dev/resource-starter.ts
189132
190140
  function findRequiredResources(service) {
189133
- const required = { postgres: [], redis: [], storage: [] };
190141
+ const required = { postgres: [], redis: [], storage: [], temporal: [] };
189134
190142
  if (service.env) {
189135
190143
  for (const value of Object.values(service.env)) {
189136
190144
  if (typeof value !== "object" || value === null) continue;
@@ -189142,6 +190150,8 @@ function findRequiredResources(service) {
189142
190150
  required.redis.push(ref.name);
189143
190151
  } else if (ref.type === "storage" && !required.storage.includes(ref.name)) {
189144
190152
  required.storage.push(ref.name);
190153
+ } else if (ref.type === "temporal" && !required.temporal.includes(ref.name)) {
190154
+ required.temporal.push(ref.name);
189145
190155
  }
189146
190156
  }
189147
190157
  }
@@ -189168,14 +190178,17 @@ async function startResources(options2) {
189168
190178
  let postgresConfigs;
189169
190179
  let redisConfigs;
189170
190180
  let storageConfigs;
190181
+ let temporalConfigs;
189171
190182
  if (selection.mode === "all") {
189172
190183
  postgresConfigs = config.postgres;
189173
190184
  redisConfigs = config.redis;
189174
190185
  storageConfigs = config.storage;
190186
+ temporalConfigs = config.temporal;
189175
190187
  } else {
189176
190188
  postgresConfigs = config.postgres.filter((p) => selection.postgres.includes(p.name));
189177
190189
  redisConfigs = config.redis.filter((r) => selection.redis.includes(r.name));
189178
190190
  storageConfigs = config.storage.filter((s) => selection.storage.includes(s.name));
190191
+ temporalConfigs = config.temporal.filter((t) => selection.temporal.includes(t.name));
189179
190192
  }
189180
190193
  for (const pg of postgresConfigs) {
189181
190194
  if (signal?.cancelled) {
@@ -189261,6 +190274,25 @@ async function startResources(options2) {
189261
190274
  if (instance.secretKey) dbState.secretKey = instance.secretKey;
189262
190275
  await stateManager.registerDatabase(storage.name, dbState);
189263
190276
  }
190277
+ if (temporalConfigs.length > 0) {
190278
+ if (signal?.cancelled) {
190279
+ return { resources, electric, startedResources, startedElectric, cancelled: true };
190280
+ }
190281
+ const grpcPort = portAllocator.allocate("temporal-grpc");
190282
+ const uiPort = portAllocator.allocate("temporal-ui");
190283
+ const names = temporalConfigs.map((t) => t.name).join(", ");
190284
+ log(`Starting temporal dev server on port ${grpcPort} (UI: ${uiPort}) with namespaces: ${names}`);
190285
+ callbacks.onResourceStarting?.(temporalConfigs[0].name, "temporal");
190286
+ const instances = await startTemporalDevServer(temporalConfigs, grpcPort, uiPort, dataDir, (progress) => {
190287
+ callbacks.onResourceProgress?.(temporalConfigs[0].name, progress);
190288
+ });
190289
+ for (const instance of instances) {
190290
+ resources.set(instance.name, instance);
190291
+ startedResources.push(instance);
190292
+ callbacks.onResourceReady?.(instance.name, instance);
190293
+ log(`Temporal namespace "${instance.name}" ready`);
190294
+ }
190295
+ }
189264
190296
  if (shouldStartElectric) {
189265
190297
  const syncDatabases = detectSyncDatabases(config);
189266
190298
  for (const pgName of syncDatabases) {
@@ -189311,24 +190343,24 @@ function watchConfigFile(configPath, debounceMs, onChange) {
189311
190343
  }
189312
190344
 
189313
190345
  // src/lib/dev/subdomain-generator.ts
189314
- import * as fs19 from "fs";
189315
- import * as path16 from "path";
190346
+ import * as fs21 from "fs";
190347
+ import * as path18 from "path";
189316
190348
  import { generateSlug } from "random-word-slugs";
189317
190349
  var StableSubdomainAllocator = class {
189318
190350
  tunnelsDir;
189319
190351
  tunnelsFilePath;
189320
190352
  baseSlug = null;
189321
190353
  constructor(projectRoot, key = "default") {
189322
- this.tunnelsDir = path16.join(projectRoot, ".specific", "keys", key);
189323
- this.tunnelsFilePath = path16.join(this.tunnelsDir, "tunnels.json");
190354
+ this.tunnelsDir = path18.join(projectRoot, ".specific", "keys", key);
190355
+ this.tunnelsFilePath = path18.join(this.tunnelsDir, "tunnels.json");
189324
190356
  this.loadTunnels();
189325
190357
  }
189326
190358
  loadTunnels() {
189327
- if (!fs19.existsSync(this.tunnelsFilePath)) {
190359
+ if (!fs21.existsSync(this.tunnelsFilePath)) {
189328
190360
  return;
189329
190361
  }
189330
190362
  try {
189331
- const content = fs19.readFileSync(this.tunnelsFilePath, "utf-8");
190363
+ const content = fs21.readFileSync(this.tunnelsFilePath, "utf-8");
189332
190364
  const data = JSON.parse(content);
189333
190365
  if (data.version === 1 && data.baseSlug) {
189334
190366
  this.baseSlug = data.baseSlug;
@@ -189338,14 +190370,14 @@ var StableSubdomainAllocator = class {
189338
190370
  }
189339
190371
  }
189340
190372
  saveTunnels() {
189341
- if (!fs19.existsSync(this.tunnelsDir)) {
189342
- fs19.mkdirSync(this.tunnelsDir, { recursive: true });
190373
+ if (!fs21.existsSync(this.tunnelsDir)) {
190374
+ fs21.mkdirSync(this.tunnelsDir, { recursive: true });
189343
190375
  }
189344
190376
  const data = {
189345
190377
  version: 1,
189346
190378
  baseSlug: this.baseSlug
189347
190379
  };
189348
- fs19.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
190380
+ fs21.writeFileSync(this.tunnelsFilePath, JSON.stringify(data, null, 2));
189349
190381
  }
189350
190382
  generateBaseSlug() {
189351
190383
  return generateSlug(2, {
@@ -189382,7 +190414,7 @@ var StableSubdomainAllocator = class {
189382
190414
 
189383
190415
  // node_modules/.pnpm/@specific+tunnel-client@file+..+tunnel+client/node_modules/@specific/tunnel-client/dist/index.js
189384
190416
  import { EventEmitter as EventEmitter2 } from "node:events";
189385
- import * as net4 from "node:net";
190417
+ import * as net5 from "node:net";
189386
190418
  var DEFAULT_HOST = "https://tunnel.spcf.app";
189387
190419
  var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 15e3];
189388
190420
  async function register(baseUrl, subdomain) {
@@ -189424,7 +190456,7 @@ var TunnelClientImpl = class extends EventEmitter2 {
189424
190456
  }
189425
190457
  }
189426
190458
  addPoolConnection() {
189427
- const remote = net4.connect({ host: this.tunnelHost, port: this.info.port });
190459
+ const remote = net5.connect({ host: this.tunnelHost, port: this.info.port });
189428
190460
  remote.setKeepAlive(true, 3e4);
189429
190461
  this.pool.add(remote);
189430
190462
  remote.once("data", (firstChunk) => {
@@ -189439,7 +190471,7 @@ var TunnelClientImpl = class extends EventEmitter2 {
189439
190471
  remote.on("close", () => this.onIdleClose(remote, errored));
189440
190472
  }
189441
190473
  pipeToLocal(remote, firstChunk) {
189442
- const local = net4.connect({ host: "127.0.0.1", port: this.localPort }, () => {
190474
+ const local = net5.connect({ host: "127.0.0.1", port: this.localPort }, () => {
189443
190475
  local.write(firstChunk);
189444
190476
  remote.pipe(local);
189445
190477
  local.pipe(remote);
@@ -189501,10 +190533,10 @@ async function startTunnel(serviceName, endpointName, port, subdomain, callbacks
189501
190533
  }
189502
190534
 
189503
190535
  // src/lib/dev/proxy-registry.ts
189504
- import * as fs20 from "fs";
189505
- import * as path17 from "path";
189506
- import * as os7 from "os";
189507
- import * as net5 from "net";
190536
+ import * as fs22 from "fs";
190537
+ import * as path19 from "path";
190538
+ import * as os8 from "os";
190539
+ import * as net6 from "net";
189508
190540
  var ProxyRegistryManager = class {
189509
190541
  proxyDir;
189510
190542
  ownerPath;
@@ -189513,14 +190545,14 @@ var ProxyRegistryManager = class {
189513
190545
  isOwner = false;
189514
190546
  registryWatcher = null;
189515
190547
  constructor() {
189516
- this.proxyDir = path17.join(os7.homedir(), ".specific", "proxy");
189517
- this.ownerPath = path17.join(this.proxyDir, "owner.json");
189518
- this.registryPath = path17.join(this.proxyDir, "registry.json");
189519
- this.lockPath = path17.join(this.proxyDir, "registry.lock");
190548
+ this.proxyDir = path19.join(os8.homedir(), ".specific", "proxy");
190549
+ this.ownerPath = path19.join(this.proxyDir, "owner.json");
190550
+ this.registryPath = path19.join(this.proxyDir, "registry.json");
190551
+ this.lockPath = path19.join(this.proxyDir, "registry.lock");
189520
190552
  }
189521
190553
  ensureProxyDir() {
189522
- if (!fs20.existsSync(this.proxyDir)) {
189523
- fs20.mkdirSync(this.proxyDir, { recursive: true });
190554
+ if (!fs22.existsSync(this.proxyDir)) {
190555
+ fs22.mkdirSync(this.proxyDir, { recursive: true });
189524
190556
  }
189525
190557
  }
189526
190558
  isProcessRunning(pid) {
@@ -189538,7 +190570,7 @@ var ProxyRegistryManager = class {
189538
190570
  */
189539
190571
  isProxyListening(port, timeoutMs = 1e3) {
189540
190572
  return new Promise((resolve10) => {
189541
- const socket = new net5.Socket();
190573
+ const socket = new net6.Socket();
189542
190574
  let resolved = false;
189543
190575
  const cleanup = () => {
189544
190576
  if (!resolved) {
@@ -189577,15 +190609,15 @@ var ProxyRegistryManager = class {
189577
190609
  const startTime = Date.now();
189578
190610
  while (Date.now() - startTime < timeoutMs) {
189579
190611
  try {
189580
- const fd = fs20.openSync(
190612
+ const fd = fs22.openSync(
189581
190613
  this.lockPath,
189582
- fs20.constants.O_CREAT | fs20.constants.O_EXCL | fs20.constants.O_WRONLY
190614
+ fs22.constants.O_CREAT | fs22.constants.O_EXCL | fs22.constants.O_WRONLY
189583
190615
  );
189584
- fs20.writeSync(fd, String(process.pid));
189585
- fs20.closeSync(fd);
190616
+ fs22.writeSync(fd, String(process.pid));
190617
+ fs22.closeSync(fd);
189586
190618
  return () => {
189587
190619
  try {
189588
- fs20.unlinkSync(this.lockPath);
190620
+ fs22.unlinkSync(this.lockPath);
189589
190621
  } catch {
189590
190622
  }
189591
190623
  };
@@ -189594,16 +190626,16 @@ var ProxyRegistryManager = class {
189594
190626
  if (err.code === "EEXIST") {
189595
190627
  try {
189596
190628
  const lockPid = parseInt(
189597
- fs20.readFileSync(this.lockPath, "utf-8").trim(),
190629
+ fs22.readFileSync(this.lockPath, "utf-8").trim(),
189598
190630
  10
189599
190631
  );
189600
190632
  if (!this.isProcessRunning(lockPid)) {
189601
- fs20.unlinkSync(this.lockPath);
190633
+ fs22.unlinkSync(this.lockPath);
189602
190634
  continue;
189603
190635
  }
189604
190636
  } catch {
189605
190637
  try {
189606
- fs20.unlinkSync(this.lockPath);
190638
+ fs22.unlinkSync(this.lockPath);
189607
190639
  } catch {
189608
190640
  }
189609
190641
  continue;
@@ -189623,8 +190655,8 @@ var ProxyRegistryManager = class {
189623
190655
  async claimProxyOwnership(key) {
189624
190656
  const releaseLock = await this.acquireLock();
189625
190657
  try {
189626
- if (fs20.existsSync(this.ownerPath)) {
189627
- const content = fs20.readFileSync(this.ownerPath, "utf-8");
190658
+ if (fs22.existsSync(this.ownerPath)) {
190659
+ const content = fs22.readFileSync(this.ownerPath, "utf-8");
189628
190660
  const ownerFile2 = JSON.parse(content);
189629
190661
  if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
189630
190662
  return false;
@@ -189654,11 +190686,11 @@ var ProxyRegistryManager = class {
189654
190686
  }
189655
190687
  const releaseLock = await this.acquireLock();
189656
190688
  try {
189657
- if (fs20.existsSync(this.ownerPath)) {
189658
- const content = fs20.readFileSync(this.ownerPath, "utf-8");
190689
+ if (fs22.existsSync(this.ownerPath)) {
190690
+ const content = fs22.readFileSync(this.ownerPath, "utf-8");
189659
190691
  const ownerFile = JSON.parse(content);
189660
190692
  if (ownerFile.owner.pid === process.pid) {
189661
- fs20.unlinkSync(this.ownerPath);
190693
+ fs22.unlinkSync(this.ownerPath);
189662
190694
  }
189663
190695
  }
189664
190696
  this.isOwner = false;
@@ -189670,12 +190702,12 @@ var ProxyRegistryManager = class {
189670
190702
  * Get the current proxy owner.
189671
190703
  */
189672
190704
  async getProxyOwner() {
189673
- if (!fs20.existsSync(this.ownerPath)) {
190705
+ if (!fs22.existsSync(this.ownerPath)) {
189674
190706
  return null;
189675
190707
  }
189676
190708
  const releaseLock = await this.acquireLock();
189677
190709
  try {
189678
- const content = fs20.readFileSync(this.ownerPath, "utf-8");
190710
+ const content = fs22.readFileSync(this.ownerPath, "utf-8");
189679
190711
  const ownerFile = JSON.parse(content);
189680
190712
  if (!await this.isProxyOwnerHealthy(ownerFile.owner.pid)) {
189681
190713
  return null;
@@ -189696,7 +190728,7 @@ var ProxyRegistryManager = class {
189696
190728
  /**
189697
190729
  * Register services for a key.
189698
190730
  */
189699
- async registerServices(key, adminPort, services, drizzleGatewayPort) {
190731
+ async registerServices(key, adminPort, services, drizzleGatewayPort, temporalUiPort) {
189700
190732
  const releaseLock = await this.acquireLock();
189701
190733
  try {
189702
190734
  const registry = this.readRegistry();
@@ -189707,6 +190739,9 @@ var ProxyRegistryManager = class {
189707
190739
  if (drizzleGatewayPort !== void 0) {
189708
190740
  registration.drizzleGatewayPort = drizzleGatewayPort;
189709
190741
  }
190742
+ if (temporalUiPort !== void 0) {
190743
+ registration.temporalUiPort = temporalUiPort;
190744
+ }
189710
190745
  registry.keys[key] = registration;
189711
190746
  registry.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
189712
190747
  this.writeFileAtomic(this.registryPath, registry);
@@ -189769,7 +190804,7 @@ var ProxyRegistryManager = class {
189769
190804
  */
189770
190805
  watchRegistry(onChange) {
189771
190806
  this.ensureProxyDir();
189772
- if (!fs20.existsSync(this.registryPath)) {
190807
+ if (!fs22.existsSync(this.registryPath)) {
189773
190808
  const emptyRegistry = {
189774
190809
  version: 1,
189775
190810
  keys: {},
@@ -189812,13 +190847,13 @@ var ProxyRegistryManager = class {
189812
190847
  async attemptElection(key) {
189813
190848
  const releaseLock = await this.acquireLock();
189814
190849
  try {
189815
- if (fs20.existsSync(this.ownerPath)) {
189816
- const content = fs20.readFileSync(this.ownerPath, "utf-8");
190850
+ if (fs22.existsSync(this.ownerPath)) {
190851
+ const content = fs22.readFileSync(this.ownerPath, "utf-8");
189817
190852
  const ownerFile2 = JSON.parse(content);
189818
190853
  if (await this.isProxyOwnerHealthy(ownerFile2.owner.pid)) {
189819
190854
  return false;
189820
190855
  }
189821
- fs20.unlinkSync(this.ownerPath);
190856
+ fs22.unlinkSync(this.ownerPath);
189822
190857
  }
189823
190858
  const ownerFile = {
189824
190859
  version: 1,
@@ -189836,7 +190871,7 @@ var ProxyRegistryManager = class {
189836
190871
  }
189837
190872
  }
189838
190873
  readRegistry() {
189839
- if (!fs20.existsSync(this.registryPath)) {
190874
+ if (!fs22.existsSync(this.registryPath)) {
189840
190875
  return {
189841
190876
  version: 1,
189842
190877
  keys: {},
@@ -189844,7 +190879,7 @@ var ProxyRegistryManager = class {
189844
190879
  };
189845
190880
  }
189846
190881
  try {
189847
- const content = fs20.readFileSync(this.registryPath, "utf-8");
190882
+ const content = fs22.readFileSync(this.registryPath, "utf-8");
189848
190883
  return JSON.parse(content);
189849
190884
  } catch {
189850
190885
  return {
@@ -189857,8 +190892,8 @@ var ProxyRegistryManager = class {
189857
190892
  writeFileAtomic(filePath, data) {
189858
190893
  this.ensureProxyDir();
189859
190894
  const tmpPath = filePath + ".tmp";
189860
- fs20.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
189861
- fs20.renameSync(tmpPath, filePath);
190895
+ fs22.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
190896
+ fs22.renameSync(tmpPath, filePath);
189862
190897
  }
189863
190898
  };
189864
190899
 
@@ -189962,10 +190997,10 @@ var COLORS = ["cyan", "yellow", "green", "magenta", "blue"];
189962
190997
  function DevUI({ instanceKey, tunnelEnabled }) {
189963
190998
  const { exit } = useApp2();
189964
190999
  const [state, setState] = useState5(() => {
189965
- const caExists = tunnelEnabled || caFilesExist();
191000
+ const setupDone = tunnelEnabled || !systemSetupNeeded();
189966
191001
  return {
189967
- status: caExists ? "loading" : "installing-ca",
189968
- ...caExists ? {} : { caInstallPhase: "installing" },
191002
+ status: setupDone ? "loading" : "installing-ca",
191003
+ ...setupDone ? {} : { caInstallPhase: "installing" },
189969
191004
  resources: /* @__PURE__ */ new Map(),
189970
191005
  resourceStatus: /* @__PURE__ */ new Map(),
189971
191006
  services: [],
@@ -189978,18 +191013,15 @@ function DevUI({ instanceKey, tunnelEnabled }) {
189978
191013
  });
189979
191014
  useEffect3(() => {
189980
191015
  if (state.status === "installing-ca" && state.caInstallPhase === "installing") {
189981
- installCA();
191016
+ installSystemConfig();
189982
191017
  }
189983
191018
  }, [state.status, state.caInstallPhase]);
189984
- async function installCA() {
191019
+ async function installSystemConfig() {
189985
191020
  try {
189986
- const { key, cert } = generateRootCA();
189987
- const certPath = saveCA(key, cert);
189988
- installCAToTrustStore(certPath);
191021
+ performSystemSetup();
189989
191022
  setState((s) => ({ ...s, status: "loading", caInstallPhase: "done" }));
189990
191023
  setReadyToStart(true);
189991
191024
  } catch (err) {
189992
- removeCA();
189993
191025
  setState((s) => ({
189994
191026
  ...s,
189995
191027
  caInstallPhase: "error",
@@ -190007,13 +191039,14 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190007
191039
  const registryWatcherCleanupRef = useRef(null);
190008
191040
  const electionIntervalRef = useRef(null);
190009
191041
  const tunnelsRef = useRef([]);
191042
+ const dnsServerRef = useRef(null);
190010
191043
  const proxyRef = useRef(null);
190011
191044
  const adminServerRef = useRef(null);
190012
191045
  const servicesRef = useRef([]);
190013
191046
  const resourcesRef = useRef(/* @__PURE__ */ new Map());
190014
191047
  const restartServicesRef = useRef(null);
190015
191048
  const [reloadTrigger, setReloadTrigger] = useState5(0);
190016
- const [readyToStart, setReadyToStart] = useState5(() => tunnelEnabled || caFilesExist());
191049
+ const [readyToStart, setReadyToStart] = useState5(() => tunnelEnabled || !systemSetupNeeded());
190017
191050
  const shutdown2 = async () => {
190018
191051
  if (shuttingDown.current) return;
190019
191052
  shuttingDown.current = true;
@@ -190032,6 +191065,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190032
191065
  await Promise.all([
190033
191066
  // Stop proxy
190034
191067
  proxyRef.current?.stop(),
191068
+ // Stop DNS server
191069
+ dnsServerRef.current?.stop(),
190035
191070
  // Stop admin server
190036
191071
  adminServerRef.current?.stop(),
190037
191072
  // Stop all services
@@ -190075,6 +191110,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190075
191110
  await Promise.all([
190076
191111
  // Stop proxy
190077
191112
  proxyRef.current?.stop(),
191113
+ // Stop DNS server
191114
+ dnsServerRef.current?.stop(),
190078
191115
  // Stop admin server
190079
191116
  adminServerRef.current?.stop(),
190080
191117
  // Stop all services
@@ -190095,6 +191132,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190095
191132
  restartServicesRef.current = null;
190096
191133
  drizzleGatewayRef.current = null;
190097
191134
  proxyRef.current = null;
191135
+ dnsServerRef.current = null;
190098
191136
  adminServerRef.current = null;
190099
191137
  servicesRef.current = [];
190100
191138
  resourcesRef.current = /* @__PURE__ */ new Map();
@@ -190126,6 +191164,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190126
191164
  writeLog("system", "Force shutting down");
190127
191165
  const allProcesses = [
190128
191166
  proxyRef.current,
191167
+ dnsServerRef.current,
190129
191168
  ...servicesRef.current,
190130
191169
  ...electricInstancesRef.current,
190131
191170
  drizzleGatewayRef.current,
@@ -190167,16 +191206,16 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190167
191206
  }, [state.status]);
190168
191207
  useEffect3(() => {
190169
191208
  if (state.status !== "running") return;
190170
- const configPath = path18.join(process.cwd(), "specific.hcl");
191209
+ const configPath = path20.join(process.cwd(), "specific.hcl");
190171
191210
  const watcher = watchConfigFile(configPath, 1e3, () => {
190172
191211
  try {
190173
- const hcl = fs21.readFileSync(configPath, "utf-8");
191212
+ const hcl = fs23.readFileSync(configPath, "utf-8");
190174
191213
  parseConfig(hcl).then(() => {
190175
191214
  triggerReload();
190176
191215
  }).catch((err) => {
190177
191216
  setState((s) => ({
190178
191217
  ...s,
190179
- parseError: `Config error: ${err instanceof Error ? err.message : String(err)}`
191218
+ parseError: formatConfigError(err, hcl, configPath)
190180
191219
  }));
190181
191220
  });
190182
191221
  } catch (err) {
@@ -190295,8 +191334,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190295
191334
  }));
190296
191335
  return;
190297
191336
  }
190298
- const configPath = path18.join(process.cwd(), "specific.hcl");
190299
- if (!fs21.existsSync(configPath)) {
191337
+ const configPath = path20.join(process.cwd(), "specific.hcl");
191338
+ if (!fs23.existsSync(configPath)) {
190300
191339
  writeLog("system", "Waiting for specific.hcl to appear");
190301
191340
  setState((s) => ({
190302
191341
  ...s,
@@ -190314,14 +191353,14 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190314
191353
  return;
190315
191354
  }
190316
191355
  let config2;
191356
+ const hcl = fs23.readFileSync(configPath, "utf-8");
190317
191357
  try {
190318
- const hcl = fs21.readFileSync(configPath, "utf-8");
190319
191358
  config2 = await parseConfig(hcl);
190320
191359
  } catch (err) {
190321
191360
  setState((s) => ({
190322
191361
  ...s,
190323
191362
  status: "error",
190324
- error: err instanceof Error ? err.message : String(err)
191363
+ error: formatConfigError(err, hcl, configPath)
190325
191364
  }));
190326
191365
  return;
190327
191366
  }
@@ -190340,6 +191379,10 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190340
191379
  colorMap.set(`res:${storage.name}`, COLORS[colorIndex % COLORS.length]);
190341
191380
  colorIndex++;
190342
191381
  }
191382
+ for (const temporal of config2.temporal) {
191383
+ colorMap.set(`res:${temporal.name}`, COLORS[colorIndex % COLORS.length]);
191384
+ colorIndex++;
191385
+ }
190343
191386
  for (const service of config2.services) {
190344
191387
  colorMap.set(
190345
191388
  `svc:${service.name}`,
@@ -190421,7 +191464,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190421
191464
  const drizzleGateway = await startDrizzleGateway(
190422
191465
  postgresResources,
190423
191466
  drizzlePort,
190424
- path18.join(process.cwd(), ".specific", "keys", instanceKey)
191467
+ path20.join(process.cwd(), ".specific", "keys", instanceKey)
190425
191468
  );
190426
191469
  startedDrizzleGateway = drizzleGateway;
190427
191470
  drizzleGatewayRef.current = drizzleGateway;
@@ -190441,7 +191484,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
190441
191484
  if (pg.reshape?.enabled) {
190442
191485
  const resource = resources2.get(pg.name);
190443
191486
  if (!resource) continue;
190444
- const migrationsDir = path18.resolve(
191487
+ const migrationsDir = path20.resolve(
190445
191488
  process.cwd(),
190446
191489
  pg.reshape.migrations_dir ?? "migrations"
190447
191490
  );
@@ -190609,10 +191652,10 @@ Add them to the config block in specific.local`);
190609
191652
  }
190610
191653
  const services2 = [];
190611
191654
  function resolveServiceCwd(service) {
190612
- if (service.root) return path18.resolve(process.cwd(), service.root);
191655
+ if (service.root) return path20.resolve(process.cwd(), service.root);
190613
191656
  if (service.build) {
190614
191657
  const build = config2.builds.find((b) => b.name === service.build.name);
190615
- if (build?.root) return path18.resolve(process.cwd(), build.root);
191658
+ if (build?.root) return path20.resolve(process.cwd(), build.root);
190616
191659
  }
190617
191660
  return process.cwd();
190618
191661
  }
@@ -190631,6 +191674,14 @@ Add them to the config block in specific.local`);
190631
191674
  "system",
190632
191675
  `Starting service "${service.name}"${portsList ? ` on port${endpointPorts.size > 1 ? "s" : ""} ${portsList}` : ""}`
190633
191676
  );
191677
+ const volumePaths = /* @__PURE__ */ new Map();
191678
+ if (service.volumes) {
191679
+ for (const vol of service.volumes) {
191680
+ const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
191681
+ fs23.mkdirSync(volumeDir, { recursive: true });
191682
+ volumePaths.set(vol.name, volumeDir);
191683
+ }
191684
+ }
190634
191685
  const running = startService(
190635
191686
  service,
190636
191687
  resources2,
@@ -190640,7 +191691,8 @@ Add them to the config block in specific.local`);
190640
191691
  serviceEndpoints,
190641
191692
  (line) => addLog(line, colorMap),
190642
191693
  publicUrls,
190643
- resolveServiceCwd(service)
191694
+ resolveServiceCwd(service),
191695
+ volumePaths
190644
191696
  );
190645
191697
  services2.push(running);
190646
191698
  startedServices.push(running);
@@ -190678,6 +191730,14 @@ Add them to the config block in specific.local`);
190678
191730
  if (!service.command && !service.dev?.command) continue;
190679
191731
  try {
190680
191732
  const endpointPorts = serviceEndpointPorts.get(service.name) || /* @__PURE__ */ new Map();
191733
+ const volumePaths = /* @__PURE__ */ new Map();
191734
+ if (service.volumes) {
191735
+ for (const vol of service.volumes) {
191736
+ const volumeDir = path20.resolve(`.specific/keys/${instanceKey}/data/volumes/${service.name}/${vol.name}`);
191737
+ fs23.mkdirSync(volumeDir, { recursive: true });
191738
+ volumePaths.set(vol.name, volumeDir);
191739
+ }
191740
+ }
190681
191741
  const running = startService(
190682
191742
  service,
190683
191743
  resources2,
@@ -190687,7 +191747,8 @@ Add them to the config block in specific.local`);
190687
191747
  serviceEndpoints,
190688
191748
  (line) => addLog(line, colorMap),
190689
191749
  void 0,
190690
- resolveServiceCwd(service)
191750
+ resolveServiceCwd(service),
191751
+ volumePaths
190691
191752
  );
190692
191753
  newServices.push(running);
190693
191754
  } catch (err) {
@@ -190774,6 +191835,7 @@ Add them to the config block in specific.local`);
190774
191835
  runningServicePorts.set(s.name, s.ports.get("default"));
190775
191836
  }
190776
191837
  const projectId = hasProjectId() ? readProjectId() : void 0;
191838
+ const hasTemporal = config2.temporal.length > 0;
190777
191839
  const getState = () => ({
190778
191840
  status: "running",
190779
191841
  services: config2.services.filter((svc) => runningServicePorts.has(svc.name) || svc.serve).map((svc) => ({
@@ -190789,22 +191851,28 @@ Add them to the config block in specific.local`);
190789
191851
  host: r.host,
190790
191852
  syncEnabled: r.type === "postgres" && syncDatabases.has(name)
190791
191853
  })),
190792
- projectId
191854
+ projectId,
191855
+ hasTemporal
190793
191856
  });
190794
191857
  const adminServer = await startAdminServer(getState);
190795
191858
  adminServerRef.current = adminServer;
190796
191859
  writeLog("system", `Admin API server started on port ${adminServer.port}`);
191860
+ const temporalInstance = [...resources2.values()].find((r) => r.type === "temporal");
191861
+ const temporalUiPort = temporalInstance?.uiPort;
190797
191862
  await proxyRegistry.registerServices(
190798
191863
  instanceKey,
190799
191864
  adminServer.port,
190800
191865
  serviceInfos,
190801
- startedDrizzleGateway?.port
191866
+ startedDrizzleGateway?.port,
191867
+ temporalUiPort
190802
191868
  );
190803
191869
  writeLog("system", `Registered ${serviceInfos.length} services with proxy registry`);
190804
191870
  const becameProxyOwner = await proxyRegistry.claimProxyOwnership(instanceKey);
190805
191871
  if (becameProxyOwner) {
190806
- writeLog("system", "Claimed proxy ownership, starting HTTP proxy");
191872
+ writeLog("system", "Claimed proxy ownership, starting HTTP proxy and DNS server");
190807
191873
  try {
191874
+ const dnsServer = await startDnsServer();
191875
+ dnsServerRef.current = dnsServer;
190808
191876
  const currentServices = await proxyRegistry.getAllServices();
190809
191877
  const registeredKeys = [...new Set(currentServices.map((s) => s.key))];
190810
191878
  const certificate = generateCertificate("local.spcf.app", registeredKeys);
@@ -190869,12 +191937,14 @@ Add them to the config block in specific.local`);
190869
191937
  writeLog("system", "Proxy owner died, attempting election");
190870
191938
  const won = await proxyRegistry.attemptElection(instanceKey);
190871
191939
  if (won) {
190872
- writeLog("system", "Won election, starting HTTP proxy");
191940
+ writeLog("system", "Won election, starting HTTP proxy and DNS server");
190873
191941
  if (electionIntervalRef.current) {
190874
191942
  clearInterval(electionIntervalRef.current);
190875
191943
  electionIntervalRef.current = null;
190876
191944
  }
190877
191945
  try {
191946
+ const dnsServer = await startDnsServer();
191947
+ dnsServerRef.current = dnsServer;
190878
191948
  const electionServices = await proxyRegistry.getAllServices();
190879
191949
  const electionKeyRegistrations = await proxyRegistry.getAllKeyRegistrations();
190880
191950
  const electionKeyNames = Object.keys(electionKeyRegistrations);
@@ -190920,6 +191990,8 @@ Add them to the config block in specific.local`);
190920
191990
  startedProxy.stop().catch(() => {
190921
191991
  });
190922
191992
  }
191993
+ dnsServerRef.current?.stop().catch(() => {
191994
+ });
190923
191995
  for (const service of startedServices) {
190924
191996
  service.stop().catch(() => {
190925
191997
  });
@@ -190952,10 +192024,10 @@ Add them to the config block in specific.local`);
190952
192024
  }, [reloadTrigger, readyToStart, instanceKey]);
190953
192025
  if (state.status === "installing-ca") {
190954
192026
  if (state.caInstallPhase === "installing") {
190955
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "TLS Certificate Setup"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Installing a local certificate authority (CA) to enable HTTPS"), /* @__PURE__ */ React6.createElement(Text6, null, "for local development. The CA is limited to Specific projects."), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Your password is required to add the CA to your system's trust store."), /* @__PURE__ */ React6.createElement(Text6, null, " "));
192027
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Local Development Setup"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Setting up TLS certificates and DNS resolution for local"), /* @__PURE__ */ React6.createElement(Text6, null, "development. This is a one-time setup for Specific projects."), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Your password is required to configure your system."), /* @__PURE__ */ React6.createElement(Text6, null, " "));
190956
192028
  }
190957
192029
  if (state.caInstallPhase === "error") {
190958
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Failed to install CA: ", state.caError));
192030
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Setup failed: ", state.caError));
190959
192031
  }
190960
192032
  }
190961
192033
  if (state.status === "loading") {
@@ -190989,7 +192061,7 @@ Add them to the config block in specific.local`);
190989
192061
  return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " No specific.hcl in project yet. Go build something with your coding agent!")));
190990
192062
  }
190991
192063
  if (state.status === "error") {
190992
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Error: ", state.error));
192064
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, state.error));
190993
192065
  }
190994
192066
  if (state.status === "stopping") {
190995
192067
  return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Shutting down..."));
@@ -191002,7 +192074,7 @@ Add them to the config block in specific.local`);
191002
192074
  return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })));
191003
192075
  }
191004
192076
  if (state.status === "starting") {
191005
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (Ctrl+C to stop)")), /* @__PURE__ */ React6.createElement(Text6, null, " "), (config.postgres.length > 0 || config.redis.length > 0 || config.storage.length > 0) && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Resources:"), config.postgres.map((pg) => {
192077
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (Ctrl+C to stop)")), /* @__PURE__ */ React6.createElement(Text6, null, " "), (config.postgres.length > 0 || config.redis.length > 0 || config.storage.length > 0 || config.temporal.length > 0) && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Resources:"), config.postgres.map((pg) => {
191006
192078
  const instance = resources.get(pg.name);
191007
192079
  const resStatus = state.resourceStatus.get(pg.name);
191008
192080
  const isReady = !!instance;
@@ -191040,6 +192112,22 @@ Add them to the config block in specific.local`);
191040
192112
  const isReady = !!instance;
191041
192113
  const statusText = resStatus?.status === "starting" ? " starting..." : "";
191042
192114
  return /* @__PURE__ */ React6.createElement(Text6, { key: storage.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, storage.name, " (storage)"), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port), !isReady && statusText && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, statusText));
192115
+ }), config.temporal.map((temporal) => {
192116
+ const instance = resources.get(temporal.name);
192117
+ const resStatus = state.resourceStatus.get(temporal.name);
192118
+ const isReady = !!instance;
192119
+ let statusText = "";
192120
+ if (resStatus?.status === "downloading") {
192121
+ const progress = resStatus.downloadProgress;
192122
+ if (progress?.percent !== void 0) {
192123
+ statusText = ` downloading ${progress.percent}%`;
192124
+ } else {
192125
+ statusText = " downloading...";
192126
+ }
192127
+ } else if (resStatus?.status === "starting") {
192128
+ statusText = " starting...";
192129
+ }
192130
+ return /* @__PURE__ */ React6.createElement(Text6, { key: temporal.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, temporal.name, " (temporal)"), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port), !isReady && statusText && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, statusText));
191043
192131
  }), /* @__PURE__ */ React6.createElement(Text6, null, " ")), config.services.length > 0 && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Services:"), config.services.map((svc) => {
191044
192132
  const running = services.find((s) => s.name === svc.name);
191045
192133
  const isReady = !!running;
@@ -191136,11 +192224,22 @@ Add them to the config block in specific.local`);
191136
192224
  }),
191137
192225
  { key: "storage-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
191138
192226
  ] : [],
192227
+ ...config.temporal.length > 0 ? [
192228
+ { key: "temporal-header", content: /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Temporal:") },
192229
+ ...config.temporal.map((temporal) => {
192230
+ const instance = resources.get(temporal.name);
192231
+ return {
192232
+ key: `temporal-${temporal.name}`,
192233
+ content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, temporal.name), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port))
192234
+ };
192235
+ }),
192236
+ { key: "temporal-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
192237
+ ] : [],
191139
192238
  { key: "separator", content: /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u2500".repeat(50)) },
191140
192239
  ...state.parseError ? [
191141
192240
  {
191142
192241
  key: "parse-error",
191143
- content: /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Warning: ", state.parseError)
192242
+ content: /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, state.parseError)
191144
192243
  }
191145
192244
  ] : [],
191146
192245
  ...output.map((line, i) => ({
@@ -191155,20 +192254,20 @@ function devCommand(instanceKey, tunnelEnabled = false) {
191155
192254
  }
191156
192255
 
191157
192256
  // src/lib/dev/git-worktree.ts
191158
- import { execSync as execSync2 } from "child_process";
191159
- import * as path19 from "path";
192257
+ import { execSync as execSync3 } from "child_process";
192258
+ import * as path21 from "path";
191160
192259
  function isInWorktree() {
191161
192260
  try {
191162
- const commonDir = execSync2("git rev-parse --git-common-dir", {
192261
+ const commonDir = execSync3("git rev-parse --git-common-dir", {
191163
192262
  encoding: "utf-8",
191164
192263
  stdio: ["pipe", "pipe", "pipe"]
191165
192264
  }).trim();
191166
- const gitDir = execSync2("git rev-parse --git-dir", {
192265
+ const gitDir = execSync3("git rev-parse --git-dir", {
191167
192266
  encoding: "utf-8",
191168
192267
  stdio: ["pipe", "pipe", "pipe"]
191169
192268
  }).trim();
191170
- const resolvedCommonDir = path19.resolve(commonDir);
191171
- const resolvedGitDir = path19.resolve(gitDir);
192269
+ const resolvedCommonDir = path21.resolve(commonDir);
192270
+ const resolvedGitDir = path21.resolve(gitDir);
191172
192271
  return resolvedCommonDir !== resolvedGitDir;
191173
192272
  } catch {
191174
192273
  return false;
@@ -191179,11 +192278,11 @@ function getWorktreeName() {
191179
192278
  return null;
191180
192279
  }
191181
192280
  try {
191182
- const gitDir = execSync2("git rev-parse --git-dir", {
192281
+ const gitDir = execSync3("git rev-parse --git-dir", {
191183
192282
  encoding: "utf-8",
191184
192283
  stdio: ["pipe", "pipe", "pipe"]
191185
192284
  }).trim();
191186
- return path19.basename(gitDir);
192285
+ return path21.basename(gitDir);
191187
192286
  } catch {
191188
192287
  return null;
191189
192288
  }
@@ -191198,36 +192297,37 @@ init_open();
191198
192297
  import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
191199
192298
  import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput5 } from "ink";
191200
192299
  import Spinner5 from "ink-spinner";
191201
- import * as fs23 from "fs";
191202
- import * as path21 from "path";
192300
+ import * as fs25 from "fs";
192301
+ import * as path23 from "path";
191203
192302
 
191204
192303
  // src/lib/deploy/build-tester.ts
191205
- import { spawn as spawn5 } from "child_process";
191206
- import { existsSync as existsSync20 } from "fs";
191207
- import { join as join21, resolve as resolve7 } from "path";
192304
+ import { spawn as spawn6 } from "child_process";
192305
+ import { existsSync as existsSync22 } from "fs";
192306
+ import { join as join23, resolve as resolve7 } from "path";
191208
192307
  function getDependencyInstallCommand(build, projectDir) {
192308
+ if (!build.base) return null;
191209
192309
  switch (build.base) {
191210
192310
  case "node":
191211
- if (existsSync20(join21(projectDir, "pnpm-lock.yaml"))) {
192311
+ if (existsSync22(join23(projectDir, "pnpm-lock.yaml"))) {
191212
192312
  return "pnpm install --frozen-lockfile";
191213
- } else if (existsSync20(join21(projectDir, "yarn.lock"))) {
192313
+ } else if (existsSync22(join23(projectDir, "yarn.lock"))) {
191214
192314
  return "yarn install --frozen-lockfile";
191215
- } else if (existsSync20(join21(projectDir, "package-lock.json"))) {
192315
+ } else if (existsSync22(join23(projectDir, "package-lock.json"))) {
191216
192316
  return "npm ci";
191217
- } else if (existsSync20(join21(projectDir, "package.json"))) {
192317
+ } else if (existsSync22(join23(projectDir, "package.json"))) {
191218
192318
  return "npm install";
191219
192319
  }
191220
192320
  return null;
191221
192321
  case "python":
191222
- if (existsSync20(join21(projectDir, "poetry.lock"))) {
192322
+ if (existsSync22(join23(projectDir, "poetry.lock"))) {
191223
192323
  return "poetry install --no-interaction";
191224
- } else if (existsSync20(join21(projectDir, "Pipfile.lock"))) {
192324
+ } else if (existsSync22(join23(projectDir, "Pipfile.lock"))) {
191225
192325
  return "pipenv install --deploy";
191226
- } else if (existsSync20(join21(projectDir, "Pipfile"))) {
192326
+ } else if (existsSync22(join23(projectDir, "Pipfile"))) {
191227
192327
  return "pipenv install";
191228
- } else if (existsSync20(join21(projectDir, "pyproject.toml"))) {
192328
+ } else if (existsSync22(join23(projectDir, "pyproject.toml"))) {
191229
192329
  return "pip install .";
191230
- } else if (existsSync20(join21(projectDir, "requirements.txt"))) {
192330
+ } else if (existsSync22(join23(projectDir, "requirements.txt"))) {
191231
192331
  return "pip install -r requirements.txt";
191232
192332
  }
191233
192333
  return null;
@@ -191245,7 +192345,7 @@ function runCommand2(command, projectDir, buildName) {
191245
192345
  const stdout = [];
191246
192346
  const stderr = [];
191247
192347
  writeLog("build-test", `[${buildName}] Running: ${command}`);
191248
- const child = spawn5(command, {
192348
+ const child = spawn6(command, {
191249
192349
  shell: true,
191250
192350
  cwd: projectDir,
191251
192351
  env: { ...process.env },
@@ -191293,6 +192393,15 @@ function runCommand2(command, projectDir, buildName) {
191293
192393
  }
191294
192394
  async function testBuild(build, projectDir) {
191295
192395
  const startTime = Date.now();
192396
+ if (build.dockerfile) {
192397
+ writeLog("build-test", `Skipping test for build "${build.name}" (custom Dockerfile)`);
192398
+ return {
192399
+ buildName: build.name,
192400
+ success: true,
192401
+ output: "Skipped: custom Dockerfile build",
192402
+ durationMs: Date.now() - startTime
192403
+ };
192404
+ }
191296
192405
  const outputs = [];
191297
192406
  const workDir = build.root ? resolve7(projectDir, build.root) : projectDir;
191298
192407
  writeLog("build-test", `Starting test for build "${build.name}" (base: ${build.base}, workDir: ${workDir})`);
@@ -191372,13 +192481,13 @@ async function testAllBuilds(builds, projectDir) {
191372
192481
  }
191373
192482
 
191374
192483
  // src/lib/tarball/create.ts
191375
- import { execSync as execSync3 } from "child_process";
191376
- import * as fs22 from "fs";
191377
- import * as path20 from "path";
192484
+ import { execSync as execSync4 } from "child_process";
192485
+ import * as fs24 from "fs";
192486
+ import * as path22 from "path";
191378
192487
  import { createTarPacker, createEntryItemGenerator } from "tar-vern";
191379
192488
  function isInsideGitRepository(dir) {
191380
192489
  try {
191381
- const result = execSync3("git rev-parse --is-inside-work-tree", {
192490
+ const result = execSync4("git rev-parse --is-inside-work-tree", {
191382
192491
  cwd: dir,
191383
192492
  encoding: "utf-8",
191384
192493
  stdio: ["pipe", "pipe", "pipe"]
@@ -191390,7 +192499,7 @@ function isInsideGitRepository(dir) {
191390
192499
  }
191391
192500
  async function createGitArchive(projectDir) {
191392
192501
  writeLog("tarball", "Creating tarball using git ls-files");
191393
- const filesOutput = execSync3(
192502
+ const filesOutput = execSync4(
191394
192503
  "git ls-files --cached --others --exclude-standard",
191395
192504
  {
191396
192505
  cwd: projectDir,
@@ -191431,10 +192540,10 @@ var EXCLUDED_DIRS = [
191431
192540
  ];
191432
192541
  async function collectPaths(baseDir, currentDir, exclude) {
191433
192542
  const results = [];
191434
- const entries = await fs22.promises.readdir(currentDir, { withFileTypes: true });
192543
+ const entries = await fs24.promises.readdir(currentDir, { withFileTypes: true });
191435
192544
  for (const entry of entries) {
191436
- const fullPath = path20.join(currentDir, entry.name);
191437
- const relativePath = path20.relative(baseDir, fullPath);
192545
+ const fullPath = path22.join(currentDir, entry.name);
192546
+ const relativePath = path22.relative(baseDir, fullPath);
191438
192547
  if (entry.isDirectory()) {
191439
192548
  if (!exclude.includes(entry.name)) {
191440
192549
  results.push(relativePath);
@@ -191449,8 +192558,8 @@ async function collectPaths(baseDir, currentDir, exclude) {
191449
192558
  }
191450
192559
  async function createTarArchive(projectDir) {
191451
192560
  writeLog("tarball", "Creating tarball using tar-vern (non-git project)");
191452
- const configPath = path20.join(projectDir, "specific.hcl");
191453
- if (!fs22.existsSync(configPath)) {
192561
+ const configPath = path22.join(projectDir, "specific.hcl");
192562
+ if (!fs24.existsSync(configPath)) {
191454
192563
  throw new Error("specific.hcl not found in project directory");
191455
192564
  }
191456
192565
  const relativePaths = await collectPaths(projectDir, projectDir, EXCLUDED_DIRS);
@@ -191467,8 +192576,8 @@ async function createTarArchive(projectDir) {
191467
192576
  }
191468
192577
  function findWidestContext(projectDir, contexts) {
191469
192578
  if (contexts.length === 0) return ".";
191470
- const absolute = contexts.map((c) => path20.resolve(projectDir, c));
191471
- const segments = absolute.map((p) => p.split(path20.sep).filter(Boolean));
192579
+ const absolute = contexts.map((c) => path22.resolve(projectDir, c));
192580
+ const segments = absolute.map((p) => p.split(path22.sep).filter(Boolean));
191472
192581
  const firstSegments = segments[0];
191473
192582
  if (!firstSegments) return ".";
191474
192583
  const minLen = Math.min(...segments.map((s) => s.length));
@@ -191482,12 +192591,12 @@ function findWidestContext(projectDir, contexts) {
191482
192591
  }
191483
192592
  }
191484
192593
  const ancestorSegments = firstSegments.slice(0, commonLength);
191485
- const ancestor = path20.sep + ancestorSegments.join(path20.sep);
191486
- return path20.relative(projectDir, ancestor) || ".";
192594
+ const ancestor = path22.sep + ancestorSegments.join(path22.sep);
192595
+ return path22.relative(projectDir, ancestor) || ".";
191487
192596
  }
191488
192597
  async function createProjectTarball(projectDir, context = ".") {
191489
- const contextDir = path20.resolve(projectDir, context);
191490
- const appPath = path20.relative(contextDir, projectDir) || ".";
192598
+ const contextDir = path22.resolve(projectDir, context);
192599
+ const appPath = path22.relative(contextDir, projectDir) || ".";
191491
192600
  writeLog("tarball", `Context: ${contextDir}, appPath: ${appPath}`);
191492
192601
  let tarball;
191493
192602
  if (isInsideGitRepository(contextDir)) {
@@ -192374,19 +193483,17 @@ ${errorMsg}`
192374
193483
  ), phase === "error" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, "Error: ", error)), phase === "success" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Deployment successful!"), deployment?.publicUrls && Object.keys(deployment.publicUrls).length > 0 && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Public URLs:"), Object.entries(deployment.publicUrls).map(([name, url]) => /* @__PURE__ */ React7.createElement(Text7, { key: name }, " ", name, ": ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, url))))));
192375
193484
  }
192376
193485
  async function deployCommand(environment, options2) {
192377
- const configPath = path21.join(process.cwd(), "specific.hcl");
192378
- if (!fs23.existsSync(configPath)) {
193486
+ const configPath = path23.join(process.cwd(), "specific.hcl");
193487
+ if (!fs25.existsSync(configPath)) {
192379
193488
  console.error("Error: No specific.hcl found in current directory");
192380
193489
  process.exit(1);
192381
193490
  }
192382
193491
  let config;
193492
+ const hcl = fs25.readFileSync(configPath, "utf-8");
192383
193493
  try {
192384
- const hcl = fs23.readFileSync(configPath, "utf-8");
192385
193494
  config = await parseConfig(hcl);
192386
193495
  } catch (err) {
192387
- console.error(
192388
- `Error: Invalid configuration: ${err instanceof Error ? err.message : String(err)}`
192389
- );
193496
+ console.error(formatConfigError(err, hcl, configPath));
192390
193497
  process.exit(1);
192391
193498
  }
192392
193499
  const env2 = environment || "prod";
@@ -192404,9 +193511,9 @@ async function deployCommand(environment, options2) {
192404
193511
  }
192405
193512
 
192406
193513
  // src/commands/exec.tsx
192407
- import { spawn as spawn6 } from "child_process";
192408
- import * as fs24 from "fs";
192409
- import * as path22 from "path";
193514
+ import { spawn as spawn7 } from "child_process";
193515
+ import * as fs26 from "fs";
193516
+ import * as path24 from "path";
192410
193517
  async function execCommand(serviceName, command, instanceKey = "default") {
192411
193518
  if (command.length === 0) {
192412
193519
  console.error(
@@ -192434,17 +193541,17 @@ async function execCommand(serviceName, command, instanceKey = "default") {
192434
193541
  }
192435
193542
  }
192436
193543
  };
192437
- const configPath = path22.join(process.cwd(), "specific.hcl");
192438
- if (!fs24.existsSync(configPath)) {
193544
+ const configPath = path24.join(process.cwd(), "specific.hcl");
193545
+ if (!fs26.existsSync(configPath)) {
192439
193546
  console.error("Error: No specific.hcl found in current directory");
192440
193547
  process.exit(1);
192441
193548
  }
192442
193549
  let config;
193550
+ const hcl = fs26.readFileSync(configPath, "utf-8");
192443
193551
  try {
192444
- const hcl = fs24.readFileSync(configPath, "utf-8");
192445
193552
  config = await parseConfig(hcl);
192446
193553
  } catch (err) {
192447
- console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
193554
+ console.error(formatConfigError(err, hcl, configPath));
192448
193555
  process.exit(1);
192449
193556
  }
192450
193557
  const service = config.services.find((s) => s.name === serviceName);
@@ -192512,7 +193619,8 @@ async function execCommand(serviceName, command, instanceKey = "default") {
192512
193619
  mode: "required",
192513
193620
  postgres: required.postgres,
192514
193621
  redis: required.redis,
192515
- storage: required.storage
193622
+ storage: required.storage,
193623
+ temporal: required.temporal
192516
193624
  },
192517
193625
  stateManager,
192518
193626
  dataDir: `.specific/keys/${instanceKey}/data`,
@@ -192557,14 +193665,14 @@ async function execCommand(serviceName, command, instanceKey = "default") {
192557
193665
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
192558
193666
  let effectiveCwd = process.cwd();
192559
193667
  if (service.root) {
192560
- effectiveCwd = path22.resolve(process.cwd(), service.root);
193668
+ effectiveCwd = path24.resolve(process.cwd(), service.root);
192561
193669
  } else if (service.build) {
192562
193670
  const build = config.builds.find((b) => b.name === service.build.name);
192563
193671
  if (build?.root) {
192564
- effectiveCwd = path22.resolve(process.cwd(), build.root);
193672
+ effectiveCwd = path24.resolve(process.cwd(), build.root);
192565
193673
  }
192566
193674
  }
192567
- child = spawn6(command[0], command.slice(1), {
193675
+ child = spawn7(command[0], command.slice(1), {
192568
193676
  cwd: effectiveCwd,
192569
193677
  env: {
192570
193678
  ...process.env,
@@ -192588,9 +193696,9 @@ async function execCommand(serviceName, command, instanceKey = "default") {
192588
193696
  }
192589
193697
 
192590
193698
  // src/commands/psql.tsx
192591
- import { spawn as spawn7 } from "child_process";
192592
- import * as fs25 from "fs";
192593
- import * as path23 from "path";
193699
+ import { spawn as spawn8 } from "child_process";
193700
+ import * as fs27 from "fs";
193701
+ import * as path25 from "path";
192594
193702
  async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []) {
192595
193703
  let startedResources = [];
192596
193704
  let ownsInstances = false;
@@ -192607,17 +193715,17 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
192607
193715
  }
192608
193716
  }
192609
193717
  };
192610
- const configPath = path23.join(process.cwd(), "specific.hcl");
192611
- if (!fs25.existsSync(configPath)) {
193718
+ const configPath = path25.join(process.cwd(), "specific.hcl");
193719
+ if (!fs27.existsSync(configPath)) {
192612
193720
  console.error("Error: No specific.hcl found in current directory");
192613
193721
  process.exit(1);
192614
193722
  }
192615
193723
  let config;
193724
+ const hcl = fs27.readFileSync(configPath, "utf-8");
192616
193725
  try {
192617
- const hcl = fs25.readFileSync(configPath, "utf-8");
192618
193726
  config = await parseConfig(hcl);
192619
193727
  } catch (err) {
192620
- console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
193728
+ console.error(formatConfigError(err, hcl, configPath));
192621
193729
  process.exit(1);
192622
193730
  }
192623
193731
  const availableDatabases = config.postgres.map((p) => p.name);
@@ -192666,7 +193774,8 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
192666
193774
  mode: "required",
192667
193775
  postgres: [targetDb],
192668
193776
  redis: [],
192669
- storage: []
193777
+ storage: [],
193778
+ temporal: []
192670
193779
  },
192671
193780
  stateManager,
192672
193781
  dataDir: `.specific/keys/${instanceKey}/data`,
@@ -192710,7 +193819,7 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
192710
193819
  };
192711
193820
  process.on("SIGINT", () => handleSignal("SIGINT"));
192712
193821
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
192713
- child = spawn7(psqlPath, ["-h", dbState.host, "-p", String(dbState.port), "-U", dbState.user, "-d", dbState.dbName, ...extraArgs], {
193822
+ child = spawn8(psqlPath, ["-h", dbState.host, "-p", String(dbState.port), "-U", dbState.user, "-d", dbState.dbName, ...extraArgs], {
192714
193823
  cwd: process.cwd(),
192715
193824
  env: {
192716
193825
  ...process.env,
@@ -192735,9 +193844,9 @@ async function psqlCommand(databaseName, instanceKey = "default", extraArgs = []
192735
193844
  }
192736
193845
 
192737
193846
  // src/commands/reshape.tsx
192738
- import { spawn as spawn8 } from "child_process";
192739
- import * as fs26 from "fs";
192740
- import * as path24 from "path";
193847
+ import { spawn as spawn9 } from "child_process";
193848
+ import * as fs28 from "fs";
193849
+ import * as path26 from "path";
192741
193850
  var VALID_ACTIONS = ["start", "complete", "status", "abort", "check"];
192742
193851
  var MIGRATION_SUBCOMMANDS = ["start", "complete", "abort"];
192743
193852
  var OFFLINE_ACTIONS = ["check"];
@@ -192749,13 +193858,13 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
192749
193858
  process.exit(1);
192750
193859
  }
192751
193860
  const isOfflineAction = OFFLINE_ACTIONS.includes(action);
192752
- const configPath = path24.join(process.cwd(), "specific.hcl");
193861
+ const configPath = path26.join(process.cwd(), "specific.hcl");
192753
193862
  let config;
192754
193863
  let migrationsDir = "migrations";
192755
193864
  let targetDb;
192756
193865
  try {
192757
- if (fs26.existsSync(configPath)) {
192758
- const configContent = fs26.readFileSync(configPath, "utf-8");
193866
+ if (fs28.existsSync(configPath)) {
193867
+ const configContent = fs28.readFileSync(configPath, "utf-8");
192759
193868
  config = await parseConfig(configContent);
192760
193869
  if (databaseName) {
192761
193870
  const postgresConfig = config.postgres.find((p) => p.name === databaseName);
@@ -192859,7 +193968,8 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
192859
193968
  mode: "required",
192860
193969
  postgres: [targetDb],
192861
193970
  redis: [],
192862
- storage: []
193971
+ storage: [],
193972
+ temporal: []
192863
193973
  },
192864
193974
  stateManager,
192865
193975
  dataDir: `.specific/keys/${instanceKey}/data`,
@@ -192888,9 +193998,9 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
192888
193998
  }
192889
193999
  const isMigrationSubcommand = MIGRATION_SUBCOMMANDS.includes(action);
192890
194000
  const reshapeArgs = isMigrationSubcommand ? ["migration", action] : [action];
192891
- const fullMigrationsPath = path24.join(process.cwd(), migrationsDir);
194001
+ const fullMigrationsPath = path26.join(process.cwd(), migrationsDir);
192892
194002
  if (action === "check" || action === "start") {
192893
- if (fs26.existsSync(fullMigrationsPath)) {
194003
+ if (fs28.existsSync(fullMigrationsPath)) {
192894
194004
  reshapeArgs.push("--dirs", fullMigrationsPath);
192895
194005
  } else if (action === "check") {
192896
194006
  console.error(`Error: Migrations directory not found: ${fullMigrationsPath}`);
@@ -192912,7 +194022,7 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
192912
194022
  };
192913
194023
  process.on("SIGINT", () => handleSignal("SIGINT"));
192914
194024
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
192915
- child = spawn8(reshapePath, reshapeArgs, {
194025
+ child = spawn9(reshapePath, reshapeArgs, {
192916
194026
  cwd: process.cwd(),
192917
194027
  env: {
192918
194028
  ...process.env,
@@ -192940,21 +194050,21 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
192940
194050
  import React8, { useState as useState7, useEffect as useEffect5 } from "react";
192941
194051
  import { render as render6, Text as Text8, Box as Box8 } from "ink";
192942
194052
  import Spinner6 from "ink-spinner";
192943
- import * as fs27 from "fs";
192944
- import * as path25 from "path";
194053
+ import * as fs29 from "fs";
194054
+ import * as path27 from "path";
192945
194055
  function CleanUI({ instanceKey }) {
192946
194056
  const [state, setState] = useState7({ status: "checking" });
192947
194057
  useEffect5(() => {
192948
194058
  async function clean() {
192949
194059
  const projectRoot = process.cwd();
192950
- const specificDir = path25.join(projectRoot, ".specific");
192951
- if (!fs27.existsSync(specificDir)) {
194060
+ const specificDir = path27.join(projectRoot, ".specific");
194061
+ if (!fs29.existsSync(specificDir)) {
192952
194062
  setState({ status: "nothing" });
192953
194063
  return;
192954
194064
  }
192955
194065
  if (instanceKey) {
192956
- const keyDir = path25.join(specificDir, "keys", instanceKey);
192957
- if (!fs27.existsSync(keyDir)) {
194066
+ const keyDir = path27.join(specificDir, "keys", instanceKey);
194067
+ if (!fs29.existsSync(keyDir)) {
192958
194068
  setState({ status: "nothing" });
192959
194069
  return;
192960
194070
  }
@@ -192970,7 +194080,7 @@ function CleanUI({ instanceKey }) {
192970
194080
  await stateManager.cleanStaleState();
192971
194081
  setState({ status: "cleaning" });
192972
194082
  try {
192973
- fs27.rmSync(keyDir, { recursive: true, force: true });
194083
+ fs29.rmSync(keyDir, { recursive: true, force: true });
192974
194084
  setState({ status: "success" });
192975
194085
  } catch (err) {
192976
194086
  setState({
@@ -192979,13 +194089,13 @@ function CleanUI({ instanceKey }) {
192979
194089
  });
192980
194090
  }
192981
194091
  } else {
192982
- const keysDir = path25.join(specificDir, "keys");
192983
- if (!fs27.existsSync(keysDir)) {
194092
+ const keysDir = path27.join(specificDir, "keys");
194093
+ if (!fs29.existsSync(keysDir)) {
192984
194094
  setState({ status: "nothing" });
192985
194095
  return;
192986
194096
  }
192987
- const keys = fs27.readdirSync(keysDir).filter(
192988
- (f) => fs27.statSync(path25.join(keysDir, f)).isDirectory()
194097
+ const keys = fs29.readdirSync(keysDir).filter(
194098
+ (f) => fs29.statSync(path27.join(keysDir, f)).isDirectory()
192989
194099
  );
192990
194100
  for (const key of keys) {
192991
194101
  const stateManager2 = new InstanceStateManager(projectRoot, key);
@@ -193009,7 +194119,7 @@ function CleanUI({ instanceKey }) {
193009
194119
  }
193010
194120
  setState({ status: "cleaning" });
193011
194121
  try {
193012
- fs27.rmSync(keysDir, { recursive: true, force: true });
194122
+ fs29.rmSync(keysDir, { recursive: true, force: true });
193013
194123
  setState({ status: "success" });
193014
194124
  } catch (err) {
193015
194125
  setState({
@@ -193172,7 +194282,7 @@ function betaCommand() {
193172
194282
  var program = new Command();
193173
194283
  var env = "production";
193174
194284
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
193175
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.61").enablePositionalOptions();
194285
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.63").enablePositionalOptions();
193176
194286
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").action((options2) => initCommand(options2));
193177
194287
  program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
193178
194288
  program.command("check").description("Validate specific.hcl configuration").action(checkCommand);