@keystrokehq/cli 0.0.130 → 0.0.132

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({
@@ -2644,6 +2670,16 @@ const CompleteProjectArtifactResponseSchema = object({
2644
2670
  artifact: ProjectArtifactSchema,
2645
2671
  project: ProjectSchema
2646
2672
  });
2673
+ const ListProjectDeploymentsResponseSchema = object({ deployments: array(object({
2674
+ id: string(),
2675
+ projectId: string(),
2676
+ version: number$1().int().positive(),
2677
+ deployedBy: string().nullable(),
2678
+ deployedByEmail: string().optional(),
2679
+ deployedByAvatarUrl: string().optional(),
2680
+ createdAt: isoDateTime$1,
2681
+ active: boolean()
2682
+ })) });
2647
2683
  const optionalCount = number$1().int().nonnegative().nullable().optional();
2648
2684
  const optionalTimestamp = string().nullable().optional();
2649
2685
  const AgentSummarySchema = object({
@@ -4953,6 +4989,16 @@ function createArtifactsResource(http) {
4953
4989
  }
4954
4990
  };
4955
4991
  }
4992
+ function createDeploymentsResource(http) {
4993
+ return { async listForProject(projectId) {
4994
+ try {
4995
+ const data = await http.get(`/api/projects/${encodeURIComponent(projectId)}/deployments`).json();
4996
+ return ListProjectDeploymentsResponseSchema.parse(data).deployments;
4997
+ } catch (error) {
4998
+ throw await toPlatformError(error);
4999
+ }
5000
+ } };
5001
+ }
4956
5002
  function createGatewayAttachmentsResource(http) {
4957
5003
  const projectPrefix = (projectId) => `/api/projects/${encodeURIComponent(projectId)}/gateways/slack/attachments`;
4958
5004
  return {
@@ -5006,16 +5052,18 @@ function createHealthResource(http) {
5006
5052
  }
5007
5053
  } };
5008
5054
  }
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
5055
  function createOrganizationsResource(http, options = {}) {
5056
+ async function update(input) {
5057
+ const body = UpdateOrganizationRequestSchema.parse(input);
5058
+ try {
5059
+ const data = await http.patch("/api/organizations/active", { json: body }).json();
5060
+ const organization = ActiveOrganizationResponseSchema.parse(data).organization;
5061
+ if (!organization) throw new Error("Active organization was not returned");
5062
+ return organization;
5063
+ } catch (error) {
5064
+ throw await toPlatformError(error);
5065
+ }
5066
+ }
5019
5067
  return {
5020
5068
  async list() {
5021
5069
  try {
@@ -5054,17 +5102,7 @@ function createOrganizationsResource(http, options = {}) {
5054
5102
  throw await toPlatformError(error);
5055
5103
  }
5056
5104
  },
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
- },
5105
+ update,
5068
5106
  async create(input) {
5069
5107
  const body = CreateOrganizationRequestSchema.parse(input);
5070
5108
  try {
@@ -5074,20 +5112,6 @@ function createOrganizationsResource(http, options = {}) {
5074
5112
  throw await toPlatformError(error);
5075
5113
  }
5076
5114
  },
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
5115
  async checkSlug(slug, options = {}) {
5092
5116
  const searchParams = new URLSearchParams({ slug });
5093
5117
  if (options.excludeOrganizationId) searchParams.set("excludeOrganizationId", options.excludeOrganizationId);
@@ -5233,13 +5257,22 @@ function createRecentsResource(http) {
5233
5257
  }
5234
5258
  } };
5235
5259
  }
5260
+ const registry = /* @__PURE__ */ new Map();
5261
+ /**
5262
+ * Wraps a mock implementation, registering it in the manifest. The returned
5263
+ * function is the unchanged implementation — `mock()` only adds bookkeeping.
5264
+ */
5265
+ function mock(entry, impl) {
5266
+ registry.set(`${entry.domain}.${entry.method}`, entry);
5267
+ return impl;
5268
+ }
5236
5269
  const DEFAULT_PROJECT_SETTINGS = {
5237
5270
  description: "",
5238
5271
  defaultRole: "editor",
5239
5272
  invitePermission: "admin"
5240
5273
  };
5241
- const MOCK_STORAGE_KEY$3 = "keystroke:mock-project-settings:v1";
5242
- function getBrowserLocalStorage$3() {
5274
+ const MOCK_STORAGE_KEY$2 = "keystroke:mock-project-settings:v1";
5275
+ function getBrowserLocalStorage$2() {
5243
5276
  if (typeof globalThis !== "object") return null;
5244
5277
  return globalThis.localStorage ?? null;
5245
5278
  }
@@ -5265,10 +5298,10 @@ function mergeProjectSettings(current, patch) {
5265
5298
  });
5266
5299
  }
5267
5300
  function readSettingsStore() {
5268
- const localStorage = getBrowserLocalStorage$3();
5301
+ const localStorage = getBrowserLocalStorage$2();
5269
5302
  if (!localStorage) return {};
5270
5303
  try {
5271
- const raw = localStorage.getItem(MOCK_STORAGE_KEY$3);
5304
+ const raw = localStorage.getItem(MOCK_STORAGE_KEY$2);
5272
5305
  if (!raw) return {};
5273
5306
  const parsed = JSON.parse(raw);
5274
5307
  if (!parsed || typeof parsed !== "object") return {};
@@ -5278,10 +5311,10 @@ function readSettingsStore() {
5278
5311
  }
5279
5312
  }
5280
5313
  function writeSettingsStore(store) {
5281
- const localStorage = getBrowserLocalStorage$3();
5314
+ const localStorage = getBrowserLocalStorage$2();
5282
5315
  if (!localStorage) return;
5283
5316
  try {
5284
- localStorage.setItem(MOCK_STORAGE_KEY$3, JSON.stringify(store));
5317
+ localStorage.setItem(MOCK_STORAGE_KEY$2, JSON.stringify(store));
5285
5318
  } catch {}
5286
5319
  }
5287
5320
  function requireProjectId(projectId) {
@@ -6761,27 +6794,6 @@ const workflowSeed = [{
6761
6794
  stepCount: 4,
6762
6795
  lastRunAt: "2026-05-31T16:40:00Z"
6763
6796
  }];
6764
- const deploymentSeed = [{
6765
- id: "deployment-v002",
6766
- projectId: "project_personal_repo",
6767
- version: "v0.0.2",
6768
- commit: "0842e21",
6769
- commitSha: "0842e21",
6770
- deployedBy: "Dallin Bentley",
6771
- deployedByEmail: "dallin@keystroke.ai",
6772
- createdAt: "2026-04-20T15:44:00Z",
6773
- active: true
6774
- }, {
6775
- id: "deployment-v001",
6776
- projectId: "project_personal_repo",
6777
- version: "v0.0.1",
6778
- commit: "5aeb762",
6779
- commitSha: "5aeb762",
6780
- deployedBy: "Dallin Bentley",
6781
- deployedByEmail: "dallin@keystroke.ai",
6782
- createdAt: "2026-04-18T15:44:00Z",
6783
- active: false
6784
- }];
6785
6797
  /** Review personas for mocked project members and API key authors (not org membership). */
6786
6798
  const mockPersonaSeed = [
6787
6799
  {
@@ -6970,18 +6982,6 @@ function maskSecretPreview(value) {
6970
6982
  if (trimmed.length <= 4) return "•".repeat(Math.max(trimmed.length, 4));
6971
6983
  return `${"•".repeat(Math.min(trimmed.length - 4, 20))}${trimmed.slice(-4)}`;
6972
6984
  }
6973
- function createDeploymentsResource() {
6974
- return { listForProject: mock({
6975
- domain: "deployments",
6976
- method: "listForProject",
6977
- plannedEndpoint: "GET /api/projects/:id/deployments"
6978
- }, async (projectId) => {
6979
- return deploymentSeed.map((deployment) => ({
6980
- ...deployment,
6981
- projectId
6982
- }));
6983
- }) };
6984
- }
6985
6985
  const projectMembersStore = /* @__PURE__ */ new Map();
6986
6986
  function getProjectMembers(projectId) {
6987
6987
  let members = projectMembersStore.get(projectId);
@@ -7686,98 +7686,67 @@ function createHistoryResource() {
7686
7686
  }, async (runId) => cancelHistoryRun(runId))
7687
7687
  };
7688
7688
  }
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 {};
7689
+ async function presignPutAndFinalize(input) {
7690
+ const contentType = input.file.type?.trim() || "application/octet-stream";
7691
+ const uploadFailedMessage = input.uploadFailedMessage ?? "Upload failed";
7735
7692
  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 {};
7693
+ const { uploadUrl, storageKey } = await input.presign(contentType);
7694
+ if (!(await fetch(uploadUrl, {
7695
+ method: "PUT",
7696
+ body: input.file,
7697
+ headers: { "Content-Type": contentType }
7698
+ })).ok) throw new Error(uploadFailedMessage);
7699
+ return await input.finalize(storageKey);
7700
+ } catch (error) {
7701
+ if (error instanceof Error && error.message === uploadFailedMessage) throw error;
7702
+ throw await input.toPlatformError(error);
7743
7703
  }
7744
7704
  }
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) {
7705
+ function createOrganizationSidebarBrandingResource(http) {
7706
+ async function presignLogoUpload(variant, contentType) {
7707
+ const body = PresignOrgLogoRequestSchema.parse({
7708
+ variant,
7709
+ contentType
7710
+ });
7711
+ const data = await http.post("/api/organizations/active/branding/logo/presign", { json: body }).json();
7712
+ return PresignOrgLogoResponseSchema.parse(data);
7713
+ }
7758
7714
  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
7715
+ async get() {
7716
+ try {
7717
+ const data = await http.get("/api/organizations/active/branding").json();
7718
+ return OrganizationSidebarBrandingSchema.parse(data);
7719
+ } catch (error) {
7720
+ throw await toPlatformError(error);
7721
+ }
7722
+ },
7723
+ async uploadLogo(file, variant) {
7724
+ const storageKeyField = variant === "light" ? "logoLightStorageKey" : "logoDarkStorageKey";
7725
+ return presignPutAndFinalize({
7726
+ file,
7727
+ presign: (contentType) => presignLogoUpload(variant, contentType),
7728
+ finalize: (storageKey) => this.update({
7729
+ [storageKeyField]: storageKey,
7730
+ customLogoEnabled: true,
7731
+ customLogoExplicitlyDisabled: false
7732
+ }),
7733
+ uploadFailedMessage: "Logo upload failed",
7734
+ toPlatformError
7778
7735
  });
7779
- return next;
7780
- })
7736
+ },
7737
+ async removeLogo(variant) {
7738
+ const storageKeyField = variant === "light" ? "logoLightStorageKey" : "logoDarkStorageKey";
7739
+ return this.update({ [storageKeyField]: null });
7740
+ },
7741
+ async update(patch) {
7742
+ const body = OrganizationSidebarBrandingPatchSchema.parse(patch);
7743
+ try {
7744
+ const data = await http.patch("/api/organizations/active/branding", { json: body }).json();
7745
+ return OrganizationSidebarBrandingSchema.parse(data);
7746
+ } catch (error) {
7747
+ throw await toPlatformError(error);
7748
+ }
7749
+ }
7781
7750
  };
