@specific.dev/cli 0.1.114 → 0.1.116

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 (67) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
  5. package/dist/admin/__next._full.txt +1 -1
  6. package/dist/admin/__next._head.txt +1 -1
  7. package/dist/admin/__next._index.txt +1 -1
  8. package/dist/admin/__next._tree.txt +1 -1
  9. package/dist/admin/_not-found/__next._full.txt +1 -1
  10. package/dist/admin/_not-found/__next._head.txt +1 -1
  11. package/dist/admin/_not-found/__next._index.txt +1 -1
  12. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  13. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  14. package/dist/admin/_not-found/__next._tree.txt +1 -1
  15. package/dist/admin/_not-found/index.html +1 -1
  16. package/dist/admin/_not-found/index.txt +1 -1
  17. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
  18. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
  20. package/dist/admin/databases/__next._full.txt +1 -1
  21. package/dist/admin/databases/__next._head.txt +1 -1
  22. package/dist/admin/databases/__next._index.txt +1 -1
  23. package/dist/admin/databases/__next._tree.txt +1 -1
  24. package/dist/admin/databases/index.html +1 -1
  25. package/dist/admin/databases/index.txt +1 -1
  26. package/dist/admin/fullscreen/__next._full.txt +1 -1
  27. package/dist/admin/fullscreen/__next._head.txt +1 -1
  28. package/dist/admin/fullscreen/__next._index.txt +1 -1
  29. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  30. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
  31. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  32. package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
  33. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  34. package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  39. package/dist/admin/fullscreen/databases/index.html +1 -1
  40. package/dist/admin/fullscreen/databases/index.txt +1 -1
  41. package/dist/admin/fullscreen/index.html +1 -1
  42. package/dist/admin/fullscreen/index.txt +1 -1
  43. package/dist/admin/index.html +1 -1
  44. package/dist/admin/index.txt +1 -1
  45. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
  46. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
  48. package/dist/admin/mail/__next._full.txt +1 -1
  49. package/dist/admin/mail/__next._head.txt +1 -1
  50. package/dist/admin/mail/__next._index.txt +1 -1
  51. package/dist/admin/mail/__next._tree.txt +1 -1
  52. package/dist/admin/mail/index.html +1 -1
  53. package/dist/admin/mail/index.txt +1 -1
  54. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
  55. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
  56. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  57. package/dist/admin/workflows/__next._full.txt +1 -1
  58. package/dist/admin/workflows/__next._head.txt +1 -1
  59. package/dist/admin/workflows/__next._index.txt +1 -1
  60. package/dist/admin/workflows/__next._tree.txt +1 -1
  61. package/dist/admin/workflows/index.html +1 -1
  62. package/dist/admin/workflows/index.txt +1 -1
  63. package/dist/cli.js +266 -231
  64. package/package.json +1 -1
  65. /package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → t-VQmQIYeEfVRQc8YYQbq}/_buildManifest.js +0 -0
  66. /package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → t-VQmQIYeEfVRQc8YYQbq}/_clientMiddlewareManifest.json +0 -0
  67. /package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → t-VQmQIYeEfVRQc8YYQbq}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -367514,8 +367514,14 @@ var ApiClient = class {
367514
367514
  Authorization: `Bearer ${token}`
367515
367515
  };
367516
367516
  }
