@dropthis/cli 0.25.0 → 0.27.0

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.
package/README.md CHANGED
@@ -333,7 +333,7 @@ Reports CLI version, auth source (`env`, `flag`, `storage`, or `missing`), and c
333
333
 
334
334
  Connecting a custom domain (`dropthis domains connect`) requires the Pro plan (1 hostname). Domains already connected keep working regardless of plan.
335
335
 
336
- `dropthis account` shows your active tier and its limits.
336
+ `dropthis account` shows your active tier, its limits, and the workspace your key is bound to. If the workspace `kind` is `team`, your publishes land under the team's shared custom domain automatically — no extra flags needed.
337
337
 
338
338
  ## Agent skills
339
339
 
package/dist/cli.cjs CHANGED
@@ -509,6 +509,11 @@ async function runAccountGet(_input, deps) {
509
509
  if (data?.status) pairs.push(["Status", String(data.status)]);
510
510
  if (data?.createdAt)
511
511
  pairs.push(["Created", String(data.createdAt).split("T")[0]]);
512
+ const ws = data?.workspace;
513
+ if (ws?.name) {
514
+ const role = ws.role ? ` \xB7 your role: ${String(ws.role)}` : "";
515
+ pairs.push(["Workspace", `${String(ws.name)} (${String(ws.kind)})${role}`]);
516
+ }
512
517
  const usage = data?.usage;
513
518
  const limits = data?.limits;
514
519
  if (typeof usage?.storageUsedBytes === "number") {
@@ -787,6 +792,32 @@ var COMMAND_ANNOTATIONS = {
787
792
  auth: "required",
788
793
  examples: ["dropthis api-keys create --label CI --json"]
789
794
  },
795
+ workspace: {
796
+ auth: "required",
797
+ examples: ["dropthis workspace list --json", "dropthis workspace use acme"]
798
+ },
799
+ "workspace list": {
800
+ auth: "required",
801
+ examples: ["dropthis workspace list --json"]
802
+ },
803
+ "workspace use": {
804
+ auth: "required",
805
+ examples: [
806
+ "dropthis workspace use acme",
807
+ "dropthis workspace use ws_team123"
808
+ ]
809
+ },
810
+ keys: {
811
+ auth: "required",
812
+ examples: ["dropthis keys create --service --workspace acme --json"]
813
+ },
814
+ "keys create": {
815
+ auth: "required",
816
+ examples: [
817
+ "dropthis keys create --json",
818
+ "dropthis keys create --service --workspace acme --json"
819
+ ]
820
+ },
790
821
  login: {
791
822
  examples: [
792
823
  "dropthis login verify --email user@example.com --otp 123456 --json"
@@ -927,6 +958,9 @@ function spreadData(data) {
927
958
  return data && typeof data === "object" ? data : { data };
928
959
  }
929
960
 
961
+ // src/version.ts
962
+ var CLI_VERSION = true ? "0.27.0" : "0.0.0-dev";
963
+
930
964
  // src/commands/doctor.ts
931
965
  async function runDoctor(_input, deps) {
932
966
  const stored = await deps.store.read();
@@ -937,13 +971,13 @@ async function runDoctor(_input, deps) {
937
971
  const authSource = credential?.source ?? "missing";
938
972
  const storageBackend = stored?.storage ?? "none";
939
973
  const pairs = [
940
- ["Version", "0.25.0"],
974
+ ["Version", CLI_VERSION],
941
975
  ["Auth", authSource],
942
976
  ["Storage", storageBackend]
943
977
  ];
944
978
  writeKv(deps, pairs, {
945
979
  ok: true,
946
- version: "0.25.0",
980
+ version: CLI_VERSION,
947
981
  auth: { source: authSource },
948
982
  storage: { backend: storageBackend }
949
983
  });
@@ -1491,6 +1525,58 @@ async function runDropsDelete(target, input, deps) {
1491
1525
  return { exitCode: 0 };
1492
1526
  }
1493
1527
 
1528
+ // src/commands/keys.ts
1529
+ async function runKeysCreate(input, deps) {
1530
+ try {
1531
+ await requireCredential({
1532
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
1533
+ env: deps.env,
1534
+ store: deps.store
1535
+ });
1536
+ } catch {
1537
+ return writeAuthError(deps);
1538
+ }
1539
+ const keyType = input.type ?? "delegated";
1540
+ if (input.workspace && keyType !== "service") {
1541
+ return writeError(
1542
+ deps,
1543
+ "invalid_usage",
1544
+ "--workspace is only valid with --service (it pins a CI service key to one workspace). A delegated login key is account-scoped and switchable \u2014 use `dropthis workspace use <slug>` to change its active workspace."
1545
+ );
1546
+ }
1547
+ if (keyType === "service" && !input.workspace) {
1548
+ return writeError(
1549
+ deps,
1550
+ "invalid_usage",
1551
+ "Service keys must be pinned to a workspace: pass --workspace <slug-or-id>. (A service key is for CI/automation and never switches workspace.)"
1552
+ );
1553
+ }
1554
+ const label = input.label ?? (keyType === "service" ? `Service key${input.workspace ? ` (${input.workspace})` : ""}` : "CLI key");
1555
+ const createInput = {
1556
+ label,
1557
+ type: keyType
1558
+ };
1559
+ if (keyType === "service" && input.workspace) {
1560
+ createInput.workspace = input.workspace;
1561
+ }
1562
+ const result = await deps.client.apiKeys.create(createInput);
1563
+ if (result.error) return writeApiError(deps, result.error);
1564
+ const data = result.data;
1565
+ const pairs = [];
1566
+ if (data.id) pairs.push(["ID", String(data.id)]);
1567
+ if (data.key) pairs.push(["Key", String(data.key)]);
1568
+ if (data.keyLast4) pairs.push(["Last 4", String(data.keyLast4)]);
1569
+ if (data.label) pairs.push(["Label", String(data.label)]);
1570
+ writeKv(deps, pairs, { ok: true, api_key: result.data });
1571
+ if (deps.outputMode === "human") {
1572
+ deps.stderr(
1573
+ `${hint("Store this key now \u2014 it will not be shown again.")}
1574
+ `
1575
+ );
1576
+ }
1577
+ return { exitCode: 0 };
1578
+ }
1579
+
1494
1580
  // src/commands/login.ts
1495
1581
  var prompts4 = __toESM(require("@clack/prompts"), 1);
1496
1582
  async function runLoginInteractive(deps) {
@@ -1548,7 +1634,10 @@ async function runLoginInteractive(deps) {
1548
1634
  return { exitCode: exitCodeFor("api_error") };
1549
1635
  }
1550
1636
  const authedClient = deps.createClient(session.data.token);
1551
- const apiKey = await authedClient.apiKeys.create({ label: "CLI" });
1637
+ const apiKey = await authedClient.apiKeys.create({
1638
+ label: "CLI",
1639
+ type: "delegated"
1640
+ });
1552
1641
  if (apiKey.error) {
1553
1642
  prompts4.cancel(apiKey.error.message);
1554
1643
  return { exitCode: exitCodeFor("api_error") };
@@ -1591,7 +1680,10 @@ async function runLoginVerify(input, deps) {
1591
1680
  return writeApiError(deps, session.error);
1592
1681
  }
1593
1682
  const authedClient = deps.createClient(session.data.token);
1594
- const apiKey = await authedClient.apiKeys.create({ label: "CLI" });
1683
+ const apiKey = await authedClient.apiKeys.create({
1684
+ label: "CLI",
1685
+ type: "delegated"
1686
+ });
1595
1687
  if (apiKey.error) {
1596
1688
  return writeApiError(deps, apiKey.error);
1597
1689
  }
@@ -1799,7 +1891,8 @@ async function parseDropOptions(raw) {
1799
1891
  ...raw.path ? { path: raw.path } : {},
1800
1892
  ...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {},
1801
1893
  ...raw.shared ? { domain: import_node.SHARED_POOL } : raw.domain ? { domain: raw.domain } : {},
1802
- ...raw.slug ? { slug: raw.slug } : {}
1894
+ ...raw.slug ? { slug: raw.slug } : {},
1895
+ ...raw.workspace ? { workspace: raw.workspace } : {}
1803
1896
  };
1804
1897
  }
1805
1898
  function parseJsonObject(value, label) {
@@ -2588,6 +2681,59 @@ async function runWhoami(_input, deps) {
2588
2681
  return { exitCode: 0 };
2589
2682
  }
2590
2683
 
2684
+ // src/commands/workspace.ts
2685
+ async function runWorkspaceList(_input, deps) {
2686
+ try {
2687
+ await requireCredential({
2688
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
2689
+ env: deps.env,
2690
+ store: deps.store
2691
+ });
2692
+ } catch {
2693
+ return writeAuthError(deps);
2694
+ }
2695
+ const result = await deps.client.workspaces.list();
2696
+ if (result.error) return writeApiError(deps, result.error);
2697
+ const raw = unwrapListData(result.data);
2698
+ const items = Array.isArray(raw) ? raw : [];
2699
+ if (deps.outputMode === "human") {
2700
+ if (items.length === 0) {
2701
+ writeEmpty(deps, "No workspaces found.", { ok: true, workspaces: [] });
2702
+ } else {
2703
+ for (const ws of items) {
2704
+ const active = ws.isActive ? "* " : " ";
2705
+ deps.stdout(
2706
+ `${active}${ws.slug} ${ws.name} (${ws.kind}, ${ws.role}, ${ws.plan})
2707
+ `
2708
+ );
2709
+ }
2710
+ }
2711
+ } else {
2712
+ writeJson(deps, { ok: true, workspaces: items });
2713
+ }
2714
+ return { exitCode: 0 };
2715
+ }
2716
+ async function runWorkspaceUse(slugOrId, _input, deps) {
2717
+ try {
2718
+ await requireCredential({
2719
+ ...deps.apiKey ? { apiKey: deps.apiKey } : {},
2720
+ env: deps.env,
2721
+ store: deps.store
2722
+ });
2723
+ } catch {
2724
+ return writeAuthError(deps);
2725
+ }
2726
+ const result = await deps.client.workspaces.use(slugOrId);
2727
+ if (result.error) return writeApiError(deps, result.error);
2728
+ const ws = result.data;
2729
+ writeHumanOrJson(
2730
+ deps,
2731
+ success(`Now using workspace: ${ws.name} (${ws.slug})`),
2732
+ { ok: true, workspace: ws }
2733
+ );
2734
+ return { exitCode: 0 };
2735
+ }
2736
+
2591
2737
  // src/context.ts
2592
2738
  var import_node2 = require("@dropthis/node");
2593
2739
  function createContext(input) {
@@ -2796,7 +2942,7 @@ function buildProgram(options = {}) {
2796
2942
  ` ${import_picocolors6.default.cyan("dropthis login")}`,
2797
2943
  ` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
2798
2944
  ].join("\n")
2799
- ).version("0.25.0").configureHelp({
2945
+ ).version(CLI_VERSION).configureHelp({
2800
2946
  subcommandTerm(cmd) {
2801
2947
  const args = cmd.registeredArguments.map((a) => {
2802
2948
  const name = a.name();
@@ -2850,6 +2996,9 @@ ${lines.map((l) => ` ${l}`).join("\n")}
2850
2996
  ).option(
2851
2997
  "--manifest <file>",
2852
2998
  "Publish a multi-file bundle defined in a JSON file (path, content/source_url/content_base64 per file). Cannot combine with a positional input."
2999
+ ).option(
3000
+ "--workspace <slugOrId>",
3001
+ "Target workspace slug or id for this publish (delegated keys only; overrides server-side active workspace for this call)"
2853
3002
  ).option("--url", "Print only the published URL (no JSON envelope)").option(
2854
3003
  "--dry-run",
2855
3004
  "Show what would be published without publishing (JSON; cannot combine with --url)"
@@ -3271,6 +3420,47 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3271
3420
  process.exitCode = result.exitCode;
3272
3421
  }
3273
3422
  );
3423
+ const workspace = program.command("workspace").description(
3424
+ "Manage workspaces. Switch your active workspace (delegated keys only) or list all workspaces you belong to."
3425
+ );
3426
+ workspace.command("list", { isDefault: true }).description("List workspaces you belong to").option("--json", "Force JSON output").action(async (commandOptions) => {
3427
+ const deps = await commandDeps(program, options, store, commandOptions);
3428
+ const result = await runWorkspaceList(commandOptions, deps);
3429
+ process.exitCode = result.exitCode;
3430
+ });
3431
+ workspace.command("use <slugOrId>").description(
3432
+ "Switch your active workspace (server-side, persists on the credential). Delegated keys only \u2014 pinned service keys cannot switch."
3433
+ ).option("--json", "Force JSON output").action(async (slugOrId, commandOptions) => {
3434
+ const deps = await commandDeps(program, options, store, commandOptions);
3435
+ const result = await runWorkspaceUse(slugOrId, commandOptions, deps);
3436
+ process.exitCode = result.exitCode;
3437
+ });
3438
+ const keys = program.command("keys").description(
3439
+ "Mint API keys (delegated login keys or pinned CI service keys)"
3440
+ );
3441
+ keys.command("create").description(
3442
+ "Create an API key. Without --service, mints a delegated account-scoped key (default for login). With --service --workspace <ws>, mints a CI key pinned to that workspace."
3443
+ ).option("--label <label>", "Key label").option(
3444
+ "--service",
3445
+ "Mint a pinned service key for CI/automation (requires --workspace to pin it)"
3446
+ ).option(
3447
+ "--workspace <slugOrId>",
3448
+ "Pin this service key to the given workspace slug or id (only valid with --service)"
3449
+ ).option("--json", "Force JSON output").action(
3450
+ async (commandOptions) => {
3451
+ const deps = await commandDeps(program, options, store, commandOptions);
3452
+ const result = await runKeysCreate(
3453
+ {
3454
+ ...commandOptions.label !== void 0 ? { label: commandOptions.label } : {},
3455
+ type: commandOptions.service ? "service" : "delegated",
3456
+ ...commandOptions.workspace !== void 0 ? { workspace: commandOptions.workspace } : {},
3457
+ ...commandOptions.json !== void 0 ? { json: commandOptions.json } : {}
3458
+ },
3459
+ deps
3460
+ );
3461
+ process.exitCode = result.exitCode;
3462
+ }
3463
+ );
3274
3464
  program.command("login").description("Authenticate with email OTP").option("--email <email>", "Email address").option("--otp <otp>", "One-time passcode").option("--json", "Force JSON output").action(
3275
3465
  async (commandOptions) => {
3276
3466
  if (!commandOptions.email || !commandOptions.otp) {
@@ -3398,7 +3588,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3398
3588
  );
3399
3589
  const result = await runUpgrade(commandOptions, {
3400
3590
  ...deps,
3401
- currentVersion: "0.25.0"
3591
+ currentVersion: CLI_VERSION
3402
3592
  });
3403
3593
  process.exitCode = result.exitCode;
3404
3594
  });
@@ -3509,6 +3699,7 @@ function toDropOptions(options) {
3509
3699
  ...options.shared ? { shared: true } : {},
3510
3700
  ...options.slug ? { slug: options.slug } : {},
3511
3701
  ...options.manifest ? { manifest: options.manifest } : {},
3702
+ ...options.workspace ? { workspace: options.workspace } : {},
3512
3703
  ...options.json !== void 0 ? { json: options.json } : {},
3513
3704
  ...options.quiet !== void 0 ? { quiet: options.quiet } : {},
3514
3705
  ...options.url !== void 0 ? { url: options.url } : {},
@@ -3652,7 +3843,7 @@ var showNotice = shouldShowNotice({
3652
3843
  if (showNotice) {
3653
3844
  const notice = noticeFromCache({
3654
3845
  cache: updateCache,
3655
- currentVersion: "0.25.0"
3846
+ currentVersion: CLI_VERSION
3656
3847
  });
3657
3848
  if (notice) {
3658
3849
  process.stderr.write(`