thinkwork-cli 0.1.0 → 0.1.1

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 +3 -3
  2. package/dist/cli.js +123 -40
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,17 +1,17 @@
1
- # @thinkwork-ai/cli
1
+ # thinkwork-cli
2
2
 
3
3
  Deploy and manage Thinkwork AI agent stacks on AWS.
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- npm install -g @thinkwork-ai/cli
8
+ npm install -g thinkwork-cli
9
9
  ```
10
10
 
11
11
  Or run without installing:
12
12
 
13
13
  ```bash
14
- npx @thinkwork-ai/cli --help
14
+ npx thinkwork-cli --help
15
15
  ```
16
16
 
17
17
  ## Quick Start
package/dist/cli.js CHANGED
@@ -713,43 +713,76 @@ import { existsSync as existsSync3, mkdirSync, writeFileSync as writeFileSync2 }
713
713
  import { resolve as resolve2, join } from "path";
714
714
  import { execSync as execSync4 } from "child_process";
715
715
  import { createInterface as createInterface3 } from "readline";
716
+ import chalk3 from "chalk";
716
717
  function ask2(prompt, defaultVal = "") {
717
718
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
718
- const suffix = defaultVal ? ` [${defaultVal}]` : "";
719
+ const suffix = defaultVal ? chalk3.dim(` [${defaultVal}]`) : "";
719
720
  return new Promise((resolve3) => {
720
- rl.question(`${prompt}${suffix}: `, (answer) => {
721
+ rl.question(` ${prompt}${suffix}: `, (answer) => {
721
722
  rl.close();
722
723
  resolve3(answer.trim() || defaultVal);
723
724
  });
724
725
  });
725
726
  }
726
- function generatePassword() {
727
- const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%";
728
- let pw = "";
729
- const bytes = new Uint8Array(32);
727
+ function choose(prompt, options, defaultVal) {
728
+ const optStr = options.map((o) => o === defaultVal ? chalk3.bold(o) : chalk3.dim(o)).join(" / ");
729
+ return ask2(`${prompt} (${optStr})`, defaultVal);
730
+ }
731
+ function generateSecret(length = 32) {
732
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
733
+ let result = "";
734
+ const bytes = new Uint8Array(length);
730
735
  globalThis.crypto.getRandomValues(bytes);
731
- for (const b of bytes) pw += chars[b % chars.length];
732
- return pw;
736
+ for (const b of bytes) result += chars[b % chars.length];
737
+ return result;
738
+ }
739
+ function buildTfvars(config) {
740
+ const lines = [
741
+ `# Thinkwork \u2014 ${config.stage} stage`,
742
+ `# Generated by: thinkwork init -s ${config.stage}`,
743
+ `# ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
744
+ ``,
745
+ `# \u2500\u2500 Core \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`,
746
+ `stage = "${config.stage}"`,
747
+ `region = "${config.region}"`,
748
+ `account_id = "${config.account_id}"`,
749
+ ``,
750
+ `# \u2500\u2500 Database \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`,
751
+ `database_engine = "${config.database_engine}"`,
752
+ `db_password = "${config.db_password}"`,
753
+ ``,
754
+ `# \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`,
755
+ `memory_engine = "${config.memory_engine}"`,
756
+ ``,
757
+ `# \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`,
758
+ `api_auth_secret = "${config.api_auth_secret}"`
759
+ ];
760
+ if (config.google_oauth_client_id) {
761
+ lines.push(``);
762
+ lines.push(`# \u2500\u2500 Google OAuth \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`);
763
+ lines.push(`google_oauth_client_id = "${config.google_oauth_client_id}"`);
764
+ lines.push(`google_oauth_client_secret = "${config.google_oauth_client_secret}"`);
765
+ } else {
766
+ lines.push(``);
767
+ lines.push(`# \u2500\u2500 Google OAuth (uncomment to enable Google social login) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
768
+ lines.push(`# google_oauth_client_id = ""`);
769
+ lines.push(`# google_oauth_client_secret = ""`);
770
+ }
771
+ if (config.admin_url && config.admin_url !== "http://localhost:5174") {
772
+ lines.push(``);
773
+ lines.push(`# \u2500\u2500 Callback URLs \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`);
774
+ lines.push(`admin_callback_urls = ["${config.admin_url}", "${config.admin_url}/auth/callback"]`);
775
+ lines.push(`admin_logout_urls = ["${config.admin_url}"]`);
776
+ }
777
+ if (config.mobile_scheme && config.mobile_scheme !== "thinkwork") {
778
+ lines.push(`mobile_callback_urls = ["${config.mobile_scheme}://", "${config.mobile_scheme}://auth/callback"]`);
779
+ lines.push(`mobile_logout_urls = ["${config.mobile_scheme}://"]`);
780
+ }
781
+ lines.push(``);
782
+ return lines.join("\n");
733
783
  }
