@keystrokehq/cli 0.0.154 → 0.0.155
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/index.mjs +427 -77
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,31 @@ keystroke auth logout
|
|
|
39
39
|
|
|
40
40
|
Existing commands do not require auth yet. Use `resolveCliAuth()` when adding protected commands.
|
|
41
41
|
|
|
42
|
+
### Platform commands
|
|
43
|
+
|
|
44
|
+
Org-scoped platform commands use `createCliPlatformClient()` and require `keystroke auth login` plus an active organization (`keystroke config use org <slug>` when you belong to more than one).
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
keystroke org update --name "Acme Inc"
|
|
48
|
+
keystroke org members list
|
|
49
|
+
keystroke org members invite --email ada@example.com --role admin
|
|
50
|
+
keystroke org members role <userId> --role builder
|
|
51
|
+
keystroke org members remove <userId>
|
|
52
|
+
keystroke org leave --yes
|
|
53
|
+
keystroke api-key list
|
|
54
|
+
keystroke api-key create --name "CI"
|
|
55
|
+
keystroke api-key revoke <apiKeyId> --yes
|
|
56
|
+
keystroke --project <slug> project members list
|
|
57
|
+
keystroke --project <slug> project members invite --email ada@example.com --role admin
|
|
58
|
+
keystroke --project <slug> project members role <userId> --role builder
|
|
59
|
+
keystroke --project <slug> project members remove <userId>
|
|
60
|
+
keystroke --project <slug> project members leave --yes
|
|
61
|
+
keystroke --project <slug> project settings get
|
|
62
|
+
keystroke --project <slug> project settings update --description "Notes" --default-role builder --invite-permission all
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`organization` is an alias for `org`. List/get-style commands print JSON; mutations set a non-zero exit code on failure.
|
|
66
|
+
|
|
42
67
|
### `trigger`
|
|
43
68
|
|
|
44
69
|
List triggers and resolve webhook URLs after deploy (requires `keystroke auth login`):
|
package/dist/index.mjs
CHANGED
|
@@ -4738,6 +4738,129 @@ function registerAgentCommand(program) {
|
|
|
4738
4738
|
registerAgentSessionsCommand(agent);
|
|
4739
4739
|
}
|
|
4740
4740
|
//#endregion
|
|
4741
|
+
//#region src/commands/project/run-project.ts
|
|
4742
|
+
async function withActivePlatformClient(config, fn) {
|
|
4743
|
+
const platform = createCliPlatformClient(config);
|
|
4744
|
+
let active = await platform.organizations.getActive();
|
|
4745
|
+
if (!active) active = await selectActiveOrganization(config);
|
|
4746
|
+
platform.setActiveOrganizationId(active.organization.id);
|
|
4747
|
+
await fn(platform);
|
|
4748
|
+
}
|
|
4749
|
+
function writeInactiveDeployHints(projects) {
|
|
4750
|
+
const bin = cliBinaryName();
|
|
4751
|
+
for (const project of projects) {
|
|
4752
|
+
if (project.status !== "inactive") continue;
|
|
4753
|
+
process.stderr.write(`Project ${formatProjectLabel(project)} is inactive. Deploy with: ${bin} deploy --project ${formatProjectLabel(project)}\n`);
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4756
|
+
async function runProjectList(config) {
|
|
4757
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4758
|
+
const projects = await platform.projects.list();
|
|
4759
|
+
process.stdout.write(`${JSON.stringify({ projects }, null, 2)}\n`);
|
|
4760
|
+
if (projects.length === 0) {
|
|
4761
|
+
const bin = cliBinaryName();
|
|
4762
|
+
process.stderr.write(`No projects yet. Create one with: ${bin} project create --name "My project"\n`);
|
|
4763
|
+
return;
|
|
4764
|
+
}
|
|
4765
|
+
writeInactiveDeployHints(projects);
|
|
4766
|
+
});
|
|
4767
|
+
}
|
|
4768
|
+
async function runProjectMetrics(config, options) {
|
|
4769
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4770
|
+
const metrics = await platform.projectMetrics.list();
|
|
4771
|
+
if (options.projectRef === void 0) {
|
|
4772
|
+
process.stdout.write(`${JSON.stringify(metrics, null, 2)}\n`);
|
|
4773
|
+
return;
|
|
4774
|
+
}
|
|
4775
|
+
const project = await resolveProjectRef(platform, options.projectRef);
|
|
4776
|
+
const output = Object.fromEntries(Object.entries(metrics).filter(([projectId]) => projectId === project.id));
|
|
4777
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
|
|
4778
|
+
});
|
|
4779
|
+
}
|
|
4780
|
+
async function runProjectDeploymentsList(config, options) {
|
|
4781
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4782
|
+
const project = await resolveProjectRef(platform, options.projectRef);
|
|
4783
|
+
const deployments = await platform.deployments.listForProject(project.id);
|
|
4784
|
+
process.stdout.write(`${JSON.stringify({ deployments }, null, 2)}\n`);
|
|
4785
|
+
});
|
|
4786
|
+
}
|
|
4787
|
+
async function runProjectCreate(config, input) {
|
|
4788
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4789
|
+
const project = await platform.projects.create(input);
|
|
4790
|
+
process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
|
|
4791
|
+
writeInactiveDeployHints([project]);
|
|
4792
|
+
});
|
|
4793
|
+
}
|
|
4794
|
+
async function runProjectUpdate(config, input) {
|
|
4795
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4796
|
+
const { projectId, ...patch } = input;
|
|
4797
|
+
const project = await platform.projects.update(projectId, patch);
|
|
4798
|
+
process.stdout.write(`${JSON.stringify({ project }, null, 2)}\n`);
|
|
4799
|
+
});
|
|
4800
|
+
}
|
|
4801
|
+
async function runProjectDelete(config, projectId) {
|
|
4802
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4803
|
+
await platform.projects.delete(projectId);
|
|
4804
|
+
process.stdout.write(`${JSON.stringify({ deleted: projectId }, null, 2)}\n`);
|
|
4805
|
+
});
|
|
4806
|
+
}
|
|
4807
|
+
//#endregion
|
|
4808
|
+
//#region src/commands/api-key/run-api-key.ts
|
|
4809
|
+
async function runApiKeyList(config) {
|
|
4810
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4811
|
+
const apiKeys = await platform.apiKeys.list();
|
|
4812
|
+
process.stdout.write(`${JSON.stringify({ apiKeys }, null, 2)}\n`);
|
|
4813
|
+
});
|
|
4814
|
+
}
|
|
4815
|
+
async function runApiKeyCreate(config, input) {
|
|
4816
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4817
|
+
const apiKey = await platform.apiKeys.create(input);
|
|
4818
|
+
process.stdout.write(`${JSON.stringify({ apiKey }, null, 2)}\n`);
|
|
4819
|
+
});
|
|
4820
|
+
}
|
|
4821
|
+
async function runApiKeyRevoke(config, apiKeyId) {
|
|
4822
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
4823
|
+
await platform.apiKeys.revoke(apiKeyId);
|
|
4824
|
+
process.stdout.write(`${JSON.stringify({ revoked: apiKeyId }, null, 2)}\n`);
|
|
4825
|
+
});
|
|
4826
|
+
}
|
|
4827
|
+
//#endregion
|
|
4828
|
+
//#region src/commands/api-key/index.ts
|
|
4829
|
+
async function handleApiKeyError(fallback, action) {
|
|
4830
|
+
const config = createCliConfig();
|
|
4831
|
+
try {
|
|
4832
|
+
await action();
|
|
4833
|
+
} catch (error) {
|
|
4834
|
+
process.stderr.write(`${formatCliError(error, fallback, {
|
|
4835
|
+
serverUrl: getPlatformUrl(config),
|
|
4836
|
+
webUrl: getWebUrl(config)
|
|
4837
|
+
})}\n`);
|
|
4838
|
+
process.exitCode = 1;
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4841
|
+
function registerApiKeyCommand(program) {
|
|
4842
|
+
const apiKey = program.command("api-key").description("Manage org-scoped platform API keys");
|
|
4843
|
+
apiKey.command("list").description("List API keys in the active organization").action(async () => {
|
|
4844
|
+
const config = createCliConfig();
|
|
4845
|
+
await handleApiKeyError("List API keys failed", async () => {
|
|
4846
|
+
await runApiKeyList(config);
|
|
4847
|
+
});
|
|
4848
|
+
});
|
|
4849
|
+
apiKey.command("create").description("Create an API key in the active organization").requiredOption("--name <name>", "API key name").action(async (options) => {
|
|
4850
|
+
const config = createCliConfig();
|
|
4851
|
+
await handleApiKeyError("Create API key failed", async () => {
|
|
4852
|
+
await runApiKeyCreate(config, { name: options.name });
|
|
4853
|
+
});
|
|
4854
|
+
});
|
|
4855
|
+
apiKey.command("revoke").description("Revoke an API key").argument("<apiKeyId>", "API key id").option("-y, --yes", "Skip confirmation prompt").action(async (apiKeyId, options) => {
|
|
4856
|
+
const config = createCliConfig();
|
|
4857
|
+
await handleApiKeyError("Revoke API key failed", async () => {
|
|
4858
|
+
if (!options.yes) throw new Error("Pass --yes to confirm API key revocation");
|
|
4859
|
+
await runApiKeyRevoke(config, apiKeyId);
|
|
4860
|
+
});
|
|
4861
|
+
});
|
|
4862
|
+
}
|
|
4863
|
+
//#endregion
|
|
4741
4864
|
//#region src/commands/app/run-app-list.ts
|
|
4742
4865
|
async function runAppList(client) {
|
|
4743
4866
|
return client.apps.listCatalog();
|
|
@@ -4883,73 +5006,6 @@ function registerConnectCommand(program) {
|
|
|
4883
5006
|
}, void 0, resolveConnectTargetOptions()));
|
|
4884
5007
|
}
|
|
4885
5008
|
//#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
5009
|
//#region src/commands/credentials/target-options.ts
|
|
4954
5010
|
function resolveCredentialsTargetOptions(options = {}) {
|
|
4955
5011
|
if (options.scopeType === "project") return {
|
|
@@ -6229,6 +6285,15 @@ function registerInitCommand(program) {
|
|
|
6229
6285
|
});
|
|
6230
6286
|
}
|
|
6231
6287
|
//#endregion
|
|
6288
|
+
//#region src/active-project.ts
|
|
6289
|
+
function clearActiveProjectIfMatches(config, project) {
|
|
6290
|
+
const activeProjectId = config.get("activeProjectId");
|
|
6291
|
+
if (activeProjectId === project.id || activeProjectId === project.slug) config.delete("activeProjectId");
|
|
6292
|
+
}
|
|
6293
|
+
function clearActiveProject(config) {
|
|
6294
|
+
if (config.get("activeProjectId") !== void 0) config.delete("activeProjectId");
|
|
6295
|
+
}
|
|
6296
|
+
//#endregion
|
|
6232
6297
|
//#region src/commands/organization/run-organization.ts
|
|
6233
6298
|
async function runOrganizationUpdate(config, input) {
|
|
6234
6299
|
await withActivePlatformClient(config, async (platform) => {
|
|
@@ -6236,20 +6301,302 @@ async function runOrganizationUpdate(config, input) {
|
|
|
6236
6301
|
process.stdout.write(`${JSON.stringify({ organization }, null, 2)}\n`);
|
|
6237
6302
|
});
|
|
6238
6303
|
}
|
|
6304
|
+
async function runOrganizationMembersList(config) {
|
|
6305
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6306
|
+
const members = await platform.members.listOrganizationMembers();
|
|
6307
|
+
process.stdout.write(`${JSON.stringify({ members }, null, 2)}\n`);
|
|
6308
|
+
});
|
|
6309
|
+
}
|
|
6310
|
+
async function runOrganizationMembersInvite(config, input) {
|
|
6311
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6312
|
+
const result = await platform.members.inviteOrganizationMembers(input);
|
|
6313
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
6314
|
+
});
|
|
6315
|
+
}
|
|
6316
|
+
async function runOrganizationMembersRole(config, input) {
|
|
6317
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6318
|
+
const member = await platform.members.updateOrganizationMember(input.userId, { role: input.role });
|
|
6319
|
+
process.stdout.write(`${JSON.stringify({ member }, null, 2)}\n`);
|
|
6320
|
+
});
|
|
6321
|
+
}
|
|
6322
|
+
async function runOrganizationMembersRemove(config, userId) {
|
|
6323
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6324
|
+
await platform.members.removeOrganizationMember(userId);
|
|
6325
|
+
process.stdout.write(`${JSON.stringify({ removed: userId }, null, 2)}\n`);
|
|
6326
|
+
});
|
|
6327
|
+
}
|
|
6328
|
+
async function runOrganizationLeave(config) {
|
|
6329
|
+
const platformUrl = getPlatformUrl(config);
|
|
6330
|
+
const token = getAccessToken(platformUrl);
|
|
6331
|
+
if (!token) throw new Error("Not authenticated. Run `keystroke auth login` first.");
|
|
6332
|
+
const user = await getSessionWithBearer(platformUrl, token);
|
|
6333
|
+
if (!user) throw new Error("Session expired. Run `keystroke auth login` again.");
|
|
6334
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6335
|
+
await platform.members.removeOrganizationMember(user.id);
|
|
6336
|
+
platform.setActiveOrganizationId(null);
|
|
6337
|
+
config.delete("activeOrganizationId");
|
|
6338
|
+
clearActiveProject(config);
|
|
6339
|
+
process.stdout.write(`${JSON.stringify({ left: user.id }, null, 2)}\n`);
|
|
6340
|
+
});
|
|
6341
|
+
}
|
|
6239
6342
|
//#endregion
|
|
6240
6343
|
//#region src/commands/organization/index.ts
|
|
6344
|
+
function collectEmails$1(value, previous) {
|
|
6345
|
+
return [...previous, value];
|
|
6346
|
+
}
|
|
6347
|
+
function parseInvitableRole(role) {
|
|
6348
|
+
if (role === "admin" || role === "builder") return role;
|
|
6349
|
+
throw new Error("Role must be admin or builder");
|
|
6350
|
+
}
|
|
6351
|
+
async function handleOrganizationError(fallback, action) {
|
|
6352
|
+
const config = createCliConfig();
|
|
6353
|
+
try {
|
|
6354
|
+
await action();
|
|
6355
|
+
} catch (error) {
|
|
6356
|
+
process.stderr.write(`${formatCliError(error, fallback, {
|
|
6357
|
+
serverUrl: getPlatformUrl(config),
|
|
6358
|
+
webUrl: getWebUrl(config)
|
|
6359
|
+
})}\n`);
|
|
6360
|
+
process.exitCode = 1;
|
|
6361
|
+
}
|
|
6362
|
+
}
|
|
6241
6363
|
function registerOrganizationCommand(program) {
|
|
6242
|
-
program.command("organization").
|
|
6364
|
+
const organization = program.command("organization").alias("org").description("Manage the active organization");
|
|
6365
|
+
organization.command("update").description("Update the active organization's display name").requiredOption("--name <name>", "Organization display name").action(async (options) => {
|
|
6243
6366
|
const config = createCliConfig();
|
|
6244
|
-
|
|
6367
|
+
await handleOrganizationError("Update organization failed", async () => {
|
|
6245
6368
|
await runOrganizationUpdate(config, { name: options.name });
|
|
6246
|
-
}
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6369
|
+
});
|
|
6370
|
+
});
|
|
6371
|
+
organization.command("leave").description("Leave the active organization").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
|
|
6372
|
+
const config = createCliConfig();
|
|
6373
|
+
await handleOrganizationError("Leave organization failed", async () => {
|
|
6374
|
+
if (!options.yes) throw new Error("Pass --yes to confirm leaving the active organization");
|
|
6375
|
+
await runOrganizationLeave(config);
|
|
6376
|
+
});
|
|
6377
|
+
});
|
|
6378
|
+
const members = organization.command("members").description("Manage organization members in the active organization");
|
|
6379
|
+
members.command("list").description("List members in the active organization").action(async () => {
|
|
6380
|
+
const config = createCliConfig();
|
|
6381
|
+
await handleOrganizationError("List organization members failed", async () => {
|
|
6382
|
+
await runOrganizationMembersList(config);
|
|
6383
|
+
});
|
|
6384
|
+
});
|
|
6385
|
+
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) => {
|
|
6386
|
+
const config = createCliConfig();
|
|
6387
|
+
await handleOrganizationError("Invite organization members failed", async () => {
|
|
6388
|
+
await runOrganizationMembersInvite(config, {
|
|
6389
|
+
emails: options.email,
|
|
6390
|
+
role: parseInvitableRole(options.role)
|
|
6391
|
+
});
|
|
6392
|
+
});
|
|
6393
|
+
});
|
|
6394
|
+
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) => {
|
|
6395
|
+
const config = createCliConfig();
|
|
6396
|
+
await handleOrganizationError("Update organization member role failed", async () => {
|
|
6397
|
+
await runOrganizationMembersRole(config, {
|
|
6398
|
+
userId,
|
|
6399
|
+
role: parseInvitableRole(options.role)
|
|
6400
|
+
});
|
|
6401
|
+
});
|
|
6402
|
+
});
|
|
6403
|
+
members.command("remove").description("Remove a member from the active organization").argument("<userId>", "Member user id").action(async (userId) => {
|
|
6404
|
+
const config = createCliConfig();
|
|
6405
|
+
await handleOrganizationError("Remove organization member failed", async () => {
|
|
6406
|
+
await runOrganizationMembersRemove(config, userId);
|
|
6407
|
+
});
|
|
6408
|
+
});
|
|
6409
|
+
}
|
|
6410
|
+
//#endregion
|
|
6411
|
+
//#region src/commands/project/run-project-members.ts
|
|
6412
|
+
async function resolveMembersProject(platform, config, projectRef) {
|
|
6413
|
+
const ref = projectRef ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
6414
|
+
if (!ref) throw new Error("Usage: keystroke --project <slug> project members <command>");
|
|
6415
|
+
return resolveProjectRef(platform, ref);
|
|
6416
|
+
}
|
|
6417
|
+
async function runProjectMembersList(config, options) {
|
|
6418
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6419
|
+
const project = await resolveMembersProject(platform, config, options.projectRef);
|
|
6420
|
+
const members = await platform.members.listForProject(project.id);
|
|
6421
|
+
process.stdout.write(`${JSON.stringify({ members }, null, 2)}\n`);
|
|
6422
|
+
});
|
|
6423
|
+
}
|
|
6424
|
+
async function runProjectMembersInvite(config, input) {
|
|
6425
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6426
|
+
const project = await resolveMembersProject(platform, config, input.projectRef);
|
|
6427
|
+
const result = await platform.members.inviteToProject({
|
|
6428
|
+
projectId: project.id,
|
|
6429
|
+
emails: input.emails,
|
|
6430
|
+
role: input.role
|
|
6431
|
+
});
|
|
6432
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
6433
|
+
});
|
|
6434
|
+
}
|
|
6435
|
+
async function runProjectMembersRole(config, input) {
|
|
6436
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6437
|
+
const project = await resolveMembersProject(platform, config, input.projectRef);
|
|
6438
|
+
const member = await platform.members.updateProjectMember(project.id, input.userId, { role: input.role });
|
|
6439
|
+
process.stdout.write(`${JSON.stringify({ member }, null, 2)}\n`);
|
|
6440
|
+
});
|
|
6441
|
+
}
|
|
6442
|
+
async function runProjectMembersRemove(config, input) {
|
|
6443
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6444
|
+
const project = await resolveMembersProject(platform, config, input.projectRef);
|
|
6445
|
+
await platform.members.removeProjectMember(project.id, input.userId);
|
|
6446
|
+
process.stdout.write(`${JSON.stringify({ removed: input.userId }, null, 2)}\n`);
|
|
6447
|
+
});
|
|
6448
|
+
}
|
|
6449
|
+
async function runProjectMembersLeave(config, options) {
|
|
6450
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6451
|
+
const project = await resolveMembersProject(platform, config, options.projectRef);
|
|
6452
|
+
await platform.members.leaveProject(project.id);
|
|
6453
|
+
clearActiveProjectIfMatches(config, project);
|
|
6454
|
+
process.stdout.write(`${JSON.stringify({ left: project.id }, null, 2)}\n`);
|
|
6455
|
+
});
|
|
6456
|
+
}
|
|
6457
|
+
//#endregion
|
|
6458
|
+
//#region src/commands/project/members.ts
|
|
6459
|
+
function collectEmails(value, previous) {
|
|
6460
|
+
return [...previous, value];
|
|
6461
|
+
}
|
|
6462
|
+
function parseProjectRole$1(role) {
|
|
6463
|
+
if (role === "admin" || role === "builder") return role;
|
|
6464
|
+
throw new Error("Role must be admin or builder");
|
|
6465
|
+
}
|
|
6466
|
+
function resolveProjectRefOption$1(config, optionsProject) {
|
|
6467
|
+
return optionsProject ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
6468
|
+
}
|
|
6469
|
+
function projectRefInput$1(config, optionsProject) {
|
|
6470
|
+
const projectRef = resolveProjectRefOption$1(config, optionsProject);
|
|
6471
|
+
return projectRef ? { projectRef } : {};
|
|
6472
|
+
}
|
|
6473
|
+
async function handleProjectMembersError(fallback, action) {
|
|
6474
|
+
const config = createCliConfig();
|
|
6475
|
+
try {
|
|
6476
|
+
await action();
|
|
6477
|
+
} catch (error) {
|
|
6478
|
+
process.stderr.write(`${formatCliError(error, fallback, {
|
|
6479
|
+
serverUrl: getPlatformUrl(config),
|
|
6480
|
+
webUrl: getWebUrl(config)
|
|
6481
|
+
})}\n`);
|
|
6482
|
+
process.exitCode = 1;
|
|
6483
|
+
}
|
|
6484
|
+
}
|
|
6485
|
+
function registerProjectMembersCommand(project) {
|
|
6486
|
+
const members = project.command("members").description("Manage members for a platform project");
|
|
6487
|
+
members.command("list").description("List members for a project").option("--project <slug>", "Project slug").action(async (options) => {
|
|
6488
|
+
const config = createCliConfig();
|
|
6489
|
+
await handleProjectMembersError("List project members failed", async () => {
|
|
6490
|
+
await runProjectMembersList(config, projectRefInput$1(config, options.project));
|
|
6491
|
+
});
|
|
6492
|
+
});
|
|
6493
|
+
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) => {
|
|
6494
|
+
const config = createCliConfig();
|
|
6495
|
+
await handleProjectMembersError("Invite project members failed", async () => {
|
|
6496
|
+
await runProjectMembersInvite(config, {
|
|
6497
|
+
...projectRefInput$1(config, options.project),
|
|
6498
|
+
emails: options.email,
|
|
6499
|
+
role: parseProjectRole$1(options.role)
|
|
6500
|
+
});
|
|
6501
|
+
});
|
|
6502
|
+
});
|
|
6503
|
+
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) => {
|
|
6504
|
+
const config = createCliConfig();
|
|
6505
|
+
await handleProjectMembersError("Update project member role failed", async () => {
|
|
6506
|
+
await runProjectMembersRole(config, {
|
|
6507
|
+
...projectRefInput$1(config, options.project),
|
|
6508
|
+
userId,
|
|
6509
|
+
role: parseProjectRole$1(options.role)
|
|
6510
|
+
});
|
|
6511
|
+
});
|
|
6512
|
+
});
|
|
6513
|
+
members.command("remove").description("Remove a member from a project").argument("<userId>", "Member user id").option("--project <slug>", "Project slug").action(async (userId, options) => {
|
|
6514
|
+
const config = createCliConfig();
|
|
6515
|
+
await handleProjectMembersError("Remove project member failed", async () => {
|
|
6516
|
+
await runProjectMembersRemove(config, {
|
|
6517
|
+
...projectRefInput$1(config, options.project),
|
|
6518
|
+
userId
|
|
6519
|
+
});
|
|
6520
|
+
});
|
|
6521
|
+
});
|
|
6522
|
+
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) => {
|
|
6523
|
+
const config = createCliConfig();
|
|
6524
|
+
await handleProjectMembersError("Leave project failed", async () => {
|
|
6525
|
+
if (!options.yes) throw new Error("Pass --yes to confirm leaving the project");
|
|
6526
|
+
await runProjectMembersLeave(config, projectRefInput$1(config, options.project));
|
|
6527
|
+
});
|
|
6528
|
+
});
|
|
6529
|
+
}
|
|
6530
|
+
//#endregion
|
|
6531
|
+
//#region src/commands/project/run-project-settings.ts
|
|
6532
|
+
async function resolveSettingsProject(platform, config, projectRef) {
|
|
6533
|
+
const ref = projectRef ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
6534
|
+
if (!ref) throw new Error("Usage: keystroke --project <slug> project settings <command>");
|
|
6535
|
+
return resolveProjectRef(platform, ref);
|
|
6536
|
+
}
|
|
6537
|
+
async function runProjectSettingsGet(config, options) {
|
|
6538
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6539
|
+
const project = await resolveSettingsProject(platform, config, options.projectRef);
|
|
6540
|
+
const settings = await platform.projectSettings.get(project.id);
|
|
6541
|
+
process.stdout.write(`${JSON.stringify({ settings }, null, 2)}\n`);
|
|
6542
|
+
});
|
|
6543
|
+
}
|
|
6544
|
+
async function runProjectSettingsUpdate(config, input) {
|
|
6545
|
+
await withActivePlatformClient(config, async (platform) => {
|
|
6546
|
+
const project = await resolveSettingsProject(platform, config, input.projectRef);
|
|
6547
|
+
const { projectRef: _projectRef, ...patch } = input;
|
|
6548
|
+
const settings = await platform.projectSettings.update(project.id, patch);
|
|
6549
|
+
process.stdout.write(`${JSON.stringify({ settings }, null, 2)}\n`);
|
|
6550
|
+
});
|
|
6551
|
+
}
|
|
6552
|
+
//#endregion
|
|
6553
|
+
//#region src/commands/project/settings.ts
|
|
6554
|
+
function resolveProjectRefOption(config, optionsProject) {
|
|
6555
|
+
return optionsProject ?? getCliTargetOptions().projectId ?? config.get("activeProjectId");
|
|
6556
|
+
}
|
|
6557
|
+
function projectRefInput(config, optionsProject) {
|
|
6558
|
+
const projectRef = resolveProjectRefOption(config, optionsProject);
|
|
6559
|
+
return projectRef ? { projectRef } : {};
|
|
6560
|
+
}
|
|
6561
|
+
function parseProjectRole(role) {
|
|
6562
|
+
if (role === "admin" || role === "builder") return role;
|
|
6563
|
+
throw new Error("Default role must be admin or builder");
|
|
6564
|
+
}
|
|
6565
|
+
function parseInvitePermission(permission) {
|
|
6566
|
+
if (permission === "admin" || permission === "all") return permission;
|
|
6567
|
+
throw new Error("Invite permission must be admin or all");
|
|
6568
|
+
}
|
|
6569
|
+
async function handleProjectSettingsError(fallback, action) {
|
|
6570
|
+
const config = createCliConfig();
|
|
6571
|
+
try {
|
|
6572
|
+
await action();
|
|
6573
|
+
} catch (error) {
|
|
6574
|
+
process.stderr.write(`${formatCliError(error, fallback, {
|
|
6575
|
+
serverUrl: getPlatformUrl(config),
|
|
6576
|
+
webUrl: getWebUrl(config)
|
|
6577
|
+
})}\n`);
|
|
6578
|
+
process.exitCode = 1;
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6581
|
+
function registerProjectSettingsCommand(project) {
|
|
6582
|
+
const settings = project.command("settings").description("View and update project governance settings");
|
|
6583
|
+
settings.command("get").description("Get settings for a project").option("--project <slug>", "Project slug").action(async (options) => {
|
|
6584
|
+
const config = createCliConfig();
|
|
6585
|
+
await handleProjectSettingsError("Get project settings failed", async () => {
|
|
6586
|
+
await runProjectSettingsGet(config, projectRefInput(config, options.project));
|
|
6587
|
+
});
|
|
6588
|
+
});
|
|
6589
|
+
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) => {
|
|
6590
|
+
const config = createCliConfig();
|
|
6591
|
+
await handleProjectSettingsError("Update project settings failed", async () => {
|
|
6592
|
+
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");
|
|
6593
|
+
await runProjectSettingsUpdate(config, {
|
|
6594
|
+
...projectRefInput(config, options.project),
|
|
6595
|
+
...options.description !== void 0 ? { description: options.description } : {},
|
|
6596
|
+
...options.defaultRole !== void 0 ? { defaultRole: parseProjectRole(options.defaultRole) } : {},
|
|
6597
|
+
...options.invitePermission !== void 0 ? { invitePermission: parseInvitePermission(options.invitePermission) } : {}
|
|
6598
|
+
});
|
|
6599
|
+
});
|
|
6253
6600
|
});
|
|
6254
6601
|
}
|
|
6255
6602
|
//#endregion
|
|
@@ -6271,7 +6618,7 @@ function registerProjectCommand(program) {
|
|
|
6271
6618
|
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) => {
|
|
6272
6619
|
const config = createCliConfig();
|
|
6273
6620
|
try {
|
|
6274
|
-
await runProjectMetrics(config,
|
|
6621
|
+
await runProjectMetrics(config, options.project ? { projectRef: options.project } : {});
|
|
6275
6622
|
} catch (error) {
|
|
6276
6623
|
process.stderr.write(`${formatCliError(error, "List project metrics failed", {
|
|
6277
6624
|
serverUrl: getPlatformUrl(config),
|
|
@@ -6343,6 +6690,8 @@ function registerProjectCommand(program) {
|
|
|
6343
6690
|
process.exitCode = 1;
|
|
6344
6691
|
}
|
|
6345
6692
|
});
|
|
6693
|
+
registerProjectMembersCommand(project);
|
|
6694
|
+
registerProjectSettingsCommand(project);
|
|
6346
6695
|
}
|
|
6347
6696
|
//#endregion
|
|
6348
6697
|
//#region src/commands/start.ts
|
|
@@ -6845,6 +7194,7 @@ function createProgram() {
|
|
|
6845
7194
|
registerConnectCommand(program);
|
|
6846
7195
|
registerConfigCommand(program);
|
|
6847
7196
|
registerOrganizationCommand(program);
|
|
7197
|
+
registerApiKeyCommand(program);
|
|
6848
7198
|
registerProjectCommand(program);
|
|
6849
7199
|
registerHistoryCommand(program);
|
|
6850
7200
|
registerCredentialsCommand(program);
|