7782
7751
  }
7783
7752
  const MOCK_STORAGE_KEY$1 = "keystroke:mock-user-preferences:v1";
@@ -7956,19 +7925,13 @@ function createUserAvatarResource(http) {
7956
7925
  }
7957
7926
  },
7958
7927
  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
- }
7928
+ return presignPutAndFinalize({
7929
+ file,
7930
+ presign: presignUpload,
7931
+ finalize: (storageKey) => this.update({ storageKey }),
7932
+ uploadFailedMessage: "Avatar upload failed",
7933
+ toPlatformError
7934
+ });
7972
7935
  },
7973
7936
  async remove() {
7974
7937
  return this.update({ storageKey: null });
@@ -8584,7 +8547,7 @@ function createPlatformClient(options) {
8584
8547
  apps: createAppsResource(),
8585
8548
  credentials: createCredentialsResource(),
8586
8549
  history: createHistoryResource(),
8587
- deployments: createDeploymentsResource(),
8550
+ deployments: createDeploymentsResource(http),
8588
8551
  gatewayAttachments: createGatewayAttachmentsResource(http),
8589
8552
  projectMetrics: createProjectMetricsResource(http),
8590
8553
  projectFiles: createProjectFilesResource(http),
@@ -8595,7 +8558,7 @@ function createPlatformClient(options) {
8595
8558
  recents: createRecentsResource(http),
8596
8559
  userPreferences: createUserPreferencesResource({ getCurrentUserId: options.getCurrentUserId }),
8597
8560
  userAvatar: createUserAvatarResource(http),
8598
- organizationSidebarBranding: createOrganizationSidebarBrandingResource({ getActiveOrganizationId: () => activeOrganizationId }),
8561
+ organizationSidebarBranding: createOrganizationSidebarBrandingResource(http),
8599
8562
  getActiveOrganizationId: () => activeOrganizationId,
8600
8563
  setActiveOrganizationId
8601
8564
  };
@@ -10177,6 +10140,12 @@ async function runProjectMetrics(config, options) {
10177
10140
  process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
10178
10141
  });
10179
10142
  }
