fss-link 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bundle/fss-link.js +177 -92
  2. package/package.json +1 -1
@@ -22379,7 +22379,7 @@ async function createContentGeneratorConfig(config, authType) {
22379
22379
  async function createContentGenerator(config, gcConfig, sessionId2) {
22380
22380
  if (DEBUG_CONTENT)
22381
22381
  console.log(`\u{1F41B} DEBUG createContentGenerator: authType=${config.authType}, apiKey=${config.apiKey}, baseUrl=${config.baseUrl}`);
22382
- const version = "1.5.0";
22382
+ const version = "1.5.1";
22383
22383
  const userAgent = `FSS-Link/${version} (${process.platform}; ${process.arch})`;
22384
22384
  const baseHeaders = {
22385
22385
  "User-Agent": userAgent
@@ -96359,7 +96359,7 @@ async function getPackageJson() {
96359
96359
  // packages/cli/src/utils/version.ts
96360
96360
  async function getCliVersion() {
96361
96361
  const pkgJson = await getPackageJson();
96362
- return "1.5.0";
96362
+ return "1.5.1";
96363
96363
  }
96364
96364
 
96365
96365
  // packages/cli/src/ui/commands/aboutCommand.ts
@@ -96411,7 +96411,7 @@ import open4 from "open";
96411
96411
  import process11 from "node:process";
96412
96412
 
96413
96413
  // packages/cli/src/generated/git-commit.ts
96414
- var GIT_COMMIT_INFO = "6eb449b6";
96414
+ var GIT_COMMIT_INFO = "7684208c";
96415
96415
 
96416
96416
  // packages/cli/src/ui/commands/bugCommand.ts
96417
96417
  init_dist2();
@@ -120708,6 +120708,9 @@ import { useState as useState33, useEffect as useEffect32 } from "react";
120708
120708
  import { Box as Box19, Text as Text26, useInput as useInput4 } from "ink";
120709
120709
 
120710
120710
  // packages/cli/src/utils/modelFetcher.ts
120711
+ init_dist2();
120712
+ var modelCache = /* @__PURE__ */ new Map();
120713
+ var MODEL_CACHE_TTL = 5 * 60 * 1e3;
120711
120714
  async function fetchModelsFromCustomEndpoint(baseUrl, providerType, apiKey) {
120712
120715
  const normalizedBase = baseUrl.replace(/\/+$/, "");
120713
120716
  const url2 = `${normalizedBase}/models`;
@@ -120779,6 +120782,39 @@ async function fetchModelsFromCustomEndpoint(baseUrl, providerType, apiKey) {
120779
120782
  throw new Error(`Connection failed: ${String(error)}`);
120780
120783
  }
120781
120784
  }
120785
+ async function fetchModelsFromProvider(provider, endpoint, apiKey, forceRefresh = false) {
120786
+ const cacheKey = `${provider}:${endpoint || "default"}`;
120787
+ if (!forceRefresh) {
120788
+ const cached = modelCache.get(cacheKey);
120789
+ if (cached && Date.now() - cached.timestamp < MODEL_CACHE_TTL) {
120790
+ console.error(`[DEBUG] Using cached models for ${cacheKey}`);
120791
+ return cached.models;
120792
+ }
120793
+ }
120794
+ let fetchUrl;
120795
+ if (endpoint) {
120796
+ fetchUrl = endpoint;
120797
+ } else {
120798
+ switch (provider) {
120799
+ case AuthType.OLLAMA:
120800
+ fetchUrl = "http://localhost:11434";
120801
+ break;
120802
+ case AuthType.LM_STUDIO:
120803
+ fetchUrl = "http://localhost:1234/v1";
120804
+ break;
120805
+ default:
120806
+ throw new Error(`No default endpoint for provider: ${provider}`);
120807
+ }
120808
+ }
120809
+ console.error(`[DEBUG] Fetching models from ${provider} at ${fetchUrl}`);
120810
+ const models = await fetchModelsFromCustomEndpoint(fetchUrl, provider, apiKey);
120811
+ modelCache.set(cacheKey, {
120812
+ models,
120813
+ timestamp: Date.now()
120814
+ });
120815
+ console.error(`[DEBUG] Cached ${models.length} models for ${cacheKey}`);
120816
+ return models;
120817
+ }
120782
120818
 
120783
120819
  // packages/cli/src/ui/components/shared/PasteAwareTextInput.tsx
120784
120820
  import TextInput from "ink-text-input";
@@ -121791,85 +121827,104 @@ function EnhancedModelSelectionDialog({
121791
121827
  onBack,
121792
121828
  onCancel
121793
121829
  }) {
121794
- const [models, setModels] = useState37([]);
121830
+ const [allModels, setAllModels] = useState37([]);
121795
121831
  const [selectedIndex, setSelectedIndex] = useState37(0);
121832
+ const [scrollOffset, setScrollOffset] = useState37(0);
121796
121833
  const [loading, setLoading] = useState37(true);
121797
121834
  const [error, setError] = useState37(null);
121798
121835
  const [switching, setSwitching] = useState37(false);
121799
- const loadModels = async () => {
121800
- try {
121801
- const modelManager = getModelManager();
121802
- const allModels = await modelManager.getAllModels();
121803
- const filtered = allModels.filter((model) => {
121804
- if (model.authType !== providerType) return false;
121805
- const modelEndpoint = model.endpointUrl || void 0;
121806
- if (endpointUrl && modelEndpoint !== endpointUrl) return false;
121807
- if (!endpointUrl && modelEndpoint) return false;
121808
- return true;
121809
- });
121810
- if (filtered.length === 0) {
121811
- setError(`No models found for ${endpointLabel}`);
121836
+ const VISIBLE_MODELS = 15;
121837
+ useEffect35(() => {
121838
+ const loadAndFetchModels = async () => {
121839
+ setLoading(true);
121840
+ setError(null);
121841
+ try {
121842
+ const modelManager = getModelManager();
121843
+ const allDbModels = await modelManager.getAllModels();
121844
+ const existing = allDbModels.filter(
121845
+ (m) => m.authType === providerType && (!endpointUrl || m.endpointUrl === endpointUrl)
121846
+ );
121847
+ const activeModel = allDbModels.find((m) => m.isActive);
121848
+ const activeModelId = activeModel?.modelName;
121849
+ console.error(`[DEBUG] Fetching models for ${providerType} from ${endpointUrl || "default"}`);
121850
+ const fetched = await fetchModelsFromProvider(providerType, endpointUrl);
121851
+ const existingModelNames = new Set(existing.map((m) => m.modelName));
121852
+ const merged = fetched.map((fm) => ({
121853
+ ...fm,
121854
+ isNew: !existingModelNames.has(fm.id),
121855
+ isExisting: existingModelNames.has(fm.id),
121856
+ isActive: fm.id === activeModelId
121857
+ }));
121858
+ merged.sort((a, b) => {
121859
+ if (a.isActive && !b.isActive) return -1;
121860
+ if (!a.isActive && b.isActive) return 1;
121861
+ if (a.isExisting && !b.isExisting) return -1;
121862
+ if (!a.isExisting && b.isExisting) return 1;
121863
+ return 0;
121864
+ });
121865
+ setAllModels(merged);
121866
+ setLoading(false);
121867
+ } catch (err) {
121868
+ setError(err instanceof Error ? err.message : "Failed to fetch models");
121812
121869
  setLoading(false);
121813
- return;
121814
- }
121815
- filtered.sort((a, b) => {
121816
- if (a.isFavorite && !b.isFavorite) return -1;
121817
- if (!a.isFavorite && b.isFavorite) return 1;
121818
- if (a.isActive && !b.isActive) return -1;
121819
- if (!a.isActive && b.isActive) return 1;
121820
- return a.modelName.localeCompare(b.modelName);
121821
- });
121822
- const activeIndex = filtered.findIndex((m) => m.isActive);
121823
- if (activeIndex !== -1) {
121824
- setSelectedIndex(activeIndex);
121825
121870
  }
121826
- setModels(filtered);
121827
- setLoading(false);
121828
- } catch (err) {
121829
- setError(err instanceof Error ? err.message : "Failed to load models");
121830
- setLoading(false);
121831
- }
121832
- };
121833
- useEffect35(() => {
121834
- loadModels();
121871
+ };
121872
+ loadAndFetchModels();
121835
121873
  }, [providerType, endpointUrl]);
121836
121874
  useInput6((input, key) => {
121837
121875
  if (loading || switching) return;
121838
- if (key.escape) {
121876
+ if (key.escape || input === "b" || input === "B") {
121839
121877
  onBack();
121840
121878
  return;
121841
121879
  }
121842
- if (input === "f" || input === "F") {
121843
- const selectedModel = models[selectedIndex];
121844
- if (selectedModel.id) {
121845
- const modelManager = getModelManager();
121846
- modelManager.toggleFavorite(selectedModel.id).then(() => {
121847
- loadModels();
121848
- }).catch((err) => {
121849
- console.error("Failed to toggle favorite:", err);
121850
- });
121880
+ if (key.upArrow && selectedIndex > 0) {
121881
+ const newIndex = selectedIndex - 1;
121882
+ setSelectedIndex(newIndex);
121883
+ if (newIndex < scrollOffset) {
121884
+ setScrollOffset(newIndex);
121851
121885
  }
121852
121886
  return;
121853
121887
  }
121854
- if (input.includes("\n") || input.includes("\r")) {
121855
- if (models.length > 0) {
121856
- const selectedModel = models[selectedIndex];
121857
- setSwitching(true);
121858
- const modelManager = getModelManager();
121859
- modelManager.switchToModel(selectedModel.id).then(() => {
121860
- onComplete();
121861
- }).catch((err) => {
121862
- setError(err instanceof Error ? err.message : "Failed to switch model");
121863
- setSwitching(false);
121864
- });
121888
+ if (key.downArrow && selectedIndex < allModels.length - 1) {
121889
+ const newIndex = selectedIndex + 1;
121890
+ setSelectedIndex(newIndex);
121891
+ if (newIndex >= scrollOffset + VISIBLE_MODELS) {
121892
+ setScrollOffset(newIndex - VISIBLE_MODELS + 1);
121865
121893
  }
121866
121894
  return;
121867
121895
  }
121868
- if (key.upArrow && selectedIndex > 0) {
121869
- setSelectedIndex(selectedIndex - 1);
121870
- }
121871
- if (key.downArrow && selectedIndex < models.length - 1) {
121872
- setSelectedIndex(selectedIndex + 1);
121896
+ if (key.return && allModels.length > 0) {
121897
+ const selectedModel = allModels[selectedIndex];
121898
+ setSwitching(true);
121899
+ const modelManager = getModelManager();
121900
+ (async () => {
121901
+ try {
121902
+ if (selectedModel.isNew) {
121903
+ console.error(`[DEBUG] Auto-adding new model: ${selectedModel.id}`);
121904
+ await modelManager.configureModel(
121905
+ providerType,
121906
+ selectedModel.id,
121907
+ endpointUrl,
121908
+ void 0,
121909
+ // No API key needed for already configured endpoints
121910
+ selectedModel.id
121911
+ // Use model ID as display name
121912
+ );
121913
+ }
121914
+ const allDbModels = await modelManager.getAllModels();
121915
+ const dbModel = allDbModels.find((m) => m.modelName === selectedModel.id);
121916
+ if (dbModel?.id) {
121917
+ await modelManager.switchToModel(dbModel.id);
121918
+ onComplete();
121919
+ } else {
121920
+ throw new Error("Failed to find model after adding");
121921
+ }
121922
+ } catch (err) {
121923
+ setError(err instanceof Error ? err.message : "Failed to switch model");
121924
+ setSwitching(false);
121925
+ }
121926
+ })();
121927
+ return;
121873
121928
  }
121874
121929
  });
121875
121930
  if (loading) {
@@ -121882,11 +121937,8 @@ function EnhancedModelSelectionDialog({
121882
121937
  padding: 1,
121883
121938
  width: "100%",
121884
121939
  children: [
121885
- /* @__PURE__ */ jsxs26(Text30, { bold: true, color: Colors.AccentBlue, children: [
121886
- "Model Selection - ",
121887
- endpointLabel
121888
- ] }),
121889
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { children: "Loading models..." }) })
121940
+ /* @__PURE__ */ jsx29(Text30, { bold: true, color: Colors.AccentBlue, children: "Model Selection" }),
121941
+ /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { children: "Loading configured models..." }) })
121890
121942
  ]
121891
121943
  }
121892
121944
  );
@@ -121904,7 +121956,7 @@ function EnhancedModelSelectionDialog({
121904
121956
  /* @__PURE__ */ jsx29(Text30, { bold: true, color: Colors.AccentBlue, children: "Switching Model" }),
121905
121957
  /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text30, { children: [
121906
121958
  "Activating ",
121907
- models[selectedIndex].modelName,
121959
+ allModels[selectedIndex]?.id,
121908
121960
  "..."
121909
121961
  ] }) })
121910
121962
  ]
@@ -121923,11 +121975,14 @@ function EnhancedModelSelectionDialog({
121923
121975
  children: [
121924
121976
  /* @__PURE__ */ jsx29(Text30, { bold: true, color: Colors.AccentRed, children: "Model Selection Error" }),
121925
121977
  /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { children: error }) }),
121926
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { color: Colors.Gray, children: "Press Esc to go back" }) })
121978
+ /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { color: Colors.Gray, children: "Press Esc to cancel" }) })
121927
121979
  ]
121928
121980
  }
121929
121981
  );
121930
121982
  }
121983
+ const visibleModels = allModels.slice(scrollOffset, scrollOffset + VISIBLE_MODELS);
121984
+ const modelsAbove = scrollOffset;
121985
+ const modelsBelow = Math.max(0, allModels.length - (scrollOffset + VISIBLE_MODELS));
121931
121986
  return /* @__PURE__ */ jsxs26(
121932
121987
  Box23,
121933
121988
  {
@@ -121939,15 +121994,35 @@ function EnhancedModelSelectionDialog({
121939
121994
  children: [
121940
121995
  /* @__PURE__ */ jsxs26(Text30, { bold: true, color: Colors.AccentBlue, children: [
121941
121996
  "Model Selection - ",
121942
- endpointLabel
121997
+ providerType
121943
121998
  ] }),
121944
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { children: "Choose a model:" }) }),
121945
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, flexDirection: "column", children: models.map((model, index) => {
121946
- const isSelected = index === selectedIndex;
121999
+ endpointLabel && /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text30, { color: Colors.Gray, children: [
122000
+ "Endpoint: ",
122001
+ endpointLabel
122002
+ ] }) }),
122003
+ /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text30, { children: [
122004
+ "Select a model (",
122005
+ allModels.length,
122006
+ " available):"
122007
+ ] }) }),
122008
+ modelsAbove > 0 && /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text30, { color: Colors.Gray, children: [
122009
+ "\u2191 ",
122010
+ modelsAbove,
122011
+ " more above"
122012
+ ] }) }),
122013
+ /* @__PURE__ */ jsx29(Box23, { marginTop: 1, flexDirection: "column", children: visibleModels.map((model, visibleIndex) => {
122014
+ const actualIndex = scrollOffset + visibleIndex;
122015
+ const isSelected = actualIndex === selectedIndex;
121947
122016
  const prefix = isSelected ? ">" : " ";
121948
- const active = model.isActive ? "\u25CF " : "";
121949
- const favorite = model.isFavorite ? "\u2605 " : "";
121950
- const label = `${prefix} ${active}${favorite}${model.modelName}`;
122017
+ let statusIcon = "";
122018
+ if (model.isActive) {
122019
+ statusIcon = "\u25CF ";
122020
+ } else if (model.isNew) {
122021
+ statusIcon = "\u{1F195} ";
122022
+ } else if (model.isExisting) {
122023
+ statusIcon = "\u2713 ";
122024
+ }
122025
+ const label = `${prefix} ${statusIcon}${model.id}`;
121951
122026
  return /* @__PURE__ */ jsx29(
121952
122027
  Text30,
121953
122028
  {
@@ -121955,15 +122030,16 @@ function EnhancedModelSelectionDialog({
121955
122030
  bold: isSelected,
121956
122031
  children: label
121957
122032
  },
121958
- model.id || index
122033
+ model.id
121959
122034
  );
121960
122035
  }) }),
121961
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { color: Colors.Gray, children: "\u25CF = Active \u2605 = Favorite" }) }),
121962
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { color: Colors.Gray, children: "Enter to switch, F to toggle favorite, Esc to go back" }) }),
121963
- /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text30, { color: Colors.Gray, children: [
121964
- "Endpoint: ",
121965
- endpointUrl || "default"
121966
- ] }) })
122036
+ modelsBelow > 0 && /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs26(Text30, { color: Colors.Gray, children: [
122037
+ "\u2193 ",
122038
+ modelsBelow,
122039
+ " more below"
122040
+ ] }) }),
122041
+ /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { color: Colors.Gray, children: "\u2191/\u2193 to navigate, Enter to select, Esc/b to go back" }) }),
122042
+ /* @__PURE__ */ jsx29(Box23, { marginTop: 1, children: /* @__PURE__ */ jsx29(Text30, { color: Colors.Gray, children: "\u{1F195} = new model, \u2713 = existing, \u25CF = currently active" }) })
121967
122043
  ]
