@hasna/connectors 0.2.5 → 0.2.7

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 (75) hide show
  1. package/README.md +6 -0
  2. package/bin/index.js +353 -3
  3. package/bin/mcp.js +1 -1
  4. package/connectors/connect-anthropic/AGENTS.md +22 -0
  5. package/connectors/connect-anthropic/CLAUDE.md +29 -0
  6. package/connectors/connect-anthropic/README.md +22 -3
  7. package/connectors/connect-anthropic/src/types/index.ts +46 -2
  8. package/connectors/connect-aws/CLAUDE.md +16 -0
  9. package/connectors/connect-brandsight/CLAUDE.md +5 -0
  10. package/connectors/connect-cloudflare/CLAUDE.md +21 -0
  11. package/connectors/connect-discord/CLAUDE.md +19 -0
  12. package/connectors/connect-docker/CLAUDE.md +8 -0
  13. package/connectors/connect-e2b/CLAUDE.md +21 -0
  14. package/connectors/connect-elevenlabs/CLAUDE.md +24 -0
  15. package/connectors/connect-exa/CLAUDE.md +35 -0
  16. package/connectors/connect-figma/CLAUDE.md +34 -0
  17. package/connectors/connect-firecrawl/CLAUDE.md +27 -0
  18. package/connectors/connect-github/CLAUDE.md +32 -2
  19. package/connectors/connect-gmail/CLAUDE.md +22 -0
  20. package/connectors/connect-google/CLAUDE.md +11 -0
  21. package/connectors/connect-googlecalendar/CLAUDE.md +9 -0
  22. package/connectors/connect-googlecloud/CLAUDE.md +12 -0
  23. package/connectors/connect-googlecontacts/CLAUDE.md +7 -0
  24. package/connectors/connect-googledocs/CLAUDE.md +7 -0
  25. package/connectors/connect-googledrive/CLAUDE.md +5 -0
  26. package/connectors/connect-googlegemini/CLAUDE.md +18 -0
  27. package/connectors/connect-googlegemini/src/types/index.ts +10 -3
  28. package/connectors/connect-googlemaps/CLAUDE.md +15 -0
  29. package/connectors/connect-googlesheets/CLAUDE.md +10 -0
  30. package/connectors/connect-googletasks/CLAUDE.md +6 -0
  31. package/connectors/connect-hedra/CLAUDE.md +15 -0
  32. package/connectors/connect-heygen/CLAUDE.md +14 -0
  33. package/connectors/connect-huggingface/CLAUDE.md +20 -0
  34. package/connectors/connect-icons8/CLAUDE.md +6 -0
  35. package/connectors/connect-maropost/CLAUDE.md +6 -0
  36. package/connectors/connect-mercury/CLAUDE.md +14 -0
  37. package/connectors/connect-meta/CLAUDE.md +16 -0
  38. package/connectors/connect-midjourney/CLAUDE.md +7 -0
  39. package/connectors/connect-mistral/CLAUDE.md +20 -0
  40. package/connectors/connect-mistral/src/types/index.ts +42 -7
  41. package/connectors/connect-mixpanel/CLAUDE.md +11 -0
  42. package/connectors/connect-notion/CLAUDE.md +30 -0
  43. package/connectors/connect-openai/AGENTS.md +15 -0
  44. package/connectors/connect-openai/CLAUDE.md +23 -0
  45. package/connectors/connect-openai/src/types/index.ts +36 -14
  46. package/connectors/connect-openweathermap/CLAUDE.md +8 -0
  47. package/connectors/connect-pandadoc/CLAUDE.md +18 -0
  48. package/connectors/connect-quo/CLAUDE.md +5 -0
  49. package/connectors/connect-reddit/CLAUDE.md +20 -0
  50. package/connectors/connect-reducto/CLAUDE.md +16 -0
  51. package/connectors/connect-resend/CLAUDE.md +21 -0
  52. package/connectors/connect-revolut/CLAUDE.md +17 -0
  53. package/connectors/connect-sedo/CLAUDE.md +6 -0
  54. package/connectors/connect-sentry/CLAUDE.md +11 -0
  55. package/connectors/connect-shadcn/CLAUDE.md +42 -0
  56. package/connectors/connect-shopify/CLAUDE.md +18 -0
  57. package/connectors/connect-snap/CLAUDE.md +6 -0
  58. package/connectors/connect-stabilityai/CLAUDE.md +13 -0
  59. package/connectors/connect-stripe/CLAUDE.md +19 -0
  60. package/connectors/connect-stripeatlas/CLAUDE.md +7 -0
  61. package/connectors/connect-substack/CLAUDE.md +6 -0
  62. package/connectors/connect-tiktok/CLAUDE.md +25 -0
  63. package/connectors/connect-tinker/CLAUDE.md +6 -0
  64. package/connectors/connect-twilio/CLAUDE.md +9 -0
  65. package/connectors/connect-uspto/CLAUDE.md +8 -0
  66. package/connectors/connect-webflow/CLAUDE.md +19 -0
  67. package/connectors/connect-wix/CLAUDE.md +20 -0
  68. package/connectors/connect-x/CLAUDE.md +15 -0
  69. package/connectors/connect-xads/CLAUDE.md +10 -0
  70. package/connectors/connect-xai/CLAUDE.md +15 -0
  71. package/connectors/connect-xai/src/types/index.ts +20 -4
  72. package/connectors/connect-youtube/CLAUDE.md +28 -0
  73. package/connectors/connect-zoom/CLAUDE.md +15 -0
  74. package/dist/lib/test-endpoints.d.ts +12 -0
  75. package/package.json +1 -1
