@specific.dev/cli 0.1.50 → 0.1.51

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 (33) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.__PAGE__.txt +1 -1
  4. package/dist/admin/__next._full.txt +1 -1
  5. package/dist/admin/__next._head.txt +1 -1
  6. package/dist/admin/__next._index.txt +1 -1
  7. package/dist/admin/__next._tree.txt +1 -1
  8. package/dist/admin/_not-found/__next._full.txt +1 -1
  9. package/dist/admin/_not-found/__next._head.txt +1 -1
  10. package/dist/admin/_not-found/__next._index.txt +1 -1
  11. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  12. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  13. package/dist/admin/_not-found/__next._tree.txt +1 -1
  14. package/dist/admin/_not-found/index.html +1 -1
  15. package/dist/admin/_not-found/index.txt +1 -1
  16. package/dist/admin/databases/__next._full.txt +1 -1
  17. package/dist/admin/databases/__next._head.txt +1 -1
  18. package/dist/admin/databases/__next._index.txt +1 -1
  19. package/dist/admin/databases/__next._tree.txt +1 -1
  20. package/dist/admin/databases/__next.databases.__PAGE__.txt +1 -1
  21. package/dist/admin/databases/__next.databases.txt +1 -1
  22. package/dist/admin/databases/index.html +1 -1
  23. package/dist/admin/databases/index.txt +1 -1
  24. package/dist/admin/index.html +1 -1
  25. package/dist/admin/index.txt +1 -1
  26. package/dist/cli.js +124 -95
  27. package/dist/docs/builds.md +42 -0
  28. package/dist/docs/services.md +34 -0
  29. package/dist/postinstall.js +1 -1
  30. package/package.json +2 -2
  31. /package/dist/admin/_next/static/{o2Qo92jA0gWbtB1ZWKQFF → h5UEt0QGdPmIwztzVl3eF}/_buildManifest.js +0 -0
  32. /package/dist/admin/_next/static/{o2Qo92jA0gWbtB1ZWKQFF → h5UEt0QGdPmIwztzVl3eF}/_clientMiddlewareManifest.json +0 -0
  33. /package/dist/admin/_next/static/{o2Qo92jA0gWbtB1ZWKQFF → h5UEt0QGdPmIwztzVl3eF}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -637,19 +637,19 @@ var init_open = __esm({
637
637
  }
638
638
  const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
639
639
  if (options2.wait) {
640
- return new Promise((resolve9, reject) => {
640
+ return new Promise((resolve10, reject) => {
641
641
  subprocess.once("error", reject);
642
642
  subprocess.once("close", (exitCode) => {
643
643
  if (!options2.allowNonzeroExitCode && exitCode !== 0) {
644
644
  reject(new Error(`Exited with code ${exitCode}`));
645
645
  return;
646
646
  }
647
- resolve9(subprocess);
647
+ resolve10(subprocess);
648
648
  });
649
649
  });
650
650
  }
651
651
  if (isFallbackAttempt) {
652
- return new Promise((resolve9, reject) => {
652
+ return new Promise((resolve10, reject) => {
653
653
  subprocess.once("error", reject);
654
654
  subprocess.once("spawn", () => {
655
655
  subprocess.once("close", (exitCode) => {
@@ -659,17 +659,17 @@ var init_open = __esm({
659
659
  return;
660
660
  }
661
661
  subprocess.unref();
662
- resolve9(subprocess);
662
+ resolve10(subprocess);
663
663
  });
664
664
  });
665
665
  });
666
666
  }
667
667
  subprocess.unref();
668
- return new Promise((resolve9, reject) => {
668
+ return new Promise((resolve10, reject) => {
669
669
  subprocess.once("error", reject);
670
670
  subprocess.once("spawn", () => {
671
671
  subprocess.off("error", reject);
672
- resolve9(subprocess);
672
+ resolve10(subprocess);
673
673
  });
674
674
  });
675
675
  };
@@ -183682,7 +183682,7 @@ async function pollUntilToken(deviceAuth, isCancelled) {
183682
183682
  return null;
183683
183683
  }
183684
183684
  function sleep(ms) {
183685
- return new Promise((resolve9) => setTimeout(resolve9, ms));
183685
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
183686
183686
  }
183687
183687
 
183688
183688
  // src/lib/auth/login.tsx
@@ -183699,7 +183699,7 @@ function LoginUI({
183699
183699
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, isReauthentication && /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Session expired. Please log in again."), /* @__PURE__ */ React.createElement(Text, { bold: true }, "Log in to Specific"), state.phase === "waiting-for-browser" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Your authentication code:", " ", /* @__PURE__ */ React.createElement(Text, { color: "cyan", bold: true }, state.userCode))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "blue" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, null, " Waiting for authentication in browser...")), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "If the browser didn't open, visit: ", state.verificationUri)) : /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "blue" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, null, " Initiating login...")));
183700
183700
  }
