@specific.dev/cli 0.1.118 → 0.1.120

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 +241 -24
  64. package/package.json +1 -1
  65. /package/dist/admin/_next/static/{Oah87wK6uSWnyXHyAwYBs → wSllkH7WRyJEpQx0UpLjo}/_buildManifest.js +0 -0
  66. /package/dist/admin/_next/static/{Oah87wK6uSWnyXHyAwYBs → wSllkH7WRyJEpQx0UpLjo}/_clientMiddlewareManifest.json +0 -0
  67. /package/dist/admin/_next/static/{Oah87wK6uSWnyXHyAwYBs → wSllkH7WRyJEpQx0UpLjo}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -369364,8 +369364,11 @@ async function startStorage(storage, port, dataDir) {
369364
369364
  secretKey,
369365
369365
  bucket: storage.name,
369366
369366
  async stop() {
369367
- server.httpServer?.closeAllConnections?.();
369368
- await server.close();
369367
+ const httpServer = server.httpServer;
369368
+ if (httpServer) {
369369
+ httpServer.close();
369370
+ httpServer.closeAllConnections();
369371
+ }
369369
369372
  }
369370
369373
  };
369371
369374
  }
@@ -372756,6 +372759,7 @@ import * as crypto3 from "crypto";
372756
372759
  import * as fs3 from "fs";
372757
372760
  import * as path3 from "path";
372758
372761
  var PROJECT_ID_FILE = ".specific/project_id";
372762
+ var ENVIRONMENT_ID_FILE = ".specific/environment_id";
372759
372763
  var ProjectNotLinkedError = class extends Error {
372760
372764
  constructor() {
372761
372765
  super(
@@ -372790,6 +372794,28 @@ function writeProjectId(projectId, projectDir = process.cwd()) {
372790
372794
  }
372791
372795
  fs3.writeFileSync(path3.join(specificDir, "project_id"), projectId + "\n");
372792
372796
  }
372797
+ function readEnvironmentId(projectDir = process.cwd()) {
372798
+ const envIdPath = path3.join(projectDir, ENVIRONMENT_ID_FILE);
372799
+ if (!fs3.existsSync(envIdPath)) {
372800
+ throw new Error(`${ENVIRONMENT_ID_FILE} does not exist`);
372801
+ }
372802
+ const envId = fs3.readFileSync(envIdPath, "utf-8").trim();
372803
+ if (!envId) {
372804
+ throw new Error(`${ENVIRONMENT_ID_FILE} is empty`);
372805
+ }
372806
+ return envId;
372807
+ }
372808
+ function hasEnvironmentId(projectDir = process.cwd()) {
372809
+ const envIdPath = path3.join(projectDir, ENVIRONMENT_ID_FILE);
372810
+ return fs3.existsSync(envIdPath);
372811
+ }
372812
+ function writeEnvironmentId(environmentId, projectDir = process.cwd()) {
372813
+ const specificDir = path3.join(projectDir, ".specific");
372814
+ if (!fs3.existsSync(specificDir)) {
372815
+ fs3.mkdirSync(specificDir, { recursive: true });
372816
+ }
372817
+ fs3.writeFileSync(path3.join(specificDir, "environment_id"), environmentId + "\n");
372818
+ }
372793
372819
 
372794
372820
  // src/lib/auth/credentials.ts
372795
372821
  import * as fs19 from "fs";
@@ -373230,7 +373256,7 @@ function trackEvent(event, properties) {
373230
373256
  event,
373231
373257
  properties: {
373232
373258
  ...properties,
373233
- cli_version: "0.1.118",
373259
+ cli_version: "0.1.120",
373234
373260
  platform: process.platform,
373235
373261
  node_version: process.version,
373236
373262
  project_id: getProjectId()
@@ -375205,6 +375231,28 @@ function NameInput({ onSubmit, onCancel }) {
375205
375231
  });
375206
375232
  return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Create new project"), /* @__PURE__ */ React7.createElement(Text7, null, "Enter project name:"), /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, "> "), /* @__PURE__ */ React7.createElement(Text7, null, value), /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "|")), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Press Enter to create, Esc to go back"));
375207
375233
  }
