@lizard-build/cli 0.3.78 → 0.3.79

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.
@@ -1,8 +1,9 @@
1
1
  import { Command } from "commander";
2
2
  /**
3
- * `lizard workspace` — create and list workspaces.
3
+ * `lizard workspace` — create, list, and delete workspaces.
4
4
  *
5
- * Member management (invite/remove/rename) intentionally lives in the
6
- * dashboard, not here, to keep CLI surface narrow (Railway model).
5
+ * Delete only removes empty workspaces (no projects, no sandboxes). Member
6
+ * management (invite/remove/rename) intentionally lives in the dashboard, not
7
+ * here, to keep the CLI surface narrow (Railway model).
7
8
  */
8
9
  export declare function registerWorkspace(program: Command): void;
@@ -1,17 +1,19 @@
1
1
  import chalk from "chalk";
2
- import { api } from "../lib/api.js";
3
- import { fetchWorkspaces } from "../lib/picker.js";
4
- import { isJSONMode, printJSON, table, success, info } from "../lib/format.js";
2
+ import * as p from "@clack/prompts";
3
+ import { api, withQuery } from "../lib/api.js";
4
+ import { fetchWorkspaces, resolveWorkspace } from "../lib/picker.js";
5
+ import { isJSONMode, printJSON, table, success, info, isTTY } from "../lib/format.js";
5
6
  /**
6
- * `lizard workspace` — create and list workspaces.
7
+ * `lizard workspace` — create, list, and delete workspaces.
7
8
  *
8
- * Member management (invite/remove/rename) intentionally lives in the
9
- * dashboard, not here, to keep CLI surface narrow (Railway model).
9
+ * Delete only removes empty workspaces (no projects, no sandboxes). Member
10
+ * management (invite/remove/rename) intentionally lives in the dashboard, not
11
+ * here, to keep the CLI surface narrow (Railway model).
10
12
  */
11
13
  export function registerWorkspace(program) {
12
14
  const ws = program
13
15
  .command("workspace")
14
- .description("Create and list workspaces");
16
+ .description("Create, list, and delete workspaces");
15
17
  ws.command("create")
16
18
  .argument("<name>", "Workspace name")
17
19
  .description("Create a new workspace")
@@ -46,5 +48,36 @@ export function registerWorkspace(program) {
46
48
  w.isPersonal ? chalk.green("✓") : "",
47
49
  ]));
48
50
  });
51
+ ws.command("rm")
52
+ .alias("delete")
53
+ .argument("<name-or-id>", "Workspace name, slug, or ID")
54
+ .description("Delete an empty workspace")
55
+ .option("-y, --yes", "Skip confirmation")
56
+ .action(async (nameOrId, opts) => {
57
+ const workspace = await resolveWorkspace(nameOrId);
58
+ if (workspace.isPersonal) {
59
+ throw new Error("Cannot delete your personal workspace.");
60
+ }
61
+ if (workspace.role !== "owner") {
62
+ throw new Error("Only the workspace owner can delete it.");
63
+ }
64
+ // Empty workspaces only. Check here for a clear message; the backend
65
+ // enforces the same via ?requireEmpty=true and also refuses if any
66
+ // sandbox remains (which the CLI can't count on its own).
67
+ const projectCount = workspace.projectCount ?? 0;
68
+ if (projectCount > 0) {
69
+ throw new Error(`Workspace "${workspace.name}" has ${projectCount} project(s). Delete them first, or use the dashboard to remove everything.`);
70
+ }
71
+ if (!opts.yes && isTTY() && !isJSONMode()) {
72
+ const ok = await p.confirm({ message: `Delete workspace ${chalk.bold(workspace.name)}?` });
73
+ if (p.isCancel(ok) || !ok)
74
+ process.exit(5);
75
+ }
76
+ await api.delete(withQuery(`/api/workspaces/${workspace.id}`, { requireEmpty: true }));
77
+ if (isJSONMode())
78
+ printJSON({ id: workspace.id, status: "deleted" });
79
+ else
80
+ success(`Workspace ${chalk.bold(workspace.name)} deleted`);
81
+ });
49
82
  }
50
83
  //# sourceMappingURL=workspace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,GAAG,EAAkB,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,MAAM,EAAE,GAAG,OAAO;SACf,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,4BAA4B,CAAC,CAAC;IAE7C,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;SACjB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SACpC,WAAW,CAAC,wBAAwB,CAAC;SACrC,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,CAAY,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzE,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,OAAO,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,6DAA6D,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEL,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;SACf,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;QAErC,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;YACrF,OAAO;QACT,CAAC;QAED,KAAK,CACH,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,EAChD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACd,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI;YACN,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YAC3B,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;SACrC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAEpC,OAAO,EAAE,GAAG,EAAE,SAAS,EAAkB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEtF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,MAAM,EAAE,GAAG,OAAO;SACf,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,qCAAqC,CAAC,CAAC;IAEtD,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;SACjB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SACpC,WAAW,CAAC,wBAAwB,CAAC;SACrC,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,CAAY,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzE,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,OAAO,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,6DAA6D,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEL,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;SACf,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;QAErC,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;YACrF,OAAO;QACT,CAAC;QAED,KAAK,CACH,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,EAChD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACd,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI;YACN,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YAC3B,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;SACrC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;SACb,KAAK,CAAC,QAAQ,CAAC;SACf,QAAQ,CAAC,cAAc,EAAE,6BAA6B,CAAC;SACvD,WAAW,CAAC,2BAA2B,CAAC;SACxC,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;SACxC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAuB,EAAE,EAAE;QAC1D,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAEnD,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,qEAAqE;QACrE,mEAAmE;QACnE,0DAA0D;QAC1D,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,IAAI,CAAC,CAAC;QACjD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,cAAc,SAAS,CAAC,IAAI,SAAS,YAAY,4EAA4E,CAC9H,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAC1C,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,oBAAoB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YAC3F,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,mBAAmB,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvF,IAAI,UAAU,EAAE;YAAE,SAAS,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;;YAChE,OAAO,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -1,4 +1,4 @@
