@hasna/connectors 0.0.1 → 0.0.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.
Files changed (3) hide show
  1. package/bin/index.js +420 -113
  2. package/dist/index.js +55 -19
  3. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -3952,6 +3952,9 @@ function Header({ title = "Connectors", subtitle }) {
3952
3952
  import { Box as Box4, Text as Text4 } from "ink";
3953
3953
 
3954
3954
  // src/lib/registry.ts
3955
+ import { existsSync, readFileSync } from "fs";
3956
+ import { join, dirname } from "path";
3957
+ import { fileURLToPath } from "url";
3955
3958
  var CATEGORIES = [
3956
3959
  "AI & ML",
3957
3960
  "Developer Tools",
@@ -4415,6 +4418,29 @@ function searchConnectors(query) {
4415
4418
  const q = query.toLowerCase();
4416
4419
  return CONNECTORS.filter((c) => c.name.toLowerCase().includes(q) || c.displayName.toLowerCase().includes(q) || c.description.toLowerCase().includes(q) || c.tags.some((t) => t.includes(q)));
4417
4420
  }
4421
+ var versionsLoaded = false;
4422
+ function loadConnectorVersions() {
4423
+ if (versionsLoaded)
4424
+ return;
4425
+ versionsLoaded = true;
4426
+ const thisDir = dirname(fileURLToPath(import.meta.url));
4427
+ const candidates = [
4428
+ join(thisDir, "..", "connectors"),
4429
+ join(thisDir, "..", "..", "connectors")
4430
+ ];
4431
+ const connectorsDir = candidates.find((d) => existsSync(d));
4432
+ if (!connectorsDir)
4433
+ return;
4434
+ for (const connector of CONNECTORS) {
4435
+ try {
4436
+ const pkgPath = join(connectorsDir, `connect-${connector.name}`, "package.json");
4437
+ if (existsSync(pkgPath)) {
4438
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
4439
+ connector.version = pkg.version || "0.0.0";
4440
+ }
4441
+ } catch {}
4442
+ }
4443
+ }
4418
4444
 
4419
4445
  // src/cli/components/CategorySelect.tsx
4420
4446
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
@@ -4450,9 +4476,12 @@ function CategorySelect({ onSelect, onBack }) {
4450
4476
  }
4451
4477
 
4452
4478
  // src/cli/components/ConnectorSelect.tsx
4453
- import { useState as useState2 } from "react";
4454
- import { Box as Box5, Text as Text5 } from "ink";
4455
- import { jsxDEV as jsxDEV3, Fragment } from "react/jsx-dev-runtime";
4479
+ import { useState as useState2, useMemo } from "react";
4480
+ import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
4481
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
4482
+ var COL_CHECK = 5;
4483
+ var COL_NAME = 20;
4484
+ var COL_VERSION = 10;
4456
4485
  function ConnectorSelect({
4457
4486
  connectors,
4458
4487
  selected,
@@ -4460,79 +4489,173 @@ function ConnectorSelect({
4460
4489
  onConfirm,
4461
4490
  onBack
4462
4491
  }) {
4463
- const items = [
4464
- { label: "\u2190 Back to categories", value: "__back__" },
4465
- ...connectors.map((c) => ({
4466
- label: `${selected.has(c.name) ? "[x]" : "[ ]"} ${c.displayName}`,
4467
- value: c.name
4468
- })),
4469
- { label: "", value: "__sep__" },
4470
- {
4471
- label: `\u2713 Install selected (${selected.size})`,
4472
- value: "__confirm__"
4473
- }
4474
- ];
4475
- const handleSelect = (item) => {
4476
- if (item.value === "__back__") {
4477
- onBack();
4478
- } else if (item.value === "__confirm__") {
4479
- if (selected.size > 0) {
4480
- onConfirm();
4492
+ const totalItems = connectors.length + 2;
4493
+ const [cursor, setCursor] = useState2(0);
4494
+ const maxVisible = 16;
4495
+ const scrollOffset = useMemo(() => {
4496
+ if (totalItems <= maxVisible)
4497
+ return 0;
4498
+ const half = Math.floor(maxVisible / 2);
4499
+ if (cursor < half)
4500
+ return 0;
4501
+ if (cursor > totalItems - maxVisible + half)
4502
+ return totalItems - maxVisible;
4503
+ return cursor - half;
4504
+ }, [cursor, totalItems]);
4505
+ useInput2((input, key) => {
4506
+ if (key.upArrow) {
4507
+ setCursor((c) => c > 0 ? c - 1 : totalItems - 1);
4508
+ } else if (key.downArrow) {
4509
+ setCursor((c) => c < totalItems - 1 ? c + 1 : 0);
4510
+ } else if (key.return) {
4511
+ if (cursor === 0) {
4512
+ onBack();
4513
+ } else if (cursor === totalItems - 1) {
4514
+ if (selected.size > 0)
4515
+ onConfirm();
4516
+ } else {
4517
+ onToggle(connectors[cursor - 1].name);
4481
4518
  }
4482
- } else if (item.value !== "__sep__") {
4483
- onToggle(item.value);
4519
+ } else if (input === " " && cursor > 0 && cursor < totalItems - 1) {
4520
+ onToggle(connectors[cursor - 1].name);
4484
4521
  }
4485
- };
4486
- const [highlightedIndex, setHighlightedIndex] = useState2(1);
4487
- const currentConnector = connectors[highlightedIndex - 1];
4522
+ });
4523
+ const visibleStart = scrollOffset;
4524
+ const visibleEnd = Math.min(scrollOffset + maxVisible, totalItems);
4488
4525
  return /* @__PURE__ */ jsxDEV3(Box5, {
4489
4526
  flexDirection: "column",
4490
4527
  children: [
4491
4528
  /* @__PURE__ */ jsxDEV3(Text5, {
4492
4529
  bold: true,
4493
4530
  marginBottom: 1,
4494
- children: "Select connectors (space to toggle, enter to confirm):"
4531
+ children: "Select connectors to install:"
4495
4532
  }, undefined, false, undefined, this),
4496
4533
  /* @__PURE__ */ jsxDEV3(Box5, {
4497
- flexDirection: "row",
4498
4534
  children: [
4499
4535
  /* @__PURE__ */ jsxDEV3(Box5, {
4500
- flexDirection: "column",
4501
- width: "50%",
4502
- children: /* @__PURE__ */ jsxDEV3(SelectInput_default, {
4503
- items,
4504
- onSelect: handleSelect,
4505
- onHighlight: (item) => {
4506
- const idx = connectors.findIndex((c) => c.name === item.value);
4507
- if (idx >= 0)
4508
- setHighlightedIndex(idx + 1);
4509
- }
4536
+ width: COL_CHECK,
4537
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4538
+ dimColor: true,
4539
+ children: " "
4510
4540
  }, undefined, false, undefined, this)
4511
4541
  }, undefined, false, undefined, this),
4512
4542
  /* @__PURE__ */ jsxDEV3(Box5, {
4513
- flexDirection: "column",
4514
- marginLeft: 2,
4515
- width: "50%",
4516
- children: currentConnector && /* @__PURE__ */ jsxDEV3(Fragment, {
4543
+ width: COL_NAME,
4544
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4545
+ bold: true,
4546
+ dimColor: true,
4547
+ children: "Connector"
4548
+ }, undefined, false, undefined, this)
4549
+ }, undefined, false, undefined, this),
4550
+ /* @__PURE__ */ jsxDEV3(Box5, {
4551
+ width: COL_VERSION,
4552
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4553
+ bold: true,
4554
+ dimColor: true,
4555
+ children: "Version"
4556
+ }, undefined, false, undefined, this)
4557
+ }, undefined, false, undefined, this),
4558
+ /* @__PURE__ */ jsxDEV3(Text5, {
4559
+ bold: true,
4560
+ dimColor: true,
4561
+ children: "Description"
4562
+ }, undefined, false, undefined, this)
4563
+ ]
4564
+ }, undefined, true, undefined, this),
4565
+ /* @__PURE__ */ jsxDEV3(Box5, {
4566
+ marginBottom: 0,
4567
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4568
+ dimColor: true,
4569
+ children: "\u2500".repeat(70)
4570
+ }, undefined, false, undefined, this)
4571
+ }, undefined, false, undefined, this),
4572
+ visibleStart > 0 && /* @__PURE__ */ jsxDEV3(Text5, {
4573
+ dimColor: true,
4574
+ children: [
4575
+ " \u2191 ",
4576
+ visibleStart,
4577
+ " more"
4578
+ ]
4579
+ }, undefined, true, undefined, this),
4580
+ Array.from({ length: visibleEnd - visibleStart }, (_, i) => {
4581
+ const idx = visibleStart + i;
4582
+ if (idx === 0) {
4583
+ const isActive2 = cursor === 0;
4584
+ return /* @__PURE__ */ jsxDEV3(Box5, {
4585
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4586
+ color: isActive2 ? "cyan" : undefined,
4587
+ bold: isActive2,
4517
4588
  children: [
4518
- /* @__PURE__ */ jsxDEV3(Text5, {
4519
- bold: true,
4520
- color: "cyan",
4521
- children: currentConnector.displayName
4522
- }, undefined, false, undefined, this),
4523
- /* @__PURE__ */ jsxDEV3(Text5, {
4524
- children: currentConnector.description
4525
- }, undefined, false, undefined, this),
4526
- /* @__PURE__ */ jsxDEV3(Text5, {
4527
- dimColor: true,
4528
- children: [
4529
- "Tags: ",
4530
- currentConnector.tags.join(", ")
4531
- ]
4532
- }, undefined, true, undefined, this)
4589
+ isActive2 ? "\u276F " : " ",
4590
+ "\u2190 Back to categories"
4533
4591
  ]
4534
4592
  }, undefined, true, undefined, this)
4535
- }, undefined, false, undefined, this)
4593
+ }, "__back__", false, undefined, this);
4594
+ }
4595
+ if (idx === totalItems - 1) {
4596
+ const isActive2 = cursor === totalItems - 1;
4597
+ const hasSelection = selected.size > 0;
4598
+ return /* @__PURE__ */ jsxDEV3(Box5, {
4599
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4600
+ color: isActive2 ? hasSelection ? "green" : "gray" : hasSelection ? "green" : "gray",
4601
+ bold: isActive2,
4602
+ dimColor: !hasSelection,
4603
+ children: [
4604
+ isActive2 ? "\u276F " : " ",
4605
+ "\u2713 Install selected (",
4606
+ selected.size,
4607
+ ")"
4608
+ ]
4609
+ }, undefined, true, undefined, this)
4610
+ }, "__confirm__", false, undefined, this);
4611
+ }
4612
+ const c = connectors[idx - 1];
4613
+ const isActive = cursor === idx;
4614
+ const isChecked = selected.has(c.name);
4615
+ return /* @__PURE__ */ jsxDEV3(Box5, {
4616
+ children: [
4617
+ /* @__PURE__ */ jsxDEV3(Box5, {
4618
+ width: 2,
4619
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4620
+ color: isActive ? "cyan" : undefined,
4621
+ children: isActive ? "\u276F" : " "
4622
+ }, undefined, false, undefined, this)
4623
+ }, undefined, false, undefined, this),
4624
+ /* @__PURE__ */ jsxDEV3(Box5, {
4625
+ width: COL_CHECK - 2,
4626
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4627
+ color: isChecked ? "green" : "gray",
4628
+ children: isChecked ? "[\u2713]" : "[ ]"
4629
+ }, undefined, false, undefined, this)
4630
+ }, undefined, false, undefined, this),
4631
+ /* @__PURE__ */ jsxDEV3(Box5, {
4632
+ width: COL_NAME,
4633
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4634
+ bold: isActive,
4635
+ color: isActive ? "cyan" : undefined,
4636
+ children: c.name
4637
+ }, undefined, false, undefined, this)
4638
+ }, undefined, false, undefined, this),
4639
+ /* @__PURE__ */ jsxDEV3(Box5, {
4640
+ width: COL_VERSION,
4641
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4642
+ dimColor: true,
4643
+ children: c.version || "-"
4644
+ }, undefined, false, undefined, this)
4645
+ }, undefined, false, undefined, this),
4646
+ /* @__PURE__ */ jsxDEV3(Text5, {
4647
+ wrap: "truncate",
4648
+ children: c.description
4649
+ }, undefined, false, undefined, this)
4650
+ ]
4651
+ }, c.name, true, undefined, this);
4652
+ }),
4653
+ visibleEnd < totalItems && /* @__PURE__ */ jsxDEV3(Text5, {
4654
+ dimColor: true,
4655
+ children: [
4656
+ " \u2193 ",
4657
+ totalItems - visibleEnd,
4658
+ " more"
4536
4659
  ]
4537
4660
  }, undefined, true, undefined, this),