375234
+ function EnvironmentSelector({
375235
+ environments,
375236
+ selectedIndex,
375237
+ onSelect,
375238
+ onUp,
375239
+ onDown
375240
+ }) {
375241
+ useInput4((input, key) => {
375242
+ if (key.return) {
375243
+ const env2 = environments[selectedIndex];
375244
+ if (env2) onSelect(env2);
375245
+ } else if (key.upArrow) {
375246
+ onUp();
375247
+ } else if (key.downArrow) {
375248
+ onDown();
375249
+ }
375250
+ });
375251
+ return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Select an environment to deploy to:"), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, environments.map((env2, index) => {
375252
+ const isSelected = index === selectedIndex;
375253
+ return /* @__PURE__ */ React7.createElement(Text7, { key: env2.id }, isSelected ? /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, " ", "> ") : /* @__PURE__ */ React7.createElement(Text7, null, " "), /* @__PURE__ */ React7.createElement(Text7, null, env2.name));
375254
+ })), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Use arrow keys to navigate, Enter to select"));
375255
+ }
375208
375256
  function getMissingSecrets(pendingActions) {
375209
375257
  if (!pendingActions) return [];
375210
375258
  const secretAction = pendingActions.find((a) => a.type === "missing_secrets");
@@ -375241,7 +375289,7 @@ function formatErrorCode(code) {
375241
375289
  function StructuredError({ error }) {
375242
375290
  return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, formatErrorCode(error.code), ": ", error.message), error.resource && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Resource: ", error.resource), error.output && /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Output:"), /* @__PURE__ */ React7.createElement(Text7, null, error.output)));
375243
375291
  }