367517
- async createDeployment(projectId, environment) {
367518
- const requestBody = { projectId, environment };
367517
+ async createDeployment(projectId, environment, options2) {
367518
+ const requestBody = {
367519
+ projectId,
367520
+ environment,
367521
+ ...options2?.triggeredBy && { triggeredBy: options2.triggeredBy },
367522
+ ...options2?.gitCommitSha && { gitCommitSha: options2.gitCommitSha },
367523
+ ...options2?.gitBranch && { gitBranch: options2.gitBranch }
367524
+ };
367519
367525
  writeLog("api", `POST ${this.baseUrl}/deployments`);
367520
367526
  writeLog("api", `Request body: ${JSON.stringify(requestBody)}`);
367521
367527
  const response = await fetch(`${this.baseUrl}/deployments`, {
@@ -367862,9 +367868,9 @@ var SpecificClient = class {
367862
367868
  return await this.client.getMe();
367863
367869
  }
367864
367870
  // --- Deployments ---
367865
- async createDeployment(projectId, environment) {
367871
+ async createDeployment(projectId, environment, options2) {
367866
367872
  return toDeployment(
367867
- await this.client.createDeployment(projectId, environment)
367873
+ await this.client.createDeployment(projectId, environment, options2)
367868
367874
  );
367869
367875
  }
367870
367876
  async uploadTarball(deploymentId, tarball, appPath) {
@@ -369210,6 +369216,22 @@ var temporalBinary = {
369210
369216
  stripComponents: 0,
369211
369217
  executables: ["temporal"]
369212
369218
  };
369219
+ function killProcess(proc) {
369220
+ return new Promise((resolve52) => {
369221
+ if (proc.killed || proc.exitCode !== null) {
369222
+ resolve52();
369223
+ return;
369224
+ }
369225
+ proc.once("exit", () => resolve52());
369226
+ proc.kill("SIGKILL");
369227
+ });
369228
+ }
369229
+ function killProcessGroup(pid) {
369230
+ try {
369231
+ process.kill(-pid, "SIGKILL");
369232
+ } catch {
369233
+ }
369234
+ }
369213
369235
  async function startPostgres(pg, port, dataDir, onProgress) {
369214
369236
  const binary = await ensureBinary(postgresBinary, void 0, onProgress);
369215
369237
  const dbDataPath = path5.join(process.cwd(), dataDir, pg.name);
@@ -369276,8 +369298,9 @@ async function startPostgres(pg, port, dataDir, onProgress) {
369276
369298
  password,
369277
369299
  dbName: pg.name,
369278
369300
  url: `postgres://${user}:${password}@${host}:${port}/${pg.name}`,
369301
+ pid: postgres.pid,
369279
369302
  async stop() {
369280
- return stopProcess(postgres);
369303
+ return killProcess(postgres);
369281
369304
  }
369282
369305
  };
369283
369306
  }
@@ -369302,8 +369325,9 @@ async function startRedis(redis, port, onProgress) {
369302
369325
  password: "",
369303
369326
  dbName: redis.name,
369304
369327
  url: `redis://${host}:${port}`,
369328
+ pid: redisProc.pid,
369305
369329
  async stop() {
369306
- return stopProcess(redisProc);
369330
+ return killProcess(redisProc);
369307
369331
  }
369308
369332
  };
369309
369333
  }
@@ -369340,6 +369364,7 @@ async function startStorage(storage, port, dataDir) {
369340
369364
  secretKey,
369341
369365
  bucket: storage.name,
369342
369366
  async stop() {
369367
+ server.httpServer?.closeAllConnections?.();
369343
369368
  await server.close();
369344
369369
  }
369345
369370
  };
@@ -369417,24 +369442,6 @@ function checkTcpPort(host, port) {
369417
369442
  socket.connect(port, host);
369418
369443
  });
369419
369444
  }
369420
- async function stopProcess(proc) {
369421
- return new Promise((resolve52) => {
369422
- if (proc.killed || proc.exitCode !== null) {
369423
- resolve52();
369424
- return;
369425
- }
369426
- proc.once("exit", () => {
369427
- clearTimeout(forceKillTimeout);
369428
- resolve52();
369429
- });
369430
- proc.kill("SIGTERM");
369431
- const forceKillTimeout = setTimeout(() => {
369432
- if (!proc.killed && proc.exitCode === null) {
369433
- proc.kill("SIGKILL");
369434
- }
369435
- }, 2e3);
369436
- });
369437
- }
369438
369445
  function sleep(ms) {
369439
369446
  return new Promise((resolve52) => setTimeout(resolve52, ms));
369440
369447
  }
@@ -369458,7 +369465,7 @@ async function parseLocalFile(content) {
369458
369465
  if (block && typeof block === "object") {
369459
369466
  for (const [key, value] of Object.entries(block)) {
369460
369467
  if (typeof value === "string") {
369461
- secrets.set(key, value);
369468
+ secrets.set(key, value.trimEnd());
369462
369469
  }
369463
369470
  }
369464
369471
  }
@@ -369470,7 +369477,7 @@ async function parseLocalFile(content) {
369470
369477
  if (block && typeof block === "object") {
369471
369478
  for (const [key, value] of Object.entries(block)) {
369472
369479
  if (typeof value === "string") {
369473
- configs.set(key, value);
369480
+ configs.set(key, value.trimEnd());
369474
369481
  }
369475
369482
  }
369476
369483
  }
@@ -369485,57 +369492,42 @@ async function loadLocal() {
369485
369492
  const content = await readFile(LOCAL_FILE, "utf-8");
369486
369493
  return await parseLocalFile(content);
369487
369494
  }
369488
- function escapeHclValue(value) {
369489
- return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
369495
+ function formatHclValue(value) {
369496
+ if (value.includes("\n")) {
369497
+ return `<<-EOT
369498
+ ${value}
369499
+ EOT`;
369500
+ }
369501
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
369502
+ return `"${escaped}"`;
369490
369503
  }
369491
- function updateBlockValue(content, blockName, key, value) {
369492
- const escapedValue = escapeHclValue(value);
369493
- const newLine = ` ${key} = "${escapedValue}"`;
369494
- const blockRegex = new RegExp(`(${blockName}\\s*\\{)([^}]*)(\\})`, "s");
369495
- const blockMatch = content.match(blockRegex);
369496
- if (blockMatch) {
369497
- const blockContent = blockMatch[2];
369498
- const keyRegex = new RegExp(`^(\\s*)${key}\\s*=\\s*"[^"]*"\\s*$`, "m");
369499
- const keyMatch = blockContent.match(keyRegex);
369500
- if (keyMatch) {
369501
- const updatedBlockContent = blockContent.replace(keyRegex, newLine);
369502
- return content.replace(blockRegex, `$1${updatedBlockContent}$3`);
369503
- } else {
369504
- const trimmedContent = blockContent.trimEnd();
369505
- const newBlockContent = trimmedContent ? `${trimmedContent}
369506
- ${newLine}
369507
- ` : `
369508
- ${newLine}
369509
- `;
369510
- return content.replace(blockRegex, `$1${newBlockContent}$3`);
369511
- }
369512
- } else {
369513
- const newBlock = `${blockName} {
369514
- ${newLine}
369504
+ function serializeBlock(blockName, entries) {
369505
+ const lines = [`${blockName} {`];
369506
+ for (const [key, value] of entries) {
369507
+ lines.push(` ${key} = ${formatHclValue(value)}`);
369508
+ }
369509
+ lines.push("}");
369510
+ return lines.join("\n");
369515
369511
  }
369516
- `;
369517
- return content.trimEnd() + "\n\n" + newBlock;
369512
+ function serializeLocalFile(secrets, configs) {
369513
+ const blocks = [];
369514
+ if (secrets.size > 0) {
369515
+ blocks.push(serializeBlock("secrets", secrets));
369516
+ }
369517
+ if (configs.size > 0) {
369518
+ blocks.push(serializeBlock("config", configs));
369518
369519
  }
369520
+ return HEADER_COMMENT + blocks.join("\n\n") + "\n";
369519
369521
  }
369520
369522
  async function saveLocalSecret(name, value) {
369521
- let content = "";
369522
- if (existsSync5(LOCAL_FILE)) {
369523
- content = await readFile(LOCAL_FILE, "utf-8");
369524
- } else {
369525
- content = HEADER_COMMENT;
369526
- }
369527
- content = updateBlockValue(content, "secrets", name, value);
369528
- await writeFile(LOCAL_FILE, content);
369523
+ const { secrets, configs } = existsSync5(LOCAL_FILE) ? await parseLocalFile(await readFile(LOCAL_FILE, "utf-8")) : { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
369524
+ secrets.set(name, value);
369525
+ await writeFile(LOCAL_FILE, serializeLocalFile(secrets, configs));
369529
369526
  }
369530
369527
  async function saveLocalConfig(name, value) {
369531
- let content = "";
369532
- if (existsSync5(LOCAL_FILE)) {
369533
- content = await readFile(LOCAL_FILE, "utf-8");
369534
- } else {
369535
- content = HEADER_COMMENT;
369536
- }
369537
- content = updateBlockValue(content, "config", name, value);
369538
- await writeFile(LOCAL_FILE, content);
369528
+ const { secrets, configs } = existsSync5(LOCAL_FILE) ? await parseLocalFile(await readFile(LOCAL_FILE, "utf-8")) : { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
369529
+ configs.set(name, value);
369530
+ await writeFile(LOCAL_FILE, serializeLocalFile(secrets, configs));
369539
369531
  }
369540
369532
  function appendSearchPathToUrl(baseUrl, searchPath) {
369541
369533
  const url = new URL(baseUrl);
@@ -369922,29 +369914,13 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
369922
369914
  resolve52();
369923
369915
  return;
369924
369916
  }
369925
- child.once("exit", () => {
369926
- clearTimeout(forceKillTimeout);
369927
- resolve52();
369928
- });
369917
+ child.once("exit", () => resolve52());
369929
369918
  const pid = child.pid;
369930
369919
  if (pid) {
369931
- try {
369932
- process.kill(-pid, "SIGTERM");
369933
- } catch {
369934
- }
369920
+ killProcessGroup(pid);
369935
369921
  } else {
369936
- child.kill("SIGTERM");
369922
+ child.kill("SIGKILL");
369937
369923
  }
369938
- const forceKillTimeout = setTimeout(() => {
369939
- if (pid) {
369940
- try {
369941
- process.kill(-pid, "SIGKILL");
369942
- } catch {
369943
- }
369944
- } else if (!child.killed) {
369945
- child.kill("SIGKILL");
369946
- }
369947
- }, 2e3);
369948
369924
  });
369949
369925
  }
369950
369926
  };
@@ -370389,6 +370365,7 @@ async function startAdminServer(getState, listenPort = 0) {
370389
370365
  port,
370390
370366
  stop: () => new Promise((res, rej) => {
370391
370367
  server.close((err) => err ? rej(err) : res());
370368
+ server.closeAllConnections();
370392
370369
  })
370393
370370
  });
370394
370371
  });
@@ -370539,7 +370516,7 @@ async function startElectric(postgres, port, dataDir, options2) {
370539
370516
  url: `http://${host}:${port}`,
370540
370517
  secret,
370541
370518
  async stop() {
370542
- return stopProcess2(electric);
370519
+ return killProcess(electric);
370543
370520
  }
370544
370521
  };
370545
370522
  }
@@ -370573,24 +370550,6 @@ function checkTcpPort2(host, port) {
370573
370550
  socket.connect(port, host);
370574
370551
  });
370575
370552
  }
370576
- async function stopProcess2(proc) {
370577
- return new Promise((resolve52) => {
370578
- if (proc.killed || proc.exitCode !== null) {
370579
- resolve52();
370580
- return;
370581
- }
370582
- proc.once("exit", () => {
370583
- clearTimeout(forceKillTimeout);
370584
- resolve52();
370585
- });
370586
- proc.kill("SIGTERM");
370587
- const forceKillTimeout = setTimeout(() => {
370588
- if (!proc.killed && proc.exitCode === null) {
370589
- proc.kill("SIGKILL");
370590
- }
370591
- }, 2e3);
370592
- });
370593
- }
370594
370553
  function sleep2(ms) {
370595
370554
  return new Promise((resolve52) => setTimeout(resolve52, ms));
370596
370555
  }
@@ -370692,12 +370651,11 @@ async function startMailServer(mail, smtpPort, apiPort) {
370692
370651
  httpServer.on("error", reject);
370693
370652
  });
