@keystrokehq/cli 0.0.130 → 0.0.131

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/index.mjs CHANGED
@@ -2096,7 +2096,10 @@ const CreateOrganizationRequestSchema = object({
2096
2096
  /** Format-only at the wire boundary; reserved-name checks run in platform-database. */
2097
2097
  slug: OrganizationSlugSchema.optional()
2098
2098
  });
2099
- const UpdateOrganizationRequestSchema = object({ slug: ClaimableOrganizationSlugSchema });
2099
+ const UpdateOrganizationRequestSchema = object({
2100
+ name: string().trim().min(1).optional(),
2101
+ slug: ClaimableOrganizationSlugSchema.optional()
2102
+ }).refine((data) => data.name !== void 0 || data.slug !== void 0, { message: "At least one field is required" });
2100
2103
  const CreateOrganizationResponseSchema = object({ organization: UserOrganizationSchema });
2101
2104
  const ListProjectsResponseSchema = object({ projects: array(ProjectSchema) });
2102
2105
  const ProjectListMetricsSchema = object({
@@ -2625,6 +2628,29 @@ const PresignUserAvatarResponseSchema = object({
2625
2628
  uploadUrl: url(),
2626
2629
  storageKey: string().min(1)
2627
2630
  });
2631
+ const OrganizationLogoVariantSchema = _enum(["light", "dark"]);
2632
+ const OrganizationSidebarBrandingSchema = object({
2633
+ customLogoEnabled: boolean(),
2634
+ customLogoExplicitlyDisabled: boolean(),
2635
+ logoLightUrl: url().nullable(),
2636
+ logoDarkUrl: url().nullable(),
2637
+ logoHeightPx: number$1().int().min(14).max(32)
2638
+ });
2639
+ const OrganizationSidebarBrandingPatchSchema = object({
2640
+ customLogoEnabled: boolean().optional(),
2641
+ customLogoExplicitlyDisabled: boolean().optional(),
2642
+ logoLightStorageKey: string().min(1).nullable().optional(),
2643
+ logoDarkStorageKey: string().min(1).nullable().optional(),
2644
+ logoHeightPx: number$1().int().min(14).max(32).optional()
2645
+ }).refine((value) => value.customLogoEnabled !== void 0 || value.customLogoExplicitlyDisabled !== void 0 || value.logoLightStorageKey !== void 0 || value.logoDarkStorageKey !== void 0 || value.logoHeightPx !== void 0, { message: "At least one branding field is required" });
2646
+ const PresignOrgLogoRequestSchema = object({
2647
+ variant: OrganizationLogoVariantSchema,
2648
+ contentType: string().trim().min(1)
2649
+ });
2650
+ const PresignOrgLogoResponseSchema = object({
2651
+ uploadUrl: url(),
2652
+ storageKey: string().min(1)
2653
+ });
2628
2654
  const ProjectArtifactStatusSchema = _enum(["pending", "ready"]);
2629
2655
  const isoDateTime$1 = string().datetime();
2630
2656
  const ProjectArtifactSchema = object({
@@ -5006,16 +5032,18 @@ function createHealthResource(http) {
5006
5032
  }
5007
5033
  } };
5008
5034
  }
5009
- const registry = /* @__PURE__ */ new Map();
5010
- /**
5011
- * Wraps a mock implementation, registering it in the manifest. The returned
5012
- * function is the unchanged implementation — `mock()` only adds bookkeeping.
5013
- */
5014
- function mock(entry, impl) {
5015
- registry.set(`${entry.domain}.${entry.method}`, entry);
5016
- return impl;
5017
- }
5018
5035
  function createOrganizationsResource(http, options = {}) {
5036
+ async function update(input) {
5037
+ const body = UpdateOrganizationRequestSchema.parse(input);
5038
+ try {
5039
+ const data = await http.patch("/api/organizations/active", { json: body }).json();
5040
+ const organization = ActiveOrganizationResponseSchema.parse(data).organization;
5041
+ if (!organization) throw new Error("Active organization was not returned");
5042
+ return organization;
5043
+ } catch (error) {
5044
+ throw await toPlatformError(error);
5045
+ }
5046
+ }
5019
5047
  return {
5020
5048
  async list() {
5021
5049
  try {
@@ -5054,17 +5082,7 @@ function createOrganizationsResource(http, options = {}) {
5054
5082
  throw await toPlatformError(error);
5055
5083
  }
5056
5084
  },
5057
- async update(input) {
5058
- const body = UpdateOrganizationRequestSchema.parse(input);
5059
- try {
5060
- const data = await http.patch("/api/organizations/active", { json: body }).json();
5061
- const organization = ActiveOrganizationResponseSchema.parse(data).organization;
5062
- if (!organization) throw new Error("Active organization was not returned");
5063
- return organization;
5064
- } catch (error) {
5065
- throw await toPlatformError(error);
5066
- }
5067
- },
5085
+ update,
5068
5086
  async create(input) {
5069
5087
  const body = CreateOrganizationRequestSchema.parse(input);
5070
5088
  try {
@@ -5074,20 +5092,6 @@ function createOrganizationsResource(http, options = {}) {
5074
5092
  throw await toPlatformError(error);
5075
5093
  }
5076
5094
  },
5077
- updateProfile: mock({
5078
- domain: "organizations",
5079
- method: "updateProfile",
5080
- plannedEndpoint: "PATCH /api/organizations/active (name)"
5081
- }, async (input) => {
5082
- const name = input.name.trim();
5083
- if (!name) throw new Error("Organization name is required");
5084
- const organizationId = options.getActiveOrganizationId?.()?.trim();
5085
- if (!organizationId) throw new Error("Active organization is required to update profile");
5086
- return {
5087
- id: organizationId,
5088
- name
5089
- };
5090
- }),
5091
5095
  async checkSlug(slug, options = {}) {
5092
5096
  const searchParams = new URLSearchParams({ slug });
5093
5097
  if (options.excludeOrganizationId) searchParams.set("excludeOrganizationId", options.excludeOrganizationId);
@@ -5233,13 +5237,22 @@ function createRecentsResource(http) {
5233
5237
  }
5234
5238
  } };
5235
5239
  }
5240
+ const registry = /* @__PURE__ */ new Map();
5241
+ /**
5242
+ * Wraps a mock implementation, registering it in the manifest. The returned
5243
+ * function is the unchanged implementation — `mock()` only adds bookkeeping.
5244
+ */
5245
+ function mock(entry, impl) {
5246
+ registry.set(`${entry.domain}.${entry.method}`, entry);
5247
+ return impl;
5248
+ }
5236
5249
  const DEFAULT_PROJECT_SETTINGS = {
5237
5250
  description: "",
5238
5251
  defaultRole: "editor",
5239
5252
  invitePermission: "admin"
5240
5253
  };
5241
- const MOCK_STORAGE_KEY$3 = "keystroke:mock-project-settings:v1";
5242
- function getBrowserLocalStorage$3() {
5254
+ const MOCK_STORAGE_KEY$2 = "keystroke:mock-project-settings:v1";
5255
+ function getBrowserLocalStorage$2() {
5243
5256
  if (typeof globalThis !== "object") return null;
5244
5257
  return globalThis.localStorage ?? null;
5245
5258
  }
@@ -5265,10 +5278,10 @@ function mergeProjectSettings(current, patch) {
5265
5278
  });
5266
5279
  }
5267
5280
  function readSettingsStore() {
5268
- const localStorage = getBrowserLocalStorage$3();
5281
+ const localStorage = getBrowserLocalStorage$2();
5269
5282
  if (!localStorage) return {};
5270
5283
  try {
5271
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$3);
5284
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY$2);
5272
5285
  if (!raw) return {};
5273
5286
  const parsed = JSON.parse(raw);
5274
5287
  if (!parsed || typeof parsed !== "object") return {};
@@ -5278,10 +5291,10 @@ function readSettingsStore() {
5278
5291
  }
5279
5292
  }
5280
5293
  function writeSettingsStore(store) {
5281
- const localStorage = getBrowserLocalStorage$3();
5294
+ const localStorage = getBrowserLocalStorage$2();
5282
5295
  if (!localStorage) return;
5283
5296
  try {
5284
- localStorage.setItem(MOCK_STORAGE_KEY$3, JSON.stringify(store));
5297
+ localStorage.setItem(MOCK_STORAGE_KEY$2, JSON.stringify(store));
5285
5298
  } catch {}
5286
5299
  }
5287
5300
  function requireProjectId(projectId) {
@@ -7686,98 +7699,67 @@ function createHistoryResource() {
7686
7699
  }, async (runId) => cancelHistoryRun(runId))
7687
7700
  };