4538
4661
  selected.size > 0 && /* @__PURE__ */ jsxDEV3(Box5, {
@@ -4544,13 +4667,20 @@ function ConnectorSelect({
4544
4667
  Array.from(selected).join(", ")
4545
4668
  ]
4546
4669
  }, undefined, true, undefined, this)
4670
+ }, undefined, false, undefined, this),
4671
+ /* @__PURE__ */ jsxDEV3(Box5, {
4672
+ marginTop: 1,
4673
+ children: /* @__PURE__ */ jsxDEV3(Text5, {
4674
+ dimColor: true,
4675
+ children: "\u2191\u2193 navigate space toggle enter confirm esc back"
4676
+ }, undefined, false, undefined, this)
4547
4677
  }, undefined, false, undefined, this)
4548
4678
  ]
4549
4679
  }, undefined, true, undefined, this);
4550
4680
  }
4551
4681
 
4552
4682
  // src/cli/components/SearchView.tsx
4553
- import { useState as useState4, useEffect as useEffect3 } from "react";
4683
+ import { useState as useState4, useEffect as useEffect3, useMemo as useMemo2 } from "react";
4554
4684
  import { Box as Box6, Text as Text7, useInput as useInput4 } from "ink";
4555
4685
 
4556
4686
  // node_modules/ink-text-input/build/index.js