183701
183701
  function performLogin(options2 = {}) {
183702
- return new Promise((resolve9) => {
183702
+ return new Promise((resolve10) => {
183703
183703
  let currentState = { phase: "initiating" };
183704
183704
  let flowHandle;
183705
183705
  const instance = render(
@@ -183739,14 +183739,14 @@ function performLogin(options2 = {}) {
183739
183739
  process.off("SIGINT", handleExit);
183740
183740
  process.off("SIGTERM", handleExit);
183741
183741
  instance.unmount();
183742
- resolve9({ success: true, userEmail: newState.email });
183742
+ resolve10({ success: true, userEmail: newState.email });
183743
183743
  }, 100);
183744
183744
  } else if (newState.phase === "error") {
183745
183745
  setTimeout(() => {
183746
183746
  process.off("SIGINT", handleExit);
183747
183747
  process.off("SIGTERM", handleExit);
183748
183748
  instance.unmount();
183749
- resolve9({ success: false, error: new Error(newState.message) });
183749
+ resolve10({ success: false, error: new Error(newState.message) });
183750
183750
  }, 100);
183751
183751
  }
183752
183752
  }
@@ -183873,7 +183873,7 @@ function trackEvent(event, properties) {
183873
183873
  event,
183874
183874
  properties: {
183875
183875
  ...properties,
183876
- cli_version: "0.1.50",
183876
+ cli_version: "0.1.51",
183877
183877
  platform: process.platform,
183878
183878
  node_version: process.version,
183879
183879
  project_id: getProjectId(),
@@ -184529,6 +184529,9 @@ function parseBuilds(buildData) {
184529
184529
  if (fieldObj.context) {
184530
184530
  build.context = String(fieldObj.context);
184531
184531
  }
184532
+ if (fieldObj.root) {
184533
+ build.root = String(fieldObj.root);
184534
+ }
184532
184535
  if (dev) {
184533
184536
  build.dev = dev;
184534
184537
  }
@@ -184616,6 +184619,9 @@ function parseServices(serviceData) {
184616
184619
  if (fieldObj.command) {
184617
184620
  service.command = String(fieldObj.command);
184618
184621
  }
184622
+ if (fieldObj.root) {
184623
+ service.root = String(fieldObj.root);
184624
+ }
184619
184625
  const endpoints = parseEndpoints(fieldObj);
184620
184626
  if (fieldObj.expose !== void 0) {
184621
184627
  service.expose = {};
@@ -185055,10 +185061,10 @@ async function downloadFile(url, destPath, onProgress) {
185055
185061
  });
185056
185062
  }
185057
185063
  }
185058
- await new Promise((resolve9, reject) => {
185064
+ await new Promise((resolve10, reject) => {
185059
185065
  fileStream.end((err) => {
185060
185066
  if (err) reject(err);
185061
- else resolve9();
185067
+ else resolve10();
185062
185068
  });
185063
185069
  });
185064
185070
  fs11.renameSync(partPath, destPath);
@@ -185241,7 +185247,7 @@ var drizzleGatewayBinary = {
185241
185247
  // src/lib/bin/definitions/reshape.ts
185242
185248
  var reshapeBinary = {
185243
185249
  name: "reshape",
185244
- versions: ["0.9.0"],
185250
+ versions: ["0.9.1"],
185245
185251
  // GitHub release assets
185246
185252
  urlTemplate: "https://github.com/fabianlindfors/reshape/releases/download/v{version}/reshape-{arch}",
185247
185253
  platformMapping: {
@@ -185265,13 +185271,13 @@ async function runReshapeCheck(migrationsDir) {
185265
185271
  try {
185266
185272
  const binary = await ensureBinary(reshapeBinary);
185267
185273
  const reshapePath = binary.executables["reshape"];
185268
- return new Promise((resolve9) => {
185274
+ return new Promise((resolve10) => {
185269
185275
  execFile7(reshapePath, ["check", "--dirs", migrationsDir], (err, _stdout, stderr) => {
185270
185276
  if (err) {
185271
185277
  const errorMsg = stderr.trim() || err.message;
185272
- resolve9({ success: false, error: errorMsg });
185278
+ resolve10({ success: false, error: errorMsg });
185273
185279
  } else {
185274
- resolve9({ success: true });
185280
+ resolve10({ success: true });
185275
185281
  }
185276
185282
  });
185277
185283
  });
@@ -186228,7 +186234,7 @@ var NodeFsHandler = class {
186228
186234
  this._addToNodeFs(path26, initialAdd, wh, depth + 1);
186229
186235
  }
186230
186236
  }).on(EV.ERROR, this._boundHandleError);
186231
- return new Promise((resolve9, reject) => {
186237
+ return new Promise((resolve10, reject) => {
186232
186238
  if (!stream)
186233
186239
  return reject();
186234
186240
  stream.once(STR_END, () => {
@@ -186237,7 +186243,7 @@ var NodeFsHandler = class {
186237
186243
  return;
186238
186244
  }
186239
186245
  const wasThrottled = throttler ? throttler.clear() : false;
186240
- resolve9(void 0);
186246
+ resolve10(void 0);
186241
186247
  previous.getChildren().filter((item) => {
186242
186248
  return item !== directory && !current.has(item);
186243
186249
  }).forEach((item) => {
@@ -187301,7 +187307,7 @@ async function startStorage(storage, port, dataDir) {
187301
187307
  };
187302
187308
  }
187303
187309
  async function runCommand(command, args, env2) {
187304
- return new Promise((resolve9, reject) => {
187310
+ return new Promise((resolve10, reject) => {
187305
187311
  const proc = spawn(command, args, {
187306
187312
  stdio: ["ignore", "pipe", "pipe"],
187307
187313
  env: env2
@@ -187312,7 +187318,7 @@ async function runCommand(command, args, env2) {
187312
187318
  });
187313
187319
  proc.on("close", (code) => {
187314
187320
  if (code === 0) {
187315
- resolve9();
187321
+ resolve10();
187316
187322
  } else {
187317
187323
  reject(new Error(`Command failed with code ${code}: ${stderr}`));
187318
187324
  }
@@ -187321,7 +187327,7 @@ async function runCommand(command, args, env2) {
187321
187327
  });
187322
187328
  }
187323
187329
  async function createPostgresDatabase(postgresPath, dataDir, dbName, env2) {
187324
- return new Promise((resolve9, reject) => {
187330
+ return new Promise((resolve10, reject) => {
187325
187331
  const proc = spawn(
187326
187332
  postgresPath,
187327
187333
  ["--single", "-D", dataDir, "postgres"],
@@ -187335,7 +187341,7 @@ async function createPostgresDatabase(postgresPath, dataDir, dbName, env2) {
187335
187341
  stderr += data.toString();
187336
187342
  });
187337
187343
  proc.on("close", (code) => {
187338
- resolve9();
187344
+ resolve10();
187339
187345
  });
187340
187346
  proc.on("error", reject);
187341
187347
  proc.stdin?.write(`CREATE DATABASE "${dbName}";
@@ -187355,33 +187361,33 @@ async function waitForTcpPort(host, port, timeoutMs = 3e4) {
187355
187361
  throw new Error(`Port ${port} did not become available within timeout`);
187356
187362
  }
187357
187363
  function checkTcpPort(host, port) {
187358
- return new Promise((resolve9) => {
187364
+ return new Promise((resolve10) => {
187359
187365
  const socket = new net.Socket();
187360
187366
  socket.setTimeout(1e3);
187361
187367
  socket.on("connect", () => {
187362
187368
  socket.destroy();
187363
- resolve9(true);
187369
+ resolve10(true);
187364
187370
  });
187365
187371
  socket.on("timeout", () => {
187366
187372
  socket.destroy();
187367
- resolve9(false);
187373
+ resolve10(false);
187368
187374
  });
187369
187375
  socket.on("error", () => {
187370
187376
  socket.destroy();
187371
- resolve9(false);
187377
+ resolve10(false);
187372
187378
  });
187373
187379
  socket.connect(port, host);
187374
187380
  });
187375
187381
  }
187376
187382
  async function stopProcess(proc) {
187377
- return new Promise((resolve9) => {
187383
+ return new Promise((resolve10) => {
187378
187384
  if (proc.killed || proc.exitCode !== null) {
187379
- resolve9();
187385
+ resolve10();
187380
187386
  return;
187381
187387
  }
187382
187388
  proc.once("exit", () => {
187383
187389
  clearTimeout(forceKillTimeout);
187384
- resolve9();
187390
+ resolve10();
187385
187391
  });
187386
187392
  proc.kill("SIGTERM");
187387
187393
  const forceKillTimeout = setTimeout(() => {
@@ -187392,7 +187398,7 @@ async function stopProcess(proc) {
187392
187398
  });
187393
187399
  }
187394
187400
  function sleep2(ms) {
187395
- return new Promise((resolve9) => setTimeout(resolve9, ms));
187401
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
187396
187402
  }
187397
187403
 
187398
187404
  // src/lib/dev/service-runner.ts
@@ -187746,7 +187752,7 @@ function resolveEnvForExec(env2, resources, secrets, configs) {
187746
187752
  }
187747
187753
 
187748
187754
  // src/lib/dev/service-runner.ts
187749
- function startService(service, resources, secrets, configs, endpointPorts, serviceEndpoints, onLog, publicUrls) {
187755
+ function startService(service, resources, secrets, configs, endpointPorts, serviceEndpoints, onLog, publicUrls, cwd) {
187750
187756
  const command = service.dev?.command ?? service.command;
187751
187757
  if (!command) {
187752
187758
  throw new Error(`Service "${service.name}" has no command`);
@@ -187768,7 +187774,7 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
187768
187774
  );
187769
187775
  const child = spawn2(command, {
187770
187776
  shell: true,
187771
- cwd: process.cwd(),
187777
+ cwd: cwd || process.cwd(),
187772
187778
  env: {
187773
187779
  ...process.env,
187774
187780
  ...resolvedEnv
@@ -187796,14 +187802,14 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
187796
187802
  ports: endpointPorts,
187797
187803
  process: child,
187798
187804
  async stop() {
187799
- return new Promise((resolve9) => {
187805
+ return new Promise((resolve10) => {
187800
187806
  if (child.killed || child.exitCode !== null) {
187801
- resolve9();
187807
+ resolve10();
187802
187808
  return;
187803
187809
  }
187804
187810
  child.once("exit", () => {
187805
187811
  clearTimeout(forceKillTimeout);
187806
- resolve9();
187812
+ resolve10();
187807
187813
  });
187808
187814
  child.kill("SIGTERM");
187809
187815
  const forceKillTimeout = setTimeout(() => {
@@ -187884,7 +187890,7 @@ var InstanceStateManager = class {
187884
187890
  }
187885
187891
  continue;
187886
187892
  }
187887
- await new Promise((resolve9) => setTimeout(resolve9, 100));
187893
+ await new Promise((resolve10) => setTimeout(resolve10, 100));
187888
187894
  } else {
187889
187895
  throw e;
187890
187896
  }
@@ -188167,7 +188173,7 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188167
188173
  handleRequest
188168
188174
  );
188169
188175
  httpsServer.on("upgrade", handleUpgrade);
188170
- return new Promise((resolve9, reject) => {
188176
+ return new Promise((resolve10, reject) => {
188171
188177
  let httpStarted = false;
188172
188178
  let httpsStarted = false;
188173
188179
  let failed = false;
@@ -188178,7 +188184,7 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188178
188184
  "proxy",
188179
188185
  `HTTP/HTTPS proxy started on ports ${HTTP_PORT}/${HTTPS_PORT}`
188180
188186
  );
188181
- resolve9({
188187
+ resolve10({
188182
188188
  httpPort: HTTP_PORT,
188183
188189
  httpsPort: HTTPS_PORT,
188184
188190
  updateServices,
@@ -188190,13 +188196,13 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188190
188196
  writeLog("proxy", "Certificate updated");
188191
188197
  },
188192
188198
  async stop() {
188193
- return new Promise((resolve10) => {
188199
+ return new Promise((resolve11) => {
188194
188200
  let closed = 0;
188195
188201
  const onClose = () => {
188196
188202
  closed++;
188197
188203
  if (closed === 2) {
188198
188204
  clearTimeout(forceCloseTimeout);
188199
- resolve10();
188205
+ resolve11();
188200
188206
  }
188201
188207
  };
188202
188208
  httpServer.close(onClose);
@@ -188204,7 +188210,7 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
188204
188210
  const forceCloseTimeout = setTimeout(() => {
188205
188211
  httpServer.closeAllConnections?.();
188206
188212
  httpsServer.closeAllConnections?.();
188207
- resolve10();
188213
+ resolve11();
188208
188214
  }, 2e3);
188209
188215
  });
188210
188216
  }
@@ -188367,7 +188373,7 @@ function serveFileContent(res, filePath, contentType, statusCode = 200) {
188367
188373
  }
188368
188374
  }
188369
188375
  async function startAdminServer(getState) {
188370
- return new Promise((resolve9, reject) => {
188376
+ return new Promise((resolve10, reject) => {
188371
188377
  const server = http.createServer((req, res) => {
188372
188378
  const url = new URL(req.url || "/", "http://localhost");
188373
188379
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -188399,7 +188405,7 @@ async function startAdminServer(getState) {
188399
188405
  }
188400
188406
  const port = addr.port;
188401
188407
  writeLog("admin", `Admin API server started on port ${port}`);
188402
- resolve9({
188408
+ resolve10({
188403
188409
  port,
188404
188410
  stop: () => new Promise((res, rej) => {
188405
188411
  server.close((err) => err ? rej(err) : res());
@@ -188560,33 +188566,33 @@ async function waitForTcpPort2(host, port, timeoutMs = 3e4) {
188560
188566
  throw new Error(`Electric port ${port} did not become available within timeout`);
188561
188567
  }
188562
188568
  function checkTcpPort2(host, port) {
188563
- return new Promise((resolve9) => {
188569
+ return new Promise((resolve10) => {
188564
188570
  const socket = new net2.Socket();
188565
188571
  socket.setTimeout(1e3);
188566
188572
  socket.on("connect", () => {
188567
188573
  socket.destroy();
188568
- resolve9(true);
188574
+ resolve10(true);
188569
188575
  });
188570
188576
  socket.on("timeout", () => {
188571
188577
  socket.destroy();
188572
- resolve9(false);
188578
+ resolve10(false);
188573
188579
  });
188574
188580
  socket.on("error", () => {
188575
188581
  socket.destroy();
188576
- resolve9(false);
188582
+ resolve10(false);
188577
188583
  });
188578
188584
  socket.connect(port, host);
188579
188585
  });
188580
188586
  }
188581
188587
  async function stopProcess2(proc) {
188582
- return new Promise((resolve9) => {
188588
+ return new Promise((resolve10) => {
188583
188589
  if (proc.killed || proc.exitCode !== null) {
188584
- resolve9();
188590
+ resolve10();
188585
188591
  return;
188586
188592
  }
188587
188593
  proc.once("exit", () => {
188588
188594
  clearTimeout(forceKillTimeout);
188589
- resolve9();
188595
+ resolve10();
188590
188596
  });
188591
188597
  proc.kill("SIGTERM");
188592
188598
  const forceKillTimeout = setTimeout(() => {
@@ -188597,7 +188603,7 @@ async function stopProcess2(proc) {
188597
188603
  });
188598
188604
  }
188599
188605
  function sleep3(ms) {
188600
- return new Promise((resolve9) => setTimeout(resolve9, ms));
188606
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
188601
188607
  }
188602
188608
 
188603
188609
  // src/lib/dev/drizzle-gateway-manager.ts
@@ -188681,33 +188687,33 @@ async function waitForTcpPort3(host, port, timeoutMs = 3e4) {
188681
188687
  );
188682
188688
  }
188683
188689
  function checkTcpPort3(host, port) {
188684
- return new Promise((resolve9) => {
188690
+ return new Promise((resolve10) => {
188685
188691
  const socket = new net3.Socket();
188686
188692
  socket.setTimeout(1e3);
188687
188693
  socket.on("connect", () => {
188688
188694
  socket.destroy();
188689
- resolve9(true);
188695
+ resolve10(true);
188690
188696
  });
188691
188697
  socket.on("timeout", () => {
188692
188698
  socket.destroy();
188693
- resolve9(false);
188699
+ resolve10(false);
188694
188700
  });
188695
188701
  socket.on("error", () => {
188696
188702
  socket.destroy();
188697
- resolve9(false);
188703
+ resolve10(false);
188698
188704
  });
188699
188705
  socket.connect(port, host);
188700
188706
  });
188701
188707
  }
188702
188708
  async function stopProcess3(proc) {
188703
- return new Promise((resolve9) => {
188709
+ return new Promise((resolve10) => {
188704
188710
  if (proc.killed || proc.exitCode !== null) {
188705
- resolve9();
188711
+ resolve10();
188706
188712
  return;
188707
188713
  }
188708
188714
  proc.once("exit", () => {
188709
188715
  clearTimeout(forceKillTimeout);
188710
- resolve9();
188716
+ resolve10();
188711
188717
  });
188712
188718
  proc.kill("SIGTERM");
188713
188719
  const forceKillTimeout = setTimeout(() => {
@@ -188718,7 +188724,7 @@ async function stopProcess3(proc) {
188718
188724
  });
188719
188725
  }
188720
188726
  function sleep4(ms) {
188721
- return new Promise((resolve9) => setTimeout(resolve9, ms));
188727
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
188722
188728
  }
188723
188729
 
188724
188730
  // src/lib/dev/sync-detector.ts
@@ -189335,7 +189341,7 @@ var ProxyRegistryManager = class {
189335
189341
  * This catches cases where the owner process is alive but the proxy has crashed.
189336
189342
  */
189337
189343
  isProxyListening(port, timeoutMs = 1e3) {
189338
- return new Promise((resolve9) => {
189344
+ return new Promise((resolve10) => {
189339
189345
  const socket = new net4.Socket();
189340
189346
  let resolved = false;
189341
189347
  const cleanup = () => {
@@ -189347,15 +189353,15 @@ var ProxyRegistryManager = class {
189347
189353
  socket.setTimeout(timeoutMs);
189348
189354
  socket.on("connect", () => {
189349
189355
  cleanup();
189350
- resolve9(true);
189356
+ resolve10(true);
189351
189357
  });
189352
189358
  socket.on("timeout", () => {
189353
189359
  cleanup();
189354
- resolve9(false);
189360
+ resolve10(false);
189355
189361
  });
189356
189362
  socket.on("error", () => {
189357
189363
  cleanup();
189358
- resolve9(false);
189364
+ resolve10(false);
189359
189365
  });
189360
189366
  socket.connect(port, "127.0.0.1");
189361
189367
  });
@@ -189406,7 +189412,7 @@ var ProxyRegistryManager = class {
189406
189412
  }
189407
189413
  continue;
189408
189414
  }
189409
- await new Promise((resolve9) => setTimeout(resolve9, 100));
189415
+ await new Promise((resolve10) => setTimeout(resolve10, 100));
189410
189416
  } else {
189411
189417
  throw e;
189412
189418
  }
@@ -189890,7 +189896,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
189890
189896
  ...tunnelsRef.current.map((tunnel) => tunnel.stop())
189891
189897
  ]);
189892
189898
  if (tunnelsRef.current.length > 0) {
189893
- await new Promise((resolve9) => setTimeout(resolve9, 1500));
189899
+ await new Promise((resolve10) => setTimeout(resolve10, 1500));
189894
189900
  }
189895
189901
  electricInstancesRef.current = [];
189896
189902
  reshapeWatchersRef.current = [];
@@ -190400,6 +190406,14 @@ Add them to the config block in specific.local`);
190400
190406
  }
190401
190407
  }
190402
190408
  const services2 = [];
190409
+ function resolveServiceCwd(service) {
190410
+ if (service.root) return path18.resolve(process.cwd(), service.root);
190411
+ if (service.build) {
190412
+ const build = config2.builds.find((b) => b.name === service.build.name);
190413
+ if (build?.root) return path18.resolve(process.cwd(), build.root);
190414
+ }
190415
+ return process.cwd();
190416
+ }
190403
190417
  for (const service of config2.services) {
190404
190418
  if (cancelled) break;
190405
190419
  if (service.serve) {
@@ -190423,7 +190437,8 @@ Add them to the config block in specific.local`);
190423
190437
  endpointPorts,
190424
190438
  serviceEndpoints,
190425
190439
  (line) => addLog(line, colorMap),
190426
- publicUrls
190440
+ publicUrls,
190441
+ resolveServiceCwd(service)
190427
190442
  );
190428
190443
  services2.push(running);
190429
190444
  startedServices.push(running);
@@ -190468,7 +190483,9 @@ Add them to the config block in specific.local`);
190468
190483
  configs,
190469
190484
  endpointPorts,
190470
190485
  serviceEndpoints,
190471
- (line) => addLog(line, colorMap)
190486
+ (line) => addLog(line, colorMap),
190487
+ void 0,
190488
+ resolveServiceCwd(service)
190472
190489
  );
190473
190490
  newServices.push(running);
190474
190491
  } catch (err) {
@@ -190978,7 +190995,7 @@ import * as path21 from "path";
190978
190995
  // src/lib/deploy/build-tester.ts
190979
190996
  import { spawn as spawn5 } from "child_process";
190980
190997
  import { existsSync as existsSync20 } from "fs";
190981
- import { join as join21 } from "path";
190998
+ import { join as join21, resolve as resolve7 } from "path";
190982
190999
  function getDependencyInstallCommand(build, projectDir) {
190983
191000
  switch (build.base) {
190984
191001
  case "node":
@@ -190988,9 +191005,10 @@ function getDependencyInstallCommand(build, projectDir) {
190988
191005
  return "yarn install --frozen-lockfile";
190989
191006
  } else if (existsSync20(join21(projectDir, "package-lock.json"))) {
190990
191007
  return "npm ci";
190991
- } else {
191008
+ } else if (existsSync20(join21(projectDir, "package.json"))) {
190992
191009
  return "npm install";
190993
191010
  }
191011
+ return null;
190994
191012
  case "python":
190995
191013
  if (existsSync20(join21(projectDir, "poetry.lock"))) {
190996
191014
  return "poetry install --no-interaction";
@@ -191014,7 +191032,7 @@ function getDependencyInstallCommand(build, projectDir) {
191014
191032
  }
191015
191033
  }
191016
191034
  function runCommand2(command, projectDir, buildName) {
191017
- return new Promise((resolve9) => {
191035
+ return new Promise((resolve10) => {
191018
191036
  const stdout = [];
191019
191037
  const stderr = [];
191020
191038
  writeLog("build-test", `[${buildName}] Running: ${command}`);
@@ -191044,7 +191062,7 @@ function runCommand2(command, projectDir, buildName) {
191044
191062
  });
191045
191063
  child.on("error", (err) => {
191046
191064
  writeLog("build-test:error", `[${buildName}] Failed to start: ${err.message}`);
191047
- resolve9({
191065
+ resolve10({
191048
191066
  success: false,
191049
191067
  output: `Failed to start command: ${err.message}`
191050
191068
  });
@@ -191053,10 +191071,10 @@ function runCommand2(command, projectDir, buildName) {
191053
191071
  const output = [...stdout, ...stderr].join("");
191054
191072
  if (code === 0) {
191055
191073
  writeLog("build-test", `[${buildName}] Command succeeded (exit code 0)`);
191056
- resolve9({ success: true, output });
191074
+ resolve10({ success: true, output });
191057
191075
  } else {
191058
191076
  writeLog("build-test:error", `[${buildName}] Command failed with exit code ${code}`);
191059
- resolve9({
191077
+ resolve10({
191060
191078
  success: false,
191061
191079
  output: output || `Exit code: ${code}`
191062
191080
  });
@@ -191067,7 +191085,7 @@ function runCommand2(command, projectDir, buildName) {
191067
191085
  async function testBuild(build, projectDir) {
191068
191086
  const startTime = Date.now();
191069
191087
  const outputs = [];
191070
- const workDir = projectDir;
191088
+ const workDir = build.root ? resolve7(projectDir, build.root) : projectDir;
191071
191089
  writeLog("build-test", `Starting test for build "${build.name}" (base: ${build.base}, workDir: ${workDir})`);
191072
191090
  const depsCommand = getDependencyInstallCommand(build, workDir);
191073
191091
  if (depsCommand) {
@@ -192328,8 +192346,17 @@ async function execCommand(serviceName, command, instanceKey = "default") {
192328
192346
  };
192329
192347
  process.on("SIGINT", () => handleSignal("SIGINT"));
192330
192348
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
192349
+ let effectiveCwd = process.cwd();
192350
+ if (service.root) {
192351
+ effectiveCwd = path22.resolve(process.cwd(), service.root);
192352
+ } else if (service.build) {
192353
+ const build = config.builds.find((b) => b.name === service.build.name);
192354
+ if (build?.root) {
192355
+ effectiveCwd = path22.resolve(process.cwd(), build.root);
192356
+ }
192357
+ }
192331
192358
  child = spawn6(command[0], command.slice(1), {
192332
- cwd: process.cwd(),
192359
+ cwd: effectiveCwd,
192333
192360
  env: {
192334
192361
  ...process.env,
192335
192362
  ...resolvedEnv
@@ -192744,20 +192771,22 @@ function CleanUI({ instanceKey }) {
192744
192771
  }
192745
192772
  } else {
192746
192773
  const keysDir = path25.join(specificDir, "keys");
192747
- if (fs27.existsSync(keysDir)) {
192748
- const keys = fs27.readdirSync(keysDir).filter(
192749
- (f) => fs27.statSync(path25.join(keysDir, f)).isDirectory()
192750
- );
192751
- for (const key of keys) {
192752
- const stateManager2 = new InstanceStateManager(projectRoot, key);
192753
- const existingInstances2 = await stateManager2.getExistingInstances();
192754
- if (existingInstances2) {
192755
- setState({
192756
- status: "error",
192757
- error: `Cannot clean while 'specific dev' is running for key "${key}" (PID ${existingInstances2.owner.pid}). Please stop it first.`
192758
- });
192759
- return;
192760
- }
192774
+ if (!fs27.existsSync(keysDir)) {
192775
+ setState({ status: "nothing" });
192776
+ return;
192777
+ }
192778
+ const keys = fs27.readdirSync(keysDir).filter(
192779
+ (f) => fs27.statSync(path25.join(keysDir, f)).isDirectory()
192780
+ );
192781
+ for (const key of keys) {
192782
+ const stateManager2 = new InstanceStateManager(projectRoot, key);
192783
+ const existingInstances2 = await stateManager2.getExistingInstances();
192784
+ if (existingInstances2) {
192785
+ setState({
192786
+ status: "error",
192787
+ error: `Cannot clean while 'specific dev' is running for key "${key}" (PID ${existingInstances2.owner.pid}). Please stop it first.`
192788
+ });
192789
+ return;
192761
192790
  }
192762
192791
  }
192763
192792
  const stateManager = new InstanceStateManager(projectRoot);
@@ -192771,7 +192800,7 @@ function CleanUI({ instanceKey }) {
192771
192800
  }
192772
192801
  setState({ status: "cleaning" });
192773
192802
  try {
192774
- fs27.rmSync(specificDir, { recursive: true, force: true });
192803
+ fs27.rmSync(keysDir, { recursive: true, force: true });
192775
192804
  setState({ status: "success" });
192776
192805
  } catch (err) {
192777
192806
  setState({
@@ -192787,16 +192816,16 @@ function CleanUI({ instanceKey }) {
192787
192816
  return /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner6, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text8, null, " Checking for running instances..."));
192788
192817
  }
192789
192818
  if (state.status === "cleaning") {
192790
- return /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner6, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text8, null, " Removing .specific directory..."));
192819
+ return /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner6, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text8, null, " Cleaning app data..."));
192791
192820
  }
192792
192821
  if (state.status === "error") {
192793
192822
  return /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, "Error: ", state.error);
192794
192823
  }
192795
192824
  if (state.status === "nothing") {
192796
- const target2 = instanceKey ? `key "${instanceKey}"` : ".specific directory";
192825
+ const target2 = instanceKey ? `key "${instanceKey}"` : "app data";
192797
192826
  return /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, "Nothing to clean (", target2, " does not exist)");
192798
192827
  }
192799
- const target = instanceKey ? `key "${instanceKey}"` : ".specific directory";
192828
+ const target = instanceKey ? `key "${instanceKey}"` : "app data";
192800
192829
  return /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, "Cleaned ", target);
192801
192830
  }
192802
192831
  function cleanCommand(instanceKey) {
@@ -192934,7 +192963,7 @@ function betaCommand() {
192934
192963
  var program = new Command();
192935
192964
  var env = "production";
192936
192965
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
192937
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.50").enablePositionalOptions();
192966
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.51").enablePositionalOptions();
192938
192967
  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));
192939
192968
  program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
192940
192969
  program.command("check").description("Validate specific.hcl configuration").action(checkCommand);