@hasna/connectors 0.0.2 → 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 +414 -116
  2. package/dist/index.js +49 -22
  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,38 +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));
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));
4793
5085
  function resolveConnectorsDir() {
4794
- const fromBin = join(__dirname2, "..", "connectors");
4795
- if (existsSync(fromBin))
5086
+ const fromBin = join2(__dirname2, "..", "connectors");
5087
+ if (existsSync2(fromBin))
4796
5088
  return fromBin;
4797
- const fromSrc = join(__dirname2, "..", "..", "connectors");
4798
- if (existsSync(fromSrc))
5089
+ const fromSrc = join2(__dirname2, "..", "..", "connectors");
5090
+ if (existsSync2(fromSrc))
4799
5091
  return fromSrc;
4800
5092
  return fromBin;
4801
5093
  }
4802
5094
  var CONNECTORS_DIR = resolveConnectorsDir();
4803
5095
  function getConnectorPath(name) {
4804
5096
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
4805
- return join(CONNECTORS_DIR, connectorName);
5097
+ return join2(CONNECTORS_DIR, connectorName);
4806
5098
  }
4807
5099
  function installConnector(name, options = {}) {
4808
5100
  const { targetDir = process.cwd(), overwrite = false } = options;
4809
5101
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
4810
5102
  const sourcePath = getConnectorPath(name);
4811
- const destDir = join(targetDir, ".connectors");
4812
- const destPath = join(destDir, connectorName);
4813
- if (!existsSync(sourcePath)) {
5103
+ const destDir = join2(targetDir, ".connectors");
5104
+ const destPath = join2(destDir, connectorName);
5105
+ if (!existsSync2(sourcePath)) {
4814
5106
  return {
4815
5107
  connector: name,
4816
5108
  success: false,
4817
5109
  error: `Connector '${name}' not found`
4818
5110
  };
4819
5111
  }
4820
- if (existsSync(destPath) && !overwrite) {
5112
+ if (existsSync2(destPath) && !overwrite) {
4821
5113
  return {
4822
5114
  connector: name,
4823
5115
  success: false,
@@ -4826,7 +5118,7 @@ function installConnector(name, options = {}) {
4826
5118
  };
4827
5119
  }
4828
5120
  try {
4829
- if (!existsSync(destDir)) {
5121
+ if (!existsSync2(destDir)) {
4830
5122
  mkdirSync(destDir, { recursive: true });
4831
5123
  }
4832
5124
  cpSync(sourcePath, destPath, { recursive: true });
@@ -4845,7 +5137,7 @@ function installConnector(name, options = {}) {
4845
5137
  }
4846
5138
  }
4847
5139
  function updateConnectorsIndex(connectorsDir) {
4848
- const indexPath = join(connectorsDir, "index.ts");
5140
+ const indexPath = join2(connectorsDir, "index.ts");
4849
5141
  const { readdirSync } = __require("fs");
4850
5142
  const connectors = readdirSync(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
4851
5143
  const exports = connectors.map((c) => {
@@ -4863,22 +5155,22 @@ ${exports}
4863
5155
  writeFileSync(indexPath, content);
4864
5156
  }
4865
5157
  function getInstalledConnectors(targetDir = process.cwd()) {
4866
- const connectorsDir = join(targetDir, ".connectors");
4867
- if (!existsSync(connectorsDir)) {
5158
+ const connectorsDir = join2(targetDir, ".connectors");
5159
+ if (!existsSync2(connectorsDir)) {
4868
5160
  return [];
4869
5161
  }
4870
5162
  const { readdirSync, statSync } = __require("fs");
4871
5163
  return readdirSync(connectorsDir).filter((f) => {
4872
- const fullPath = join(connectorsDir, f);
5164
+ const fullPath = join2(connectorsDir, f);
4873
5165
  return f.startsWith("connect-") && statSync(fullPath).isDirectory();
4874
5166
  }).map((f) => f.replace("connect-", ""));
4875
5167
  }
4876
5168
  function removeConnector(name, targetDir = process.cwd()) {
4877
5169
  const { rmSync } = __require("fs");
4878
5170
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
4879
- const connectorsDir = join(targetDir, ".connectors");
4880
- const connectorPath = join(connectorsDir, connectorName);
4881
- if (!existsSync(connectorPath)) {
5171
+ const connectorsDir = join2(targetDir, ".connectors");
5172
+ const connectorPath = join2(connectorsDir, connectorName);
5173
+ if (!existsSync2(connectorPath)) {
4882
5174
  return false;
4883
5175
  }
4884
5176
  rmSync(connectorPath, { recursive: true });
@@ -5189,8 +5481,9 @@ function App({ initialConnectors, overwrite = false }) {
5189
5481
 
5190
5482
  // src/cli/index.tsx
5191
5483
  import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
5484
+ loadConnectorVersions();
5192
5485
  var program2 = new Command;
5193
- 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");
5194
5487
  program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
5195
5488
  render(/* @__PURE__ */ jsxDEV7(App, {}, undefined, false, undefined, this));
5196
5489
  });
@@ -5239,8 +5532,10 @@ Installed connectors (${installed.length}):
5239
5532
  console.log(chalk2.bold(`
5240
5533
  ${category} (${connectors.length}):
5241
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)}`));
5242
5537
  for (const c of connectors) {
5243
- 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}`);
5244
5539
  }
5245
5540
  return;
5246
5541
  }
@@ -5250,8 +5545,10 @@ Available connectors (${CONNECTORS.length}):
5250
5545
  for (const category of CATEGORIES) {
5251
5546
  const connectors = getConnectorsByCategory(category);
5252
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)}`));
5253
5550
  for (const c of connectors) {
5254
- 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}`);
5255
5552
  }
5256
5553
  console.log();
5257
5554
  }
@@ -5265,9 +5562,10 @@ program2.command("search").argument("<query>", "Search term").description("Searc
5265
5562
  console.log(chalk2.bold(`
5266
5563
  Found ${results.length} connector(s):
5267
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)}`));
5268
5567
  for (const c of results) {
5269
- console.log(` ${chalk2.cyan(c.name)} ${chalk2.dim(`[${c.category}]`)}`);
5270
- 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}`);
5271
5569
  }
5272
5570
  });
5273
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,42 +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));
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));
476
502
  function resolveConnectorsDir() {
477
- const fromBin = join(__dirname2, "..", "connectors");
478
- if (existsSync(fromBin))
503
+ const fromBin = join2(__dirname2, "..", "connectors");
504
+ if (existsSync2(fromBin))
479
505
  return fromBin;
480
- const fromSrc = join(__dirname2, "..", "..", "connectors");
481
- if (existsSync(fromSrc))
506
+ const fromSrc = join2(__dirname2, "..", "..", "connectors");
507
+ if (existsSync2(fromSrc))
482
508
  return fromSrc;
483
509
  return fromBin;
484
510
  }
