@keystrokehq/cli 0.0.154 → 0.0.156

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
@@ -3605,11 +3605,38 @@ function createOrganizationsResource(http, options = {}) {
3605
3605
  }
3606
3606
  };
3607
3607
  }
3608
+ function listSearchParams(options) {
3609
+ const params = {};
3610
+ const projectId = options?.projectId?.trim();
3611
+ if (projectId) params.projectId = projectId;
3612
+ if (options?.admin) params.admin = "true";
3613
+ return Object.keys(params).length > 0 ? params : void 0;
3614
+ }
3615
+ function createAgentsResource(http) {
3616
+ return {
3617
+ async list(options) {
3618
+ try {
3619
+ const data = await http.get("/api/agents", { searchParams: listSearchParams(options) }).json();
3620
+ return AgentSummaryListResponseSchema.parse(data);
3621
+ } catch (error) {
3622
+ throw await toPlatformError(error);
3623
+ }
3624
+ },
3625
+ async get(agentId) {
3626
+ try {
3627
+ const data = await http.get(`/api/agents/${encodeURIComponent(agentId)}`).json();
3628
+ return AgentSummaryDetailResponseSchema.parse(data);
3629
+ } catch (error) {
3630
+ throw await toPlatformError(error);
3631
+ }
3632
+ }
3633
+ };
3634
+ }
3608
3635
  function createProjectsResource(http) {
3609
3636
  return {
3610
- async list() {
3637
+ async list(options) {
3611
3638
  try {
3612
- const data = await http.get("/api/projects").json();
3639
+ const data = await http.get("/api/projects", { searchParams: listSearchParams(options) }).json();
3613
3640
  return ListProjectsResponseSchema.parse(data).projects;
3614
3641
  } catch (error) {
3615
3642
  throw await toPlatformError(error);
@@ -3669,48 +3696,20 @@ function createProjectsResource(http) {
3669
3696
  };
3670
3697
  }
3671
3698
  function createProjectMetricsResource(http) {
3672
- return { async list() {
3699
+ return { async list(options) {
3673
3700
  try {
3674
- const data = await http.get("/api/projects/metrics").json();
3701
+ const data = await http.get("/api/projects/metrics", { searchParams: listSearchParams(options) }).json();
3675
3702
  return ListProjectMetricsResponseSchema.parse(data).metrics;
3676
3703
  } catch (error) {
3677
3704
  throw await toPlatformError(error);
3678
3705
  }
3679
3706
  } };
3680
3707
  }
3681
- function listSearchParams$2(options) {
3682
- const projectId = options?.projectId?.trim();
3683
- return projectId ? { projectId } : void 0;
3684
- }
3685
- function createAgentsResource(http) {
3686
- return {
3687
- async list(options) {
3688
- try {
3689
- const data = await http.get("/api/agents", { searchParams: listSearchParams$2(options) }).json();
3690
- return AgentSummaryListResponseSchema.parse(data);
3691
- } catch (error) {
3692
- throw await toPlatformError(error);
3693
- }
3694
- },
3695
- async get(agentId) {
3696
- try {
3697
- const data = await http.get(`/api/agents/${encodeURIComponent(agentId)}`).json();
3698
- return AgentSummaryDetailResponseSchema.parse(data);
3699
- } catch (error) {
3700
- throw await toPlatformError(error);
3701
- }
3702
- }
3703
- };
3704
- }
3705
- function listSearchParams$1(options) {
3706
- const projectId = options?.projectId?.trim();
3707
- return projectId ? { projectId } : void 0;
3708
- }
3709
3708
  function createWorkflowsResource(http) {
3710
3709
  return {
3711
3710
  async list(options) {
3712
3711
  try {
3713
- const data = await http.get("/api/workflows", { searchParams: listSearchParams$1(options) }).json();
3712
+ const data = await http.get("/api/workflows", { searchParams: listSearchParams(options) }).json();
3714
3713
  return WorkflowSummaryListResponseSchema.parse(data);
3715
3714
  } catch (error) {
3716
3715
  throw await toPlatformError(error);
@@ -3726,10 +3725,6 @@ function createWorkflowsResource(http) {
3726
3725
  }
3727
3726
  };
3728
3727
  }
3729
- function listSearchParams(options) {
3730
- const projectId = options?.projectId?.trim();
3731
- return projectId ? { projectId } : void 0;
3732
- }
3733
3728
  function createSkillsResource(http) {
3734
3729
  return {
3735
3730
  async list(options) {
@@ -3761,7 +3756,9 @@ function createTeamRequestsResource(http) {
3761
3756
  } };
3762
3757
  }
3763
3758
  function createRecentsResource(http) {
3764
- return { async list() {
3759
+ return {
3760
+ /** Always the viewer's own recents, scoped to their project memberships. */
3761
+ async list() {
3765
3762
  try {
3766
3763
  const data = await http.get("/api/recents").json();
3767
3764
  return RecentResourceListResponseSchema.parse(data);
@@ -4010,11 +4007,13 @@ function createHistoryResource(http) {
4010
4007
  /** Runs across projects the current user can access in the active org. */
4011
4008
  async list(filters) {
4012
4009
  try {
4013
- const parsedFilters = filters ? HistoryRunListQuerySchema.parse(filters) : void 0;
4010
+ const { admin, ...queryFilters } = filters ?? {};
4011
+ const parsedFilters = Object.keys(queryFilters).length ? HistoryRunListQuerySchema.parse(queryFilters) : void 0;
4014
4012
  const searchParams = new URLSearchParams();
4015
4013
  if (parsedFilters?.project) searchParams.set("project", parsedFilters.project);
4016
4014
  if (parsedFilters?.status) searchParams.set("status", parsedFilters.status);
4017
4015
  if (parsedFilters?.kind) searchParams.set("kind", parsedFilters.kind);
4016
+ if (admin) searchParams.set("admin", "true");
4018
4017
  const query = searchParams.toString();
4019
4018
  const data = await http.get(query ? `api/history?${query}` : "api/history").json();
4020
4019
  return HistoryRunListResponseSchema.parse(data);
@@ -4677,6 +4676,13 @@ function parseJsonOption(value, flag) {
4677
4676
  }
4678
4677
  }
4679
4678
  //#endregion
4679
+ //#region src/organization/require-admin-role.ts
4680
+ async function requireAdminRole(config) {
4681
+ await ensureActiveOrganization(config);
4682
+ const active = await createCliPlatformClient(config).organizations.getActive();
4683
+ if (!active || active.role !== "owner" && active.role !== "admin") throw new Error("--admin requires org owner or admin");
4684
+ }
4685
+ //#endregion
4680
4686
  //#region src/resolve-project-target.ts
4681
4687
  async function resolveActiveProject(config, platform) {
4682
4688
  const ref = getCliTargetOptions().projectId ?? config.get("activeProjectId");
@@ -4691,12 +4697,16 @@ async function resolveActiveProjectId(config) {
4691
4697
  //#endregion
4692
4698
  //#region src/commands/agent/list.ts
4693
4699
  function registerAgentListCommand(agent) {
4694
- agent.command("list").description("List agents in the active organization").action(() => runCliCommand("List agents failed", async () => {
4700
+ agent.command("list").description("List agents in the active organization").option("--admin", "List all org resources (org owner or admin only)").action((options) => runCliCommand("List agents failed", async () => {
4695
4701
  const config = createCliConfig();
4696
4702
  const client = createCliPlatformClient(config);
4697
4703
  await ensureActiveOrganization(config);
4704
+ if (options.admin) await requireAdminRole(config);
4698
4705
  const projectId = await resolveActiveProjectId(config);
4699
- const result = await client.agents.list(projectId ? { projectId } : void 0);
4706
+ const result = await client.agents.list({
4707
+ ...projectId ? { projectId } : {},
4708
+ ...options.admin ? { admin: true } : {}
4709
+ });
4700
4710
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
4701
4711
  }, void 0, { orgScoped: true }));
4702
4712
  }
@@ -4738,6 +4748,131 @@ function registerAgentCommand(program) {
4738
4748
  registerAgentSessionsCommand(agent);
4739
4749
  }
4740
4750
  //#endregion
4751
+ //#region src/commands/project/run-project.ts
4752
+ async function withActivePlatformClient(config, fn) {
4753
+ const platform = createCliPlatformClient(config);
4754
+ let active = await platform.organizations.getActive();
4755
+ if (!active) active = await selectActiveOrganization(config);
4756
+ platform.setActiveOrganizationId(active.organization.id);
4757
+ await fn(platform);
4758
+ }
4759
+ function writeInactiveDeployHints(projects) {
4760
+ const bin = cliBinaryName();
4761
+ for (const project of projects) {
4762
+ if (project.status !== "inactive") continue;
4763
+ process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin} deploy --project ${formatProjectLabel(project)}\n`);
4764
+ }
4765
+ }
4766
+ async function runProjectList(config, options = {}) {
4767
+ if (options.admin) await requireAdminRole(config);
4768
+ await withActivePlatformClient(config, async (platform) => {
4769
+ const projects = await platform.projects.list(options.admin ? { admin: true } : void 0);
4770
+ process.stdout.write(`${JSON.stringify({ projects }, null, 2)}\n`);
4771
+ if (projects.length === 0) {
4772
+ const bin = cliBinaryName();
4773
+ process.stderr.write(`No projects yet. Create one with: ${bin} project create --name "My project"\n`);
4774
+ return;
4775
+ }
4776
+ writeInactiveDeployHints(projects);
4777
+ });
4778
+ }
4779
+ async function runProjectMetrics(config, options = {}) {
4780
+ if (options.admin) await requireAdminRole(config);
4781
+ await withActivePlatformClient(config, async (platform) => {
4782
+ const metrics = await platform.projectMetrics.list(options.admin ? { admin: true } : void 0);
4783
+ if (options.projectRef === void 0) {
4784
+ process.stdout.write(`${JSON.stringify(metrics, null, 2)}\n`);
4785
+ return;
4786
+ }
4787
+ const project = await resolveProjectRef(platform, options.projectRef);
4788
+ const output = Object.fromEntries(Object.entries(metrics).filter(([projectId]) => projectId === project.id));
4789
+ process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
4790
+ });
4791
+ }
4792
+ async function runProjectDeploymentsList(config, options) {
4793
+ await withActivePlatformClient(config, async (platform) => {
4794
+ const project = await resolveProjectRef(platform, options.projectRef);
4795
+ const deployments = await platform.deployments.listForProject(project.id);
4796
+ process.stdout.write(`${JSON.stringify({ deployments }, null, 2)}\n`);
4797
+ });
4798
+ }
4799
+ async function runProjectCreate(config, input) {
4800
+ await withActivePlatformClient(config, async (platform) => {
4801
+ const project = await platform.projects.create(input);
4802
+ process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
4803
+ writeInactiveDeployHints([project]);
4804
+ });
4805
+ }
4806
+ async function runProjectUpdate(config, input) {
4807
+ await withActivePlatformClient(config, async (platform) => {
4808
+ const { projectId, ...patch } = input;
4809
+ const project = await platform.projects.update(projectId, patch);
4810
+ process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
4811
+ });
4812
+ }
4813
+ async function runProjectDelete(config, projectId) {
4814
+ await withActivePlatformClient(config, async (platform) => {
4815
+ await platform.projects.delete(projectId);
4816
+ process.stdout.write(`${JSON.stringify({ deleted: projectId }, null, 2)}\n`);
4817
+ });
4818
+ }
4819
+ //#endregion
4820
+ //#region src/commands/api-key/run-api-key.ts
4821
+ async function runApiKeyList(config) {
4822
+ await withActivePlatformClient(config, async (platform) => {
4823
+ const apiKeys = await platform.apiKeys.list();
4824
+ process.stdout.write(`${JSON.stringify({ apiKeys }, null, 2)}\n`);
4825
+ });
4826
+ }
4827
+ async function runApiKeyCreate(config, input) {
4828
+ await withActivePlatformClient(config, async (platform) => {
4829
+ const apiKey = await platform.apiKeys.create(input);
4830
+ process.stdout.write(`${JSON.stringify({ apiKey }, null, 2)}\n`);
4831
+ });
4832
+ }
4833
+ async function runApiKeyRevoke(config, apiKeyId) {
4834
+ await withActivePlatformClient(config, async (platform) => {
4835
+ await platform.apiKeys.revoke(apiKeyId);
4836
+ process.stdout.write(`${JSON.stringify({ revoked: apiKeyId }, null, 2)}\n`);
4837
+ });
4838
+ }
4839
+ //#endregion
4840
+ //#region src/commands/api-key/index.ts
4841
+ async function handleApiKeyError(fallback, action) {
4842
+ const config = createCliConfig();
4843
+ try {
4844
+ await action();
4845
+ } catch (error) {
4846
+ process.stderr.write(`${formatCliError(error, fallback, {
4847
+ serverUrl: getPlatformUrl(config),
4848
+ webUrl: getWebUrl(config)
4849
+ })}\n`);
4850
+ process.exitCode = 1;
4851
+ }
4852
+ }
4853
+ function registerApiKeyCommand(program) {
4854
+ const apiKey = program.command("api-key").description("Manage org-scoped platform API keys");
4855
+ apiKey.command("list").description("List API keys in the active organization").action(async () => {
4856
+ const config = createCliConfig();
4857
+ await handleApiKeyError("List API keys failed", async () => {
4858
+ await runApiKeyList(config);
4859
+ });
4860
+ });
4861
+ apiKey.command("create").description("Create an API key in the active organization").requiredOption("--name <name>", "API key name").action(async (options) => {
4862
+ const config = createCliConfig();
4863
+ await handleApiKeyError("Create API key failed", async () => {
4864
+ await runApiKeyCreate(config, { name: options.name });
4865
+ });
4866
+ });
4867
+ apiKey.command("revoke").description("Revoke an API key").argument("<apiKeyId>", "API key id").option("-y, --yes", "Skip confirmation prompt").action(async (apiKeyId, options) => {
4868
+ const config = createCliConfig();
4869
+ await handleApiKeyError("Revoke API key failed", async () => {
4870
+ if (!options.yes) throw new Error("Pass --yes to confirm API key revocation");
4871
+ await runApiKeyRevoke(config, apiKeyId);
4872
+ });
4873
+ });
4874
+ }
4875
+ //#endregion
4741
4876
  //#region src/commands/app/run-app-list.ts
4742
4877
  async function runAppList(client) {
4743
4878
  return client.apps.listCatalog();
@@ -4883,73 +5018,6 @@ function registerConnectCommand(program) {
4883
5018
  }, void 0, resolveConnectTargetOptions()));
4884
5019
  }
4885
5020
  //#endregion
4886
- //#region src/commands/project/run-project.ts
4887
- async function withActivePlatformClient(config, fn) {
4888
- const platform = createCliPlatformClient(config);
4889
- let active = await platform.organizations.getActive();
4890
- if (!active) active = await selectActiveOrganization(config);
4891
- platform.setActiveOrganizationId(active.organization.id);
4892
- await fn(platform);
4893
- }
4894
- function writeInactiveDeployHints(projects) {
4895
- const bin = cliBinaryName();
4896
- for (const project of projects) {
4897
- if (project.status !== "inactive") continue;
4898
- process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin} deploy --project ${formatProjectLabel(project)}\n`);
4899
- }
4900
- }
4901
- async function runProjectList(config) {
4902
- await withActivePlatformClient(config, async (platform) => {
4903
- const projects = await platform.projects.list();
4904
- process.stdout.write(`${JSON.stringify({ projects }, null, 2)}\n`);
4905
- if (projects.length === 0) {
4906
- const bin = cliBinaryName();
4907
- process.stderr.write(`No projects yet. Create one with: ${bin} project create --name "My project"\n`);
4908
- return;
4909
- }
4910
- writeInactiveDeployHints(projects);
4911
- });
4912
- }
4913
- async function runProjectMetrics(config, options) {
4914
- await withActivePlatformClient(config, async (platform) => {
4915
- const metrics = await platform.projectMetrics.list();
4916
- if (options.projectRef === void 0) {
4917
- process.stdout.write(`${JSON.stringify(metrics, null, 2)}\n`);
4918
- return;
4919
- }
4920
- const project = await resolveProjectRef(platform, options.projectRef);
4921
- const output = Object.fromEntries(Object.entries(metrics).filter(([projectId]) => projectId === project.id));
4922
- process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
4923
- });
4924
- }
4925
- async function runProjectDeploymentsList(config, options) {
4926
- await withActivePlatformClient(config, async (platform) => {
4927
- const project = await resolveProjectRef(platform, options.projectRef);
4928
- const deployments = await platform.deployments.listForProject(project.id);
4929
- process.stdout.write(`${JSON.stringify({ deployments }, null, 2)}\n`);
4930
- });
4931
- }
4932
- async function runProjectCreate(config, input) {
4933
- await withActivePlatformClient(config, async (platform) => {
4934
- const project = await platform.projects.create(input);
4935
- process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
4936
- writeInactiveDeployHints([project]);
4937
- });
4938
- }
4939
- async function runProjectUpdate(config, input) {
4940
- await withActivePlatformClient(config, async (platform) => {
4941
- const { projectId, ...patch } = input;
4942
- const project = await platform.projects.update(projectId, patch);
4943
- process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
4944
- });
4945
- }
4946
- async function runProjectDelete(config, projectId) {
4947
- await withActivePlatformClient(config, async (platform) => {
4948
- await platform.projects.delete(projectId);
4949
- process.stdout.write(`${JSON.stringify({ deleted: projectId }, null, 2)}\n`);
4950
- });
4951
- }
4952
- //#endregion
4953
5021
  //#region src/commands/credentials/target-options.ts
4954
5022
  function resolveCredentialsTargetOptions(options = {}) {
4955
5023
  if (options.scopeType === "project") return {
@@ -5839,6 +5907,7 @@ function registerDevCommand(program) {
5839
5907
  //#endregion
5840
5908
  //#region src/commands/history/run-history.ts
5841
5909
  async function runHistoryList(config, filters) {
5910
+ if (filters?.admin) await requireAdminRole(config);
5842
5911
  await withActivePlatformClient(config, async (platform) => {
5843
5912
  const runs = await platform.history.list(filters);
5844
5913
  process.stdout.write(`${JSON.stringify(runs, null, 2)}\n`);
@@ -5860,13 +5929,14 @@ async function runHistoryCancel(config, runId) {
5860
5929
  //#region src/commands/history/index.ts
5861
5930
  function registerHistoryCommand(program) {
5862
5931
  const history = program.command("history").description("List, inspect, and cancel platform run history");
5863
- history.command("list").description("List runs across projects in the active organization").option("--project <id>", "Filter by project id").option("--status <status>", "Filter by status (pending, running, sleeping, waiting_hook, completed, failed, canceled)").option("--kind <kind>", "Filter by kind (workflow or agent)").action(async (options) => {
5932
+ history.command("list").description("List runs across projects in the active organization").option("--project <id>", "Filter by project id").option("--status <status>", "Filter by status (pending, running, sleeping, waiting_hook, completed, failed, canceled)").option("--kind <kind>", "Filter by kind (workflow or agent)").option("--admin", "List all org resources (org owner or admin only)").action(async (options) => {
5864
5933
  const config = createCliConfig();
5865
5934
  try {
5866
5935
  await runHistoryList(config, {
5867
5936
  ...options.project ? { project: options.project } : {},
5868
5937
  ...options.status ? { status: options.status } : {},
5869
- ...options.kind ? { kind: options.kind } : {}
5938
+ ...options.kind ? { kind: options.kind } : {},
5939
+ ...options.admin ? { admin: true } : {}
5870
5940
  });
5871
5941
  } catch (error) {
5872
5942
  process.stderr.write(`${formatCliError(error, "List history failed", {
@@ -6229,6 +6299,15 @@ function registerInitCommand(program) {
6229
6299
  });
6230
6300
  }
6231
6301
  //#endregion
6302
+ //#region src/active-project.ts
6303
+ function clearActiveProjectIfMatches(config, project) {
6304
+ const activeProjectId = config.get("activeProjectId");
6305
+ if (activeProjectId === project.id || activeProjectId === project.slug) config.delete("activeProjectId");
6306
+ }
6307
+ function clearActiveProject(config) {
6308
+ if (config.get("activeProjectId") !== void 0) config.delete("activeProjectId");
6309
+ }
6310
+ //#endregion
6232
6311
  //#region src/commands/organization/run-organization.ts
6233
6312
  async function runOrganizationUpdate(config, input) {
6234
6313
  await withActivePlatformClient(config, async (platform) => {
@@ -6236,30 +6315,312 @@ async function runOrganizationUpdate(config, input) {
6236
6315
  process.stdout.write(`${JSON.stringify({ organization }, null, 2)}\n`);
6237
6316
  });
6238
6317
  }
6318
+ async function runOrganizationMembersList(config) {
6319
+ await withActivePlatformClient(config, async (platform) => {
6320
+ const members = await platform.members.listOrganizationMembers();
6321
+ process.stdout.write(`${JSON.stringify({ members }, null, 2)}\n`);
6322
+ });
6323
+ }
6324
+ async function runOrganizationMembersInvite(config, input) {
6325
+ await withActivePlatformClient(config, async (platform) => {
6326
+ const result = await platform.members.inviteOrganizationMembers(input);
6327
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
6328
+ });
6329
+ }
6330
+ async function runOrganizationMembersRole(config, input) {
6331
+ await withActivePlatformClient(config, async (platform) => {
6332
+ const member = await platform.members.updateOrganizationMember(input.userId, { role: input.role });
6333
+ process.stdout.write(`${JSON.stringify({ member }, null, 2)}\n`);
6334
+ });
6335
+ }
6336
+ async function runOrganizationMembersRemove(config, userId) {
6337
+ await withActivePlatformClient(config, async (platform) => {
6338
+ await platform.members.removeOrganizationMember(userId);
6339
+ process.stdout.write(`${JSON.stringify({ removed: userId }, null, 2)}\n`);
6340
+ });
6341
+ }
6342
+ async function runOrganizationLeave(config) {
6343
+ const platformUrl = getPlatformUrl(config);
6344
+ const token = getAccessToken(platformUrl);
6345
+ if (!token) throw new Error("Not authenticated. Run `keystroke auth login` first.");
6346
+ const user = await getSessionWithBearer(platformUrl, token);
6347
+ if (!user) throw new Error("Session expired. Run `keystroke auth login` again.");
6348
+ await withActivePlatformClient(config, async (platform) => {
6349
+ await platform.members.removeOrganizationMember(user.id);
6350
+ platform.setActiveOrganizationId(null);
6351
+ config.delete("activeOrganizationId");
6352
+ clearActiveProject(config);
6353
+ process.stdout.write(`${JSON.stringify({ left: user.id }, null, 2)}\n`);
6354
+ });
6355
+ }
6239
6356
  //#endregion
6240
6357
  //#region src/commands/organization/index.ts
6358
+ function collectEmails$1(value, previous) {
6359
+ return [...previous, value];
6360
+ }
6361
+ function parseInvitableRole(role) {
6362
+ if (role === "admin" || role === "builder") return role;
6363
+ throw new Error("Role must be admin or builder");
6364
+ }
6365
+ async function handleOrganizationError(fallback, action) {
6366
+ const config = createCliConfig();
6367
+ try {
6368
+ await action();
6369
+ } catch (error) {
6370
+ process.stderr.write(`${formatCliError(error, fallback, {
6371
+ serverUrl: getPlatformUrl(config),
6372
+ webUrl: getWebUrl(config)
6373
+ })}\n`);
6374
+ process.exitCode = 1;
6375
+ }
6376
+ }
6241
6377
  function registerOrganizationCommand(program) {
6242
- 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) => {
6378
+ const organization = program.command("organization").alias("org").description("Manage the active organization");
6379
+ organization.command("update").description("Update the active organization's display name").requiredOption("--name <name>", "Organization display name").action(async (options) => {
6243
6380
  const config = createCliConfig();
6244
- try {
6381
+ await handleOrganizationError("Update organization failed", async () => {
6245
6382
  await runOrganizationUpdate(config, { name: options.name });
6246
- } catch (error) {
6247
- process.stderr.write(`${formatCliError(error, "Update organization failed", {
6248
- serverUrl: getPlatformUrl(config),
6249
- webUrl: getWebUrl(config)
6250
- })}\n`);
6251
- process.exitCode = 1;
6252
- }
6383
+ });
6384
+ });
6385
+ organization.command("leave").description("Leave the active organization").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
6386
+ const config = createCliConfig();
6387
+ await handleOrganizationError("Leave organization failed", async () => {
6388
+ if (!options.yes) throw new Error("Pass --yes to confirm leaving the active organization");
6389
+ await runOrganizationLeave(config);
6390
+ });
6391
+ });
6392
+ const members = organization.command("members").description("Manage organization members in the active organization");
6393
+ members.command("list").description("List members in the active organization").action(async () => {
6394
+ const config = createCliConfig();
6395
+ await handleOrganizationError("List organization members failed", async () => {
6396
+ await runOrganizationMembersList(config);
6397
+ });
6398
+ });
6399
+ members.command("invite").description("Invite people to the active organization").requiredOption("--email <email>", "Email address (repeat for multiple)", collectEmails$1, []).requiredOption("--role <role>", "Member role (admin or builder)").action(async (options) => {
6400
+ const config = createCliConfig();
6401
+ await handleOrganizationError("Invite organization members failed", async () => {
6402
+ await runOrganizationMembersInvite(config, {
6403
+ emails: options.email,
6404
+ role: parseInvitableRole(options.role)
6405
+ });
6406
+ });
6407
+ });
6408
+ members.command("role").description("Update a member's role in the active organization").argument("<userId>", "Member user id").requiredOption("--role <role>", "Member role (admin or builder)").action(async (userId, options) => {
6409
+ const config = createCliConfig();
6410
+ await handleOrganizationError("Update organization member role failed", async () => {
6411
+ await runOrganizationMembersRole(config, {
6412
+ userId,
6413
+ role: parseInvitableRole(options.role)
6414
+ });
6415
+ });
6416
+ });
6417
+ members.command("remove").description("Remove a member from the active organization").argument("<userId>", "Member user id").action(async (userId) => {
6418
+ const config = createCliConfig();
6419
+ await handleOrganizationError("Remove organization member failed", async () => {
6420
+ await runOrganizationMembersRemove(config, userId);
6421
+ });
6422
+ });
6423
+ }
6424
+ //#endregion
6425
+ //#region src/commands/project/run-project-members.ts
6426
+ async function resolveMembersProject(platform, config, projectRef) {
6427
+ const ref = projectRef ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
6428
+ if (!ref) throw new Error("Usage: keystroke --project <slug> project members <command>");
6429
+ return resolveProjectRef(platform, ref);
6430
+ }
6431
+ async function runProjectMembersList(config, options) {
6432
+ await withActivePlatformClient(config, async (platform) => {
6433
+ const project = await resolveMembersProject(platform, config, options.projectRef);
6434
+ const members = await platform.members.listForProject(project.id);
6435
+ process.stdout.write(`${JSON.stringify({ members }, null, 2)}\n`);
6436
+ });
6437
+ }
6438
+ async function runProjectMembersInvite(config, input) {
6439
+ await withActivePlatformClient(config, async (platform) => {
6440
+ const project = await resolveMembersProject(platform, config, input.projectRef);
6441
+ const result = await platform.members.inviteToProject({
6442
+ projectId: project.id,
6443
+ emails: input.emails,
6444
+ role: input.role
6445
+ });
6446
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
6447
+ });
6448
+ }
6449
+ async function runProjectMembersRole(config, input) {
6450
+ await withActivePlatformClient(config, async (platform) => {
6451
+ const project = await resolveMembersProject(platform, config, input.projectRef);
6452
+ const member = await platform.members.updateProjectMember(project.id, input.userId, { role: input.role });
6453
+ process.stdout.write(`${JSON.stringify({ member }, null, 2)}\n`);
6454
+ });
6455
+ }
6456
+ async function runProjectMembersRemove(config, input) {
6457
+ await withActivePlatformClient(config, async (platform) => {
6458
+ const project = await resolveMembersProject(platform, config, input.projectRef);
6459
+ await platform.members.removeProjectMember(project.id, input.userId);
6460
+ process.stdout.write(`${JSON.stringify({ removed: input.userId }, null, 2)}\n`);
6461
+ });
6462
+ }
6463
+ async function runProjectMembersLeave(config, options) {
6464
+ await withActivePlatformClient(config, async (platform) => {
6465
+ const project = await resolveMembersProject(platform, config, options.projectRef);
6466
+ await platform.members.leaveProject(project.id);
6467
+ clearActiveProjectIfMatches(config, project);
6468
+ process.stdout.write(`${JSON.stringify({ left: project.id }, null, 2)}\n`);
6469
+ });
6470
+ }
6471
+ //#endregion
6472
+ //#region src/commands/project/members.ts
6473
+ function collectEmails(value, previous) {
6474
+ return [...previous, value];
6475
+ }
6476
+ function parseProjectRole$1(role) {
6477
+ if (role === "admin" || role === "builder") return role;
6478
+ throw new Error("Role must be admin or builder");
6479
+ }
6480
+ function resolveProjectRefOption$1(config, optionsProject) {
6481
+ return optionsProject ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
6482
+ }
6483
+ function projectRefInput$1(config, optionsProject) {
6484
+ const projectRef = resolveProjectRefOption$1(config, optionsProject);
6485
+ return projectRef ? { projectRef } : {};
6486
+ }
6487
+ async function handleProjectMembersError(fallback, action) {
6488
+ const config = createCliConfig();
6489
+ try {
6490
+ await action();
6491
+ } catch (error) {
6492
+ process.stderr.write(`${formatCliError(error, fallback, {
6493
+ serverUrl: getPlatformUrl(config),
6494
+ webUrl: getWebUrl(config)
6495
+ })}\n`);
6496
+ process.exitCode = 1;
6497
+ }
6498
+ }
6499
+ function registerProjectMembersCommand(project) {
6500
+ const members = project.command("members").description("Manage members for a platform project");
6501
+ members.command("list").description("List members for a project").option("--project <slug>", "Project slug").action(async (options) => {
6502
+ const config = createCliConfig();
6503
+ await handleProjectMembersError("List project members failed", async () => {
6504
+ await runProjectMembersList(config, projectRefInput$1(config, options.project));
6505
+ });
6506
+ });
6507
+ members.command("invite").description("Invite people to a project").option("--project <slug>", "Project slug").requiredOption("--email <email>", "Email address (repeat for multiple)", collectEmails, []).requiredOption("--role <role>", "Project role (admin or builder)").action(async (options) => {
6508
+ const config = createCliConfig();
6509
+ await handleProjectMembersError("Invite project members failed", async () => {
6510
+ await runProjectMembersInvite(config, {
6511
+ ...projectRefInput$1(config, options.project),
6512
+ emails: options.email,
6513
+ role: parseProjectRole$1(options.role)
6514
+ });
6515
+ });
6516
+ });
6517
+ members.command("role").description("Update a project member role").argument("<userId>", "Member user id").option("--project <slug>", "Project slug").requiredOption("--role <role>", "Project role (admin or builder)").action(async (userId, options) => {
6518
+ const config = createCliConfig();
6519
+ await handleProjectMembersError("Update project member role failed", async () => {
6520
+ await runProjectMembersRole(config, {
6521
+ ...projectRefInput$1(config, options.project),
6522
+ userId,
6523
+ role: parseProjectRole$1(options.role)
6524
+ });
6525
+ });
6526
+ });
6527
+ members.command("remove").description("Remove a member from a project").argument("<userId>", "Member user id").option("--project <slug>", "Project slug").action(async (userId, options) => {
6528
+ const config = createCliConfig();
6529
+ await handleProjectMembersError("Remove project member failed", async () => {
6530
+ await runProjectMembersRemove(config, {
6531
+ ...projectRefInput$1(config, options.project),
6532
+ userId
6533
+ });
6534
+ });
6535
+ });
6536
+ members.command("leave").description("Leave a project as the current user").option("--project <slug>", "Project slug").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
6537
+ const config = createCliConfig();
6538
+ await handleProjectMembersError("Leave project failed", async () => {
6539
+ if (!options.yes) throw new Error("Pass --yes to confirm leaving the project");
6540
+ await runProjectMembersLeave(config, projectRefInput$1(config, options.project));
6541
+ });
6542
+ });
6543
+ }
6544
+ //#endregion
6545
+ //#region src/commands/project/run-project-settings.ts
6546
+ async function resolveSettingsProject(platform, config, projectRef) {
6547
+ const ref = projectRef ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
6548
+ if (!ref) throw new Error("Usage: keystroke --project <slug> project settings <command>");
6549
+ return resolveProjectRef(platform, ref);
6550
+ }
6551
+ async function runProjectSettingsGet(config, options) {
6552
+ await withActivePlatformClient(config, async (platform) => {
6553
+ const project = await resolveSettingsProject(platform, config, options.projectRef);
6554
+ const settings = await platform.projectSettings.get(project.id);
6555
+ process.stdout.write(`${JSON.stringify({ settings }, null, 2)}\n`);
6556
+ });
6557
+ }
6558
+ async function runProjectSettingsUpdate(config, input) {
6559
+ await withActivePlatformClient(config, async (platform) => {
6560
+ const project = await resolveSettingsProject(platform, config, input.projectRef);
6561
+ const { projectRef: _projectRef, ...patch } = input;
6562
+ const settings = await platform.projectSettings.update(project.id, patch);
6563
+ process.stdout.write(`${JSON.stringify({ settings }, null, 2)}\n`);
6564
+ });
6565
+ }
6566
+ //#endregion
6567
+ //#region src/commands/project/settings.ts
6568
+ function resolveProjectRefOption(config, optionsProject) {
6569
+ return optionsProject ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
6570
+ }
6571
+ function projectRefInput(config, optionsProject) {
6572
+ const projectRef = resolveProjectRefOption(config, optionsProject);
6573
+ return projectRef ? { projectRef } : {};
6574
+ }
6575
+ function parseProjectRole(role) {
6576
+ if (role === "admin" || role === "builder") return role;
6577
+ throw new Error("Default role must be admin or builder");
6578
+ }
6579
+ function parseInvitePermission(permission) {
6580
+ if (permission === "admin" || permission === "all") return permission;
6581
+ throw new Error("Invite permission must be admin or all");
6582
+ }
6583
+ async function handleProjectSettingsError(fallback, action) {
6584
+ const config = createCliConfig();
6585
+ try {
6586
+ await action();
6587
+ } catch (error) {
6588
+ process.stderr.write(`${formatCliError(error, fallback, {
6589
+ serverUrl: getPlatformUrl(config),
6590
+ webUrl: getWebUrl(config)
6591
+ })}\n`);
6592
+ process.exitCode = 1;
6593
+ }
6594
+ }
6595
+ function registerProjectSettingsCommand(project) {
6596
+ const settings = project.command("settings").description("View and update project governance settings");
6597
+ settings.command("get").description("Get settings for a project").option("--project <slug>", "Project slug").action(async (options) => {
6598
+ const config = createCliConfig();
6599
+ await handleProjectSettingsError("Get project settings failed", async () => {
6600
+ await runProjectSettingsGet(config, projectRefInput(config, options.project));
6601
+ });
6602
+ });
6603
+ settings.command("update").description("Update settings for a project").option("--project <slug>", "Project slug").option("--description <description>", "Project description").option("--default-role <role>", "Default role for new members (admin or builder)").option("--invite-permission <permission>", "Who can invite members (admin or all)").action(async (options) => {
6604
+ const config = createCliConfig();
6605
+ await handleProjectSettingsError("Update project settings failed", async () => {
6606
+ if (options.description === void 0 && options.defaultRole === void 0 && options.invitePermission === void 0) throw new Error("At least one of --description, --default-role, or --invite-permission is required");
6607
+ await runProjectSettingsUpdate(config, {
6608
+ ...projectRefInput(config, options.project),
6609
+ ...options.description !== void 0 ? { description: options.description } : {},
6610
+ ...options.defaultRole !== void 0 ? { defaultRole: parseProjectRole(options.defaultRole) } : {},
6611
+ ...options.invitePermission !== void 0 ? { invitePermission: parseInvitePermission(options.invitePermission) } : {}
6612
+ });
6613
+ });
6253
6614
  });
6254
6615
  }
6255
6616
  //#endregion
6256
6617
  //#region src/commands/project/index.ts
6257
6618
  function registerProjectCommand(program) {
6258
6619
  const project = program.command("project").description("List, create, update, and delete platform projects");
6259
- project.command("list").description("List projects in the active organization").action(async () => {
6620
+ project.command("list").description("List projects in the active organization").option("--admin", "List all org resources (org owner or admin only)").action(async (options) => {
6260
6621
  const config = createCliConfig();
6261
6622
  try {
6262
- await runProjectList(config);
6623
+ await runProjectList(config, { ...options.admin ? { admin: true } : {} });
6263
6624
  } catch (error) {
6264
6625
  process.stderr.write(`${formatCliError(error, "List projects failed", {
6265
6626
  serverUrl: getPlatformUrl(config),
@@ -6268,10 +6629,13 @@ function registerProjectCommand(program) {
6268
6629
  process.exitCode = 1;
6269
6630
  }
6270
6631
  });
6271
- project.command("metrics").description("List rollup metrics for projects in the active organization").option("--project <slug>", "Return metrics for a single project").action(async (options) => {
6632
+ project.command("metrics").description("List rollup metrics for projects in the active organization").option("--project <slug>", "Return metrics for a single project").option("--admin", "List all org resources (org owner or admin only)").action(async (options) => {
6272
6633
  const config = createCliConfig();
6273
6634
  try {
6274
- await runProjectMetrics(config, { ...options.project ? { projectRef: options.project } : {} });
6635
+ await runProjectMetrics(config, {
6636
+ ...options.project ? { projectRef: options.project } : {},
6637
+ ...options.admin ? { admin: true } : {}
6638
+ });
6275
6639
  } catch (error) {
6276
6640
  process.stderr.write(`${formatCliError(error, "List project metrics failed", {
6277
6641
  serverUrl: getPlatformUrl(config),
@@ -6343,6 +6707,8 @@ function registerProjectCommand(program) {
6343
6707
  process.exitCode = 1;
6344
6708
  }
6345
6709
  });
6710
+ registerProjectMembersCommand(project);
6711
+ registerProjectSettingsCommand(project);
6346
6712
  }
6347
6713
  //#endregion
6348
6714
  //#region src/commands/start.ts
@@ -6452,12 +6818,16 @@ function registerTriggerCommand(program) {
6452
6818
  //#endregion
6453
6819
  //#region src/commands/workflow/list.ts
6454
6820
  function registerWorkflowListCommand(workflow) {
6455
- workflow.command("list").description("List workflows in the active organization").action(() => runCliCommand("List workflows failed", async () => {
6821
+ workflow.command("list").description("List workflows in the active organization").option("--admin", "List all org resources (org owner or admin only)").action((options) => runCliCommand("List workflows failed", async () => {
6456
6822
  const config = createCliConfig();
6457
6823
  const client = createCliPlatformClient(config);
6458
6824
  await ensureActiveOrganization(config);
6825
+ if (options.admin) await requireAdminRole(config);
6459
6826
  const projectId = await resolveActiveProjectId(config);
6460
- const result = await client.workflows.list(projectId ? { projectId } : void 0);
6827
+ const result = await client.workflows.list({
6828
+ ...projectId ? { projectId } : {},
6829
+ ...options.admin ? { admin: true } : {}
6830
+ });
6461
6831
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
6462
6832
  }, void 0, { orgScoped: true }));
6463
6833
  }
@@ -6760,12 +7130,16 @@ function registerConfigCommand(program) {
6760
7130
  //#endregion
6761
7131
  //#region src/commands/skill/index.ts
6762
7132
  function registerSkillCommand(program) {
6763
- program.command("skill").description("Inspect platform skills").command("list").description("List skills in the active organization").action(() => runCliCommand("List skills failed", async () => {
7133
+ program.command("skill").description("Inspect platform skills").command("list").description("List skills in the active organization").option("--admin", "List all org resources (org owner or admin only)").action((options) => runCliCommand("List skills failed", async () => {
6764
7134
  const config = createCliConfig();
6765
7135
  const client = createCliPlatformClient(config);
6766
7136
  await ensureActiveOrganization(config);
7137
+ if (options.admin) await requireAdminRole(config);
6767
7138
  const projectId = await resolveActiveProjectId(config);
6768
- const result = await client.skills.list(projectId ? { projectId } : void 0);
7139
+ const result = await client.skills.list({
7140
+ ...projectId ? { projectId } : {},
7141
+ ...options.admin ? { admin: true } : {}
7142
+ });
6769
7143
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
6770
7144
  }, void 0, { orgScoped: true }));
6771
7145
  }
@@ -6845,6 +7219,7 @@ function createProgram() {
6845
7219
  registerConnectCommand(program);
6846
7220
  registerConfigCommand(program);
6847
7221
  registerOrganizationCommand(program);
7222
+ registerApiKeyCommand(program);
6848
7223
  registerProjectCommand(program);
6849
7224
  registerHistoryCommand(program);
6850
7225
  registerCredentialsCommand(program);