734
- var TFVARS_TEMPLATE = `# Thinkwork \u2014 {STAGE} stage
735
- # Generated by: thinkwork init -s {STAGE}
736
-
737
- stage = "{STAGE}"
738
- region = "{REGION}"
739
- account_id = "{ACCOUNT_ID}"
740
-
741
- # Database
742
- database_engine = "aurora-serverless"
743
- db_password = "{DB_PASSWORD}"
744
-
745
- # Memory engine: "managed" (built-in) or "hindsight" (ECS Fargate service)
746
- memory_engine = "{MEMORY_ENGINE}"
747
-
748
- # API authentication secret (shared between services)
749
- api_auth_secret = "{API_SECRET}"
750
- `;
751
784
  function registerInitCommand(program2) {
752
- program2.command("init").description("Initialize a new Thinkwork environment").requiredOption("-s, --stage <name>", "Stage name (e.g. dev, staging, prod)").option("-d, --dir <path>", "Directory to initialize in", ".").action(async (opts) => {
785
+ program2.command("init").description("Initialize a new Thinkwork environment").requiredOption("-s, --stage <name>", "Stage name (e.g. dev, staging, prod)").option("-d, --dir <path>", "Directory to initialize in", ".").option("--defaults", "Skip interactive prompts, use all defaults").action(async (opts) => {
753
786
  const stageCheck = validateStage(opts.stage);
754
787
  if (!stageCheck.valid) {
755
788
  printError(stageCheck.error);
@@ -766,38 +799,88 @@ function registerInitCommand(program2) {
766
799
  const tfvarsPath = join(tfDir, "terraform.tfvars");
767
800
  if (existsSync3(tfvarsPath)) {
768
801
  printWarning(`terraform.tfvars already exists at ${tfvarsPath}`);
769
- const overwrite = await ask2(" Overwrite? [y/N]");
802
+ const overwrite = await ask2("Overwrite?", "N");
770
803
  if (overwrite.toLowerCase() !== "y") {
771
804
  console.log(" Aborted.");
772
805
  return;
773
806
  }
807
+ console.log("");
808
+ }
809
+ const config = {
810
+ stage: opts.stage,
811
+ account_id: identity.account,
812
+ db_password: generateSecret(24),
813
+ api_auth_secret: `tw-${opts.stage}-${generateSecret(16)}`
814
+ };
815
+ if (opts.defaults) {
816
+ config.region = identity.region !== "unknown" ? identity.region : "us-east-1";
817
+ config.database_engine = "aurora-serverless";
818
+ config.memory_engine = "managed";
819
+ config.google_oauth_client_id = "";
820
+ config.google_oauth_client_secret = "";
821
+ config.admin_url = "http://localhost:5174";
822
+ config.mobile_scheme = "thinkwork";
823
+ } else {
824
+ console.log(chalk3.bold(" Configure your Thinkwork environment\n"));
825
+ const defaultRegion = identity.region !== "unknown" ? identity.region : "us-east-1";
826
+ config.region = await ask2("AWS Region", defaultRegion);
827
+ console.log("");
828
+ console.log(chalk3.dim(" \u2500\u2500 Database \u2500\u2500"));
829
+ config.database_engine = await choose("Database engine", ["aurora-serverless", "rds-postgres"], "aurora-serverless");
830
+ console.log("");
831
+ console.log(chalk3.dim(" \u2500\u2500 Memory \u2500\u2500"));
832
+ console.log(chalk3.dim(" managed = Built-in AgentCore memory (remember/recall/forget)"));
833
+ console.log(chalk3.dim(" hindsight = ECS Fargate service with semantic + graph retrieval"));
834
+ config.memory_engine = await choose("Memory engine", ["managed", "hindsight"], "managed");
835
+ console.log("");
836
+ console.log(chalk3.dim(" \u2500\u2500 Auth \u2500\u2500"));
837
+ const useGoogle = await ask2("Enable Google OAuth login? (y/N)", "N");
838
+ if (useGoogle.toLowerCase() === "y") {
839
+ config.google_oauth_client_id = await ask2("Google OAuth Client ID");
840
+ config.google_oauth_client_secret = await ask2("Google OAuth Client Secret");
841
+ } else {
842
+ config.google_oauth_client_id = "";
843
+ config.google_oauth_client_secret = "";
844
+ }
845
+ console.log("");
846
+ console.log(chalk3.dim(" \u2500\u2500 Frontend URLs \u2500\u2500"));
847
+ config.admin_url = await ask2("Admin UI URL", "http://localhost:5174");
848
+ config.mobile_scheme = await ask2("Mobile app URL scheme", "thinkwork");
849
+ console.log("");
850
+ console.log(chalk3.dim(" \u2500\u2500 Secrets (auto-generated) \u2500\u2500"));
851
+ console.log(chalk3.dim(` DB password: ${config.db_password.slice(0, 8)}...`));
852
+ console.log(chalk3.dim(` API auth secret: ${config.api_auth_secret.slice(0, 16)}...`));
774
853
  }
775
- console.log(" Configure your Thinkwork environment:\n");
776
- const region = await ask2(" AWS Region", identity.region !== "unknown" ? identity.region : "us-east-1");
777
- const memoryEngine = await ask2(" Memory engine (managed/hindsight)", "managed");
778
- const dbPassword = generatePassword();
779
- const apiSecret = `tw-${opts.stage}-${generatePassword().slice(0, 12)}`;
780
854
  if (!existsSync3(tfDir)) {
781
855
  mkdirSync(tfDir, { recursive: true });
782
856
  }
783
- const tfvars = TFVARS_TEMPLATE.replace(/{STAGE}/g, opts.stage).replace(/{REGION}/g, region).replace(/{ACCOUNT_ID}/g, identity.account).replace(/{DB_PASSWORD}/g, dbPassword).replace(/{MEMORY_ENGINE}/g, memoryEngine).replace(/{API_SECRET}/g, apiSecret);
857
+ const tfvars = buildTfvars(config);
784
858
  writeFileSync2(tfvarsPath, tfvars);
785
- console.log(`
786
- Wrote ${tfvarsPath}`);
859
+ console.log("");
860
+ console.log(` Wrote ${chalk3.cyan(tfvarsPath)}`);
861
+ console.log("");
862
+ 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"));
863
+ console.log(` ${chalk3.bold("Stage:")} ${config.stage}`);
864
+ console.log(` ${chalk3.bold("Region:")} ${config.region}`);
865
+ console.log(` ${chalk3.bold("Account:")} ${config.account_id}`);
866
+ console.log(` ${chalk3.bold("Database:")} ${config.database_engine}`);
867
+ console.log(` ${chalk3.bold("Memory:")} ${config.memory_engine}`);
868
+ console.log(` ${chalk3.bold("Google OAuth:")} ${config.google_oauth_client_id ? "enabled" : "disabled"}`);
869
+ 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"));
787
870
  console.log("\n Initializing Terraform...\n");
788
871
  try {
789
872
  execSync4("terraform init", { cwd: tfDir, stdio: "inherit" });
790
873
  } catch {
791
- printWarning("Terraform init failed \u2014 you may need to install Terraform first.");
792
- printWarning("Run: thinkwork doctor -s " + opts.stage);
874
+ printWarning("Terraform init failed. Run `thinkwork doctor -s " + opts.stage + "` to check prerequisites.");
793
875
  return;
794
876
  }
795
877
  printSuccess(`Environment "${opts.stage}" initialized`);
796
878
  console.log("");
797
879
  console.log(" Next steps:");
798
- console.log(` 1. thinkwork plan -s ${opts.stage} # Review the plan`);
799
- console.log(` 2. thinkwork deploy -s ${opts.stage} # Deploy infrastructure`);
800
- console.log(` 3. thinkwork bootstrap -s ${opts.stage} # Seed workspace + skills`);
880
+ console.log(` ${chalk3.cyan("1.")} thinkwork plan -s ${opts.stage} ${chalk3.dim("# Review infrastructure plan")}`);
881
+ console.log(` ${chalk3.cyan("2.")} thinkwork deploy -s ${opts.stage} ${chalk3.dim("# Deploy to AWS")}`);
882
+ console.log(` ${chalk3.cyan("3.")} thinkwork bootstrap -s ${opts.stage} ${chalk3.dim("# Seed workspace files + skills")}`);
883
+ console.log(` ${chalk3.cyan("4.")} thinkwork outputs -s ${opts.stage} ${chalk3.dim("# Show API URL, Cognito IDs, etc.")}`);
801
884
  console.log("");
802
885
  });
803
886
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkwork-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Thinkwork CLI — deploy, manage, and interact with your Thinkwork stack",
5
5
  "license": "MIT",
6
6
  "type": "module",