375244
- function DeployUI({ environment, config }) {
375292
+ function DeployUI({ envFlag, config }) {
375245
375293
  const { exit } = useApp3();
375246
375294
  const [state, setState] = useState6({ phase: "checking-auth" });
375247
375295
  const clientRef = React7.useRef(null);
@@ -375251,10 +375299,7 @@ function DeployUI({ environment, config }) {
375251
375299
  if (hasProjectId(projectDir)) {
375252
375300
  const projectId = readProjectId(projectDir);
375253
375301
  if (isLoggedIn()) {
375254
- setState({
375255
- phase: "creating-tarball",
375256
- projectId
375257
- });
375302
+ setState({ phase: "loading-environments", projectId });
375258
375303
  } else {
375259
375304
  setState({ phase: "logging-in", projectId });
375260
375305
  }
@@ -375309,7 +375354,7 @@ function DeployUI({ environment, config }) {
375309
375354
  const successResponse = response;
375310
375355
  await saveCredentialsFromToken(successResponse);
375311
375356
  setState(
375312
- (s) => s.projectId ? { phase: "creating-tarball", projectId: s.projectId } : { phase: "loading-projects" }
375357
+ (s) => s.projectId ? { phase: "loading-environments", projectId: s.projectId } : { phase: "loading-projects" }
375313
375358
  );
375314
375359
  }
375315
375360
  };
@@ -375368,8 +375413,9 @@ function DeployUI({ environment, config }) {
375368
375413
  const proj = project;
375369
375414
  writeProjectId(proj.id);
375370
375415
  setState({
375371
- phase: "creating-tarball",
375372
- projectId: proj.id
375416
+ phase: "loading-environments",
375417
+ projectId: proj.id,
375418
+ environments: proj.environments
375373
375419
  });
375374
375420
  }
375375
375421
  },
@@ -375392,8 +375438,9 @@ function DeployUI({ environment, config }) {
375392
375438
  if (cancelled) return;
375393
375439
  writeProjectId(project.id);
375394
375440
  setState({
375395
- phase: "creating-tarball",
375396
- projectId: project.id
375441
+ phase: "loading-environments",
375442
+ projectId: project.id,
375443
+ environments: project.environments
375397
375444
  });
375398
375445
  } catch (err) {
375399
375446
  if (cancelled) return;
@@ -375408,6 +375455,101 @@ function DeployUI({ environment, config }) {
375408
375455
  cancelled = true;
375409
375456
  };
375410
375457
  }, [state.phase, state.newProjectName]);
375458
+ useEffect6(() => {
375459
+ if (state.phase !== "loading-environments" || !state.projectId) return;
375460
+ let cancelled = false;
375461
+ async function loadEnvironments() {
375462
+ try {
375463
+ let environments = state.environments;
375464
+ if (!environments) {
375465
+ const token = await getValidAccessToken();
375466
+ const client2 = new SpecificClient({ accessToken: token });
375467
+ const projects2 = await client2.listProjects();
375468
+ const project = projects2.find((p) => p.id === state.projectId);
375469
+ environments = project?.environments ?? [];
375470
+ }
375471
+ if (cancelled) return;
375472
+ if (environments.length === 0) {
375473
+ setState((s) => ({
375474
+ ...s,
375475
+ phase: "error",
375476
+ error: "No environments found for this project"
375477
+ }));
375478
+ return;
375479
+ }
375480
+ if (envFlag) {
375481
+ const match = environments.find((e) => e.name === envFlag);
375482
+ if (!match) {
375483
+ setState((s) => ({
375484
+ ...s,
375485
+ phase: "error",
375486
+ error: `Environment "${envFlag}" not found. Available: ${environments.map((e) => e.name).join(", ")}`
375487
+ }));
375488
+ return;
375489
+ }
375490
+ writeEnvironmentId(match.id);
375491
+ setState((s) => ({
375492
+ ...s,
375493
+ phase: "creating-tarball",
375494
+ environmentName: match.name,
375495
+ environments
375496
+ }));
375497
+ return;
375498
+ }
375499
+ const projectDir = process.cwd();
375500
+ if (hasEnvironmentId(projectDir)) {
375501
+ const savedEnvId = readEnvironmentId(projectDir);
375502
+ const match = environments.find((e) => e.id === savedEnvId);
375503
+ if (match) {
375504
+ setState((s) => ({
375505
+ ...s,
375506
+ phase: "creating-tarball",
375507
+ environmentName: match.name,
375508
+ environments
375509
+ }));
375510
+ return;
375511
+ }
375512
+ }
375513
+ if (environments.length === 1) {
375514
+ writeEnvironmentId(environments[0].id);
375515
+ setState((s) => ({
375516
+ ...s,
375517
+ phase: "creating-tarball",
375518
+ environmentName: environments[0].name,
375519
+ environments
375520
+ }));
375521
+ return;
375522
+ }
375523
+ setState((s) => ({
375524
+ ...s,
375525
+ phase: "selecting-environment",
375526
+ environments,
375527
+ environmentSelectedIndex: 0
375528
+ }));
375529
+ } catch (err) {
375530
+ if (cancelled) return;
375531
+ setState({
375532
+ phase: "error",
375533
+ error: err instanceof Error ? err.message : String(err)
375534
+ });
375535
+ }
375536
+ }
375537
+ loadEnvironments();
375538
+ return () => {
375539
+ cancelled = true;
375540
+ };
375541
+ }, [state.phase, state.projectId]);
375542
+ const handleEnvironmentSelect = useCallback3(
375543
+ (env2) => {
375544
+ writeEnvironmentId(env2.id);
375545
+ setState((s) => ({
375546
+ ...s,
375547
+ phase: "creating-tarball",
375548
+ environmentName: env2.name
375549
+ }));
375550
+ },
375551
+ []
375552
+ );
375411
375553
  const handleSecretSubmit = useCallback3((value) => {
375412
375554
  setState((s) => {
375413
375555
  if (!s.missingSecrets || s.currentSecretIndex === void 0) return s;
@@ -375552,12 +375694,13 @@ function DeployUI({ environment, config }) {
375552
375694
  }
375553
375695
  })();
375554
375696
  }, [state]);
375697
+ const environment = state.environmentName || "prod";
375555
375698
  useEffect6(() => {
375556
- if (state.phase !== "creating-tarball" || !state.projectId) return;
375699
+ if (state.phase !== "creating-tarball" || !state.projectId || !state.environmentName) return;
375557
375700
  let cancelled = false;
375558
375701
  async function runDeploy() {
375559
375702
  const projectDir = process.cwd();
375560
- writeLog("deploy", `Starting deployment to "${environment}"`);
375703
+ writeLog("deploy", `Starting deployment to "${state.environmentName}"`);
375561
375704
  writeLog("deploy", `Project directory: ${projectDir}`);
375562
375705
  const client2 = new SpecificClient({ tokenProvider: getValidAccessToken });
375563
375706
  clientRef.current = client2;
@@ -375589,7 +375732,7 @@ function DeployUI({ environment, config }) {
375589
375732
  try {
375590
375733
  writeLog("deploy", `Creating deployment for project ${state.projectId}`);
375591
375734
  const gitInfo = getGitInfo(projectDir);
375592
- deployment2 = await client2.createDeployment(state.projectId, environment, {
375735
+ deployment2 = await client2.createDeployment(state.projectId, state.environmentName, {
375593
375736
  triggeredBy: "cli",
375594
375737
  ...gitInfo && {
375595
375738
  gitCommitSha: gitInfo.commitSha,
@@ -375631,7 +375774,7 @@ function DeployUI({ environment, config }) {
375631
375774
  return () => {
375632
375775
  cancelled = true;
375633
375776
  };
375634
- }, [state.projectId, environment, config.builds]);
375777
+ }, [state.projectId, state.environmentName, config.builds]);
375635
375778
  useEffect6(() => {
375636
375779
  if (state.phase !== "pending" || !state.deployment) return;
375637
375780
  let pollInterval;
@@ -375899,6 +376042,30 @@ function DeployUI({ environment, config }) {
375899
376042
  if (phase === "creating-project") {
375900
376043
  return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Creating project..."));
375901
376044
  }
376045
+ if (phase === "loading-environments") {
376046
+ return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Loading environments..."));
376047
+ }
376048
+ if (phase === "selecting-environment" && state.environments && state.environmentSelectedIndex !== void 0) {
376049
+ return /* @__PURE__ */ React7.createElement(
376050
+ EnvironmentSelector,
376051
+ {
376052
+ environments: state.environments,
376053
+ selectedIndex: state.environmentSelectedIndex,
376054
+ onSelect: handleEnvironmentSelect,
376055
+ onUp: () => setState((s) => ({
376056
+ ...s,
376057
+ environmentSelectedIndex: Math.max(0, (s.environmentSelectedIndex ?? 0) - 1)
376058
+ })),
376059
+ onDown: () => setState((s) => ({
376060
+ ...s,
376061
+ environmentSelectedIndex: Math.min(
376062
+ (s.environments?.length ?? 1) - 1,
376063
+ (s.environmentSelectedIndex ?? 0) + 1
376064
+ )
376065
+ }))
376066
+ }
376067
+ );
376068
+ }
375902
376069
  const currentSecret = missingSecrets && currentSecretIndex !== void 0 ? missingSecrets[currentSecretIndex] : void 0;
375903
376070
  const currentConfig = missingConfigs && currentConfigIndex !== void 0 ? missingConfigs[currentConfigIndex] : void 0;
375904
376071
  const getDisplayPhase = () => {
@@ -376004,6 +376171,52 @@ async function runDeployPipeline(options2) {
376004
376171
  } else if (!hasProjectId(projectDir)) {
376005
376172
  writeProjectId(projectId);
376006
376173
  }
376174
+ let environmentName;
376175
+ if (options2.env) {
376176
+ environmentName = options2.env;
376177
+ } else if (hasEnvironmentId(projectDir)) {
376178
+ const savedEnvId = readEnvironmentId(projectDir);
376179
+ const projects = await client2.listProjects();
376180
+ const project = projects.find((p) => p.id === projectId);
376181
+ const env2 = project?.environments.find((e) => e.id === savedEnvId);
376182
+ if (env2) {
376183
+ environmentName = env2.name;
376184
+ } else {
376185
+ const environments = project?.environments ?? [];
376186
+ if (environments.length === 1) {
376187
+ environmentName = environments[0].name;
376188
+ writeEnvironmentId(environments[0].id);
376189
+ } else if (environments.length === 0) {
376190
+ console.error("Error: No environments found for this project");
376191
+ process.exit(1);
376192
+ } else {
376193
+ console.error(
376194
+ `Error: Multiple environments available. Specify one with --env.
376195
+ Available: ${environments.map((e) => e.name).join(", ")}
376196
+ Example: specific deploy --env ${environments[0].name}`
376197
+ );
376198
+ process.exit(1);
376199
+ }
376200
+ }
376201
+ } else {
376202
+ const projects = await client2.listProjects();
376203
+ const project = projects.find((p) => p.id === projectId);
376204
+ const environments = project?.environments ?? [];
376205
+ if (environments.length === 1) {
376206
+ environmentName = environments[0].name;
376207
+ writeEnvironmentId(environments[0].id);
376208
+ } else if (environments.length === 0) {
376209
+ console.error("Error: No environments found for this project");
376210
+ process.exit(1);
376211
+ } else {
376212
+ console.error(
376213
+ `Error: Multiple environments available. Specify one with --env.
376214
+ Available: ${environments.map((e) => e.name).join(", ")}
376215
+ Example: specific deploy --env ${environments[0].name}`
376216
+ );
376217
+ process.exit(1);
376218
+ }
376219
+ }
376007
376220
  const parsedSecrets = {};
376008
376221
  if (options2.secrets) {
376009
376222
  for (const s of options2.secrets) {
@@ -376037,7 +376250,7 @@ async function runDeployPipeline(options2) {
376037
376250
  let deployment;
376038
376251
  try {
376039
376252
  const gitInfo = getGitInfo(projectDir);
376040
- deployment = await client2.createDeployment(projectId, "prod", {
376253
+ deployment = await client2.createDeployment(projectId, environmentName, {
376041
376254
  triggeredBy: "cli",
376042
376255
  ...gitInfo && {
376043
376256
  gitCommitSha: gitInfo.commitSha,
@@ -376184,6 +376397,7 @@ async function deployCommand(options2) {
376184
376397
  await runDeployPipeline({
376185
376398
  config,
376186
376399
  projectId: options2.project,
376400
+ env: options2.env,
376187
376401
  secrets: options2.secret,
376188
376402
  configs: options2.config
376189
376403
  });
@@ -376193,7 +376407,7 @@ async function deployCommand(options2) {
376193
376407
  /* @__PURE__ */ React7.createElement(
376194
376408
  DeployUI,
376195
376409
  {
376196
- environment: "prod",
376410
+ envFlag: options2.env,
376197
376411
  config
376198
376412
  }
376199
376413
  )
@@ -377054,7 +377268,7 @@ function compareVersions(a, b) {
377054
377268
  return 0;
377055
377269
  }
377056
377270
  async function checkForUpdate() {
377057
- const currentVersion = "0.1.118";
377271
+ const currentVersion = "0.1.120";
377058
377272
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
377059
377273
  if (!response.ok) {
377060
377274
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -377303,12 +377517,14 @@ async function projectListCommand() {
377303
377517
  if (!grouped.has(orgName)) {
377304
377518
  grouped.set(orgName, []);
377305
377519
  }
377306
- grouped.get(orgName).push({ id: project.id, name: project.name });
377520
+ grouped.get(orgName).push({ id: project.id, name: project.name, environments: project.environments });
377307
377521
  }
377308
377522
  for (const [orgName, orgProjects] of grouped) {
377309
377523
  console.log(`${orgName}:`);
377310
377524
  for (const project of orgProjects) {
377311
- console.log(` ${project.name} (${project.id})`);
377525
+ const envNames = project.environments.map((e) => e.name).join(", ");
377526
+ const envSuffix = envNames ? ` \u2014 ${envNames}` : "";
377527
+ console.log(` ${project.name} (${project.id})${envSuffix}`);
377312
377528
  }
377313
377529
  }
377314
377530
  } catch (error) {
@@ -377322,7 +377538,7 @@ async function projectListCommand() {
377322
377538
  var program = new Command();
377323
377539
  var env = "production";
377324
377540
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
377325
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.118").enablePositionalOptions();
377541
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.120").enablePositionalOptions();
377326
377542
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
377327
377543
  Examples:
377328
377544
  $ specific init
@@ -377343,9 +377559,10 @@ Examples:
377343
377559
  const key = options2.key ?? getDefaultKey();
377344
377560
  devCommand(key, options2.tunnel ?? false);
377345
377561
  });
377346
- program.command("deploy").description("Deploy to Specific infrastructure").option("--project <id>", "Project ID to deploy to (overrides .projectid file)").option("--secret <key=value...>", "Secret values (repeatable)").option("--config <key=value...>", "Config values (repeatable)").addHelpText("after", `
377562
+ program.command("deploy").description("Deploy to Specific infrastructure").option("--project <id>", "Project ID to deploy to (overrides .projectid file)").option("--env <name>", "Target environment (auto-selected if only one exists)").option("--secret <key=value...>", "Secret values (repeatable)").option("--config <key=value...>", "Config values (repeatable)").addHelpText("after", `
377347
377563
  Examples:
377348
377564
  $ specific deploy
377565
+ $ specific deploy --env staging
377349
377566
  $ specific deploy --project proj_123
377350
377567
  $ specific deploy --secret db_url=postgres://... --config domain=app.com`).action((options2) => {
377351
377568
  deployCommand(options2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.118",
3
+ "version": "0.1.120",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",