1
- export declare const CURRENT_VERSION = "0.3.78";
1
+ export declare const CURRENT_VERSION = "0.3.79";
2
2
  /**
3
3
  * True only when running as the Bun-compiled standalone binary. Under
4
4
  * npm/node, `process.execPath` is the *node* executable — self-update would
@@ -4,7 +4,7 @@ import { Readable } from "node:stream";
4
4
  import { join, dirname } from "node:path";
5
5
  import os from "node:os";
6
6
  import { spawn } from "node:child_process";
7
- export const CURRENT_VERSION = "0.3.78";
7
+ export const CURRENT_VERSION = "0.3.79";
8
8
  const RELEASES_API = "https://api.github.com/repos/lizard-build/lizard-cli/releases/latest";
9
9
  const RELEASE_BASE = "https://github.com/lizard-build/lizard-cli/releases/latest/download";
10
10
  /** Minimum gap between background update checks. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lizard-build/cli",
3
- "version": "0.3.78",
3
+ "version": "0.3.79",
4
4
  "description": "Lizard CLI — deploy and manage apps on Lizard",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,19 +1,21 @@
1
1
  import chalk from "chalk";
2
+ import * as p from "@clack/prompts";
2
3
  import { Command } from "commander";
3
- import { api, type Workspace } from "../lib/api.js";
4
- import { fetchWorkspaces } from "../lib/picker.js";
5
- import { isJSONMode, printJSON, table, success, info } from "../lib/format.js";
4
+ import { api, withQuery, type Workspace } from "../lib/api.js";
5
+ import { fetchWorkspaces, resolveWorkspace } from "../lib/picker.js";
6
+ import { isJSONMode, printJSON, table, success, info, isTTY } from "../lib/format.js";
6
7
 
7
8
  /**
8
- * `lizard workspace` — create and list workspaces.
9
+ * `lizard workspace` — create, list, and delete workspaces.
9
10
  *
10
- * Member management (invite/remove/rename) intentionally lives in the
11
- * dashboard, not here, to keep CLI surface narrow (Railway model).
11
+ * Delete only removes empty workspaces (no projects, no sandboxes). Member
12
+ * management (invite/remove/rename) intentionally lives in the dashboard, not
13
+ * here, to keep the CLI surface narrow (Railway model).
12
14
  */
13
15
  export function registerWorkspace(program: Command) {
14
16
  const ws = program
15
17
  .command("workspace")
16
- .description("Create and list workspaces");
18
+ .description("Create, list, and delete workspaces");
17
19
 
18
20
  ws.command("create")
19
21
  .argument("<name>", "Workspace name")
@@ -58,4 +60,38 @@ export function registerWorkspace(program: Command) {
58
60
  ]),
59
61
  );
60
62
  });
63
+
64
+ ws.command("rm")
65
+ .alias("delete")
66
+ .argument("<name-or-id>", "Workspace name, slug, or ID")
67
+ .description("Delete an empty workspace")
68
+ .option("-y, --yes", "Skip confirmation")
69
+ .action(async (nameOrId: string, opts: { yes?: boolean }) => {
70
+ const workspace = await resolveWorkspace(nameOrId);
71
+
72
+ if (workspace.isPersonal) {
73
+ throw new Error("Cannot delete your personal workspace.");
74
+ }
75
+ if (workspace.role !== "owner") {
76
+ throw new Error("Only the workspace owner can delete it.");
77
+ }
78
+ // Empty workspaces only. Check here for a clear message; the backend
79
+ // enforces the same via ?requireEmpty=true and also refuses if any
80
+ // sandbox remains (which the CLI can't count on its own).
81
+ const projectCount = workspace.projectCount ?? 0;
82
+ if (projectCount > 0) {
83
+ throw new Error(
84
+ `Workspace "${workspace.name}" has ${projectCount} project(s). Delete them first, or use the dashboard to remove everything.`,
85
+ );
86
+ }
87
+
88
+ if (!opts.yes && isTTY() && !isJSONMode()) {
89
+ const ok = await p.confirm({ message: `Delete workspace ${chalk.bold(workspace.name)}?` });
90
+ if (p.isCancel(ok) || !ok) process.exit(5);
91
+ }
92
+
93
+ await api.delete(withQuery(`/api/workspaces/${workspace.id}`, { requireEmpty: true }));
94
+ if (isJSONMode()) printJSON({ id: workspace.id, status: "deleted" });
95
+ else success(`Workspace ${chalk.bold(workspace.name)} deleted`);
96
+ });
61
97
  }
@@ -5,7 +5,7 @@ import { join, dirname } from "node:path";
5
5
  import os from "node:os";
6
6
  import { spawn } from "node:child_process";
7
7
 
8
- export const CURRENT_VERSION = "0.3.78";
8
+ export const CURRENT_VERSION = "0.3.79";
9
9
  const RELEASES_API = "https://api.github.com/repos/lizard-build/lizard-cli/releases/latest";
10
10
  const RELEASE_BASE = "https://github.com/lizard-build/lizard-cli/releases/latest/download";
11
11