package/README.md CHANGED
@@ -34,6 +34,8 @@ npx @hasna/connectors
34
34
 
35
35
  ```bash
36
36
  connectors install figma stripe github # Install connectors
37
+ connectors install --preset ai # Install a preset bundle
38
+ connectors install --category "AI & ML" # Install entire category
37
39
  connectors install figma --overwrite # Overwrite existing
38
40
  connectors remove figma # Remove a connector
39
41
  ```
@@ -49,6 +51,10 @@ connectors info stripe # Connector details
49
51
  connectors docs gmail # Auth, env vars, CLI docs
50
52
  connectors status # Auth status of installed connectors
51
53
  connectors doctor # Health check and troubleshooting
54
+ connectors test # Verify API keys with real requests
55
+ connectors whoami # Show setup summary
56
+ connectors env # Generate .env.example
57
+ connectors presets # List preset bundles
52
58
  ```
53
59
 
54
60
  ### Dashboard
package/bin/index.js CHANGED
@@ -6499,12 +6499,91 @@ init_auth();
6499
6499
  import { readdirSync as readdirSync4, existsSync as existsSync5, statSync as statSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
6500
6500
  import { homedir as homedir3 } from "os";
6501
6501
  import { join as join5, relative } from "path";
6502
+
6503
+ // src/lib/test-endpoints.ts
6504
+ var TEST_ENDPOINTS = {
6505
+ anthropic: {
6506
+ url: "https://api.anthropic.com/v1/models",
6507
+ headers: (key) => ({ "x-api-key": key, "anthropic-version": "2023-06-01" })
6508
+ },
6509
+ openai: {
6510
+ url: "https://api.openai.com/v1/models",
6511
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6512
+ },
6513
+ xai: {
6514
+ url: "https://api.x.ai/v1/models",
6515
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6516
+ },
6517
+ mistral: {
6518
+ url: "https://api.mistral.ai/v1/models",
6519
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6520
+ },
6521
+ github: {
6522
+ url: "https://api.github.com/user",
6523
+ headers: (key) => ({ Authorization: `Bearer ${key}`, "User-Agent": "connectors-cli" })
6524
+ },
6525
+ stripe: {
6526
+ url: "https://api.stripe.com/v1/balance",
6527
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6528
+ },
6529
+ figma: {
6530
+ url: "https://api.figma.com/v1/me",
6531
+ headers: (key) => ({ "X-Figma-Token": key })
6532
+ },
6533
+ discord: {
6534
+ url: "https://discord.com/api/v10/users/@me",
6535
+ headers: (key) => ({ Authorization: `Bot ${key}` })
6536
+ },
6537
+ resend: {
6538
+ url: "https://api.resend.com/domains",
6539
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6540
+ },
6541
+ notion: {
6542
+ url: "https://api.notion.com/v1/users/me",
6543
+ headers: (key) => ({ Authorization: `Bearer ${key}`, "Notion-Version": "2022-06-28" })
6544
+ },
6545
+ exa: {
6546
+ url: "https://api.exa.ai/search",
6547
+ method: "POST",
6548
+ headers: (key) => ({ "x-api-key": key, "Content-Type": "application/json" })
6549
+ },
6550
+ sentry: {
6551
+ url: "https://sentry.io/api/0/",
6552
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6553
+ },
6554
+ huggingface: {
6555
+ url: "https://huggingface.co/api/whoami-v2",
6556
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6557
+ },
6558
+ elevenlabs: {
6559
+ url: "https://api.elevenlabs.io/v1/user",
6560
+ headers: (key) => ({ "xi-api-key": key })
6561
+ },
6562
+ cloudflare: {
6563
+ url: "https://api.cloudflare.com/client/v4/user/tokens/verify",
6564
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6565
+ },
6566
+ mixpanel: {
6567
+ url: "https://mixpanel.com/api/app/me",
6568
+ headers: (key) => ({ Authorization: `Bearer ${key}` })
6569
+ }
6570
+ };
6571
+
6572
+ // src/cli/index.tsx
6502
6573
  import { createInterface } from "readline";
6503
6574
  import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
6504
6575
  loadConnectorVersions();
6505
6576
  var isTTY = process.stdout.isTTY ?? false;
6577
+ var PRESETS = {
6578
+ fullstack: { description: "Full-stack web app essentials", connectors: ["stripe", "github", "resend", "anthropic", "figma"] },
6579
+ ai: { description: "AI and ML models", connectors: ["anthropic", "openai", "xai", "mistral", "googlegemini", "elevenlabs"] },
6580
+ google: { description: "Google Workspace suite", connectors: ["gmail", "googledrive", "googledocs", "googlesheets", "googlecalendar", "googletasks", "googlecontacts"] },
6581
+ social: { description: "Social media platforms", connectors: ["x", "reddit", "youtube", "tiktok", "meta", "discord", "substack"] },
6582
+ devtools: { description: "Developer tooling", connectors: ["github", "docker", "sentry", "cloudflare", "e2b", "firecrawl"] },
6583
+ commerce: { description: "Commerce and finance", connectors: ["stripe", "shopify", "revolut", "mercury", "pandadoc"] }
6584
+ };
6506
6585
  var program2 = new Command;
6507
- program2.name("connectors").description("Install API connectors for your project").version("0.2.5");
6586
+ program2.name("connectors").description("Install API connectors for your project").version("0.2.7");
6508
6587
  program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
6509
6588
  if (!isTTY) {
6510
6589
  console.log(`Non-interactive environment detected. Use a subcommand:
