thinkwork-cli 0.5.1 → 0.5.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/README.md +16 -11
- package/dist/cli.js +57 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ No repo clone required — `thinkwork init` scaffolds all Terraform modules from
|
|
|
90
90
|
|
|
91
91
|
- **AWS Region** — where to deploy (default: us-east-1)
|
|
92
92
|
- **Database engine** — `aurora-serverless` (production) or `rds-postgres` (dev, cheaper)
|
|
93
|
-
- **
|
|
93
|
+
- **Hindsight add-on** — optional y/N (managed AgentCore memory with automatic per-turn retention is always on; Hindsight adds ECS Fargate semantic + entity-graph retrieval alongside it)
|
|
94
94
|
- **Google OAuth** — optional social login for Cognito
|
|
95
95
|
- **Admin UI URL** — callback URL for the admin dashboard
|
|
96
96
|
- **Mobile app scheme** — deep link scheme for the mobile app
|
|
@@ -119,22 +119,27 @@ thinkwork status
|
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
```
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
⬡ dev
|
|
123
|
+
─────────────────────────────────────────
|
|
124
|
+
Source: AWS + local config
|
|
125
|
+
Region: us-east-1
|
|
126
|
+
Account: 123456789012
|
|
127
|
+
Lambda fns: 42
|
|
128
|
+
AgentCore: Active
|
|
129
|
+
Memory: managed (always on)
|
|
130
|
+
Hindsight: healthy
|
|
131
|
+
...
|
|
130
132
|
```
|
|
131
133
|
|
|
132
134
|
URLs are clickable in supported terminals (iTerm2, Windows Terminal, VS Code, etc.).
|
|
133
135
|
|
|
134
|
-
###
|
|
136
|
+
### Enable the Hindsight memory add-on
|
|
137
|
+
|
|
138
|
+
Managed AgentCore memory is always on. To also enable Hindsight (ECS Fargate
|
|
139
|
+
service for semantic + entity-graph retrieval) alongside it:
|
|
135
140
|
|
|
136
141
|
```bash
|
|
137
|
-
thinkwork config set
|
|
142
|
+
thinkwork config set enable-hindsight true -s dev --apply
|
|
138
143
|
```
|
|
139
144
|
|
|
140
145
|
### Deploy a specific tier
|
package/dist/cli.js
CHANGED
|
@@ -534,24 +534,28 @@ function resolveTerraformDir(stage) {
|
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
// src/commands/config.ts
|
|
537
|
-
var VALID_MEMORY_ENGINES = ["managed", "hindsight"];
|
|
538
537
|
function readTfVar(tfvarsPath, key) {
|
|
539
538
|
if (!existsSync3(tfvarsPath)) return null;
|
|
540
539
|
const content = readFileSync2(tfvarsPath, "utf-8");
|
|
541
|
-
const
|
|
542
|
-
|
|
540
|
+
const quoted = content.match(new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, "m"));
|
|
541
|
+
if (quoted) return quoted[1];
|
|
542
|
+
const bare = content.match(new RegExp(`^${key}\\s*=\\s*([^\\s#]+)`, "m"));
|
|
543
|
+
return bare ? bare[1] : null;
|
|
543
544
|
}
|
|
545
|
+
var BARE_KEYS = /* @__PURE__ */ new Set(["enable_hindsight"]);
|
|
544
546
|
function setTfVar(tfvarsPath, key, value) {
|
|
545
547
|
if (!existsSync3(tfvarsPath)) {
|
|
546
548
|
throw new Error(`terraform.tfvars not found at ${tfvarsPath}`);
|
|
547
549
|
}
|
|
548
550
|
let content = readFileSync2(tfvarsPath, "utf-8");
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
551
|
+
const bare = BARE_KEYS.has(key);
|
|
552
|
+
const newLine = bare ? `${key} = ${value}` : `${key} = "${value}"`;
|
|
553
|
+
const existingRegex = new RegExp(`^${key}\\s*=\\s*(?:"[^"]*"|[^\\s#]+)`, "m");
|
|
554
|
+
if (existingRegex.test(content)) {
|
|
555
|
+
content = content.replace(existingRegex, newLine);
|
|
552
556
|
} else {
|
|
553
557
|
content += `
|
|
554
|
-
${
|
|
558
|
+
${newLine}
|
|
555
559
|
`;
|
|
556
560
|
}
|
|
557
561
|
writeFileSync2(tfvarsPath, content);
|
|
@@ -581,7 +585,7 @@ function registerConfigCommand(program2) {
|
|
|
581
585
|
console.log(` ${chalk3.bold("Region:")} ${env.region}`);
|
|
582
586
|
console.log(` ${chalk3.bold("Account:")} ${env.accountId}`);
|
|
583
587
|
console.log(` ${chalk3.bold("Database:")} ${env.databaseEngine}`);
|
|
584
|
-
console.log(` ${chalk3.bold("Memory:")} ${env.
|
|
588
|
+
console.log(` ${chalk3.bold("Memory:")} managed (always on)${env.enableHindsight ? " + hindsight" : ""}`);
|
|
585
589
|
console.log(` ${chalk3.bold("Terraform dir:")} ${env.terraformDir}`);
|
|
586
590
|
console.log(` ${chalk3.bold("Created:")} ${env.createdAt}`);
|
|
587
591
|
console.log(` ${chalk3.bold("Updated:")} ${env.updatedAt}`);
|
|
@@ -622,7 +626,7 @@ function registerConfigCommand(program2) {
|
|
|
622
626
|
console.log(chalk3.bold(" Environments"));
|
|
623
627
|
console.log(chalk3.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
624
628
|
for (const env of envs) {
|
|
625
|
-
const memBadge = env.
|
|
629
|
+
const memBadge = env.enableHindsight ? chalk3.magenta("managed+hindsight") : chalk3.dim("managed");
|
|
626
630
|
const dbBadge = env.databaseEngine === "rds-postgres" ? chalk3.yellow("rds") : chalk3.dim("aurora");
|
|
627
631
|
console.log(
|
|
628
632
|
` ${chalk3.bold.cyan(env.stage.padEnd(16))}${env.region.padEnd(14)}${env.accountId.padEnd(16)}${dbBadge.padEnd(20)}${memBadge}`
|
|
@@ -634,7 +638,7 @@ function registerConfigCommand(program2) {
|
|
|
634
638
|
console.log(` Show details: ${chalk3.cyan("thinkwork config list -s <stage>")}`);
|
|
635
639
|
console.log("");
|
|
636
640
|
});
|
|
637
|
-
config.command("get <key>").description("Get a configuration value (e.g.
|
|
641
|
+
config.command("get <key>").description("Get a configuration value (e.g. enable-hindsight)").requiredOption("-s, --stage <name>", "Deployment stage").action((key, opts) => {
|
|
638
642
|
const stageCheck = validateStage(opts.stage);
|
|
639
643
|
if (!stageCheck.valid) {
|
|
640
644
|
printError(stageCheck.error);
|
|
@@ -655,17 +659,27 @@ function registerConfigCommand(program2) {
|
|
|
655
659
|
printError(stageCheck.error);
|
|
656
660
|
process.exit(1);
|
|
657
661
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
662
|
+
let tfKey = key.replace(/-/g, "_");
|
|
663
|
+
let tfValue = value;
|
|
664
|
+
if (tfKey === "memory_engine") {
|
|
665
|
+
if (value !== "managed" && value !== "hindsight") {
|
|
666
|
+
printError(`Invalid memory engine "${value}". Must be 'managed' or 'hindsight'. Note: memory_engine is deprecated \u2014 use enable_hindsight instead.`);
|
|
667
|
+
process.exit(1);
|
|
668
|
+
}
|
|
669
|
+
printWarning("memory_engine is deprecated \u2014 translating to enable_hindsight. Managed memory is always on.");
|
|
670
|
+
tfKey = "enable_hindsight";
|
|
671
|
+
tfValue = value === "hindsight" ? "true" : "false";
|
|
672
|
+
}
|
|
673
|
+
if (tfKey === "enable_hindsight" && tfValue !== "true" && tfValue !== "false") {
|
|
674
|
+
printError(`Invalid enable_hindsight value "${tfValue}". Must be 'true' or 'false'.`);
|
|
661
675
|
process.exit(1);
|
|
662
676
|
}
|
|
663
677
|
const identity = getAwsIdentity();
|
|
664
678
|
printHeader("config set", opts.stage, identity);
|
|
665
679
|
const tfvarsPath = resolveTfvarsPath(opts.stage);
|
|
666
680
|
const oldValue = readTfVar(tfvarsPath, tfKey);
|
|
667
|
-
setTfVar(tfvarsPath, tfKey,
|
|
668
|
-
console.log(` ${
|
|
681
|
+
setTfVar(tfvarsPath, tfKey, tfValue);
|
|
682
|
+
console.log(` ${tfKey}: ${oldValue ?? "(unset)"} \u2192 ${tfValue}`);
|
|
669
683
|
if (opts.apply) {
|
|
670
684
|
const tfDir = resolveTerraformDir(opts.stage);
|
|
671
685
|
if (!tfDir) {
|
|
@@ -685,9 +699,9 @@ function registerConfigCommand(program2) {
|
|
|
685
699
|
printError(`Deploy failed (exit ${code})`);
|
|
686
700
|
process.exit(code);
|
|
687
701
|
}
|
|
688
|
-
printSuccess(`Configuration applied: ${
|
|
702
|
+
printSuccess(`Configuration applied: ${tfKey} = ${tfValue}`);
|
|
689
703
|
} else {
|
|
690
|
-
printSuccess(`Configuration updated: ${
|
|
704
|
+
printSuccess(`Configuration updated: ${tfKey} = ${tfValue}`);
|
|
691
705
|
printWarning("Run with --apply to deploy the change, or run 'thinkwork deploy' separately.");
|
|
692
706
|
}
|
|
693
707
|
});
|
|
@@ -1027,7 +1041,9 @@ function buildTfvars(config) {
|
|
|
1027
1041
|
`db_password = "${config.db_password}"`,
|
|
1028
1042
|
``,
|
|
1029
1043
|
`# \u2500\u2500 Memory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
1030
|
-
|
|
1044
|
+
`# AgentCore managed memory is always on (automatic retention).`,
|
|
1045
|
+
`# Hindsight is an optional add-on for semantic + graph retrieval.`,
|
|
1046
|
+
`enable_hindsight = ${config.enable_hindsight === "true"}`,
|
|
1031
1047
|
``,
|
|
1032
1048
|
`# \u2500\u2500 Auth \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
1033
1049
|
`api_auth_secret = "${config.api_auth_secret}"`
|
|
@@ -1094,7 +1110,7 @@ function registerInitCommand(program2) {
|
|
|
1094
1110
|
if (opts.defaults) {
|
|
1095
1111
|
config.region = identity.region !== "unknown" ? identity.region : "us-east-1";
|
|
1096
1112
|
config.database_engine = "aurora-serverless";
|
|
1097
|
-
config.
|
|
1113
|
+
config.enable_hindsight = "false";
|
|
1098
1114
|
config.google_oauth_client_id = "";
|
|
1099
1115
|
config.google_oauth_client_secret = "";
|
|
1100
1116
|
config.admin_url = "http://localhost:5174";
|
|
@@ -1108,9 +1124,11 @@ function registerInitCommand(program2) {
|
|
|
1108
1124
|
config.database_engine = await choose("Database engine", ["aurora-serverless", "rds-postgres"], "aurora-serverless");
|
|
1109
1125
|
console.log("");
|
|
1110
1126
|
console.log(chalk5.dim(" \u2500\u2500 Memory \u2500\u2500"));
|
|
1111
|
-
console.log(chalk5.dim(" managed
|
|
1112
|
-
console.log(chalk5.dim("
|
|
1113
|
-
|
|
1127
|
+
console.log(chalk5.dim(" AgentCore managed memory is always on (automatic retention)."));
|
|
1128
|
+
console.log(chalk5.dim(" Hindsight is an optional add-on: ECS Fargate service for"));
|
|
1129
|
+
console.log(chalk5.dim(" semantic + entity-graph retrieval (~$75/mo)."));
|
|
1130
|
+
const hindsightAnswer = await ask2("Enable Hindsight long-term memory add-on? (y/N)", "N");
|
|
1131
|
+
config.enable_hindsight = hindsightAnswer.toLowerCase() === "y" ? "true" : "false";
|
|
1114
1132
|
console.log("");
|
|
1115
1133
|
console.log(chalk5.dim(" \u2500\u2500 Auth \u2500\u2500"));
|
|
1116
1134
|
const useGoogle = await ask2("Enable Google OAuth login? (y/N)", "N");
|
|
@@ -1189,7 +1207,7 @@ variable "region" { type = string; default = "us-east-1" }
|
|
|
1189
1207
|
variable "account_id" { type = string }
|
|
1190
1208
|
variable "db_password" { type = string; sensitive = true }
|
|
1191
1209
|
variable "database_engine" { type = string; default = "aurora-serverless" }
|
|
1192
|
-
variable "
|
|
1210
|
+
variable "enable_hindsight" { type = bool; default = false }
|
|
1193
1211
|
variable "google_oauth_client_id" { type = string; default = "" }
|
|
1194
1212
|
variable "google_oauth_client_secret" { type = string; sensitive = true; default = "" }
|
|
1195
1213
|
variable "pre_signup_lambda_zip" { type = string; default = "" }
|
|
@@ -1209,7 +1227,7 @@ module "thinkwork" {
|
|
|
1209
1227
|
|
|
1210
1228
|
db_password = var.db_password
|
|
1211
1229
|
database_engine = var.database_engine
|
|
1212
|
-
|
|
1230
|
+
enable_hindsight = var.enable_hindsight
|
|
1213
1231
|
google_oauth_client_id = var.google_oauth_client_id
|
|
1214
1232
|
google_oauth_client_secret = var.google_oauth_client_secret
|
|
1215
1233
|
pre_signup_lambda_zip = var.pre_signup_lambda_zip
|
|
@@ -1228,9 +1246,10 @@ output "mobile_client_id" { value = module.thinkwork.mobile_client_id }
|
|
|
1228
1246
|
output "bucket_name" { value = module.thinkwork.bucket_name }
|
|
1229
1247
|
output "db_cluster_endpoint" { value = module.thinkwork.db_cluster_endpoint }
|
|
1230
1248
|
output "db_secret_arn" { value = module.thinkwork.db_secret_arn; sensitive = true }
|
|
1231
|
-
output "ecr_repository_url"
|
|
1232
|
-
output "
|
|
1249
|
+
output "ecr_repository_url" { value = module.thinkwork.ecr_repository_url }
|
|
1250
|
+
output "hindsight_enabled" { value = module.thinkwork.hindsight_enabled }
|
|
1233
1251
|
output "hindsight_endpoint" { value = module.thinkwork.hindsight_endpoint }
|
|
1252
|
+
output "agentcore_memory_id" { value = module.thinkwork.agentcore_memory_id }
|
|
1234
1253
|
`);
|
|
1235
1254
|
}
|
|
1236
1255
|
console.log(` Wrote ${chalk5.cyan(tfDir + "/")}`);
|
|
@@ -1240,7 +1259,7 @@ output "hindsight_endpoint" { value = module.thinkwork.hindsight_endpoint }
|
|
|
1240
1259
|
console.log(` ${chalk5.bold("Region:")} ${config.region}`);
|
|
1241
1260
|
console.log(` ${chalk5.bold("Account:")} ${config.account_id}`);
|
|
1242
1261
|
console.log(` ${chalk5.bold("Database:")} ${config.database_engine}`);
|
|
1243
|
-
console.log(` ${chalk5.bold("Memory:")} ${config.
|
|
1262
|
+
console.log(` ${chalk5.bold("Memory:")} managed (always on)${config.enable_hindsight === "true" ? " + hindsight" : ""}`);
|
|
1244
1263
|
console.log(` ${chalk5.bold("Google OAuth:")} ${config.google_oauth_client_id ? "enabled" : "disabled"}`);
|
|
1245
1264
|
console.log(` ${chalk5.bold("Directory:")} ${tfDir}`);
|
|
1246
1265
|
console.log(chalk5.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -1258,7 +1277,7 @@ output "hindsight_endpoint" { value = module.thinkwork.hindsight_endpoint }
|
|
|
1258
1277
|
accountId: config.account_id,
|
|
1259
1278
|
terraformDir: tfDir,
|
|
1260
1279
|
databaseEngine: config.database_engine,
|
|
1261
|
-
|
|
1280
|
+
enableHindsight: config.enable_hindsight === "true",
|
|
1262
1281
|
createdAt: now,
|
|
1263
1282
|
updatedAt: now
|
|
1264
1283
|
});
|
|
@@ -1332,7 +1351,7 @@ function discoverAwsStages(region) {
|
|
|
1332
1351
|
`ecs describe-services --cluster thinkwork-${stage}-cluster --services thinkwork-${stage}-hindsight --region ${region} --query "services[0].runningCount" --output text 2>/dev/null`
|
|
1333
1352
|
);
|
|
1334
1353
|
if (ecsRaw && ecsRaw !== "None" && ecsRaw !== "0") {
|
|
1335
|
-
info.
|
|
1354
|
+
info.hindsightEnabled = true;
|
|
1336
1355
|
const albRaw = runAws(
|
|
1337
1356
|
`elbv2 describe-load-balancers --region ${region} --query "LoadBalancers[?contains(LoadBalancerName, 'tw-${stage}-hindsight')].DNSName|[0]" --output text`
|
|
1338
1357
|
);
|
|
@@ -1346,7 +1365,7 @@ function discoverAwsStages(region) {
|
|
|
1346
1365
|
}
|
|
1347
1366
|
}
|
|
1348
1367
|
} else {
|
|
1349
|
-
info.
|
|
1368
|
+
info.hindsightEnabled = false;
|
|
1350
1369
|
}
|
|
1351
1370
|
const dbRaw = runAws(
|
|
1352
1371
|
`rds describe-db-clusters --region ${region} --query "DBClusters[?starts_with(DBClusterIdentifier, 'thinkwork-${stage}')].Endpoint|[0]" --output text`
|
|
@@ -1380,8 +1399,9 @@ function printStageDetail(info) {
|
|
|
1380
1399
|
console.log(` ${chalk6.bold("Account:")} ${info.accountId}`);
|
|
1381
1400
|
console.log(` ${chalk6.bold("Lambda fns:")} ${info.lambdaCount || "\u2014"}`);
|
|
1382
1401
|
console.log(` ${chalk6.bold("AgentCore:")} ${info.agentcoreStatus || "unknown"}`);
|
|
1383
|
-
console.log(` ${chalk6.bold("Memory:")}
|
|
1384
|
-
|
|
1402
|
+
console.log(` ${chalk6.bold("Memory:")} managed (always on)`);
|
|
1403
|
+
const hindsightLabel = info.hindsightEnabled === void 0 ? "unknown" : info.hindsightEnabled ? info.hindsightHealth || "running" : "disabled";
|
|
1404
|
+
console.log(` ${chalk6.bold("Hindsight:")} ${hindsightLabel}`);
|
|
1385
1405
|
if (info.bucketName) console.log(` ${chalk6.bold("S3 bucket:")} ${info.bucketName}`);
|
|
1386
1406
|
if (info.dbEndpoint) console.log(` ${chalk6.bold("Database:")} ${info.dbEndpoint}`);
|
|
1387
1407
|
if (info.ecrUrl) console.log(` ${chalk6.bold("ECR:")} ${info.ecrUrl}`);
|
|
@@ -1671,7 +1691,7 @@ function registerMcpCommand(program2) {
|
|
|
1671
1691
|
});
|
|
1672
1692
|
}
|
|
1673
1693
|
|
|
1674
|
-
// src/commands/
|
|
1694
|
+
// src/commands/update.ts
|
|
1675
1695
|
import { execSync as execSync8 } from "child_process";
|
|
1676
1696
|
import chalk8 from "chalk";
|
|
1677
1697
|
function getLatestVersion() {
|
|
@@ -1708,9 +1728,9 @@ function compareVersions(a, b) {
|
|
|
1708
1728
|
}
|
|
1709
1729
|
return 0;
|
|
1710
1730
|
}
|
|
1711
|
-
function
|
|
1712
|
-
program2.command("
|
|
1713
|
-
printHeader("
|
|
1731
|
+
function registerUpdateCommand(program2) {
|
|
1732
|
+
program2.command("update").description("Check for and install CLI updates").option("--check", "Only check for updates, don't install").action(async (opts) => {
|
|
1733
|
+
printHeader("update", "", null);
|
|
1714
1734
|
console.log(` Current version: ${chalk8.bold(VERSION)}`);
|
|
1715
1735
|
const latest = getLatestVersion();
|
|
1716
1736
|
if (!latest) {
|
|
@@ -1780,5 +1800,5 @@ registerStatusCommand(program);
|
|
|
1780
1800
|
registerOutputsCommand(program);
|
|
1781
1801
|
registerConfigCommand(program);
|
|
1782
1802
|
registerMcpCommand(program);
|
|
1783
|
-
|
|
1803
|
+
registerUpdateCommand(program);
|
|
1784
1804
|
program.parse();
|