370694
370653
  const stop = async () => {
370695
- await new Promise((resolve52) => {
370696
- smtpServer.close(() => resolve52());
370697
- });
370698
- await new Promise((resolve52) => {
370699
- httpServer.close(() => resolve52());
370700
- });
370654
+ httpServer.closeAllConnections();
370655
+ await Promise.all([
370656
+ new Promise((resolve52) => smtpServer.close(() => resolve52())),
370657
+ new Promise((resolve52) => httpServer.close(() => resolve52()))
370658
+ ]);
370701
370659
  };
370702
370660
  const resource = {
370703
370661
  name: mail.name,
@@ -370774,8 +370732,9 @@ async function startDrizzleGateway(postgresInstances, port, configDir, options2)
370774
370732
  return {
370775
370733
  port,
370776
370734
  url: `http://${host}:${port}`,
370735
+ pid: drizzleGateway.pid,
370777
370736
  async stop() {
370778
- return stopProcess3(drizzleGateway);
370737
+ return killProcess(drizzleGateway);
370779
370738
  }
370780
370739
  };
370781
370740
  }
@@ -370811,24 +370770,6 @@ function checkTcpPort3(host, port) {
370811
370770
  socket.connect(port, host);
370812
370771
  });
370813
370772
  }
370814
- async function stopProcess3(proc) {
370815
- return new Promise((resolve52) => {
370816
- if (proc.killed || proc.exitCode !== null) {
370817
- resolve52();
370818
- return;
370819
- }
370820
- proc.once("exit", () => {
370821
- clearTimeout(forceKillTimeout);
370822
- resolve52();
370823
- });
370824
- proc.kill("SIGTERM");
370825
- const forceKillTimeout = setTimeout(() => {
370826
- if (!proc.killed && proc.exitCode === null) {
370827
- proc.kill("SIGKILL");
370828
- }
370829
- }, 2e3);
370830
- });
370831
- }
370832
370773
  function sleep3(ms) {
370833
370774
  return new Promise((resolve52) => setTimeout(resolve52, ms));
370834
370775
  }
@@ -371169,7 +371110,7 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
371169
371110
  );
371170
371111
  pipeProcess("temporal", proc);
371171
371112
  await waitForTcpPort4(host, grpcPort);