7688
7701
  }
7689
- const MOCK_STORAGE_KEY$2 = "keystroke:mock-organization-sidebar-branding:v1";
7690
- function getBrowserLocalStorage$2() {
7691
- if (typeof globalThis !== "object") return null;
7692
- return globalThis.localStorage ?? null;
7693
- }
7694
- const DEFAULT_ORGANIZATION_SIDEBAR_BRANDING = {
7695
- customSidebarLogoEnabled: false,
7696
- customSidebarLogoExplicitlyDisabled: false,
7697
- sidebarLogoLightDataUrl: null,
7698
- sidebarLogoDarkDataUrl: null,
7699
- sidebarLogoHeightPx: 20
7700
- };
7701
- function normalizeSidebarLogoDataUrl(value) {
7702
- if (typeof value !== "string" || !value.startsWith("data:image/")) return null;
7703
- return value;
7704
- }
7705
- function normalizeCustomSidebarLogoEnabled(value, branding) {
7706
- const hasCustomLogo = Boolean(normalizeSidebarLogoDataUrl(branding.sidebarLogoLightDataUrl) || normalizeSidebarLogoDataUrl(branding.sidebarLogoDarkDataUrl));
7707
- if (branding.customSidebarLogoExplicitlyDisabled === true) return false;
7708
- if (typeof value === "boolean") return value || hasCustomLogo;
7709
- return hasCustomLogo;
7710
- }
7711
- function normalizeSidebarLogoHeightPx(value) {
7712
- if (typeof value !== "number" || !Number.isFinite(value)) return DEFAULT_ORGANIZATION_SIDEBAR_BRANDING.sidebarLogoHeightPx;
7713
- return Math.min(32, Math.max(14, Math.round(value)));
7714
- }
7715
- function normalizeOrganizationSidebarBranding(value) {
7716
- if (!value || typeof value !== "object") return DEFAULT_ORGANIZATION_SIDEBAR_BRANDING;
7717
- const branding = value;
7718
- return {
7719
- customSidebarLogoEnabled: normalizeCustomSidebarLogoEnabled(branding.customSidebarLogoEnabled, branding),
7720
- customSidebarLogoExplicitlyDisabled: branding.customSidebarLogoExplicitlyDisabled === true,
7721
- sidebarLogoLightDataUrl: normalizeSidebarLogoDataUrl(branding.sidebarLogoLightDataUrl),
7722
- sidebarLogoDarkDataUrl: normalizeSidebarLogoDataUrl(branding.sidebarLogoDarkDataUrl),
7723
- sidebarLogoHeightPx: normalizeSidebarLogoHeightPx(branding.sidebarLogoHeightPx)
7724
- };
7725
- }
7726
- function mergeOrganizationSidebarBranding(current, patch) {
7727
- return normalizeOrganizationSidebarBranding({
7728
- ...current,
7729
- ...patch
7730
- });
7731
- }
7732
- function readBrandingStore() {
7733
- const localStorage = getBrowserLocalStorage$2();
7734
- if (!localStorage) return {};
7702
+ async function presignPutAndFinalize(input) {
7703
+ const contentType = input.file.type?.trim() || "application/octet-stream";
7704
+ const uploadFailedMessage = input.uploadFailedMessage ?? "Upload failed";
7735
7705
  try {
7736
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$2);
7737
- if (!raw) return {};
7738
- const parsed = JSON.parse(raw);
7739
- if (!parsed || typeof parsed !== "object") return {};
7740
- return Object.fromEntries(Object.entries(parsed).map(([organizationId, value]) => [organizationId, normalizeOrganizationSidebarBranding(value)]));
7741
- } catch {
7742
- return {};
7706
+ const { uploadUrl, storageKey } = await input.presign(contentType);
7707
+ if (!(await fetch(uploadUrl, {
7708
+ method: "PUT",
7709
+ body: input.file,
7710
+ headers: { "Content-Type": contentType }
7711
+ })).ok) throw new Error(uploadFailedMessage);
7712
+ return await input.finalize(storageKey);
7713
+ } catch (error) {
7714
+ if (error instanceof Error && error.message === uploadFailedMessage) throw error;
7715
+ throw await input.toPlatformError(error);
7743
7716
  }
7744
7717
  }