@@ -6534,7 +6613,7 @@ function listFilesRecursive(dir, base = dir) {
6534
6613
  }
6535
6614
  return files;
6536
6615
  }
6537
- program2.command("install").alias("add").argument("[connectors...]", "Connectors to install").option("-o, --overwrite", "Overwrite existing connectors", false).option("-d, --dry-run", "Preview what would be installed without making changes", false).option("-c, --category <category>", "Install all connectors in a category").option("--json", "Output results as JSON", false).description("Install one or more connectors").action((connectors, options) => {
6616
+ program2.command("install").alias("add").argument("[connectors...]", "Connectors to install").option("-o, --overwrite", "Overwrite existing connectors", false).option("-d, --dry-run", "Preview what would be installed without making changes", false).option("-c, --category <category>", "Install all connectors in a category").option("--preset <preset>", "Install a preset bundle (e.g. ai, fullstack, google)").option("--json", "Output results as JSON", false).description("Install one or more connectors").action((connectors, options) => {
6538
6617
  if (options.category) {
6539
6618
  const category = CATEGORIES.find((c) => c.toLowerCase() === options.category.toLowerCase());
6540
6619
  if (!category) {
@@ -6550,6 +6629,20 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
6550
6629
  const categoryConnectors = getConnectorsByCategory(category).map((c) => c.name);
6551
6630
  connectors.push(...categoryConnectors);
6552
6631
  }
6632
+ if (options.preset) {
6633
+ const preset = PRESETS[options.preset.toLowerCase()];
6634
+ if (!preset) {
6635
+ if (options.json) {
6636
+ console.log(JSON.stringify({ error: `Unknown preset: ${options.preset}. Available: ${Object.keys(PRESETS).join(", ")}` }));
6637
+ } else {
6638
+ console.log(chalk2.red(`Unknown preset: ${options.preset}`));
6639
+ console.log(chalk2.dim(`Available: ${Object.keys(PRESETS).join(", ")}`));
6640
+ }
6641
+ process.exit(1);
6642
+ return;
6643
+ }
6644
+ connectors.push(...preset.connectors);
6645
+ }
6553
6646
  if (connectors.length === 0) {
6554
6647
  if (!isTTY) {
6555
6648
  console.error("Error: specify connectors to install. Example: connectors install figma stripe");
@@ -7653,7 +7746,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
7653
7746
  }
7654
7747
  });
7655
7748
  program2.command("upgrade").alias("self-update").option("--check", "Only check for updates, don't install", false).option("--json", "Output as JSON", false).description("Check for updates and upgrade to the latest version").action(async (options) => {
7656
- const currentVersion = "0.2.5";
7749
+ const currentVersion = "0.2.7";
7657
7750
  try {
7658
7751
  const res = await fetch("https://registry.npmjs.org/@hasna/connectors/latest");
7659
7752
  if (!res.ok)
@@ -7792,4 +7885,261 @@ complete -F _connectors connectors`);
7792
7885
  process.exit(1);
7793
7886
  }
7794
7887
  });
7888
+ program2.command("env").option("-o, --output <file>", "Write to file instead of stdout").option("--json", "Output as JSON", false).description("Generate .env.example from installed connectors' required env vars").action((options) => {
7889
+ const installed = getInstalledConnectors();
7890
+ if (installed.length === 0) {
7891
+ if (options.json) {
7892
+ console.log(JSON.stringify({ vars: [], connectors: [] }));
7893
+ } else {
7894
+ console.log(chalk2.dim("No connectors installed. Run: connectors install <name>"));
7895
+ }
7896
+ return;
7897
+ }
7898
+ const vars = [];
7899
+ const seen = new Set;
7900
+ for (const name of installed) {
7901
+ const docs = getConnectorDocs(name);
7902
+ if (!docs?.envVars)
7903
+ continue;
7904
+ for (const v of docs.envVars) {
7905
+ if (!seen.has(v.variable)) {
7906
+ seen.add(v.variable);
7907
+ vars.push({ variable: v.variable, description: v.description, connector: name });
7908
+ }
7909
+ }
7910
+ }
7911
+ if (options.json) {
7912
+ console.log(JSON.stringify({ vars, connectors: installed }, null, 2));
7913
+ return;
7914
+ }
7915
+ const lines = [
7916
+ "# Environment Variables",
7917
+ `# Generated by connectors env (${installed.length} installed connectors)`,
7918
+ "#"
7919
+ ];
7920
+ let lastConnector = "";
7921
+ for (const v of vars) {
7922
+ if (v.connector !== lastConnector) {
7923
+ lines.push("");
7924
+ lines.push(`# ${v.connector}`);
7925
+ lastConnector = v.connector;
7926
+ }
7927
+ if (v.description)
7928
+ lines.push(`# ${v.description}`);
7929
+ lines.push(`${v.variable}=`);
7930
+ }
7931
+ const output = lines.join(`
7932
+ `) + `
7933
+ `;
7934
+ if (options.output) {
7935
+ writeFileSync4(options.output, output);
7936
+ console.log(chalk2.green(`\u2713 Written to ${options.output} (${vars.length} variables)`));
7937
+ } else {
7938
+ console.log(output);
7939
+ }
7940
+ });
7941
+ program2.command("presets").option("--json", "Output as JSON", false).description("List available connector preset bundles").action((options) => {
7942
+ if (options.json) {
7943
+ console.log(JSON.stringify(Object.entries(PRESETS).map(([name, p]) => ({
7944
+ name,
7945
+ description: p.description,
7946
+ connectors: p.connectors,
7947
+ count: p.connectors.length
7948
+ })), null, 2));
7949
+ return;
7950
+ }
7951
+ console.log(chalk2.bold(`
7952
+ Available presets:
7953
+ `));
7954
+ for (const [name, preset] of Object.entries(PRESETS)) {
7955
+ console.log(` ${chalk2.cyan(name.padEnd(12))} ${preset.description}`);
7956
+ console.log(chalk2.dim(` ${"".padEnd(12)} ${preset.connectors.join(", ")}`));
7957
+ console.log();
7958
+ }
7959
+ console.log(chalk2.dim(` Install with: connectors install --preset <name>
7960
+ `));
7961
+ });
7962
+ program2.command("whoami").option("--json", "Output as JSON", false).description("Show current setup: config dir, installed connectors, auth status").action((options) => {
7963
+ const configDir = join5(homedir3(), ".connectors");
7964
+ const installed = getInstalledConnectors();
7965
+ const version = "0.2.7";
7966
+ let configured = 0;
7967
+ let unconfigured = 0;
7968
+ const connectorDetails = [];
7969
+ for (const name of installed) {
7970
+ const auth = getAuthStatus(name);
7971
+ if (auth.configured)
7972
+ configured++;
7973
+ else
7974
+ unconfigured++;
7975
+ const connectorConfigDir = join5(configDir, name.startsWith("connect-") ? name : `connect-${name}`);
7976
+ const currentProfileFile = join5(connectorConfigDir, "current_profile");
7977
+ let profile = "default";
7978
+ if (existsSync5(currentProfileFile)) {
7979
+ try {
7980
+ profile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
7981
+ } catch {}
7982
+ }
7983
+ connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile });
7984
+ }
7985
+ if (options.json) {
7986
+ console.log(JSON.stringify({
7987
+ version,
7988
+ configDir,
7989
+ configDirExists: existsSync5(configDir),
7990
+ installed: installed.length,
7991
+ configured,
7992
+ unconfigured,
7993
+ connectors: connectorDetails
7994
+ }, null, 2));
7995
+ return;
7996
+ }
7997
+ console.log(chalk2.bold(`
7998
+ Connectors Setup
7999
+ `));
8000
+ console.log(` Version: ${chalk2.cyan(version)}`);
8001
+ console.log(` Config: ${configDir}${existsSync5(configDir) ? "" : chalk2.dim(" (not created yet)")}`);
8002
+ console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
8003
+ console.log(` Configured: ${chalk2.green(String(configured))} ready, ${unconfigured > 0 ? chalk2.red(String(unconfigured)) : chalk2.dim("0")} need auth`);
8004
+ if (connectorDetails.length > 0) {
8005
+ console.log(chalk2.bold(`
8006
+ Connectors:
8007
+ `));
8008
+ const nameWidth = Math.max(10, ...connectorDetails.map((c) => c.name.length)) + 2;
8009
+ for (const c of connectorDetails) {
8010
+ const status = c.configured ? chalk2.green("\u2713") : chalk2.red("\u2717");
8011
+ const profileLabel = c.profile !== "default" ? chalk2.dim(` [${c.profile}]`) : "";
8012
+ console.log(` ${status} ${chalk2.cyan(c.name.padEnd(nameWidth))}${c.authType.padEnd(8)}${profileLabel}`);
8013
+ }
8014
+ }
8015
+ console.log();
8016
+ });
8017
+ program2.command("test").argument("[connector]", "Connector to test (default: all installed)").option("--json", "Output as JSON", false).option("--timeout <ms>", "Request timeout in milliseconds", "10000").description("Verify API credentials by making a real request to the connector's API").action(async (connector, options) => {
8018
+ const timeout = parseInt(options.timeout, 10) || 1e4;
8019
+ const installed = getInstalledConnectors();
8020
+ let toTest;
8021
+ if (connector) {
8022
+ if (!getConnector(connector)) {
8023
+ if (options.json) {
8024
+ console.log(JSON.stringify({ error: `Connector '${connector}' not found` }));
8025
+ } else {
8026
+ console.log(chalk2.red(`Connector '${connector}' not found`));
8027
+ }
8028
+ process.exit(1);
8029
+ return;
8030
+ }
8031
+ toTest = [connector];
8032
+ } else {
8033
+ if (installed.length === 0) {
8034
+ if (options.json) {
8035
+ console.log(JSON.stringify({ results: [], tested: 0 }));
8036
+ } else {
8037
+ console.log(chalk2.dim("No connectors installed. Run: connectors install <name>"));
8038
+ }
8039
+ return;
8040
+ }
8041
+ toTest = installed;
8042
+ }
8043
+ if (!options.json)
8044
+ console.log(chalk2.bold(`
8045
+ Testing connector credentials...
8046
+ `));
8047
+ const results = [];
8048
+ for (const name of toTest) {
8049
+ const auth = getAuthStatus(name);
8050
+ const endpoint = TEST_ENDPOINTS[name];
8051
+ if (!auth.configured) {
8052
+ results.push({ name, status: "no-key", message: "No credentials configured" });
8053
+ if (!options.json)
8054
+ console.log(` ${chalk2.dim("\u25CB")} ${chalk2.dim(name)} \u2014 ${chalk2.dim("no credentials configured")}`);
8055
+ continue;
8056
+ }
8057
+ if (!endpoint) {
8058
+ results.push({ name, status: "skip", message: "No test endpoint defined" });
8059
+ if (!options.json)
8060
+ console.log(` ${chalk2.dim("\u25CB")} ${chalk2.dim(name)} \u2014 ${chalk2.dim("no test endpoint (key exists)")}`);
8061
+ continue;
8062
+ }
8063
+ const docs = getConnectorDocs(name);
8064
+ const envVars = docs?.envVars || [];
8065
+ let apiKey;
8066
+ for (const v of envVars) {
8067
+ if (process.env[v.variable]) {
8068
+ apiKey = process.env[v.variable];
8069
+ break;
8070
+ }
8071
+ }
8072
+ if (!apiKey) {
8073
+ const connectorConfigDir = join5(homedir3(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
8074
+ const profileFile = join5(connectorConfigDir, "profiles", "default.json");
8075
+ if (existsSync5(profileFile)) {
8076
+ try {
8077
+ const config = JSON.parse(readFileSync5(profileFile, "utf-8"));
8078
+ apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
8079
+ } catch {}
8080
+ }
8081
+ if (!apiKey) {
8082
+ const profileDirConfig = join5(connectorConfigDir, "profiles", "default", "config.json");
8083
+ if (existsSync5(profileDirConfig)) {
8084
+ try {
8085
+ const config = JSON.parse(readFileSync5(profileDirConfig, "utf-8"));
8086
+ apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
8087
+ } catch {}
8088
+ }
8089
+ }
8090
+ }
8091
+ if (!apiKey) {
8092
+ results.push({ name, status: "no-key", message: "Credentials configured but could not extract key" });
8093
+ if (!options.json)
8094
+ console.log(` ${chalk2.yellow("\u26A0")} ${chalk2.yellow(name)} \u2014 ${chalk2.dim("could not extract key")}`);
8095
+ continue;
8096
+ }
8097
+ const start = Date.now();
8098
+ try {
8099
+ const res = await fetch(endpoint.url, {
8100
+ method: endpoint.method || "GET",
8101
+ headers: endpoint.headers(apiKey),
8102
+ body: endpoint.method === "POST" ? JSON.stringify({ query: "test", num_results: 1 }) : undefined,
8103
+ signal: AbortSignal.timeout(timeout)
8104
+ });
8105
+ const ms = Date.now() - start;
8106
+ const successCodes = endpoint.successCodes || [200];
8107
+ if (successCodes.includes(res.status) || res.status >= 200 && res.status < 300) {
8108
+ results.push({ name, status: "pass", message: `OK (${res.status})`, ms });
8109
+ if (!options.json)
8110
+ console.log(` ${chalk2.green("\u2713")} ${chalk2.green(name)} \u2014 ${chalk2.dim(`${res.status} OK`)} ${chalk2.dim(`(${ms}ms)`)}`);
8111
+ } else {
8112
+ const body = await res.text().catch(() => "");
8113
+ const msg = res.status === 401 ? "Invalid or expired credentials" : `HTTP ${res.status}`;
8114
+ results.push({ name, status: "fail", message: msg, ms });
8115
+ if (!options.json)
8116
+ console.log(` ${chalk2.red("\u2717")} ${chalk2.red(name)} \u2014 ${chalk2.red(msg)} ${chalk2.dim(`(${ms}ms)`)}`);
8117
+ }
8118
+ } catch (e) {
8119
+ const ms = Date.now() - start;
8120
+ const msg = e instanceof Error ? e.message : String(e);
8121
+ results.push({ name, status: "fail", message: msg, ms });
8122
+ if (!options.json)
8123
+ console.log(` ${chalk2.red("\u2717")} ${chalk2.red(name)} \u2014 ${chalk2.red(msg)}`);
8124
+ }
8125
+ }
8126
+ if (options.json) {
8127
+ console.log(JSON.stringify({ results, tested: results.length, passed: results.filter((r) => r.status === "pass").length }, null, 2));
8128
+ } else {
8129
+ const passed = results.filter((r) => r.status === "pass").length;
8130
+ const failed = results.filter((r) => r.status === "fail").length;
8131
+ const skipped = results.filter((r) => r.status === "skip" || r.status === "no-key").length;
8132
+ console.log();
8133
+ const parts = [];
8134
+ if (passed > 0)
8135
+ parts.push(chalk2.green(`${passed} passed`));
8136
+ if (failed > 0)
8137
+ parts.push(chalk2.red(`${failed} failed`));
8138
+ if (skipped > 0)
8139
+ parts.push(chalk2.dim(`${skipped} skipped`));
8140
+ console.log(` ${parts.join(", ")}
8141
+ `);
8142
+ }
8143
+ process.exit(results.some((r) => r.status === "fail") ? 1 : 0);
8144
+ });
7795
8145
  program2.parse();
package/bin/mcp.js CHANGED
@@ -20275,7 +20275,7 @@ function guessKeyField(name) {
20275
20275
  loadConnectorVersions();
20276
20276
  var server = new McpServer({
20277
20277
  name: "connectors",
20278
- version: "0.2.5"
20278
+ version: "0.2.7"
20279
20279
  });
20280
20280
  server.registerTool("search_connectors", {
20281
20281
  title: "Search Connectors",
@@ -47,6 +47,28 @@ src/
47
47
  └── index.ts # Library exports
48
48
  ```
49
49
 
50
+ ## Models (2026)
51
+
52
+ | Model ID | Description |
53
+ |----------|-------------|
54
+ | `claude-opus-4-6` | Most intelligent (default for complex tasks), 200K ctx, 128K output |
55
+ | `claude-sonnet-4-6` | Best balance — **use this as default** |
56
+ | `claude-opus-4-20250514` | Claude 4 Opus (2025) |
57
+ | `claude-sonnet-4-20250514` | Claude 4 Sonnet (2025) |
58
+ | `claude-3-5-haiku-20241022` | Fast, cheap |
59
+
60
+ Default: `claude-sonnet-4-6`
61
+
62
+ ## Adaptive Thinking
63
+
64
+ On `claude-opus-4-6` and `claude-sonnet-4-6`, use:
65
+ ```typescript
66
+ thinking: { type: 'adaptive' } // Claude decides when to think
67
+ thinking: { type: 'adaptive', effort: 'low' } // less thinking
68
+ thinking: { type: 'adaptive', effort: 'high' } // most thinking (default)
69
+ ```
70
+ Deprecated on 4.6: `thinking: { type: 'enabled', budget_tokens: N }`
71
+
50
72
  ## Authentication
51
73
 
52
74
  Bearer Token authentication. Credentials can be set via:
@@ -47,6 +47,35 @@ src/
47
47
  └── index.ts # Library exports
48
48
  ```
49
49
 
50
+ ## Models (2026)
51
+
52
+ | Model ID | Description |
53
+ |----------|-------------|
54
+ | `claude-opus-4-6` | Most intelligent, 200K context (1M beta), 128K max output, adaptive thinking |
55
+ | `claude-sonnet-4-6` | Best speed/intelligence balance, 200K context (1M beta), 64K max output |
56
+ | `claude-opus-4-20250514` | Claude 4 Opus (2025) |
57
+ | `claude-sonnet-4-20250514` | Claude 4 Sonnet (2025) |
58
+ | `claude-3-5-haiku-20241022` | Fast and cost-effective |
59
+ | `claude-3-5-sonnet-20241022` | Claude 3.5 Sonnet |
60
+
61
+ Default model: `claude-sonnet-4-6`
62
+
63
+ ## Adaptive Thinking (claude-opus-4-6 / claude-sonnet-4-6)
64
+
65
+ Use adaptive thinking to let Claude decide when and how much to think:
66
+
67
+ ```typescript
68
+ const response = await client.messages.create({
69
+ model: 'claude-opus-4-6',
70
+ max_tokens: 16000,
71
+ thinking: { type: 'adaptive' }, // default effort: high
72
+ thinking: { type: 'adaptive', effort: 'low' }, // less thinking for simple problems
73
+ messages: [{ role: 'user', content: '...' }],
74
+ });
75
+ ```
76
+
77
+ Note: `thinking: {type: "enabled", budget_tokens: N}` is deprecated on 4.6 models. Use adaptive thinking instead.
78
+
50
79
  ## Authentication
51
80
 
52
81
  Bearer Token authentication. Credentials can be set via:
@@ -56,6 +56,18 @@ connect-anthropic -p personal <command>
56
56
  connect-anthropic profile list
57
57
  ```
58
58
 
59
+ ## Models (2026)
60
+
61
+ | Model ID | Context | Description |
62
+ |----------|---------|-------------|
63
+ | `claude-opus-4-6` | 200K (1M beta) | Most intelligent, adaptive thinking |
64
+ | `claude-sonnet-4-6` | 200K (1M beta) | Best speed/intelligence balance |
65
+ | `claude-opus-4-20250514` | 200K | Claude 4 Opus |
66
+ | `claude-sonnet-4-20250514` | 200K | Claude 4 Sonnet |
67
+ | `claude-3-5-haiku-20241022` | 200K | Fast, cost-effective |
68
+
69
+ Default: `claude-sonnet-4-6`
70
+
59
71
  ## Library Usage
60
72
 
61
73
  ```typescript
@@ -63,8 +75,15 @@ import { Anthropic } from '@hasna/connect-anthropic';
63
75
 
64
76
  const client = new Anthropic({ apiKey: 'YOUR_API_KEY' });
65
77
 
66
- // Use the client
67
- // See CLAUDE.md for detailed API documentation
78
+ // Basic chat
79
+ const response = await client.chat('Explain quantum computing');
80
+
81
+ // With adaptive thinking (claude-opus-4-6 / claude-sonnet-4-6)
82
+ const response = await client.chat('Solve this hard problem', {
83
+ model: 'claude-opus-4-6',
84
+ thinking: { type: 'adaptive' },
85
+ maxTokens: 16000,
86
+ });
68
87
  ```
69
88
 
70
89
  ## Environment Variables
@@ -103,4 +122,4 @@ bun run typecheck
103
122
 
104
123
  ## License
105
124
 
106
- MIT
125
+ Apache-2.0
@@ -14,25 +14,37 @@ export interface AnthropicConfig {
14
14
  // ============================================
15
15
 
16
16
  export type AnthropicModel =
17
+ // Claude 4.6 (latest, 2026)
18
+ | 'claude-opus-4-6'
19
+ | 'claude-sonnet-4-6'
20
+ // Claude 4 (2025)
17
21
  | 'claude-opus-4-20250514'
18
22
  | 'claude-sonnet-4-20250514'
23
+ // Claude 3.5
19
24
  | 'claude-3-5-haiku-20241022'
20
25
  | 'claude-3-5-sonnet-20241022'
26
+ // Claude 3 (legacy)
21
27
  | 'claude-3-opus-20240229'
22
28
  | 'claude-3-sonnet-20240229'
23
29
  | 'claude-3-haiku-20240307';
24
30
 
25
31
  export const ANTHROPIC_MODELS: AnthropicModel[] = [
32
+ // Claude 4.6 (latest, 2026)
33
+ 'claude-opus-4-6',
34
+ 'claude-sonnet-4-6',
35
+ // Claude 4 (2025)
26
36
  'claude-opus-4-20250514',
27
37
  'claude-sonnet-4-20250514',
38
+ // Claude 3.5
28
39
  'claude-3-5-haiku-20241022',
29
40
  'claude-3-5-sonnet-20241022',
41
+ // Claude 3 (legacy)
30
42
  'claude-3-opus-20240229',
31
43
  'claude-3-sonnet-20240229',
32
44
  'claude-3-haiku-20240307',
33
45
  ];
34
46
 
35
- export const DEFAULT_MODEL: AnthropicModel = 'claude-sonnet-4-20250514';
47
+ export const DEFAULT_MODEL: AnthropicModel = 'claude-sonnet-4-6';
36
48
 
37
49
  // ============================================
38
50
  // Messages API
@@ -71,6 +83,7 @@ export interface MessagesRequest {
71
83
  top_k?: number;
72
84
  stop_sequences?: string[];
73
85
  stream?: boolean;
86
+ thinking?: ThinkingConfig;
74
87
  metadata?: {
75
88
  user_id?: string;
76
89
  };
@@ -81,6 +94,16 @@ export interface TextBlock {
81
94
  text: string;
82
95
  }
83
96
 
97
+ export interface ThinkingBlock {
98
+ type: 'thinking';
99
+ thinking: string;
100
+ }
101
+
102
+ export interface RedactedThinkingBlock {
103
+ type: 'redacted_thinking';
104
+ data: string;
105
+ }
106
+
84
107
  export interface ToolUseBlock {
85
108
  type: 'tool_use';
86
109
  id: string;
@@ -88,7 +111,27 @@ export interface ToolUseBlock {
88
111
  input: Record<string, unknown>;
89
112
  }
90
113
 
91
- export type ResponseContentBlock = TextBlock | ToolUseBlock;
114
+ export type ResponseContentBlock = TextBlock | ThinkingBlock | RedactedThinkingBlock | ToolUseBlock;
115
+
116
+ // ============================================
117
+ // Thinking (Extended / Adaptive)
118
+ // ============================================
119
+
120
+ export type ThinkingEffort = 'low' | 'medium' | 'high';
121
+
122
+ /** Adaptive thinking (recommended for claude-opus-4-6 and claude-sonnet-4-6) */
123
+ export interface AdaptiveThinking {
124
+ type: 'adaptive';
125
+ effort?: ThinkingEffort;
126
+ budget_tokens?: number;
127
+ }
128
+
129
+ /** Disabled thinking */
130
+ export interface DisabledThinking {
131
+ type: 'disabled';
132
+ }
133
+
134
+ export type ThinkingConfig = AdaptiveThinking | DisabledThinking;
92
135
 
93
136
  export interface MessagesResponse {
94
137
  id: string;
@@ -168,6 +211,7 @@ export interface ChatOptions {
168
211
  topK?: number;
169
212
  stopSequences?: string[];
170
213
  systemPrompt?: string;
214
+ thinking?: ThinkingConfig;
171
215
  }
172
216
 
173
217
  // ============================================
@@ -47,6 +47,22 @@ src/
47
47
  └── index.ts # Library exports
48
48
  ```
49
49
 
50
+ ## Auth Updates (2025-2026)
51
+
52
+ ### Amazon Bedrock API Keys (GA Jul 2025, GovCloud Jan 2026)
53
+ Bedrock now supports direct API keys for authentication — no IAM principal setup required:
54
+ - Short-term keys: valid for console session or up to 12 hours
55
+ - Long-term keys: custom validity, managed from IAM console
56
+ - Generate from Bedrock console or AWS SDK
57
+
58
+ ### IAM Role Creation in Service Workflows (Mar 2026)
59
+ IAM roles can now be created and customized inline within service workflows (no tab-switching). Available for EC2, Lambda, EKS, ECS, Glue, CloudFormation, DMS, Systems Manager, Secrets Manager, RDS, IoT Core. US East (N. Virginia) region first.
60
+
61
+ ### Best Practice: Use IAM Roles, Not Access Keys
62
+ - Prefer IAM roles with temporary credentials over long-term access keys
63
+ - Use `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` + `AWS_REGION` for programmatic access
64
+ - Or use IAM Instance Roles / ECS Task Roles for zero-key auth in cloud environments
65
+
50
66
  ## Authentication
51
67
 
52
68
  API Key authentication. Credentials can be set via:
@@ -47,6 +47,11 @@ src/
47
47
  └── index.ts # Library exports
48
48
  ```
49
49
 
50
+ ## API Notes (2026)
51
+
52
+ Brandsight provides brand monitoring and analytics APIs. Check https://brandsight.com/docs for current API reference.
53
+ Auth: API key via header or query parameter.
54
+
50
55
  ## Authentication
51
56
 
52
57
  SSO Key authentication. Credentials can be set via: