fss-link 1.1.4 → 1.1.6

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 +206 -66
  2. package/package.json +1 -1
@@ -8710,7 +8710,9 @@ var init_metrics = __esm({
8710
8710
  ValueType = otelApi.ValueType;
8711
8711
  openTelemetryAvailable = true;
8712
8712
  } catch (error) {
8713
- console.debug("OpenTelemetry unavailable, using fallback metrics system");
8713
+ if (process.env["FSS_DEBUG"] === "true") {
8714
+ console.debug("OpenTelemetry unavailable, using fallback metrics system");
8715
+ }
8714
8716
  openTelemetryAvailable = false;
8715
8717
  metrics = { getMeter: () => null };
8716
8718
  ValueType = { INT: "int" };
@@ -11081,7 +11083,9 @@ var init_sdk = __esm({
11081
11083
  HttpInstrumentation = otelInstrumentationHttp.HttpInstrumentation;
11082
11084
  openTelemetryAvailable2 = true;
11083
11085
  } catch (error) {
11084
- console.debug("OpenTelemetry SDK unavailable, telemetry disabled");
11086
+ if (process.env["FSS_DEBUG"] === "true") {
11087
+ console.debug("OpenTelemetry SDK unavailable, telemetry disabled");
11088
+ }
11085
11089
  openTelemetryAvailable2 = false;
11086
11090
  }
11087
11091
  if (openTelemetryAvailable2 && diag && DiagConsoleLogger && DiagLogLevel) {
@@ -11601,7 +11605,9 @@ var init_loggers = __esm({
11601
11605
  SemanticAttributes = otelSemanticConventions.SemanticAttributes;
11602
11606
  openTelemetryAvailable3 = true;
11603
11607
  } catch (error) {
11604
- console.debug("OpenTelemetry loggers unavailable, using stubs");
11608
+ if (process.env["FSS_DEBUG"] === "true") {
11609
+ console.debug("OpenTelemetry loggers unavailable, using stubs");
11610
+ }
11605
11611
  openTelemetryAvailable3 = false;
11606
11612
  LogAttributes = {};
11607
11613
  LogRecord = class {
@@ -22084,7 +22090,7 @@ async function createContentGeneratorConfig(config, authType) {
22084
22090
  async function createContentGenerator(config, gcConfig, sessionId2) {
22085
22091
  if (DEBUG_CONTENT)
22086
22092
  console.log(`\u{1F41B} DEBUG createContentGenerator: authType=${config.authType}, apiKey=${config.apiKey}, baseUrl=${config.baseUrl}`);
22087
- const version = "1.1.4";
22093
+ const version = "1.1.6";
22088
22094
  const userAgent = `FSS-Link/${version} (${process.platform}; ${process.arch})`;
22089
22095
  const baseHeaders = {
22090
22096
  "User-Agent": userAgent
@@ -81781,6 +81787,29 @@ var init_databaseMigrations = __esm({
81781
81787
  db.exec("DROP TABLE IF EXISTS model_configs");
81782
81788
  }
81783
81789
  });
81790
+ this.migrations.push({
81791
+ version: 2,
81792
+ name: "normalize_endpoint_urls",
81793
+ up: (db) => {
81794
+ db.exec(`
81795
+ UPDATE model_configs
81796
+ SET endpoint_url = NULL
81797
+ WHERE endpoint_url = '' OR TRIM(endpoint_url) = ''
81798
+ `);
81799
+ if (process.env["FSS_DEBUG"] === "true") {
81800
+ const result = db.exec(`
81801
+ SELECT COUNT(*) as count
81802
+ FROM model_configs
81803
+ WHERE endpoint_url IS NULL
81804
+ `);
81805
+ const count = result[0]?.values?.[0]?.[0] || 0;
81806
+ console.log(`Migration v2: Normalized endpoints (${count} records with NULL endpoint)`);
81807
+ }
81808
+ },
81809
+ down: (db) => {
81810
+ console.warn("Migration v2 rollback not implemented - endpoint normalization is one-way");
81811
+ }
81812
+ });
81784
81813
  }
81785
81814
  /**
81786
81815
  * Get current schema version from database
@@ -83111,57 +83140,167 @@ var init_model_database = __esm({
83111
83140
  [id]
83112
83141
  );
83113
83142
  }
83143
+ /**
83144
+ * Normalize endpoint URL to canonical form:
83145
+ * - undefined → NULL
83146
+ * - '' (empty string) → NULL
83147
+ * - whitespace-only → NULL
83148
+ * - Non-empty string → trimmed string
83149
+ *
83150
+ * This ensures UNIQUE(auth_type, model_name, endpoint_url) works correctly
83151
+ */
83152
+ normalizeEndpointUrl(endpointUrl) {
83153
+ if (!endpointUrl || endpointUrl.trim() === "") {
83154
+ return null;
83155
+ }
83156
+ return endpointUrl.trim();
83157
+ }
83158
+ /**
83159
+ * Find model by UNIQUE constraint (auth_type, model_name, endpoint_url)
83160
+ * With canonical NULL normalization, we use simple exact match
83161
+ */
83162
+ async findByUniqueKey(authType, modelName, endpointUrl) {
83163
+ if (endpointUrl === null) {
83164
+ return await safeQueryFirstWithLocking(
83165
+ this.db,
83166
+ `SELECT id FROM model_configs
83167
+ WHERE auth_type = ?
83168
+ AND model_name = ?
83169
+ AND endpoint_url IS NULL
83170
+ LIMIT 1`,
83171
+ [authType, modelName]
83172
+ );
83173
+ } else {
83174
+ return await safeQueryFirstWithLocking(
83175
+ this.db,
83176
+ `SELECT id FROM model_configs
83177
+ WHERE auth_type = ?
83178
+ AND model_name = ?
83179
+ AND endpoint_url = ?
83180
+ LIMIT 1`,
83181
+ [authType, modelName, endpointUrl]
83182
+ );
83183
+ }
83184
+ }
83185
+ /**
83186
+ * Update existing model record with canonical normalization
83187
+ */
83188
+ async updateModelRecord(recordId, config, normalizedModelName, normalizedEndpointUrl, encryptedApiKey) {
83189
+ const updateParams = [
83190
+ config.authType || "",
83191
+ normalizedModelName,
83192
+ normalizedEndpointUrl,
83193
+ // NULL or actual URL (never '')
83194
+ encryptedApiKey,
83195
+ config.displayName || null,
83196
+ config.isFavorite === true ? 1 : 0,
83197
+ config.isActive === true ? 1 : 0,
83198
+ recordId
83199
+ ];
83200
+ await safeExecWithLocking(this.db, `
83201
+ UPDATE model_configs SET
83202
+ auth_type = ?,
83203
+ model_name = ?,
83204
+ endpoint_url = ?, -- Can be NULL
83205
+ api_key = ?,
83206
+ display_name = ?,
83207
+ is_favorite = ?,
83208
+ is_active = ?,
83209
+ last_used = CURRENT_TIMESTAMP
83210
+ WHERE id = ?
83211
+ `, updateParams);
83212
+ return recordId;
83213
+ }
83214
+ /**
83215
+ * Insert new model record with canonical normalization
83216
+ */
83217
+ async insertModelRecord(config, normalizedModelName, normalizedEndpointUrl, encryptedApiKey) {
83218
+ const insertParams = [
83219
+ config.authType || "",
83220
+ normalizedModelName,
83221
+ normalizedEndpointUrl,
83222
+ // NULL or actual URL (never '')
83223
+ encryptedApiKey,
83224
+ config.displayName || null,
83225
+ config.isFavorite === true ? 1 : 0,
83226
+ config.isActive === true ? 1 : 0,
83227
+ config.source || "db"
83228
+ ];
83229
+ await safeExecWithLocking(this.db, `
83230
+ INSERT INTO model_configs
83231
+ (auth_type, model_name, endpoint_url, api_key, display_name, is_favorite, is_active, last_used, source)
83232
+ VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, ?)
83233
+ `, insertParams);
83234
+ return getLastInsertId(this.db);
83235
+ }
83114
83236
  /**
83115
83237
  * Upsert model configuration - UPDATE existing or INSERT new
83238
+ *
83239
+ * Uses cascading lookup strategy:
83240
+ * 1. Level 1: Lookup by ID (explicit update)
83241
+ * 2. Level 2: Lookup by UNIQUE key (auth_type, model_name, endpoint_url)
83242
+ * 3. Level 3: Fallback to auth_type only (backward compatibility)
83116
83243
  */
83117
83244
  async upsertModelConfig(config) {
83118
83245
  if (!this.db) {
83119
83246
  throw new Error("Database not initialized");
83120
83247
  }
83121
83248
  const encryptedApiKey = config.apiKey ? FSSLinkDatabase.encryptApiKey(config.apiKey) : null;
83122
- const normalizedEndpointUrl = config.endpointUrl || "";
83123
- const existingRecord = await safeQueryFirstWithLocking(
83124
- this.db,
83125
- "SELECT id FROM model_configs WHERE auth_type = ?",
83126
- [config.authType]
83249
+ const normalizedEndpointUrl = this.normalizeEndpointUrl(config.endpointUrl);
83250
+ const normalizedModelName = config.modelName?.trim() || "";
83251
+ let existingRecord = null;
83252
+ if (config.id) {
83253
+ existingRecord = await safeQueryFirstWithLocking(
83254
+ this.db,
83255
+ "SELECT id FROM model_configs WHERE id = ?",
83256
+ [config.id]
83257
+ );
83258
+ if (existingRecord) {
83259
+ return await this.updateModelRecord(
83260
+ existingRecord.id,
83261
+ config,
83262
+ normalizedModelName,
83263
+ normalizedEndpointUrl,
83264
+ encryptedApiKey
83265
+ );
83266
+ }
83267
+ }
83268
+ existingRecord = await this.findByUniqueKey(
83269
+ config.authType,
83270
+ normalizedModelName,
83271
+ normalizedEndpointUrl
83127
83272
  );
83128
- if (existingRecord || config.id) {
83129
- const recordId = existingRecord?.id || config.id;
83130
- const updateParams = [
83131
- config.authType || "",
83132
- config.modelName || "",
83133
- normalizedEndpointUrl,
83134
- encryptedApiKey || null,
83135
- config.displayName || null,
83136
- config.isFavorite === true ? 1 : 0,
83137
- config.isActive === true ? 1 : 0,
83138
- recordId
83139
- ];
83140
- await safeExecWithLocking(this.db, `
83141
- UPDATE model_configs SET
83142
- auth_type = ?, model_name = ?, endpoint_url = ?, api_key = ?,
83143
- display_name = ?, is_favorite = ?, is_active = ?, last_used = CURRENT_TIMESTAMP
83144
- WHERE id = ?
83145
- `, updateParams);
83146
- return recordId || 0;
83147
- } else {
83148
- const insertParams = [
83149
- config.authType || "",
83150
- config.modelName || "",
83273
+ if (existingRecord) {
83274
+ return await this.updateModelRecord(
83275
+ existingRecord.id,
83276
+ config,
83277
+ normalizedModelName,
83151
83278
  normalizedEndpointUrl,
83152
- encryptedApiKey || null,
83153
- config.displayName || null,
83154
- config.isFavorite === true ? 1 : 0,
83155
- config.isActive === true ? 1 : 0,
83156
- config.source || "db"
83157
- ];
83158
- await safeExecWithLocking(this.db, `
83159
- INSERT INTO model_configs
83160
- (auth_type, model_name, endpoint_url, api_key, display_name, is_favorite, is_active, last_used, source)
83161
- VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, ?)
83162
- `, insertParams);
83163
- return getLastInsertId(this.db);
83279
+ encryptedApiKey
83280
+ );
83164
83281
  }
83282
+ if (!normalizedModelName || normalizedModelName === "") {
83283
+ existingRecord = await safeQueryFirstWithLocking(
83284
+ this.db,
83285
+ "SELECT id FROM model_configs WHERE auth_type = ? LIMIT 1",
83286
+ [config.authType]
83287
+ );
83288
+ if (existingRecord) {
83289
+ return await this.updateModelRecord(
83290
+ existingRecord.id,
83291
+ config,
83292
+ normalizedModelName,
83293
+ normalizedEndpointUrl,
83294
+ encryptedApiKey
83295
+ );
83296
+ }
83297
+ }
83298
+ return await this.insertModelRecord(
83299
+ config,
83300
+ normalizedModelName,
83301
+ normalizedEndpointUrl,
83302
+ encryptedApiKey
83303
+ );
83165
83304
  }
83166
83305
  /**
83167
83306
  * Get all model configurations
@@ -84883,11 +85022,11 @@ var init_modelManager = __esm({
84883
85022
  const db2 = await this.getDb();
84884
85023
  const existingSettings = await db2.getProviderSettings(modelId);
84885
85024
  if (!existingSettings["num_ctx"]) {
84886
- console.log(`Creating provider settings for model ${modelId}`);
84887
- console.log(`\u2705 Created default provider settings for Ollama model ${modelId}: num_ctx=32768`);
85025
+ if (DEBUG_MODEL) console.log(`Creating provider settings for model ${modelId}`);
85026
+ if (DEBUG_MODEL) console.log(`\u2705 Created default provider settings for Ollama model ${modelId}: num_ctx=32768`);
84888
85027
  }
84889
85028
  } catch (error) {
84890
- console.warn("Failed to initialize provider settings for new model:", error);
85029
+ if (DEBUG_MODEL) console.warn("Failed to initialize provider settings for new model:", error);
84891
85030
  }
84892
85031
  }
84893
85032
  await this.updateEnvironmentFromModel(config);
@@ -84918,7 +85057,7 @@ var init_modelManager = __esm({
84918
85057
  await this.updateEnvironmentFromModel(config);
84919
85058
  if (this.configRef && this.configRef.setModel) {
84920
85059
  this.configRef.setModel(modelName);
84921
- console.log(`\u{1F527} Notified Config of model change: ${modelName}`);
85060
+ if (DEBUG_MODEL) console.log(`\u{1F527} Notified Config of model change: ${modelName}`);
84922
85061
  }
84923
85062
  return modelId;
84924
85063
  }
@@ -84942,7 +85081,7 @@ var init_modelManager = __esm({
84942
85081
  if (DEBUG_MODEL) console.log(`\u274C [MODEL-MANAGER] Failed to switch to model ID: ${modelId} - model not found`);
84943
85082
  return false;
84944
85083
  } catch (error) {
84945
- console.error(`\u274C [MODEL-MANAGER] Failed to switch to model ID ${modelId}:`, error);
85084
+ if (DEBUG_MODEL) console.error(`\u274C [MODEL-MANAGER] Failed to switch to model ID ${modelId}:`, error);
84946
85085
  return false;
84947
85086
  }
84948
85087
  }
@@ -84971,7 +85110,7 @@ var init_modelManager = __esm({
84971
85110
  });
84972
85111
  const modelToActivate = models[0];
84973
85112
  if (!modelToActivate.id) {
84974
- console.error(`\u274C [MODEL-MANAGER] Model missing ID, cannot activate`);
85113
+ if (DEBUG_MODEL) console.error(`\u274C [MODEL-MANAGER] Model missing ID, cannot activate`);
84975
85114
  return false;
84976
85115
  }
84977
85116
  if (DEBUG_MODEL) {
@@ -84984,7 +85123,7 @@ var init_modelManager = __esm({
84984
85123
  }
84985
85124
  return true;
84986
85125
  } catch (error) {
84987
- console.error(`\u274C [MODEL-MANAGER] Failed to switch to auth type ${authType}:`, error);
85126
+ if (DEBUG_MODEL) console.error(`\u274C [MODEL-MANAGER] Failed to switch to auth type ${authType}:`, error);
84988
85127
  return false;
84989
85128
  }
84990
85129
  }
@@ -85015,7 +85154,7 @@ var init_modelManager = __esm({
85015
85154
  const db = await this.getDb();
85016
85155
  const models = await db.getAllModelConfigs();
85017
85156
  const modelConfigs = models.map((model) => model);
85018
- console.log(`\u2705 [MODEL-MANAGER] Retrieved ${modelConfigs.length} models`);
85157
+ if (DEBUG_MODEL) console.log(`\u2705 [MODEL-MANAGER] Retrieved ${modelConfigs.length} models`);
85019
85158
  return modelConfigs;
85020
85159
  }
85021
85160
  /**
@@ -85028,7 +85167,7 @@ var init_modelManager = __esm({
85028
85167
  const db = await this.getDb();
85029
85168
  const favoriteModels = await db.getFavoriteModels();
85030
85169
  const modelConfigs = favoriteModels.map((model) => model);
85031
- console.log(`\u2705 [MODEL-MANAGER] Retrieved ${modelConfigs.length} favorite models`);
85170
+ if (DEBUG_MODEL) console.log(`\u2705 [MODEL-MANAGER] Retrieved ${modelConfigs.length} favorite models`);
85032
85171
  return modelConfigs;
85033
85172
  }
85034
85173
  /**
@@ -85041,7 +85180,7 @@ var init_modelManager = __esm({
85041
85180
  const db = await this.getDb();
85042
85181
  const recentModels = await db.getRecentlyUsedModels(limit2);
85043
85182
  const modelConfigs = recentModels.map((model) => model);
85044
- console.log(`\u2705 [MODEL-MANAGER] Retrieved ${modelConfigs.length} recent models`);
85183
+ if (DEBUG_MODEL) console.log(`\u2705 [MODEL-MANAGER] Retrieved ${modelConfigs.length} recent models`);
85045
85184
  return modelConfigs;
85046
85185
  }
85047
85186
  /**
@@ -85058,7 +85197,7 @@ var init_modelManager = __esm({
85058
85197
  return;
85059
85198
  }
85060
85199
  const newFavoriteStatus = await db.toggleModelFavorite(modelId);
85061
- console.log(`\u2705 [MODEL-MANAGER] Model ID ${modelId} favorite status: ${newFavoriteStatus ? "enabled" : "disabled"}`);
85200
+ if (DEBUG_MODEL) console.log(`\u2705 [MODEL-MANAGER] Model ID ${modelId} favorite status: ${newFavoriteStatus ? "enabled" : "disabled"}`);
85062
85201
  }
85063
85202
  /**
85064
85203
  * Delete a model configuration
@@ -85120,7 +85259,7 @@ var init_modelManager = __esm({
85120
85259
  if (DEBUG_MODEL) console.log(`\u26A0\uFE0F [MODEL-MANAGER] No active model or auth type found`);
85121
85260
  return void 0;
85122
85261
  }
85123
- console.log(`\u2705 [MODEL-MANAGER] Current auth type: ${activeModel.authType}`);
85262
+ if (DEBUG_MODEL) console.log(`\u2705 [MODEL-MANAGER] Current auth type: ${activeModel.authType}`);
85124
85263
  return activeModel.authType;
85125
85264
  }
85126
85265
  /**
@@ -85136,7 +85275,7 @@ var init_modelManager = __esm({
85136
85275
  if (DEBUG_MODEL) console.log(`\u26A0\uFE0F [MODEL-MANAGER] No active model or auth type found for FSS auth type`);
85137
85276
  return void 0;
85138
85277
  }
85139
- console.log(`\u2705 [MODEL-MANAGER] Current FSS auth type: ${activeModel.authType}`);
85278
+ if (DEBUG_MODEL) console.log(`\u2705 [MODEL-MANAGER] Current FSS auth type: ${activeModel.authType}`);
85140
85279
  return activeModel.authType;
85141
85280
  }
85142
85281
  /**
@@ -85153,7 +85292,7 @@ var init_modelManager = __esm({
85153
85292
  settings = await db.getProviderSettings(model.id);
85154
85293
  }
85155
85294
  } catch (error) {
85156
- console.warn("Failed to load provider settings:", error);
85295
+ if (DEBUG_MODEL) console.warn("Failed to load provider settings:", error);
85157
85296
  }
85158
85297
  await this.applyEnvironmentVariables(model, settings);
85159
85298
  }
@@ -85206,7 +85345,7 @@ var init_modelManager = __esm({
85206
85345
  case "qwen-oauth":
85207
85346
  break;
85208
85347
  default:
85209
- console.warn(`Unknown auth type: ${model.authType}`);
85348
+ if (DEBUG_MODEL) console.warn(`Unknown auth type: ${model.authType}`);
85210
85349
  break;
85211
85350
  }
85212
85351
  if (Object.keys(settings).length > 0) {
@@ -85232,10 +85371,10 @@ var init_modelManager = __esm({
85232
85371
  samplingParams["top_k"] = parseInt(settings["top_k"], 10);
85233
85372
  }
85234
85373
  if (Object.keys(samplingParams).length > 0) {
85235
- console.debug("Provider settings ready for application:", samplingParams);
85374
+ if (DEBUG_MODEL) console.debug("Provider settings ready for application:", samplingParams);
85236
85375
  }
85237
85376
  } catch (error) {
85238
- console.warn("Failed to apply provider settings:", error);
85377
+ if (DEBUG_MODEL) console.warn("Failed to apply provider settings:", error);
85239
85378
  }
85240
85379
  }
85241
85380
  /**
@@ -85256,7 +85395,7 @@ var init_modelManager = __esm({
85256
85395
  settings = await db.getProviderSettings(activeModel.id);
85257
85396
  if (DEBUG_MODEL) console.log(`\u{1F41B} DEBUG getCurrentSamplingParams: Retrieved settings for model ID ${activeModel.id}:`, settings);
85258
85397
  } catch (dbError) {
85259
- console.warn(`\u26A0\uFE0F Database connection issue for provider settings (non-critical):`, dbError);
85398
+ if (DEBUG_MODEL) console.warn(`\u26A0\uFE0F Database connection issue for provider settings (non-critical):`, dbError);
85260
85399
  return {};
85261
85400
  }
85262
85401
  const samplingParams = {};
@@ -85275,7 +85414,7 @@ var init_modelManager = __esm({
85275
85414
  if (DEBUG_MODEL) console.log(`\u{1F41B} DEBUG getCurrentSamplingParams: Final sampling params:`, samplingParams);
85276
85415
  return samplingParams;
85277
85416
  } catch (error) {
85278
- console.warn("Failed to get current sampling params:", error);
85417
+ if (DEBUG_MODEL) console.warn("Failed to get current sampling params:", error);
85279
85418
  return {};
85280
85419
  }
85281
85420
  }
@@ -94141,7 +94280,7 @@ async function getPackageJson() {
94141
94280
  // packages/cli/src/utils/version.ts
94142
94281
  async function getCliVersion() {
94143
94282
  const pkgJson = await getPackageJson();
94144
- return "1.1.4";
94283
+ return "1.1.6";
94145
94284
  }
94146
94285
 
94147
94286
  // packages/cli/src/ui/commands/aboutCommand.ts
@@ -94193,7 +94332,7 @@ import open4 from "open";
94193
94332
  import process11 from "node:process";
94194
94333
 
94195
94334
  // packages/cli/src/generated/git-commit.ts
94196
- var GIT_COMMIT_INFO = "a15d9a12";
94335
+ var GIT_COMMIT_INFO = "2fbcfa4c";
94197
94336
 
94198
94337
  // packages/cli/src/ui/commands/bugCommand.ts
94199
94338
  init_dist2();
@@ -117981,8 +118120,9 @@ import { useState as useState33 } from "react";
117981
118120
  init_dist2();
117982
118121
  init_settings();
117983
118122
  init_database();
118123
+ var DEBUG_AUTH = process.env["FSS_DEBUG"] === "true" || process.env["NODE_ENV"] === "development";
117984
118124
  var validateAuthMethod = (authMethod) => {
117985
- console.log(`\u{1F510} [AUTH-SYSTEM] Legacy auth validation: ${authMethod}`);
118125
+ if (DEBUG_AUTH) console.log(`\u{1F510} [AUTH-SYSTEM] Legacy auth validation: ${authMethod}`);
117986
118126
  loadEnvironment();
117987
118127
  return validateAuthEnvironment(authMethod);
117988
118128
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fss-link",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "engines": {
5
5
  "node": ">=20.0.0"
6
6
  },