thinkwork-cli 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +125 -28
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -802,6 +802,7 @@ function registerBootstrapCommand(program2) {
|
|
|
802
802
|
// src/commands/login.ts
|
|
803
803
|
import { execSync as execSync4 } from "child_process";
|
|
804
804
|
import { createInterface as createInterface2 } from "readline";
|
|
805
|
+
import { select, Separator } from "@inquirer/prompts";
|
|
805
806
|
import chalk5 from "chalk";
|
|
806
807
|
|
|
807
808
|
// src/aws-profiles.ts
|
|
@@ -1036,33 +1037,41 @@ function describeType(type) {
|
|
|
1036
1037
|
}
|
|
1037
1038
|
}
|
|
1038
1039
|
async function pickProfile(profiles) {
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
const idx = String(i + 1).padStart(2, " ");
|
|
1043
|
-
console.log(
|
|
1044
|
-
` ${chalk5.cyan(idx)}. ${chalk5.bold(p.name)} ${chalk5.dim(`(${describeType(p.type)})`)}`
|
|
1040
|
+
if (!process.stdin.isTTY) {
|
|
1041
|
+
printError(
|
|
1042
|
+
"The profile picker needs an interactive terminal. Re-run with --keys, --sso, or --profile <name>."
|
|
1045
1043
|
);
|
|
1046
|
-
});
|
|
1047
|
-
const newIdx = profiles.length + 1;
|
|
1048
|
-
const ssoIdx = profiles.length + 2;
|
|
1049
|
-
console.log(
|
|
1050
|
-
` ${chalk5.cyan(String(newIdx).padStart(2, " "))}. Enter new access keys`
|
|
1051
|
-
);
|
|
1052
|
-
console.log(
|
|
1053
|
-
` ${chalk5.cyan(String(ssoIdx).padStart(2, " "))}. Log in via AWS SSO`
|
|
1054
|
-
);
|
|
1055
|
-
console.log("");
|
|
1056
|
-
const answer = await ask(` Pick a profile [1-${ssoIdx}] (Enter to cancel): `);
|
|
1057
|
-
if (!answer) return { kind: "cancel" };
|
|
1058
|
-
const n = Number.parseInt(answer, 10);
|
|
1059
|
-
if (Number.isNaN(n) || n < 1 || n > ssoIdx) {
|
|
1060
|
-
printError(`"${answer}" is not a valid option.`);
|
|
1061
1044
|
return { kind: "cancel" };
|
|
1062
1045
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1046
|
+
const choices = profiles.map((p) => ({
|
|
1047
|
+
name: `${p.name} ${chalk5.dim(`(${describeType(p.type)})`)}`,
|
|
1048
|
+
value: { kind: "existing", name: p.name }
|
|
1049
|
+
}));
|
|
1050
|
+
choices.push(new Separator());
|
|
1051
|
+
choices.push({
|
|
1052
|
+
name: "Enter new access keys",
|
|
1053
|
+
value: { kind: "keys" },
|
|
1054
|
+
description: "Paste an AWS Access Key ID and Secret Access Key; saved to a new profile."
|
|
1055
|
+
});
|
|
1056
|
+
choices.push({
|
|
1057
|
+
name: "Log in via AWS SSO",
|
|
1058
|
+
value: { kind: "sso" },
|
|
1059
|
+
description: "Run `aws sso login` against the configured SSO profile."
|
|
1060
|
+
});
|
|
1061
|
+
try {
|
|
1062
|
+
const picked = await select({
|
|
1063
|
+
message: "Pick an AWS profile for Thinkwork:",
|
|
1064
|
+
choices,
|
|
1065
|
+
loop: false,
|
|
1066
|
+
pageSize: Math.max(profiles.length + 2, 10)
|
|
1067
|
+
});
|
|
1068
|
+
return picked;
|
|
1069
|
+
} catch (err) {
|
|
1070
|
+
if (err instanceof Error && err.name === "ExitPromptError") {
|
|
1071
|
+
return { kind: "cancel" };
|
|
1072
|
+
}
|
|
1073
|
+
throw err;
|
|
1074
|
+
}
|
|
1066
1075
|
}
|
|
1067
1076
|
async function runKeyEntry(targetProfile) {
|
|
1068
1077
|
console.log("");
|
|
@@ -1145,7 +1154,26 @@ function registerLoginCommand(program2) {
|
|
|
1145
1154
|
"--profile <name>",
|
|
1146
1155
|
"AWS profile name to configure (used when entering new keys or SSO)",
|
|
1147
1156
|
"thinkwork"
|
|
1148
|
-
).option("--sso", "Skip the picker and go straight to SSO login").option("--keys", "Skip the picker and go straight to access-key entry").
|
|
1157
|
+
).option("--sso", "Skip the picker and go straight to SSO login").option("--keys", "Skip the picker and go straight to access-key entry").addHelpText(
|
|
1158
|
+
"after",
|
|
1159
|
+
`
|
|
1160
|
+
Examples:
|
|
1161
|
+
# Interactive picker \u2014 lists profiles from ~/.aws, verifies the one you pick,
|
|
1162
|
+
# and saves it as your Thinkwork default.
|
|
1163
|
+
$ thinkwork login
|
|
1164
|
+
|
|
1165
|
+
# Skip the picker, enter fresh access keys into a named profile
|
|
1166
|
+
$ thinkwork login --keys --profile thinkwork
|
|
1167
|
+
|
|
1168
|
+
# Skip the picker, log in via AWS SSO
|
|
1169
|
+
$ thinkwork login --sso --profile work-sso
|
|
1170
|
+
|
|
1171
|
+
After login, commands resolve the AWS profile in this order:
|
|
1172
|
+
1. --profile <name> (per-command override)
|
|
1173
|
+
2. $AWS_PROFILE env var
|
|
1174
|
+
3. defaultProfile from ~/.thinkwork/config.json (set by this command)
|
|
1175
|
+
`
|
|
1176
|
+
).action(async (opts) => {
|
|
1149
1177
|
printHeader("login", opts.profile);
|
|
1150
1178
|
const awsOk = await ensureAwsCli();
|
|
1151
1179
|
if (!awsOk) process.exit(1);
|
|
@@ -1744,7 +1772,30 @@ function printStageDetail(info) {
|
|
|
1744
1772
|
function registerStatusCommand(program2) {
|
|
1745
1773
|
program2.command("status").alias("list").alias("ls").description(
|
|
1746
1774
|
"Show all Thinkwork environments / deployments (AWS + local). Aliases: list, ls"
|
|
1747
|
-
).option("-s, --stage <name>", "Show details for a specific stage").option("--region <region>", "AWS region to scan", "us-east-1").
|
|
1775
|
+
).option("-s, --stage <name>", "Show details for a specific stage").option("--region <region>", "AWS region to scan", "us-east-1").addHelpText(
|
|
1776
|
+
"after",
|
|
1777
|
+
`
|
|
1778
|
+
Examples:
|
|
1779
|
+
# List every deployment in the current AWS account (us-east-1)
|
|
1780
|
+
$ thinkwork list
|
|
1781
|
+
|
|
1782
|
+
# Same thing, tighter verb
|
|
1783
|
+
$ thinkwork ls
|
|
1784
|
+
|
|
1785
|
+
# Deep-dive on one stage (same info but scoped)
|
|
1786
|
+
$ thinkwork list -s dev
|
|
1787
|
+
|
|
1788
|
+
# Scan a different region
|
|
1789
|
+
$ thinkwork list --region us-west-2
|
|
1790
|
+
|
|
1791
|
+
# Use a specific AWS profile for this call only
|
|
1792
|
+
$ thinkwork --profile work-sso list
|
|
1793
|
+
|
|
1794
|
+
Discovers stages by looking for \`thinkwork-<stage>-api-graphql-http\`
|
|
1795
|
+
Lambdas and fans out to API Gateway, AppSync, S3, RDS, ECS, CloudFront,
|
|
1796
|
+
and AgentCore for per-stage detail.
|
|
1797
|
+
`
|
|
1798
|
+
).action(async (opts) => {
|
|
1748
1799
|
const identity = getAwsIdentity();
|
|
1749
1800
|
printHeader("status", opts.stage || "all", identity);
|
|
1750
1801
|
if (!identity) {
|
|
@@ -2342,7 +2393,38 @@ function registerUserCommand(program2) {
|
|
|
2342
2393
|
const user = program2.command("user").description("User-management utilities for a deployed Thinkwork stack");
|
|
2343
2394
|
user.command("invite <email>").description(
|
|
2344
2395
|
"Invite a teammate to a tenant. Creates the Cognito user (Cognito emails a temporary password) and adds them as a tenant member."
|
|
2345
|
-
).requiredOption("-s, --stage <name>", "Deployment stage
|
|
2396
|
+
).requiredOption("-s, --stage <name>", "Deployment stage (e.g. dev, prod)").requiredOption(
|
|
2397
|
+
"--tenant <slug>",
|
|
2398
|
+
"Tenant slug (the URL-safe tenant id, e.g. acme)"
|
|
2399
|
+
).option("--name <name>", "Display name for the invited user").option(
|
|
2400
|
+
"--role <role>",
|
|
2401
|
+
'Tenant member role: "member", "admin", or "owner"',
|
|
2402
|
+
"member"
|
|
2403
|
+
).addHelpText(
|
|
2404
|
+
"after",
|
|
2405
|
+
`
|
|
2406
|
+
Examples:
|
|
2407
|
+
# Invite a teammate as a regular member
|
|
2408
|
+
$ thinkwork user invite alice@example.com --tenant acme -s dev
|
|
2409
|
+
|
|
2410
|
+
# Invite with a display name and admin role
|
|
2411
|
+
$ thinkwork user invite bob@example.com --tenant acme -s dev \\
|
|
2412
|
+
--name "Bob Smith" --role admin
|
|
2413
|
+
|
|
2414
|
+
# Re-inviting someone who's already a member is a no-op (no second email)
|
|
2415
|
+
$ thinkwork user invite alice@example.com --tenant acme -s dev
|
|
2416
|
+
\u26A0 alice@example.com is already a member of "acme" (role: member). No email sent.
|
|
2417
|
+
|
|
2418
|
+
What happens:
|
|
2419
|
+
1. A Cognito user is created (or reused if the email already exists).
|
|
2420
|
+
2. Cognito emails the user a temporary password.
|
|
2421
|
+
3. The user is added to the tenant with the given role.
|
|
2422
|
+
4. On first sign-in they're prompted to set a real password.
|
|
2423
|
+
|
|
2424
|
+
Requires the stack to be deployed (the CLI discovers the API Gateway URL
|
|
2425
|
+
and reads api_auth_secret from terraform.tfvars for the stage).
|
|
2426
|
+
`
|
|
2427
|
+
).action(
|
|
2346
2428
|
async (email, opts) => {
|
|
2347
2429
|
const stageCheck = validateStage(opts.stage);
|
|
2348
2430
|
if (!stageCheck.valid) {
|
|
@@ -2402,9 +2484,24 @@ function registerUserCommand(program2) {
|
|
|
2402
2484
|
);
|
|
2403
2485
|
user.command("reset-password <email>").description(
|
|
2404
2486
|
"Trigger Cognito's forgot-password flow for a user (admin-initiated). Sends them a verification code email."
|
|
2405
|
-
).option("-p, --profile <name>", "AWS profile").requiredOption("-s, --stage <name>", "Deployment stage").option(
|
|
2487
|
+
).option("-p, --profile <name>", "AWS profile").requiredOption("-s, --stage <name>", "Deployment stage (e.g. dev, prod)").option(
|
|
2406
2488
|
"-r, --region <name>",
|
|
2407
2489
|
"AWS region (defaults to AWS CLI default / AWS_REGION)"
|
|
2490
|
+
).addHelpText(
|
|
2491
|
+
"after",
|
|
2492
|
+
`
|
|
2493
|
+
Examples:
|
|
2494
|
+
# Admin-triggered password reset \u2014 works even if the account is locked
|
|
2495
|
+
$ thinkwork user reset-password alice@example.com -s dev
|
|
2496
|
+
|
|
2497
|
+
# Target a specific AWS profile + region
|
|
2498
|
+
$ thinkwork user reset-password alice@example.com -s prod \\
|
|
2499
|
+
--profile thinkwork --region us-east-1
|
|
2500
|
+
|
|
2501
|
+
Cognito emails the user a verification code; they set a new password on
|
|
2502
|
+
next sign-in. Use this instead of \`forgot-password\` when the user is in
|
|
2503
|
+
FORCE_CHANGE_PASSWORD or has been disabled.
|
|
2504
|
+
`
|
|
2408
2505
|
).action(
|
|
2409
2506
|
async (email, opts) => {
|
|
2410
2507
|
const stageCheck = validateStage(opts.stage);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkwork-cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Thinkwork CLI — deploy, manage, and interact with your Thinkwork stack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"prepublishOnly": "npm run build && npm run typecheck"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@inquirer/prompts": "^8.4.1",
|
|
22
23
|
"chalk": "^5.6.2",
|
|
23
24
|
"commander": "^12.0.0",
|
|
24
25
|
"ora": "^9.3.0"
|