thinkwork-cli 0.5.2 → 0.5.3

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 CHANGED
@@ -752,8 +752,8 @@ function registerBootstrapCommand(program2) {
752
752
  bucket = await getTerraformOutput(cwd, "bucket_name");
753
753
  dbEndpoint = await getTerraformOutput(cwd, "db_cluster_endpoint");
754
754
  const secretArn = await getTerraformOutput(cwd, "db_secret_arn");
755
- const { execSync: execSync9 } = await import("child_process");
756
- const secretJson = execSync9(
755
+ const { execSync: execSync10 } = await import("child_process");
756
+ const secretJson = execSync10(
757
757
  `aws secretsmanager get-secret-value --secret-id "${secretArn}" --query SecretString --output text`,
758
758
  { encoding: "utf-8" }
759
759
  ).trim();
@@ -901,10 +901,10 @@ async function ensurePrerequisites() {
901
901
  }
902
902
 
903
903
  // src/commands/login.ts
904
- function ask(prompt) {
904
+ function ask(prompt2) {
905
905
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
906
906
  return new Promise((resolve3) => {
907
- rl.question(prompt, (answer) => {
907
+ rl.question(prompt2, (answer) => {
908
908
  rl.close();
909
909
  resolve3(answer.trim());
910
910
  });
@@ -994,19 +994,19 @@ import { fileURLToPath } from "url";
994
994
  import { createInterface as createInterface3 } from "readline";
995
995
  import chalk5 from "chalk";
996
996
  var __dirname = dirname(fileURLToPath(import.meta.url));
997
- function ask2(prompt, defaultVal = "") {
997
+ function ask2(prompt2, defaultVal = "") {
998
998
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
999
999
  const suffix = defaultVal ? chalk5.dim(` [${defaultVal}]`) : "";
1000
1000
  return new Promise((resolve3) => {
1001
- rl.question(` ${prompt}${suffix}: `, (answer) => {
1001
+ rl.question(` ${prompt2}${suffix}: `, (answer) => {
1002
1002
  rl.close();
1003
1003
  resolve3(answer.trim() || defaultVal);
1004
1004
  });
1005
1005
  });
1006
1006
  }
1007
- function choose(prompt, options, defaultVal) {
1007
+ function choose(prompt2, options, defaultVal) {
1008
1008
  const optStr = options.map((o) => o === defaultVal ? chalk5.bold(o) : chalk5.dim(o)).join(" / ");
1009
- return ask2(`${prompt} (${optStr})`, defaultVal);
1009
+ return ask2(`${prompt2} (${optStr})`, defaultVal);
1010
1010
  }
1011
1011
  function generateSecret(length = 32) {
1012
1012
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -1017,9 +1017,9 @@ function generateSecret(length = 32) {
1017
1017
  return result;
1018
1018
  }
1019
1019
  function findBundledTerraform() {
1020
- const bundled = resolve2(__dirname, "..", "terraform");
1020
+ const bundled = resolve2(__dirname, "terraform");
1021
1021
  if (existsSync5(join3(bundled, "modules"))) return bundled;
1022
- const repoTf = resolve2(__dirname, "..", "..", "..", "..", "terraform");
1022
+ const repoTf = resolve2(__dirname, "..", "..", "..", "terraform");
1023
1023
  if (existsSync5(join3(repoTf, "modules"))) return repoTf;
1024
1024
  throw new Error(
1025
1025
  "Terraform modules not found. The CLI package may be incomplete.\nTry reinstalling: npm install -g thinkwork-cli@latest"
@@ -1202,21 +1202,86 @@ provider "aws" {
1202
1202
  region = var.region
1203
1203
  }
1204
1204
 
1205
- variable "stage" { type = string }
1206
- variable "region" { type = string; default = "us-east-1" }
1207
- variable "account_id" { type = string }
1208
- variable "db_password" { type = string; sensitive = true }
1209
- variable "database_engine" { type = string; default = "aurora-serverless" }
1210
- variable "enable_hindsight" { type = bool; default = false }
1211
- variable "google_oauth_client_id" { type = string; default = "" }
1212
- variable "google_oauth_client_secret" { type = string; sensitive = true; default = "" }
1213
- variable "pre_signup_lambda_zip" { type = string; default = "" }
1214
- variable "lambda_zips_dir" { type = string; default = "" }
1215
- variable "api_auth_secret" { type = string; sensitive = true; default = "" }
1216
- variable "admin_callback_urls" { type = list(string); default = ["http://localhost:5174", "http://localhost:5174/auth/callback"] }
1217
- variable "admin_logout_urls" { type = list(string); default = ["http://localhost:5174"] }
1218
- variable "mobile_callback_urls" { type = list(string); default = ["exp://localhost:8081", "thinkwork://", "thinkwork://auth/callback"] }
1219
- variable "mobile_logout_urls" { type = list(string); default = ["exp://localhost:8081", "thinkwork://"] }
1205
+ variable "stage" {
1206
+ type = string
1207
+ }
1208
+
1209
+ variable "region" {
1210
+ type = string
1211
+ default = "us-east-1"
1212
+ }
1213
+
1214
+ variable "account_id" {
1215
+ type = string
1216
+ }
1217
+
1218
+ variable "db_password" {
1219
+ type = string
1220
+ sensitive = true
1221
+ }
1222
+
1223
+ variable "database_engine" {
1224
+ type = string
1225
+ default = "aurora-serverless"
1226
+ }
1227
+
1228
+ variable "enable_hindsight" {
1229
+ type = bool
1230
+ default = false
1231
+ }
1232
+
1233
+ variable "agentcore_memory_id" {
1234
+ type = string
1235
+ default = ""
1236
+ description = "Optional pre-existing Bedrock AgentCore Memory resource ID. Leave empty to auto-provision."
1237
+ }
1238
+
1239
+ variable "google_oauth_client_id" {
1240
+ type = string
1241
+ default = ""
1242
+ }
1243
+
1244
+ variable "google_oauth_client_secret" {
1245
+ type = string
1246
+ sensitive = true
1247
+ default = ""
1248
+ }
1249
+
1250
+ variable "pre_signup_lambda_zip" {
1251
+ type = string
1252
+ default = ""
1253
+ }
1254
+
1255
+ variable "lambda_zips_dir" {
1256
+ type = string
1257
+ default = ""
1258
+ }
1259
+
1260
+ variable "api_auth_secret" {
1261
+ type = string
1262
+ sensitive = true
1263
+ default = ""
1264
+ }
1265
+
1266
+ variable "admin_callback_urls" {
1267
+ type = list(string)
1268
+ default = ["http://localhost:5174", "http://localhost:5174/auth/callback"]
1269
+ }
1270
+
1271
+ variable "admin_logout_urls" {
1272
+ type = list(string)
1273
+ default = ["http://localhost:5174"]
1274
+ }
1275
+
1276
+ variable "mobile_callback_urls" {
1277
+ type = list(string)
1278
+ default = ["exp://localhost:8081", "thinkwork://", "thinkwork://auth/callback"]
1279
+ }
1280
+
1281
+ variable "mobile_logout_urls" {
1282
+ type = list(string)
1283
+ default = ["exp://localhost:8081", "thinkwork://"]
1284
+ }
1220
1285
 
1221
1286
  module "thinkwork" {
1222
1287
  source = "./modules/thinkwork"
@@ -1228,6 +1293,7 @@ module "thinkwork" {
1228
1293
  db_password = var.db_password
1229
1294
  database_engine = var.database_engine
1230
1295
  enable_hindsight = var.enable_hindsight
1296
+ agentcore_memory_id = var.agentcore_memory_id
1231
1297
  google_oauth_client_id = var.google_oauth_client_id
1232
1298
  google_oauth_client_secret = var.google_oauth_client_secret
1233
1299
  pre_signup_lambda_zip = var.pre_signup_lambda_zip
@@ -1239,17 +1305,50 @@ module "thinkwork" {
1239
1305
  mobile_logout_urls = var.mobile_logout_urls
1240
1306
  }
1241
1307
 
1242
- output "api_endpoint" { value = module.thinkwork.api_endpoint }
1243
- output "user_pool_id" { value = module.thinkwork.user_pool_id }
1244
- output "admin_client_id" { value = module.thinkwork.admin_client_id }
1245
- output "mobile_client_id" { value = module.thinkwork.mobile_client_id }
1246
- output "bucket_name" { value = module.thinkwork.bucket_name }
1247
- output "db_cluster_endpoint" { value = module.thinkwork.db_cluster_endpoint }
1248
- output "db_secret_arn" { value = module.thinkwork.db_secret_arn; sensitive = true }
1249
- output "ecr_repository_url" { value = module.thinkwork.ecr_repository_url }
1250
- output "hindsight_enabled" { value = module.thinkwork.hindsight_enabled }
1251
- output "hindsight_endpoint" { value = module.thinkwork.hindsight_endpoint }
1252
- output "agentcore_memory_id" { value = module.thinkwork.agentcore_memory_id }
1308
+ output "api_endpoint" {
1309
+ value = module.thinkwork.api_endpoint
1310
+ }
1311
+
1312
+ output "user_pool_id" {
1313
+ value = module.thinkwork.user_pool_id
1314
+ }
1315
+
1316
+ output "admin_client_id" {
1317
+ value = module.thinkwork.admin_client_id
1318
+ }
1319
+
1320
+ output "mobile_client_id" {
1321
+ value = module.thinkwork.mobile_client_id
1322
+ }
1323
+
1324
+ output "bucket_name" {
1325
+ value = module.thinkwork.bucket_name
1326
+ }
1327
+
1328
+ output "db_cluster_endpoint" {
1329
+ value = module.thinkwork.db_cluster_endpoint
1330
+ }
1331
+
1332
+ output "db_secret_arn" {
1333
+ value = module.thinkwork.db_secret_arn
1334
+ sensitive = true
1335
+ }
1336
+
1337
+ output "ecr_repository_url" {
1338
+ value = module.thinkwork.ecr_repository_url
1339
+ }
1340
+
1341
+ output "hindsight_enabled" {
1342
+ value = module.thinkwork.hindsight_enabled
1343
+ }
1344
+
1345
+ output "hindsight_endpoint" {
1346
+ value = module.thinkwork.hindsight_endpoint
1347
+ }
1348
+
1349
+ output "agentcore_memory_id" {
1350
+ value = module.thinkwork.agentcore_memory_id
1351
+ }
1253
1352
  `);
1254
1353
  }
1255
1354
  console.log(` Wrote ${chalk5.cyan(tfDir + "/")}`);
@@ -1691,12 +1790,246 @@ function registerMcpCommand(program2) {
1691
1790
  });
1692
1791
  }
1693
1792
 
1694
- // src/commands/update.ts
1793
+ // src/commands/tools.ts
1794
+ import { readFileSync as readFileSync4, existsSync as existsSync7 } from "fs";
1695
1795
  import { execSync as execSync8 } from "child_process";
1796
+ import { createInterface as createInterface4 } from "readline";
1696
1797
  import chalk8 from "chalk";
1798
+ function readTfVar3(tfvarsPath, key) {
1799
+ if (!existsSync7(tfvarsPath)) return null;
1800
+ const content = readFileSync4(tfvarsPath, "utf-8");
1801
+ const match = content.match(new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, "m"));
1802
+ return match ? match[1] : null;
1803
+ }
1804
+ function resolveTfvarsPath3(stage) {
1805
+ const tfDir = resolveTerraformDir(stage);
1806
+ if (tfDir) {
1807
+ const direct = `${tfDir}/terraform.tfvars`;
1808
+ if (existsSync7(direct)) return direct;
1809
+ }
1810
+ const terraformDir = process.env.THINKWORK_TERRAFORM_DIR || process.cwd();
1811
+ const cwd = resolveTierDir(terraformDir, stage, "app");
1812
+ return `${cwd}/terraform.tfvars`;
1813
+ }
1814
+ function getApiEndpoint2(stage, region) {
1815
+ try {
1816
+ const raw = execSync8(
1817
+ `aws apigatewayv2 get-apis --region ${region} --query "Items[?Name=='thinkwork-${stage}-api'].ApiEndpoint|[0]" --output text`,
1818
+ { encoding: "utf-8", timeout: 15e3, stdio: ["pipe", "pipe", "pipe"] }
1819
+ ).trim();
1820
+ return raw && raw !== "None" ? raw : null;
1821
+ } catch {
1822
+ return null;
1823
+ }
1824
+ }
1825
+ async function apiFetch2(apiUrl, authSecret, path2, options = {}, extraHeaders = {}) {
1826
+ const res = await fetch(`${apiUrl}${path2}`, {
1827
+ ...options,
1828
+ headers: {
1829
+ "Content-Type": "application/json",
1830
+ Authorization: `Bearer ${authSecret}`,
1831
+ ...extraHeaders,
1832
+ ...options.headers
1833
+ }
1834
+ });
1835
+ if (!res.ok) {
1836
+ const body = await res.json().catch(() => ({}));
1837
+ throw new Error(body.error || `HTTP ${res.status}`);
1838
+ }
1839
+ return res.json();
1840
+ }
1841
+ function resolveApiConfig2(stage) {
1842
+ const tfvarsPath = resolveTfvarsPath3(stage);
1843
+ const authSecret = readTfVar3(tfvarsPath, "api_auth_secret");
1844
+ if (!authSecret) {
1845
+ printError(`Cannot read api_auth_secret from ${tfvarsPath}`);
1846
+ return null;
1847
+ }
1848
+ const region = readTfVar3(tfvarsPath, "region") || "us-east-1";
1849
+ const apiUrl = getApiEndpoint2(stage, region);
1850
+ if (!apiUrl) {
1851
+ printError(`Cannot discover API endpoint for stage "${stage}". Is the stack deployed?`);
1852
+ return null;
1853
+ }
1854
+ return { apiUrl, authSecret };
1855
+ }
1856
+ function prompt(question) {
1857
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
1858
+ return new Promise((resolve3) => {
1859
+ rl.question(question, (answer) => {
1860
+ rl.close();
1861
+ resolve3(answer.trim());
1862
+ });
1863
+ });
1864
+ }
1865
+ var TOOL_PROVIDERS = {
1866
+ "web-search": ["exa", "serpapi"]
1867
+ };
1868
+ function registerToolsCommand(program2) {
1869
+ const tools = program2.command("tools").description("Configure built-in agent tools (web_search, \u2026) for your tenant");
1870
+ tools.command("list").description("List configured built-in tools").requiredOption("-s, --stage <name>", "Deployment stage").requiredOption("--tenant <slug>", "Tenant slug").action(async (opts) => {
1871
+ const check = validateStage(opts.stage);
1872
+ if (!check.valid) {
1873
+ printError(check.error);
1874
+ process.exit(1);
1875
+ }
1876
+ const api = resolveApiConfig2(opts.stage);
1877
+ if (!api) process.exit(1);
1878
+ printHeader("tools list", opts.stage);
1879
+ try {
1880
+ const { tools: rows } = await apiFetch2(
1881
+ api.apiUrl,
1882
+ api.authSecret,
1883
+ "/api/skills/builtin-tools",
1884
+ {},
1885
+ { "x-tenant-slug": opts.tenant }
1886
+ );
1887
+ if (!rows || rows.length === 0) {
1888
+ console.log(chalk8.dim(" No built-in tools configured."));
1889
+ console.log(chalk8.dim(" Try: thinkwork tools web-search set --tenant <slug> -s <stage>"));
1890
+ return;
1891
+ }
1892
+ console.log("");
1893
+ for (const r of rows) {
1894
+ const status = r.enabled ? chalk8.green("enabled") : chalk8.dim("disabled");
1895
+ const key = r.hasSecret ? chalk8.green("yes") : chalk8.red("no");
1896
+ const provider = r.provider ?? chalk8.dim("\u2014");
1897
+ console.log(` ${chalk8.bold(r.toolSlug)} ${status}`);
1898
+ console.log(` Provider: ${provider}`);
1899
+ console.log(` Has key: ${key}`);
1900
+ if (r.lastTestedAt) {
1901
+ console.log(` Tested: ${new Date(r.lastTestedAt).toLocaleString()}`);
1902
+ }
1903
+ console.log("");
1904
+ }
1905
+ } catch (err) {
1906
+ printError(err.message);
1907
+ process.exit(1);
1908
+ }
1909
+ });
1910
+ const webSearch = tools.command("web-search").description("Configure the web_search built-in tool");
1911
+ webSearch.command("set").description("Set or update web_search provider + API key (enables the tool)").requiredOption("-s, --stage <name>", "Deployment stage").requiredOption("--tenant <slug>", "Tenant slug").option("--provider <name>", `Provider (${TOOL_PROVIDERS["web-search"].join("|")})`).option("--key <key>", "API key").action(async (opts) => {
1912
+ const check = validateStage(opts.stage);
1913
+ if (!check.valid) {
1914
+ printError(check.error);
1915
+ process.exit(1);
1916
+ }
1917
+ const api = resolveApiConfig2(opts.stage);
1918
+ if (!api) process.exit(1);
1919
+ let provider = opts.provider;
1920
+ if (!provider) {
1921
+ provider = (await prompt(`Provider [${TOOL_PROVIDERS["web-search"].join("/")}]: `)).toLowerCase();
1922
+ }
1923
+ if (!TOOL_PROVIDERS["web-search"].includes(provider)) {
1924
+ printError(`provider must be one of: ${TOOL_PROVIDERS["web-search"].join(", ")}`);
1925
+ process.exit(1);
1926
+ }
1927
+ let apiKey = opts.key;
1928
+ if (!apiKey) {
1929
+ apiKey = await prompt(`${provider} API key: `);
1930
+ }
1931
+ if (!apiKey) {
1932
+ printError("API key is required");
1933
+ process.exit(1);
1934
+ }
1935
+ try {
1936
+ await apiFetch2(
1937
+ api.apiUrl,
1938
+ api.authSecret,
1939
+ "/api/skills/builtin-tools/web-search",
1940
+ {
1941
+ method: "PUT",
1942
+ body: JSON.stringify({ provider, apiKey, enabled: true })
1943
+ },
1944
+ { "x-tenant-slug": opts.tenant }
1945
+ );
1946
+ printSuccess(`web_search configured with provider=${provider}, enabled=true`);
1947
+ printWarning("Run `thinkwork tools web-search test` to verify connectivity.");
1948
+ } catch (err) {
1949
+ printError(err.message);
1950
+ process.exit(1);
1951
+ }
1952
+ });
1953
+ webSearch.command("test").description("Test the stored web_search provider + key against the provider API").requiredOption("-s, --stage <name>", "Deployment stage").requiredOption("--tenant <slug>", "Tenant slug").action(async (opts) => {
1954
+ const check = validateStage(opts.stage);
1955
+ if (!check.valid) {
1956
+ printError(check.error);
1957
+ process.exit(1);
1958
+ }
1959
+ const api = resolveApiConfig2(opts.stage);
1960
+ if (!api) process.exit(1);
1961
+ printHeader("tools web-search test", opts.stage);
1962
+ try {
1963
+ const result = await apiFetch2(
1964
+ api.apiUrl,
1965
+ api.authSecret,
1966
+ "/api/skills/builtin-tools/web-search/test",
1967
+ { method: "POST", body: "{}" },
1968
+ { "x-tenant-slug": opts.tenant }
1969
+ );
1970
+ if (result.ok) {
1971
+ printSuccess(`${result.provider}: ${result.resultCount} result(s) returned.`);
1972
+ } else {
1973
+ printError(`Test failed: ${result.error}`);
1974
+ process.exit(1);
1975
+ }
1976
+ } catch (err) {
1977
+ printError(err.message);
1978
+ process.exit(1);
1979
+ }
1980
+ });
1981
+ webSearch.command("disable").description("Disable web_search without deleting the stored key").requiredOption("-s, --stage <name>", "Deployment stage").requiredOption("--tenant <slug>", "Tenant slug").action(async (opts) => {
1982
+ const check = validateStage(opts.stage);
1983
+ if (!check.valid) {
1984
+ printError(check.error);
1985
+ process.exit(1);
1986
+ }
1987
+ const api = resolveApiConfig2(opts.stage);
1988
+ if (!api) process.exit(1);
1989
+ try {
1990
+ await apiFetch2(
1991
+ api.apiUrl,
1992
+ api.authSecret,
1993
+ "/api/skills/builtin-tools/web-search",
1994
+ { method: "PUT", body: JSON.stringify({ enabled: false }) },
1995
+ { "x-tenant-slug": opts.tenant }
1996
+ );
1997
+ printSuccess("web_search disabled.");
1998
+ } catch (err) {
1999
+ printError(err.message);
2000
+ process.exit(1);
2001
+ }
2002
+ });
2003
+ webSearch.command("clear").description("Remove web_search config entirely (deletes stored key)").requiredOption("-s, --stage <name>", "Deployment stage").requiredOption("--tenant <slug>", "Tenant slug").action(async (opts) => {
2004
+ const check = validateStage(opts.stage);
2005
+ if (!check.valid) {
2006
+ printError(check.error);
2007
+ process.exit(1);
2008
+ }
2009
+ const api = resolveApiConfig2(opts.stage);
2010
+ if (!api) process.exit(1);
2011
+ try {
2012
+ await apiFetch2(
2013
+ api.apiUrl,
2014
+ api.authSecret,
2015
+ "/api/skills/builtin-tools/web-search",
2016
+ { method: "DELETE" },
2017
+ { "x-tenant-slug": opts.tenant }
2018
+ );
2019
+ printSuccess("web_search configuration cleared.");
2020
+ } catch (err) {
2021
+ printError(err.message);
2022
+ process.exit(1);
2023
+ }
2024
+ });
2025
+ }
2026
+
2027
+ // src/commands/update.ts
2028
+ import { execSync as execSync9 } from "child_process";
2029
+ import chalk9 from "chalk";
1697
2030
  function getLatestVersion() {
1698
2031
  try {
1699
- return execSync8("npm view thinkwork-cli version", {
2032
+ return execSync9("npm view thinkwork-cli version", {
1700
2033
  encoding: "utf-8",
1701
2034
  timeout: 1e4,
1702
2035
  stdio: ["pipe", "pipe", "pipe"]
@@ -1707,7 +2040,7 @@ function getLatestVersion() {
1707
2040
  }
1708
2041
  function detectInstallMethod() {
1709
2042
  try {
1710
- const which = execSync8("which thinkwork", {
2043
+ const which = execSync9("which thinkwork", {
1711
2044
  encoding: "utf-8",
1712
2045
  timeout: 5e3,
1713
2046
  stdio: ["pipe", "pipe", "pipe"]
@@ -1731,28 +2064,28 @@ function compareVersions(a, b) {
1731
2064
  function registerUpdateCommand(program2) {
1732
2065
  program2.command("update").description("Check for and install CLI updates").option("--check", "Only check for updates, don't install").action(async (opts) => {
1733
2066
  printHeader("update", "", null);
1734
- console.log(` Current version: ${chalk8.bold(VERSION)}`);
2067
+ console.log(` Current version: ${chalk9.bold(VERSION)}`);
1735
2068
  const latest = getLatestVersion();
1736
2069
  if (!latest) {
1737
- console.log(chalk8.yellow(" Could not check npm registry for updates."));
2070
+ console.log(chalk9.yellow(" Could not check npm registry for updates."));
1738
2071
  return;
1739
2072
  }
1740
- console.log(` Latest version: ${chalk8.bold(latest)}`);
2073
+ console.log(` Latest version: ${chalk9.bold(latest)}`);
1741
2074
  console.log("");
1742
2075
  const cmp = compareVersions(VERSION, latest);
1743
2076
  if (cmp >= 0) {
1744
- console.log(chalk8.green(" \u2713 You're on the latest version."));
2077
+ console.log(chalk9.green(" \u2713 You're on the latest version."));
1745
2078
  console.log("");
1746
2079
  return;
1747
2080
  }
1748
- console.log(chalk8.cyan(` Update available: ${VERSION} \u2192 ${latest}`));
2081
+ console.log(chalk9.cyan(` Update available: ${VERSION} \u2192 ${latest}`));
1749
2082
  console.log("");
1750
2083
  if (opts.check) {
1751
2084
  const method2 = detectInstallMethod();
1752
2085
  if (method2 === "homebrew") {
1753
- console.log(` Run: ${chalk8.cyan("brew upgrade thinkwork-ai/tap/thinkwork")}`);
2086
+ console.log(` Run: ${chalk9.cyan("brew upgrade thinkwork-ai/tap/thinkwork")}`);
1754
2087
  } else {
1755
- console.log(` Run: ${chalk8.cyan(`npm install -g thinkwork-cli@${latest}`)}`);
2088
+ console.log(` Run: ${chalk9.cyan(`npm install -g thinkwork-cli@${latest}`)}`);
1756
2089
  }
1757
2090
  console.log("");
1758
2091
  return;
@@ -1760,16 +2093,16 @@ function registerUpdateCommand(program2) {
1760
2093
  const method = detectInstallMethod();
1761
2094
  const cmd = method === "homebrew" ? "brew upgrade thinkwork-ai/tap/thinkwork" : `npm install -g thinkwork-cli@${latest}`;
1762
2095
  console.log(` Installing via ${method}...`);
1763
- console.log(chalk8.dim(` $ ${cmd}`));
2096
+ console.log(chalk9.dim(` $ ${cmd}`));
1764
2097
  console.log("");
1765
2098
  try {
1766
- execSync8(cmd, { stdio: "inherit", timeout: 12e4 });
2099
+ execSync9(cmd, { stdio: "inherit", timeout: 12e4 });
1767
2100
  console.log("");
1768
- console.log(chalk8.green(` \u2713 Upgraded to thinkwork-cli@${latest}`));
2101
+ console.log(chalk9.green(` \u2713 Upgraded to thinkwork-cli@${latest}`));
1769
2102
  } catch {
1770
2103
  console.log("");
1771
- console.log(chalk8.red(` Failed to upgrade. Try manually:`));
1772
- console.log(` ${chalk8.cyan(cmd)}`);
2104
+ console.log(chalk9.red(` Failed to upgrade. Try manually:`));
2105
+ console.log(` ${chalk9.cyan(cmd)}`);
1773
2106
  }
1774
2107
  console.log("");
1775
2108
  });
@@ -1800,5 +2133,6 @@ registerStatusCommand(program);
1800
2133
  registerOutputsCommand(program);
1801
2134
  registerConfigCommand(program);
1802
2135
  registerMcpCommand(program);
2136
+ registerToolsCommand(program);
1803
2137
  registerUpdateCommand(program);
1804
2138
  program.parse();
@@ -72,10 +72,10 @@ variable "database_engine" {
72
72
  default = "aurora-serverless"
73
73
  }
74
74
 
75
- variable "memory_engine" {
76
- description = "Memory engine: 'managed' (AgentCore built-in, default) or 'hindsight' (ECS+ALB, opt-in)"
77
- type = string
78
- default = "managed"
75
+ variable "enable_hindsight" {
76
+ description = "Optional Hindsight add-on alongside the always-on managed memory (ECS+ALB for semantic + graph retrieval)"
77
+ type = bool
78
+ default = false
79
79
  }
80
80
 
81
81
  variable "google_oauth_client_id" {
@@ -119,7 +119,7 @@ module "thinkwork" {
119
119
 
120
120
  db_password = var.db_password
121
121
  database_engine = var.database_engine
122
- memory_engine = var.memory_engine
122
+ enable_hindsight = var.enable_hindsight
123
123
  google_oauth_client_id = var.google_oauth_client_id
124
124
  google_oauth_client_secret = var.google_oauth_client_secret
125
125
  pre_signup_lambda_zip = var.pre_signup_lambda_zip
@@ -199,16 +199,21 @@ output "database_name" {
199
199
  value = module.thinkwork.database_name
200
200
  }
201
201
 
202
- output "memory_engine" {
203
- description = "Active memory engine (managed or hindsight)"
204
- value = module.thinkwork.memory_engine
202
+ output "hindsight_enabled" {
203
+ description = "Whether the Hindsight add-on is enabled"
204
+ value = module.thinkwork.hindsight_enabled
205
205
  }
206
206
 
207
207
  output "hindsight_endpoint" {
208
- description = "Hindsight API endpoint (null when memory_engine = managed)"
208
+ description = "Hindsight API endpoint (null when enable_hindsight = false)"
209
209
  value = module.thinkwork.hindsight_endpoint
210
210
  }
211
211
 
212
+ output "agentcore_memory_id" {
213
+ description = "AgentCore Memory resource ID used for automatic retention"
214
+ value = module.thinkwork.agentcore_memory_id
215
+ }
216
+
212
217
  output "admin_url" {
213
218
  description = "Admin app URL"
214
219
  value = "https://${module.thinkwork.admin_distribution_domain}"
@@ -12,10 +12,13 @@ account_id = "123456789012" # your AWS account ID
12
12
  # "rds-postgres" — Standard RDS PostgreSQL (dev/test, cheaper, deletion protection off)
13
13
  database_engine = "rds-postgres"
14
14
 
15
- # Memory engine:
16
- # "managed" — AgentCore built-in long-term memory (default, no extra infra)
17
- # "hindsight" Hindsight ECS+ALB service (opt-in, adds retain/recall/reflect tools)
18
- memory_engine = "managed"
15
+ # Memory:
16
+ # AgentCore managed memory is always on every agent gets automatic
17
+ # per-turn retention with zero config. Uncomment the line below to
18
+ # enable Hindsight as an optional add-on (adds an ECS+ALB service for
19
+ # semantic + entity-graph + cross-encoder retrieval tools alongside the
20
+ # built-in remember/recall/forget tools).
21
+ # enable_hindsight = true
19
22
 
20
23
  # Database master password — use a strong password
21
24
  db_password = "CHANGE_ME_strong_password_here"