@specific.dev/cli 0.1.101 → 0.1.102

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 (68) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +2 -2
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
  5. package/dist/admin/__next._full.txt +2 -2
  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/_next/static/chunks/{1f8468aeb163fb80.js → 93d028b73685d80d.js} +1 -1
  10. package/dist/admin/_not-found/__next._full.txt +1 -1
  11. package/dist/admin/_not-found/__next._head.txt +1 -1
  12. package/dist/admin/_not-found/__next._index.txt +1 -1
  13. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  14. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  15. package/dist/admin/_not-found/__next._tree.txt +1 -1
  16. package/dist/admin/_not-found/index.html +1 -1
  17. package/dist/admin/_not-found/index.txt +1 -1
  18. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  20. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
  21. package/dist/admin/databases/__next._full.txt +1 -1
  22. package/dist/admin/databases/__next._head.txt +1 -1
  23. package/dist/admin/databases/__next._index.txt +1 -1
  24. package/dist/admin/databases/__next._tree.txt +1 -1
  25. package/dist/admin/databases/index.html +1 -1
  26. package/dist/admin/databases/index.txt +1 -1
  27. package/dist/admin/fullscreen/__next._full.txt +2 -2
  28. package/dist/admin/fullscreen/__next._head.txt +1 -1
  29. package/dist/admin/fullscreen/__next._index.txt +1 -1
  30. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  31. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
  32. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  33. package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
  34. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  39. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  40. package/dist/admin/fullscreen/databases/index.html +1 -1
  41. package/dist/admin/fullscreen/databases/index.txt +1 -1
  42. package/dist/admin/fullscreen/index.html +1 -1
  43. package/dist/admin/fullscreen/index.txt +2 -2
  44. package/dist/admin/index.html +1 -1
  45. package/dist/admin/index.txt +2 -2
  46. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  48. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
  49. package/dist/admin/mail/__next._full.txt +1 -1
  50. package/dist/admin/mail/__next._head.txt +1 -1
  51. package/dist/admin/mail/__next._index.txt +1 -1
  52. package/dist/admin/mail/__next._tree.txt +1 -1
  53. package/dist/admin/mail/index.html +1 -1
  54. package/dist/admin/mail/index.txt +1 -1
  55. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
  56. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
  57. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  58. package/dist/admin/workflows/__next._full.txt +1 -1
  59. package/dist/admin/workflows/__next._head.txt +1 -1
  60. package/dist/admin/workflows/__next._index.txt +1 -1
  61. package/dist/admin/workflows/__next._tree.txt +1 -1
  62. package/dist/admin/workflows/index.html +1 -1
  63. package/dist/admin/workflows/index.txt +1 -1
  64. package/dist/cli.js +315 -16
  65. package/package.json +1 -1
  66. /package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_buildManifest.js +0 -0
  67. /package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_clientMiddlewareManifest.json +0 -0
  68. /package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -373033,7 +373033,7 @@ function trackEvent(event, properties) {
373033
373033
  event,
373034
373034
  properties: {
373035
373035
  ...properties,
373036
- cli_version: "0.1.101",
373036
+ cli_version: "0.1.102",
373037
373037
  platform: process.platform,
373038
373038
  node_version: process.version,
373039
373039
  project_id: getProjectId()
@@ -375666,7 +375666,185 @@ function DeployUI({ environment, config }) {
375666
375666
  }
375667
375667
  ), phase === "error" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, deployment?.error ? /* @__PURE__ */ React7.createElement(StructuredError, { error: deployment.error }) : /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, error), buildOutput && /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Build output:"), /* @__PURE__ */ React7.createElement(Text7, null, buildOutput))), phase === "success" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Deployment successful!"), deployment?.publicUrls && Object.keys(deployment.publicUrls).length > 0 && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Public URLs:"), Object.entries(deployment.publicUrls).map(([name, url]) => /* @__PURE__ */ React7.createElement(Text7, { key: name }, " ", name, ": ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, url))))));
375668
375668
  }
