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.
Files changed (3) hide show
  1. package/README.md +16 -11
  2. package/dist/cli.js +57 -37
  3. 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
- - **Memory engine** — `managed` (built-in) or `hindsight` (ECS Fargate with semantic + graph retrieval)
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
- Environments
123
- ──────────────────────────────────────────────────────────────────────
124
- Stage Source Lambdas AgentCore Memory URLs
125
- ──────────────────────────────────────────────────────────────────────
126
- ● dev aws+cli 42 active hindsight ✓ API: https://ho7oy...
127
- WS: dcrs2r...
128
- Mem: http://tw-dev...
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
- ### Switch memory engine
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 memory-engine hindsight -s dev --apply
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 match = content.match(new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, "m"));
542
- return match ? match[1] : null;
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 regex = new RegExp(`^(${key}\\s*=\\s*)"[^"]*"`, "m");
550
- if (regex.test(content)) {
551
- content = content.replace(regex, `$1"${value}"`);
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
- ${key} = "${value}"
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.memoryEngine}`);
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.memoryEngine === "hindsight" ? chalk3.magenta("hindsight") : chalk3.dim("managed");
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. memory-engine)").requiredOption("-s, --stage <name>", "Deployment stage").action((key, opts) => {
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
- const tfKey = key.replace(/-/g, "_");
659
- if (tfKey === "memory_engine" && !VALID_MEMORY_ENGINES.includes(value)) {
660
- printError(`Invalid memory engine "${value}". Must be: ${VALID_MEMORY_ENGINES.join(", ")}`);
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, value);
668
- console.log(` ${key}: ${oldValue ?? "(unset)"} \u2192 ${value}`);
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: ${key} = ${value}`);
702
+ printSuccess(`Configuration applied: ${tfKey} = ${tfValue}`);
689
703
  } else {
690
- printSuccess(`Configuration updated: ${key} = ${value}`);
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
- `memory_engine = "${config.memory_engine}"`,
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.memory_engine = "managed";
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 = Built-in AgentCore memory (remember/recall/forget)"));
1112
- console.log(chalk5.dim(" hindsight = ECS Fargate service with semantic + graph retrieval"));
1113
- config.memory_engine = await choose("Memory engine", ["managed", "hindsight"], "managed");
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 "memory_engine" { type = string; default = "managed" }
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
- memory_engine = var.memory_engine
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" { value = module.thinkwork.ecr_repository_url }
1232
- output "memory_engine" { value = module.thinkwork.memory_engine }
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.memory_engine}`);
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
- memoryEngine: config.memory_engine,
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.memoryEngine = "hindsight";
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.memoryEngine = "managed";
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:")} ${info.memoryEngine || "unknown"}`);
1384
- if (info.hindsightHealth) console.log(` ${chalk6.bold("Hindsight:")} ${info.hindsightHealth}`);
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/upgrade.ts
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 registerUpgradeCommand(program2) {
1712
- program2.command("upgrade").description("Check for and install CLI updates").option("--check", "Only check for updates, don't install").action(async (opts) => {
1713
- printHeader("upgrade", "", null);
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
- registerUpgradeCommand(program);
1803
+ registerUpdateCommand(program);
1784
1804
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkwork-cli",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Thinkwork CLI — deploy, manage, and interact with your Thinkwork stack",
5
5
  "license": "MIT",
6
6
  "type": "module",