10143
+ async function runProjectDeploymentsList(config, options) {
10144
+ await withActivePlatformClient(config, async (platform) => {
10145
+ const deployments = await platform.deployments.listForProject(options.projectId);
10146
+ process.stdout.write(`${JSON.stringify({ deployments }, null, 2)}\n`);
10147
+ });
10148
+ }
10180
10149
  async function runProjectCreate(config, input) {
10181
10150
  await withActivePlatformClient(config, async (platform) => {
10182
10151
  const project = await platform.projects.create(input);
@@ -10198,6 +10167,30 @@ async function runProjectDelete(config, projectId) {
10198
10167
  });
10199
10168
  }
10200
10169
  //#endregion
10170
+ //#region src/commands/organization/run-organization.ts
10171
+ async function runOrganizationUpdate(config, input) {
10172
+ await withActivePlatformClient(config, async (platform) => {
10173
+ const organization = await platform.organizations.update(input);
10174
+ process.stdout.write(`${JSON.stringify({ organization }, null, 2)}\n`);
10175
+ });
10176
+ }
10177
+ //#endregion
10178
+ //#region src/commands/organization/index.ts
10179
+ function registerOrganizationCommand(program) {
10180
+ 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) => {
10181
+ const config = createCliConfig();
10182
+ try {
10183
+ await runOrganizationUpdate(config, { name: options.name });
10184
+ } catch (error) {
10185
+ process.stderr.write(`${formatCliError(error, "Update organization failed", {
10186
+ serverUrl: getPlatformUrl(config),
10187
+ webUrl: getWebUrl(config)
10188
+ })}\n`);
10189
+ process.exitCode = 1;
10190
+ }
10191
+ });
10192
+ }
10193
+ //#endregion
10201
10194
  //#region src/commands/project/index.ts