7745
- function writeBrandingStore(store) {
7746
- const localStorage = getBrowserLocalStorage$2();
7747
- if (!localStorage) return;
7748
- try {
7749
- localStorage.setItem(MOCK_STORAGE_KEY$2, JSON.stringify(store));
7750
- } catch {}
7751
- }
7752
- function resolveOrganizationId(getActiveOrganizationId) {
7753
- const organizationId = getActiveOrganizationId()?.trim();
7754
- if (!organizationId) throw new Error("Organization sidebar branding requires an active organization");
7755
- return organizationId;
7756
- }
7757
- function createOrganizationSidebarBrandingResource(options) {
7718
+ function createOrganizationSidebarBrandingResource(http) {
7719
+ async function presignLogoUpload(variant, contentType) {
7720
+ const body = PresignOrgLogoRequestSchema.parse({
7721
+ variant,
7722
+ contentType
7723
+ });
7724
+ const data = await http.post("/api/organizations/active/branding/logo/presign", { json: body }).json();
7725
+ return PresignOrgLogoResponseSchema.parse(data);
7726
+ }
7758
7727
  return {
7759
- get: mock({
7760
- domain: "organizationSidebarBranding",
7761
- method: "get",
7762
- plannedEndpoint: "GET /api/organizations/active/branding"
7763
- }, async () => {
7764
- const organizationId = resolveOrganizationId(options.getActiveOrganizationId ?? (() => null));
7765
- return readBrandingStore()[organizationId] ?? DEFAULT_ORGANIZATION_SIDEBAR_BRANDING;
7766
- }),
7767
- update: mock({
7768
- domain: "organizationSidebarBranding",
7769
- method: "update",
7770
- plannedEndpoint: "PATCH /api/organizations/active/branding"
7771
- }, async (patch) => {
7772
- const organizationId = resolveOrganizationId(options.getActiveOrganizationId ?? (() => null));
7773
- const store = readBrandingStore();
7774
- const next = mergeOrganizationSidebarBranding(store[organizationId] ?? DEFAULT_ORGANIZATION_SIDEBAR_BRANDING, patch);
7775
- writeBrandingStore({
7776
- ...store,
7777
- [organizationId]: next
7728
+ async get() {
7729
+ try {
7730
+ const data = await http.get("/api/organizations/active/branding").json();
7731
+ return OrganizationSidebarBrandingSchema.parse(data);
7732
+ } catch (error) {
7733
+ throw await toPlatformError(error);
7734
+ }
7735
+ },
7736
+ async uploadLogo(file, variant) {
7737
+ const storageKeyField = variant === "light" ? "logoLightStorageKey" : "logoDarkStorageKey";
7738
+ return presignPutAndFinalize({
7739
+ file,
7740
+ presign: (contentType) => presignLogoUpload(variant, contentType),
7741
+ finalize: (storageKey) => this.update({
7742
+ [storageKeyField]: storageKey,
7743
+ customLogoEnabled: true,
7744
+ customLogoExplicitlyDisabled: false
7745
+ }),
7746
+ uploadFailedMessage: "Logo upload failed",
7747
+ toPlatformError
7778
7748
  });
7779
- return next;
7780
- })
7749
+ },
7750
+ async removeLogo(variant) {
7751
+ const storageKeyField = variant === "light" ? "logoLightStorageKey" : "logoDarkStorageKey";
7752
+ return this.update({ [storageKeyField]: null });
7753
+ },
7754
+ async update(patch) {
7755
+ const body = OrganizationSidebarBrandingPatchSchema.parse(patch);
7756
+ try {
7757
+ const data = await http.patch("/api/organizations/active/branding", { json: body }).json();
7758
+ return OrganizationSidebarBrandingSchema.parse(data);
7759
+ } catch (error) {
7760
+ throw await toPlatformError(error);
7761
+ }
7762
+ }
7781
7763
  };
7782
7764
  }
7783
7765
  const MOCK_STORAGE_KEY$1 = "keystroke:mock-user-preferences:v1";
@@ -7956,19 +7938,13 @@ function createUserAvatarResource(http) {
7956
7938
  }
7957
7939
  },
7958
7940
  async upload(file) {
7959
- const contentType = file.type?.trim() || "application/octet-stream";
7960
- try {
7961
- const { uploadUrl, storageKey } = await presignUpload(contentType);
7962
- if (!(await fetch(uploadUrl, {
7963
- method: "PUT",
7964
- body: file,
7965
- headers: { "Content-Type": contentType }
7966
- })).ok) throw new Error("Avatar upload failed");
7967
- return await this.update({ storageKey });
7968
- } catch (error) {
7969
- if (error instanceof Error && error.message === "Avatar upload failed") throw error;
7970
- throw await toPlatformError(error);
7971
- }
7941
+ return presignPutAndFinalize({
7942
+ file,
7943
+ presign: presignUpload,
7944
+ finalize: (storageKey) => this.update({ storageKey }),
7945
+ uploadFailedMessage: "Avatar upload failed",
7946
+ toPlatformError
7947
+ });
7972
7948
  },
7973
7949
  async remove() {
7974
7950
  return this.update({ storageKey: null });
@@ -8595,7 +8571,7 @@ function createPlatformClient(options) {
8595
8571
  recents: createRecentsResource(http),
8596
8572
  userPreferences: createUserPreferencesResource({ getCurrentUserId: options.getCurrentUserId }),
8597
8573
  userAvatar: createUserAvatarResource(http),
8598
- organizationSidebarBranding: createOrganizationSidebarBrandingResource({ getActiveOrganizationId: () => activeOrganizationId }),
8574
+ organizationSidebarBranding: createOrganizationSidebarBrandingResource(http),
8599
8575
  getActiveOrganizationId: () => activeOrganizationId,
8600
8576
  setActiveOrganizationId
8601
8577
  };
@@ -10198,6 +10174,30 @@ async function runProjectDelete(config, projectId) {
10198
10174
  });
10199
10175
  }
10200
10176
  //#endregion
10177
+ //#region src/commands/organization/run-organization.ts
10178
+ async function runOrganizationUpdate(config, input) {
10179
+ await withActivePlatformClient(config, async (platform) => {
10180
+ const organization = await platform.organizations.update(input);
10181
+ process.stdout.write(`${JSON.stringify({ organization }, null, 2)}\n`);
10182
+ });
10183
+ }
10184
+ //#endregion
10185
+ //#region src/commands/organization/index.ts
10186
+ function registerOrganizationCommand(program) {
10187
+ program.command("organization").description("Manage the active organization").command("update").description("Update the active organization's display name").requiredOption("--name <name>", "Organization display name").action(async (options) => {
10188
+ const config = createCliConfig();
10189
+ try {
10190
+ await runOrganizationUpdate(config, { name: options.name });
10191
+ } catch (error) {
10192
+ process.stderr.write(`${formatCliError(error, "Update organization failed", {
10193
+ serverUrl: getPlatformUrl(config),
10194
+ webUrl: getWebUrl(config)
10195
+ })}\n`);
10196
+ process.exitCode = 1;
10197
+ }
10198
+ });
10199
+ }
10200
+ //#endregion
10201
10201
  //#region src/commands/project/index.ts
10202
10202
  function registerProjectCommand(program) {
10203
10203
  const project = program.command("project").description("List, create, update, and delete platform projects");
@@ -10570,6 +10570,7 @@ function createProgram() {
10570
10570
  registerAuthCommand(program);
10571
10571
  registerConnectCommand(program);
10572
10572
  registerConfigCommand(program);
10573
+ registerOrganizationCommand(program);
10573
10574
  registerProjectCommand(program);
10574
10575
  registerCredentialsCommand(program);
10575
10576
  registerHealthCommand(program);