121968
122044
  }
121969
122045
  );
@@ -123668,14 +123744,18 @@ async function loadCliConfig(settings, extensions, sessionId2, argv, cwd3 = proc
123668
123744
  const { SearchEngineConfigProvider: SearchEngineConfigProvider2 } = await Promise.resolve().then(() => (init_SearchEngineConfigProvider(), SearchEngineConfigProvider_exports));
123669
123745
  const configProvider = SearchEngineConfigProvider2.getInstance();
123670
123746
  const config2 = await configProvider.loadConfiguration();
123671
- console.log("[API KEY DEBUG] Search engine config loaded at startup:", {
123672
- hasBrave: !!config2.braveApiKey,
123673
- hasTavily: !!config2.tavilyApiKey,
123674
- braveEnvSet: !!process16.env["BRAVE_SEARCH_API_KEY"],
123675
- tavilyEnvSet: !!process16.env["TAVILY_API_KEY"]
123676
- });
123747
+ if (debugMode) {
123748
+ console.log("[API KEY DEBUG] Search engine config loaded at startup:", {
123749
+ hasBrave: !!config2.braveApiKey,
123750
+ hasTavily: !!config2.tavilyApiKey,
123751
+ braveEnvSet: !!process16.env["BRAVE_SEARCH_API_KEY"],
123752
+ tavilyEnvSet: !!process16.env["TAVILY_API_KEY"]
123753
+ });
123754
+ }
123677
123755
  } catch (error) {
123678
- console.error("[API KEY DEBUG] Failed to load search engine config at startup:", error);
123756
+ if (debugMode) {
123757
+ console.error("[API KEY DEBUG] Failed to load search engine config at startup:", error);
123758
+ }
123679
123759
  }
123680
123760
  const webScraperConfigLoader = () => {
123681
123761
  try {
@@ -131762,6 +131842,11 @@ main().catch((error) => {
131762
131842
  * Copyright 2025 FSS Coding
131763
131843
  * SPDX-License-Identifier: Apache-2.0
131764
131844
  */
131845
+ /**
131846
+ * @license
131847
+ * Copyright 2025 Google LLC
131848
+ * SPDX-License-Identifier: Apache-2.0
131849
+ */
131765
131850
  /*! Bundled license information:
131766
131851
 
131767
131852
  js-yaml/dist/js-yaml.mjs:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fss-link",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "engines": {
5
5
  "node": ">=20.0.0"
6
6
  },