@@ -4647,6 +4777,9 @@ var build_default = TextInput;
4647
4777
 
4648
4778
  // src/cli/components/SearchView.tsx
4649
4779
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
4780
+ var COL_CHECK2 = 5;
4781
+ var COL_NAME2 = 20;
4782
+ var COL_VERSION2 = 10;
4650
4783
  function SearchView({
4651
4784
  selected,
4652
4785
  onToggle,
@@ -4656,13 +4789,28 @@ function SearchView({
4656
4789
  const [query, setQuery] = useState4("");
4657
4790
  const [results, setResults] = useState4([]);
4658
4791
  const [mode, setMode] = useState4("search");
4792
+ const [cursor, setCursor] = useState4(0);
4659
4793
  useEffect3(() => {
4660
4794
  if (query.length >= 2) {
4661
4795
  setResults(searchConnectors(query));
4796
+ setCursor(0);
4662
4797
  } else {
4663
4798
  setResults([]);
4664
4799
  }
4665
4800
  }, [query]);
4801
+ const hasConfirm = selected.size > 0;
4802
+ const totalItems = results.length + 1 + (hasConfirm ? 1 : 0);
4803
+ const maxVisible = 14;
4804
+ const scrollOffset = useMemo2(() => {
4805
+ if (totalItems <= maxVisible)
4806
+ return 0;
4807
+ const half = Math.floor(maxVisible / 2);
4808
+ if (cursor < half)
4809
+ return 0;
4810
+ if (cursor > totalItems - maxVisible + half)
4811
+ return totalItems - maxVisible;
4812
+ return cursor - half;
4813
+ }, [cursor, totalItems]);
4666
4814
  useInput4((input, key) => {
4667
4815
  if (key.escape) {
4668
4816
  if (mode === "select") {
@@ -4670,34 +4818,43 @@ function SearchView({
4670
4818
  } else {
4671
4819
  onBack();
4672
4820
  }
4821
+ return;
4673
4822
  }
4674
- if (key.downArrow && mode === "search" && results.length > 0) {
4675
- setMode("select");
4823
+ if (mode === "search") {
4824
+ if (key.downArrow && results.length > 0) {
4825
+ setMode("select");
4826
+ setCursor(0);
4827
+ }
4828
+ return;
4676
4829
  }
4677
- });
4678
- const items = [
4679
- { label: "\u2190 Back", value: "__back__" },
4680
- ...results.map((c) => ({
4681
- label: `${selected.has(c.name) ? "[x]" : "[ ]"} ${c.displayName} - ${c.description}`,
4682
- value: c.name
4683
- }))
4684
- ];
4685
- if (selected.size > 0) {
4686
- items.push({ label: "", value: "__sep__" });
4687
- items.push({
4688
- label: `\u2713 Install selected (${selected.size})`,
4689
- value: "__confirm__"
4690
- });
4691
- }
4692
- const handleSelect = (item) => {
4693
- if (item.value === "__back__") {
4694
- onBack();
4695
- } else if (item.value === "__confirm__") {
4696
- onConfirm();
4697
- } else if (item.value !== "__sep__") {
4698
- onToggle(item.value);
4830
+ if (key.upArrow) {
4831
+ if (cursor === 0) {
4832
+ setMode("search");
4833
+ } else {
4834
+ setCursor((c) => c - 1);
4835
+ }
4836
+ } else if (key.downArrow) {
4837
+ setCursor((c) => c < totalItems - 1 ? c + 1 : c);
4838
+ } else if (key.return) {
4839
+ if (cursor === 0) {
4840
+ onBack();
4841
+ } else if (hasConfirm && cursor === totalItems - 1) {
4842
+ onConfirm();
4843
+ } else {
4844
+ const connectorIdx = cursor - 1;
4845
+ if (connectorIdx < results.length) {
4846
+ onToggle(results[connectorIdx].name);
4847
+ }
4848
+ }
4849
+ } else if (input === " " && cursor > 0) {
4850
+ const connectorIdx = cursor - 1;
4851
+ if (connectorIdx < results.length) {
4852
+ onToggle(results[connectorIdx].name);
4853
+ }
4699
4854
  }
4700
- };
4855
+ });
4856
+ const visibleStart = scrollOffset;
4857
+ const visibleEnd = Math.min(scrollOffset + maxVisible, totalItems);
4701
4858
  return /* @__PURE__ */ jsxDEV4(Box6, {
4702
4859
  flexDirection: "column",
4703
4860
  children: [
@@ -4711,7 +4868,8 @@ function SearchView({
4711
4868
  /* @__PURE__ */ jsxDEV4(build_default, {
4712
4869
  value: query,
4713
4870
  onChange: setQuery,
4714
- placeholder: "Type to search connectors..."
4871
+ placeholder: "Type to search connectors...",
4872
+ focus: mode === "search"
4715
4873
  }, undefined, false, undefined, this)
4716
4874
  ]
4717
4875
  }, undefined, true, undefined, this),
@@ -4736,13 +4894,140 @@ function SearchView({
4736
4894
  children: [
4737
4895
  "Found ",
4738
4896
  results.length,
4739
- " connector(s):"
4897
+ " connector(s)",
4898
+ mode === "search" ? " \u2014 press \u2193 to select" : "",
4899
+ ":"
4740
4900
  ]
4741
4901
  }, undefined, true, undefined, this),
4742
- /* @__PURE__ */ jsxDEV4(SelectInput_default, {
4743
- items,
4744
- onSelect: handleSelect
4745
- }, undefined, false, undefined, this)
4902
+ /* @__PURE__ */ jsxDEV4(Box6, {
4903
+ children: [
4904
+ /* @__PURE__ */ jsxDEV4(Box6, {
4905
+ width: COL_CHECK2,
4906
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4907
+ dimColor: true,
4908
+ children: " "
4909
+ }, undefined, false, undefined, this)
4910
+ }, undefined, false, undefined, this),
4911
+ /* @__PURE__ */ jsxDEV4(Box6, {
4912
+ width: COL_NAME2,
4913
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4914
+ bold: true,
4915
+ dimColor: true,
4916
+ children: "Connector"
4917
+ }, undefined, false, undefined, this)
4918
+ }, undefined, false, undefined, this),
4919
+ /* @__PURE__ */ jsxDEV4(Box6, {
4920
+ width: COL_VERSION2,
4921
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4922
+ bold: true,
4923
+ dimColor: true,
4924
+ children: "Version"
4925
+ }, undefined, false, undefined, this)
4926
+ }, undefined, false, undefined, this),
4927
+ /* @__PURE__ */ jsxDEV4(Text7, {
4928
+ bold: true,
4929
+ dimColor: true,
4930
+ children: "Description"
4931
+ }, undefined, false, undefined, this)
4932
+ ]
4933
+ }, undefined, true, undefined, this),
4934
+ /* @__PURE__ */ jsxDEV4(Box6, {
4935
+ marginBottom: 0,
4936
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4937
+ dimColor: true,
4938
+ children: "\u2500".repeat(70)
4939
+ }, undefined, false, undefined, this)
4940
+ }, undefined, false, undefined, this),
4941
+ visibleStart > 0 && /* @__PURE__ */ jsxDEV4(Text7, {
4942
+ dimColor: true,
4943
+ children: [
4944
+ " \u2191 ",
4945
+ visibleStart,
4946
+ " more"
4947
+ ]
4948
+ }, undefined, true, undefined, this),
4949
+ Array.from({ length: visibleEnd - visibleStart }, (_, i) => {
4950
+ const idx = visibleStart + i;
4951
+ if (idx === 0) {
4952
+ const isActive2 = mode === "select" && cursor === 0;
4953
+ return /* @__PURE__ */ jsxDEV4(Box6, {
4954
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4955
+ color: isActive2 ? "cyan" : undefined,
4956
+ bold: isActive2,
4957
+ children: [
4958
+ isActive2 ? "\u276F " : " ",
4959
+ "\u2190 Back"
4960
+ ]
4961
+ }, undefined, true, undefined, this)
4962
+ }, "__back__", false, undefined, this);
4963
+ }
4964
+ if (hasConfirm && idx === totalItems - 1) {
4965
+ const isActive2 = mode === "select" && cursor === totalItems - 1;
4966
+ return /* @__PURE__ */ jsxDEV4(Box6, {
4967
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4968
+ color: isActive2 ? "green" : "green",
4969
+ bold: isActive2,
4970
+ dimColor: !isActive2,
4971
+ children: [
4972
+ isActive2 ? "\u276F " : " ",
4973
+ "\u2713 Install selected (",
4974
+ selected.size,
4975
+ ")"
4976
+ ]
4977
+ }, undefined, true, undefined, this)
4978
+ }, "__confirm__", false, undefined, this);
4979
+ }
4980
+ const c = results[idx - 1];
4981
+ if (!c)
4982
+ return null;
4983
+ const isActive = mode === "select" && cursor === idx;
4984
+ const isChecked = selected.has(c.name);
4985
+ return /* @__PURE__ */ jsxDEV4(Box6, {
4986
+ children: [
4987
+ /* @__PURE__ */ jsxDEV4(Box6, {
4988
+ width: 2,
4989
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4990
+ color: isActive ? "cyan" : undefined,
4991
+ children: isActive ? "\u276F" : " "
4992
+ }, undefined, false, undefined, this)
4993
+ }, undefined, false, undefined, this),
4994
+ /* @__PURE__ */ jsxDEV4(Box6, {
4995
+ width: COL_CHECK2 - 2,
4996
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
4997
+ color: isChecked ? "green" : "gray",
4998
+ children: isChecked ? "[\u2713]" : "[ ]"
4999
+ }, undefined, false, undefined, this)
5000
+ }, undefined, false, undefined, this),
5001
+ /* @__PURE__ */ jsxDEV4(Box6, {
5002
+ width: COL_NAME2,
5003
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
5004
+ bold: isActive,
5005
+ color: isActive ? "cyan" : undefined,
5006
+ children: c.name
5007
+ }, undefined, false, undefined, this)
5008
+ }, undefined, false, undefined, this),
5009
+ /* @__PURE__ */ jsxDEV4(Box6, {
5010
+ width: COL_VERSION2,
5011
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
5012
+ dimColor: true,
5013
+ children: c.version || "-"
5014
+ }, undefined, false, undefined, this)
5015
+ }, undefined, false, undefined, this),
5016
+ /* @__PURE__ */ jsxDEV4(Text7, {
5017
+ wrap: "truncate",
5018
+ children: c.description
5019
+ }, undefined, false, undefined, this)
5020
+ ]
5021
+ }, c.name, true, undefined, this);
5022
+ }),
5023
+ visibleEnd < totalItems && /* @__PURE__ */ jsxDEV4(Text7, {
5024
+ dimColor: true,
5025
+ children: [
5026
+ " \u2193 ",
5027
+ totalItems - visibleEnd,
5028
+ " more"
5029
+ ]
5030
+ }, undefined, true, undefined, this)
4746
5031
  ]