371172
- const stopServer = () => stopProcess4(proc);
371113
+ const stopServer = () => killProcess(proc);
371173
371114
  const instances = temporals.map((temporal, i) => ({
371174
371115
  name: temporal.name,
371175
371116
  type: "temporal",
@@ -371180,6 +371121,7 @@ async function startTemporalDevServer(temporals, grpcPort, uiPort, dataDir, onPr
371180
371121
  dbName: temporal.name,
371181
371122
  url: `${host}:${grpcPort}`,
371182
371123
  uiPort,
371124
+ pid: i === 0 ? proc.pid : void 0,
371183
371125
  // Only the first instance owns the server lifecycle
371184
371126
  stop: i === 0 ? stopServer : async () => {
371185
371127
  }
@@ -371216,24 +371158,6 @@ function checkTcpPort4(host, port) {
371216
371158
  socket.connect(port, host);
371217
371159
  });
371218
371160
  }
371219
- async function stopProcess4(proc) {
371220
- return new Promise((resolve52) => {
371221
- if (proc.killed || proc.exitCode !== null) {
371222
- resolve52();
371223
- return;
371224
- }
371225
- proc.once("exit", () => {
371226
- clearTimeout(forceKillTimeout);
371227
- resolve52();
371228
- });
371229
- proc.kill("SIGTERM");
371230
- const forceKillTimeout = setTimeout(() => {
371231
- if (!proc.killed && proc.exitCode === null) {
371232
- proc.kill("SIGKILL");
371233
- }
371234
- }, 2e3);
371235
- });
371236
- }
371237
371161
  function findRequiredResources(service) {
371238
371162
  const required = { postgres: [], redis: [], storage: [], temporal: [], mail: [] };
371239
371163
  if (service.env) {
@@ -371909,28 +371833,35 @@ var DevEnvironment = class extends TypedEventEmitter {
371909
371833
  * Fire-and-forget stop all processes without waiting.
371910
371834
  */
371911
371835
  forceStop() {
371912
- if (this.shuttingDown) {
371913
- this.systemLog("Force shutting down");
371914
- const allProcesses = [
371915
- ...this.services,
371916
- ...this.electricInstances,
371917
- this.drizzleGateway,
371918
- ...[...this.resources.values()],
371919
- ...this.tunnels
371920
- ].filter(Boolean);
371921
- for (const proc of allProcesses) {
371836
+ this.systemLog("Force shutting down");
371837
+ for (const service of this.services) {
371838
+ const pid = service.process.pid;
371839
+ if (pid) {
371840
+ killProcessGroup(pid);
371841
+ }
371842
+ }
371843
+ for (const electric of this.electricInstances) {
371844
+ if (electric.pid) {
371922
371845
  try {
371923
- proc?.stop().catch(() => {
371924
- });
371846
+ process.kill(electric.pid, "SIGKILL");
371847
+ } catch {
371848
+ }
371849
+ }
371850
+ }
371851
+ if (this.drizzleGateway?.pid) {
371852
+ try {
371853
+ process.kill(this.drizzleGateway.pid, "SIGKILL");
371854
+ } catch {
371855
+ }
371856
+ }
371857
+ for (const resource of this.resources.values()) {
371858
+ if (resource.pid) {
371859
+ try {
371860
+ process.kill(resource.pid, "SIGKILL");
371925
371861
  } catch {
371926
371862
  }
371927
371863
  }
371928
- return;
371929
371864
  }
371930
- this.shuttingDown = true;
371931
- this.cancelled = true;
371932
- this.shutdownInternal().catch(() => {
371933
- });
371934
371865
  }
371935
371866
  /**
371936
371867
  * Reload the dev environment (stop everything except release instance ownership completely, then restart).
@@ -372044,13 +371975,11 @@ var DevEnvironment = class extends TypedEventEmitter {
372044
371975
  ...this.reshapeWatchers.map((watcher) => watcher.close()),
372045
371976
  this.drizzleGateway?.stop(),
372046
371977
  ...[...this.resources.values()].map((resource) => resource.stop()),
372047
- ...this.tunnels.map((tunnel) => tunnel.stop())
371978
+ ...this.tunnels.map((tunnel) => tunnel.stop()),
371979
+ this.stateManager?.releaseOwnership()
372048
371980
  ]);
372049
371981
  this.reshapeWatchers = [];
372050
371982
  this.restartServices = null;
372051
- if (this.stateManager) {
372052
- await this.stateManager.releaseOwnership();
372053
- }
372054
371983
  this.removeExitHandler();
372055
371984
  this.systemLog("Shutdown complete");
372056
371985
  closeDebugLog();
@@ -372070,6 +371999,15 @@ var DevEnvironment = class extends TypedEventEmitter {
372070
371999
  registerExitHandler() {
372071
372000
  this.removeExitHandler();
372072
372001
  this.exitHandler = () => {
372002
+ for (const service of this.services) {
372003
+ const pid = service.process.pid;
372004
+ if (pid) {
372005
+ try {
372006
+ process.kill(-pid, "SIGKILL");
372007
+ } catch {
372008
+ }
372009
+ }
372010
+ }
372073
372011
  for (const electric of this.electricInstances) {
372074
372012
  if (electric.pid) {
372075
372013
  try {
@@ -372078,11 +372016,16 @@ var DevEnvironment = class extends TypedEventEmitter {
372078
372016
  }
372079
372017
  }
372080
372018
  }
372081
- for (const service of this.services) {
372082
- const pid = service.process.pid;
372083
- if (pid) {
372019
+ if (this.drizzleGateway?.pid) {
372020
+ try {
372021
+ process.kill(this.drizzleGateway.pid, "SIGKILL");
372022
+ } catch {
372023
+ }
372024
+ }
372025
+ for (const resource of this.resources.values()) {
372026
+ if (resource.pid) {
372084
372027
  try {
372085
- process.kill(-pid, "SIGKILL");
372028
+ process.kill(resource.pid, "SIGKILL");
372086
372029
  } catch {
372087
372030
  }
372088
372031
  }
@@ -373287,7 +373230,7 @@ function trackEvent(event, properties) {
373287
373230
  event,
373288
373231
  properties: {
373289
373232
  ...properties,
373290
- cli_version: "0.1.114",
373233
+ cli_version: "0.1.116",
373291
373234
  platform: process.platform,
373292
373235
  node_version: process.version,
373293
373236
  project_id: getProjectId()
@@ -373296,7 +373239,7 @@ function trackEvent(event, properties) {
373296
373239
  }
373297
373240
  async function shutdown() {
373298
373241
  if (client) {
373299
- await client.shutdown();
373242
+ await client.shutdown(1e3);
373300
373243
  client = null;
373301
373244
  }
373302
373245
  }
@@ -374520,53 +374463,113 @@ function checkCommand() {
374520
374463
  }
374521
374464
 
374522
374465
  // src/commands/dev.tsx
374523
- import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
374466
+ import React6, { useState as useState5, useEffect as useEffect5, useRef as useRef3 } from "react";
374524
374467
  import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
374525
374468
  import Spinner3 from "ink-spinner";
374526
374469
  import { Readable as Readable2 } from "stream";
374527
374470
 
374528
374471
  // src/lib/ui/SecretInput.tsx
374529
- import React4, { useState as useState3 } from "react";
374472
+ import React4, { useState as useState3, useRef, useCallback, useEffect as useEffect3 } from "react";
374530
374473
  import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
374474
+ var PASTE_DETECT_DELAY_MS = 100;
374531
374475
  function SecretInput({ secretName, onSubmit, onCancel }) {
374532
374476
  const [value, setValue] = useState3("");
374477
+ const valueRef = useRef("");
374478
+ const submitTimer = useRef(null);
374479
+ useEffect3(() => {
374480
+ valueRef.current = value;
374481
+ }, [value]);
374482
+ const scheduleSubmit = useCallback(() => {
374483
+ if (submitTimer.current) {
374484
+ clearTimeout(submitTimer.current);
374485
+ }
374486
+ submitTimer.current = setTimeout(() => {
374487
+ submitTimer.current = null;
374488
+ if (valueRef.current.trim() !== "") {
374489
+ onSubmit(valueRef.current);
374490
+ }
374491
+ }, PASTE_DETECT_DELAY_MS);
374492
+ }, [onSubmit]);
374493
+ const cancelSubmit = useCallback(() => {
374494
+ if (submitTimer.current) {
374495
+ clearTimeout(submitTimer.current);
374496
+ submitTimer.current = null;
374497
+ setValue((prev) => prev + "\n");
374498
+ }
374499
+ }, []);
374500
+ useEffect3(() => {
374501
+ return () => {
374502
+ if (submitTimer.current) clearTimeout(submitTimer.current);
374503
+ };
374504
+ }, []);
374533
374505
  useInput2((input, key) => {
374534
374506
  if (key.return) {
374535
- if (value.trim() !== "") {
374536
- onSubmit(value);
374537
- }
374507
+ scheduleSubmit();
374538
374508
  } else if (key.escape) {
374539
374509
  onCancel();
374540
374510
  } else if (key.backspace || key.delete) {
374511
+ cancelSubmit();
374541
374512
  setValue((prev) => prev.slice(0, -1));
374542
374513
  } else if (!key.ctrl && !key.meta && input) {
374514
+ cancelSubmit();
374543
374515
  setValue((prev) => prev + input);
374544
374516
  }
374545
374517
  });
374546
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, "Enter value for secret ", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, secretName), ":"), /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, "> "), /* @__PURE__ */ React4.createElement(Text4, null, value.length > 0 ? "*".repeat(value.length) : ""), /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "|")), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
374518
+ const lineCount = value.split("\n").length;
374519
+ return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, "Enter value for secret ", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, secretName), ":"), /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, "> "), /* @__PURE__ */ React4.createElement(Text4, null, value.length > 0 ? lineCount > 1 ? `[${lineCount} lines, ${value.length} chars]` : "*".repeat(value.length) : ""), /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "|")), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
374547
374520
  }
