@dropthis/cli 0.26.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/dist/cli.cjs CHANGED
@@ -792,6 +792,32 @@ var COMMAND_ANNOTATIONS = {
792
792
  auth: "required",
793
793
  examples: ["dropthis api-keys create --label CI --json"]
794
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
+ },
795
821
  login: {
796
822
  examples: [
797
823
  "dropthis login verify --email user@example.com --otp 123456 --json"
@@ -932,6 +958,9 @@ function spreadData(data) {
932
958
  return data && typeof data === "object" ? data : { data };
933
959
  }
934
960
 
961
+ // src/version.ts
962
+ var CLI_VERSION = true ? "0.27.0" : "0.0.0-dev";
963
+
935
964
  // src/commands/doctor.ts
936
965
  async function runDoctor(_input, deps) {
937
966
  const stored = await deps.store.read();
@@ -942,13 +971,13 @@ async function runDoctor(_input, deps) {
942
971
  const authSource = credential?.source ?? "missing";
943
972
  const storageBackend = stored?.storage ?? "none";
944
973
  const pairs = [
945
- ["Version", "0.26.0"],
974
+ ["Version", CLI_VERSION],
946
975
  ["Auth", authSource],
947
976
  ["Storage", storageBackend]
948
977
  ];
949
978
  writeKv(deps, pairs, {
950
979
  ok: true,
951
- version: "0.26.0",
980
+ version: CLI_VERSION,
952
981
  auth: { source: authSource },
953
982
  storage: { backend: storageBackend }
954
983
  });
@@ -1496,6 +1525,58 @@ async function runDropsDelete(target, input, deps) {
1496
1525
  return { exitCode: 0 };
1497
1526
  }
1498
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
+
1499
1580
  // src/commands/login.ts
1500
1581
  var prompts4 = __toESM(require("@clack/prompts"), 1);
1501
1582
  async function runLoginInteractive(deps) {
@@ -1553,7 +1634,10 @@ async function runLoginInteractive(deps) {
1553
1634
  return { exitCode: exitCodeFor("api_error") };
1554
1635
  }
1555
1636
  const authedClient = deps.createClient(session.data.token);
1556
- const apiKey = await authedClient.apiKeys.create({ label: "CLI" });
1637
+ const apiKey = await authedClient.apiKeys.create({
1638
+ label: "CLI",
1639
+ type: "delegated"
1640
+ });
1557
1641
  if (apiKey.error) {
1558
1642
  prompts4.cancel(apiKey.error.message);
1559
1643
  return { exitCode: exitCodeFor("api_error") };
@@ -1596,7 +1680,10 @@ async function runLoginVerify(input, deps) {
1596
1680
  return writeApiError(deps, session.error);
1597
1681
  }
1598
1682
  const authedClient = deps.createClient(session.data.token);
1599
- const apiKey = await authedClient.apiKeys.create({ label: "CLI" });
1683
+ const apiKey = await authedClient.apiKeys.create({
1684
+ label: "CLI",
1685
+ type: "delegated"
1686
+ });
1600
1687
  if (apiKey.error) {
1601
1688
  return writeApiError(deps, apiKey.error);
1602
1689
  }
@@ -1804,7 +1891,8 @@ async function parseDropOptions(raw) {
1804
1891
  ...raw.path ? { path: raw.path } : {},
1805
1892
  ...raw.idempotencyKey ? { idempotencyKey: raw.idempotencyKey } : {},
1806
1893
  ...raw.shared ? { domain: import_node.SHARED_POOL } : raw.domain ? { domain: raw.domain } : {},
1807
- ...raw.slug ? { slug: raw.slug } : {}
1894
+ ...raw.slug ? { slug: raw.slug } : {},
1895
+ ...raw.workspace ? { workspace: raw.workspace } : {}
1808
1896
  };
1809
1897
  }
1810
1898
  function parseJsonObject(value, label) {
@@ -2593,6 +2681,59 @@ async function runWhoami(_input, deps) {
2593
2681
  return { exitCode: 0 };
2594
2682
  }
2595
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
+
2596
2737
  // src/context.ts
2597
2738
  var import_node2 = require("@dropthis/node");
2598
2739
  function createContext(input) {
@@ -2801,7 +2942,7 @@ function buildProgram(options = {}) {
2801
2942
  ` ${import_picocolors6.default.cyan("dropthis login")}`,
2802
2943
  ` ${import_picocolors6.default.cyan("dropthis publish ./dist")}`
2803
2944
  ].join("\n")
2804
- ).version("0.26.0").configureHelp({
2945
+ ).version(CLI_VERSION).configureHelp({
2805
2946
  subcommandTerm(cmd) {
2806
2947
  const args = cmd.registeredArguments.map((a) => {
2807
2948
  const name = a.name();
@@ -2855,6 +2996,9 @@ ${lines.map((l) => ` ${l}`).join("\n")}
2855
2996
  ).option(
2856
2997
  "--manifest <file>",
2857
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)"
2858
3002
  ).option("--url", "Print only the published URL (no JSON envelope)").option(
2859
3003
  "--dry-run",
2860
3004
  "Show what would be published without publishing (JSON; cannot combine with --url)"
@@ -3276,6 +3420,47 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3276
3420
  process.exitCode = result.exitCode;
3277
3421
  }
3278
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
+ );
3279
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(
3280
3465
  async (commandOptions) => {
3281
3466
  if (!commandOptions.email || !commandOptions.otp) {
@@ -3403,7 +3588,7 @@ ${import_picocolors6.default.bold("Canonical vs raw URLs:")}`,
3403
3588
  );
3404
3589
  const result = await runUpgrade(commandOptions, {
3405
3590
  ...deps,
3406
- currentVersion: "0.26.0"
3591
+ currentVersion: CLI_VERSION
3407
3592
  });
3408
3593
  process.exitCode = result.exitCode;
3409
3594
  });
@@ -3514,6 +3699,7 @@ function toDropOptions(options) {
3514
3699
  ...options.shared ? { shared: true } : {},
3515
3700
  ...options.slug ? { slug: options.slug } : {},
3516
3701
  ...options.manifest ? { manifest: options.manifest } : {},
3702
+ ...options.workspace ? { workspace: options.workspace } : {},
3517
3703
  ...options.json !== void 0 ? { json: options.json } : {},
3518
3704
  ...options.quiet !== void 0 ? { quiet: options.quiet } : {},
3519
3705
  ...options.url !== void 0 ? { url: options.url } : {},
@@ -3657,7 +3843,7 @@ var showNotice = shouldShowNotice({
3657
3843
  if (showNotice) {
3658
3844
  const notice = noticeFromCache({
3659
3845
  cache: updateCache,
3660
- currentVersion: "0.26.0"
3846
+ currentVersion: CLI_VERSION
3661
3847
  });
3662
3848
  if (notice) {
3663
3849
  process.stderr.write(`