4747
5032
  }, undefined, true, undefined, this),
4748
5033
  selected.size > 0 && /* @__PURE__ */ jsxDEV4(Box6, {
@@ -4754,6 +5039,13 @@ function SearchView({
4754
5039
  Array.from(selected).join(", ")
4755
5040
  ]
4756
5041
  }, undefined, true, undefined, this)
5042
+ }, undefined, false, undefined, this),
5043
+ /* @__PURE__ */ jsxDEV4(Box6, {
5044
+ marginTop: 1,
5045
+ children: /* @__PURE__ */ jsxDEV4(Text7, {
5046
+ dimColor: true,
5047
+ children: mode === "search" ? "type to search \u2193 select results esc back" : "\u2191\u2193 navigate space toggle enter confirm esc search"
5048
+ }, undefined, false, undefined, this)
4757
5049
  }, undefined, false, undefined, this)
4758
5050
  ]
4759
5051
  }, undefined, true, undefined, this);
@@ -4786,29 +5078,38 @@ function Spinner({ type = "dots" }) {
4786
5078
  var build_default2 = Spinner;
4787
5079
 
4788
5080
  // src/lib/installer.ts
4789
- import { existsSync, cpSync, mkdirSync, writeFileSync } from "fs";
4790
- import { join, dirname } from "path";
4791
- import { fileURLToPath } from "url";
4792
- var __dirname2 = dirname(fileURLToPath(import.meta.url));
4793
- var CONNECTORS_DIR = join(__dirname2, "..", "..", "connectors");
5081
+ import { existsSync as existsSync2, cpSync, mkdirSync, writeFileSync } from "fs";
5082
+ import { join as join2, dirname as dirname2 } from "path";
5083
+ import { fileURLToPath as fileURLToPath2 } from "url";
5084
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
5085
+ function resolveConnectorsDir() {
5086
+ const fromBin = join2(__dirname2, "..", "connectors");
5087
+ if (existsSync2(fromBin))
5088
+ return fromBin;
5089
+ const fromSrc = join2(__dirname2, "..", "..", "connectors");
5090
+ if (existsSync2(fromSrc))
5091
+ return fromSrc;
5092
+ return fromBin;
5093
+ }
5094
+ var CONNECTORS_DIR = resolveConnectorsDir();
4794
5095
  function getConnectorPath(name) {
4795
5096
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
4796
- return join(CONNECTORS_DIR, connectorName);
5097
+ return join2(CONNECTORS_DIR, connectorName);
4797
5098
  }
4798
5099
  function installConnector(name, options = {}) {
4799
5100
  const { targetDir = process.cwd(), overwrite = false } = options;
4800
5101
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
4801
5102
  const sourcePath = getConnectorPath(name);
4802
- const destDir = join(targetDir, ".connectors");
4803
- const destPath = join(destDir, connectorName);
4804
- if (!existsSync(sourcePath)) {
5103
+ const destDir = join2(targetDir, ".connectors");
5104
+ const destPath = join2(destDir, connectorName);
5105
+ if (!existsSync2(sourcePath)) {
4805
5106
  return {
4806
5107
  connector: name,
4807
5108
  success: false,
4808
5109
  error: `Connector '${name}' not found`
4809
5110
  };
4810
5111
  }
4811
- if (existsSync(destPath) && !overwrite) {
5112
+ if (existsSync2(destPath) && !overwrite) {
4812
5113
  return {
4813
5114
  connector: name,
4814
5115
  success: false,
@@ -4817,7 +5118,7 @@ function installConnector(name, options = {}) {
4817
5118
  };
4818
5119
  }
4819
5120
  try {
4820
- if (!existsSync(destDir)) {
5121
+ if (!existsSync2(destDir)) {
4821
5122
  mkdirSync(destDir, { recursive: true });
4822
5123
  }
4823
5124
  cpSync(sourcePath, destPath, { recursive: true });
@@ -4836,7 +5137,7 @@ function installConnector(name, options = {}) {
4836
5137
  }
4837
5138
  }
4838
5139
  function updateConnectorsIndex(connectorsDir) {
4839
- const indexPath = join(connectorsDir, "index.ts");
5140
+ const indexPath = join2(connectorsDir, "index.ts");
4840
5141
  const { readdirSync } = __require("fs");
4841
5142
  const connectors = readdirSync(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
4842
5143
  const exports = connectors.map((c) => {
@@ -4854,22 +5155,22 @@ ${exports}
4854
5155
  writeFileSync(indexPath, content);
4855
5156
  }
4856
5157
  function getInstalledConnectors(targetDir = process.cwd()) {
4857
- const connectorsDir = join(targetDir, ".connectors");
4858
- if (!existsSync(connectorsDir)) {
5158
+ const connectorsDir = join2(targetDir, ".connectors");
5159
+ if (!existsSync2(connectorsDir)) {
4859
5160
  return [];
4860
5161
  }
4861
5162
  const { readdirSync, statSync } = __require("fs");
4862
5163
  return readdirSync(connectorsDir).filter((f) => {
4863
- const fullPath = join(connectorsDir, f);
5164
+ const fullPath = join2(connectorsDir, f);
4864
5165
  return f.startsWith("connect-") && statSync(fullPath).isDirectory();
4865
5166
  }).map((f) => f.replace("connect-", ""));
4866
5167
  }
4867
5168
  function removeConnector(name, targetDir = process.cwd()) {
4868
5169
  const { rmSync } = __require("fs");
4869
5170
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
4870
- const connectorsDir = join(targetDir, ".connectors");
4871
- const connectorPath = join(connectorsDir, connectorName);
4872
- if (!existsSync(connectorPath)) {
5171
+ const connectorsDir = join2(targetDir, ".connectors");
5172
+ const connectorPath = join2(connectorsDir, connectorName);
5173
+ if (!existsSync2(connectorPath)) {
4873
5174
  return false;
4874
5175
  }
4875
5176
  rmSync(connectorPath, { recursive: true });
@@ -5180,8 +5481,9 @@ function App({ initialConnectors, overwrite = false }) {
5180
5481
 
5181
5482
  // src/cli/index.tsx
5182
5483
  import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
5484
+ loadConnectorVersions();
5183
5485
  var program2 = new Command;
5184
- program2.name("connectors").description("Install API connectors for your project").version("0.0.1");
5486
+ program2.name("connectors").description("Install API connectors for your project").version("0.0.3");
5185
5487
  program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
5186
5488
  render(/* @__PURE__ */ jsxDEV7(App, {}, undefined, false, undefined, this));
5187
5489
  });
@@ -5230,8 +5532,10 @@ Installed connectors (${installed.length}):
5230
5532
  console.log(chalk2.bold(`
5231
5533
  ${category} (${connectors.length}):
5232
5534
  `));
5535
+ console.log(` ${chalk2.dim("Name".padEnd(20))}${chalk2.dim("Version".padEnd(10))}${chalk2.dim("Description")}`);
5536
+ console.log(chalk2.dim(` ${"\u2500".repeat(60)}`));
5233
5537
  for (const c of connectors) {
5234
- console.log(` ${chalk2.cyan(c.name)} - ${c.description}`);
5538
+ console.log(` ${chalk2.cyan(c.name.padEnd(20))}${chalk2.dim((c.version || "-").padEnd(10))}${c.description}`);
5235
5539
  }
5236
5540
  return;
5237
5541
  }
@@ -5241,8 +5545,10 @@ Available connectors (${CONNECTORS.length}):
5241
5545
  for (const category of CATEGORIES) {
5242
5546
  const connectors = getConnectorsByCategory(category);
5243
5547
  console.log(chalk2.bold(`${category} (${connectors.length}):`));
5548
+ console.log(` ${chalk2.dim("Name".padEnd(20))}${chalk2.dim("Version".padEnd(10))}${chalk2.dim("Description")}`);
5549
+ console.log(chalk2.dim(` ${"\u2500".repeat(60)}`));
5244
5550
  for (const c of connectors) {
5245
- console.log(` ${chalk2.cyan(c.name)} - ${c.description}`);
5551
+ console.log(` ${chalk2.cyan(c.name.padEnd(20))}${chalk2.dim((c.version || "-").padEnd(10))}${c.description}`);
5246
5552
  }
5247
5553
  console.log();
5248
5554
  }
@@ -5256,9 +5562,10 @@ program2.command("search").argument("<query>", "Search term").description("Searc
5256
5562
  console.log(chalk2.bold(`
5257
5563
  Found ${results.length} connector(s):
5258
5564
  `));
5565
+ console.log(` ${chalk2.dim("Name".padEnd(20))}${chalk2.dim("Version".padEnd(10))}${chalk2.dim("Category".padEnd(20))}${chalk2.dim("Description")}`);
5566
+ console.log(chalk2.dim(` ${"\u2500".repeat(70)}`));
5259
5567
  for (const c of results) {
5260
- console.log(` ${chalk2.cyan(c.name)} ${chalk2.dim(`[${c.category}]`)}`);
5261
- console.log(` ${c.description}`);
5568
+ console.log(` ${chalk2.cyan(c.name.padEnd(20))}${chalk2.dim((c.version || "-").padEnd(10))}${chalk2.dim(c.category.padEnd(20))}${c.description}`);
5262
5569
  }
5263
5570
  });
5264
5571
  program2.command("remove").alias("rm").argument("<connector>", "Connector to remove").description("Remove an installed connector").action((connector) => {
package/dist/index.js CHANGED
@@ -2,6 +2,9 @@
2
2
  var __require = import.meta.require;
3
3
 
4
4
  // src/lib/registry.ts
5
+ import { existsSync, readFileSync } from "fs";
6
+ import { join, dirname } from "path";
7
+ import { fileURLToPath } from "url";
5
8
  var CATEGORIES = [
6
9
  "AI & ML",
7
10
  "Developer Tools",
@@ -468,33 +471,65 @@ function searchConnectors(query) {
468
471
  function getConnector(name) {
469
472
  return CONNECTORS.find((c) => c.name === name);
470
473
  }
474
+ var versionsLoaded = false;
475
+ function loadConnectorVersions() {
476
+ if (versionsLoaded)
477
+ return;
478
+ versionsLoaded = true;
479
+ const thisDir = dirname(fileURLToPath(import.meta.url));
480
+ const candidates = [
481
+ join(thisDir, "..", "connectors"),
482
+ join(thisDir, "..", "..", "connectors")
483
+ ];
484
+ const connectorsDir = candidates.find((d) => existsSync(d));
485
+ if (!connectorsDir)
486
+ return;
487
+ for (const connector of CONNECTORS) {
488
+ try {
489
+ const pkgPath = join(connectorsDir, `connect-${connector.name}`, "package.json");
490
+ if (existsSync(pkgPath)) {
491
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
492
+ connector.version = pkg.version || "0.0.0";
493
+ }
494
+ } catch {}
495
+ }
496
+ }
471
497
  // src/lib/installer.ts
472
- import { existsSync, cpSync, mkdirSync, writeFileSync } from "fs";
473
- import { join, dirname } from "path";
474
- import { fileURLToPath } from "url";
475
- var __dirname2 = dirname(fileURLToPath(import.meta.url));
476
- var CONNECTORS_DIR = join(__dirname2, "..", "..", "connectors");
498
+ import { existsSync as existsSync2, cpSync, mkdirSync, writeFileSync } from "fs";
499
+ import { join as join2, dirname as dirname2 } from "path";
500
+ import { fileURLToPath as fileURLToPath2 } from "url";
501
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
502
+ function resolveConnectorsDir() {
503
+ const fromBin = join2(__dirname2, "..", "connectors");
504
+ if (existsSync2(fromBin))
505
+ return fromBin;
506
+ const fromSrc = join2(__dirname2, "..", "..", "connectors");
507
+ if (existsSync2(fromSrc))
508
+ return fromSrc;
509
+ return fromBin;
510
+ }
511
+ var CONNECTORS_DIR = resolveConnectorsDir();
477
512
  function getConnectorPath(name) {
478
513
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
479
- return join(CONNECTORS_DIR, connectorName);
514
+ return join2(CONNECTORS_DIR, connectorName);
480
515
  }
481
516
  function connectorExists(name) {
482
- return existsSync(getConnectorPath(name));
517
+ return existsSync2(getConnectorPath(name));
483
518
  }
484
519
  function installConnector(name, options = {}) {
485
520
  const { targetDir = process.cwd(), overwrite = false } = options;
486
521
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
487
522
  const sourcePath = getConnectorPath(name);
488
- const destDir = join(targetDir, ".connectors");
489
- const destPath = join(destDir, connectorName);
490
- if (!existsSync(sourcePath)) {
523
+ const destDir = join2(targetDir, ".connectors");
524
+ const destPath = join2(destDir, connectorName);
525
+ if (!existsSync2(sourcePath)) {
491
526
  return {
492
527
  connector: name,
493
528
  success: false,
494
529
  error: `Connector '${name}' not found`
495
530
  };
496
531
  }
497
- if (existsSync(destPath) && !overwrite) {
532
+ if (existsSync2(destPath) && !overwrite) {
498
533
  return {
499
534
  connector: name,
500
535
  success: false,
@@ -503,7 +538,7 @@ function installConnector(name, options = {}) {
503
538
  };
504
539
  }
505
540
  try {
506
- if (!existsSync(destDir)) {
541
+ if (!existsSync2(destDir)) {
507
542
  mkdirSync(destDir, { recursive: true });
508
543
  }
509
544
  cpSync(sourcePath, destPath, { recursive: true });
@@ -525,7 +560,7 @@ function installConnectors(names, options = {}) {
525
560
  return names.map((name) => installConnector(name, options));
526
561
  }
527
562
  function updateConnectorsIndex(connectorsDir) {
528
- const indexPath = join(connectorsDir, "index.ts");
563
+ const indexPath = join2(connectorsDir, "index.ts");
529
564
  const { readdirSync } = __require("fs");
530
565
  const connectors = readdirSync(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
531
566
  const exports = connectors.map((c) => {
@@ -543,22 +578,22 @@ ${exports}
543
578
  writeFileSync(indexPath, content);
544
579
  }
545
580
  function getInstalledConnectors(targetDir = process.cwd()) {
546
- const connectorsDir = join(targetDir, ".connectors");
547
- if (!existsSync(connectorsDir)) {
581
+ const connectorsDir = join2(targetDir, ".connectors");
582
+ if (!existsSync2(connectorsDir)) {
548
583
  return [];
549
584
  }
550
585
  const { readdirSync, statSync } = __require("fs");
551
586
  return readdirSync(connectorsDir).filter((f) => {
552
- const fullPath = join(connectorsDir, f);
587
+ const fullPath = join2(connectorsDir, f);
553
588
  return f.startsWith("connect-") && statSync(fullPath).isDirectory();
554
589
  }).map((f) => f.replace("connect-", ""));
555
590
  }
556
591
  function removeConnector(name, targetDir = process.cwd()) {
557
592
  const { rmSync } = __require("fs");
558
593
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
559
- const connectorsDir = join(targetDir, ".connectors");
560
- const connectorPath = join(connectorsDir, connectorName);
561
- if (!existsSync(connectorPath)) {
594
+ const connectorsDir = join2(targetDir, ".connectors");
595
+ const connectorPath = join2(connectorsDir, connectorName);
596
+ if (!existsSync2(connectorPath)) {
562
597
  return false;
563
598
  }
564
599
  rmSync(connectorPath, { recursive: true });
@@ -568,6 +603,7 @@ function removeConnector(name, targetDir = process.cwd()) {
568
603
  export {
569
604
  searchConnectors,
570
605
  removeConnector,
606
+ loadConnectorVersions,
571
607
  installConnectors,
572
608
  installConnector,
573
609
  getInstalledConnectors,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/connectors",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Open source connector library - Install API connectors with a single command",
5
5
  "type": "module",
6
6
  "bin": {