thinkwork-cli 0.5.2 → 0.5.4
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 +392 -53
- package/dist/terraform/examples/greenfield/main.tf +14 -9
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +7 -4
- package/dist/terraform/modules/app/agentcore-memory/README.md +77 -0
- package/dist/terraform/modules/app/agentcore-memory/main.tf +159 -0
- package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +212 -0
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +29 -18
- package/dist/terraform/modules/app/hindsight-memory/README.md +50 -29
- package/dist/terraform/modules/app/hindsight-memory/main.tf +9 -7
- package/dist/terraform/modules/app/lambda-api/handlers.tf +43 -38
- package/dist/terraform/modules/app/lambda-api/main.tf +58 -0
- package/dist/terraform/modules/app/lambda-api/variables.tf +35 -5
- package/dist/terraform/modules/thinkwork/main.tf +44 -18
- package/dist/terraform/modules/thinkwork/outputs.tf +10 -5
- package/dist/terraform/modules/thinkwork/variables.tf +12 -6
- package/package.json +1 -1
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:
|
|
756
|
-
const secretJson =
|
|
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(
|
|
904
|
+
function ask(prompt2) {
|
|
905
905
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
906
906
|
return new Promise((resolve3) => {
|
|
907
|
-
rl.question(
|
|
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(
|
|
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(` ${
|
|
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(
|
|
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(`${
|
|
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, "
|
|
1020
|
+
const bundled = resolve2(__dirname, "terraform");
|
|
1021
1021
|
if (existsSync5(join3(bundled, "modules"))) return bundled;
|
|
1022
|
-
const repoTf = resolve2(__dirname, "..", "..", "..", "
|
|
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" {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
variable "
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
variable "
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
variable "
|
|
1219
|
-
|
|
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"
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
output "
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
output "
|
|
1251
|
-
|
|
1252
|
-
|
|
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,247 @@ function registerMcpCommand(program2) {
|
|
|
1691
1790
|
});
|
|
1692
1791
|
}
|
|
1693
1792
|
|
|
1694
|
-
// src/commands/
|
|
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 { realpathSync } from "fs";
|
|
2030
|
+
import chalk9 from "chalk";
|
|
1697
2031
|
function getLatestVersion() {
|
|
1698
2032
|
try {
|
|
1699
|
-
return
|
|
2033
|
+
return execSync9("npm view thinkwork-cli version", {
|
|
1700
2034
|
encoding: "utf-8",
|
|
1701
2035
|
timeout: 1e4,
|
|
1702
2036
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -1707,13 +2041,17 @@ function getLatestVersion() {
|
|
|
1707
2041
|
}
|
|
1708
2042
|
function detectInstallMethod() {
|
|
1709
2043
|
try {
|
|
1710
|
-
const which =
|
|
2044
|
+
const which = execSync9("which thinkwork", {
|
|
1711
2045
|
encoding: "utf-8",
|
|
1712
2046
|
timeout: 5e3,
|
|
1713
2047
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1714
2048
|
}).trim();
|
|
1715
|
-
|
|
1716
|
-
|
|
2049
|
+
let resolved = which;
|
|
2050
|
+
try {
|
|
2051
|
+
resolved = realpathSync(which);
|
|
2052
|
+
} catch {
|
|
2053
|
+
}
|
|
2054
|
+
if (resolved.includes("/Cellar/")) return "homebrew";
|
|
1717
2055
|
return "npm";
|
|
1718
2056
|
} catch {
|
|
1719
2057
|
return "npm";
|
|
@@ -1731,28 +2069,28 @@ function compareVersions(a, b) {
|
|
|
1731
2069
|
function registerUpdateCommand(program2) {
|
|
1732
2070
|
program2.command("update").description("Check for and install CLI updates").option("--check", "Only check for updates, don't install").action(async (opts) => {
|
|
1733
2071
|
printHeader("update", "", null);
|
|
1734
|
-
console.log(` Current version: ${
|
|
2072
|
+
console.log(` Current version: ${chalk9.bold(VERSION)}`);
|
|
1735
2073
|
const latest = getLatestVersion();
|
|
1736
2074
|
if (!latest) {
|
|
1737
|
-
console.log(
|
|
2075
|
+
console.log(chalk9.yellow(" Could not check npm registry for updates."));
|
|
1738
2076
|
return;
|
|
1739
2077
|
}
|
|
1740
|
-
console.log(` Latest version: ${
|
|
2078
|
+
console.log(` Latest version: ${chalk9.bold(latest)}`);
|
|
1741
2079
|
console.log("");
|
|
1742
2080
|
const cmp = compareVersions(VERSION, latest);
|
|
1743
2081
|
if (cmp >= 0) {
|
|
1744
|
-
console.log(
|
|
2082
|
+
console.log(chalk9.green(" \u2713 You're on the latest version."));
|
|
1745
2083
|
console.log("");
|
|
1746
2084
|
return;
|
|
1747
2085
|
}
|
|
1748
|
-
console.log(
|
|
2086
|
+
console.log(chalk9.cyan(` Update available: ${VERSION} \u2192 ${latest}`));
|
|
1749
2087
|
console.log("");
|
|
1750
2088
|
if (opts.check) {
|
|
1751
2089
|
const method2 = detectInstallMethod();
|
|
1752
2090
|
if (method2 === "homebrew") {
|
|
1753
|
-
console.log(` Run: ${
|
|
2091
|
+
console.log(` Run: ${chalk9.cyan("brew upgrade thinkwork-ai/tap/thinkwork")}`);
|
|
1754
2092
|
} else {
|
|
1755
|
-
console.log(` Run: ${
|
|
2093
|
+
console.log(` Run: ${chalk9.cyan(`npm install -g thinkwork-cli@${latest}`)}`);
|
|
1756
2094
|
}
|
|
1757
2095
|
console.log("");
|
|
1758
2096
|
return;
|
|
@@ -1760,16 +2098,16 @@ function registerUpdateCommand(program2) {
|
|
|
1760
2098
|
const method = detectInstallMethod();
|
|
1761
2099
|
const cmd = method === "homebrew" ? "brew upgrade thinkwork-ai/tap/thinkwork" : `npm install -g thinkwork-cli@${latest}`;
|
|
1762
2100
|
console.log(` Installing via ${method}...`);
|
|
1763
|
-
console.log(
|
|
2101
|
+
console.log(chalk9.dim(` $ ${cmd}`));
|
|
1764
2102
|
console.log("");
|
|
1765
2103
|
try {
|
|
1766
|
-
|
|
2104
|
+
execSync9(cmd, { stdio: "inherit", timeout: 12e4 });
|
|
1767
2105
|
console.log("");
|
|
1768
|
-
console.log(
|
|
2106
|
+
console.log(chalk9.green(` \u2713 Upgraded to thinkwork-cli@${latest}`));
|
|
1769
2107
|
} catch {
|
|
1770
2108
|
console.log("");
|
|
1771
|
-
console.log(
|
|
1772
|
-
console.log(` ${
|
|
2109
|
+
console.log(chalk9.red(` Failed to upgrade. Try manually:`));
|
|
2110
|
+
console.log(` ${chalk9.cyan(cmd)}`);
|
|
1773
2111
|
}
|
|
1774
2112
|
console.log("");
|
|
1775
2113
|
});
|
|
@@ -1800,5 +2138,6 @@ registerStatusCommand(program);
|
|
|
1800
2138
|
registerOutputsCommand(program);
|
|
1801
2139
|
registerConfigCommand(program);
|
|
1802
2140
|
registerMcpCommand(program);
|
|
2141
|
+
registerToolsCommand(program);
|
|
1803
2142
|
registerUpdateCommand(program);
|
|
1804
2143
|
program.parse();
|
|
@@ -72,10 +72,10 @@ variable "database_engine" {
|
|
|
72
72
|
default = "aurora-serverless"
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
variable "
|
|
76
|
-
description = "
|
|
77
|
-
type =
|
|
78
|
-
default =
|
|
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
|
-
|
|
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 "
|
|
203
|
-
description = "
|
|
204
|
-
value = module.thinkwork.
|
|
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
|
|
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
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
|
|
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"
|