374548
374521
 
374549
374522
  // src/lib/ui/ConfigInput.tsx
374550
- import React5, { useState as useState4 } from "react";
374523
+ import React5, { useState as useState4, useRef as useRef2, useCallback as useCallback2, useEffect as useEffect4 } from "react";
374551
374524
  import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
374525
+ var PASTE_DETECT_DELAY_MS2 = 100;
374552
374526
  function ConfigInput({ configName, defaultValue, onSubmit, onCancel }) {
374553
374527
  const [value, setValue] = useState4("");
374554
- useInput3((input, key) => {
374555
- if (key.return) {
374556
- if (value.trim() !== "") {
374557
- onSubmit(value);
374528
+ const valueRef = useRef2("");
374529
+ const submitTimer = useRef2(null);
374530
+ useEffect4(() => {
374531
+ valueRef.current = value;
374532
+ }, [value]);
374533
+ const scheduleSubmit = useCallback2(() => {
374534
+ if (submitTimer.current) {
374535
+ clearTimeout(submitTimer.current);
374536
+ }
374537
+ submitTimer.current = setTimeout(() => {
374538
+ submitTimer.current = null;
374539
+ if (valueRef.current.trim() !== "") {
374540
+ onSubmit(valueRef.current);
374558
374541
  } else if (defaultValue !== void 0) {
374559
374542
  onSubmit(defaultValue);
374560
374543
  }
374544
+ }, PASTE_DETECT_DELAY_MS2);
374545
+ }, [onSubmit, defaultValue]);
374546
+ const cancelSubmit = useCallback2(() => {
374547
+ if (submitTimer.current) {
374548
+ clearTimeout(submitTimer.current);
374549
+ submitTimer.current = null;
374550
+ setValue((prev) => prev + "\n");
374551
+ }
374552
+ }, []);
374553
+ useEffect4(() => {
374554
+ return () => {
374555
+ if (submitTimer.current) clearTimeout(submitTimer.current);
374556
+ };
374557
+ }, []);
374558
+ useInput3((input, key) => {
374559
+ if (key.return) {
374560
+ scheduleSubmit();
374561
374561
  } else if (key.escape) {
374562
374562
  onCancel();
374563
374563
  } else if (key.backspace || key.delete) {
374564
+ cancelSubmit();
374564
374565
  setValue((prev) => prev.slice(0, -1));
374565
374566
  } else if (!key.ctrl && !key.meta && input) {
374567
+ cancelSubmit();
374566
374568
  setValue((prev) => prev + input);
374567
374569
  }
374568
374570
  });
374569
- return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, null, "Enter value for config ", /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, configName), defaultValue !== void 0 && /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " (default: ", defaultValue, ")"), ":"), /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(Text5, null, value), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "|")), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, defaultValue !== void 0 ? "(Press Enter to accept default, type to override, Esc to cancel)" : "(Press Enter to save, Esc to cancel)"));
374571
+ const lineCount = value.split("\n").length;
374572
+ return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, null, "Enter value for config ", /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, configName), defaultValue !== void 0 && /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " (default: ", defaultValue, ")"), ":"), /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(Text5, null, lineCount > 1 ? `[${lineCount} lines]` : value), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "|")), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, defaultValue !== void 0 ? "(Press Enter to accept default, type to override, Esc to cancel)" : "(Press Enter to save, Esc to cancel)"));
374570
374573
  }