485
511
  var CONNECTORS_DIR = resolveConnectorsDir();
486
512
  function getConnectorPath(name) {
487
513
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
488
- return join(CONNECTORS_DIR, connectorName);
514
+ return join2(CONNECTORS_DIR, connectorName);
489
515
  }
490
516
  function connectorExists(name) {
491
- return existsSync(getConnectorPath(name));
517
+ return existsSync2(getConnectorPath(name));
492
518
  }
493
519
  function installConnector(name, options = {}) {
494
520
  const { targetDir = process.cwd(), overwrite = false } = options;
495
521
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
496
522
  const sourcePath = getConnectorPath(name);
497
- const destDir = join(targetDir, ".connectors");
498
- const destPath = join(destDir, connectorName);
499
- if (!existsSync(sourcePath)) {
523
+ const destDir = join2(targetDir, ".connectors");
524
+ const destPath = join2(destDir, connectorName);
525
+ if (!existsSync2(sourcePath)) {
500
526
  return {
501
527
  connector: name,
502
528
  success: false,
503
529
  error: `Connector '${name}' not found`
504
530
  };
505
531
  }
506
- if (existsSync(destPath) && !overwrite) {
532
+ if (existsSync2(destPath) && !overwrite) {
507
533
  return {
508
534
  connector: name,
509
535
  success: false,
@@ -512,7 +538,7 @@ function installConnector(name, options = {}) {
512
538
  };
513
539
  }
514
540
  try {
515
- if (!existsSync(destDir)) {
541
+ if (!existsSync2(destDir)) {
516
542
  mkdirSync(destDir, { recursive: true });
517
543
  }
518
544
  cpSync(sourcePath, destPath, { recursive: true });
@@ -534,7 +560,7 @@ function installConnectors(names, options = {}) {
534
560
  return names.map((name) => installConnector(name, options));
535
561
  }
536
562
  function updateConnectorsIndex(connectorsDir) {
537
- const indexPath = join(connectorsDir, "index.ts");
563
+ const indexPath = join2(connectorsDir, "index.ts");
538
564
  const { readdirSync } = __require("fs");
539
565
  const connectors = readdirSync(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
540
566
  const exports = connectors.map((c) => {
@@ -552,22 +578,22 @@ ${exports}
552
578
  writeFileSync(indexPath, content);
553
579
  }
554
580
  function getInstalledConnectors(targetDir = process.cwd()) {
555
- const connectorsDir = join(targetDir, ".connectors");
556
- if (!existsSync(connectorsDir)) {
581
+ const connectorsDir = join2(targetDir, ".connectors");
582
+ if (!existsSync2(connectorsDir)) {
557
583
  return [];
558
584
  }
559
585
  const { readdirSync, statSync } = __require("fs");
560
586
  return readdirSync(connectorsDir).filter((f) => {
561
- const fullPath = join(connectorsDir, f);
587
+ const fullPath = join2(connectorsDir, f);
562
588
  return f.startsWith("connect-") && statSync(fullPath).isDirectory();
563
589
  }).map((f) => f.replace("connect-", ""));
564
590
  }
565
591
  function removeConnector(name, targetDir = process.cwd()) {
566
592
  const { rmSync } = __require("fs");
567
593
  const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
568
- const connectorsDir = join(targetDir, ".connectors");
569
- const connectorPath = join(connectorsDir, connectorName);
570
- if (!existsSync(connectorPath)) {
594
+ const connectorsDir = join2(targetDir, ".connectors");
595
+ const connectorPath = join2(connectorsDir, connectorName);
596
+ if (!existsSync2(connectorPath)) {
571
597
  return false;
572
598
  }
573
599
  rmSync(connectorPath, { recursive: true });
@@ -577,6 +603,7 @@ function removeConnector(name, targetDir = process.cwd()) {
577
603
  export {
578
604
  searchConnectors,
579
605
  removeConnector,
606
+ loadConnectorVersions,
580
607
  installConnectors,
581
608
  installConnector,
582
609
  getInstalledConnectors,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/connectors",
3
- "version": "0.0.2",
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": {