375669
- async function deployCommand(environment) {
375669
+ async function runDeployPipeline(options2) {
375670
+ const { config } = options2;
375671
+ const projectDir = process.cwd();
375672
+ let token;
375673
+ try {
375674
+ token = await getValidAccessToken();
375675
+ } catch {
375676
+ console.error("Error: Not logged in.\n Run 'specific login' first.");
375677
+ process.exit(1);
375678
+ }
375679
+ const client2 = new SpecificClient({ accessToken: token });
375680
+ let projectId = options2.projectId;
375681
+ if (!projectId) {
375682
+ if (hasProjectId(projectDir)) {
375683
+ projectId = readProjectId(projectDir);
375684
+ } else {
375685
+ console.error(
375686
+ "Error: No project linked.\n Create one first: specific project new <name> [--org <org-id>]\n Or pass one directly: specific deploy --project <project-id>"
375687
+ );
375688
+ process.exit(1);
375689
+ }
375690
+ } else if (!hasProjectId(projectDir)) {
375691
+ writeProjectId(projectId);
375692
+ }
375693
+ const parsedSecrets = {};
375694
+ if (options2.secrets) {
375695
+ for (const s of options2.secrets) {
375696
+ const eqIndex = s.indexOf("=");
375697
+ if (eqIndex > 0) {
375698
+ parsedSecrets[s.substring(0, eqIndex)] = s.substring(eqIndex + 1);
375699
+ }
375700
+ }
375701
+ }
375702
+ const parsedConfigs = {};
375703
+ if (options2.configs) {
375704
+ for (const c of options2.configs) {
375705
+ const eqIndex = c.indexOf("=");
375706
+ if (eqIndex > 0) {
375707
+ parsedConfigs[c.substring(0, eqIndex)] = c.substring(eqIndex + 1);
375708
+ }
375709
+ }
375710
+ }
375711
+ console.log("Creating archive...");
375712
+ let tarball;
375713
+ let appPath;
375714
+ try {
375715
+ const result = await createTarball(config, projectDir);
375716
+ tarball = result.tarball;
375717
+ appPath = result.appPath;
375718
+ } catch (err) {
375719
+ console.error(`Error: Failed to create archive: ${err instanceof Error ? err.message : String(err)}`);
375720
+ process.exit(1);
375721
+ }
375722
+ console.log("Creating deployment...");
375723
+ let deployment;
375724
+ try {
375725
+ deployment = await client2.createDeployment(projectId, "prod");
375726
+ } catch (err) {
375727
+ console.error(`Error: Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`);
375728
+ process.exit(1);
375729
+ }
375730
+ console.log("Uploading...");
375731
+ try {
375732
+ deployment = await client2.uploadTarball(deployment.id, tarball, appPath);
375733
+ } catch (err) {
375734
+ console.error(`Error: Failed to upload: ${err instanceof Error ? err.message : String(err)}`);
375735
+ process.exit(1);
375736
+ }
375737
+ console.log("Waiting for build...");
375738
+ while (true) {
375739
+ await new Promise((resolve9) => setTimeout(resolve9, 2e3));
375740
+ const status = await client2.getDeployment(deployment.id);
375741
+ deployment = status;
375742
+ if (status.state === "failed") {
375743
+ console.error(`Error: Deployment failed: ${status.stateMessage || "Unknown error"}`);
375744
+ process.exit(1);
375745
+ }
375746
+ const failedBuild = getFailedBuild(status.pendingActions);
375747
+ if (failedBuild && failedBuild.type === "build_failed") {
375748
+ console.error(`Error: Build "${failedBuild.serviceName}" failed: ${failedBuild.error}`);
375749
+ if (failedBuild.output) {
375750
+ console.error(`
375751
+ Build output:
375752
+ ${failedBuild.output}`);
375753
+ }
375754
+ process.exit(1);
375755
+ }
375756
+ const missingSecrets = getMissingSecrets(status.pendingActions);
375757
+ if (missingSecrets.length > 0) {
375758
+ const secretsToSubmit = {};
375759
+ const stillMissing = [];
375760
+ for (const name of missingSecrets) {
375761
+ if (parsedSecrets[name] !== void 0) {
375762
+ secretsToSubmit[name] = parsedSecrets[name];
375763
+ } else {
375764
+ stillMissing.push(name);
375765
+ }
375766
+ }
375767
+ if (stillMissing.length > 0) {
375768
+ console.error(
375769
+ `Error: Missing required secrets: ${stillMissing.join(", ")}
375770
+ ${stillMissing.map((s) => `specific deploy --secret ${s}=<value>`).join(" ")}`
375771
+ );
375772
+ process.exit(1);
375773
+ }
375774
+ await client2.submitSecrets(deployment.id, secretsToSubmit);
375775
+ continue;
375776
+ }
375777
+ const missingConfigs = getMissingConfigs(status.pendingActions);
375778
+ if (missingConfigs.length > 0) {
375779
+ const configsToSubmit = {};
375780
+ const stillMissing = [];
375781
+ for (const name of missingConfigs) {
375782
+ if (parsedConfigs[name] !== void 0) {
375783
+ configsToSubmit[name] = parsedConfigs[name];
375784
+ } else {
375785
+ stillMissing.push(name);
375786
+ }
375787
+ }
375788
+ if (stillMissing.length > 0) {
375789
+ console.error(
375790
+ `Error: Missing required configs: ${stillMissing.join(", ")}
375791
+ ${stillMissing.map((c) => `specific deploy --config ${c}=<value>`).join(" ")}`
375792
+ );
375793
+ process.exit(1);
375794
+ }
375795
+ await client2.submitConfigs(deployment.id, configsToSubmit);
375796
+ continue;
375797
+ }
375798
+ if (hasBuildsInProgress(status.pendingActions)) {
375799
+ continue;
375800
+ }
375801
+ if (!status.pendingActions || status.pendingActions.length === 0) {
375802
+ break;
375803
+ }
375804
+ }
375805
+ console.log("Starting deployment...");
375806
+ try {
375807
+ await client2.startDeployment(deployment.id);
375808
+ } catch (err) {
375809
+ console.error(`Error: Failed to start deployment: ${err instanceof Error ? err.message : String(err)}`);
375810
+ process.exit(1);
375811
+ }
375812
+ console.log("Deploying...");
375813
+ while (true) {
375814
+ await new Promise((resolve9) => setTimeout(resolve9, 2e3));
375815
+ const status = await client2.getDeployment(deployment.id);
375816
+ deployment = status;
375817
+ if (status.state === "failed") {
375818
+ if (status.error) {
375819
+ console.error(`Error: ${formatErrorCode(status.error.code)}: ${status.error.message}`);
375820
+ if (status.error.output) {
375821
+ console.error(`
375822
+ Output:
375823
+ ${status.error.output}`);
375824
+ }
375825
+ } else {
375826
+ console.error(`Error: Deployment failed: ${status.stateMessage || "Unknown error"}`);
375827
+ }
375828
+ process.exit(1);
375829
+ }
375830
+ if (status.state === "active") {
375831
+ deployment = status;
375832
+ break;
375833
+ }
375834
+ }
375835
+ console.log("");
375836
+ console.log(`\u2713 Deployed successfully`);
375837
+ console.log("");
375838
+ console.log(` deployment: ${deployment.id}`);
375839
+ if (deployment.publicUrls && Object.keys(deployment.publicUrls).length > 0) {
375840
+ console.log("");
375841
+ console.log(" URLs:");
375842
+ for (const [name, url] of Object.entries(deployment.publicUrls)) {
375843
+ console.log(` ${name}: ${url}`);
375844
+ }
375845
+ }
375846
+ }
375847
+ async function deployCommand(options2) {
375670
375848
  const configPath = path19.join(process.cwd(), "specific.hcl");
375671
375849
  if (!fs21.existsSync(configPath)) {
375672
375850
  console.error("Error: No specific.hcl found in current directory");
@@ -375680,12 +375858,21 @@ async function deployCommand(environment) {
375680
375858
  console.error(formatConfigError(err, hcl, configPath));
375681
375859
  process.exit(1);
375682
375860
  }
375683
- const env2 = environment || "prod";
375861
+ const hasNonInteractiveFlags = options2.project || options2.secret?.length || options2.config?.length;
375862
+ if (!isInteractive() || hasNonInteractiveFlags) {
375863
+ await runDeployPipeline({
375864
+ config,
375865
+ projectId: options2.project,
375866
+ secrets: options2.secret,
375867
+ configs: options2.config
375868
+ });
375869
+ return;
375870
+ }
375684
375871
  render5(
375685
375872
  /* @__PURE__ */ React7.createElement(
375686
375873
  DeployUI,
375687
375874
  {
375688
- environment: env2,
375875
+ environment: "prod",
375689
375876
  config
375690
375877
  }
375691
375878
  )
@@ -376525,7 +376712,7 @@ function compareVersions(a, b) {
376525
376712
  return 0;
376526
376713
  }
376527
376714
  async function checkForUpdate() {
376528
- const currentVersion = "0.1.101";
376715
+ const currentVersion = "0.1.102";
376529
376716
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
376530
376717
  if (!response.ok) {
376531
376718
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -376720,38 +376907,150 @@ function updateCommand() {
376720
376907
  render9(/* @__PURE__ */ React11.createElement(UpdateUI, null));
376721
376908
  }
376722
376909
 
376910
+ // src/commands/project.tsx
376911
+ async function projectNewCommand(name, options2) {
376912
+ try {
376913
+ const token = await getValidAccessToken();
376914
+ const client2 = new SpecificClient({ accessToken: token });
376915
+ let orgId = options2.org;
376916
+ if (!orgId) {
376917
+ const organizations = await client2.listOrganizations();
376918
+ if (organizations.length === 0) {
376919
+ console.error(
376920
+ "You don't belong to any organizations. Please create one first."
376921
+ );
376922
+ process.exit(1);
376923
+ }
376924
+ if (organizations.length === 1) {
376925
+ orgId = organizations[0].id;
376926
+ } else {
376927
+ console.error(
376928
+ "You belong to multiple organizations. Please specify one with --org.\n"
376929
+ );
376930
+ console.error("Available organizations:");
376931
+ for (const org of organizations) {
376932
+ console.error(` ${org.name} (${org.id})`);
376933
+ }
376934
+ process.exit(1);
376935
+ }
376936
+ }
376937
+ const project = await client2.createProject(name, orgId);
376938
+ console.log(`Project created: ${project.id}`);
376939
+ } catch (error) {
376940
+ const message = error instanceof Error ? error.message : "Unknown error occurred";
376941
+ console.error(`Failed to create project: ${message}`);
376942
+ process.exit(1);
376943
+ }
376944
+ }
376945
+ async function projectListCommand() {
376946
+ try {
376947
+ const token = await getValidAccessToken();
376948
+ const client2 = new SpecificClient({ accessToken: token });
376949
+ const [projects, organizations] = await Promise.all([
376950
+ client2.listProjects(),
376951
+ client2.listOrganizations()
376952
+ ]);
376953
+ if (projects.length === 0) {
376954
+ console.log("No projects found.");
376955
+ return;
376956
+ }
376957
+ const orgMap = new Map(organizations.map((org) => [org.id, org.name]));
376958
+ const grouped = /* @__PURE__ */ new Map();
376959
+ for (const project of projects) {
376960
+ const orgName = orgMap.get(project.organizationId) ?? project.organizationId;
376961
+ if (!grouped.has(orgName)) {
376962
+ grouped.set(orgName, []);
376963
+ }
376964
+ grouped.get(orgName).push({ id: project.id, name: project.name });
376965
+ }
376966
+ for (const [orgName, orgProjects] of grouped) {
376967
+ console.log(`${orgName}:`);
376968
+ for (const project of orgProjects) {
376969
+ console.log(` ${project.name} (${project.id})`);
376970
+ }
376971
+ }
376972
+ } catch (error) {
376973
+ const message = error instanceof Error ? error.message : "Unknown error occurred";
376974
+ console.error(`Failed to list projects: ${message}`);
376975
+ process.exit(1);
376976
+ }
376977
+ }
376978
+
376723
376979
  // src/cli-program.tsx
376724
376980
  var program = new Command();
376725
376981
  var env = "production";
376726
376982
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
376727
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.101").enablePositionalOptions();
376728
- 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));
376729
- program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
376730
- program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
376731
- program.command("dev").description("Start local development environment").option("-k, --key <key>", "Namespace for isolated dev environment (auto-detected from git worktree if not specified)").option("--tunnel", "Expose public services via localtunnel URLs").action((options2) => {
376983
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.102").enablePositionalOptions();
376984
+ program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
376985
+ Examples:
376986
+ $ specific init
376987
+ $ specific init --agent claude cursor`).action((options2) => initCommand(options2));
376988
+ program.command("docs [topic]").description("Fetch LLM-optimized documentation").addHelpText("after", `
376989
+ Examples:
376990
+ $ specific docs
376991
+ $ specific docs services
376992
+ $ specific docs postgres/reshape`).action(docsCommand);
376993
+ program.command("check").description("Validate specific.hcl configuration").addHelpText("after", `
376994
+ Examples:
376995
+ $ specific check`).action(checkCommand);
376996
+ program.command("dev").description("Start local development environment").option("-k, --key <key>", "Namespace for isolated dev environment (auto-detected from git worktree if not specified)").option("--tunnel", "Expose public services via localtunnel URLs").addHelpText("after", `
376997
+ Examples:
376998
+ $ specific dev
376999
+ $ specific dev --tunnel
377000
+ $ specific dev --key feature-branch`).action((options2) => {
376732
377001
  const key = options2.key ?? getDefaultKey();
376733
377002
  devCommand(key, options2.tunnel ?? false);
376734
377003
  });
376735
- program.command("deploy [environment]").description("Deploy to Specific infrastructure").action((environment) => {
376736
- deployCommand(environment);
377004
+ 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", `
377005
+ Examples:
377006
+ $ specific deploy
377007
+ $ specific deploy --project proj_123
377008
+ $ specific deploy --secret db_url=postgres://... --config domain=app.com`).action((options2) => {
377009
+ deployCommand(options2);
376737
377010
  });
376738
- program.command("exec <service> [args...]").description("Run a one-off command with service environment").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().action(async (service, args, options2) => {
377011
+ program.command("exec <service> [args...]").description("Run a one-off command with service environment").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().addHelpText("after", `
377012
+ Examples:
377013
+ $ specific exec api -- npm run migrate
377014
+ $ specific exec worker -- python manage.py shell`).action(async (service, args, options2) => {
376739
377015
  const filteredArgs = args[0] === "--" ? args.slice(1) : args;
376740
377016
  const key = options2.key ?? getDefaultKey();
376741
377017
  await execCommand(service, filteredArgs, key);
376742
377018
  });
376743
- program.command("psql [database] [args...]").description("Connect to a Postgres database").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().action((database, args, options2) => {
377019
+ program.command("psql [database] [args...]").description("Connect to a Postgres database").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().addHelpText("after", `
377020
+ Examples:
377021
+ $ specific psql
377022
+ $ specific psql mydb
377023
+ $ specific psql mydb -- -c "SELECT 1"`).action((database, args, options2) => {
376744
377024
  const filteredArgs = args[0] === "--" ? args.slice(1) : args;
376745
377025
  const key = options2.key ?? getDefaultKey();
376746
377026
  psqlCommand(database, key, filteredArgs);
376747
377027
  });
376748
- program.command("reshape <action> [database]").description("Run Reshape migrations (start|complete|status|abort)").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").action((action, database, options2) => {
377028
+ program.command("reshape <action> [database]").description("Run Reshape migrations (start|complete|status|abort)").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").addHelpText("after", `
377029
+ Examples:
377030
+ $ specific reshape start
377031
+ $ specific reshape complete
377032
+ $ specific reshape status mydb`).action((action, database, options2) => {
376749
377033
  const key = options2.key ?? getDefaultKey();
376750
377034
  reshapeCommand(action, database, key);
376751
377035
  });
376752
- program.command("clean").description("Remove .specific directory for a clean slate").option("-k, --key <key>", "Clean only the specified dev environment key").action((options2) => {
377036
+ program.command("clean").description("Remove .specific directory for a clean slate").option("-k, --key <key>", "Clean only the specified dev environment key").addHelpText("after", `
377037
+ Examples:
377038
+ $ specific clean
377039
+ $ specific clean --key feature-branch`).action((options2) => {
376753
377040
  cleanCommand(options2.key);
376754
377041
  });
377042
+ var projectCmd = program.command("project").description("Manage projects");
377043
+ projectCmd.command("new <name>").description("Create a new project").option("--org <id>", "Organization ID (required if you belong to multiple organizations)").addHelpText("after", `
377044
+ Examples:
377045
+ $ specific project new my-app
377046
+ $ specific project new my-app --org org_123`).action((name, options2) => {
377047
+ projectNewCommand(name, options2);
377048
+ });
377049
+ projectCmd.command("list").description("List all projects").addHelpText("after", `
377050
+ Examples:
377051
+ $ specific project list`).action(() => {
377052
+ projectListCommand();
377053
+ });
376755
377054
  program.command("beta").description("Manage beta feature flags").action(betaCommand);
376756
377055
  program.command("update").description("Update Specific CLI to the latest version").action(updateCommand);
376757
377056
  program.command("login").description("Log in to Specific").action(loginCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.101",
3
+ "version": "0.1.102",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",