10202
10195
  function registerProjectCommand(program) {
10203
10196
  const project = program.command("project").description("List, create, update, and delete platform projects");
@@ -10225,6 +10218,20 @@ function registerProjectCommand(program) {
10225
10218
  process.exitCode = 1;
10226
10219
  }
10227
10220
  });
10221
+ project.command("deployments").description("View deployment history for platform projects").command("list").description("List deployment history for a project").option("--project <id>", "Project ID").action(async (options) => {
10222
+ const config = createCliConfig();
10223
+ try {
10224
+ const projectId = options.project ?? resolveActiveProjectId(config);
10225
+ if (!projectId) throw new Error("Usage: keystroke project deployments list --project <id>");
10226
+ await runProjectDeploymentsList(config, { projectId });
10227
+ } catch (error) {
10228
+ process.stderr.write(`${formatCliError(error, "List deployments failed", {
10229
+ serverUrl: getPlatformUrl(config),
10230
+ webUrl: getWebUrl(config)
10231
+ })}\n`);
10232
+ process.exitCode = 1;
10233
+ }
10234
+ });
10228
10235
  project.command("create").description("Create a platform project in the active organization").requiredOption("--name <name>", "Project name").option("--description <description>", "Project description").action(async (options) => {
10229
10236
  const config = createCliConfig();
10230
10237
  try {
@@ -10570,6 +10577,7 @@ function createProgram() {
10570
10577
  registerAuthCommand(program);
10571
10578
  registerConnectCommand(program);
10572
10579
  registerConfigCommand(program);
10580
+ registerOrganizationCommand(program);
10573
10581
  registerProjectCommand(program);
10574
10582
  registerCredentialsCommand(program);
10575
10583
  registerHealthCommand(program);