374571
374574
 
374572
374575
  // src/commands/dev.tsx
@@ -374583,8 +374586,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
374583
374586
  tunnelUrls: /* @__PURE__ */ new Map(),
374584
374587
  tunnelStatus: /* @__PURE__ */ new Map()
374585
374588
  });
374586
- const devEnvRef = useRef(null);
374587
- const startTimeRef = useRef(null);
374589
+ const devEnvRef = useRef3(null);
374590
+ const startTimeRef = useRef3(null);
374588
374591
  const buildColorMap = (config2) => {
374589
374592
  const colorMap = /* @__PURE__ */ new Map();
374590
374593
  let colorIndex = 0;
@@ -374610,7 +374613,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
374610
374613
  }
374611
374614
  return colorMap;
374612
374615
  };
374613
- useEffect3(() => {
374616
+ useEffect5(() => {
374614
374617
  const devEnv = new DevEnvironment({
374615
374618
  projectDir: process.cwd(),
374616
374619
  instanceKey,
@@ -374747,7 +374750,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
374747
374750
  devEnvRef.current = null;
374748
374751
  };
374749
374752
  }, [instanceKey, tunnelEnabled]);
374750
- useEffect3(() => {
374753
+ useEffect5(() => {
374751
374754
  const handleSignal = () => {
374752
374755
  const devEnv = devEnvRef.current;
374753
374756
  if (!devEnv) return;
@@ -374778,7 +374781,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
374778
374781
  process.off("unhandledRejection", handleCrash);
374779
374782
  };
374780
374783
  }, []);
374781
- useEffect3(() => {
374784
+ useEffect5(() => {
374782
374785
  if (state.status === "running" && !startTimeRef.current) {
374783
374786
  startTimeRef.current = Date.now();
374784
374787
  trackEvent("dev_started");
@@ -375074,11 +375077,29 @@ function devCommand(instanceKey, tunnelEnabled = false) {
375074
375077
 
375075
375078
  // src/commands/deploy.tsx
375076
375079
  init_open();
375077
- import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
375080
+ import React7, { useState as useState6, useEffect as useEffect6, useCallback as useCallback3 } from "react";
375078
375081
  import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput4 } from "ink";
375079
375082
  import Spinner4 from "ink-spinner";
375080
375083
  import * as fs22 from "fs";
375081
375084
  import * as path20 from "path";
375085
+ import { execFileSync as execFileSync2 } from "child_process";
375086
+ function getGitInfo(cwd) {
375087
+ try {
375088
+ const commitSha = execFileSync2("git", ["rev-parse", "HEAD"], {
375089
+ cwd,
375090
+ encoding: "utf-8",
375091
+ stdio: ["pipe", "pipe", "pipe"]
375092
+ }).trim();
375093
+ const branch = execFileSync2(
375094
+ "git",
375095
+ ["rev-parse", "--abbrev-ref", "HEAD"],
375096
+ { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
375097
+ ).trim();
375098
+ return { commitSha, branch };
375099
+ } catch {
375100
+ return null;
375101
+ }
375102
+ }
375082
375103
  function formatBytes(bytes) {
375083
375104
  if (bytes < 1024) return `${bytes} B`;
375084
375105
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -375224,7 +375245,7 @@ function DeployUI({ environment, config }) {
375224
375245
  const { exit } = useApp3();
375225
375246
  const [state, setState] = useState6({ phase: "checking-auth" });
375226
375247
  const clientRef = React7.useRef(null);
375227
- useEffect4(() => {
375248
+ useEffect6(() => {
375228
375249
  if (state.phase !== "checking-auth") return;
375229
375250
  const projectDir = process.cwd();
375230
375251
  if (hasProjectId(projectDir)) {
@@ -375245,7 +375266,7 @@ function DeployUI({ environment, config }) {
375245
375266
  }
375246
375267
  setState({ phase: "logging-in" });
375247
375268
  }, [state.phase]);
375248
- useEffect4(() => {
375269
+ useEffect6(() => {
375249
375270
  if (state.phase !== "logging-in") return;
375250
375271
  let cancelled = false;
375251
375272
  async function startLogin() {
@@ -375306,7 +375327,7 @@ function DeployUI({ environment, config }) {
375306
375327
  cancelled = true;
375307
375328
  };
375308
375329
  }, [state.phase]);
375309
- useEffect4(() => {
375330
+ useEffect6(() => {
375310
375331
  if (state.phase !== "loading-projects") return;
375311
375332
  let cancelled = false;
375312
375333
  async function loadProjects() {
@@ -375339,7 +375360,7 @@ function DeployUI({ environment, config }) {
375339
375360
  cancelled = true;
375340
375361
  };
375341
375362
  }, [state.phase]);
375342
- const handleProjectSelect = useCallback(
375363
+ const handleProjectSelect = useCallback3(
375343
375364
  (project) => {
375344
375365
  if ("type" in project && project.type === "new") {
375345
375366
  setState((s) => ({ ...s, phase: "entering-name", selectedOrganizationId: project.orgId }));
@@ -375354,13 +375375,13 @@ function DeployUI({ environment, config }) {
375354
375375
  },
375355
375376
  []
375356
375377
  );
375357
- const handleNameSubmit = useCallback((name) => {
375378
+ const handleNameSubmit = useCallback3((name) => {
375358
375379
  setState((s) => ({ ...s, phase: "creating-project", newProjectName: name }));
375359
375380
  }, []);
375360
- const handleNameCancel = useCallback(() => {
375381
+ const handleNameCancel = useCallback3(() => {
375361
375382
  setState((s) => ({ ...s, phase: "selecting-project" }));
375362
375383
  }, []);
375363
- useEffect4(() => {
375384
+ useEffect6(() => {
375364
375385
  if (state.phase !== "creating-project" || !state.newProjectName) return;
375365
375386
  let cancelled = false;
375366
375387
  async function createProject() {
@@ -375387,7 +375408,7 @@ function DeployUI({ environment, config }) {
375387
375408
  cancelled = true;
375388
375409
  };
375389
375410
  }, [state.phase, state.newProjectName]);
375390
- const handleSecretSubmit = useCallback((value) => {
375411
+ const handleSecretSubmit = useCallback3((value) => {
375391
375412
  setState((s) => {
375392
375413
  if (!s.missingSecrets || s.currentSecretIndex === void 0) return s;
375393
375414
  const currentSecret2 = s.missingSecrets[s.currentSecretIndex];
@@ -375410,14 +375431,14 @@ function DeployUI({ environment, config }) {
375410
375431
  };
375411
375432
  });
375412
375433
  }, []);
375413
- const handleSecretCancel = useCallback(() => {
375434
+ const handleSecretCancel = useCallback3(() => {
375414
375435
  setState((s) => ({
375415
375436
  ...s,
375416
375437
  phase: "error",
375417
375438
  error: "Deployment cancelled - secrets not provided"
375418
375439
  }));
375419
375440
  }, []);
375420
- const handleConfigSubmit = useCallback((value) => {
375441
+ const handleConfigSubmit = useCallback3((value) => {
375421
375442
  setState((s) => {
375422
375443
  if (!s.missingConfigs || s.currentConfigIndex === void 0) return s;
375423
375444
  const currentConfig2 = s.missingConfigs[s.currentConfigIndex];
@@ -375440,14 +375461,14 @@ function DeployUI({ environment, config }) {
375440
375461
  };
375441
375462
  });
375442
375463
  }, []);
375443
- const handleConfigCancel = useCallback(() => {
375464
+ const handleConfigCancel = useCallback3(() => {
375444
375465
  setState((s) => ({
375445
375466
  ...s,
375446
375467
  phase: "error",
375447
375468
  error: "Deployment cancelled - configs not provided"
375448
375469
  }));
375449
375470
  }, []);
375450
- useEffect4(() => {
375471
+ useEffect6(() => {
375451
375472
  const {
375452
375473
  phase: phase2,
375453
375474
  deployment: deployment2,
@@ -375489,7 +375510,7 @@ function DeployUI({ environment, config }) {
375489
375510
  }
375490
375511
  })();
375491
375512
  }, [state]);
375492
- useEffect4(() => {
375513
+ useEffect6(() => {
375493
375514
  const {
375494
375515
  phase: phase2,
375495
375516
  deployment: deployment2,
@@ -375531,7 +375552,7 @@ function DeployUI({ environment, config }) {
375531
375552
  }
375532
375553
  })();
375533
375554
  }, [state]);
375534
- useEffect4(() => {
375555
+ useEffect6(() => {
375535
375556
  if (state.phase !== "creating-tarball" || !state.projectId) return;
375536
375557
  let cancelled = false;
375537
375558
  async function runDeploy() {
@@ -375567,7 +375588,14 @@ function DeployUI({ environment, config }) {
375567
375588
  let deployment2;
375568
375589
  try {
375569
375590
  writeLog("deploy", `Creating deployment for project ${state.projectId}`);
375570
- deployment2 = await client2.createDeployment(state.projectId, environment);
375591
+ const gitInfo = getGitInfo(projectDir);
375592
+ deployment2 = await client2.createDeployment(state.projectId, environment, {
375593
+ triggeredBy: "cli",
375594
+ ...gitInfo && {
375595
+ gitCommitSha: gitInfo.commitSha,
375596
+ gitBranch: gitInfo.branch
375597
+ }
375598
+ });
375571
375599
  writeLog("deploy", `Deployment created: ${deployment2.id}`);
375572
375600
  } catch (err) {
375573
375601
  const errorMsg = `Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`;
@@ -375604,7 +375632,7 @@ function DeployUI({ environment, config }) {
375604
375632
  cancelled = true;
375605
375633
  };
375606
375634
  }, [state.projectId, environment, config.builds]);
375607
- useEffect4(() => {
375635
+ useEffect6(() => {
375608
375636
  if (state.phase !== "pending" || !state.deployment) return;
375609
375637
  let pollInterval;
375610
375638
  let cancelled = false;
@@ -375713,7 +375741,7 @@ function DeployUI({ environment, config }) {
375713
375741
  if (pollInterval) clearInterval(pollInterval);
375714
375742
  };
375715
375743
  }, [state.phase, state.deployment?.id]);
375716
- useEffect4(() => {
375744
+ useEffect6(() => {
375717
375745
  if (state.phase !== "starting" || !state.deployment) return;
375718
375746
  let cancelled = false;
375719
375747
  const client2 = clientRef.current;
@@ -375743,7 +375771,7 @@ function DeployUI({ environment, config }) {
375743
375771
  cancelled = true;
375744
375772
  };
375745
375773
  }, [state.phase, state.deployment?.id]);
375746
- useEffect4(() => {
375774
+ useEffect6(() => {
375747
375775
  if (state.phase !== "queued" && state.phase !== "deploying" || !state.deployment) return;
375748
375776
  let pollInterval;
375749
375777
  let cancelled = false;
@@ -375796,12 +375824,12 @@ function DeployUI({ environment, config }) {
375796
375824
  if (pollInterval) clearInterval(pollInterval);
375797
375825
  };
375798
375826
  }, [state.phase, state.deployment?.id]);
375799
- useEffect4(() => {
375827
+ useEffect6(() => {
375800
375828
  if (state.phase === "creating-tarball") {
375801
375829
  trackEvent("deploy_started", { environment });
375802
375830
  }
375803
375831
  }, [state.phase, environment]);
375804
- useEffect4(() => {
375832
+ useEffect6(() => {
375805
375833
  if (state.phase === "success") {
375806
375834
  trackEvent("deploy_succeeded", { environment });
375807
375835
  closeDebugLog();
@@ -376008,7 +376036,14 @@ async function runDeployPipeline(options2) {
376008
376036
  console.log("Creating deployment...");
376009
376037
  let deployment;
376010
376038
  try {
376011
- deployment = await client2.createDeployment(projectId, "prod");
376039
+ const gitInfo = getGitInfo(projectDir);
376040
+ deployment = await client2.createDeployment(projectId, "prod", {
376041
+ triggeredBy: "cli",
376042
+ ...gitInfo && {
376043
+ gitCommitSha: gitInfo.commitSha,
376044
+ gitBranch: gitInfo.branch
376045
+ }
376046
+ });
376012
376047
  } catch (err) {
376013
376048
  console.error(`Error: Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`);
376014
376049
  process.exit(1);
@@ -376753,14 +376788,14 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
376753
376788
  }
376754
376789
 
376755
376790
  // src/commands/clean.tsx
376756
- import React8, { useState as useState7, useEffect as useEffect5 } from "react";
376791
+ import React8, { useState as useState7, useEffect as useEffect7 } from "react";
376757
376792
  import { render as render6, Text as Text8, Box as Box8 } from "ink";
376758
376793
  import Spinner5 from "ink-spinner";
376759
376794
  import * as fs26 from "fs";
376760
376795
  import * as path24 from "path";
376761
376796
  function CleanUI({ instanceKey }) {
376762
376797
  const [state, setState] = useState7({ status: "checking" });
376763
- useEffect5(() => {
376798
+ useEffect7(() => {
376764
376799
  async function clean() {
376765
376800
  const projectRoot = process.cwd();
376766
376801
  const specificDir = path24.join(projectRoot, ".specific");
@@ -376888,14 +376923,14 @@ async function loginCommand(options2 = {}) {
376888
376923
  }
376889
376924
 
376890
376925
  // src/commands/logout.tsx
376891
- import React9, { useState as useState8, useEffect as useEffect6 } from "react";
376926
+ import React9, { useState as useState8, useEffect as useEffect8 } from "react";
376892
376927
  import { render as render7, Text as Text9, useApp as useApp4 } from "ink";
376893
376928
  function LogoutUI() {
376894
376929
  const { exit } = useApp4();
376895
376930
  const [state, setState] = useState8({
376896
376931
  phase: "checking"
376897
376932
  });
376898
- useEffect6(() => {
376933
+ useEffect8(() => {
376899
376934
  if (state.phase !== "checking") return;
376900
376935
  if (!isLoggedIn()) {
376901
376936
  setState({ phase: "not-logged-in" });
@@ -376904,7 +376939,7 @@ function LogoutUI() {
376904
376939
  clearUserCredentials();
376905
376940
  setState({ phase: "done" });
376906
376941
  }, [state.phase]);
376907
- useEffect6(() => {
376942
+ useEffect8(() => {
376908
376943
  if (state.phase === "done" || state.phase === "not-logged-in") {
376909
376944
  const timer = setTimeout(() => exit(), 100);
376910
376945
  return () => clearTimeout(timer);
@@ -376923,7 +376958,7 @@ function logoutCommand() {
376923
376958
  }
376924
376959
 
376925
376960
  // src/commands/beta.tsx
376926
- import React10, { useState as useState9, useEffect as useEffect7 } from "react";
376961
+ import React10, { useState as useState9, useEffect as useEffect9 } from "react";
376927
376962
  import { render as render8, Text as Text10, Box as Box9, useInput as useInput5, useApp as useApp5 } from "ink";
376928
376963
  function BetaToggleUI() {
376929
376964
  const { exit } = useApp5();
@@ -376961,7 +376996,7 @@ function BetaToggleUI() {
376961
376996
  setSaved(true);
376962
376997
  }
376963
376998
  });
376964
- useEffect7(() => {
376999
+ useEffect9(() => {
376965
377000
  if (saved) {
376966
377001
  const timer = setTimeout(() => exit(), 100);
376967
377002
  return () => clearTimeout(timer);
@@ -376999,7 +377034,7 @@ function betaCommand() {
376999
377034
  }
377000
377035
 
377001
377036
  // src/commands/update.tsx
377002
- import React11, { useState as useState10, useEffect as useEffect8 } from "react";
377037
+ import React11, { useState as useState10, useEffect as useEffect10 } from "react";
377003
377038
  import { render as render9, Text as Text11, Box as Box10, useApp as useApp6 } from "ink";
377004
377039
  import Spinner6 from "ink-spinner";
377005
377040
 
@@ -377019,7 +377054,7 @@ function compareVersions(a, b) {
377019
377054
  return 0;
377020
377055
  }
377021
377056
  async function checkForUpdate() {
377022
- const currentVersion = "0.1.114";
377057
+ const currentVersion = "0.1.116";
377023
377058
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
377024
377059
  if (!response.ok) {
377025
377060
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -377115,7 +377150,7 @@ function maybeStartBackgroundUpdate() {
377115
377150
  function UpdateUI() {
377116
377151
  const { exit } = useApp6();
377117
377152
  const [state, setState] = useState10({ phase: "checking" });
377118
- useEffect8(() => {
377153
+ useEffect10(() => {
377119
377154
  if (state.phase !== "checking") return;
377120
377155
  let cancelled = false;
377121
377156
  async function check() {
@@ -377144,7 +377179,7 @@ function UpdateUI() {
377144
377179
  cancelled = true;
377145
377180
  };
377146
377181
  }, [state.phase]);
377147
- useEffect8(() => {
377182
+ useEffect10(() => {
377148
377183
  if (state.phase !== "downloading" || !state.checkResult) return;
377149
377184
  let cancelled = false;
377150
377185
  async function download() {
@@ -377176,7 +377211,7 @@ function UpdateUI() {
377176
377211
  cancelled = true;
377177
377212
  };
377178
377213
  }, [state.phase, state.checkResult]);
377179
- useEffect8(() => {
377214
+ useEffect10(() => {
377180
377215
  if (state.phase === "up-to-date" || state.phase === "success" || state.phase === "error" || state.phase === "permission-error") {
377181
377216
  const timer = setTimeout(() => exit(), 100);
377182
377217
  return () => clearTimeout(timer);
@@ -377287,7 +377322,7 @@ async function projectListCommand() {
377287
377322
  var program = new Command();
377288
377323
  var env = "production";
377289
377324
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
377290
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.114").enablePositionalOptions();
377325
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.116").enablePositionalOptions();
377291
377326
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
377292
377327
  Examples:
377293
377328
  $ specific init